/[emacs]/emacs/lib-src/etags.c
ViewVC logotype

Diff of /emacs/lib-src/etags.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 3.21 by pot, Thu Jun 6 22:37:28 2002 UTC revision 3.21.2.1 by miles, Fri Apr 4 06:19:54 2003 UTC
# Line 2  Line 2 
2     Copyright (C) 1984, 1987-1989, 1993-1995, 1998-2001, 2002     Copyright (C) 1984, 1987-1989, 1993-1995, 1998-2001, 2002
3     Free Software Foundation, Inc. and Ken Arnold     Free Software Foundation, Inc. and Ken Arnold
4    
5  This file is not considered part of GNU Emacs.   This file is not considered part of GNU Emacs.
6    
7  This program is free software; you can redistribute it and/or modify   This program is free software; you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by   it under the terms of the GNU General Public License as published by
9  the Free Software Foundation; either version 2 of the License, or   the Free Software Foundation; either version 2 of the License, or
10  (at your option) any later version.   (at your option) any later version.
11    
12  This program is distributed in the hope that it will be useful,   This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  GNU General Public License for more details.   GNU General Public License for more details.
16    
17  You should have received a copy of the GNU General Public License   You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software Foundation,   along with this program; if not, write to the Free Software Foundation,
19  Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
20    
21  /*  /*
22   * Authors:   * Authors:
# Line 27  Inc., 59 Temple Place - Suite 330, Bosto Line 27  Inc., 59 Temple Place - Suite 330, Bosto
27   * 1989 Sam Kendall added C++.   * 1989 Sam Kendall added C++.
28   * 1992 Joseph B. Wells improved C and C++ parsing.   * 1992 Joseph B. Wells improved C and C++ parsing.
29   * 1993 Francesco Potort́ reorganised C and C++.   * 1993 Francesco Potort́ reorganised C and C++.
30   * 1994 Regexp tags by Tom Tromey.   * 1994 Line-by-line regexp tags by Tom Tromey.
31   * 2001 Nested classes by Francesco Potort́ (concept by Mykola Dzyuba).   * 2001 Nested classes by Francesco Potort́ (concept by Mykola Dzyuba).
32   * 2002 #line directives by Francesco Potort́.   * 2002 #line directives by Francesco Potort́.
33   *   *
34   *      Francesco Potort́ <pot@gnu.org> has maintained it since 1993.   * Francesco Potort́ <pot@gnu.org> has maintained and improved it since 1993.
35     *
36   */   */
37    
38  char pot_etags_version[] = "@(#) pot revision number is 16.10";  char pot_etags_version[] = "@(#) pot revision number is 16.56";
39    
40  #define TRUE    1  #define TRUE    1
41  #define FALSE   0  #define FALSE   0
# Line 186  If you want regular expression support, Line 187  If you want regular expression support,
187  #endif  #endif
188    
189  #define streq(s,t)      (assert((s)!=NULL || (t)!=NULL), !strcmp (s, t))  #define streq(s,t)      (assert((s)!=NULL || (t)!=NULL), !strcmp (s, t))
190    #define strcaseeq(s,t)  (assert((s)!=NULL && (t)!=NULL), !etags_strcasecmp (s, t))
191  #define strneq(s,t,n)   (assert((s)!=NULL || (t)!=NULL), !strncmp (s, t, n))  #define strneq(s,t,n)   (assert((s)!=NULL || (t)!=NULL), !strncmp (s, t, n))
192    #define strncaseeq(s,t,n) (assert((s)!=NULL && (t)!=NULL), !etags_strncasecmp (s, t, n))
193    
194  #define CHARS 256               /* 2^sizeof(char) */  #define CHARS 256               /* 2^sizeof(char) */
195  #define CHAR(x)         ((unsigned int)(x) & (CHARS - 1))  #define CHAR(x)         ((unsigned int)(x) & (CHARS - 1))
196  #define iswhite(c)      (_wht[CHAR(c)]) /* c is white */  #define iswhite(c)      (_wht[CHAR(c)]) /* c is white (see white) */
197  #define notinname(c)    (_nin[CHAR(c)]) /* c is not in a name */  #define notinname(c)    (_nin[CHAR(c)]) /* c is not in a name (see nonam) */
198  #define begtoken(c)     (_btk[CHAR(c)]) /* c can start token */  #define begtoken(c)     (_btk[CHAR(c)]) /* c can start token (see begtk) */
199  #define intoken(c)      (_itk[CHAR(c)]) /* c can be in token */  #define intoken(c)      (_itk[CHAR(c)]) /* c can be in token (see midtk) */
200  #define endtoken(c)     (_etk[CHAR(c)]) /* c ends tokens */  #define endtoken(c)     (_etk[CHAR(c)]) /* c ends tokens (see endtk) */
201    
202  #define ISALNUM(c)      isalnum (CHAR(c))  #define ISALNUM(c)      isalnum (CHAR(c))
203  #define ISALPHA(c)      isalpha (CHAR(c))  #define ISALPHA(c)      isalpha (CHAR(c))
# Line 236  typedef struct Line 239  typedef struct
239  typedef struct  typedef struct
240  {  {
241    char *name;                   /* language name */    char *name;                   /* language name */
242    bool metasource;              /* source used to generate other sources */    char *help;                   /* detailed help for the language */
243    Lang_function *function;      /* parse function */    Lang_function *function;      /* parse function */
   char **filenames;             /* names of this language's files */  
244    char **suffixes;              /* name suffixes of this language's files */    char **suffixes;              /* name suffixes of this language's files */
245      char **filenames;             /* names of this language's files */
246    char **interpreters;          /* interpreters for this language */    char **interpreters;          /* interpreters for this language */
247      bool metasource;              /* source used to generate other sources */
248  } language;  } language;
249    
250  typedef struct fdesc  typedef struct fdesc
# Line 253  typedef struct fdesc Line 257  typedef struct fdesc
257    language *lang;               /* language of file */    language *lang;               /* language of file */
258    char *prop;                   /* file properties to write in tagfile */    char *prop;                   /* file properties to write in tagfile */
259    bool usecharno;               /* etags tags shall contain char number */    bool usecharno;               /* etags tags shall contain char number */
260      bool written;                 /* entry written in the tags file */
261  } fdesc;  } fdesc;
262    
263  typedef struct node_st  typedef struct node_st
# Line 260  typedef struct node_st Line 265  typedef struct node_st
265    struct node_st *left, *right; /* left and right sons */    struct node_st *left, *right; /* left and right sons */
266    fdesc *fdp;                   /* description of file to whom tag belongs */    fdesc *fdp;                   /* description of file to whom tag belongs */
267    char *name;                   /* tag name */    char *name;                   /* tag name */
268    char *pat;                    /* search pattern */    char *regex;                  /* search regexp */
269    bool valid;                   /* write this tag on the tag file */    bool valid;                   /* write this tag on the tag file */
270    bool is_func;                 /* function tag: use pattern in CTAGS mode */    bool is_func;                 /* function tag: use regexp in CTAGS mode */
271    bool been_warned;             /* warning already given for duplicated tag */    bool been_warned;             /* warning already given for duplicated tag */
272    int lno;                      /* line number tag is on */    int lno;                      /* line number tag is on */
273    long cno;                     /* character number line starts on */    long cno;                     /* character number line starts on */
# Line 288  typedef struct Line 293  typedef struct
293    enum {    enum {
294      at_language,                /* a language specification */      at_language,                /* a language specification */
295      at_regexp,                  /* a regular expression */      at_regexp,                  /* a regular expression */
     at_icregexp,                /* same, but with case ignored */  
296      at_filename,                /* a file name */      at_filename,                /* a file name */
297      at_stdin                    /* read from stdin here */      at_stdin,                   /* read from stdin here */
298        at_end                      /* stop parsing the list */
299    } arg_type;                   /* argument type */    } arg_type;                   /* argument type */
300    language *lang;               /* language associated with the argument */    language *lang;               /* language associated with the argument */
301    char *what;                   /* the argument itself */    char *what;                   /* the argument itself */
# Line 298  typedef struct Line 303  typedef struct
303    
304  #ifdef ETAGS_REGEXPS  #ifdef ETAGS_REGEXPS
305  /* Structure defining a regular expression. */  /* Structure defining a regular expression. */
306  typedef struct pattern  typedef struct regexp
307  {  {
308    struct pattern *p_next;    struct regexp *p_next;        /* pointer to next in list */
309    language *lang;    language *lang;               /* if set, use only for this language */
310    char *regex;    char *pattern;                /* the regexp pattern */
311    struct re_pattern_buffer *pat;    char *name;                   /* tag name */
312    struct re_registers regs;    struct re_pattern_buffer *pat; /* the compiled pattern */
313    char *name_pattern;    struct re_registers regs;     /* re registers */
314    bool error_signaled;    bool error_signaled;          /* already signaled for this regexp */
315    bool ignore_case;    bool force_explicit_name;     /* do not allow implict tag name */
316  } pattern;    bool ignore_case;             /* ignore case when matching */
317      bool multi_line;              /* do a multi-line match on the whole file */
318    } regexp;
319  #endif /* ETAGS_REGEXPS */  #endif /* ETAGS_REGEXPS */
320    
321    
# Line 326  static void Cplusplus_entries __P((FILE Line 333  static void Cplusplus_entries __P((FILE
333  static void Cstar_entries __P((FILE *));  static void Cstar_entries __P((FILE *));
334  static void Erlang_functions __P((FILE *));  static void Erlang_functions __P((FILE *));
335  static void Fortran_functions __P((FILE *));  static void Fortran_functions __P((FILE *));
336  static void Yacc_entries __P((FILE *));  static void HTML_labels __P((FILE *));
337  static void Lisp_functions __P((FILE *));  static void Lisp_functions __P((FILE *));
338  static void Makefile_targets __P((FILE *));  static void Makefile_targets __P((FILE *));
339  static void Pascal_functions __P((FILE *));  static void Pascal_functions __P((FILE *));
340  static void Perl_functions __P((FILE *));  static void Perl_functions __P((FILE *));
341  static void PHP_functions __P((FILE *));  static void PHP_functions __P((FILE *));
342  static void Postscript_functions __P((FILE *));  static void PS_functions __P((FILE *));
343  static void Prolog_functions __P((FILE *));  static void Prolog_functions __P((FILE *));
344  static void Python_functions __P((FILE *));  static void Python_functions __P((FILE *));
345  static void Scheme_functions __P((FILE *));  static void Scheme_functions __P((FILE *));
346  static void TeX_commands __P((FILE *));  static void TeX_commands __P((FILE *));
347  static void Texinfo_nodes __P((FILE *));  static void Texinfo_nodes __P((FILE *));
348    static void Yacc_entries __P((FILE *));
349  static void just_read_file __P((FILE *));  static void just_read_file __P((FILE *));
350    
351  static void print_language_names __P((void));  static void print_language_names __P((void));
352  static void print_version __P((void));  static void print_version __P((void));
353  static void print_help __P((void));  static void print_help __P((argument *));
354  int main __P((int, char **));  int main __P((int, char **));
355    
356  static compressor *get_compressor_from_suffix __P((char *, char **));  static compressor *get_compressor_from_suffix __P((char *, char **));
# Line 352  static language *get_language_from_filen Line 360  static language *get_language_from_filen
360  static void readline __P((linebuffer *, FILE *));  static void readline __P((linebuffer *, FILE *));
361  static long readline_internal __P((linebuffer *, FILE *));  static long readline_internal __P((linebuffer *, FILE *));
362  static bool nocase_tail __P((char *));  static bool nocase_tail __P((char *));
363  static char *get_tag __P((char *));  static void get_tag __P((char *, char **));
364    
365  #ifdef ETAGS_REGEXPS  #ifdef ETAGS_REGEXPS
366  static void analyse_regex __P((char *, bool));  static void analyse_regex __P((char *));
367  static void add_regex __P((char *, bool, language *));  static void free_regexps __P((void));
368  static void free_patterns __P((void));  static void regex_tag_multiline __P((void));
369  #endif /* ETAGS_REGEXPS */  #endif /* ETAGS_REGEXPS */
370  static void error __P((const char *, const char *));  static void error __P((const char *, const char *));
371  static void suggest_asking_for_help __P((void));  static void suggest_asking_for_help __P((void));
# Line 366  static void pfatal __P((char *)); Line 374  static void pfatal __P((char *));
374  static void add_node __P((node *, node **));  static void add_node __P((node *, node **));
375    
376  static void init __P((void));  static void init __P((void));
 static void initbuffer __P((linebuffer *));  
377  static void process_file_name __P((char *, language *));  static void process_file_name __P((char *, language *));
378  static void process_file __P((FILE *, char *, language *));  static void process_file __P((FILE *, char *, language *));
379  static void find_entries __P((FILE *));  static void find_entries __P((FILE *));
380  static void free_tree __P((node *));  static void free_tree __P((node *));
381  static void free_fdesc __P((fdesc *));  static void free_fdesc __P((fdesc *));
382  static void pfnote __P((char *, bool, char *, int, int, long));  static void pfnote __P((char *, bool, char *, int, int, long));
383  static void new_pfnote __P((char *, int, bool, char *, int, int, long));  static void make_tag __P((char *, int, bool, char *, int, int, long));
384  static void invalidate_nodes __P((fdesc *, node **));  static void invalidate_nodes __P((fdesc *, node **));
385  static void put_entries __P((node *));  static void put_entries __P((node *));
386    
# Line 384  static char *savenstr __P((char *, int)) Line 391  static char *savenstr __P((char *, int))
391  static char *savestr __P((char *));  static char *savestr __P((char *));
392  static char *etags_strchr __P((const char *, int));  static char *etags_strchr __P((const char *, int));
393  static char *etags_strrchr __P((const char *, int));  static char *etags_strrchr __P((const char *, int));
394  static bool strcaseeq __P((const char *, const char *));  static int etags_strcasecmp __P((const char *, const char *));
395    static int etags_strncasecmp __P((const char *, const char *, int));
396  static char *etags_getcwd __P((void));  static char *etags_getcwd __P((void));
397  static char *relative_filename __P((char *, char *));  static char *relative_filename __P((char *, char *));
398  static char *absolute_filename __P((char *, char *));  static char *absolute_filename __P((char *, char *));
399  static char *absolute_dirname __P((char *, char *));  static char *absolute_dirname __P((char *, char *));
400  static bool filename_is_absolute __P((char *f));  static bool filename_is_absolute __P((char *f));
401  static void canonicalize_filename __P((char *));  static void canonicalize_filename __P((char *));
402    static void linebuffer_init __P((linebuffer *));
403  static void linebuffer_setlen __P((linebuffer *, int));  static void linebuffer_setlen __P((linebuffer *, int));
404  static PTR xmalloc __P((unsigned int));  static PTR xmalloc __P((unsigned int));
405  static PTR xrealloc __P((char *, unsigned int));  static PTR xrealloc __P((char *, unsigned int));
# Line 417  static node *nodehead;         /* the head of t Line 426  static node *nodehead;         /* the head of t
426  static node *last_node;         /* the last node created */  static node *last_node;         /* the last node created */
427    
428  static linebuffer lb;           /* the current line */  static linebuffer lb;           /* the current line */
429    static linebuffer filebuf;      /* a buffer containing the whole file */
430    static linebuffer token_name;   /* a buffer containing a tag name */
431    
432  /* boolean "functions" (see init)       */  /* boolean "functions" (see init)       */
433  static bool _wht[CHARS], _nin[CHARS], _itk[CHARS], _btk[CHARS], _etk[CHARS];  static bool _wht[CHARS], _nin[CHARS], _itk[CHARS], _btk[CHARS], _etk[CHARS];
# Line 424  static char Line 435  static char
435    /* white chars */    /* white chars */
436    *white = " \f\t\n\r\v",    *white = " \f\t\n\r\v",
437    /* not in a name */    /* not in a name */
438    *nonam = " \f\t\n\r()=,;",    *nonam = " \f\t\n\r()=,;",    /* look at make_tag before modifying! */
439    /* token ending chars */    /* token ending chars */
440    *endtk = " \t\n\r\"'#()[]{}=-+%*/&|^~!<>;,.:?",    *endtk = " \t\n\r\"'#()[]{}=-+%*/&|^~!<>;,.:?",
441    /* token starting chars */    /* token starting chars */
# Line 450  static bool vgrind_style;      /* -v: create Line 461  static bool vgrind_style;      /* -v: create
461  static bool no_warnings;        /* -w: suppress warnings */  static bool no_warnings;        /* -w: suppress warnings */
462  static bool cxref_style;        /* -x: create cxref style output */  static bool cxref_style;        /* -x: create cxref style output */
463  static bool cplusplus;          /* .[hc] means C++, not C */  static bool cplusplus;          /* .[hc] means C++, not C */
464  static bool noindentypedefs;    /* -I: ignore indentation in C */  static bool ignoreindent;       /* -I: ignore indentation in C */
465  static bool packages_only;      /* --packages-only: in Ada, only tag packages*/  static bool packages_only;      /* --packages-only: in Ada, only tag packages*/
466    
467  #define STDIN 0x1001            /* returned by getopt_long on --parse-stdin */  #define STDIN 0x1001            /* returned by getopt_long on --parse-stdin */
468  static bool parsing_stdin;      /* --parse-stdin used */  static bool parsing_stdin;      /* --parse-stdin used */
469    
470  #ifdef ETAGS_REGEXPS  #ifdef ETAGS_REGEXPS
471  /* List of all regexps. */  static regexp *p_head;          /* list of all regexps */
472  static pattern *p_head;  static bool need_filebuf;       /* some regexes are multi-line */
473    #else
474  /* How many characters in the character set.  (From regex.c.)  */  # define need_filebuf FALSE
 #define CHAR_SET_SIZE 256  
 /* Translation table for case-insensitive matching. */  
 static char lc_trans[CHAR_SET_SIZE];  
