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