/[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.11 by eggert, Sat Mar 23 06:48:31 2002 UTC revision 3.12 by pot, Mon Apr 15 14:18:47 2002 UTC
# Line 1  Line 1 
1  /* Tags file maker to go with GNU Emacs           -*- coding: latin-1 -*-  /* Tags file maker to go with GNU Emacs           -*- coding: latin-1 -*-
2     Copyright (C) 1984, 1987-1989, 1993-1995, 1998-2001     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.
# Line 33  Inc., 59 Temple Place - Suite 330, Bosto Line 33  Inc., 59 Temple Place - Suite 330, Bosto
33   *      Francesco Potort́ <pot@gnu.org> has maintained it since 1993.   *      Francesco Potort́ <pot@gnu.org> has maintained it since 1993.
34   */   */
35    
36  char pot_etags_version[] = "@(#) pot revision number is 15.2";  char pot_etags_version[] = "@(#) pot revision number is 15.10";
37    
38  #define TRUE    1  #define TRUE    1
39  #define FALSE   0  #define FALSE   0
# Line 228  typedef void Lang_function __P((FILE *)) Line 228  typedef void Lang_function __P((FILE *))
228    
229  typedef struct  typedef struct
230  {  {
231    char *suffix;    char *suffix;                 /* file name suffix for this compressor */
232    char *command;                /* Takes one arg and decompresses to stdout */    char *command;                /* takes one arg and decompresses to stdout */
233  } compressor;  } compressor;
234    
235  typedef struct  typedef struct
236  {  {
237    char *name;    char *name;                   /* language name */
238    Lang_function *function;    bool metasource;              /* source used to generate other sources */
239    char **filenames;    Lang_function *function;      /* parse function */
240    char **suffixes;    char **filenames;             /* names of this language's files */
241    char **interpreters;    char **suffixes;              /* name suffixes of this language's files */
242      char **interpreters;          /* interpreters for this language */
243  } language;  } language;
244    
245    typedef struct fdesc
246    {
247      struct fdesc *next;           /* for the linked list */
248      char *infname;                /* uncompressed input file name */
249      char *infabsname;             /* absolute uncompressed input file name */
250      char *infabsdir;              /* absolute dir of input file */
251      char *taggedfname;            /* file name to write in tagfile */
252      language *lang;               /* language of file */
253      char *prop;                   /* file properties to write in tagfile */
254      bool usecharno;               /* etags tags shall contain char number */
255    } fdesc;
256    
257  typedef struct node_st  typedef struct node_st
258  {                               /* sorting structure            */  {                               /* sorting structure */
259    char *name;                   /* function or type name        */    struct node_st *left, *right; /* left and right sons */
260    char *file;                   /* file name                    */    fdesc *fdp;                   /* description of file to whom tag belongs */
261    bool is_func;                 /* use pattern or line no       */    char *name;                   /* tag name */
262    bool been_warned;             /* set if noticed dup           */    char *pat;                    /* search pattern */
263    int lno;                      /* line number tag is on        */    bool valid;                   /* write this tag on the tag file */
264      bool is_func;                 /* function tag: use pattern in CTAGS mode */
265      bool been_warned;             /* warning already given for duplicated tag */
266      int lno;                      /* line number tag is on */
267    long cno;                     /* character number line starts on */    long cno;                     /* character number line starts on */
   char *pat;                    /* search pattern               */  
   struct node_st *left, *right; /* left and right sons          */  
268  } node;  } node;
269    
270  /*  /*
# Line 267  typedef struct Line 281  typedef struct
281    char *buffer;    char *buffer;
282  } linebuffer;  } linebuffer;
283    
284    /* Used to support mixing of --lang and file names. */
285    typedef struct
286    {
287      enum {
288        at_language,                /* a language specification */
289        at_regexp,                  /* a regular expression */
290        at_icregexp,                /* same, but with case ignored */
291        at_filename                 /* a file name */
292      } arg_type;                   /* argument type */
293      language *lang;               /* language associated with the argument */
294      char *what;                   /* the argument itself */
295    } argument;
296    
297    #ifdef ETAGS_REGEXPS
298    /* Structure defining a regular expression. */
299    typedef struct pattern
300    {
301      struct pattern *p_next;
302      language *lang;
303      char *regex;
304      struct re_pattern_buffer *pat;
305      struct re_registers regs;
306      char *name_pattern;
307      bool error_signaled;
308      bool ignore_case;
309    } pattern;
310    #endif /* ETAGS_REGEXPS */
311    
312    
313  /* Many compilers barf on this:  /* Many compilers barf on this:
314          Lang_function Ada_funcs;          Lang_function Ada_funcs;
315     so let's write it this way */     so let's write it this way */
# Line 322  static void add_node __P((node *, node * Line 365  static void add_node __P((node *, node *
365    
366  static void init __P((void));  static void init __P((void));
367  static void initbuffer __P((linebuffer *));  static void initbuffer __P((linebuffer *));
368  static void find_entries __P((char *, FILE *));  static void process_file __P((char *, language *));
369    static void find_entries __P((FILE *));
370  static void free_tree __P((node *));  static void free_tree __P((node *));
371  static void pfnote __P((char *, bool, char *, int, int, long));  static void pfnote __P((char *, bool, char *, int, int, long));
372  static void new_pfnote __P((char *, int, bool, char *, int, int, long));  static void new_pfnote __P((char *, int, bool, char *, int, int, long));
373  static void process_file __P((char *));  static void invalidate_nodes __P((fdesc *, node *));
374  static void put_entries __P((node *));  static void put_entries __P((node *));
375    
376  static char *concat __P((char *, char *, char *));  static char *concat __P((char *, char *, char *));
# Line 355  static char *cwd;              /* current working di Line 399  static char *cwd;              /* current working di
399  static char *tagfiledir;        /* directory of tagfile */  static char *tagfiledir;        /* directory of tagfile */
400  static FILE *tagf;              /* ioptr for tags file */  static FILE *tagf;              /* ioptr for tags file */
401    
402  static char *curfile;           /* current input uncompressed file name */  static fdesc *fdhead;           /* head of file description list */
403  static char *curfiledir;        /* absolute dir of curfile */  static fdesc *curfdp;           /* current file description */
 static char *curtagfname;       /* current file name to write in tagfile */  
 static language *curlang;       /* current language */  
   
404  static int lineno;              /* line number of current line */  static int lineno;              /* line number of current line */
405  static long charno;             /* current character number */  static long charno;             /* current character number */
406  static long linecharno;         /* charno of start of current line */  static long linecharno;         /* charno of start of current line */
407  static char *dbp;               /* pointer to start of current tag */  static char *dbp;               /* pointer to start of current tag */
408  static bool nocharno;           /* only use line number when making tag  */  
409  static const int invalidcharno = -1;  static const int invalidcharno = -1;
410    
411  static node *head;              /* the head of the binary tree of tags */  static node *nodehead;          /* the head of the binary tree of tags */
412    
413  static linebuffer lb;           /* the current line */  static linebuffer lb;           /* the current line */
414    
# Line 386  static char Line 427  static char
427    *midtk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$0123456789";    *midtk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$0123456789";
428    
429  static bool append_to_tagfile;  /* -a: append to tags */  static bool append_to_tagfile;  /* -a: append to tags */
430  /* The following four default to TRUE for etags, but to FALSE for ctags.  */  /* The next four default to TRUE for etags, but to FALSE for ctags.  */
431  static bool typedefs;           /* -t: create tags for C and Ada typedefs */  static bool typedefs;           /* -t: create tags for C and Ada typedefs */
432  static bool typedefs_or_cplusplus; /* -T: create tags for C typedefs, level */  static bool typedefs_or_cplusplus; /* -T: create tags for C typedefs, level */
433                                  /* 0 struct/enum/union decls, and C++ */                                  /* 0 struct/enum/union decls, and C++ */
# Line 394  static bool typedefs_or_cplusplus; /* -T Line 435  static bool typedefs_or_cplusplus; /* -T
435  static bool constantypedefs;    /* -d: create tags for C #define, enum */  static bool constantypedefs;    /* -d: create tags for C #define, enum */
436                                  /* constants and variables. */                                  /* constants and variables. */
437                                  /* -D: opposite of -d.  Default under ctags. */                                  /* -D: opposite of -d.  Default under ctags. */
 static bool declarations;       /* --declarations: tag them and extern in C&Co*/  
438  static bool globals;            /* create tags for global variables */  static bool globals;            /* create tags for global variables */
439  static bool no_line_directive;  /* ignore #line directives */  static bool declarations;       /* --declarations: tag them and extern in C&Co*/
440  static bool members;            /* create tags for C member variables */  static bool members;            /* create tags for C member variables */
441    static bool no_line_directive;  /* ignore #line directives */
442  static bool update;             /* -u: update tags */  static bool update;             /* -u: update tags */
443  static bool vgrind_style;       /* -v: create vgrind style index output */  static bool vgrind_style;       /* -v: create vgrind style index output */
444  static bool no_warnings;        /* -w: suppress warnings */  static bool no_warnings;        /* -w: suppress warnings */
# Line 406  static bool cplusplus;         /* .[hc] means C Line 447  static bool cplusplus;         /* .[hc] means C
447  static bool noindentypedefs;    /* -I: ignore indentation in C */  static bool noindentypedefs;    /* -I: ignore indentation in C */
448  static bool packages_only;      /* --packages-only: in Ada, only tag packages*/  static bool packages_only;      /* --packages-only: in Ada, only tag packages*/
449    
450    #ifdef ETAGS_REGEXPS
451    /* List of all regexps. */
452    static pattern *p_head;
453    
454    /* How many characters in the character set.  (From regex.c.)  */
455    #define CHAR_SET_SIZE 256
456    /* Translation table for case-insensitive matching. */
457    static char lc_trans[CHAR_SET_SIZE];
458    #endif /* ETAGS_REGEXPS */
459    
460  #ifdef LONG_OPTIONS  #ifdef LONG_OPTIONS
461  static struct option longopts[] =  static struct option longopts[] =
462  {  {
463    { "packages-only",      no_argument,       &packages_only,     TRUE  },    { "packages-only",      no_argument,       &packages_only,     TRUE  },
   { "append",             no_argument,       NULL,               'a'   },  
   { "backward-search",    no_argument,       NULL,               'B'   },  
464    { "c++",                no_argument,       NULL,               'C'   },    { "c++",                no_argument,       NULL,               'C'   },
   { "cxref",              no_argument,       NULL,               'x'   },  
   { "defines",            no_argument,       NULL,               'd'   },  
465    { "declarations",       no_argument,       &declarations,      TRUE  },    { "declarations",       no_argument,       &declarations,      TRUE  },
   { "no-defines",         no_argument,       NULL,               'D'   },  
   { "globals",            no_argument,       &globals,           TRUE  },  
   { "no-globals",         no_argument,       &globals,           FALSE },  
466    { "no-line-directive",  no_argument,       &no_line_directive, TRUE  },    { "no-line-directive",  no_argument,       &no_line_directive, TRUE  },
467    { "help",               no_argument,       NULL,               'h'   },    { "help",               no_argument,       NULL,               'h'   },
468    { "help",               no_argument,       NULL,               'H'   },    { "help",               no_argument,       NULL,               'H'   },
469    { "ignore-indentation", no_argument,       NULL,               'I'   },    { "ignore-indentation", no_argument,       NULL,               'I'   },
   { "include",            required_argument, NULL,               'i'   },  
470    { "language",           required_argument, NULL,               'l'   },    { "language",           required_argument, NULL,               'l'   },
471    { "members",            no_argument,       &members,           TRUE  },    { "members",            no_argument,       &members,           TRUE  },
472    { "no-members",         no_argument,       &members,           FALSE },    { "no-members",         no_argument,       &members,           FALSE },
   { "no-warn",            no_argument,       NULL,               'w'   },  
473    { "output",             required_argument, NULL,               'o'   },    { "output",             required_argument, NULL,               'o'   },
474  #ifdef ETAGS_REGEXPS  #ifdef ETAGS_REGEXPS
475    { "regex",              required_argument, NULL,               'r'   },    { "regex",              required_argument, NULL,               'r'   },
476    { "no-regex",           no_argument,       NULL,               'R'   },    { "no-regex",           no_argument,       NULL,               'R'   },
477    { "ignore-case-regex",  required_argument, NULL,               'c'   },    { "ignore-case-regex",  required_argument, NULL,               'c'   },
478  #endif /* ETAGS_REGEXPS */  #endif /* ETAGS_REGEXPS */
479      { "version",            no_argument,       NULL,               'V'   },
480    
481    #if CTAGS /* Etags options */
482      { "backward-search",    no_argument,       NULL,               'B'   },
483      { "cxref",              no_argument,       NULL,               'x'   },
484      { "defines",            no_argument,       NULL,               'd'   },
485      { "globals",            no_argument,       &globals,           TRUE  },
486    { "typedefs",           no_argument,       NULL,               't'   },    { "typedefs",           no_argument,       NULL,               't'   },
487    { "typedefs-and-c++",   no_argument,       NULL,               'T'   },    { "typedefs-and-c++",   no_argument,       NULL,               'T'   },
488    { "update",             no_argument,       NULL,               'u'   },    { "update",             no_argument,       NULL,               'u'   },
   { "version",            no_argument,       NULL,               'V'   },  
489    { "vgrind",             no_argument,       NULL,               'v'   },    { "vgrind",             no_argument,       NULL,               'v'   },
490      { "no-warn",            no_argument,       NULL,               'w'   },
491    
492    #else /* Ctags options */
493      { "append",             no_argument,       NULL,               'a'   },
494      { "no-defines",         no_argument,       NULL,               'D'   },
495      { "no-globals",         no_argument,       &globals,           FALSE },
496      { "include",            required_argument, NULL,               'i'   },
497    #endif
498    { NULL }    { NULL }
499  };  };
500  #endif /* LONG_OPTIONS */  #endif /* LONG_OPTIONS */
501    
 #ifdef ETAGS_REGEXPS  
 /* Structure defining a regular expression.  Elements are  
    the compiled pattern, and the name string. */  
 typedef struct pattern  
 {  
   struct pattern *p_next;  
   language *lang;  
   char *regex;  
   struct re_pattern_buffer *pat;  
   struct re_registers regs;  
   char *name_pattern;  
   bool error_signaled;  
 } pattern;  
   
 /* List of all regexps. */  
 static pattern *p_head = NULL;  
   
 /* How many characters in the character set.  (From regex.c.)  */  
 #define CHAR_SET_SIZE 256  
 /* Translation table for case-insensitive matching. */  
 static char lc_trans[CHAR_SET_SIZE];  
 #endif /* ETAGS_REGEXPS */  
   
502  static compressor compressors[] =  static compressor compressors[] =
503  {  {
504    { "z", "gzip -d -c"},    { "z", "gzip -d -c"},
# Line 480  static compressor compressors[] = Line 513  static compressor compressors[] =
513   * Language stuff.   * Language stuff.
514   */   */
515    
 /* Non-NULL if language fixed. */  
 static language *forced_lang = NULL;  
   
516  /* Ada code */  /* Ada code */
517  static char *Ada_suffixes [] =  static char *Ada_suffixes [] =
518    { "ads", "adb", "ada", NULL };    { "ads", "adb", "ada", NULL };
# Line 582  static char *Yacc_suffixes [] = Line 612  static char *Yacc_suffixes [] =
612    
613  static language lang_names [] =  static language lang_names [] =
614  {  {
615    { "ada",        Ada_funcs,            NULL, Ada_suffixes,             NULL },    { "ada",      FALSE, Ada_funcs,            NULL, Ada_suffixes,        NULL },
616    { "asm",        Asm_labels,           NULL, Asm_suffixes,             NULL },    { "asm",      FALSE, Asm_labels,           NULL, Asm_suffixes,        NULL },
617    { "c",          default_C_entries,    NULL, default_C_suffixes,       NULL },    { "c",        FALSE, default_C_entries,    NULL, default_C_suffixes,  NULL },
618    { "c++",        Cplusplus_entries,    NULL, Cplusplus_suffixes,       NULL },    { "c++",      FALSE, Cplusplus_entries,    NULL, Cplusplus_suffixes,  NULL },
619    { "c*",         Cstar_entries,        NULL, Cstar_suffixes,           NULL },    { "c*",       FALSE, Cstar_entries,        NULL, Cstar_suffixes,      NULL },
620    { "cobol",      Cobol_paragraphs,     NULL, Cobol_suffixes,           NULL },    { "cobol",    FALSE, Cobol_paragraphs,     NULL, Cobol_suffixes,      NULL },
621    { "erlang",     Erlang_functions,     NULL, Erlang_suffixes,          NULL },    { "erlang",   FALSE, Erlang_functions,     NULL, Erlang_suffixes,     NULL },
622    { "fortran",    Fortran_functions,    NULL, Fortran_suffixes,         NULL },    { "fortran",  FALSE, Fortran_functions,    NULL, Fortran_suffixes,    NULL },
623    { "java",       Cjava_entries,        NULL, Cjava_suffixes,           NULL },    { "java",     FALSE, Cjava_entries,        NULL, Cjava_suffixes,      NULL },
624    { "lisp",       Lisp_functions,       NULL, Lisp_suffixes,            NULL },    { "lisp",     FALSE, Lisp_functions,       NULL, Lisp_suffixes,       NULL },
625    { "makefile",   Makefile_targets,     Makefile_filenames, NULL,       NULL },    { "makefile", FALSE, Makefile_targets,     Makefile_filenames, NULL,  NULL },
626    { "pascal",     Pascal_functions,     NULL, Pascal_suffixes,          NULL },    { "pascal",   FALSE, Pascal_functions,     NULL, Pascal_suffixes,     NULL },
627    { "perl",       Perl_functions,     NULL, Perl_suffixes, Perl_interpreters },    { "perl",     FALSE, Perl_functions,NULL, Perl_suffixes, Perl_interpreters },
628    { "php",        PHP_functions,        NULL, PHP_suffixes,             NULL },    { "php",      FALSE, PHP_functions,        NULL, PHP_suffixes,        NULL },
629    { "postscript", Postscript_functions, NULL, Postscript_suffixes,      NULL },    { "postscript",FALSE, Postscript_functions,NULL, Postscript_suffixes, NULL },
630    { "proc",       plain_C_entries,      NULL, plain_C_suffixes,         NULL },    { "proc",     FALSE, plain_C_entries,      NULL, plain_C_suffixes,    NULL },
631    { "prolog",     Prolog_functions,     NULL, Prolog_suffixes,          NULL },    { "prolog",   FALSE, Prolog_functions,     NULL, Prolog_suffixes,     NULL },
632    { "python",     Python_functions,     NULL, Python_suffixes,          NULL },    { "python",   FALSE, Python_functions,     NULL, Python_suffixes,     NULL },
633    { "scheme",     Scheme_functions,     NULL, Scheme_suffixes,          NULL },    { "scheme",   FALSE, Scheme_functions,     NULL, Scheme_suffixes,     NULL },
634    { "tex",        TeX_commands,         NULL, TeX_suffixes,             NULL },    { "tex",      FALSE, TeX_commands,         NULL, TeX_suffixes,        NULL },
635    { "texinfo",    Texinfo_nodes,        NULL, Texinfo_suffixes,         NULL },    { "texinfo",  FALSE, Texinfo_nodes,        NULL, Texinfo_suffixes,    NULL },
636    { "yacc",       Yacc_entries,         NULL, Yacc_suffixes,            NULL },    { "yacc",      TRUE, Yacc_entries,         NULL, Yacc_suffixes,       NULL },
637    { "auto", NULL },             /* default guessing scheme */    { "auto", FALSE, NULL },             /* default guessing scheme */
638    { "none", just_read_file },   /* regexp matching only */    { "none", FALSE, just_read_file },   /* regexp matching only */
639    { NULL, NULL }                /* end of list */    { NULL, FALSE, NULL }                /* end of list */
640  };  };
641    
642    
# Line 649  static void Line 679  static void
679  print_version ()  print_version ()
680  {  {
681    printf ("%s (%s %s)\n", (CTAGS) ? "ctags" : "etags", EMACS_NAME, VERSION);    printf ("%s (%s %s)\n", (CTAGS) ? "ctags" : "etags", EMACS_NAME, VERSION);
682    puts ("Copyright (C) 1999 Free Software Foundation, Inc. and Ken Arnold");    puts ("Copyright (C) 2002 Free Software Foundation, Inc. and Ken Arnold");
683    puts ("This program is distributed under the same terms as Emacs");    puts ("This program is distributed under the same terms as Emacs");
684    
685    exit (GOOD);    exit (GOOD);
# Line 667  These are the options accepted by %s.\n" Line 697  These are the options accepted by %s.\n"
697    puts ("Long option names do not work with this executable, as it is not\n\    puts ("Long option names do not work with this executable, as it is not\n\
698  linked with GNU getopt.");  linked with GNU getopt.");
699  #endif /* LONG_OPTIONS */  #endif /* LONG_OPTIONS */
700    puts ("A - as file name means read names from stdin (one per line).");    puts ("  A - as file name means read names from stdin (one per line).\n\
701    if (!CTAGS)  Absolute names are stored in the output file as they are.\n\
702      printf ("  Absolute names are stored in the output file as they are.\n\  Relative ones are stored relative to the output file's directory.\n");
 Relative ones are stored relative to the output file's directory.");  
   puts ("\n");  
703    
704    puts ("-a, --append\n\    if (!CTAGS)
705        puts ("-a, --append\n\
706          Append tag entries to existing tags file.");          Append tag entries to existing tags file.");
707    
708    puts ("--packages-only\n\    puts ("--packages-only\n\
709          For Ada files, only generate tags for packages .");          For Ada files, only generate tags for packages.");
710    
711    if (CTAGS)    if (CTAGS)
712      puts ("-B, --backward-search\n\      puts ("-B, --backward-search\n\
# Line 709  Relative ones are stored relative to the Line 738  Relative ones are stored relative to the
738          This makes the tags file smaller.");          This makes the tags file smaller.");
739    
740    if (!CTAGS)    if (!CTAGS)
741      {      puts ("-i FILE, --include=FILE\n\
       puts ("-i FILE, --include=FILE\n\  
742          Include a note in tag file indicating that, when searching for\n\          Include a note in tag file indicating that, when searching for\n\
743          a tag, one should also consult the tags file FILE after\n\          a tag, one should also consult the tags file FILE after\n\
744          checking the current file.");          checking the current file.");
745        puts ("-l LANG, --language=LANG\n\  
746      puts ("-l LANG, --language=LANG\n\
747          Force the following files to be considered as written in the\n\          Force the following files to be considered as written in the\n\
748          named language up to the next --language=LANG option.");          named language up to the next --language=LANG option.");
     }  
749    
750    if (CTAGS)    if (CTAGS)
751      puts ("--globals\n\      puts ("--globals\n\
# Line 758  Relative ones are stored relative to the Line 786  Relative ones are stored relative to the
786        puts ("-T, --typedefs-and-c++\n\        puts ("-T, --typedefs-and-c++\n\
787          Generate tag entries for C typedefs, C struct/enum/union tags,\n\          Generate tag entries for C typedefs, C struct/enum/union tags,\n\
788          and C++ member functions.");          and C++ member functions.");
789        puts ("-u, --update\n\      }
790    
791      if (CTAGS)
792        puts ("-u, --update\n\
793          Update the tag entries for the given files, leaving tag\n\          Update the tag entries for the given files, leaving tag\n\
794          entries for other files in place.  Currently, this is\n\          entries for other files in place.  Currently, this is\n\
795          implemented by deleting the existing entries for the given\n\          implemented by deleting the existing entries for the given\n\
796          files and then rewriting the new entries at the end of the\n\          files and then rewriting the new entries at the end of the\n\
797          tags file.  It is often faster to simply rebuild the entire\n\          tags file.  It is often faster to simply rebuild the entire\n\
798          tag file than to use this.");          tag file than to use this.");
799    
800      if (CTAGS)
801        {
802        puts ("-v, --vgrind\n\        puts ("-v, --vgrind\n\
803          Generates an index of items intended for human consumption,\n\          Generates an index of items intended for human consumption,\n\
804          similar to the output of vgrind.  The index is sorted, and\n\          similar to the output of vgrind.  The index is sorted, and\n\
# Line 793  Relative ones are stored relative to the Line 827  Relative ones are stored relative to the
827  }  }
828    
829    
 enum argument_type  
 {  
   at_language,  
   at_regexp,  
   at_filename,  
   at_icregexp  
 };  
   
 /* This structure helps us allow mixing of --lang and file names. */  
 typedef struct  
 {  
   enum argument_type arg_type;  
   char *what;  
   language *lang;               /* language of the regexp */  
 } argument;  
   
830  #ifdef VMS                      /* VMS specific functions */  #ifdef VMS                      /* VMS specific functions */
831    
832  #define EOS     '\0'  #define EOS     '\0'
# Line 942  main (argc, argv) Line 960  main (argc, argv)
960    int i;    int i;
961    unsigned int nincluded_files;    unsigned int nincluded_files;
962    char **included_files;    char **included_files;
   char *this_file;  
963    argument *argbuffer;    argument *argbuffer;
964    int current_arg, file_count;    int current_arg, file_count;
965    linebuffer filename_lb;    linebuffer filename_lb;
# Line 981  main (argc, argv) Line 998  main (argc, argv)
998      {      {
999        typedefs = typedefs_or_cplusplus = constantypedefs = TRUE;        typedefs = typedefs_or_cplusplus = constantypedefs = TRUE;
1000        globals = TRUE;        globals = TRUE;
       declarations = FALSE;  
       members = FALSE;  
1001      }      }
1002    
1003    while (1)    while (1)
1004      {      {
1005        int opt;        int opt;
1006        char *optstring;        char *optstring = "-";
1007    
1008  #ifdef ETAGS_REGEXPS  #ifdef ETAGS_REGEXPS
1009        optstring = "-aCdDf:Il:o:r:c:RStTi:BuvxwVhH";        optstring = "-r:Rc:";
 #else  
       optstring = "-aCdDf:Il:o:StTi:BuvxwVhH";  
1010  #endif /* ETAGS_REGEXPS */  #endif /* ETAGS_REGEXPS */
1011    
1012  #ifndef LONG_OPTIONS  #ifndef LONG_OPTIONS
1013        optstring = optstring + 1;        optstring = optstring + 1;
1014  #endif /* LONG_OPTIONS */  #endif /* LONG_OPTIONS */
1015    
1016          optstring = concat (optstring,
1017                              "Cf:Il:o:SVhH",
1018                              (CTAGS) ? "BxdtTuvw" : "aDi:");
1019    
1020        opt = getopt_long (argc, argv, optstring, longopts, 0);        opt = getopt_long (argc, argv, optstring, longopts, 0);
1021        if (opt == EOF)        if (opt == EOF)
1022          break;          break;
# Line 1020  main (argc, argv) Line 1037  main (argc, argv)
1037            break;            break;
1038    
1039            /* Common options. */            /* Common options. */
         case 'a': append_to_tagfile = TRUE;     break;  
1040          case 'C': cplusplus = TRUE;             break;          case 'C': cplusplus = TRUE;             break;
         case 'd': constantypedefs = TRUE;       break;  
         case 'D': constantypedefs = FALSE;      break;  
1041          case 'f':               /* for compatibility with old makefiles */          case 'f':               /* for compatibility with old makefiles */
1042          case 'o':          case 'o':
1043            if (tagfile)            if (tagfile)
# Line 1070  main (argc, argv) Line 1084  main (argc, argv)
1084          case 'H':          case 'H':
1085            print_help ();            print_help ();
1086            break;            break;
1087          case 't':  
           typedefs = TRUE;  
           break;  
         case 'T':  
           typedefs = typedefs_or_cplusplus = TRUE;  
           break;  
1088            /* Etags options */            /* Etags options */
1089          case 'i':          case 'a': append_to_tagfile = TRUE;                     break;
1090            included_files[nincluded_files++] = optarg;          case 'D': constantypedefs = FALSE;                      break;
1091            break;          case 'i': included_files[nincluded_files++] = optarg;   break;
1092    
1093            /* Ctags options. */            /* Ctags options. */
1094          case 'B': searchar = '?';       break;          case 'B': searchar = '?';                               break;
1095          case 'u': update = TRUE;        break;          case 'd': constantypedefs = TRUE;                       break;
1096          case 'v': vgrind_style = TRUE;  /*FALLTHRU*/          case 't': typedefs = TRUE;                              break;
1097          case 'x': cxref_style = TRUE;   break;          case 'T': typedefs = typedefs_or_cplusplus = TRUE;      break;
1098          case 'w': no_warnings = TRUE;   break;          case 'u': update = TRUE;                                break;
1099            case 'v': vgrind_style = TRUE;                    /*FALLTHRU*/
1100            case 'x': cxref_style = TRUE;                           break;
1101            case 'w': no_warnings = TRUE;                           break;
1102          default:          default:
1103            suggest_asking_for_help ();            suggest_asking_for_help ();
1104          }          }
# Line 1147  main (argc, argv) Line 1160  main (argc, argv)
1160     */     */
1161    for (i = 0; i < current_arg; ++i)    for (i = 0; i < current_arg; ++i)
1162      {      {
1163          static language *lang;    /* non-NULL if language is forced */
1164          char *this_file;
1165    
1166        switch (argbuffer[i].arg_type)        switch (argbuffer[i].arg_type)
1167          {          {
1168          case at_language:          case at_language:
1169            forced_lang = argbuffer[i].lang;            lang = argbuffer[i].lang;
1170            break;            break;
1171  #ifdef ETAGS_REGEXPS  #ifdef ETAGS_REGEXPS
1172          case at_regexp:          case at_regexp:
# Line 1180  main (argc, argv) Line 1196  main (argc, argv)
1196                   (one per line) and use them. */                   (one per line) and use them. */
1197                if (streq (this_file, "-"))                if (streq (this_file, "-"))
1198                  while (readline_internal (&filename_lb, stdin) > 0)                  while (readline_internal (&filename_lb, stdin) > 0)
1199                    process_file (filename_lb.buffer);                    process_file (filename_lb.buffer, lang);
1200                else                else
1201                  process_file (this_file);                  process_file (this_file, lang);
1202  #ifdef VMS  #ifdef VMS
1203              }              }
1204  #endif  #endif
# Line 1196  main (argc, argv) Line 1212  main (argc, argv)
1212    
1213    if (!CTAGS || cxref_style)    if (!CTAGS || cxref_style)
1214      {      {
1215        put_entries (head);        put_entries (nodehead);
1216        free_tree (head);        free_tree (nodehead);
1217        head = NULL;        nodehead = NULL;
1218        if (!CTAGS)        if (!CTAGS)
1219          while (nincluded_files-- > 0)          while (nincluded_files-- > 0)
1220            fprintf (tagf, "\f\n%s,include\n", *included_files++);            fprintf (tagf, "\f\n%s,include\n", *included_files++);
# Line 1227  main (argc, argv) Line 1243  main (argc, argv)
1243    tagf = fopen (tagfile, append_to_tagfile ? "a" : "w");    tagf = fopen (tagfile, append_to_tagfile ? "a" : "w");
1244    if (tagf == NULL)    if (tagf == NULL)
1245      pfatal (tagfile);      pfatal (tagfile);
1246    put_entries (head);    put_entries (nodehead);
1247    free_tree (head);    free_tree (nodehead);
1248    head = NULL;    nodehead = NULL;
1249    if (fclose (tagf) == EOF)    if (fclose (tagf) == EOF)
1250      pfatal (tagfile);      pfatal (tagfile);
1251    
1252    if (update)    if (update)
1253      {      {
1254        char cmd[BUFSIZ];        char cmd[BUFSIZ];
1255        sprintf (cmd, "sort -o %s %s", tagfile, tagfile);        sprintf (cmd, "sort %s -o %s", tagfile, tagfile);
1256        exit (system (cmd));        exit (system (cmd));
1257      }      }
1258    return GOOD;    return GOOD;
1259  }  }
1260    
1261    
   
1262  /*  /*
1263   * Return a compressor given the file name.  If EXTPTR is non-zero,   * Return a compressor given the file name.  If EXTPTR is non-zero,
1264   * return a pointer into FILE where the compressor-specific   * return a pointer into FILE where the compressor-specific
# Line 1362  get_language_from_filename (file) Line 1377  get_language_from_filename (file)
1377    return NULL;    return NULL;
1378  }  }
1379    
1380    
   
1381  /*  /*
1382   * This routine is called on each file argument.   * This routine is called on each file argument.
1383   */   */
1384  static void  static void
1385  process_file (file)  process_file (file, lang)
1386       char *file;       char *file;
1387         language *lang;
1388  {  {
1389    struct stat stat_buf;    struct stat stat_buf;
1390    FILE *inf;    FILE *inf;
1391      static const fdesc emptyfdesc;
1392      fdesc *fdp;
1393    compressor *compr;    compressor *compr;
1394    char *compressed_name, *uncompressed_name;    char *compressed_name, *uncompressed_name;
1395    char *ext, *real_name;    char *ext, *real_name;
# Line 1396  process_file (file) Line 1413  process_file (file)
1413        uncompressed_name = savenstr (file, ext - file);        uncompressed_name = savenstr (file, ext - file);
1414      }      }
1415    
1416    /* If the canonicalized uncompressed name has already be dealt with,    /* If the canonicalized uncompressed name
1417       skip it silently, else add it to the list. */       has already been dealt with, skip it silently. */
1418    {    for (fdp = fdhead; fdp != NULL; fdp = fdp->next)
1419      typedef struct processed_file      {
1420      {        assert (fdp->infname != NULL);
1421        char *filename;        if (streq (uncompressed_name, fdp->infname))
1422        struct processed_file *next;          goto cleanup;
1423      } processed_file;      }
1424      static processed_file *pf_head = NULL;  
1425      register processed_file *fnp;    /* Create a new input file description entry. */
1426      fdp = fdhead;
1427      for (fnp = pf_head; fnp != NULL; fnp = fnp->next)    fdhead = xnew (1, fdesc);
1428        if (streq (uncompressed_name, fnp->filename))    *fdhead = emptyfdesc;
1429          goto exit;    fdhead->next = fdp;
     fnp = pf_head;  
     pf_head = xnew (1, struct processed_file);  
     pf_head->filename = savestr (uncompressed_name);  
     pf_head->next = fnp;  
   }  
1430    
1431    if (stat (real_name, &stat_buf) != 0)    if (stat (real_name, &stat_buf) != 0)
1432      {      {
# Line 1461  process_file (file) Line 1473  process_file (file)
1473        if (real_name == NULL)        if (real_name == NULL)
1474          {          {
1475            perror (file);            perror (file);
1476            goto exit;            goto cleanup;
1477          }          }
1478      } /* try with a different name */      } /* try with a different name */
1479    
1480    if (!S_ISREG (stat_buf.st_mode))    if (!S_ISREG (stat_buf.st_mode))
1481      {      {
1482        error ("skipping %s: it is not a regular file.", real_name);        error ("skipping %s: it is not a regular file.", real_name);
1483        goto exit;        goto cleanup;
1484      }      }
1485    if (real_name == compressed_name)    if (real_name == compressed_name)
1486      {      {
# Line 1481  process_file (file) Line 1493  process_file (file)
1493    if (inf == NULL)    if (inf == NULL)
1494      {      {
1495        perror (real_name);        perror (real_name);
1496        goto exit;        goto cleanup;
1497      }      }
1498    
1499    curfile = uncompressed_name;    fdhead->infname = savestr (uncompressed_name);
1500    curfiledir = absolute_dirname (curfile, cwd);    fdhead->lang = lang;
1501    if (filename_is_absolute (curfile))    fdhead->infabsname = absolute_filename (uncompressed_name, cwd);
1502      fdhead->infabsdir = absolute_dirname (uncompressed_name, cwd);
1503      if (filename_is_absolute (uncompressed_name))
1504      {      {
1505        /* file is an absolute file name.  Canonicalize it. */        /* file is an absolute file name.  Canonicalize it. */
1506        curtagfname = absolute_filename (curfile, NULL);        fdhead->taggedfname = absolute_filename (uncompressed_name, NULL);
1507      }      }
1508    else    else
1509      {      {
1510        /* file is a file name relative to cwd.  Make it relative        /* file is a file name relative to cwd.  Make it relative
1511           to the directory of the tags file. */           to the directory of the tags file. */
1512        curtagfname = relative_filename (curfile, tagfiledir);        fdhead->taggedfname = relative_filename (uncompressed_name, tagfiledir);
1513      }      }
1514    nocharno = FALSE;             /* use char position when making tags */    fdhead->usecharno = TRUE;     /* use char position when making tags */
1515    find_entries (curfile, inf);    fdhead->prop = NULL;
1516    
1517      curfdp = fdhead;              /* the current file description */
1518    
1519      find_entries (inf);
1520    
   free (curfiledir);  
1521    if (real_name == compressed_name)    if (real_name == compressed_name)
1522      retval = pclose (inf);      retval = pclose (inf);
1523    else    else
# Line 1508  process_file (file) Line 1525  process_file (file)
1525    if (retval < 0)    if (retval < 0)
1526      pfatal (file);      pfatal (file);
1527    
1528   exit:   cleanup:
1529    if (compressed_name) free(compressed_name);    /* XXX if no more useful, delete head of file description list */
1530    if (uncompressed_name) free(uncompressed_name);    if (compressed_name) free (compressed_name);
1531      if (uncompressed_name) free (uncompressed_name);
1532    return;    return;
1533  }  }
1534    
# Line 1548  init () Line 1566  init ()
1566  static node *last_node = NULL;  static node *last_node = NULL;
1567    
1568  static void  static void
1569  find_entries (file, inf)  find_entries (inf)
      char *file;  
1570       FILE *inf;       FILE *inf;
1571  {  {
1572    char *cp;    char *cp;
   language *lang;  
1573    node *old_last_node;    node *old_last_node;
1574      language *lang = curfdp->lang;
1575      Lang_function *parser = NULL;
1576    
1577    /* If user specified a language, use it. */    /* If user specified a language, use it. */
   lang = forced_lang;  
1578    if (lang != NULL && lang->function != NULL)    if (lang != NULL && lang->function != NULL)
1579      {      {
1580        curlang = lang;        parser = lang->function;
       lang->function (inf);  
       return;  
1581      }      }
1582    
1583    /* Try to guess the language given the file name. */    /* Else try to guess the language given the file name. */
1584    lang = get_language_from_filename (file);    if (parser == NULL)
   if (lang != NULL && lang->function != NULL)  
1585      {      {
1586        curlang = lang;        lang = get_language_from_filename (curfdp->infname);
1587        lang->function (inf);        if (lang != NULL && lang->function != NULL)
1588        return;          {
1589              curfdp->lang = lang;
1590              parser = lang->function;
1591            }
1592      }      }
1593    
1594    /* Look for sharp-bang as the first two characters. */    /* Else look for sharp-bang as the first two characters. */
1595    if (readline_internal (&lb, inf) > 0    if (parser == NULL
1596          && readline_internal (&lb, inf) > 0
1597        && lb.len >= 2        && lb.len >= 2
1598        && lb.buffer[0] == '#'        && lb.buffer[0] == '#'
1599        && lb.buffer[1] == '!')        && lb.buffer[1] == '!')
# Line 1598  find_entries (file, inf) Line 1616  find_entries (file, inf)
1616            lang = get_language_from_interpreter (lp);            lang = get_language_from_interpreter (lp);
1617            if (lang != NULL && lang->function != NULL)            if (lang != NULL && lang->function != NULL)
1618              {              {
1619                curlang = lang;                curfdp->lang = lang;
1620                lang->function (inf);                parser = lang->function;
               return;  
1621              }              }
1622          }          }
1623      }      }
1624    
1625      if (!no_line_directive
1626          && curfdp->lang != NULL && curfdp->lang->metasource)
1627        /* It may be that this is an xxx.y file, and we already parsed an xxx.c
1628           file, or anyway we parsed a file that is automatically generated from
1629           this one.  If this is the case, the xxx.c file contained #line
1630           directives that generated tags pointing to this file.  Let's delete
1631           them all before parsing this file, which is the real source. */
1632        {
1633          fdesc **fdpp = &fdhead;
1634          while (*fdpp != NULL)
1635            if (*fdpp != curfdp
1636                && streq ((*fdpp)->taggedfname, curfdp->taggedfname))
1637              /* We found one of those!  We must delete both the file description
1638                 and all tags referring to it. */
1639              {
1640                fdesc *badfdp = *fdpp;
1641    
1642                *fdpp = badfdp->next; /* remove the bad description from the list */
1643                fdpp = &badfdp->next; /* advance the list pointer */
1644    
1645                fprintf (stderr, "Removing references to \"%s\" obtained from \"%s\"\n",
1646                         badfdp->taggedfname, badfdp->infname);
1647                /* Delete the tags referring to badfdp. */
1648                invalidate_nodes (badfdp, nodehead);
1649    
1650                /* Delete badfdp. */
1651                if (badfdp->infname != NULL) free (badfdp->infname);
1652                if (badfdp->infabsname != NULL) free (badfdp->infabsname);
1653                if (badfdp->infabsdir != NULL) free (badfdp->infabsdir);
1654                if (badfdp->taggedfname != NULL) free (badfdp->taggedfname);
1655                if (badfdp->prop != NULL) free (badfdp->prop);
1656                free (badfdp);
1657              }
1658            else
1659              fdpp = &(*fdpp)->next; /* advance the list pointer */
1660        }
1661    
1662      if (parser != NULL)
1663        {
1664          parser (inf);
1665          return;
1666        }
1667    
1668    /* 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
1669       length of the first line is longer than the pipe block size,       length of the first line is longer than the pipe block size,
1670       which is unlikely. */       which is unlikely. */
1671    rewind (inf);    rewind (inf);
1672    
1673    /* Try Fortran. */    /* Else try Fortran. */
1674    old_last_node = last_node;    old_last_node = last_node;
1675    curlang = get_language_from_langname ("fortran");    curfdp->lang = get_language_from_langname ("fortran");
1676    Fortran_functions (inf);    Fortran_functions (inf);
1677    
   /* No Fortran entries found.  Try C. */  
1678    if (old_last_node == last_node)    if (old_last_node == last_node)
1679        /* No Fortran entries found.  Try C. */
1680      {      {
1681        /* We do not tag if rewind fails.        /* We do not tag if rewind fails.
1682           Only the file name will be recorded in the tags file. */           Only the file name will be recorded in the tags file. */
1683        rewind (inf);        rewind (inf);
1684        curlang = get_language_from_langname (cplusplus ? "c++" : "c");        curfdp->lang = get_language_from_langname (cplusplus ? "c++" : "c");
1685        default_C_entries (inf);        default_C_entries (inf);
1686      }      }
1687    return;    return;
# Line 1647  pfnote (name, is_func, linestart, linele Line 1708  pfnote (name, is_func, linestart, linele
1708    /* If ctags mode, change name "main" to M<thisfilename>. */    /* If ctags mode, change name "main" to M<thisfilename>. */
1709    if (CTAGS && !cxref_style && streq (name, "main"))    if (CTAGS && !cxref_style && streq (name, "main"))
1710      {      {
1711        register char *fp = etags_strrchr (curtagfname, '/');        register char *fp = etags_strrchr (curfdp->taggedfname, '/');
1712        np->name = concat ("M", fp == NULL ? curtagfname : fp + 1, "");        np->name = concat ("M", fp == NULL ? curfdp->taggedfname : fp + 1, "");
1713        fp = etags_strrchr (np->name, '.');        fp = etags_strrchr (np->name, '.');
1714        if (fp != NULL && fp[1] != '\0' && fp[2] == '\0')        if (fp != NULL && fp[1] != '\0' && fp[2] == '\0')
1715          fp[0] = '\0';          fp[0] = '\0';
1716      }      }
1717    else    else
1718      np->name = name;      np->name = name;
1719      np->valid = TRUE;
1720    np->been_warned = FALSE;    np->been_warned = FALSE;
1721    np->file = curtagfname;    np->fdp = curfdp;
1722    np->is_func = is_func;    np->is_func = is_func;
1723    np->lno = lno;    np->lno = lno;
1724    if (nocharno)    if (np->fdp->usecharno)
     np->cno = invalidcharno;  
   else  
1725      /* Our char numbers are 0-base, because of C language tradition?      /* Our char numbers are 0-base, because of C language tradition?
1726         ctags compatibility?  old versions compatibility?   I don't know.         ctags compatibility?  old versions compatibility?   I don't know.
1727         Anyway, since emacs's are 1-base we expect etags.el to take care         Anyway, since emacs's are 1-base we expect etags.el to take care
1728         of the difference.  If we wanted to have 1-based numbers, we would         of the difference.  If we wanted to have 1-based numbers, we would
1729         uncomment the +1 below. */         uncomment the +1 below. */
1730      np->cno = cno /* + 1 */ ;      np->cno = cno /* + 1 */ ;
1731      else
1732        np->cno = invalidcharno;
1733    np->left = np->right = NULL;    np->left = np->right = NULL;
1734    if (CTAGS && !cxref_style)    if (CTAGS && !cxref_style)
1735      {      {
# Line 1679  pfnote (name, is_func, linestart, linele Line 1741  pfnote (name, is_func, linestart, linele
1741    else    else
1742      np->pat = savenstr (linestart, linelen);      np->pat = savenstr (linestart, linelen);
1743    
1744    add_node (np, &head);    add_node (np, &nodehead);
1745  }  }
1746    
1747  /*  /*
# Line 1789  add_node (np, cur_node_p) Line 1851  add_node (np, cur_node_p)
1851           pointer.  The first tags of different files are a linked list           pointer.  The first tags of different files are a linked list
1852           on the left pointer.  last_node points to the end of the last           on the left pointer.  last_node points to the end of the last
1853           used sublist. */           used sublist. */
1854        if (last_node->file == np->file)        if (last_node->fdp == np->fdp)
1855          {          {
1856            /* Let's use the same sublist as the last added node. */            /* Let's use the same sublist as the last added node. */
1857            last_node->right = np;            last_node->right = np;
1858            last_node = np;            last_node = np;
1859          }          }
1860        else if (streq (cur_node->file, np->file))        else if (cur_node->fdp == np->fdp)
1861          {          {
1862            /* Scanning the list we found the head of a sublist which is            /* Scanning the list we found the head of a sublist which is
1863               good for us.  Let's scan this sublist. */               good for us.  Let's scan this sublist. */
# Line 1817  add_node (np, cur_node_p) Line 1879  add_node (np, cur_node_p)
1879         */         */
1880        if (!dif)        if (!dif)
1881          {          {
1882            if (streq (np->file, cur_node->file))            if (np->fdp == cur_node->fdp)
1883              {              {
1884                if (!no_warnings)                if (!no_warnings)
1885                  {                  {
1886                    fprintf (stderr, "Duplicate entry in file %s, line %d: %s\n",                    fprintf (stderr, "Duplicate entry in file %s, line %d: %s\n",
1887                             np->file, lineno, np->name);                             np->fdp->infname, lineno, np->name);
1888                    fprintf (stderr, "Second entry ignored\n");                    fprintf (stderr, "Second entry ignored\n");
1889                  }                  }
1890              }              }
# Line 1831  add_node (np, cur_node_p) Line 1893  add_node (np, cur_node_p)
1893                fprintf                fprintf
1894                  (stderr,                  (stderr,
1895                   "Duplicate entry in files %s and %s: %s (Warning only)\n",                   "Duplicate entry in files %s and %s: %s (Warning only)\n",
1896                   np->file, cur_node->file, np->name);                   np->fdp->infname, cur_node->fdp->infname, np->name);
1897                cur_node->been_warned = TRUE;                cur_node->been_warned = TRUE;
1898              }              }
1899            return;            return;
# Line 1842  add_node (np, cur_node_p) Line 1904  add_node (np, cur_node_p)
1904      }      }
1905  }  }
1906    
1907    /*
1908     * invalidate_nodes ()
1909     *      Scan the node tree and invalidate all nodes pointing to the
1910     *      given file description.
1911     */
1912    static void
1913    invalidate_nodes (badfdp, np)
1914         fdesc *badfdp;
1915         node *np;
1916    {
1917      if (np->left != NULL)
1918        invalidate_nodes (badfdp, np->left);
1919      if (np->fdp == badfdp)
1920        np-> valid = FALSE;
1921      if (np->right != NULL)
1922        invalidate_nodes (badfdp, np->right);
1923    }
1924    
1925    
1926  static int total_size_of_entries __P((node *));  static int total_size_of_entries __P((node *));
1927  static int number_len __P((long));  static int number_len __P((long));
1928    
1929  /* Length of a number's decimal representation. */  /* Length of a non-negative number's decimal representation. */
1930  static int  static int
1931  number_len (num)  number_len (num)
1932       long num;       long num;
# Line 1888  put_entries (np) Line 1968  put_entries (np)
1968       register node *np;       register node *np;
1969  {  {
1970    register char *sp;    register char *sp;
1971    static char *file = NULL;    static fdesc *fdp = NULL;
1972    
1973    if (np == NULL)    if (np == NULL)
1974      return;      return;
# Line 1898  put_entries (np) Line 1978  put_entries (np)
1978      put_entries (np->left);      put_entries (np->left);
1979    
1980    /* Output this entry */    /* Output this entry */
1981    if (!CTAGS)    if (np->valid)
1982      {      {
1983        /* Etags mode */        if (!CTAGS)
       if (file != np->file  
           && (file == NULL || !streq (file, np->file)))  
         {  
           file = np->file;  
           fprintf (tagf, "\f\n%s,%d\n",  
                    file, total_size_of_entries (np));  
         }  
       fputs (np->pat, tagf);  
       fputc ('\177', tagf);  
       if (np->name != NULL)  
1984          {          {
1985            fputs (np->name, tagf);            /* Etags mode */
1986            fputc ('\001', tagf);            if (fdp != np->fdp)
1987          }              {
1988        fprintf (tagf, "%d,", np->lno);                fdp = np->fdp;
1989        if (np->cno == invalidcharno)                fprintf (tagf, "\f\n%s,%d\n",
1990          fputc ('\n', tagf);                         fdp->taggedfname, total_size_of_entries (np));
1991        else              }
1992          fprintf (tagf, "%ld\n", np->cno);            fputs (np->pat, tagf);
1993      }            fputc ('\177', tagf);
1994    else            if (np->name != NULL)
1995      {              {
1996        /* Ctags mode */                fputs (np->name, tagf);
1997        if (np->name == NULL)                fputc ('\001', tagf);
1998          error ("internal error: NULL name in ctags mode.", (char *)NULL);              }
1999              fprintf (tagf, "%d,", np->lno);
2000        if (cxref_style)            if (np->cno != invalidcharno)
2001          {              fprintf (tagf, "%ld", np->cno);
2002            if (vgrind_style)            fputs ("\n", tagf);
             fprintf (stdout, "%s %s %d\n",  
                      np->name, np->file, (np->lno + 63) / 64);  
           else  
             fprintf (stdout, "%-16s %3d %-16s %s\n",  
                      np->name, np->lno, np->file, np->pat);  
2003          }          }
2004        else        else
2005          {          {
2006            fprintf (tagf, "%s\t%s\t", np->name, np->file);            /* Ctags mode */
2007              if (np->name == NULL)
2008                error ("internal error: NULL name in ctags mode.", (char *)NULL);
2009    
2010              if (cxref_style)
2011                {
2012                  if (vgrind_style)
2013                    fprintf (stdout, "%s %s %d\n",
2014                             np->name, np->fdp->taggedfname, (np->lno + 63) / 64);
2015                  else
2016                    fprintf (stdout, "%-16s %3d %-16s %s\n",
2017                             np->name, np->lno, np->fdp->taggedfname, np->pat);
2018                }
2019              else
2020                {
2021                  fprintf (tagf, "%s\t%s\t", np->name, np->fdp->taggedfname);
2022    
2023            if (np->is_func)                if (np->is_func)
2024              {                   /* a function */                  {               /* function or #define macro with args */
2025                putc (searchar, tagf);                    putc (searchar, tagf);
2026                putc ('^', tagf);                    putc ('^', tagf);
2027    
2028                for (sp = np->pat; *sp; sp++)                    for (sp = np->pat; *sp; sp++)
2029                  {                      {
2030                    if (*sp == '\\' || *sp == searchar)                        if (*sp == '\\' || *sp == searchar)
2031                      putc ('\\', tagf);                          putc ('\\', tagf);
2032                    putc (*sp, tagf);                        putc (*sp, tagf);
2033                        }
2034                      putc (searchar, tagf);
2035                  }                  }
2036                putc (searchar, tagf);                else
2037              }                  {               /* anything else; text pattern inadequate */
2038            else                    fprintf (tagf, "%d", np->lno);
2039              {                   /* a typedef; text pattern inadequate */                  }
2040                fprintf (tagf, "%d", np->lno);                putc ('\n', tagf);
2041              }              }
           putc ('\n', tagf);  
2042          }          }
2043      }      } /* if this node contains a valid tag */
   
2044    
2045    /* Output subentries that follow this one */    /* Output subentries that follow this one */
2046    put_entries (np->right);    put_entries (np->right);
# Line 5247  add_regex (regexp_pattern, ignore_case, Line 5327  add_regex (regexp_pattern, ignore_case,
5327    p_head->pat = patbuf;    p_head->pat = patbuf;
5328    p_head->name_pattern = savestr (name);    p_head->name_pattern = savestr (name);
5329    p_head->error_signaled = FALSE;    p_head->error_signaled = FALSE;
5330      p_head->ignore_case = ignore_case;
5331  }  }
5332    
5333  /*  /*
# Line 5444  readline (lbp, stream) Line 5525  readline (lbp, stream)
5525    long result = readline_internal (lbp, stream);    long result = readline_internal (lbp, stream);
5526    
5527    /* Honour #line directives. */    /* Honour #line directives. */
5528    if (!no_line_directive    if (!no_line_directive)
       && result > 12 && strneq (lbp->buffer, "#line ", 6))  
5529      {      {
5530        int start, lno;        static bool discard_until_line_directive;
5531    
5532        if (sscanf (lbp->buffer, "#line %d \"%n", &lno, &start) == 1)        /* Check whether this is a #line directive. */
5533          if (result > 12 && strneq (lbp->buffer, "#line ", 6))
5534          {          {
5535            char *endp = lbp->buffer + start;            int start, lno;
5536    
5537            while ((endp = etags_strchr (endp, '"')) != NULL            if (DEBUG) start = 0; /* shut up the compiler */
5538                   && endp[-1] == '\\')            if (sscanf (lbp->buffer, "#line %d \"%n", &lno, &start) == 1)
             endp++;  
           if (endp != NULL)  
5539              {              {
5540                char *absname, *name = lbp->buffer + start;                char *endp = lbp->buffer + start;
               *endp = '\0';  
5541    
5542                canonicalize_filename(name); /* for DOS */                assert (start > 0);
5543                absname = absolute_filename (name, curfiledir);                while ((endp = etags_strchr (endp, '"')) != NULL
5544                if (filename_is_absolute (name)                       && endp[-1] == '\\')
5545                    || filename_is_absolute (curfile))                  endp++;
5546                  name = absname;                if (endp != NULL)
5547                else                  /* Ok, this is a real #line directive.  Let's deal with it. */
5548                  {                  {
5549                    name = relative_filename (absname, tagfiledir);                    char *taggedabsname;  /* absolute name of original file */
5550                    free (absname);                    char *taggedfname;    /* name of original file as given */
5551                  }                    char *name;           /* temp var */
5552    
5553                      discard_until_line_directive = FALSE; /* found it */
5554                      name = lbp->buffer + start;
5555                      *endp = '\0';
5556                      canonicalize_filename (name); /* for DOS */
5557                      taggedabsname = absolute_filename (name, curfdp->infabsdir);
5558                      if (filename_is_absolute (name)
5559                          || filename_is_absolute (curfdp->infname))
5560                        taggedfname = savestr (taggedabsname);
5561                      else
5562                        taggedfname = relative_filename (taggedabsname,tagfiledir);
5563    
5564                if (streq (curtagfname, name))                    if (streq (curfdp->taggedfname, taggedfname))
5565                  free (name);                      /* The #line directive is only a line number change.  We
5566                else                         deal with this afterwards. */
5567                  curtagfname = name;                      free (taggedfname);
5568                lineno = lno;                    else
5569                nocharno = TRUE;  /* do not use char position for tags */                      /* The tags following this #line directive should be
5570                return readline (lbp, stream);                         attributed to taggedfname.  In order to do this, set
5571              }                         curfdp accordingly. */
5572                        {
5573                          fdesc *fdp; /* file description pointer */
5574    
5575                          /* Go look for a file description already set up for the
5576                             file indicated in the #line directive.  If there is
5577                             one, use it from now until the next #line
5578                             directive. */
5579                          for (fdp = fdhead; fdp != NULL; fdp = fdp->next)
5580                            if (streq (fdp->infname, curfdp->infname)
5581                                && streq (fdp->taggedfname, taggedfname))
5582                              /* If we remove the second test above (after the &&)
5583                                 then all entries pertaining to the same file are
5584                                 coalesced in the tags file.  If we use it, then
5585                                 entries pertaining to the same file but generated
5586                                 from different files (via #line directives) will
5587                                 go into separate sections in the tags file.  These
5588                                 alternatives look equivalent.  The first one
5589                                 destroys some apparently useless information. */
5590                              {
5591                                curfdp = fdp;
5592                                free (taggedfname);
5593                                break;
5594                              }
5595                          /* Else, if we already tagged the real file, skip all
5596                             input lines until the next #line directive. */
5597                          if (fdp == NULL) /* not found */
5598                            for (fdp = fdhead; fdp != NULL; fdp = fdp->next)
5599                              if (streq (fdp->infabsname, taggedabsname))
5600                                {
5601                                  discard_until_line_directive = TRUE;
5602                                  free (taggedfname);
5603                                  break;
5604                                }
5605                          /* Else create a new file description and use that from
5606                             now on, until the next #line directive. */
5607                          if (fdp == NULL) /* not found */
5608                            {
5609                              fdp = fdhead;
5610                              fdhead = xnew (1, fdesc);
5611                              *fdhead = *curfdp; /* copy curr. file description */
5612                              fdhead->next = fdp;
5613                              fdhead->infname = savestr (curfdp->infname);
5614                              fdhead->infabsname = savestr (curfdp->infabsname);
5615                              fdhead->infabsdir = savestr (curfdp->infabsdir);
5616                              fdhead->taggedfname = taggedfname;
5617                              fdhead->usecharno = FALSE;
5618                              curfdp = fdhead;
5619                            }
5620                        }
5621                      free (taggedabsname);
5622                      lineno = lno;
5623                      return readline (lbp, stream);
5624                    } /* if a real #line directive */
5625                } /* if #line is followed by a a number */
5626            } /* if line begins with "#line " */
5627    
5628          /* If we are here, no #line directive was found. */
5629          if (discard_until_line_directive)
5630            {
5631              if (result > 0)
5632                /* Do a tail recursion on ourselves, thus discarding the contents
5633                   of the line buffer. */
5634                return readline (lbp, stream);
5635              /* End of file. */
5636              discard_until_line_directive = FALSE;
5637              return 0;
5638          }          }
5639      }      } /* if #line directives should be considered */
5640    
5641  #ifdef ETAGS_REGEXPS  #ifdef ETAGS_REGEXPS
5642    {    {
# Line 5493  readline (lbp, stream) Line 5648  readline (lbp, stream)
5648        for (pp = p_head; pp != NULL; pp = pp->p_next)        for (pp = p_head; pp != NULL; pp = pp->p_next)
5649          {          {
5650            /* Only use generic regexps or those for the current language. */            /* Only use generic regexps or those for the current language. */
5651            if (pp->lang != NULL && pp->lang != curlang)            if (pp->lang != NULL && pp->lang != fdhead->lang)
5652              continue;              continue;
5653    
5654            match = re_match (pp->pat, lbp->buffer, lbp->len, 0, &pp->regs);            match = re_match (pp->pat, lbp->buffer, lbp->len, 0, &pp->regs);
# Line 5931  xrealloc (ptr, size) Line 6086  xrealloc (ptr, size)
6086   * c-indentation-style: gnu   * c-indentation-style: gnu
6087   * indent-tabs-mode: t   * indent-tabs-mode: t
6088   * tab-width: 8   * tab-width: 8
6089   * c-font-lock-extra-types: ("FILE" "bool" "language" "linebuffer")   * fill-column: 79
6090     * c-font-lock-extra-types: ("FILE" "bool" "language" "linebuffer" "fdesc")
6091   * End:   * End:
6092   */   */

Legend:
Removed from v.3.11  
changed lines
  Added in v.3.12

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