475  #endif /* ETAGS_REGEXPS */  #endif /* ETAGS_REGEXPS */
476    
477  #ifdef LONG_OPTIONS  #ifdef LONG_OPTIONS
# Line 526  static compressor compressors[] = Line 534  static compressor compressors[] =
534  /* Ada code */  /* Ada code */
535  static char *Ada_suffixes [] =  static char *Ada_suffixes [] =
536    { "ads", "adb", "ada", NULL };    { "ads", "adb", "ada", NULL };
537    static char Ada_help [] =
538    "In Ada code, functions, procedures, packages, tasks and types are\n\
539    tags.  Use the `--packages-only' option to create tags for\n\
540    packages only.\n\
541    Ada tag names have suffixes indicating the type of entity:\n\
542            Entity type:    Qualifier:\n\
543            ------------    ----------\n\
544            function        /f\n\
545            procedure       /p\n\
546            package spec    /s\n\
547            package body    /b\n\
548            type            /t\n\
549            task            /k\n\
550    Thus, `M-x find-tag <RET> bidule/b <RET>' will go directly to the\n\
551    body of the package `bidule', while `M-x find-tag <RET> bidule <RET>'\n\
552    will just search for any tag `bidule'.";
553    
554  /* Assembly code */  /* Assembly code */
555  static char *Asm_suffixes [] =  static char *Asm_suffixes [] =
# Line 539  static char *Asm_suffixes [] = Line 563  static char *Asm_suffixes [] =
563      "src", /* BSO/Tasking C compiler output */      "src", /* BSO/Tasking C compiler output */
564      NULL      NULL
565    };    };
566    static char Asm_help [] =
567    "In assembler code, labels appearing at the beginning of a line,\n\
568    followed by a colon, are tags.";
569    
570    
571  /* Note that .c and .h can be considered C++, if the --c++ flag was  /* Note that .c and .h can be considered C++, if the --c++ flag was
572     given, or if the `class' keyowrd is met inside the file.     given, or if the `class' or `template' keyowrds are met inside the file.
573     That is why default_C_entries is called for these. */     That is why default_C_entries is called for these. */
574  static char *default_C_suffixes [] =  static char *default_C_suffixes [] =
575    { "c", "h", NULL };    { "c", "h", NULL };
576    static char default_C_help [] =
577    "In C code, any C function or typedef is a tag, and so are\n\
578    definitions of `struct', `union' and `enum'.  `#define' macro\n\
579    definitions and `enum' constants are tags unless you specify\n\
580    `--no-defines'.  Global variables are tags unless you specify\n\
581    `--no-globals'.  Use of `--no-globals' and `--no-defines'\n\
582    can make the tags table file much smaller.\n\
583    You can tag function declarations and external variables by\n\
584    using `--declarations', and struct members by using `--members'.";
585    
586  static char *Cplusplus_suffixes [] =  static char *Cplusplus_suffixes [] =
587    { "C", "c++", "cc", "cpp", "cxx", "H", "h++", "hh", "hpp", "hxx",    { "C", "c++", "cc", "cpp", "cxx", "H", "h++", "hh", "hpp", "hxx",
588      "M",                        /* Objective C++ */      "M",                        /* Objective C++ */
589      "pdb",                      /* Postscript with C syntax */      "pdb",                      /* Postscript with C syntax */
590      NULL };      NULL };
591    static char Cplusplus_help [] =
592    "In C++ code, all the tag constructs of C code are tagged.  (Use\n\
593    --help --lang=c --lang=c++ for full help.)\n\
594    In addition to C tags, member functions are also recognized, and\n\
595    optionally member variables if you use the `--members' option.\n\
596    Tags for variables and functions in classes are named `CLASS::VARIABLE'\n\
597    and `CLASS::FUNCTION'.  `operator' definitions have tag names like\n\
598    `operator+'.";
599    
600  static char *Cjava_suffixes [] =  static char *Cjava_suffixes [] =
601    { "java", NULL };    { "java", NULL };
602    static char Cjava_help [] =
603    "In Java code, all the tags constructs of C and C++ code are\n\
604    tagged.  (Use --help --lang=c --lang=c++ --lang=java for full help.)";
605    
606    
607  static char *Cobol_suffixes [] =  static char *Cobol_suffixes [] =
608    { "COB", "cob", NULL };    { "COB", "cob", NULL };
609    static char Cobol_help [] =
610    "In Cobol code, tags are paragraph names; that is, any word\n\
611    starting in column 8 and followed by a period.";
612    
613  static char *Cstar_suffixes [] =  static char *Cstar_suffixes [] =
614    { "cs", "hs", NULL };    { "cs", "hs", NULL };
615    
616  static char *Erlang_suffixes [] =  static char *Erlang_suffixes [] =
617    { "erl", "hrl", NULL };    { "erl", "hrl", NULL };
618    static char Erlang_help [] =
619    "In Erlang code, the tags are the functions, records and macros\n\
620    defined in the file.";
621    
622  static char *Fortran_suffixes [] =  static char *Fortran_suffixes [] =
623    { "F", "f", "f90", "for", NULL };    { "F", "f", "f90", "for", NULL };
624    static char Fortran_help [] =
625    "In Fortran code, functions, subroutines and block data are tags.";
626    
627    static char *HTML_suffixes [] =
628      { "htm", "html", "shtml", NULL };
629    static char HTML_help [] =
630    "In HTML input files, the tags are the `title' and the `h1', `h2',\n\
631    `h3' headers.  Also, tags are `name=' in anchors and all\n\
632    occurrences of `id='.";
633    
634  static char *Lisp_suffixes [] =  static char *Lisp_suffixes [] =
635    { "cl", "clisp", "el", "l", "lisp", "LSP", "lsp", "ml", NULL };    { "cl", "clisp", "el", "l", "lisp", "LSP", "lsp", "ml", NULL };
636    static char Lisp_help [] =
637    "In Lisp code, any function defined with `defun', any variable\n\
638    defined with `defvar' or `defconst', and in general the first\n\
639    argument of any expression that starts with `(def' in column zero\n\
640    is a tag.";
641    
642  static char *Makefile_filenames [] =  static char *Makefile_filenames [] =
643    { "Makefile", "makefile", "GNUMakefile", "Makefile.in", "Makefile.am", NULL};    { "Makefile", "makefile", "GNUMakefile", "Makefile.in", "Makefile.am", NULL};
644    static char Makefile_help [] =
645    "In makefiles, targets are tags; additionally, variables are tags\n\
646    unless you specify `--no-globals'.";
647    
648    static char *Objc_suffixes [] =
649      { "lm",                       /* Objective lex file */
650        "m",                        /* Objective C file */
651         NULL };
652    static char Objc_help [] =
653    "In Objective C code, tags include Objective C definitions for classes,\n\
654    class categories, methods and protocols.  Tags for variables and\n\
655    functions in classes are named `CLASS::VARIABLE' and `CLASS::FUNCTION'.";
656    
657  static char *Pascal_suffixes [] =  static char *Pascal_suffixes [] =
658    { "p", "pas", NULL };    { "p", "pas", NULL };
659    static char Pascal_help [] =
660    "In Pascal code, the tags are the functions and procedures defined\n\
661    in the file.";
662    
663  static char *Perl_suffixes [] =  static char *Perl_suffixes [] =
664    { "pl", "pm", NULL };    { "pl", "pm", NULL };
   
665  static char *Perl_interpreters [] =  static char *Perl_interpreters [] =
666    { "perl", "@PERL@", NULL };    { "perl", "@PERL@", NULL };
667    static char Perl_help [] =
668    "In Perl code, the tags are the packages, subroutines and variables\n\
669    defined by the `package', `sub', `my' and `local' keywords.  Use\n\
670    `--globals' if you want to tag global variables.  Tags for\n\
671    subroutines are named `PACKAGE::SUB'.  The name for subroutines\n\
672    defined in the default package is `main::SUB'.";
673    
674  static char *PHP_suffixes [] =  static char *PHP_suffixes [] =
675    { "php", "php3", "php4", NULL };    { "php", "php3", "php4", NULL };
676    static char PHP_help [] =
677    "In PHP code, tags are functions, classes and defines.  When using\n\
678    the `--members' option, vars are tags too.";
679    
680  static char *plain_C_suffixes [] =  static char *plain_C_suffixes [] =
681    { "lm",                       /* Objective lex file */    { "pc",                       /* Pro*C file */
     "m",                        /* Objective C file */  
     "pc",                       /* Pro*C file */  
682       NULL };       NULL };
683    
684  static char *Postscript_suffixes [] =  static char *PS_suffixes [] =
685    { "ps", "psw", NULL };        /* .psw is for PSWrap */    { "ps", "psw", NULL };        /* .psw is for PSWrap */
686    static char PS_help [] =
687    "In PostScript code, the tags are the functions.";
688    
689  static char *Prolog_suffixes [] =  static char *Prolog_suffixes [] =
690    { "prolog", NULL };    { "prolog", NULL };
691    static char Prolog_help [] =
692    "In Prolog code, tags are predicates and rules at the beginning of\n\
693    line.";
694    
695  static char *Python_suffixes [] =  static char *Python_suffixes [] =
696    { "py", NULL };    { "py", NULL };
697    static char Python_help [] =
698    "In Python code, `def' or `class' at the beginning of a line\n\
699    generate a tag.";
700    
701  /* Can't do the `SCM' or `scm' prefix with a version number. */  /* Can't do the `SCM' or `scm' prefix with a version number. */
702  static char *Scheme_suffixes [] =  static char *Scheme_suffixes [] =
703    { "oak", "sch", "scheme", "SCM", "scm", "SM", "sm", "ss", "t", NULL };    { "oak", "sch", "scheme", "SCM", "scm", "SM", "sm", "ss", "t", NULL };
704    static char Scheme_help [] =
705    "In Scheme code, tags include anything defined with `def' or with a\n\
706    construct whose name starts with `def'.  They also include\n\
707    variables set with `set!' at top level in the file.";
708    
709  static char *TeX_suffixes [] =  static char *TeX_suffixes [] =
710    { "bib", "clo", "cls", "ltx", "sty", "TeX", "tex", NULL };    { "bib", "clo", "cls", "ltx", "sty", "TeX", "tex", NULL };
711    static char TeX_help [] =
712    "In LaTeX text, the argument of any of the commands `\\chapter',\n\
713    `\\section', `\\subsection', `\\subsubsection', `\\eqno', `\\label',\n\
714    `\\ref', `\\cite', `\\bibitem', `\\part', `\\appendix', `\\entry',\n\
715    `\\index', `\\def', `\\newcommand', `\\renewcommand',\n\
716    `\\newenvironment' or `\\renewenvironment' is a tag.\n\
717    \n\
718    Other commands can be specified by setting the environment variable\n\
719    `TEXTAGS' to a colon-separated list like, for example,\n\
720         TEXTAGS=\"mycommand:myothercommand\".";
721    
722    
723  static char *Texinfo_suffixes [] =  static char *Texinfo_suffixes [] =
724    { "texi", "texinfo", "txi", NULL };    { "texi", "texinfo", "txi", NULL };
725    static char Texinfo_help [] =
726    "for texinfo files, lines starting with @node are tagged.";
727    
728  static char *Yacc_suffixes [] =  static char *Yacc_suffixes [] =
729    { "y", "y++", "ym", "yxx", "yy", NULL }; /* .ym is Objective yacc file */    { "y", "y++", "ym", "yxx", "yy", NULL }; /* .ym is Objective yacc file */
730    static char Yacc_help [] =
731    "In Bison or Yacc input files, each rule defines as a tag the\n\
732    nonterminal it constructs.  The portions of the file that contain\n\
733    C code are parsed as C code (use --help --lang=c --lang=yacc\n\
734    for full help).";
735    
736    static char auto_help [] =
737    "`auto' is not a real language, it indicates to use\n\
738    a default language for files base on file name suffix and file contents.";
739    
740    static char none_help [] =
741    "`none' is not a real language, it indicates to only do\n\
742    regexp processing on files.";
743    
744    static char no_lang_help [] =
745    "No detailed help available for this language.";
746    
747    
748  /*  /*
749   * Table of languages.   * Table of languages.
# Line 622  static char *Yacc_suffixes [] = Line 754  static char *Yacc_suffixes [] =
754    
755  static language lang_names [] =  static language lang_names [] =
756  {  {
757    { "ada",      FALSE, Ada_funcs,            NULL, Ada_suffixes,        NULL },    { "ada",       Ada_help,       Ada_funcs,         Ada_suffixes       },
758    { "asm",      FALSE, Asm_labels,           NULL, Asm_suffixes,        NULL },    { "asm",       Asm_help,       Asm_labels,        Asm_suffixes       },
759    { "c",        FALSE, default_C_entries,    NULL, default_C_suffixes,  NULL },    { "c",         default_C_help, default_C_entries, default_C_suffixes },
760    { "c++",      FALSE, Cplusplus_entries,    NULL, Cplusplus_suffixes,  NULL },    { "c++",       Cplusplus_help, Cplusplus_entries, Cplusplus_suffixes },
761    { "c*",       FALSE, Cstar_entries,        NULL, Cstar_suffixes,      NULL },    { "c*",        no_lang_help,   Cstar_entries,     Cstar_suffixes     },
762    { "cobol",    FALSE, Cobol_paragraphs,     NULL, Cobol_suffixes,      NULL },    { "cobol",     Cobol_help,     Cobol_paragraphs,  Cobol_suffixes     },
763    { "erlang",   FALSE, Erlang_functions,     NULL, Erlang_suffixes,     NULL },    { "erlang",    Erlang_help,    Erlang_functions,  Erlang_suffixes    },
764    { "fortran",  FALSE, Fortran_functions,    NULL, Fortran_suffixes,    NULL },    { "fortran",   Fortran_help,   Fortran_functions, Fortran_suffixes   },
765    { "java",     FALSE, Cjava_entries,        NULL, Cjava_suffixes,      NULL },    { "html",      HTML_help,      HTML_labels,       HTML_suffixes      },
766    { "lisp",     FALSE, Lisp_functions,       NULL, Lisp_suffixes,       NULL },    { "java",      Cjava_help,     Cjava_entries,     Cjava_suffixes     },
767    { "makefile", FALSE, Makefile_targets,     Makefile_filenames, NULL,  NULL },    { "lisp",      Lisp_help,      Lisp_functions,    Lisp_suffixes      },
768    { "pascal",   FALSE, Pascal_functions,     NULL, Pascal_suffixes,     NULL },    { "makefile",  Makefile_help,Makefile_targets,NULL,Makefile_filenames},
769    { "perl",     FALSE, Perl_functions,NULL, Perl_suffixes, Perl_interpreters },    { "objc",      Objc_help,      plain_C_entries,   Objc_suffixes      },
770    { "php",      FALSE, PHP_functions,        NULL, PHP_suffixes,        NULL },    { "pascal",    Pascal_help,    Pascal_functions,  Pascal_suffixes    },
771    { "postscript",FALSE, Postscript_functions,NULL, Postscript_suffixes, NULL },    { "perl",Perl_help,Perl_functions,Perl_suffixes,NULL,Perl_interpreters},
772    { "proc",     FALSE, plain_C_entries,      NULL, plain_C_suffixes,    NULL },    { "php",       PHP_help,       PHP_functions,     PHP_suffixes       },
773    { "prolog",   FALSE, Prolog_functions,     NULL, Prolog_suffixes,     NULL },    { "postscript",PS_help,        PS_functions,      PS_suffixes        },
774    { "python",   FALSE, Python_functions,     NULL, Python_suffixes,     NULL },    { "proc",      no_lang_help,   plain_C_entries,   plain_C_suffixes   },
775    { "scheme",   FALSE, Scheme_functions,     NULL, Scheme_suffixes,     NULL },    { "prolog",    Prolog_help,    Prolog_functions,  Prolog_suffixes    },
776    { "tex",      FALSE, TeX_commands,         NULL, TeX_suffixes,        NULL },    { "python",    Python_help,    Python_functions,  Python_suffixes    },
777    { "texinfo",  FALSE, Texinfo_nodes,        NULL, Texinfo_suffixes,    NULL },    { "scheme",    Scheme_help,    Scheme_functions,  Scheme_suffixes    },
778    { "yacc",      TRUE, Yacc_entries,         NULL, Yacc_suffixes,       NULL },    { "tex",       TeX_help,       TeX_commands,      TeX_suffixes       },
779    { "auto", FALSE, NULL },             /* default guessing scheme */    { "texinfo",   Texinfo_help,   Texinfo_nodes,     Texinfo_suffixes   },
780    { "none", FALSE, just_read_file },   /* regexp matching only */    { "yacc",      Yacc_help,Yacc_entries,Yacc_suffixes,NULL,NULL,TRUE},
781    { NULL, FALSE, NULL }                /* end of list */    { "auto",      auto_help },                      /* default guessing scheme */
782      { "none",      none_help,      just_read_file }, /* regexp matching only */
783      { NULL }                /* end of list */
784  };  };
785    
786    
# Line 669  default file names and dot suffixes:"); Line 803  default file names and dot suffixes:");
803            printf (" .%s", *ext);            printf (" .%s", *ext);
804        puts ("");        puts ("");
805      }      }
806    puts ("Where `auto' means use default language for files based on file\n\    puts ("where `auto' means use default language for files based on file\n\
807  name suffix, and `none' means only do regexp processing on files.\n\  name suffix, and `none' means only do regexp processing on files.\n\
808  If no language is specified and no matching suffix is found,\n\  If no language is specified and no matching suffix is found,\n\
809  the first line of the file is read for a sharp-bang (#!) sequence\n\  the first line of the file is read for a sharp-bang (#!) sequence\n\
810  followed by the name of an interpreter.  If no such sequence is found,\n\  followed by the name of an interpreter.  If no such sequence is found,\n\
811  Fortran is tried first; if no tags are found, C is tried next.\n\  Fortran is tried first; if no tags are found, C is tried next.\n\
812  When parsing any C file, a \"class\" keyword switches to C++.\n\  When parsing any C file, a \"class\" or \"template\" keyword\n\
813  Compressed files are supported using gzip and bzip2.");  switches to C++.");
814      puts ("Compressed files are supported using gzip and bzip2.\n\
815    \n\
816    For detailed help on a given language use, for example,\n\
817    etags --help --lang=ada.");
818  }  }
819    
820  #ifndef EMACS_NAME  #ifndef EMACS_NAME
821  # define EMACS_NAME "GNU Emacs"  # define EMACS_NAME "standalone"
822  #endif  #endif
823  #ifndef VERSION  #ifndef VERSION
824  # define VERSION "21"  # define VERSION "version"
825  #endif  #endif
826  static void  static void
827  print_version ()  print_version ()
# Line 696  print_version () Line 834  print_version ()
834  }  }
835    
836  static void  static void
837  print_help ()  print_help (argbuffer)
838         argument *argbuffer;
839  {  {
840      bool help_for_lang = FALSE;
841    
842      for (; argbuffer->arg_type != at_end; argbuffer++)
843        if (argbuffer->arg_type == at_language)
844          {
845            if (help_for_lang)
846              puts ("");
847            puts (argbuffer->lang->help);
848            help_for_lang = TRUE;
849          }
850    
851      if (help_for_lang)
852        exit (GOOD);
853    
854    printf ("Usage: %s [options] [[regex-option ...] file-name] ...\n\    printf ("Usage: %s [options] [[regex-option ...] file-name] ...\n\
855  \n\  \n\
856  These are the options accepted by %s.\n", progname, progname);  These are the options accepted by %s.\n", progname, progname);
# Line 726  Relative ones are stored relative to the Line 879  Relative ones are stored relative to the
879    /* This option is mostly obsolete, because etags can now automatically    /* This option is mostly obsolete, because etags can now automatically
880       detect C++.  Retained for backward compatibility and for debugging and       detect C++.  Retained for backward compatibility and for debugging and
881       experimentation.  In principle, we could want to tag as C++ even       experimentation.  In principle, we could want to tag as C++ even
882       before any "class" keyword.       before any "class" or "template" keyword.
883    puts ("-C, --c++\n\    puts ("-C, --c++\n\
884          Treat files whose name suffix defaults to C language as C++ files.");          Treat files whose name suffix defaults to C language as C++ files.");
885    */    */
# Line 765  Relative ones are stored relative to the Line 918  Relative ones are stored relative to the
918          Do not create tag entries for global variables in some\n\          Do not create tag entries for global variables in some\n\
919          languages.  This makes the tags file smaller.");          languages.  This makes the tags file smaller.");
920    puts ("--members\n\    puts ("--members\n\
921          Create tag entries for member variables in C and derived languages.");          Create tag entries for members of structures in some languages.");
922    
923  #ifdef ETAGS_REGEXPS  #ifdef ETAGS_REGEXPS
924    puts ("-r /REGEXP/, --regex=/REGEXP/ or --regex=@regexfile\n\    puts ("-r REGEXP, --regex=REGEXP or --regex=@regexfile\n\
925          Make a tag for each line matching pattern REGEXP in the following\n\          Make a tag for each line matching a regular expression pattern\n\
926          files.  {LANGUAGE}/REGEXP/ uses REGEXP for LANGUAGE files only.\n\          in the following files.  {LANGUAGE}REGEXP uses REGEXP for LANGUAGE\n\
927          regexfile is a file containing one REGEXP per line.\n\          files only.  REGEXFILE is a file containing one REGEXP per line.\n\
928          REGEXP is anchored (as if preceded by ^).\n\          REGEXP takes the form /TAGREGEXP/TAGNAME/MODS, where TAGNAME/ is\n\
929          The form /REGEXP/NAME/ creates a named tag.\n\          optional.  The TAGREGEXP pattern is anchored (as if preceded by ^).");
930      puts ("       If TAGNAME/ is present, the tags created are named.\n\
931          For example Tcl named tags can be created with:\n\          For example Tcl named tags can be created with:\n\
932          --regex=\"/proc[ \\t]+\\([^ \\t]+\\)/\\1/.\"");            --regex=\"/proc[ \\t]+\\([^ \\t]+\\)/\\1/.\".\n\
933    puts ("-c /REGEXP/, --ignore-case-regex=/REGEXP/ or --ignore-case-regex=@regexfile\n\          MODS are optional one-letter modifiers: `i' means to ignore case,\n\
934          Like -r, --regex but ignore case when matching expressions.");          `m' means to allow multi-line matches, `s' implies `m' and\n\
935            causes dot to match any character, including newline.");
936    puts ("-R, --no-regex\n\    puts ("-R, --no-regex\n\
937          Don't create tags from regexps for the following files.");          Don't create tags from regexps for the following files.");
938  #endif /* ETAGS_REGEXPS */  #endif /* ETAGS_REGEXPS */
939    puts ("-I, --ignore-indentation\n\    puts ("-I, --ignore-indentation\n\
940          Don't rely on indentation quite as much as normal.  Currently,\n\          In C and C++ do not assume that a closing brace in the first\n\
941          this means not to assume that a closing brace in the first\n\          column is the final brace of a function or structure definition.");
         column is the final brace of a function or structure\n\  
         definition in C and C++.");  
942    puts ("-o FILE, --output=FILE\n\    puts ("-o FILE, --output=FILE\n\
943          Write the tags to FILE.");          Write the tags to FILE.");
944    puts ("--parse-stdin=NAME\n\    puts ("--parse-stdin=NAME\n\
# Line 828  Relative ones are stored relative to the Line 981  Relative ones are stored relative to the
981    puts ("-V, --version\n\    puts ("-V, --version\n\
982          Print the version of the program.\n\          Print the version of the program.\n\
983  -h, --help\n\  -h, --help\n\
984          Print this help message.");          Print this help message.\n\
985            Followed by one or more `--language' options prints detailed\n\
986            help about tag generation for the specified languages.");
987    
988    print_language_names ();    print_language_names ();
989    
# Line 975  main (argc, argv) Line 1130  main (argc, argv)
1130    argument *argbuffer;    argument *argbuffer;
1131    int current_arg, file_count;    int current_arg, file_count;
1132    linebuffer filename_lb;    linebuffer filename_lb;
1133      bool help_asked = FALSE;
1134  #ifdef VMS  #ifdef VMS
1135    bool got_err;    bool got_err;
1136  #endif  #endif
# Line 996  main (argc, argv) Line 1152  main (argc, argv)
1152       is small. */       is small. */
1153    argbuffer = xnew (argc, argument);    argbuffer = xnew (argc, argument);
1154    
 #ifdef ETAGS_REGEXPS  
   /* Set syntax for regular expression routines. */  
   re_set_syntax (RE_SYNTAX_EMACS | RE_INTERVALS);  
   /* Translation table for case-insensitive search. */  
   for (i = 0; i < CHAR_SET_SIZE; i++)  
     lc_trans[i] = lowcase (i);  
 #endif /* ETAGS_REGEXPS */  
   
1155    /*    /*
1156     * If etags, always find typedefs and structure tags.  Why not?     * If etags, always find typedefs and structure tags.  Why not?
1157     * Also default to find macro constants, enum constants and     * Also default to find macro constants, enum constants and
# Line 1061  main (argc, argv) Line 1209  main (argc, argv)
1209            {            {
1210              error ("-o option may only be given once.", (char *)NULL);              error ("-o option may only be given once.", (char *)NULL);
1211              suggest_asking_for_help ();              suggest_asking_for_help ();
1212                /* NOTREACHED */
1213            }            }
1214          tagfile = optarg;          tagfile = optarg;
1215          break;          break;
1216        case 'I':        case 'I':
1217        case 'S':         /* for backward compatibility */        case 'S':         /* for backward compatibility */
1218          noindentypedefs = TRUE;          ignoreindent = TRUE;
1219          break;          break;
1220        case 'l':        case 'l':
1221          {          {
# Line 1079  main (argc, argv) Line 1228  main (argc, argv)
1228              }              }
1229          }          }
1230          break;          break;
1231          case 'c':
1232            /* Backward compatibility: support obsolete --ignore-case-regexp. */
1233            optarg = concat (optarg, "i", ""); /* memory leak here */
1234            /* FALLTHRU */
1235        case 'r':        case 'r':
1236          argbuffer[current_arg].arg_type = at_regexp;          argbuffer[current_arg].arg_type = at_regexp;
1237          argbuffer[current_arg].what = optarg;          argbuffer[current_arg].what = optarg;
# Line 1089  main (argc, argv) Line 1242  main (argc, argv)
1242          argbuffer[current_arg].what = NULL;          argbuffer[current_arg].what = NULL;
1243          ++current_arg;          ++current_arg;
1244          break;          break;
       case 'c':  
         argbuffer[current_arg].arg_type = at_icregexp;  
         argbuffer[current_arg].what = optarg;  
         ++current_arg;  
         break;  
