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. |
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 |
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 |
/* |
/* |
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 */ |
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 *)); |
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 |
|
|
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++ */ |
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 */ |
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"}, |
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 }; |
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 |
|
|
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); |
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\ |
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\ |
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\ |
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' |
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; |
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; |
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) |
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 |
} |
} |
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: |
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 |
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++); |
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 |
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; |
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 |
{ |
{ |
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 |
{ |
{ |
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 |
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 |
|
|
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] == '!') |
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; |
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 |
{ |
{ |
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 |
/* |
/* |
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. */ |
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 |
} |
} |
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; |
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; |
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; |
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); |
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 |
/* |
/* |
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 |
{ |
{ |
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); |
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 |
*/ |
*/ |