forked from emacs-mirror/emacs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathetags.c
7348 lines (6700 loc) · 188 KB
/
etags.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/* Tags file maker to go with GNU Emacs -*- coding: utf-8 -*-
Copyright (C) 1984 The Regents of the University of California
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the
distribution.
3. Neither the name of the University nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS''
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Copyright (C) 1984, 1987-1989, 1993-1995, 1998-2020 Free Software
Foundation, Inc.
This file is not considered part of GNU Emacs.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at
your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
/* NB To comply with the above BSD license, copyright information is
reproduced in etc/ETAGS.README. That file should be updated when the
above notices are.
To the best of our knowledge, this code was originally based on the
ctags.c distributed with BSD4.2, which was copyrighted by the
University of California, as described above. */
/*
* Authors:
* 1983 Ctags originally by Ken Arnold.
* 1984 Fortran added by Jim Kleckner.
* 1984 Ed Pelegri-Llopart added C typedefs.
* 1985 Emacs TAGS format by Richard Stallman.
* 1989 Sam Kendall added C++.
* 1992 Joseph B. Wells improved C and C++ parsing.
* 1993 Francesco Potortì reorganized C and C++.
* 1994 Line-by-line regexp tags by Tom Tromey.
* 2001 Nested classes by Francesco Potortì (concept by Mykola Dzyuba).
* 2002 #line directives by Francesco Potortì.
* Francesco Potortì maintained and improved it for many years
starting in 1993.
*/
/*
* If you want to add support for a new language, start by looking at the LUA
* language, which is the simplest. Alternatively, consider distributing etags
* together with a configuration file containing regexp definitions for etags.
*/
#ifdef DEBUG
# undef DEBUG
# define DEBUG true
#else
# define DEBUG false
#endif
#include <config.h>
/* WIN32_NATIVE is for XEmacs.
MSDOS, WINDOWSNT, DOS_NT are for Emacs. */
#ifdef WIN32_NATIVE
# undef MSDOS
# undef WINDOWSNT
# define WINDOWSNT
#endif /* WIN32_NATIVE */
#ifdef MSDOS
# undef MSDOS
# define MSDOS true
# include <sys/param.h>
#else
# define MSDOS false
#endif /* MSDOS */
#ifdef WINDOWSNT
# include <direct.h>
# undef HAVE_NTGUI
# undef DOS_NT
# define DOS_NT
/* The WINDOWSNT build doesn't use Gnulib's fcntl.h. */
# define O_CLOEXEC O_NOINHERIT
#endif /* WINDOWSNT */
#include <inttypes.h>
#include <limits.h>
#include <unistd.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <sysstdio.h>
#include <errno.h>
#include <fcntl.h>
#include <binary-io.h>
#include <intprops.h>
#include <unlocked-io.h>
#include <verify.h>
#include <c-ctype.h>
#include <c-strcase.h>
#include <assert.h>
#include <getopt.h>
#include <regex.h>
/* Define CTAGS to make the program "ctags" compatible with the usual one.
Leave it undefined to make the program "etags", which makes emacs-style
tag tables and tags typedefs, #defines and struct/union/enum by default. */
#ifdef CTAGS
# undef CTAGS
# define CTAGS true
#else
# define CTAGS false
#endif
/* Copy to DEST from SRC (containing LEN bytes), and append a NUL byte. */
static void
memcpyz (void *dest, void const *src, ptrdiff_t len)
{
char *e = mempcpy (dest, src, len);
*e = '\0';
}
static bool
streq (char const *s, char const *t)
{
return strcmp (s, t) == 0;
}
static bool
strcaseeq (char const *s, char const *t)
{
return c_strcasecmp (s, t) == 0;
}
static bool
strneq (char const *s, char const *t, size_t n)
{
return strncmp (s, t, n) == 0;
}
static bool
strncaseeq (char const *s, char const *t, size_t n)
{
return c_strncasecmp (s, t, n) == 0;
}
/* C is not in a name. */
static bool
notinname (unsigned char c)
{
/* Look at make_tag before modifying! */
static bool const table[UCHAR_MAX + 1] = {
['\0']=1, ['\t']=1, ['\n']=1, ['\f']=1, ['\r']=1, [' ']=1,
['(']=1, [')']=1, [',']=1, [';']=1, ['=']=1
};
return table[c];
}
/* C can start a token. */
static bool
begtoken (unsigned char c)
{
static bool const table[UCHAR_MAX + 1] = {
['$']=1, ['@']=1,
['A']=1, ['B']=1, ['C']=1, ['D']=1, ['E']=1, ['F']=1, ['G']=1, ['H']=1,
['I']=1, ['J']=1, ['K']=1, ['L']=1, ['M']=1, ['N']=1, ['O']=1, ['P']=1,
['Q']=1, ['R']=1, ['S']=1, ['T']=1, ['U']=1, ['V']=1, ['W']=1, ['X']=1,
['Y']=1, ['Z']=1,
['_']=1,
['a']=1, ['b']=1, ['c']=1, ['d']=1, ['e']=1, ['f']=1, ['g']=1, ['h']=1,
['i']=1, ['j']=1, ['k']=1, ['l']=1, ['m']=1, ['n']=1, ['o']=1, ['p']=1,
['q']=1, ['r']=1, ['s']=1, ['t']=1, ['u']=1, ['v']=1, ['w']=1, ['x']=1,
['y']=1, ['z']=1,
['~']=1
};
return table[c];
}
/* C can be in the middle of a token. */
static bool
intoken (unsigned char c)
{
static bool const table[UCHAR_MAX + 1] = {
['$']=1,
['0']=1, ['1']=1, ['2']=1, ['3']=1, ['4']=1,
['5']=1, ['6']=1, ['7']=1, ['8']=1, ['9']=1,
['A']=1, ['B']=1, ['C']=1, ['D']=1, ['E']=1, ['F']=1, ['G']=1, ['H']=1,
['I']=1, ['J']=1, ['K']=1, ['L']=1, ['M']=1, ['N']=1, ['O']=1, ['P']=1,
['Q']=1, ['R']=1, ['S']=1, ['T']=1, ['U']=1, ['V']=1, ['W']=1, ['X']=1,
['Y']=1, ['Z']=1,
['_']=1,
['a']=1, ['b']=1, ['c']=1, ['d']=1, ['e']=1, ['f']=1, ['g']=1, ['h']=1,
['i']=1, ['j']=1, ['k']=1, ['l']=1, ['m']=1, ['n']=1, ['o']=1, ['p']=1,
['q']=1, ['r']=1, ['s']=1, ['t']=1, ['u']=1, ['v']=1, ['w']=1, ['x']=1,
['y']=1, ['z']=1
};
return table[c];
}
/* C can end a token. */
static bool
endtoken (unsigned char c)
{
static bool const table[UCHAR_MAX + 1] = {
['\0']=1, ['\t']=1, ['\n']=1, ['\r']=1, [' ']=1,
['!']=1, ['"']=1, ['#']=1, ['%']=1, ['&']=1, ['\'']=1, ['(']=1, [')']=1,
['*']=1, ['+']=1, [',']=1, ['-']=1, ['.']=1, ['/']=1, [':']=1, [';']=1,
['<']=1, ['=']=1, ['>']=1, ['?']=1, ['[']=1, [']']=1, ['^']=1,
['{']=1, ['|']=1, ['}']=1, ['~']=1
};
return table[c];
}
/*
* xnew, xrnew -- allocate, reallocate storage
*
* SYNOPSIS: Type *xnew (ptrdiff_t n, Type);
* void xrnew (OldPointer, ptrdiff_t n, int multiplier);
*/
#define xnew(n, Type) ((Type *) xnmalloc (n, sizeof (Type)))
#define xrnew(op, n, m) ((op) = xnrealloc (op, n, (m) * sizeof *(op)))
typedef void Lang_function (FILE *);
typedef struct
{
const char *suffix; /* file name suffix for this compressor */
const char *command; /* takes one arg and decompresses to stdout */
} compressor;
typedef struct
{
const char *name; /* language name */
const char *help; /* detailed help for the language */
Lang_function *function; /* parse function */
const char **suffixes; /* name suffixes of this language's files */
const char **filenames; /* names of this language's files */
const char **interpreters; /* interpreters for this language */
bool metasource; /* source used to generate other sources */
} language;
typedef struct fdesc
{
struct fdesc *next; /* for the linked list */
char *infname; /* uncompressed input file name */
char *infabsname; /* absolute uncompressed input file name */
char *infabsdir; /* absolute dir of input file */
char *taggedfname; /* file name to write in tagfile */
language *lang; /* language of file */
char *prop; /* file properties to write in tagfile */
bool usecharno; /* etags tags shall contain char number */
bool written; /* entry written in the tags file */
} fdesc;
typedef struct node_st
{ /* sorting structure */
struct node_st *left, *right; /* left and right sons */
fdesc *fdp; /* description of file to whom tag belongs */
char *name; /* tag name */
char *regex; /* search regexp */
bool valid; /* write this tag on the tag file */
bool is_func; /* function tag: use regexp in CTAGS mode */
bool been_warned; /* warning already given for duplicated tag */
intmax_t lno; /* line number tag is on */
intmax_t cno; /* character number line starts on */
} node;
/*
* A `linebuffer' is a structure which holds a line of text.
* `readline_internal' reads a line from a stream into a linebuffer
* and works regardless of the length of the line.
* SIZE is the size of BUFFER, LEN is the length of the string in
* BUFFER after readline reads it.
*/
typedef struct
{
ptrdiff_t size;
ptrdiff_t len;
char *buffer;
} linebuffer;
/* Used to support mixing of --lang and file names. */
typedef struct
{
enum {
at_language, /* a language specification */
at_regexp, /* a regular expression */
at_filename, /* a file name */
at_stdin, /* read from stdin here */
at_end /* stop parsing the list */
} arg_type; /* argument type */
language *lang; /* language associated with the argument */
char *what; /* the argument itself */
} argument;
/* Structure defining a regular expression. */
typedef struct regexp
{
struct regexp *p_next; /* pointer to next in list */
language *lang; /* if set, use only for this language */
char *pattern; /* the regexp pattern */
char *name; /* tag name */
struct re_pattern_buffer *pat; /* the compiled pattern */
struct re_registers regs; /* re registers */
bool error_signaled; /* already signaled for this regexp */
bool force_explicit_name; /* do not allow implicit tag name */
bool ignore_case; /* ignore case when matching */
bool multi_line; /* do a multi-line match on the whole file */
} regexp;
/* Many compilers barf on this:
Lang_function Ada_funcs;
so let's write it this way */
static void Ada_funcs (FILE *);
static void Asm_labels (FILE *);
static void C_entries (int c_ext, FILE *);
static void default_C_entries (FILE *);
static void plain_C_entries (FILE *);
static void Cjava_entries (FILE *);
static void Cobol_paragraphs (FILE *);
static void Cplusplus_entries (FILE *);
static void Cstar_entries (FILE *);
static void Erlang_functions (FILE *);
static void Forth_words (FILE *);
static void Fortran_functions (FILE *);
static void Go_functions (FILE *);
static void HTML_labels (FILE *);
static void Lisp_functions (FILE *);
static void Lua_functions (FILE *);
static void Makefile_targets (FILE *);
static void Pascal_functions (FILE *);
static void Perl_functions (FILE *);
static void PHP_functions (FILE *);
static void PS_functions (FILE *);
static void Prolog_functions (FILE *);
static void Python_functions (FILE *);
static void Ruby_functions (FILE *);
static void Scheme_functions (FILE *);
static void TeX_commands (FILE *);
static void Texinfo_nodes (FILE *);
static void Yacc_entries (FILE *);
static void just_read_file (FILE *);
static language *get_language_from_langname (const char *);
static void readline (linebuffer *, FILE *);
static ptrdiff_t readline_internal (linebuffer *, FILE *, char const *);
static bool nocase_tail (const char *);
static void get_tag (char *, char **);
static void get_lispy_tag (char *);
static void analyze_regex (char *);
static void free_regexps (void);
static void regex_tag_multiline (void);
static void error (const char *, ...) ATTRIBUTE_FORMAT_PRINTF (1, 2);
static void verror (char const *, va_list) ATTRIBUTE_FORMAT_PRINTF (1, 0);
static _Noreturn void suggest_asking_for_help (void);
static _Noreturn void fatal (char const *, ...) ATTRIBUTE_FORMAT_PRINTF (1, 2);
static _Noreturn void pfatal (const char *);
static void add_node (node *, node **);
static void process_file_name (char *, language *);
static void process_file (FILE *, char *, language *);
static void find_entries (FILE *);
static void free_tree (node *);
static void free_fdesc (fdesc *);
static void pfnote (char *, bool, char *, ptrdiff_t, intmax_t, intmax_t);
static void invalidate_nodes (fdesc *, node **);
static void put_entries (node *);
static char *concat (const char *, const char *, const char *);
static char *skip_spaces (char *);
static char *skip_non_spaces (char *);
static char *skip_name (char *);
static char *savenstr (const char *, ptrdiff_t);
static char *savestr (const char *);
static char *etags_getcwd (void);
static char *relative_filename (char *, char *);
static char *absolute_filename (char *, char *);
static char *absolute_dirname (char *, char *);
static bool filename_is_absolute (char *f);
static void canonicalize_filename (char *);
static char *etags_mktmp (void);
static void linebuffer_init (linebuffer *);
static void linebuffer_setlen (linebuffer *, ptrdiff_t);
static void *xmalloc (ptrdiff_t) ATTRIBUTE_MALLOC_SIZE ((1));
static void *xnmalloc (ptrdiff_t, ptrdiff_t) ATTRIBUTE_MALLOC_SIZE ((1,2));
static void *xnrealloc (void *, ptrdiff_t, ptrdiff_t)
ATTRIBUTE_ALLOC_SIZE ((2,3));
static char searchar = '/'; /* use /.../ searches */
static char *tagfile; /* output file */
static char *progname; /* name this program was invoked with */
static char *cwd; /* current working directory */
static char *tagfiledir; /* directory of tagfile */
static FILE *tagf; /* ioptr for tags file */
static ptrdiff_t whatlen_max; /* maximum length of any 'what' member */
static fdesc *fdhead; /* head of file description list */
static fdesc *curfdp; /* current file description */
static char *infilename; /* current input file name */
static intmax_t lineno; /* line number of current line */
static intmax_t charno; /* current character number */
static intmax_t linecharno; /* charno of start of current line */
static char *dbp; /* pointer to start of current tag */
static intmax_t const invalidcharno = -1;
static node *nodehead; /* the head of the binary tree of tags */
static node *last_node; /* the last node created */
static linebuffer lb; /* the current line */
static linebuffer filebuf; /* a buffer containing the whole file */
static linebuffer token_name; /* a buffer containing a tag name */
static bool append_to_tagfile; /* -a: append to tags */
/* The next five default to true in C and derived languages. */
static bool typedefs; /* -t: create tags for C and Ada typedefs */
static bool typedefs_or_cplusplus; /* -T: create tags for C typedefs, level */
/* 0 struct/enum/union decls, and C++ */
/* member functions. */
static bool constantypedefs; /* -d: create tags for C #define, enum */
/* constants and variables. */
/* -D: opposite of -d. Default under ctags. */
static int globals; /* create tags for global variables */
static int members; /* create tags for C member variables */
static int declarations; /* --declarations: tag them and extern in C&Co*/
static int no_line_directive; /* ignore #line directives (undocumented) */
static int no_duplicates; /* no duplicate tags for ctags (undocumented) */
static bool update; /* -u: update tags */
static bool vgrind_style; /* -v: create vgrind style index output */
static bool no_warnings; /* -w: suppress warnings (undocumented) */
static bool cxref_style; /* -x: create cxref style output */
static bool cplusplus; /* .[hc] means C++, not C (undocumented) */
static bool ignoreindent; /* -I: ignore indentation in C */
static int packages_only; /* --packages-only: in Ada, only tag packages*/
static int class_qualify; /* -Q: produce class-qualified tags in C++/Java */
static int debug; /* --debug */
/* STDIN is defined in LynxOS system headers */
#ifdef STDIN
# undef STDIN
#endif
#define STDIN 0x1001 /* returned by getopt_long on --parse-stdin */
static bool parsing_stdin; /* --parse-stdin used */
static regexp *p_head; /* list of all regexps */
static bool need_filebuf; /* some regexes are multi-line */
static struct option longopts[] =
{
{ "append", no_argument, NULL, 'a' },
{ "packages-only", no_argument, &packages_only, 1 },
{ "c++", no_argument, NULL, 'C' },
{ "debug", no_argument, &debug, 1 },
{ "declarations", no_argument, &declarations, 1 },
{ "no-line-directive", no_argument, &no_line_directive, 1 },
{ "no-duplicates", no_argument, &no_duplicates, 1 },
{ "help", no_argument, NULL, 'h' },
{ "help", no_argument, NULL, 'H' },
{ "ignore-indentation", no_argument, NULL, 'I' },
{ "language", required_argument, NULL, 'l' },
{ "members", no_argument, &members, 1 },
{ "no-members", no_argument, &members, 0 },
{ "output", required_argument, NULL, 'o' },
{ "class-qualify", no_argument, &class_qualify, 'Q' },
{ "regex", required_argument, NULL, 'r' },
{ "no-regex", no_argument, NULL, 'R' },
{ "ignore-case-regex", required_argument, NULL, 'c' },
{ "parse-stdin", required_argument, NULL, STDIN },
{ "version", no_argument, NULL, 'V' },
#if CTAGS /* Ctags options */
{ "backward-search", no_argument, NULL, 'B' },
{ "cxref", no_argument, NULL, 'x' },
{ "defines", no_argument, NULL, 'd' },
{ "globals", no_argument, &globals, 1 },
{ "typedefs", no_argument, NULL, 't' },
{ "typedefs-and-c++", no_argument, NULL, 'T' },
{ "update", no_argument, NULL, 'u' },
{ "vgrind", no_argument, NULL, 'v' },
{ "no-warn", no_argument, NULL, 'w' },
#else /* Etags options */
{ "no-defines", no_argument, NULL, 'D' },
{ "no-globals", no_argument, &globals, 0 },
{ "include", required_argument, NULL, 'i' },
#endif
{ NULL }
};
static compressor compressors[] =
{
{ "z", "gzip -d -c"},
{ "Z", "gzip -d -c"},
{ "gz", "gzip -d -c"},
{ "GZ", "gzip -d -c"},
{ "bz2", "bzip2 -d -c" },
{ "xz", "xz -d -c" },
{ "zst", "zstd -d -c" },
{ NULL }
};
/*
* Language stuff.
*/
/* Ada code */
static const char *Ada_suffixes [] =
{ "ads", "adb", "ada", NULL };
static const char Ada_help [] =
"In Ada code, functions, procedures, packages, tasks and types are\n\
tags. Use the '--packages-only' option to create tags for\n\
packages only.\n\
Ada tag names have suffixes indicating the type of entity:\n\
Entity type: Qualifier:\n\
------------ ----------\n\
function /f\n\
procedure /p\n\
package spec /s\n\
package body /b\n\
type /t\n\
task /k\n\
Thus, 'M-x find-tag <RET> bidule/b <RET>' will go directly to the\n\
body of the package 'bidule', while 'M-x find-tag <RET> bidule <RET>'\n\
will just search for any tag 'bidule'.";
/* Assembly code */
static const char *Asm_suffixes [] =
{ "a", /* Unix assembler */
"asm", /* Microcontroller assembly */
"def", /* BSO/Tasking definition includes */
"inc", /* Microcontroller include files */
"ins", /* Microcontroller include files */
"s", "sa", /* Unix assembler */
"S", /* cpp-processed Unix assembler */
"src", /* BSO/Tasking C compiler output */
NULL
};
static const char Asm_help [] =
"In assembler code, labels appearing at the beginning of a line,\n\
followed by a colon, are tags.";
/* Note that .c and .h can be considered C++, if the --c++ flag was
given, or if the `class' or `template' keywords are met inside the file.
That is why default_C_entries is called for these. */
static const char *default_C_suffixes [] =
{ "c", "h", NULL };
#if CTAGS /* C help for Ctags */
static const char default_C_help [] =
"In C code, any C function is a tag. Use -t to tag typedefs.\n\
Use -T to tag definitions of 'struct', 'union' and 'enum'.\n\
Use -d to tag '#define' macro definitions and 'enum' constants.\n\
Use --globals to tag global variables.\n\
You can tag function declarations and external variables by\n\
using '--declarations', and struct members by using '--members'.";
#else /* C help for Etags */
static const char default_C_help [] =
"In C code, any C function or typedef is a tag, and so are\n\
definitions of 'struct', 'union' and 'enum'. '#define' macro\n\
definitions and 'enum' constants are tags unless you specify\n\
'--no-defines'. Global variables are tags unless you specify\n\
'--no-globals' and so are struct members unless you specify\n\
'--no-members'. Use of '--no-globals', '--no-defines' and\n\
'--no-members' can make the tags table file much smaller.\n\
You can tag function declarations and external variables by\n\
using '--declarations'.";
#endif /* C help for Ctags and Etags */
static const char *Cplusplus_suffixes [] =
{ "C", "c++", "cc", "cpp", "cxx", "H", "h++", "hh", "hpp", "hxx",
"M", /* Objective C++ */
"pdb", /* PostScript with C syntax */
NULL };
static const char Cplusplus_help [] =
"In C++ code, all the tag constructs of C code are tagged. (Use\n\
--help --lang=c --lang=c++ for full help.)\n\
In addition to C tags, member functions are also recognized. Member\n\
variables are recognized unless you use the '--no-members' option.\n\
Tags for variables and functions in classes are named 'CLASS::VARIABLE'\n\
and 'CLASS::FUNCTION'. 'operator' definitions have tag names like\n\
'operator+'.";
static const char *Cjava_suffixes [] =
{ "java", NULL };
static char Cjava_help [] =
"In Java code, all the tags constructs of C and C++ code are\n\
tagged. (Use --help --lang=c --lang=c++ --lang=java for full help.)";
static const char *Cobol_suffixes [] =
{ "COB", "cob", NULL };
static char Cobol_help [] =
"In Cobol code, tags are paragraph names; that is, any word\n\
starting in column 8 and followed by a period.";
static const char *Cstar_suffixes [] =
{ "cs", "hs", NULL };
static const char *Erlang_suffixes [] =
{ "erl", "hrl", NULL };
static const char Erlang_help [] =
"In Erlang code, the tags are the functions, records and macros\n\
defined in the file.";
static const char *Erlang_interpreters [] =
{ "escript", NULL };
static const char *Forth_suffixes [] =
{ "fth", "tok", NULL };
static const char Forth_help [] =
"In Forth code, tags are words defined by ':',\n\
constant, code, create, defer, value, variable, buffer:, field.";
static const char *Fortran_suffixes [] =
{ "F", "f", "f90", "for", NULL };
static const char Fortran_help [] =
"In Fortran code, functions, subroutines and block data are tags.";
static const char *Go_suffixes [] = {"go", NULL};
static const char Go_help [] =
"In Go code, functions, interfaces and packages are tags.";
static const char *HTML_suffixes [] =
{ "htm", "html", "shtml", NULL };
static const char HTML_help [] =
"In HTML input files, the tags are the 'title' and the 'h1', 'h2',\n\
'h3' headers. Also, tags are 'name=' in anchors and all\n\
occurrences of 'id='.";
static const char *Lisp_suffixes [] =
{ "cl", "clisp", "el", "l", "lisp", "LSP", "lsp", "ml", NULL };
static const char Lisp_help [] =
"In Lisp code, any function defined with 'defun', any variable\n\
defined with 'defvar' or 'defconst', and in general the first\n\
argument of any expression that starts with '(def' in column zero\n\
is a tag.\n\
The '--declarations' option tags \"(defvar foo)\" constructs too.";
static const char *Lua_suffixes [] =
{ "lua", "LUA", NULL };
static const char Lua_help [] =
"In Lua scripts, all functions are tags.";
static const char *Lua_interpreters [] =
{ "lua", NULL };
static const char *Makefile_filenames [] =
{ "Makefile", "makefile", "GNUMakefile", "Makefile.in", "Makefile.am", NULL};
static const char Makefile_help [] =
"In makefiles, targets are tags; additionally, variables are tags\n\
unless you specify '--no-globals'.";
static const char *Objc_suffixes [] =
{ "lm", /* Objective lex file */
"m", /* Objective C file */
NULL };
static const char Objc_help [] =
"In Objective C code, tags include Objective C definitions for classes,\n\
class categories, methods and protocols. Tags for variables and\n\
functions in classes are named 'CLASS::VARIABLE' and 'CLASS::FUNCTION'.\
\n(Use --help --lang=c --lang=objc --lang=java for full help.)";
static const char *Pascal_suffixes [] =
{ "p", "pas", NULL };
static const char Pascal_help [] =
"In Pascal code, the tags are the functions and procedures defined\n\
in the file.";
/* " // this is for working around an Emacs highlighting bug... */
static const char *Perl_suffixes [] =
{ "pl", "pm", NULL };
static const char *Perl_interpreters [] =
{ "perl", "@PERL@", NULL };
static const char Perl_help [] =
"In Perl code, the tags are the packages, subroutines and variables\n\
defined by the 'package', 'sub', 'my' and 'local' keywords. Use\n\
'--globals' if you want to tag global variables. Tags for\n\
subroutines are named 'PACKAGE::SUB'. The name for subroutines\n\
defined in the default package is 'main::SUB'.";
static const char *PHP_suffixes [] =
{ "php", "php3", "php4", NULL };
static const char PHP_help [] =
"In PHP code, tags are functions, classes and defines. Unless you use\n\
the '--no-members' option, vars are tags too.";
static const char *plain_C_suffixes [] =
{ "pc", /* Pro*C file */
NULL };
static const char *PS_suffixes [] =
{ "ps", "psw", NULL }; /* .psw is for PSWrap */
static const char PS_help [] =
"In PostScript code, the tags are the functions.";
static const char *Prolog_suffixes [] =
{ "prolog", NULL };
static const char Prolog_help [] =
"In Prolog code, tags are predicates and rules at the beginning of\n\
line.";
static const char *Prolog_interpreters [] =
{ "gprolog", "pl", "yap", "swipl", "prolog", NULL };
static const char *Python_suffixes [] =
{ "py", NULL };
static const char Python_help [] =
"In Python code, 'def' or 'class' at the beginning of a line\n\
generate a tag.";
static const char *Python_interpreters [] =
{ "python", NULL };
static const char *Ruby_suffixes [] =
{ "rb", "ru", "rbw", NULL };
static const char *Ruby_filenames [] =
{ "Rakefile", "Thorfile", NULL };
static const char Ruby_help [] =
"In Ruby code, 'def' or 'class' or 'module' at the beginning of\n\
a line generate a tag. Constants also generate a tag.";
static const char *Ruby_interpreters [] =
{ "ruby", NULL };
/* Can't do the `SCM' or `scm' prefix with a version number. */
static const char *Scheme_suffixes [] =
{ "oak", "sch", "scheme", "SCM", "scm", "SM", "sm", "ss", "t", NULL };
static const char Scheme_help [] =
"In Scheme code, tags include anything defined with 'def' or with a\n\
construct whose name starts with 'def'. They also include\n\
variables set with 'set!' at top level in the file.";
static const char *TeX_suffixes [] =
{ "bib", "clo", "cls", "ltx", "sty", "TeX", "tex", NULL };
static const char TeX_help [] =
"In LaTeX text, the argument of any of the commands '\\chapter',\n\
'\\section', '\\subsection', '\\subsubsection', '\\eqno', '\\label',\n\
'\\ref', '\\cite', '\\bibitem', '\\part', '\\appendix', '\\entry',\n\
'\\index', '\\def', '\\newcommand', '\\renewcommand',\n\
'\\newenvironment' or '\\renewenvironment' is a tag.\n\
\n\
Other commands can be specified by setting the environment variable\n\
'TEXTAGS' to a colon-separated list like, for example,\n\
TEXTAGS=\"mycommand:myothercommand\".";
static const char *Texinfo_suffixes [] =
{ "texi", "texinfo", "txi", NULL };
static const char Texinfo_help [] =
"for texinfo files, lines starting with @node are tagged.";
static const char *Yacc_suffixes [] =
{ "y", "y++", "ym", "yxx", "yy", NULL }; /* .ym is Objective yacc file */
static const char Yacc_help [] =
"In Bison or Yacc input files, each rule defines as a tag the\n\
nonterminal it constructs. The portions of the file that contain\n\
C code are parsed as C code (use --help --lang=c --lang=yacc\n\
for full help).";
static const char auto_help [] =
"'auto' is not a real language, it indicates to use\n\
a default language for files base on file name suffix and file contents.";
static const char none_help [] =
"'none' is not a real language, it indicates to only do\n\
regexp processing on files.";
static const char no_lang_help [] =
"No detailed help available for this language.";
/*
* Table of languages.
*
* It is ok for a given function to be listed under more than one
* name. I just didn't.
*/
static language lang_names [] =
{
{ "ada", Ada_help, Ada_funcs, Ada_suffixes },
{ "asm", Asm_help, Asm_labels, Asm_suffixes },
{ "c", default_C_help, default_C_entries, default_C_suffixes },
{ "c++", Cplusplus_help, Cplusplus_entries, Cplusplus_suffixes },
{ "c*", no_lang_help, Cstar_entries, Cstar_suffixes },
{ "cobol", Cobol_help, Cobol_paragraphs, Cobol_suffixes },
{ "erlang", Erlang_help, Erlang_functions, Erlang_suffixes,
NULL, Erlang_interpreters },
{ "forth", Forth_help, Forth_words, Forth_suffixes },
{ "fortran", Fortran_help, Fortran_functions, Fortran_suffixes },
{ "go", Go_help, Go_functions, Go_suffixes },
{ "html", HTML_help, HTML_labels, HTML_suffixes },
{ "java", Cjava_help, Cjava_entries, Cjava_suffixes },
{ "lisp", Lisp_help, Lisp_functions, Lisp_suffixes },
{ "lua", Lua_help,Lua_functions,Lua_suffixes,NULL,Lua_interpreters},
{ "makefile", Makefile_help,Makefile_targets,NULL,Makefile_filenames},
{ "objc", Objc_help, plain_C_entries, Objc_suffixes },
{ "pascal", Pascal_help, Pascal_functions, Pascal_suffixes },
{ "perl",Perl_help,Perl_functions,Perl_suffixes,NULL,Perl_interpreters},
{ "php", PHP_help, PHP_functions, PHP_suffixes },
{ "postscript",PS_help, PS_functions, PS_suffixes },
{ "proc", no_lang_help, plain_C_entries, plain_C_suffixes },
{ "prolog", Prolog_help, Prolog_functions, Prolog_suffixes,
NULL, Prolog_interpreters },
{ "python", Python_help, Python_functions, Python_suffixes,
NULL, Python_interpreters },
{ "ruby", Ruby_help, Ruby_functions, Ruby_suffixes,
Ruby_filenames, Ruby_interpreters },
{ "scheme", Scheme_help, Scheme_functions, Scheme_suffixes },
{ "tex", TeX_help, TeX_commands, TeX_suffixes },
{ "texinfo", Texinfo_help, Texinfo_nodes, Texinfo_suffixes },
{ "yacc", Yacc_help,Yacc_entries,Yacc_suffixes,NULL,NULL,true},
{ "auto", auto_help }, /* default guessing scheme */
{ "none", none_help, just_read_file }, /* regexp matching only */
{ NULL } /* end of list */
};
static void
print_language_names (void)
{
language *lang;
const char **name, **ext;
puts ("\nThese are the currently supported languages, along with the\n\
default file names and dot suffixes:");
for (lang = lang_names; lang->name != NULL; lang++)
{
printf (" %-*s", 10, lang->name);
if (lang->filenames != NULL)
for (name = lang->filenames; *name != NULL; name++)
printf (" %s", *name);
if (lang->suffixes != NULL)
for (ext = lang->suffixes; *ext != NULL; ext++)
printf (" .%s", *ext);
puts ("");
}
puts ("where 'auto' means use default language for files based on file\n\
name suffix, and 'none' means only do regexp processing on files.\n\
If no language is specified and no matching suffix is found,\n\
the first line of the file is read for a sharp-bang (#!) sequence\n\
followed by the name of an interpreter. If no such sequence is found,\n\
Fortran is tried first; if no tags are found, C is tried next.\n\
When parsing any C file, a \"class\" or \"template\" keyword\n\
switches to C++.");
puts ("Compressed files are supported using gzip, bzip2, xz, and zstd.\n\
\n\
For detailed help on a given language use, for example,\n\
etags --help --lang=ada.");
}
#if CTAGS
# define PROGRAM_NAME "ctags"
#else
# define PROGRAM_NAME "etags"
#endif
static _Noreturn void
print_version (void)
{
fputs ((PROGRAM_NAME " (" PACKAGE_NAME " " PACKAGE_VERSION ")\n"
COPYRIGHT "\n"
"This program is distributed under the terms in ETAGS.README\n"),
stdout);
exit (EXIT_SUCCESS);
}
#ifndef PRINT_UNDOCUMENTED_OPTIONS_HELP
# define PRINT_UNDOCUMENTED_OPTIONS_HELP false
#endif
static _Noreturn void
print_help (argument *argbuffer)
{
bool help_for_lang = false;
for (; argbuffer->arg_type != at_end; argbuffer++)
if (argbuffer->arg_type == at_language)
{
if (help_for_lang)
puts ("");
puts (argbuffer->lang->help);
help_for_lang = true;
}
if (help_for_lang)
exit (EXIT_SUCCESS);
printf ("Usage: %s [options] [[regex-option ...] file-name] ...\n\
\n\
These are the options accepted by %s.\n", progname, progname);
puts ("You may use unambiguous abbreviations for the long option names.");
puts (" A - as file name means read names from stdin (one per line).\n\
Absolute names are stored in the output file as they are.\n\
Relative ones are stored relative to the output file's directory.\n");
puts ("-a, --append\n\
Append tag entries to existing tags file.");
puts ("--packages-only\n\
For Ada files, only generate tags for packages.");
if (CTAGS)
puts ("-B, --backward-search\n\
Write the search commands for the tag entries using '?', the\n\
backward-search command instead of '/', the forward-search command.");
/* This option is mostly obsolete, because etags can now automatically
detect C++. Retained for backward compatibility and for debugging and
experimentation. In principle, we could want to tag as C++ even
before any "class" or "template" keyword.
puts ("-C, --c++\n\
Treat files whose name suffix defaults to C language as C++ files.");
*/
puts ("--declarations\n\
In C and derived languages, create tags for function declarations,");
if (CTAGS)
puts ("\tand create tags for extern variables if --globals is used.");
else
puts
("\tand create tags for extern variables unless --no-globals is used.");
if (CTAGS)
puts ("-d, --defines\n\
Create tag entries for C #define constants and enum constants, too.");
else
puts ("-D, --no-defines\n\
Don't create tag entries for C #define constants and enum constants.\n\
This makes the tags file smaller.");
if (!CTAGS)
puts ("-i FILE, --include=FILE\n\
Include a note in tag file indicating that, when searching for\n\
a tag, one should also consult the tags file FILE after\n\
checking the current file.");
puts ("-l LANG, --language=LANG\n\
Force the following files to be considered as written in the\n\
named language up to the next --language=LANG option.");
if (CTAGS)
puts ("--globals\n\
Create tag entries for global variables in some languages.");
else
puts ("--no-globals\n\
Do not create tag entries for global variables in some\n\
languages. This makes the tags file smaller.");
puts ("--no-line-directive\n\
Ignore #line preprocessor directives in C and derived languages.");
if (CTAGS)
puts ("--members\n\
Create tag entries for members of structures in some languages.");
else
puts ("--no-members\n\
Do not create tag entries for members of structures\n\
in some languages.");
puts ("-Q, --class-qualify\n\
Qualify tag names with their class name in C++, ObjC, Java, and Perl.\n\
This produces tag names of the form \"class::member\" for C++,\n\
\"class(category)\" for Objective C, and \"class.member\" for Java.\n\
For Objective C, this also produces class methods qualified with\n\
their arguments, as in \"foo:bar:baz:more\".\n\
For Perl, this produces \"package::member\".");
puts ("-r REGEXP, --regex=REGEXP or --regex=@regexfile\n\
Make a tag for each line matching a regular expression pattern\n\
in the following files. {LANGUAGE}REGEXP uses REGEXP for LANGUAGE\n\
files only. REGEXFILE is a file containing one REGEXP per line.\n\