1245        case 'V':        case 'V':
1246          print_version ();          print_version ();
1247          break;          break;
1248        case 'h':        case 'h':
1249        case 'H':        case 'H':
1250          print_help ();          help_asked = TRUE;
1251          break;          break;
1252    
1253          /* Etags options */          /* Etags options */
# Line 1118  main (argc, argv) Line 1266  main (argc, argv)
1266        case 'w': no_warnings = TRUE;                             break;        case 'w': no_warnings = TRUE;                             break;
1267        default:        default:
1268          suggest_asking_for_help ();          suggest_asking_for_help ();
1269            /* NOTREACHED */
1270        }        }
1271    
1272    for (; optind < argc; ++optind)    for (; optind < argc; optind++)
1273      {      {
1274        argbuffer[current_arg].arg_type = at_filename;        argbuffer[current_arg].arg_type = at_filename;
1275        argbuffer[current_arg].what = argv[optind];        argbuffer[current_arg].what = argv[optind];
# Line 1128  main (argc, argv) Line 1277  main (argc, argv)
1277        ++file_count;        ++file_count;
1278      }      }
1279    
1280      argbuffer[current_arg].arg_type = at_end;
1281    
1282      if (help_asked)
1283        print_help (argbuffer);
1284        /* NOTREACHED */
1285    
1286    if (nincluded_files == 0 && file_count == 0)    if (nincluded_files == 0 && file_count == 0)
1287      {      {
1288        error ("no input files specified.", (char *)NULL);        error ("no input files specified.", (char *)NULL);
1289        suggest_asking_for_help ();        suggest_asking_for_help ();
1290          /* NOTREACHED */
1291      }      }
1292    
1293    if (tagfile == NULL)    if (tagfile == NULL)
# Line 1150  main (argc, argv) Line 1306  main (argc, argv)
1306    
1307    init ();                      /* set up boolean "functions" */    init ();                      /* set up boolean "functions" */
1308    
1309    initbuffer (&lb);    linebuffer_init (&lb);
1310    initbuffer (&filename_lb);    linebuffer_init (&filename_lb);
1311      linebuffer_init (&filebuf);
1312      linebuffer_init (&token_name);
1313    
1314    if (!CTAGS)    if (!CTAGS)
1315      {      {
# Line 1174  main (argc, argv) Line 1332  main (argc, argv)
1332    /*    /*
1333     * Loop through files finding functions.     * Loop through files finding functions.
1334     */     */
1335    for (i = 0; i < current_arg; ++i)    for (i = 0; i < current_arg; i++)
1336      {      {
1337        static language *lang;    /* non-NULL if language is forced */        static language *lang;    /* non-NULL if language is forced */
1338        char *this_file;        char *this_file;
# Line 1186  main (argc, argv) Line 1344  main (argc, argv)
1344            break;            break;
1345  #ifdef ETAGS_REGEXPS  #ifdef ETAGS_REGEXPS
1346          case at_regexp:          case at_regexp:
1347            analyse_regex (argbuffer[i].what, FALSE);            analyse_regex (argbuffer[i].what);
           break;  
         case at_icregexp:  
           analyse_regex (argbuffer[i].what, TRUE);  
1348            break;            break;
1349  #endif  #endif
1350          case at_filename:          case at_filename:
# Line 1232  main (argc, argv) Line 1387  main (argc, argv)
1387      }      }
1388    
1389  #ifdef ETAGS_REGEXPS  #ifdef ETAGS_REGEXPS
1390    free_patterns ();    free_regexps ();
1391  #endif /* ETAGS_REGEXPS */  #endif /* ETAGS_REGEXPS */
1392      free (lb.buffer);
1393      free (filebuf.buffer);
1394      free (token_name.buffer);
1395    
1396    if (!CTAGS || cxref_style)    if (!CTAGS || cxref_style)
1397      {      {
1398        put_entries (nodehead);        put_entries (nodehead);   /* write the remainig tags (ETAGS) */
1399        free_tree (nodehead);        free_tree (nodehead);
1400        nodehead = NULL;        nodehead = NULL;
1401        if (!CTAGS)        if (!CTAGS)
1402          while (nincluded_files-- > 0)          {
1403            fprintf (tagf, "\f\n%s,include\n", *included_files++);            fdesc *fdp;
1404    
1405              /* Output file entries that have no tags. */
1406              for (fdp = fdhead; fdp != NULL; fdp = fdp->next)
1407                if (!fdp->written)
1408                  fprintf (tagf, "\f\n%s,0\n", fdp->taggedfname);
1409    
1410              while (nincluded_files-- > 0)
1411                fprintf (tagf, "\f\n%s,include\n", *included_files++);
1412            }
1413    
1414        if (fclose (tagf) == EOF)        if (fclose (tagf) == EOF)
1415          pfatal (tagfile);          pfatal (tagfile);
# Line 1274  main (argc, argv) Line 1441  main (argc, argv)
1441    tagf = fopen (tagfile, append_to_tagfile ? "a" : "w");    tagf = fopen (tagfile, append_to_tagfile ? "a" : "w");
1442    if (tagf == NULL)    if (tagf == NULL)
1443      pfatal (tagfile);      pfatal (tagfile);
1444    put_entries (nodehead);    put_entries (nodehead);       /* write all the tags (CTAGS) */
1445    free_tree (nodehead);    free_tree (nodehead);
1446    nodehead = NULL;    nodehead = NULL;
1447    if (fclose (tagf) == EOF)    if (fclose (tagf) == EOF)
# Line 1571  process_file (fh, fn, lang) Line 1738  process_file (fh, fn, lang)
1738      }      }
1739    fdp->usecharno = TRUE;        /* use char position when making tags */    fdp->usecharno = TRUE;        /* use char position when making tags */
1740    fdp->prop = NULL;    fdp->prop = NULL;
1741      fdp->written = FALSE;         /* not written on tags file yet */
1742    
1743    fdhead = fdp;    fdhead = fdp;
1744    curfdp = fdhead;              /* the current file description */    curfdp = fdhead;              /* the current file description */
# Line 1648  find_entries (inf) Line 1816  find_entries (inf)
1816       FILE *inf;       FILE *inf;
1817  {  {
1818    char *cp;    char *cp;
   node *old_last_node;  
1819    language *lang = curfdp->lang;    language *lang = curfdp->lang;
1820    Lang_function *parser = NULL;    Lang_function *parser = NULL;
1821    
# Line 1703  find_entries (inf) Line 1870  find_entries (inf)
1870    /* We rewind here, even if inf may be a pipe.  We fail if the    /* We rewind here, even if inf may be a pipe.  We fail if the
1871       length of the first line is longer than the pipe block size,       length of the first line is longer than the pipe block size,
1872       which is unlikely. */       which is unlikely. */
1873      rewind (inf);    rewind (inf);
1874    
1875    /* Else try to guess the language given the case insensitive file name. */    /* Else try to guess the language given the case insensitive file name. */
1876    if (parser == NULL)    if (parser == NULL)
# Line 1716  find_entries (inf) Line 1883  find_entries (inf)
1883          }          }
1884      }      }
1885    
1886      /* Else try Fortran or C. */
1887      if (parser == NULL)
1888        {
1889          node *old_last_node = last_node;
1890    
1891          curfdp->lang = get_language_from_langname ("fortran");
1892          find_entries (inf);
1893    
1894          if (old_last_node == last_node)
1895            /* No Fortran entries found.  Try C. */
1896            {
1897              /* We do not tag if rewind fails.
1898                 Only the file name will be recorded in the tags file. */
1899              rewind (inf);
1900              curfdp->lang = get_language_from_langname (cplusplus ? "c++" : "c");
1901              find_entries (inf);
1902            }
1903          return;
1904        }
1905    
1906    if (!no_line_directive    if (!no_line_directive
1907        && curfdp->lang != NULL && curfdp->lang->metasource)        && curfdp->lang != NULL && curfdp->lang->metasource)
1908      /* It may be that this is a bingo.y file, and we already parsed a bingo.c      /* It may be that this is a bingo.y file, and we already parsed a bingo.c
# Line 1733  find_entries (inf) Line 1920  find_entries (inf)
1920            {            {
1921              fdesc *badfdp = *fdpp;              fdesc *badfdp = *fdpp;
1922    
1923              if (DEBUG)              /* Delete the tags referring to badfdp->taggedfname
1924                fprintf (stderr,                 that were obtained from badfdp->infname. */
                        "Removing references to \"%s\" obtained from \"%s\"\n",  
                        badfdp->taggedfname, badfdp->infname);  
   
             /* Delete the tags referring to badfdp. */  
1925              invalidate_nodes (badfdp, &nodehead);              invalidate_nodes (badfdp, &nodehead);
1926    
1927              *fdpp = badfdp->next; /* remove the bad description from the list */              *fdpp = badfdp->next; /* remove the bad description from the list */
# Line 1748  find_entries (inf) Line 1931  find_entries (inf)
1931            fdpp = &(*fdpp)->next; /* advance the list pointer */            fdpp = &(*fdpp)->next; /* advance the list pointer */
1932      }      }
1933    
1934    if (parser != NULL)    assert (parser != NULL);
1935    
1936      /* Generic initialisations before reading from file. */
1937      linebuffer_setlen (&filebuf, 0); /* reset the file buffer */
1938    
1939      /* Generic initialisations before parsing file with readline. */
1940      lineno = 0;                  /* reset global line number */
1941      charno = 0;                  /* reset global char number */
1942      linecharno = 0;              /* reset global char number of line start */
1943    
1944      parser (inf);
1945    
1946    #ifdef ETAGS_REGEXPS
1947      regex_tag_multiline ();
1948    #endif /* ETAGS_REGEXPS */
1949    }
1950    
1951    
1952    /*
1953     * Check whether an implicitly named tag should be created,
1954     * then call `pfnote'.
1955     * NAME is a string that is internally copied by this function.
1956     *
1957     * TAGS format specification
1958     * Idea by Sam Kendall <kendall@mv.mv.com> (1997)
1959     * The following is explained in some more detail in etc/ETAGS.EBNF.
1960     *
1961     * make_tag creates tags with "implicit tag names" (unnamed tags)
1962     * if the following are all true, assuming NONAM=" \f\t\n\r()=,;":
1963     *  1. NAME does not contain any of the characters in NONAM;
1964     *  2. LINESTART contains name as either a rightmost, or rightmost but
1965     *     one character, substring;
1966     *  3. the character, if any, immediately before NAME in LINESTART must
1967     *     be a character in NONAM;
1968     *  4. the character, if any, immediately after NAME in LINESTART must
1969     *     also be a character in NONAM.
1970     *
1971     * The implementation uses the notinname() macro, which recognises the
1972     * characters stored in the string `nonam'.
1973     * etags.el needs to use the same characters that are in NONAM.
1974     */
1975    static void
1976    make_tag (name, namelen, is_func, linestart, linelen, lno, cno)
1977         char *name;                /* tag name, or NULL if unnamed */
1978         int namelen;               /* tag length */
1979         bool is_func;              /* tag is a function */
1980         char *linestart;           /* start of the line where tag is */
1981         int linelen;               /* length of the line where tag is */
1982         int lno;                   /* line number */
1983         long cno;                  /* character number */
1984    {
1985      bool named = (name != NULL && namelen > 0);
1986    
1987      if (!CTAGS && named)          /* maybe set named to false */
1988        /* Let's try to make an implicit tag name, that is, create an unnamed tag
1989           such that etags.el can guess a name from it. */
1990      {      {
1991        /* Generic initialisations before reading from file. */        int i;
1992        lineno = 0;               /* reset global line number */        register char *cp = name;
       charno = 0;               /* reset global char number */  
       linecharno = 0;           /* reset global char number of line start */  
1993    
1994        parser (inf);        for (i = 0; i < namelen; i++)
1995        return;          if (notinname (*cp++))
1996              break;
1997          if (i == namelen)                         /* rule #1 */
1998            {
1999              cp = linestart + linelen - namelen;
2000              if (notinname (linestart[linelen-1]))
2001                cp -= 1;                            /* rule #4 */
2002              if (cp >= linestart                   /* rule #2 */
2003                  && (cp == linestart
2004                      || notinname (cp[-1]))        /* rule #3 */
2005                  && strneq (name, cp, namelen))    /* rule #2 */
2006                named = FALSE;      /* use implicit tag name */
2007            }
2008      }      }
2009    
2010    /* Else try Fortran. */    if (named)
2011    old_last_node = last_node;      name = savenstr (name, namelen);
2012    curfdp->lang = get_language_from_langname ("fortran");    else
2013    find_entries (inf);      name = NULL;
2014      pfnote (name, is_func, linestart, linelen, lno, cno);
   if (old_last_node == last_node)  
     /* No Fortran entries found.  Try C. */  
     {  
       /* We do not tag if rewind fails.  
          Only the file name will be recorded in the tags file. */  
       rewind (inf);  
       curfdp->lang = get_language_from_langname (cplusplus ? "c++" : "c");  
       find_entries (inf);  
     }  
   return;  
2015  }  }
2016    
   
2017  /* Record a tag. */  /* Record a tag. */
2018  static void  static void
2019  pfnote (name, is_func, linestart, linelen, lno, cno)  pfnote (name, is_func, linestart, linelen, lno, cno)
# Line 1789  pfnote (name, is_func, linestart, linele Line 2026  pfnote (name, is_func, linestart, linele
2026  {  {
2027    register node *np;    register node *np;
2028    
2029      assert (name == NULL || name[0] != '\0');
2030    if (CTAGS && name == NULL)    if (CTAGS && name == NULL)
2031      return;      return;
2032    
# Line 1823  pfnote (name, is_func, linestart, linele Line 2061  pfnote (name, is_func, linestart, linele
2061    if (CTAGS && !cxref_style)    if (CTAGS && !cxref_style)
2062      {      {
2063        if (strlen (linestart) < 50)        if (strlen (linestart) < 50)
2064          np->pat = concat (linestart, "$", "");          np->regex = concat (linestart, "$", "");
2065        else        else
2066          np->pat = savenstr (linestart, 50);          np->regex = savenstr (linestart, 50);
2067      }      }
2068    else    else
2069      np->pat = savenstr (linestart, linelen);      np->regex = savenstr (linestart, linelen);
2070    
2071    add_node (np, &nodehead);    add_node (np, &nodehead);
2072  }  }
2073    
2074  /*  /*
  * TAGS format specification  
  * Idea by Sam Kendall <kendall@mv.mv.com> (1997)  
  *  
  * pfnote should emit the optimized form [unnamed tag] only if:  
  *  1. name does not contain any of the characters " \t\r\n(),;";  
  *  2. linestart contains name as either a rightmost, or rightmost but  
  *     one character, substring;  
  *  3. the character, if any, immediately before name in linestart must  
  *     be one of the characters " \t(),;";  
  *  4. the character, if any, immediately after name in linestart must  
  *     also be one of the characters " \t(),;".  
  *  
  * The real implementation uses the notinname() macro, which recognises  
  * characters slightly different from " \t\r\n(),;".  See the variable  
  * `nonam'.  
  */  
 #define traditional_tag_style TRUE  
 static void  
 new_pfnote (name, namelen, is_func, linestart, linelen, lno, cno)  
      char *name;                /* tag name, or NULL if unnamed */  
      int namelen;               /* tag length */  
      bool is_func;              /* tag is a function */  
      char *linestart;           /* start of the line where tag is */  
      int linelen;               /* length of the line where tag is */  
      int lno;                   /* line number */  
      long cno;                  /* character number */  
 {  
   register char *cp;  
   bool named;  
   
   named = TRUE;  
   if (!CTAGS)  
     {  
       for (cp = name; !notinname (*cp); cp++)  
         continue;  
       if (*cp == '\0')                          /* rule #1 */  
         {  
           cp = linestart + linelen - namelen;  
           if (notinname (linestart[linelen-1]))  
             cp -= 1;                            /* rule #4 */  
           if (cp >= linestart                   /* rule #2 */  
               && (cp == linestart  
                   || notinname (cp[-1]))        /* rule #3 */  
               && strneq (name, cp, namelen))    /* rule #2 */  
             named = FALSE;      /* use unnamed tag */  
         }  
     }  
   
   if (named)  
     name = savenstr (name, namelen);  
   else  
     name = NULL;  
   pfnote (name, is_func, linestart, linelen, lno, cno);  
 }  
   
 /*  
2075   * free_tree ()   * free_tree ()
2076   *      recurse on left children, iterate on right children.   *      recurse on left children, iterate on right children.
2077   */   */
# Line 1903  free_tree (np) Line 2085  free_tree (np)
2085        free_tree (np->left);        free_tree (np->left);
2086        if (np->name != NULL)        if (np->name != NULL)
2087          free (np->name);          free (np->name);
2088        free (np->pat);        free (np->regex);
2089        free (np);        free (np);
2090        np = node_right;        np = node_right;
2091      }      }
# Line 2030  invalidate_nodes (badfdp, npp) Line 2212  invalidate_nodes (badfdp, npp)
2212        if (np->left != NULL)        if (np->left != NULL)
2213          invalidate_nodes (badfdp, &np->left);          invalidate_nodes (badfdp, &np->left);
2214        if (np->fdp == badfdp)        if (np->fdp == badfdp)
2215          np-> valid = FALSE;          np->valid = FALSE;
2216        if (np->right != NULL)        if (np->right != NULL)
2217          invalidate_nodes (badfdp, &np->right);          invalidate_nodes (badfdp, &np->right);
2218      }      }
2219    else    else
2220      {      {
2221        node **next = &np->left;        assert (np->fdp != NULL);
2222        if (np->fdp == badfdp)        if (np->fdp == badfdp)
2223          {          {
2224            *npp = *next;         /* detach the sublist from the list */            *npp = np->left;      /* detach the sublist from the list */
2225            np->left = NULL;      /* isolate it */            np->left = NULL;      /* isolate it */
2226            free_tree (np);       /* free it */            free_tree (np);       /* free it */
2227              invalidate_nodes (badfdp, npp);
2228          }          }
2229        invalidate_nodes (badfdp, next);        else
2230            invalidate_nodes (badfdp, &np->left);
2231      }      }
2232  }  }
2233    
# Line 2075  total_size_of_entries (np) Line 2259  total_size_of_entries (np)
2259    register int total = 0;    register int total = 0;
2260    
2261    for (; np != NULL; np = np->right)    for (; np != NULL; np = np->right)
2262      {      if (np->valid)
2263        total += strlen (np->pat) + 1;            /* pat\177 */        {
2264        if (np->name != NULL)          total += strlen (np->regex) + 1;                /* pat\177 */
2265          total += strlen (np->name) + 1;         /* name\001 */          if (np->name != NULL)
2266        total += number_len ((long) np->lno) + 1; /* lno, */            total += strlen (np->name) + 1;               /* name\001 */
2267        if (np->cno != invalidcharno)             /* cno */          total += number_len ((long) np->lno) + 1;       /* lno, */
2268          total += number_len (np->cno);          if (np->cno != invalidcharno)                   /* cno */
2269        total += 1;                               /* newline */            total += number_len (np->cno);
2270      }          total += 1;                                     /* newline */
2271          }
2272    
2273    return total;    return total;
2274  }  }
# Line 2113  put_entries (np) Line 2298  put_entries (np)
2298                fdp = np->fdp;                fdp = np->fdp;
2299                fprintf (tagf, "\f\n%s,%d\n",                fprintf (tagf, "\f\n%s,%d\n",
2300                         fdp->taggedfname, total_size_of_entries (np));                         fdp->taggedfname, total_size_of_entries (np));
2301                  fdp->written = TRUE;
2302              }              }
2303            fputs (np->pat, tagf);            fputs (np->regex, tagf);
2304            fputc ('\177', tagf);            fputc ('\177', tagf);
2305            if (np->name != NULL)            if (np->name != NULL)
2306              {              {
# Line 2139  put_entries (np) Line 2325  put_entries (np)
2325                           np->name, np->fdp->taggedfname, (np->lno + 63) / 64);                           np->name, np->fdp->taggedfname, (np->lno + 63) / 64);
2326                else                else
2327                  fprintf (stdout, "%-16s %3d %-16s %s\n",                  fprintf (stdout, "%-16s %3d %-16s %s\n",
2328                           np->name, np->lno, np->fdp->taggedfname, np->pat);                           np->name, np->lno, np->fdp->taggedfname, np->regex);
2329              }              }
2330            else            else
2331              {              {
# Line 2150  put_entries (np) Line 2336  put_entries (np)
2336                    putc (searchar, tagf);                    putc (searchar, tagf);
2337                    putc ('^', tagf);                    putc ('^', tagf);
2338    
2339                    for (sp = np->pat; *sp; sp++)                    for (sp = np->regex; *sp; sp++)
2340                      {                      {
2341                        if (*sp == '\\' || *sp == searchar)                        if (*sp == '\\' || *sp == searchar)
2342                          putc ('\\', tagf);                          putc ('\\', tagf);
# Line 2534  static enum Line 2720  static enum
2720   */   */
2721  static struct tok  static struct tok
2722  {  {
2723    bool valid;    char *line;                   /* string containing the token */
2724    bool named;    int offset;                   /* where the token starts in LINE */
2725    int offset;    int length;                   /* token length */
2726    int length;    /*
2727    int lineno;      The previous members can be used to pass strings around for generic
2728    long linepos;      purposes.  The following ones specifically refer to creating tags.  In this
2729    char *line;      case the token contained here is the pattern that will be used to create a
2730        tag.
2731      */
2732      bool valid;                   /* do not create a tag; the token should be
2733                                       invalidated whenever a state machine is
2734                                       reset prematurely */
2735      bool named;                   /* create a named tag */
2736      int lineno;                   /* source line number of tag */
2737      long linepos;                 /* source char number of tag */
2738  } token;                        /* latest token read */  } token;                        /* latest token read */
 static linebuffer token_name;   /* its name */  
2739    
2740  /*  /*
2741   * Variables and functions for dealing with nested structures.   * Variables and functions for dealing with nested structures.
# Line 2560  static struct { Line 2753  static struct {
2753  } cstack;                       /* stack for nested declaration tags */  } cstack;                       /* stack for nested declaration tags */
2754  /* Current struct nesting depth (namespace, class, struct, union, enum). */  /* Current struct nesting depth (namespace, class, struct, union, enum). */
2755  #define nestlev         (cstack.nl)  #define nestlev         (cstack.nl)
2756  /* After struct keyword or in struct body, not inside an nested function. */  /* After struct keyword or in struct body, not inside a nested function. */
2757  #define instruct        (structdef == snone && nestlev > 0                      \  #define instruct        (structdef == snone && nestlev > 0                      \
2758                           && cblev == cstack.cblev[nestlev-1] + 1)                           && cblev == cstack.cblev[nestlev-1] + 1)
2759    
# Line 2778  consider_token (str, len, c, c_extp, cbl Line 2971  consider_token (str, len, c, c_extp, cbl
2971        return FALSE;        return FALSE;
2972      case st_C_template:      case st_C_template:
2973      case st_C_class:      case st_C_class:
2974        if (cblev == 0        if ((*c_extp & C_AUTO)    /* automatic detection of C++ language */
2975            && (*c_extp & C_AUTO) /* automatic detection of C++ language */            && cblev == 0
2976            && definedef == dnone && structdef == snone            && definedef == dnone && structdef == snone
2977            && typdef == tnone && fvdef == fvnone)            && typdef == tnone && fvdef == fvnone)
2978          *c_extp = (*c_extp | C_PLPL) & ~C_AUTO;          *c_extp = (*c_extp | C_PLPL) & ~C_AUTO;
# Line 2884  consider_token (str, len, c, c_extp, cbl Line 3077  consider_token (str, len, c, c_extp, cbl
3077        fvextern = TRUE;        fvextern = TRUE;
3078        /* FALLTHRU */        /* FALLTHRU */
3079      case st_C_typespec:      case st_C_typespec:
3080        if (fvdef != finlist && fvdef != fignore && fvdef != vignore)        switch  (fvdef)
3081          fvdef = fvnone;         /* should be useless */          {
3082            case finlist:
3083            case flistseen:
3084            case fignore:
3085            case vignore:
3086              break;
3087            default:
3088              fvdef = fvnone;
3089            }
3090        return FALSE;        return FALSE;
3091      case st_C_ignore:      case st_C_ignore:
3092        fvextern = FALSE;        fvextern = FALSE;
# Line 2915  consider_token (str, len, c, c_extp, cbl Line 3116  consider_token (str, len, c, c_extp, cbl
3116                fvdef = vignore;                fvdef = vignore;
3117                return FALSE;                return FALSE;
3118              }              }
3119            if ((*c_extp & C_PLPL) && strneq (str+len-10, "::operator", 10))            if (strneq (str+len-10, "::operator", 10))
3120              {              {
3121                  if (*c_extp & C_AUTO) /* automatic detection of C++ */
3122                    *c_extp = (*c_extp | C_PLPL) & ~C_AUTO;
3123                fvdef = foperator;                fvdef = foperator;
3124                *is_func_or_var = TRUE;                *is_func_or_var = TRUE;
3125                return TRUE;                return TRUE;
# Line 2953  static struct Line 3156  static struct
3156  #define curlinepos (lbs[curndx].linepos)  #define curlinepos (lbs[curndx].linepos)
3157  #define newlinepos (lbs[newndx].linepos)  #define newlinepos (lbs[newndx].linepos)
3158    
3159    #define plainc ((c_ext & C_EXT) == C_PLAIN)
3160    #define cplpl (c_ext & C_PLPL)
3161    #define cjava ((c_ext & C_JAVA) == C_JAVA)
3162    
3163  #define CNL_SAVE_DEFINEDEF()                                            \  #define CNL_SAVE_DEFINEDEF()                                            \
3164  do {                                                                    \  do {                                                                    \
3165    curlinepos = charno;                                                  \    curlinepos = charno;                                                  \
# Line 2980  make_C_tag (isfun) Line 3187  make_C_tag (isfun)
3187  {  {
3188    /* This function should never be called when token.valid is FALSE, but    /* This function should never be called when token.valid is FALSE, but
3189       we must protect against invalid input or internal errors. */       we must protect against invalid input or internal errors. */
3190    if (DEBUG || token.valid)    if (!DEBUG && !token.valid)
3191      {      return;
       if (traditional_tag_style)  
         {  
           /* This was the original code.  Now we call new_pfnote instead,  
              which uses the new method for naming tags (see new_pfnote). */  
           char *name = NULL;  
3192    
3193            if (CTAGS || token.named)    if (token.valid)
3194              name = savestr (token_name.buffer);      make_tag (token_name.buffer, token_name.len, isfun, token.line,
3195            if (DEBUG && !token.valid)                token.offset+token.length+1, token.lineno, token.linepos);
3196              {    else                          /* this case is optimised away if !DEBUG */
3197                if (token.named)      make_tag (concat ("INVALID TOKEN:-->", token_name.buffer, ""),
3198                  name = concat (name, "##invalid##", "");                token_name.len + 17, isfun, token.line,
3199                else                token.offset+token.length+1, token.lineno, token.linepos);
3200                  name = savestr ("##invalid##");  
3201              }    token.valid = FALSE;
           pfnote (name, isfun, token.line,  
                   token.offset+token.length+1, token.lineno, token.linepos);  
         }  
       else  
         new_pfnote (token_name.buffer, token_name.len, isfun, token.line,  
                     token.offset+token.length+1, token.lineno, token.linepos);  
       token.valid = FALSE;  
     }  
3202  }  }
3203    
3204    
# Line 3030  C_entries (c_ext, inf) Line 3224  C_entries (c_ext, inf)
3224    int parlev;                   /* current parenthesis level */    int parlev;                   /* current parenthesis level */
3225    int typdefcblev;              /* cblev where a typedef struct body begun */    int typdefcblev;              /* cblev where a typedef struct body begun */
3226    bool incomm, inquote, inchar, quotednl, midtoken;    bool incomm, inquote, inchar, quotednl, midtoken;
   bool cplpl, cjava;  
3227    bool yacc_rules;              /* in the rules part of a yacc file */    bool yacc_rules;              /* in the rules part of a yacc file */
3228    struct tok savetoken;         /* token saved during preprocessor handling */    struct tok savetoken;         /* token saved during preprocessor handling */
3229    
3230    
3231    initbuffer (&token_name);    linebuffer_init (&lbs[0].lb);
3232    initbuffer (&lbs[0].lb);    linebuffer_init (&lbs[1].lb);
   initbuffer (&lbs[1].lb);  
3233    if (cstack.size == 0)    if (cstack.size == 0)
3234      {      {
3235        cstack.size = (DEBUG) ? 1 : 4;        cstack.size = (DEBUG) ? 1 : 4;
# Line 3058  C_entries (c_ext, inf) Line 3250  C_entries (c_ext, inf)
3250    token.valid = savetoken.valid = FALSE;    token.valid = savetoken.valid = FALSE;
3251    cblev = 0;    cblev = 0;
3252    parlev = 0;    parlev = 0;
   cplpl = (c_ext & C_PLPL) == C_PLPL;  
   cjava = (c_ext & C_JAVA) == C_JAVA;  
3253    if (cjava)    if (cjava)
3254      { qualifier = "."; qlen = 1; }      { qualifier = "."; qlen = 1; }
3255    else    else
# Line 3225  C_entries (c_ext, inf) Line 3415  C_entries (c_ext, inf)
3415              {              {
3416                if (endtoken (c))                if (endtoken (c))
3417                  {                  {
3418                    if (c == ':' && cplpl && *lp == ':' && begtoken (lp[1]))                    if (c == ':' && *lp == ':' && begtoken (lp[1]))
3419                        /* This handles :: in the middle,
3420                           but not at the beginning of an identifier.
3421                           Also, space-separated :: is not recognised. */
3422                      {                      {
3423                        /*                        if (c_ext & C_AUTO) /* automatic detection of C++ */
3424                         * This handles :: in the middle, but not at the                          c_ext = (c_ext | C_PLPL) & ~C_AUTO;
                        * beginning of an identifier.  Also, space-separated  
                        * :: is not recognised.  
                        */  
3425                        lp += 2;                        lp += 2;
3426                        toklen += 2;                        toklen += 2;
3427                        c = lp[-1];                        c = lp[-1];
# Line 3258  C_entries (c_ext, inf) Line 3448  C_entries (c_ext, inf)
3448                                toklen += lp - oldlp;                                toklen += lp - oldlp;
3449                              }                              }
3450                            token.named = FALSE;                            token.named = FALSE;
3451                            if ((c_ext & C_EXT)   /* not pure C */                            if (!plainc
3452                                && nestlev > 0 && definedef == dnone)                                && nestlev > 0 && definedef == dnone)
3453                              /* in struct body */                              /* in struct body */
3454                              {                              {
# Line 3374  C_entries (c_ext, inf) Line 3564  C_entries (c_ext, inf)
3564                        fvdef = finlist;                        fvdef = finlist;
3565                        continue;                        continue;
3566                      case flistseen:                      case flistseen:
3567                        make_C_tag (TRUE); /* a function */                        if (plainc || declarations)
3568                        fvdef = fignore;                          {
3569                              make_C_tag (TRUE); /* a function */
3570                              fvdef = fignore;
3571                            }
3572                        break;                        break;
3573                      case fvnameseen:                      case fvnameseen:
3574                        fvdef = fvnone;                        fvdef = fvnone;
# Line 3428  C_entries (c_ext, inf) Line 3621  C_entries (c_ext, inf)
3621                break;                break;
3622              }              }
3623            if (structdef == stagseen)            if (structdef == stagseen)
3624              structdef = scolonseen;              {
3625                  structdef = scolonseen;
3626                  break;
3627                }
3628              /* Should be useless, but may be work as a safety net. */
3629              if (cplpl && fvdef == flistseen)
3630                {
3631                  make_C_tag (TRUE); /* a function */
3632                  fvdef = fignore;
3633                  break;
3634                }
3635            break;            break;
3636          case ';':          case ';':
3637            if (definedef != dnone)            if (definedef != dnone)
# Line 3447  C_entries (c_ext, inf) Line 3650  C_entries (c_ext, inf)
3650                switch (fvdef)                switch (fvdef)
3651                  {                  {
3652                  case fignore:                  case fignore:
3653                    if (typdef == tignore)                    if (typdef == tignore || cplpl)
3654                      fvdef = fvnone;                      fvdef = fvnone;
3655                    break;                    break;
3656                  case fvnameseen:                  case fvnameseen:
# Line 3459  C_entries (c_ext, inf) Line 3662  C_entries (c_ext, inf)
3662                    token.valid = FALSE;                    token.valid = FALSE;
3663                    break;                    break;
3664                  case flistseen:                  case flistseen:
3665                    if ((declarations && typdef == tnone && !instruct)                    if (declarations
3666                        || (members && typdef != tignore && instruct))                        && (typdef == tnone || (typdef != tignore && instruct)))
3667                      make_C_tag (TRUE);  /* a function declaration */                      make_C_tag (TRUE);  /* a function declaration */
3668                    /* FALLTHRU */                    /* FALLTHRU */
3669                  default:                  default:
3670                    fvextern = FALSE;                    fvextern = FALSE;
3671                    fvdef = fvnone;                    fvdef = fvnone;
3672                    if (declarations                    if (declarations
3673                        && structdef == stagseen && (c_ext & C_PLPL))                         && cplpl && structdef == stagseen)
3674                      make_C_tag (FALSE); /* forward declaration */                      make_C_tag (FALSE); /* forward declaration */
3675                    else                    else
                     /* The following instruction invalidates the token.  
                        Probably the token should be invalidated in all other  
                        cases where some state machine is reset prematurely. */  
3676                      token.valid = FALSE;                      token.valid = FALSE;
3677                  } /* switch (fvdef) */                  } /* switch (fvdef) */
3678                /* FALLTHRU */                /* FALLTHRU */
# Line 3675  C_entries (c_ext, inf) Line 3875  C_entries (c_ext, inf)
3875            if (definedef != dnone)            if (definedef != dnone)
3876              break;              break;
3877            if (fvdef == fstartlist)            if (fvdef == fstartlist)
3878              fvdef = fvnone;     /* avoid tagging `foo' in `foo (*bar()) ()' */              {
3879                  fvdef = fvnone;   /* avoid tagging `foo' in `foo (*bar()) ()' */
3880                  token.valid = FALSE;
3881                }
3882            break;            break;
3883          case '}':          case '}':
3884            if (definedef != dnone)            if (definedef != dnone)
3885              break;              break;
3886            if (!noindentypedefs && lp == newlb.buffer + 1)            if (!ignoreindent && lp == newlb.buffer + 1)
3887              {              {
3888                  if (cblev != 0)
3889                    token.valid = FALSE;
3890                cblev = 0;        /* reset curly brace level if first column */                cblev = 0;        /* reset curly brace level if first column */
3891                parlev = 0;       /* also reset paren level, just in case... */                parlev = 0;       /* also reset paren level, just in case... */
3892              }              }
3893            else if (cblev > 0)            else if (cblev > 0)
3894              cblev--;              cblev--;
3895              else
3896                token.valid = FALSE; /* something gone amiss, token unreliable */
3897            popclass_above (cblev);            popclass_above (cblev);
3898            structdef = snone;            structdef = snone;
3899            /* Only if typdef == tinbody is typdefcblev significant. */            /* Only if typdef == tinbody is typdefcblev significant. */
# Line 3770  C_entries (c_ext, inf) Line 3977  C_entries (c_ext, inf)
3977    
3978      } /* while not eof */      } /* while not eof */
3979    
   free (token_name.buffer);  
3980    free (lbs[0].lb.buffer);    free (lbs[0].lb.buffer);
3981    free (lbs[1].lb.buffer);    free (lbs[1].lb.buffer);
3982  }  }
# Line 3831  Yacc_entries (inf) Line 4037  Yacc_entries (inf)
4037  #define LOOP_ON_INPUT_LINES(file_pointer, line_buffer, char_pointer)    \  #define LOOP_ON_INPUT_LINES(file_pointer, line_buffer, char_pointer)    \
4038    for (;                        /* loop initialization */               \    for (;                        /* loop initialization */               \
4039         !feof (file_pointer)     /* loop test */                         \         !feof (file_pointer)     /* loop test */                         \
4040         && (char_pointer = lb.buffer, /* instructions at start of loop */ \         &&                       /* instructions at start of loop */     \
4041             readline (&line_buffer, file_pointer),                       \            (readline (&line_buffer, file_pointer),                       \
4042               char_pointer = line_buffer.buffer,                           \
4043             TRUE);                                                       \             TRUE);                                                       \
4044        )        )
4045  #define LOOKING_AT(cp, keyword) /* keyword is a constant string */      \  #define LOOKING_AT(cp, keyword) /* keyword is a constant string */      \
# Line 3903  F_getit (inf) Line 4110  F_getit (inf)
4110      return;      return;
4111    for (cp = dbp + 1; *cp != '\0' && intoken (*cp); cp++)    for (cp = dbp + 1; *cp != '\0' && intoken (*cp); cp++)
4112      continue;      continue;
4113    pfnote (savenstr (dbp, cp-dbp), TRUE,    make_tag (dbp, cp-dbp, TRUE,
4114            lb.buffer, cp - lb.buffer + 1, lineno, linecharno);              lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4115  }  }
4116    
4117    
# Line 3971  Fortran_functions (inf) Line 4178  Fortran_functions (inf)
4178              {              {
4179                dbp = skip_spaces (dbp);                dbp = skip_spaces (dbp);
4180                if (*dbp == '\0') /* assume un-named */                if (*dbp == '\0') /* assume un-named */
4181                  pfnote (savestr ("blockdata"), TRUE,                  make_tag ("blockdata", 9, TRUE,
4182                          lb.buffer, dbp - lb.buffer, lineno, linecharno);                            lb.buffer, dbp - lb.buffer, lineno, linecharno);
4183                else                else
4184                  F_getit (inf);  /* look for name */                  F_getit (inf);  /* look for name */
4185              }              }
# Line 3985  Fortran_functions (inf) Line 4192  Fortran_functions (inf)
4192  /*  /*
4193   * Ada parsing   * Ada parsing
4194   * Original code by   * Original code by
4195   * Philippe Waroquiers <philippe.waroquiers@eurocontrol.be> (1998)   * Philippe Waroquiers <philippe.waroquiers@eurocontrol.int> (1998)
4196   */   */
4197    
4198  static void Ada_getit __P((FILE *, char *));  static void Ada_getit __P((FILE *, char *));
# Line 4048  Ada_getit (inf, name_qualifier) Line 4255  Ada_getit (inf, name_qualifier)
4255        *cp = '\0';        *cp = '\0';
4256        name = concat (dbp, name_qualifier, "");        name = concat (dbp, name_qualifier, "");
4257        *cp = c;        *cp = c;
4258        pfnote (name, TRUE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno);        make_tag (name, strlen (name), TRUE,
4259                    lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4260          free (name);
4261        if (c == '"')        if (c == '"')
4262          dbp = cp + 1;          dbp = cp + 1;
4263        return;        return;
# Line 4060  Ada_funcs (inf) Line 4269  Ada_funcs (inf)
4269       FILE *inf;       FILE *inf;
4270  {  {
4271    bool inquote = FALSE;    bool inquote = FALSE;
4272      bool skip_till_semicolumn = FALSE;
4273    
4274    LOOP_ON_INPUT_LINES (inf, lb, dbp)    LOOP_ON_INPUT_LINES (inf, lb, dbp)
4275      {      {
# Line 4096  Ada_funcs (inf) Line 4306  Ada_funcs (inf)
4306                continue;                continue;
4307              }              }
4308    
4309              if (skip_till_semicolumn)
4310                {
4311                  if (*dbp == ';')
4312                    skip_till_semicolumn = FALSE;
4313                  dbp++;
4314                  continue;         /* advance char */
4315                }
4316    
4317            /* Search for beginning of a token.  */            /* Search for beginning of a token.  */
4318            if (!begtoken (*dbp))            if (!begtoken (*dbp))
4319              {              {
# Line 4122  Ada_funcs (inf) Line 4340  Ada_funcs (inf)
4340                else                else
4341                  break;          /* from switch */                  break;          /* from switch */
4342                continue;         /* advance char */                continue;         /* advance char */
4343    
4344                case 'u':
4345                  if (typedefs && !packages_only && nocase_tail ("use"))
4346                    {
4347                      /* when tagging types, avoid tagging  use type Pack.Typename;
4348                         for this, we will skip everything till a ; */
4349                      skip_till_semicolumn = TRUE;
4350                      continue;     /* advance char */
4351                    }
4352    
4353              case 't':              case 't':
4354                if (!packages_only && nocase_tail ("task"))                if (!packages_only && nocase_tail ("task"))
4355                  Ada_getit (inf, "/k");                  Ada_getit (inf, "/k");
# Line 4167  Asm_labels (inf) Line 4395  Asm_labels (inf)
4395            while (ISALNUM (*cp) || *cp == '_' || *cp == '.' || *cp == '$')            while (ISALNUM (*cp) || *cp == '_' || *cp == '.' || *cp == '$')
4396              cp++;              cp++;
4397            if (*cp == ':' || iswhite (*cp))            if (*cp == ':' || iswhite (*cp))
4398              {              /* Found end of label, so copy it and add it to the table. */
4399                /* Found end of label, so copy it and add it to the table. */              make_tag (lb.buffer, cp - lb.buffer, TRUE,
               pfnote (savenstr(lb.buffer, cp-lb.buffer), TRUE,  
4400                        lb.buffer, cp - lb.buffer + 1, lineno, linecharno);                        lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
             }  
4401          }          }
4402      }      }
4403  }  }
# Line 4199  Perl_functions (inf) Line 4425  Perl_functions (inf)
4425        if (LOOKING_AT (cp, "package"))        if (LOOKING_AT (cp, "package"))
4426          {          {
4427            free (package);            free (package);
4428            package = get_tag (cp);            get_tag (cp, &package);
           if (package == NULL)  /* can't parse package name */  
             package = savestr ("");  
           else  
             package = savestr(package); /* make a copy */  
4429          }          }
4430        else if (LOOKING_AT (cp, "sub"))        else if (LOOKING_AT (cp, "sub"))
4431          {          {
4432            char *name, *fullname, *pos;            char *pos;
4433            char *sp = cp;            char *sp = cp;
4434    
4435            while (!notinname (*cp))            while (!notinname (*cp))
4436              cp++;              cp++;
4437            if (cp == sp)            if (cp == sp)
4438              continue;              continue;           /* nothing found */
4439            name = savenstr (sp, cp-sp);            if ((pos = etags_strchr (sp, ':')) != NULL
4440            if ((pos = etags_strchr (name, ':')) != NULL && pos[1] == ':')                && pos < cp && pos[1] == ':')
4441              fullname = name;              /* The name is already qualified. */
4442                make_tag (sp, cp - sp, TRUE,
4443                          lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4444            else            else
4445              fullname = concat (package, "::", name);              /* Qualify it. */
4446            pfnote (fullname, TRUE,              {
4447                    lb.buffer, cp - lb.buffer + 1, lineno, linecharno);                char savechar, *name;
4448            if (name != fullname)  
4449              free (name);                savechar = *cp;
4450                  *cp = '\0';
4451                  name = concat (package, "::", sp);
4452                  *cp = savechar;
4453                  make_tag (name, strlen(name), TRUE,
4454                            lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4455                  free (name);
4456                }
4457          }          }
4458         else if (globals         /* only if tagging global vars is enabled */         else if (globals)        /* only if we are tagging global vars */
                 && (LOOKING_AT (cp, "my") || LOOKING_AT (cp, "local")))  
4459          {          {
4460              /* Skip a qualifier, if any. */
4461              bool qual = LOOKING_AT (cp, "my") || LOOKING_AT (cp, "local");
4462            /* After "my" or "local", but before any following paren or space. */            /* After "my" or "local", but before any following paren or space. */
4463            char *varname = NULL;            char *varstart = cp;
4464    
4465            if (*cp == '$' || *cp == '@' || *cp == '%')            if (qual              /* should this be removed?  If yes, how? */
4466                  && (*cp == '$' || *cp == '@' || *cp == '%'))
4467              {              {
4468                char* varstart = ++cp;                varstart += 1;
4469                while (ISALNUM (*cp) || *cp == '_')                do
4470                  cp++;                  cp++;
4471                varname = savenstr (varstart, cp-varstart);                while (ISALNUM (*cp) || *cp == '_');
4472              }              }
4473            else            else if (qual)
4474              {              {
4475                /* Should be examining a variable list at this point;                /* Should be examining a variable list at this point;
4476                   could insist on seeing an open parenthesis. */                   could insist on seeing an open parenthesis. */
4477                while (*cp != '\0' && *cp != ';' && *cp != '=' &&  *cp != ')')                while (*cp != '\0' && *cp != ';' && *cp != '=' &&  *cp != ')')
4478                  cp++;                  cp++;
4479              }              }
4480              else
4481                continue;
4482    
4483            /* Perhaps I should back cp up one character, so the TAGS table            make_tag (varstart, cp - varstart, FALSE,
4484               doesn't mention (and so depend upon) the following char. */                      lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
           pfnote (varname, FALSE,  
                   lb.buffer, cp - lb.buffer + 1, lineno, linecharno);  
4485          }          }
4486      }      }
4487  }  }
# Line 4274  Python_functions (inf) Line 4507  Python_functions (inf)
4507            char *name = cp;            char *name = cp;
4508            while (!notinname (*cp) && *cp != ':')            while (!notinname (*cp) && *cp != ':')
4509              cp++;              cp++;
4510            pfnote (savenstr (name, cp-name), TRUE,            make_tag (name, cp - name, TRUE,
4511                    lb.buffer, cp - lb.buffer + 1, lineno, linecharno);                      lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4512          }          }
4513      }      }
4514  }  }
# Line 4307  PHP_functions (inf) Line 4540  PHP_functions (inf)
4540          {          {
4541            while (!notinname (*cp))            while (!notinname (*cp))
4542              cp++;              cp++;
4543            pfnote (savenstr (name, cp-name), TRUE,            make_tag (name, cp - name, TRUE,
4544                    lb.buffer, cp - lb.buffer + 1, lineno, linecharno);                      lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4545            search_identifier = FALSE;            search_identifier = FALSE;
4546          }          }
4547        else if (LOOKING_AT (cp, "function"))        else if (LOOKING_AT (cp, "function"))
# Line 4320  PHP_functions (inf) Line 4553  PHP_functions (inf)
4553                name = cp;                name = cp;
4554                while (!notinname (*cp))                while (!notinname (*cp))
4555                  cp++;                  cp++;
4556                pfnote (savenstr (name, cp-name), TRUE,                make_tag (name, cp - name, TRUE,
4557                        lb.buffer, cp - lb.buffer + 1, lineno, linecharno);                          lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4558              }              }
4559            else            else
4560              search_identifier = TRUE;              search_identifier = TRUE;
# Line 4333  PHP_functions (inf) Line 4566  PHP_functions (inf)
4566                name = cp;                name = cp;
4567                while (*cp != '\0' && !iswhite (*cp))                while (*cp != '\0' && !iswhite (*cp))
4568                  cp++;                  cp++;
4569                pfnote (savenstr (name, cp-name), FALSE,                make_tag (name, cp - name, FALSE,
4570                        lb.buffer, cp - lb.buffer + 1, lineno, linecharno);                          lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4571              }              }
4572            else            else
4573              search_identifier = TRUE;              search_identifier = TRUE;
# Line 4348  PHP_functions (inf) Line 4581  PHP_functions (inf)
4581            name = cp;            name = cp;
4582            while (*cp != quote && *cp != '\0')            while (*cp != quote && *cp != '\0')
4583              cp++;              cp++;
4584            pfnote (savenstr (name, cp-name), FALSE,            make_tag (name, cp - name, FALSE,
4585                    lb.buffer, cp - lb.buffer + 1, lineno, linecharno);                      lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4586          }          }
4587        else if (members        else if (members
4588                 && LOOKING_AT (cp, "var")                 && LOOKING_AT (cp, "var")
# Line 4358  PHP_functions (inf) Line 4591  PHP_functions (inf)
4591            name = cp;            name = cp;
4592            while (!notinname(*cp))            while (!notinname(*cp))
4593              cp++;              cp++;
4594            pfnote (savenstr (name, cp-name), FALSE,            make_tag (name, cp - name, FALSE,
4595                    lb.buffer, cp - lb.buffer + 1, lineno, linecharno);                      lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4596          }          }
4597      }      }
4598  }  }
# Line 4390  Cobol_paragraphs (inf) Line 4623  Cobol_paragraphs (inf)
4623        for (ep = bp; ISALNUM (*ep) || *ep == '-'; ep++)        for (ep = bp; ISALNUM (*ep) || *ep == '-'; ep++)
4624          continue;          continue;
4625        if (*ep++ == '.')        if (*ep++ == '.')
4626          pfnote (savenstr (bp, ep-bp), TRUE,          make_tag (bp, ep - bp, TRUE,
4627                  lb.buffer, ep - lb.buffer + 1, lineno, linecharno);                    lb.buffer, ep - lb.buffer + 1, lineno, linecharno);
4628      }      }
4629  }  }
4630    
4631    
4632  /*  /*
4633   * Makefile support   * Makefile support
4634   * Idea by Assar Westerlund <assar@sics.se> (2001)   * Ideas by Assar Westerlund <assar@sics.se> (2001)
4635   */   */
4636  static void  static void
4637  Makefile_targets (inf)  Makefile_targets (inf)
# Line 4412  Makefile_targets (inf) Line 4645  Makefile_targets (inf)
4645          continue;          continue;
4646        while (*bp != '\0' && *bp != '=' && *bp != ':')        while (*bp != '\0' && *bp != '=' && *bp != ':')
4647          bp++;          bp++;
4648        if (*bp == ':')        if (*bp == ':' || (globals && *bp == '='))
4649          pfnote (savenstr (lb.buffer, bp - lb.buffer), TRUE,          make_tag (lb.buffer, bp - lb.buffer, TRUE,
4650                  lb.buffer, bp - lb.buffer + 1, lineno, linecharno);                    lb.buffer, bp - lb.buffer + 1, lineno, linecharno);
4651      }      }
4652  }  }
4653    
# Line 4434  Pascal_functions (inf) Line 4667  Pascal_functions (inf)
4667  {  {
4668    linebuffer tline;             /* mostly copied from C_entries */    linebuffer tline;             /* mostly copied from C_entries */
4669    long save_lcno;    long save_lcno;
4670    int save_lineno, save_len;    int save_lineno, namelen, taglen;
4671    char c, *cp, *namebuf;    char c, *name;
4672    
4673    bool                          /* each of these flags is TRUE iff: */    bool                          /* each of these flags is TRUE iff: */
4674      incomment,                  /* point is inside a comment */      incomment,                  /* point is inside a comment */
# Line 4449  Pascal_functions (inf) Line 4682  Pascal_functions (inf)
4682                                     is a FORWARD/EXTERN to be ignored, or                                     is a FORWARD/EXTERN to be ignored, or
4683                                     whether it is a real tag */                                     whether it is a real tag */
4684    
4685    save_lcno = save_lineno = save_len = 0; /* keep compiler quiet */    save_lcno = save_lineno = namelen = taglen = 0; /* keep compiler quiet */
4686    namebuf = NULL;               /* keep compiler quiet */    name = NULL;                  /* keep compiler quiet */
4687    dbp = lb.buffer;    dbp = lb.buffer;
4688    *dbp = '\0';    *dbp = '\0';
4689    initbuffer (&tline);    linebuffer_init (&tline);
4690    
4691    incomment = inquote = FALSE;    incomment = inquote = FALSE;
4692    found_tag = FALSE;            /* have a proc name; check if extern */    found_tag = FALSE;            /* have a proc name; check if extern */
4693    get_tagname = FALSE;          /* have found "procedure" keyword    */    get_tagname = FALSE;          /* found "procedure" keyword         */
4694    inparms = FALSE;              /* found '(' after "proc"            */    inparms = FALSE;              /* found '(' after "proc"            */
4695    verify_tag = FALSE;           /* check if "extern" is ahead        */    verify_tag = FALSE;           /* check if "extern" is ahead        */
4696    
# Line 4526  Pascal_functions (inf) Line 4759  Pascal_functions (inf)
4759            }            }
4760        if (found_tag && verify_tag && (*dbp != ' '))        if (found_tag && verify_tag && (*dbp != ' '))
4761          {          {
4762            /* check if this is an "extern" declaration */            /* Check if this is an "extern" declaration. */
4763            if (*dbp == '\0')            if (*dbp == '\0')
4764              continue;              continue;
4765            if (lowcase (*dbp == 'e'))            if (lowcase (*dbp == 'e'))
# Line 4539  Pascal_functions (inf) Line 4772  Pascal_functions (inf)
4772              }              }
4773            else if (lowcase (*dbp) == 'f')            else if (lowcase (*dbp) == 'f')
4774              {              {
4775                if (nocase_tail ("forward")) /*  check for forward reference */                if (nocase_tail ("forward")) /* check for forward reference */
4776                  {                  {
4777                    found_tag = FALSE;                    found_tag = FALSE;
4778                    verify_tag = FALSE;                    verify_tag = FALSE;
# Line 4549  Pascal_functions (inf) Line 4782  Pascal_functions (inf)
4782              {              {
4783                found_tag = FALSE;                found_tag = FALSE;
4784                verify_tag = FALSE;                verify_tag = FALSE;
4785                pfnote (namebuf, TRUE,                make_tag (name, namelen, TRUE,
4786                        tline.buffer, save_len, save_lineno, save_lcno);                          tline.buffer, taglen, save_lineno, save_lcno);
4787                continue;                continue;
4788              }              }
4789          }          }
4790        if (get_tagname)          /* grab name of proc or fn */        if (get_tagname)          /* grab name of proc or fn */
4791          {          {
4792              char *cp;
4793    
4794            if (*dbp == '\0')            if (*dbp == '\0')
4795              continue;              continue;
4796    
4797            /* save all values for later tagging */            /* Find block name. */
4798              for (cp = dbp + 1; *cp != '\0' && !endtoken (*cp); cp++)
4799                continue;
4800    
4801              /* Save all values for later tagging. */
4802            linebuffer_setlen (&tline, lb.len);            linebuffer_setlen (&tline, lb.len);
4803            strcpy (tline.buffer, lb.buffer);            strcpy (tline.buffer, lb.buffer);
4804            save_lineno = lineno;            save_lineno = lineno;
4805            save_lcno = linecharno;            save_lcno = linecharno;
4806              name = tline.buffer + (dbp - lb.buffer);
4807              namelen = cp - dbp;
4808              taglen = cp - lb.buffer + 1;
4809    
           /* grab block name */  
           for (cp = dbp + 1; *cp != '\0' && !endtoken (*cp); cp++)  
             continue;  
           namebuf = savenstr (dbp, cp-dbp);  
4810            dbp = cp;             /* set dbp to e-o-token */            dbp = cp;             /* set dbp to e-o-token */
           save_len = dbp - lb.buffer + 1;  
4811            get_tagname = FALSE;            get_tagname = FALSE;
4812            found_tag = TRUE;            found_tag = TRUE;
4813            continue;            continue;
4814    
4815            /* and proceed to check for "extern" */            /* And proceed to check for "extern". */
4816          }          }
4817        else if (!incomment && !inquote && !found_tag)        else if (!incomment && !inquote && !found_tag)
4818          {          {
4819            /* check for proc/fn keywords */            /* Check for proc/fn keywords. */
4820            switch (lowcase (c))            switch (lowcase (c))
4821              {              {
4822              case 'p':              case 'p':
# Line 4592  Pascal_functions (inf) Line 4829  Pascal_functions (inf)
4829                continue;                continue;
4830              }              }
4831          }          }
4832      }                           /* while not eof */      } /* while not eof */
4833    
4834    free (tline.buffer);    free (tline.buffer);
4835  }  }
# Line 4618  L_getit () Line 4855  L_getit ()
4855        /* Ok, then skip "(" before name in (defstruct (foo)) */        /* Ok, then skip "(" before name in (defstruct (foo)) */
4856        dbp = skip_spaces (dbp);        dbp = skip_spaces (dbp);
4857    }    }
4858    get_tag (dbp);    get_tag (dbp, NULL);
4859  }  }
4860    
4861  static void  static void
# Line 4669  Lisp_functions (inf) Line 4906  Lisp_functions (inf)
4906   *   Masatake Yamato <masata-y@is.aist-nara.ac.jp> (1999)   *   Masatake Yamato <masata-y@is.aist-nara.ac.jp> (1999)
4907   */   */
4908  static void  static void
4909  Postscript_functions (inf)  PS_functions (inf)
4910       FILE *inf;       FILE *inf;
4911  {  {
4912    register char *bp, *ep;    register char *bp, *ep;
# Line 4682  Postscript_functions (inf) Line 4919  Postscript_functions (inf)
4919                 *ep != '\0' && *ep != ' ' && *ep != '{';                 *ep != '\0' && *ep != ' ' && *ep != '{';
4920                 ep++)                 ep++)
4921              continue;              continue;
4922            pfnote (savenstr (bp, ep-bp), TRUE,            make_tag (bp, ep - bp, TRUE,
4923                    lb.buffer, ep - lb.buffer + 1, lineno, linecharno);                      lb.buffer, ep - lb.buffer + 1, lineno, linecharno);
4924          }          }
4925        else if (LOOKING_AT (bp, "defineps"))        else if (LOOKING_AT (bp, "defineps"))
4926          get_tag (bp);          get_tag (bp, NULL);
4927      }      }
4928  }  }
4929    
# Line 4714  Scheme_functions (inf) Line 4951  Scheme_functions (inf)
4951            /* Skip over open parens and white space */            /* Skip over open parens and white space */
4952            while (notinname (*bp))            while (notinname (*bp))
4953              bp++;              bp++;
4954            get_tag (bp);            get_tag (bp, NULL);
4955          }          }
4956        if (LOOKING_AT (bp, "(SET!") || LOOKING_AT (bp, "(set!"))        if (LOOKING_AT (bp, "(SET!") || LOOKING_AT (bp, "(set!"))
4957          get_tag (bp);          get_tag (bp, NULL);
4958      }      }
4959  }  }
4960    
# Line 4779  TeX_commands (inf) Line 5016  TeX_commands (inf)
5016              if (strneq (cp, key->buffer, key->len))              if (strneq (cp, key->buffer, key->len))
5017                {                {
5018                  register char *p;                  register char *p;
5019                  char *name;                  int namelen, linelen;
                 int linelen;  
5020                  bool opgrp = FALSE;                  bool opgrp = FALSE;
5021    
5022                  cp = skip_spaces (cp + key->len);                  cp = skip_spaces (cp + key->len);
# Line 4794  TeX_commands (inf) Line 5030  TeX_commands (inf)
5030                        *p != TEX_opgrp && *p != TEX_clgrp);                        *p != TEX_opgrp && *p != TEX_clgrp);
5031                       p++)                       p++)
5032                    continue;                    continue;
5033                  name = savenstr (cp, p-cp);                  namelen = p - cp;
5034                  linelen = lb.len;                  linelen = lb.len;
5035                  if (!opgrp || *p == TEX_clgrp)                  if (!opgrp || *p == TEX_clgrp)
5036                    {                    {
# Line 4802  TeX_commands (inf) Line 5038  TeX_commands (inf)
5038                        *p++;                        *p++;
5039                      linelen = p - lb.buffer + 1;                      linelen = p - lb.buffer + 1;
5040                    }                    }
5041                  pfnote (name, TRUE, lb.buffer, linelen, lineno, linecharno);                  make_tag (cp, namelen, TRUE,
5042                              lb.buffer, linelen, lineno, linecharno);
5043                  goto tex_next_line; /* We only tag a line once */                  goto tex_next_line; /* We only tag a line once */
5044                }                }
5045          }          }
# Line 4912  Texinfo_nodes (inf) Line 5149  Texinfo_nodes (inf)
5149          start = cp;          start = cp;
5150          while (*cp != '\0' && *cp != ',')          while (*cp != '\0' && *cp != ',')
5151            cp++;            cp++;
5152          pfnote (savenstr (start, cp - start), TRUE,          make_tag (start, cp - start, TRUE,
5153                  lb.buffer, cp - lb.buffer + 1, lineno, linecharno);                    lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
5154          }
5155    }
5156    
5157    
5158    /* Similar to LOOKING_AT but does not use notinname, does not skip */
5159    #define LOOKING_AT_NOCASE(cp, kw)       /* kw is a constant string */   \
5160      (strncaseeq ((cp), kw, sizeof(kw)-1)  /* cp points at kw */           \
5161       && ((cp) += sizeof(kw)-1))           /* skip spaces */
5162    
5163    /*
5164     * HTML support.
5165     * Contents of <title>, <h1>, <h2>, <h3> are tags.
5166     * Contents of <a name=xxx> are tags with name xxx.
5167     *
5168     * Francesco Potort́, 2002.
5169     */
5170    static void
5171    HTML_labels (inf)
5172         FILE * inf;
5173    {
5174      bool getnext = FALSE;         /* next text outside of HTML tags is a tag */
5175      bool skiptag = FALSE;         /* skip to the end of the current HTML tag */
5176      bool intag = FALSE;           /* inside an html tag, looking for ID= */
5177      bool inanchor = FALSE;        /* when INTAG, is an anchor, look for NAME= */
5178      char *end;
5179    
5180    
5181      linebuffer_setlen (&token_name, 0); /* no name in buffer */
5182    
5183      LOOP_ON_INPUT_LINES (inf, lb, dbp)
5184        for (;;)                    /* loop on the same line */
5185          {
5186            if (skiptag)            /* skip HTML tag */
5187              {
5188                while (*dbp != '\0' && *dbp != '>')
5189                  dbp++;
5190                if (*dbp == '>')
5191                  {
5192                    dbp += 1;
5193                    skiptag = FALSE;
5194                    continue;       /* look on the same line */
5195                  }
5196                break;              /* go to next line */
5197              }
5198    
5199            else if (intag) /* look for "name=" or "id=" */
5200              {
5201                while (*dbp != '\0' && *dbp != '>'
5202                       && lowcase (*dbp) != 'n' && lowcase (*dbp) != 'i')
5203                  dbp++;
5204                if (*dbp == '\0')
5205                  break;            /* go to next line */
5206                if (*dbp == '>')
5207                  {
5208                    dbp += 1;
5209                    intag = FALSE;
5210                    continue;       /* look on the same line */
5211                  }
5212                if ((inanchor && LOOKING_AT_NOCASE (dbp, "name="))
5213                    || LOOKING_AT_NOCASE (dbp, "id="))
5214                  {
5215                    bool quoted = (dbp[0] == '"');
5216    
5217                    if (quoted)
5218                      for (end = ++dbp; *end != '\0' && *end != '"'; end++)
5219                        continue;
5220                    else
5221                      for (end = dbp; *end != '\0' && intoken (*end); end++)
5222                        continue;
5223                    linebuffer_setlen (&token_name, end - dbp);
5224                    strncpy (token_name.buffer, dbp, end - dbp);
5225                    token_name.buffer[end - dbp] = '\0';
5226    
5227                    dbp = end;
5228                    intag = FALSE;  /* we found what we looked for */
5229                    skiptag = TRUE; /* skip to the end of the tag */
5230                    getnext = TRUE; /* then grab the text */
5231                    continue;       /* look on the same line */
5232                  }
5233                dbp += 1;
5234              }
5235    
5236            else if (getnext)       /* grab next tokens and tag them */
5237              {
5238                dbp = skip_spaces (dbp);
5239                if (*dbp == '\0')
5240                  break;            /* go to next line */
5241                if (*dbp == '<')
5242                  {
5243                    intag = TRUE;
5244                    inanchor = (lowcase (dbp[1]) == 'a' && !intoken (dbp[2]));
5245                    continue;       /* look on the same line */
5246                  }
5247    
5248                for (end = dbp + 1; *end != '\0' && *end != '<'; end++)
5249                  continue;
5250                make_tag (token_name.buffer, token_name.len, TRUE,
5251                          dbp, end - dbp, lineno, linecharno);
5252                linebuffer_setlen (&token_name, 0); /* no name in buffer */
5253                getnext = FALSE;
5254                break;              /* go to next line */
5255              }
5256    
5257            else                    /* look for an interesting HTML tag */
5258              {
5259                while (*dbp != '\0' && *dbp != '<')
5260                  dbp++;
5261                if (*dbp == '\0')
5262                  break;            /* go to next line */
5263                intag = TRUE;
5264                if (lowcase (dbp[1]) == 'a' && !intoken (dbp[2]))
5265                  {
5266                    inanchor = TRUE;
5267                    continue;       /* look on the same line */
5268                  }
5269                else if (LOOKING_AT_NOCASE (dbp, "<title>")
5270                         || LOOKING_AT_NOCASE (dbp, "<h1>")
5271                         || LOOKING_AT_NOCASE (dbp, "<h2>")
5272                         || LOOKING_AT_NOCASE (dbp, "<h3>"))
5273                  {
5274                    intag = FALSE;
5275                    getnext = TRUE;
5276                    continue;       /* look on the same line */
5277                  }
5278                dbp += 1;
5279              }
5280        }        }
5281  }  }
5282    
# Line 5016  prolog_pr (s, last) Line 5379  prolog_pr (s, last)
5379            || len != strlen (last)            || len != strlen (last)
5380            || !strneq (s, last, len)))            || !strneq (s, last, len)))
5381          {          {
5382            pfnote (savenstr (s, len), TRUE, s, pos, lineno, linecharno);            make_tag (s, len, TRUE, s, pos, lineno, linecharno);
5383            return len;            return len;
5384          }          }
5385    else    else
# Line 5092  prolog_atom (s, pos) Line 5455  prolog_atom (s, pos)
5455   */   */
5456  static int erlang_func __P((char *, char *));  static int erlang_func __P((char *, char *));
5457  static void erlang_attribute __P((char *));  static void erlang_attribute __P((char *));
5458  static int erlang_atom __P((char *, int));  static int erlang_atom __P((char *));
5459    
5460  static void  static void
5461  Erlang_functions (inf)  Erlang_functions (inf)
# Line 5157  erlang_func (s, last) Line 5520  erlang_func (s, last)
5520    int pos;    int pos;
5521    int len;    int len;
5522    
5523    pos = erlang_atom (s, 0);    pos = erlang_atom (s);
5524    if (pos < 1)    if (pos < 1)
5525      return 0;      return 0;
5526    
# Line 5170  erlang_func (s, last) Line 5533  erlang_func (s, last)
5533            || len != (int)strlen (last)            || len != (int)strlen (last)
5534            || !strneq (s, last, len)))            || !strneq (s, last, len)))
5535          {          {
5536            pfnote (savenstr (s, len), TRUE, s, pos, lineno, linecharno);            make_tag (s, len, TRUE, s, pos, lineno, linecharno);
5537            return len;            return len;
5538          }          }
5539    
# Line 5191  static void Line 5554  static void
5554  erlang_attribute (s)  erlang_attribute (s)
5555       char *s;       char *s;
5556  {  {
5557    int pos;    char *cp = s;
   int len;  
5558    
5559    if (LOOKING_AT (s, "-define") || LOOKING_AT (s, "-record"))    if ((LOOKING_AT (cp, "-define") || LOOKING_AT (cp, "-record"))
5560          && *cp++ == '(')
5561      {      {
5562        if (s[pos++] == '(')        int len = erlang_atom (skip_spaces (cp));
5563          {        if (len > 0)
5564            pos = skip_spaces (s + pos) - s;          make_tag (cp, len, TRUE, s, cp + len - s, lineno, linecharno);
           len = erlang_atom (s, pos);  
           if (len != 0)  
             pfnote (savenstr (& s[pos], len), TRUE,  
                     s, pos + len, lineno, linecharno);  
         }  
5565      }      }
5566    return;    return;
5567  }  }
# Line 5214  erlang_attribute (s) Line 5572  erlang_attribute (s)
5572   * Return the number of bytes consumed, or -1 if there was an error.   * Return the number of bytes consumed, or -1 if there was an error.
5573   */   */
5574  static int  static int
5575  erlang_atom (s, pos)  erlang_atom (s)
5576       char *s;       char *s;
      int pos;  
5577  {  {
5578    int origpos;    int pos = 0;
   
   origpos = pos;  
5579    
5580    if (ISALPHA (s[pos]) || s[pos] == '_')    if (ISALPHA (s[pos]) || s[pos] == '_')
5581      {      {
5582        /* The atom is unquoted. */        /* The atom is unquoted. */
5583        pos++;        do
       while (ISALNUM (s[pos]) || s[pos] == '_')  
5584          pos++;          pos++;
5585        return pos - origpos;        while (ISALNUM (s[pos]) || s[pos] == '_');
5586      }      }
5587    else if (s[pos] == '\'')    else if (s[pos] == '\'')
5588      {      {
5589          for (pos++; s[pos] != '\''; pos++)
5590            if (s[pos] == '\0'      /* multiline quoted atoms are ignored */
5591                || (s[pos] == '\\' && s[++pos] == '\0'))
5592              return 0;
5593        pos++;        pos++;
   
       for (;;)  
         {  
           if (s[pos] == '\'')  
             {  
               pos++;  
               break;  
             }  
           else if (s[pos] == '\0')  
             /* Multiline quoted atoms are ignored. */  
             return -1;  
           else if (s[pos] == '\\')  
             {  
               if (s[pos+1] == '\0')  
                 return -1;  
               pos += 2;  
             }  
           else  
             pos++;  
         }  
       return pos - origpos;  
5594      }      }
5595    else  
5596      return -1;    return pos;
5597  }  }
5598    
5599    
5600  #ifdef ETAGS_REGEXPS  #ifdef ETAGS_REGEXPS
5601    
5602  static char *scan_separators __P((char *));  static char *scan_separators __P((char *));
5603  static void analyse_regex __P((char *, bool));  static void add_regex __P((char *, language *));
 static void add_regex __P((char *, bool, language *));  
5604  static char *substitute __P((char *, char *, struct re_registers *));  static char *substitute __P((char *, char *, struct re_registers *));
5605    
5606  /* Take a string like "/blah/" and turn it into "blah", making sure  /*
5607     that the first and last characters are the same, and handling   * Take a string like "/blah/" and turn it into "blah", verifying
5608     quoted separator characters.  Actually, stops on the occurrence of   * that the first and last characters are the same, and handling
5609     an unquoted separator.  Also turns "\t" into a Tab character, and   * quoted separator characters.  Actually, stops on the occurrence of
5610     similarly for all character escape sequences supported by Gcc.   * an unquoted separator.  Also process \t, \n, etc. and turn into
5611     Returns pointer to terminating separator.  Works in place.  Null   * appropriate characters. Works in place.  Null terminates name string.
5612     terminates name string. */   * Returns pointer to terminating separator, or NULL for
5613     * unterminated regexps.
5614     */
5615  static char *  static char *
5616  scan_separators (name)  scan_separators (name)
5617       char *name;       char *name;
# Line 5288  scan_separators (name) Line 5626  scan_separators (name)
5626          {          {
5627            switch (*name)            switch (*name)
5628              {              {
5629              case 'a': *copyto++ = '\007'; break;              case 'a': *copyto++ = '\007'; break; /* BEL (bell)           */
5630              case 'b': *copyto++ = '\b'; break;              case 'b': *copyto++ = '\b'; break;   /* BS (back space)      */
5631              case 'd': *copyto++ = 0177; break;              case 'd': *copyto++ = 0177; break;   /* DEL (delete)         */
5632              case 'e': *copyto++ = 033; break;              case 'e': *copyto++ = 033; break;    /* ESC (delete)         */
5633              case 'f': *copyto++ = '\f'; break;              case 'f': *copyto++ = '\f'; break;   /* FF (form feed)       */
5634              case 'n': *copyto++ = '\n'; break;              case 'n': *copyto++ = '\n'; break;   /* NL (new line)        */
5635              case 'r': *copyto++ = '\r'; break;              case 'r': *copyto++ = '\r'; break;   /* CR (carriage return) */
5636              case 't': *copyto++ = '\t'; break;              case 't': *copyto++ = '\t'; break;   /* TAB (horizontal tab) */
5637              case 'v': *copyto++ = '\v'; break;              case 'v': *copyto++ = '\v'; break;   /* VT (vertical tab)    */
5638              default:              default:
5639                if (*name == sep)                if (*name == sep)
5640                  *copyto++ = sep;                  *copyto++ = sep;
# Line 5317  scan_separators (name) Line 5655  scan_separators (name)
5655        else        else
5656          *copyto++ = *name;          *copyto++ = *name;
5657      }      }
5658      if (*name != sep)
5659        name = NULL;                /* signal unterminated regexp */
5660    
5661    /* Terminate copied string. */    /* Terminate copied string. */
5662    *copyto = '\0';    *copyto = '\0';
# Line 5326  scan_separators (name) Line 5666  scan_separators (name)
5666  /* Look at the argument of --regex or --no-regex and do the right  /* Look at the argument of --regex or --no-regex and do the right
5667     thing.  Same for each line of a regexp file. */     thing.  Same for each line of a regexp file. */
5668  static void  static void
5669  analyse_regex (regex_arg, ignore_case)  analyse_regex (regex_arg)
5670       char *regex_arg;       char *regex_arg;
      bool ignore_case;  
5671  {  {
5672    if (regex_arg == NULL)    if (regex_arg == NULL)
5673      {      {
5674        free_patterns ();         /* --no-regex: remove existing regexps */        free_regexps ();          /* --no-regex: remove existing regexps */
5675        return;        return;
5676      }      }
5677    
# Line 5360  analyse_regex (regex_arg, ignore_case) Line 5699  analyse_regex (regex_arg, ignore_case)
5699              pfatal (regexfile);              pfatal (regexfile);
5700              return;              return;
5701            }            }
5702          initbuffer (&regexbuf);          linebuffer_init (&regexbuf);
5703          while (readline_internal (&regexbuf, regexfp) > 0)          while (readline_internal (&regexbuf, regexfp) > 0)
5704            analyse_regex (regexbuf.buffer, ignore_case);            analyse_regex (regexbuf.buffer);
5705          free (regexbuf.buffer);          free (regexbuf.buffer);
5706          fclose (regexfp);          fclose (regexfp);
5707        }        }
# Line 5381  analyse_regex (regex_arg, ignore_case) Line 5720  analyse_regex (regex_arg, ignore_case)
5720                error ("unterminated language name in regex: %s", regex_arg);                error ("unterminated language name in regex: %s", regex_arg);
5721                return;                return;
5722              }              }
5723          *cp = '\0';          *cp++ = '\0';
5724          lang = get_language_from_langname (lang_name);          lang = get_language_from_langname (lang_name);
5725          if (lang == NULL)          if (lang == NULL)
5726            return;            return;
5727          add_regex (cp + 1, ignore_case, lang);          add_regex (cp, lang);
5728        }        }
5729        break;        break;
5730    
5731        /* Regexp to be used for any language. */        /* Regexp to be used for any language. */
5732      default:      default:
5733        add_regex (regex_arg, ignore_case, NULL);        add_regex (regex_arg, NULL);
5734        break;        break;
5735      }      }
5736  }  }
5737    
5738  /* Turn a name, which is an ed-style (but Emacs syntax) regular  /* Separate the regexp pattern, compile it,
5739     expression, into a real regular expression by compiling it. */     and care for optional name and modifiers. */
5740  static void  static void
5741  add_regex (regexp_pattern, ignore_case, lang)  add_regex (regexp_pattern, lang)
5742       char *regexp_pattern;       char *regexp_pattern;
      bool ignore_case;  
5743       language *lang;       language *lang;
5744  {  {
5745    static struct re_pattern_buffer zeropattern;    static struct re_pattern_buffer zeropattern;
5746    char *name;    char sep, *pat, *name, *modifiers;
5747    const char *err;    const char *err;
5748    struct re_pattern_buffer *patbuf;    struct re_pattern_buffer *patbuf;
5749    pattern *pp;    regexp *rp;
5750      bool
5751        force_explicit_name = TRUE, /* do not use implicit tag names */
5752        ignore_case = FALSE,        /* case is significant */
5753        multi_line = FALSE,         /* matches are done one line at a time */
5754        single_line = FALSE;        /* dot does not match newline */
5755    
5756    
5757    if (regexp_pattern[strlen(regexp_pattern)-1] != regexp_pattern[0])    if (strlen(regexp_pattern) < 3)
5758      {      {
5759        error ("%s: unterminated regexp", regexp_pattern);        error ("null regexp", (char *)NULL);
5760        return;        return;
5761      }      }
5762      sep = regexp_pattern[0];
5763    name = scan_separators (regexp_pattern);    name = scan_separators (regexp_pattern);
5764    if (regexp_pattern[0] == '\0')    if (name == NULL)
5765      {      {
5766        error ("null regexp", (char *)NULL);        error ("%s: unterminated regexp", regexp_pattern);
5767        return;        return;
5768      }      }
5769    (void) scan_separators (name);    if (name[1] == sep)
5770        {
5771          error ("null name for regexp \"%s\"", regexp_pattern);
5772          return;
5773        }
5774      modifiers = scan_separators (name);
5775      if (modifiers == NULL)        /* no terminating separator --> no name */
5776        {
5777          modifiers = name;
5778          name = "";
5779        }
5780      else
5781        modifiers += 1;             /* skip separator */
5782    
5783      /* Parse regex modifiers. */
5784      for (; modifiers[0] != '\0'; modifiers++)
5785        switch (modifiers[0])
5786          {
5787          case 'N':
5788            if (modifiers == name)
5789              error ("forcing explicit tag name but no name, ignoring", NULL);
5790            force_explicit_name = TRUE;
5791            break;
5792          case 'i':
5793            ignore_case = TRUE;
5794            break;
5795          case 's':
5796            single_line = TRUE;
5797            /* FALLTHRU */
5798          case 'm':
5799            multi_line = TRUE;
5800            need_filebuf = TRUE;
5801            break;
5802          default:
5803            {
5804              char wrongmod [2];
5805              wrongmod[0] = modifiers[0];
5806              wrongmod[1] = '\0';
5807              error ("invalid regexp modifier `%s', ignoring", wrongmod);
5808            }
5809            break;
5810          }
5811    
5812    patbuf = xnew (1, struct re_pattern_buffer);    patbuf = xnew (1, struct re_pattern_buffer);
5813    *patbuf = zeropattern;    *patbuf = zeropattern;
5814    if (ignore_case)    if (ignore_case)
5815      patbuf->translate = lc_trans;       /* translation table to fold case  */      {
5816          static char lc_trans[CHARS];
5817          int i;
5818          for (i = 0; i < CHARS; i++)
5819            lc_trans[i] = lowcase (i);
5820          patbuf->translate = lc_trans;     /* translation table to fold case  */
5821        }
5822    
5823      if (multi_line)
5824        pat = concat ("^", regexp_pattern, ""); /* anchor to beginning of line */
5825      else
5826        pat = regexp_pattern;
5827    
5828      if (single_line)
5829        re_set_syntax (RE_SYNTAX_EMACS | RE_DOT_NEWLINE);
5830      else
5831        re_set_syntax (RE_SYNTAX_EMACS);
5832    
5833    err = re_compile_pattern (regexp_pattern, strlen (regexp_pattern), patbuf);    err = re_compile_pattern (pat, strlen (regexp_pattern), patbuf);
5834      if (multi_line)
5835        free (pat);
5836    if (err != NULL)    if (err != NULL)
5837      {      {
5838        error ("%s while compiling pattern", err);        error ("%s while compiling pattern", err);
5839        return;        return;
5840      }      }
5841    
5842    pp = p_head;    rp = p_head;
5843    p_head = xnew (1, pattern);    p_head = xnew (1, regexp);
5844    p_head->regex = savestr (regexp_pattern);    p_head->pattern = savestr (regexp_pattern);
5845    p_head->p_next = pp;    p_head->p_next = rp;
5846    p_head->lang = lang;    p_head->lang = lang;
5847    p_head->pat = patbuf;    p_head->pat = patbuf;
5848    p_head->name_pattern = savestr (name);    p_head->name = savestr (name);
5849    p_head->error_signaled = FALSE;    p_head->error_signaled = FALSE;
5850      p_head->force_explicit_name = force_explicit_name;
5851    p_head->ignore_case = ignore_case;    p_head->ignore_case = ignore_case;
5852      p_head->multi_line = multi_line;
5853  }  }
5854    
5855  /*  /*
# Line 5478  substitute (in, out, regs) Line 5883  substitute (in, out, regs)
5883        size -= 1;        size -= 1;
5884    
5885    /* Allocate space and do the substitutions. */    /* Allocate space and do the substitutions. */
5886      assert (size >= 0);
5887    result = xnew (size + 1, char);    result = xnew (size + 1, char);
5888    
5889    for (t = result; *out != '\0'; out++)    for (t = result; *out != '\0'; out++)
# Line 5492  substitute (in, out, regs) Line 5898  substitute (in, out, regs)
5898        *t++ = *out;        *t++ = *out;
5899    *t = '\0';    *t = '\0';
5900    
5901    assert (t <= result + size && t - result == (int)strlen (result));    assert (t <= result + size);
5902      assert (t - result == (int)strlen (result));
5903    
5904    return result;    return result;
5905  }  }
5906    
5907  /* Deallocate all patterns. */  /* Deallocate all regexps. */
5908  static void  static void
5909  free_patterns ()  free_regexps ()
5910  {  {
5911    pattern *pp;    regexp *rp;
5912    while (p_head != NULL)    while (p_head != NULL)
5913      {      {
5914        pp = p_head->p_next;        rp = p_head->p_next;
5915        free (p_head->regex);        free (p_head->pattern);
5916        free (p_head->name_pattern);        free (p_head->name);
5917        free (p_head);        free (p_head);
5918        p_head = pp;        p_head = rp;
5919      }      }
5920    return;    return;
5921  }  }
5922    
5923    /*
5924     * Reads the whole file as a single string from `filebuf' and looks for
5925     * multi-line regular expressions, creating tags on matches.
5926     * readline already dealt with normal regexps.
5927     *
5928     * Idea by Ben Wing <ben@666.com> (2002).
5929     */
5930    static void
5931    regex_tag_multiline ()
5932    {
5933      char *buffer = filebuf.buffer;
5934      regexp *rp;
5935      char *name;
5936    
5937      for (rp = p_head; rp != NULL; rp = rp->p_next)
5938        {
5939          int match = 0;
5940    
5941          if (!rp->multi_line)
5942            continue;               /* skip normal regexps */
5943    
5944          /* Generic initialisations before parsing file from memory. */
5945          lineno = 1;               /* reset global line number */
5946          charno = 0;               /* reset global char number */
5947          linecharno = 0;           /* reset global char number of line start */
5948    
5949          /* Only use generic regexps or those for the current language. */
5950          if (rp->lang != NULL && rp->lang != curfdp->lang)
5951            continue;
5952    
5953          while (match >= 0 && match < filebuf.len)
5954            {
5955              match = re_search (rp->pat, buffer, filebuf.len, charno,
5956                                 filebuf.len - match, &rp->regs);
5957              switch (match)
5958                {
5959                case -2:
5960                  /* Some error. */
5961                  if (!rp->error_signaled)
5962                    {
5963                      error ("regexp stack overflow while matching \"%s\"",
5964                             rp->pattern);
5965                      rp->error_signaled = TRUE;
5966                    }
5967                  break;
5968                case -1:
5969                  /* No match. */
5970                  break;
5971                default:
5972                  if (match == rp->regs.end[0])
5973                    {
5974                      if (!rp->error_signaled)
5975                        {
5976                          error ("regexp matches the empty string: \"%s\"",
5977                                 rp->pattern);
5978                          rp->error_signaled = TRUE;
5979                        }
5980                      match = -3;   /* exit from while loop */
5981                      break;
5982                    }
5983    
5984                  /* Match occurred.  Construct a tag. */
5985                  while (charno < rp->regs.end[0])
5986                    if (buffer[charno++] == '\n')
5987                      lineno++, linecharno = charno;
5988                  name = rp->name;
5989                  if (name[0] == '\0')
5990                    name = NULL;
5991                  else /* make a named tag */
5992                    name = substitute (buffer, rp->name, &rp->regs);
5993                  if (rp->force_explicit_name)
5994                    /* Force explicit tag name, if a name is there. */
5995                    pfnote (name, TRUE, buffer + linecharno,
5996                            charno - linecharno + 1, lineno, linecharno);
5997                  else
5998                    make_tag (name, strlen (name), TRUE, buffer + linecharno,
5999                              charno - linecharno + 1, lineno, linecharno);
6000                  break;
6001                }
6002            }
6003        }
6004    }
6005    
6006  #endif /* ETAGS_REGEXPS */  #endif /* ETAGS_REGEXPS */
6007    
6008    
# Line 5531  nocase_tail (cp) Line 6022  nocase_tail (cp)
6022    return FALSE;    return FALSE;
6023  }  }
6024    
6025  static char *  static void
6026  get_tag (bp)  get_tag (bp, namepp)
6027       register char *bp;       register char *bp;
6028         char **namepp;
6029  {  {
6030    register char *cp, *name;    register char *cp = bp;
6031    
6032    if (*bp == '\0')    if (*bp != '\0')
6033      return NULL;      {
6034    /* Go till you get to white space or a syntactic break */        /* Go till you get to white space or a syntactic break */
6035    for (cp = bp + 1; !notinname (*cp); cp++)        for (cp = bp + 1; !notinname (*cp); cp++)
6036      continue;          continue;
6037    name = savenstr (bp, cp-bp);        make_tag (bp, cp - bp, TRUE,
6038    pfnote (name, TRUE,                  lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
6039            lb.buffer, cp - lb.buffer + 1, lineno, linecharno);      }
   return name;  
 }  
6040    
6041  /* Initialize a linebuffer for use */    if (namepp != NULL)
6042  static void      *namepp = savenstr (bp, cp - bp);
 initbuffer (lbp)  
      linebuffer *lbp;  
 {  
   lbp->size = (DEBUG) ? 3 : 200;  
   lbp->buffer = xnew (lbp->size, char);  
   lbp->buffer[0] = '\0';  
   lbp->len = 0;  
6043  }  }
6044    
6045  /*  /*
# Line 5564  initbuffer (lbp) Line 6047  initbuffer (lbp)
6047   * newline or CR-NL, if any.  Return the number of characters read from   * newline or CR-NL, if any.  Return the number of characters read from
6048   * `stream', which is the length of the line including the newline.   * `stream', which is the length of the line including the newline.
6049   *   *
6050   * On DOS or Windows we do not count the CR character, if any, before the   * On DOS or Windows we do not count the CR character, if any before the
6051   * NL, in the returned length; this mirrors the behavior of emacs on those   * NL, in the returned length; this mirrors the behavior of Emacs on those
6052   * platforms (for text files, it translates CR-NL to NL as it reads in the   * platforms (for text files, it translates CR-NL to NL as it reads in the
6053   * file).   * file).
6054     *
6055     * If multi-line regular expressions are requested, each line read is
6056     * appended to `filebuf'.
6057   */   */
6058  static long  static long
6059  readline_internal (lbp, stream)  readline_internal (lbp, stream)
# Line 5626  readline_internal (lbp, stream) Line 6112  readline_internal (lbp, stream)
6112      }      }
6113    lbp->len = p - buffer;    lbp->len = p - buffer;
6114    
6115      if (need_filebuf              /* we need filebuf for multi-line regexps */
6116          && chars_deleted > 0)     /* not at EOF */
6117        {
6118          while (filebuf.size <= filebuf.len + lbp->len + 1) /* +1 for \n */
6119            {
6120              /* Expand filebuf. */
6121              filebuf.size *= 2;
6122              xrnew (filebuf.buffer, filebuf.size, char);
6123            }
6124          strncpy (filebuf.buffer + filebuf.len, lbp->buffer, lbp->len);
6125          filebuf.len += lbp->len;
6126          filebuf.buffer[filebuf.len++] = '\n';
6127          filebuf.buffer[filebuf.len] = '\0';
6128        }
6129    
6130    return lbp->len + chars_deleted;    return lbp->len + chars_deleted;
6131  }  }
6132    
6133  /*  /*
6134   * Like readline_internal, above, but in addition try to match the   * Like readline_internal, above, but in addition try to match the
6135   * input line against relevant regular expressions.   * input line against relevant regular expressions and manage #line
6136     * directives.
6137   */   */
6138  static void  static void
6139  readline (lbp, stream)  readline (lbp, stream)
# Line 5736  readline (lbp, stream) Line 6238  readline (lbp, stream)
6238                            fdhead->infabsdir = savestr (curfdp->infabsdir);                            fdhead->infabsdir = savestr (curfdp->infabsdir);
6239                            fdhead->taggedfname = taggedfname;                            fdhead->taggedfname = taggedfname;
6240                            fdhead->usecharno = FALSE;                            fdhead->usecharno = FALSE;
6241                              fdhead->prop = NULL;
6242                              fdhead->written = FALSE;
6243                            curfdp = fdhead;                            curfdp = fdhead;
6244                          }                          }
6245                      }                      }
# Line 5752  readline (lbp, stream) Line 6256  readline (lbp, stream)
6256          {          {
6257            if (result > 0)            if (result > 0)
6258              {              {
6259              /* Do a tail recursion on ourselves, thus discarding the contents                /* Do a tail recursion on ourselves, thus discarding the contents
6260                 of the line buffer. */                   of the line buffer. */
6261                readline (lbp, stream);                readline (lbp, stream);
6262                return;                return;
6263              }              }
# Line 5766  readline (lbp, stream) Line 6270  readline (lbp, stream)
6270  #ifdef ETAGS_REGEXPS  #ifdef ETAGS_REGEXPS
6271    {    {
6272      int match;      int match;
6273      pattern *pp;      regexp *rp;
6274        char *name;
6275    
6276      /* Match against relevant patterns. */      /* Match against relevant regexps. */
6277      if (lbp->len > 0)      if (lbp->len > 0)
6278        for (pp = p_head; pp != NULL; pp = pp->p_next)        for (rp = p_head; rp != NULL; rp = rp->p_next)
6279          {          {
6280            /* Only use generic regexps or those for the current language. */            /* Only use generic regexps or those for the current language.
6281            if (pp->lang != NULL && pp->lang != fdhead->lang)               Also do not use multiline regexps, which is the job of
6282                 regex_tag_multiline. */
6283              if ((rp->lang != NULL && rp->lang != fdhead->lang)
6284                  || rp->multi_line)
6285              continue;              continue;
6286    
6287            match = re_match (pp->pat, lbp->buffer, lbp->len, 0, &pp->regs);            match = re_match (rp->pat, lbp->buffer, lbp->len, 0, &rp->regs);
6288            switch (match)            switch (match)
6289              {              {
6290              case -2:              case -2:
6291                /* Some error. */                /* Some error. */
6292                if (!pp->error_signaled)                if (!rp->error_signaled)
6293                  {                  {
6294                    error ("error while matching \"%s\"", pp->regex);                    error ("regexp stack overflow while matching \"%s\"",
6295                    pp->error_signaled = TRUE;                           rp->pattern);
6296                      rp->error_signaled = TRUE;
6297                  }                  }
6298                break;                break;
6299              case -1:              case -1:
6300                /* No match. */                /* No match. */
6301                break;                break;
6302              default:              case 0:
6303                /* Match occurred.  Construct a tag. */                /* Empty string matched. */
6304                if (pp->name_pattern[0] != '\0')                if (!rp->error_signaled)
6305                  {                  {
6306                    /* Make a named tag. */                    error ("regexp matches the empty string: \"%s\"", rp->pattern);
6307                    char *name = substitute (lbp->buffer,                    rp->error_signaled = TRUE;
                                            pp->name_pattern, &pp->regs);  
                   if (name != NULL)  
                     pfnote (name, TRUE, lbp->buffer, match, lineno, linecharno);  
6308                  }                  }
6309                  break;
6310                default:
6311                  /* Match occurred.  Construct a tag. */
6312                  name = rp->name;
6313                  if (name[0] == '\0')
6314                    name = NULL;
6315                  else /* make a named tag */
6316                    name = substitute (lbp->buffer, rp->name, &rp->regs);
6317                  if (rp->force_explicit_name)
6318                    /* Force explicit tag name, if a name is there. */
6319                    pfnote (name, TRUE, lbp->buffer, match, lineno, linecharno);
6320                else                else
6321                  {                  make_tag (name, strlen (name), TRUE,
                   /* Make an unnamed tag. */  
                   pfnote ((char *)NULL, TRUE,  
6322                            lbp->buffer, match, lineno, linecharno);                            lbp->buffer, match, lineno, linecharno);
                 }  
6323                break;                break;
6324              }              }
6325          }          }
# Line 5884  etags_strchr (sp, c) Line 6398  etags_strchr (sp, c)
6398  }  }
6399    
6400  /*  /*
6401   * Return TRUE if the two strings are equal, ignoring case for alphabetic   * Compare two strings, ignoring case for alphabetic characters.
  * characters.  
6402   *   *
6403   * Analogous to BSD's strcasecmp, included for portability.   * Same as BSD's strcasecmp, included for portability.
6404   */   */
6405  static bool  static int
6406  strcaseeq (s1, s2)  etags_strcasecmp (s1, s2)
6407       register const char *s1;       register const char *s1;
6408       register const char *s2;       register const char *s2;
6409  {  {
# Line 5900  strcaseeq (s1, s2) Line 6413  strcaseeq (s1, s2)
6413               : *s1 == *s2))               : *s1 == *s2))
6414      s1++, s2++;      s1++, s2++;
6415    
6416    return (*s1 == *s2);    return (ISALPHA (*s1) && ISALPHA (*s2)
6417              ? lowcase (*s1) - lowcase (*s2)
6418              : *s1 - *s2);
6419    }
6420    
6421    /*
6422     * Compare two strings, ignoring case for alphabetic characters.
6423     * Stop after a given number of characters
6424     *
6425     * Same as BSD's strncasecmp, included for portability.
6426     */
6427    static int
6428    etags_strncasecmp (s1, s2, n)
6429         register const char *s1;
6430         register const char *s2;
6431         register int n;
6432    {
6433      while (*s1 != '\0' && n-- > 0
6434             && (ISALPHA (*s1) && ISALPHA (*s2)
6435                 ? lowcase (*s1) == lowcase (*s2)
6436                 : *s1 == *s2))
6437        s1++, s2++;
6438    
6439      if (n < 0)
6440        return 0;
6441      else
6442        return (ISALPHA (*s1) && ISALPHA (*s2)
6443                ? lowcase (*s1) - lowcase (*s2)
6444                : *s1 - *s2);
6445  }  }
6446    
6447  /* Skip spaces, return new pointer. */  /* Skip spaces, return new pointer. */
# Line 6021  etags_getcwd () Line 6562  etags_getcwd ()
6562    linebuffer path;    linebuffer path;
6563    FILE *pipe;    FILE *pipe;
6564    
6565    initbuffer (&path);    linebuffer_init (&path);
6566    pipe = (FILE *) popen ("pwd 2>/dev/null", "r");    pipe = (FILE *) popen ("pwd 2>/dev/null", "r");
6567    if (pipe == NULL || readline_internal (&path, pipe) == 0)    if (pipe == NULL || readline_internal (&path, pipe) == 0)
6568      pfatal ("pwd");      pfatal ("pwd");
# Line 6187  canonicalize_filename (fn) Line 6728  canonicalize_filename (fn)
6728  #endif  #endif
6729  }  }
6730    
6731    
6732    /* Initialize a linebuffer for use */
6733    static void
6734    linebuffer_init (lbp)
6735         linebuffer *lbp;
6736    {
6737      lbp->size = (DEBUG) ? 3 : 200;
6738      lbp->buffer = xnew (lbp->size, char);
6739      lbp->buffer[0] = '\0';
6740      lbp->len = 0;
6741    }
6742    
6743  /* Set the minimum size of a string contained in a linebuffer. */  /* Set the minimum size of a string contained in a linebuffer. */
6744  static void  static void
6745  linebuffer_setlen (lbp, toksize)  linebuffer_setlen (lbp, toksize)
# Line 6201  linebuffer_setlen (lbp, toksize) Line 6754  linebuffer_setlen (lbp, toksize)
6754    lbp->len = toksize;    lbp->len = toksize;
6755  }  }
6756    
6757  /* Like malloc but get fatal error if memory is exhausted.  */  /* Like malloc but get fatal error if memory is exhausted. */
6758  static PTR  static PTR
6759  xmalloc (size)  xmalloc (size)
6760       unsigned int size;       unsigned int size;
# Line 6229  xrealloc (ptr, size) Line 6782  xrealloc (ptr, size)
6782   * indent-tabs-mode: t   * indent-tabs-mode: t
6783   * tab-width: 8   * tab-width: 8
6784   * fill-column: 79   * fill-column: 79
6785   * c-font-lock-extra-types: ("FILE" "bool" "language" "linebuffer" "fdesc" "node")   * c-font-lock-extra-types: ("FILE" "bool" "language" "linebuffer" "fdesc" "node" "regexp")
6786   * End:   * End:
6787   */   */

Legend:
Removed from v.3.21  
changed lines
  Added in v.3.21.2.1

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26