ctags.rb 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. data/Gemfile +2 -0
  2. data/Rakefile +23 -0
  3. data/ctags.rb.gemspec +23 -0
  4. data/ext/.gitignore +3 -0
  5. data/ext/extconf.rb +15 -0
  6. data/ext/vendor/exuberant-ctags/.gitignore +6 -0
  7. data/ext/vendor/exuberant-ctags/.indent.pro +31 -0
  8. data/ext/vendor/exuberant-ctags/COPYING +340 -0
  9. data/ext/vendor/exuberant-ctags/EXTENDING.html +386 -0
  10. data/ext/vendor/exuberant-ctags/FAQ +371 -0
  11. data/ext/vendor/exuberant-ctags/INSTALL +215 -0
  12. data/ext/vendor/exuberant-ctags/INSTALL.oth +73 -0
  13. data/ext/vendor/exuberant-ctags/MAINTAINERS +88 -0
  14. data/ext/vendor/exuberant-ctags/Makefile.in +222 -0
  15. data/ext/vendor/exuberant-ctags/NEWS +871 -0
  16. data/ext/vendor/exuberant-ctags/README +73 -0
  17. data/ext/vendor/exuberant-ctags/ant.c +42 -0
  18. data/ext/vendor/exuberant-ctags/argproc.c +505 -0
  19. data/ext/vendor/exuberant-ctags/args.c +274 -0
  20. data/ext/vendor/exuberant-ctags/args.h +63 -0
  21. data/ext/vendor/exuberant-ctags/asm.c +387 -0
  22. data/ext/vendor/exuberant-ctags/asp.c +328 -0
  23. data/ext/vendor/exuberant-ctags/awk.c +81 -0
  24. data/ext/vendor/exuberant-ctags/basic.c +203 -0
  25. data/ext/vendor/exuberant-ctags/beta.c +321 -0
  26. data/ext/vendor/exuberant-ctags/c.c +2932 -0
  27. data/ext/vendor/exuberant-ctags/cobol.c +50 -0
  28. data/ext/vendor/exuberant-ctags/config.h.in +277 -0
  29. data/ext/vendor/exuberant-ctags/configure +7704 -0
  30. data/ext/vendor/exuberant-ctags/configure.ac +532 -0
  31. data/ext/vendor/exuberant-ctags/ctags.1 +1186 -0
  32. data/ext/vendor/exuberant-ctags/ctags.h +28 -0
  33. data/ext/vendor/exuberant-ctags/ctags.html +2087 -0
  34. data/ext/vendor/exuberant-ctags/ctags.spec +40 -0
  35. data/ext/vendor/exuberant-ctags/debug.c +113 -0
  36. data/ext/vendor/exuberant-ctags/debug.h +70 -0
  37. data/ext/vendor/exuberant-ctags/descrip.mms +68 -0
  38. data/ext/vendor/exuberant-ctags/dosbatch.c +42 -0
  39. data/ext/vendor/exuberant-ctags/e_amiga.h +24 -0
  40. data/ext/vendor/exuberant-ctags/e_djgpp.h +47 -0
  41. data/ext/vendor/exuberant-ctags/e_mac.h +143 -0
  42. data/ext/vendor/exuberant-ctags/e_msoft.h +76 -0
  43. data/ext/vendor/exuberant-ctags/e_os2.h +37 -0
  44. data/ext/vendor/exuberant-ctags/e_qdos.h +34 -0
  45. data/ext/vendor/exuberant-ctags/e_riscos.h +58 -0
  46. data/ext/vendor/exuberant-ctags/e_vms.h +31 -0
  47. data/ext/vendor/exuberant-ctags/eiffel.c +1352 -0
  48. data/ext/vendor/exuberant-ctags/entry.c +847 -0
  49. data/ext/vendor/exuberant-ctags/entry.h +103 -0
  50. data/ext/vendor/exuberant-ctags/erlang.c +189 -0
  51. data/ext/vendor/exuberant-ctags/flex.c +2243 -0
  52. data/ext/vendor/exuberant-ctags/fortran.c +2197 -0
  53. data/ext/vendor/exuberant-ctags/general.h +127 -0
  54. data/ext/vendor/exuberant-ctags/get.c +669 -0
  55. data/ext/vendor/exuberant-ctags/get.h +50 -0
  56. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/all-wcprops +47 -0
  57. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/entries +112 -0
  58. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/README.txt.svn-base +5 -0
  59. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regcomp.c.svn-base +3818 -0
  60. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regex.c.svn-base +74 -0
  61. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regex.h.svn-base +575 -0
  62. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regex_internal.c.svn-base +1713 -0
  63. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regex_internal.h.svn-base +773 -0
  64. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regexec.c.svn-base +4338 -0
  65. data/ext/vendor/exuberant-ctags/gnu_regex/README.txt +5 -0
  66. data/ext/vendor/exuberant-ctags/gnu_regex/regcomp.c +3818 -0
  67. data/ext/vendor/exuberant-ctags/gnu_regex/regex.c +74 -0
  68. data/ext/vendor/exuberant-ctags/gnu_regex/regex.h +575 -0
  69. data/ext/vendor/exuberant-ctags/gnu_regex/regex_internal.c +1713 -0
  70. data/ext/vendor/exuberant-ctags/gnu_regex/regex_internal.h +773 -0
  71. data/ext/vendor/exuberant-ctags/gnu_regex/regexec.c +4338 -0
  72. data/ext/vendor/exuberant-ctags/html.c +49 -0
  73. data/ext/vendor/exuberant-ctags/jscript.c +1572 -0
  74. data/ext/vendor/exuberant-ctags/keyword.c +258 -0
  75. data/ext/vendor/exuberant-ctags/keyword.h +34 -0
  76. data/ext/vendor/exuberant-ctags/lisp.c +139 -0
  77. data/ext/vendor/exuberant-ctags/lregex.c +704 -0
  78. data/ext/vendor/exuberant-ctags/lua.c +133 -0
  79. data/ext/vendor/exuberant-ctags/mac.c +273 -0
  80. data/ext/vendor/exuberant-ctags/magic.diff +21 -0
  81. data/ext/vendor/exuberant-ctags/main.c +584 -0
  82. data/ext/vendor/exuberant-ctags/main.h +32 -0
  83. data/ext/vendor/exuberant-ctags/maintainer.mak +476 -0
  84. data/ext/vendor/exuberant-ctags/make.c +217 -0
  85. data/ext/vendor/exuberant-ctags/matlab.c +44 -0
  86. data/ext/vendor/exuberant-ctags/mk_bc3.mak +46 -0
  87. data/ext/vendor/exuberant-ctags/mk_bc5.mak +49 -0
  88. data/ext/vendor/exuberant-ctags/mk_djg.mak +18 -0
  89. data/ext/vendor/exuberant-ctags/mk_manx.mak +65 -0
  90. data/ext/vendor/exuberant-ctags/mk_mingw.mak +31 -0
  91. data/ext/vendor/exuberant-ctags/mk_mpw.mak +130 -0
  92. data/ext/vendor/exuberant-ctags/mk_mvc.mak +40 -0
  93. data/ext/vendor/exuberant-ctags/mk_os2.mak +104 -0
  94. data/ext/vendor/exuberant-ctags/mk_qdos.mak +100 -0
  95. data/ext/vendor/exuberant-ctags/mk_sas.mak +63 -0
  96. data/ext/vendor/exuberant-ctags/mkinstalldirs +40 -0
  97. data/ext/vendor/exuberant-ctags/ocaml.c +1842 -0
  98. data/ext/vendor/exuberant-ctags/options.c +1842 -0
  99. data/ext/vendor/exuberant-ctags/options.h +155 -0
  100. data/ext/vendor/exuberant-ctags/parse.c +677 -0
  101. data/ext/vendor/exuberant-ctags/parse.h +129 -0
  102. data/ext/vendor/exuberant-ctags/parsers.h +63 -0
  103. data/ext/vendor/exuberant-ctags/pascal.c +267 -0
  104. data/ext/vendor/exuberant-ctags/perl.c +382 -0
  105. data/ext/vendor/exuberant-ctags/php.c +237 -0
  106. data/ext/vendor/exuberant-ctags/python.c +771 -0
  107. data/ext/vendor/exuberant-ctags/qdos.c +106 -0
  108. data/ext/vendor/exuberant-ctags/read.c +569 -0
  109. data/ext/vendor/exuberant-ctags/read.h +116 -0
  110. data/ext/vendor/exuberant-ctags/readtags.c +959 -0
  111. data/ext/vendor/exuberant-ctags/readtags.h +252 -0
  112. data/ext/vendor/exuberant-ctags/rexx.c +39 -0
  113. data/ext/vendor/exuberant-ctags/routines.c +891 -0
  114. data/ext/vendor/exuberant-ctags/routines.h +134 -0
  115. data/ext/vendor/exuberant-ctags/ruby.c +408 -0
  116. data/ext/vendor/exuberant-ctags/scheme.c +111 -0
  117. data/ext/vendor/exuberant-ctags/sh.c +115 -0
  118. data/ext/vendor/exuberant-ctags/slang.c +41 -0
  119. data/ext/vendor/exuberant-ctags/sml.c +212 -0
  120. data/ext/vendor/exuberant-ctags/sort.c +230 -0
  121. data/ext/vendor/exuberant-ctags/sort.h +32 -0
  122. data/ext/vendor/exuberant-ctags/source.mak +122 -0
  123. data/ext/vendor/exuberant-ctags/sql.c +2112 -0
  124. data/ext/vendor/exuberant-ctags/strlist.c +281 -0
  125. data/ext/vendor/exuberant-ctags/strlist.h +54 -0
  126. data/ext/vendor/exuberant-ctags/tcl.c +116 -0
  127. data/ext/vendor/exuberant-ctags/tex.c +524 -0
  128. data/ext/vendor/exuberant-ctags/verilog.c +340 -0
  129. data/ext/vendor/exuberant-ctags/vhdl.c +835 -0
  130. data/ext/vendor/exuberant-ctags/vim.c +636 -0
  131. data/ext/vendor/exuberant-ctags/vstring.c +232 -0
  132. data/ext/vendor/exuberant-ctags/vstring.h +85 -0
  133. data/ext/vendor/exuberant-ctags/yacc.c +40 -0
  134. data/lib/ctags/exuberant.rb +45 -0
  135. data/lib/ctags/version.rb +3 -0
  136. data/lib/ctags.rb +6 -0
  137. data/test/test_ctags.rb +24 -0
  138. metadata +233 -0
@@ -0,0 +1,1842 @@
1
+ /*
2
+ * $Id: options.c 576 2007-06-30 04:16:23Z elliotth $
3
+ *
4
+ * Copyright (c) 1996-2003, Darren Hiebert
5
+ *
6
+ * This source code is released for free distribution under the terms of the
7
+ * GNU General Public License.
8
+ *
9
+ * This module contains functions to process command line options.
10
+ */
11
+
12
+ /*
13
+ * INCLUDE FILES
14
+ */
15
+ #include "general.h" /* must always come first */
16
+
17
+ #include <stdlib.h>
18
+ #include <string.h>
19
+ #include <stdio.h>
20
+ #include <ctype.h> /* to declare isspace () */
21
+
22
+ #include "ctags.h"
23
+ #include "debug.h"
24
+ #include "main.h"
25
+ #define OPTION_WRITE
26
+ #include "options.h"
27
+ #include "parse.h"
28
+ #include "routines.h"
29
+
30
+ /*
31
+ * MACROS
32
+ */
33
+ #define INVOCATION "Usage: %s [options] [file(s)]\n"
34
+
35
+ #define CTAGS_ENVIRONMENT "CTAGS"
36
+ #define ETAGS_ENVIRONMENT "ETAGS"
37
+
38
+ #define CTAGS_FILE "tags"
39
+ #define ETAGS_FILE "TAGS"
40
+
41
+ #ifndef ETAGS
42
+ # define ETAGS "etags" /* name which causes default use of to -e */
43
+ #endif
44
+
45
+ /* The following separators are permitted for list options.
46
+ */
47
+ #define EXTENSION_SEPARATOR '.'
48
+ #define PATTERN_START '('
49
+ #define PATTERN_STOP ')'
50
+ #define IGNORE_SEPARATORS ", \t\n"
51
+
52
+ #ifndef DEFAULT_FILE_FORMAT
53
+ # define DEFAULT_FILE_FORMAT 2
54
+ #endif
55
+
56
+ #if defined (HAVE_OPENDIR) || defined (HAVE_FINDFIRST) || defined (HAVE__FINDFIRST) || defined (AMIGA)
57
+ # define RECURSE_SUPPORTED
58
+ #endif
59
+
60
+ #define isCompoundOption(c) (boolean) (strchr ("fohiILpDb", (c)) != NULL)
61
+
62
+ /*
63
+ * Data declarations
64
+ */
65
+
66
+ enum eOptionLimits {
67
+ MaxHeaderExtensions = 100, /* maximum number of extensions in -h option */
68
+ MaxSupportedTagFormat = 2
69
+ };
70
+
71
+ typedef struct sOptionDescription {
72
+ int usedByEtags;
73
+ const char *description;
74
+ } optionDescription;
75
+
76
+ typedef void (*parametricOptionHandler) (const char *const option, const char *const parameter);
77
+
78
+ typedef const struct {
79
+ const char* name; /* name of option as specified by user */
80
+ parametricOptionHandler handler; /* routine to handle option */
81
+ boolean initOnly; /* option must be specified before any files */
82
+ } parametricOption;
83
+
84
+ typedef const struct {
85
+ const char* name; /* name of option as specified by user */
86
+ boolean* pValue; /* pointer to option value */
87
+ boolean initOnly; /* option must be specified before any files */
88
+ } booleanOption;
89
+
90
+ /*
91
+ * DATA DEFINITIONS
92
+ */
93
+
94
+ static boolean NonOptionEncountered;
95
+ static stringList *OptionFiles;
96
+ static stringList* Excluded;
97
+ static boolean FilesRequired = TRUE;
98
+ static boolean SkipConfiguration;
99
+
100
+ static const char *const HeaderExtensions [] = {
101
+ "h", "H", "hh", "hpp", "hxx", "h++", "inc", "def", NULL
102
+ };
103
+
104
+ optionValues Option = {
105
+ {
106
+ FALSE, /* --extra=f */
107
+ FALSE, /* --extra=q */
108
+ TRUE, /* --file-scope */
109
+ },
110
+ {
111
+ FALSE, /* -fields=a */
112
+ TRUE, /* -fields=f */
113
+ FALSE, /* -fields=m */
114
+ FALSE, /* -fields=i */
115
+ TRUE, /* -fields=k */
116
+ FALSE, /* -fields=z */
117
+ FALSE, /* -fields=K */
118
+ FALSE, /* -fields=l */
119
+ FALSE, /* -fields=n */
120
+ TRUE, /* -fields=s */
121
+ FALSE, /* -fields=S */
122
+ TRUE /* -fields=t */
123
+ },
124
+ NULL, /* -I */
125
+ FALSE, /* -a */
126
+ FALSE, /* -B */
127
+ FALSE, /* -e */
128
+ #ifdef MACROS_USE_PATTERNS
129
+ EX_PATTERN, /* -n, --excmd */
130
+ #else
131
+ EX_MIX, /* -n, --excmd */
132
+ #endif
133
+ FALSE, /* -R */
134
+ SO_SORTED, /* -u, --sort */
135
+ FALSE, /* -V */
136
+ FALSE, /* -x */
137
+ NULL, /* -L */
138
+ NULL, /* -o */
139
+ NULL, /* -h */
140
+ NULL, /* --etags-include */
141
+ DEFAULT_FILE_FORMAT,/* --format */
142
+ FALSE, /* --if0 */
143
+ FALSE, /* --kind-long */
144
+ LANG_AUTO, /* --lang */
145
+ TRUE, /* --links */
146
+ FALSE, /* --filter */
147
+ NULL, /* --filter-terminator */
148
+ FALSE, /* --tag-relative */
149
+ FALSE, /* --totals */
150
+ FALSE, /* --line-directives */
151
+ #ifdef DEBUG
152
+ 0, 0 /* -D, -b */
153
+ #endif
154
+ };
155
+
156
+ /*
157
+ - Locally used only
158
+ */
159
+
160
+ static optionDescription LongOptionDescription [] = {
161
+ {1," -a Append the tags to an existing tag file."},
162
+ #ifdef DEBUG
163
+ {1," -b <line>"},
164
+ {1," Set break line."},
165
+ #endif
166
+ {0," -B Use backward searching patterns (?...?)."},
167
+ #ifdef DEBUG
168
+ {1," -D <level>"},
169
+ {1," Set debug level."},
170
+ #endif
171
+ {0," -e Output tag file for use with Emacs."},
172
+ {1," -f <name>"},
173
+ {1," Write tags to specified file. Value of \"-\" writes tags to stdout"},
174
+ {1," [\"tags\"; or \"TAGS\" when -e supplied]."},
175
+ {0," -F Use forward searching patterns (/.../) (default)."},
176
+ {1," -h <list>"},
177
+ {1," Specify list of file extensions to be treated as include files."},
178
+ {1," [\".h.H.hh.hpp.hxx.h++\"]."},
179
+ {1," -I <list|@file>"},
180
+ {1," A list of tokens to be specially handled is read from either the"},
181
+ {1," command line or the specified file."},
182
+ {1," -L <file>"},
183
+ {1," A list of source file names are read from the specified file."},
184
+ {1," If specified as \"-\", then standard input is read."},
185
+ {0," -n Equivalent to --excmd=number."},
186
+ {0," -N Equivalent to --excmd=pattern."},
187
+ {1," -o Alternative for -f."},
188
+ #ifdef RECURSE_SUPPORTED
189
+ {1," -R Equivalent to --recurse."},
190
+ #else
191
+ {1," -R Not supported on this platform."},
192
+ #endif
193
+ {0," -u Equivalent to --sort=no."},
194
+ {1," -V Equivalent to --verbose."},
195
+ {1," -x Print a tabular cross reference file to standard output."},
196
+ {1," --append=[yes|no]"},
197
+ {1," Should tags should be appended to existing tag file [no]?"},
198
+ {1," --etags-include=file"},
199
+ {1," Include reference to 'file' in Emacs-style tag file (requires -e)."},
200
+ {1," --exclude=pattern"},
201
+ {1," Exclude files and directories matching 'pattern'."},
202
+ {0," --excmd=number|pattern|mix"},
203
+ #ifdef MACROS_USE_PATTERNS
204
+ {0," Uses the specified type of EX command to locate tags [pattern]."},
205
+ #else
206
+ {0," Uses the specified type of EX command to locate tags [mix]."},
207
+ #endif
208
+ {1," --extra=[+|-]flags"},
209
+ {1," Include extra tag entries for selected information (flags: \"fq\")."},
210
+ {1," --fields=[+|-]flags"},
211
+ {1," Include selected extension fields (flags: \"afmikKlnsStz\") [fks]."},
212
+ {1," --file-scope=[yes|no]"},
213
+ {1," Should tags scoped only for a single file (e.g. \"static\" tags"},
214
+ {1," be included in the output [yes]?"},
215
+ {1," --filter=[yes|no]"},
216
+ {1," Behave as a filter, reading file names from standard input and"},
217
+ {1," writing tags to standard output [no]."},
218
+ {1," --filter-terminator=string"},
219
+ {1," Specify string to print to stdout following the tags for each file"},
220
+ {1," parsed when --filter is enabled."},
221
+ {0," --format=level"},
222
+ #if DEFAULT_FILE_FORMAT == 1
223
+ {0," Force output of specified tag file format [1]."},
224
+ #else
225
+ {0," Force output of specified tag file format [2]."},
226
+ #endif
227
+ {1," --help"},
228
+ {1," Print this option summary."},
229
+ {1," --if0=[yes|no]"},
230
+ {1," Should C code within #if 0 conditional branches be parsed [no]?"},
231
+ {1," --<LANG>-kinds=[+|-]kinds"},
232
+ {1," Enable/disable tag kinds for language <LANG>."},
233
+ {1," --langdef=name"},
234
+ {1," Define a new language to be parsed with regular expressions."},
235
+ {1," --langmap=map(s)"},
236
+ {1," Override default mapping of language to source file extension."},
237
+ {1," --language-force=language"},
238
+ {1," Force all files to be interpreted using specified language."},
239
+ {1," --languages=[+|-]list"},
240
+ {1," Restrict files scanned for tags to those mapped to langauges"},
241
+ {1," specified in the comma-separated 'list'. The list can contain any"},
242
+ {1," built-in or user-defined language [all]."},
243
+ {1," --license"},
244
+ {1," Print details of software license."},
245
+ {0," --line-directives=[yes|no]"},
246
+ {0," Should #line directives be processed [no]?"},
247
+ {1," --links=[yes|no]"},
248
+ {1," Indicate whether symbolic links should be followed [yes]."},
249
+ {1," --list-kinds=[language|all]"},
250
+ {1," Output a list of all tag kinds for specified language or all."},
251
+ {1," --list-languages"},
252
+ {1," Output list of supported languages."},
253
+ {1," --list-maps=[language|all]"},
254
+ {1," Output list of language mappings."},
255
+ {1," --options=file"},
256
+ {1," Specify file from which command line options should be read."},
257
+ {1," --recurse=[yes|no]"},
258
+ #ifdef RECURSE_SUPPORTED
259
+ {1," Recurse into directories supplied on command line [no]."},
260
+ #else
261
+ {1," Not supported on this platform."},
262
+ #endif
263
+ #ifdef HAVE_REGEX
264
+ {1," --regex-<LANG>=/line_pattern/name_pattern/[flags]"},
265
+ {1," Define regular expression for locating tags in specific language."},
266
+ #endif
267
+ {0," --sort=[yes|no|foldcase]"},
268
+ {0," Should tags be sorted (optionally ignoring case) [yes]?."},
269
+ {0," --tag-relative=[yes|no]"},
270
+ {0," Should paths be relative to location of tag file [no; yes when -e]?"},
271
+ {1," --totals=[yes|no]"},
272
+ {1," Print statistics about source and tag files [no]."},
273
+ {1," --verbose=[yes|no]"},
274
+ {1," Enable verbose messages describing actions on each source file."},
275
+ {1," --version"},
276
+ {1," Print version identifier to standard output."},
277
+ {1, NULL}
278
+ };
279
+
280
+ static const char* const License1 =
281
+ "This program is free software; you can redistribute it and/or\n"
282
+ "modify it under the terms of the GNU General Public License\n"
283
+ "as published by the Free Software Foundation; either version 2\n"
284
+ "of the License, or (at your option) any later version.\n"
285
+ "\n";
286
+ static const char* const License2 =
287
+ "This program is distributed in the hope that it will be useful,\n"
288
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
289
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
290
+ "GNU General Public License for more details.\n"
291
+ "\n"
292
+ "You should have received a copy of the GNU General Public License\n"
293
+ "along with this program; if not, write to the Free Software\n"
294
+ "Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n";
295
+
296
+ /* Contains a set of strings describing the set of "features" compiled into
297
+ * the code.
298
+ */
299
+ static const char *const Features [] = {
300
+ #ifdef WIN32
301
+ "win32",
302
+ #endif
303
+ #ifdef DJGPP
304
+ "msdos_32",
305
+ #else
306
+ # ifdef MSDOS
307
+ "msdos_16",
308
+ # endif
309
+ #endif
310
+ #ifdef OS2
311
+ "os2",
312
+ #endif
313
+ #ifdef AMIGA
314
+ "amiga",
315
+ #endif
316
+ #ifdef VMS
317
+ "vms",
318
+ #endif
319
+ #ifdef HAVE_FNMATCH
320
+ "wildcards",
321
+ #endif
322
+ #ifdef HAVE_REGEX
323
+ "regex",
324
+ #endif
325
+ #ifndef EXTERNAL_SORT
326
+ "internal-sort",
327
+ #endif
328
+ #ifdef CUSTOM_CONFIGURATION_FILE
329
+ "custom-conf",
330
+ #endif
331
+ #if (defined (MSDOS) || defined (WIN32) || defined (OS2)) && defined (UNIX_PATH_SEPARATOR)
332
+ "unix-path-separator",
333
+ #endif
334
+ #ifdef DEBUG
335
+ "debug",
336
+ #endif
337
+ NULL
338
+ };
339
+
340
+ /*
341
+ * FUNCTION PROTOTYPES
342
+ */
343
+ static boolean parseFileOptions (const char *const fileName);
344
+
345
+ /*
346
+ * FUNCTION DEFINITIONS
347
+ */
348
+
349
+ extern void verbose (const char *const format, ...)
350
+ {
351
+ if (Option.verbose)
352
+ {
353
+ va_list ap;
354
+ va_start (ap, format);
355
+ vprintf (format, ap);
356
+ va_end (ap);
357
+ }
358
+ }
359
+
360
+ static char *stringCopy (const char *const string)
361
+ {
362
+ char* result = NULL;
363
+ if (string != NULL)
364
+ result = eStrdup (string);
365
+ return result;
366
+ }
367
+
368
+ static void freeString (char **const pString)
369
+ {
370
+ if (*pString != NULL)
371
+ {
372
+ eFree (*pString);
373
+ *pString = NULL;
374
+ }
375
+ }
376
+
377
+ extern void freeList (stringList** const pList)
378
+ {
379
+ if (*pList != NULL)
380
+ {
381
+ stringListDelete (*pList);
382
+ *pList = NULL;
383
+ }
384
+ }
385
+
386
+ extern void setDefaultTagFileName (void)
387
+ {
388
+ if (Option.tagFileName != NULL)
389
+ ; /* accept given name */
390
+ else if (Option.etags)
391
+ Option.tagFileName = stringCopy (ETAGS_FILE);
392
+ else
393
+ Option.tagFileName = stringCopy (CTAGS_FILE);
394
+ }
395
+
396
+ extern boolean filesRequired (void)
397
+ {
398
+ boolean result = FilesRequired;
399
+ if (Option.recurse || Option.stdinFileName)
400
+ result = FALSE;
401
+ return result;
402
+ }
403
+
404
+ extern void checkOptions (void)
405
+ {
406
+ const char* notice;
407
+ if (Option.xref)
408
+ {
409
+ notice = "xref output";
410
+ if (Option.include.fileNames)
411
+ {
412
+ error (WARNING, "%s disables file name tags", notice);
413
+ Option.include.fileNames = FALSE;
414
+ }
415
+ }
416
+ if (Option.append)
417
+ {
418
+ notice = "append mode is not compatible with";
419
+ if (isDestinationStdout ())
420
+ error (FATAL, "%s tags to stdout", notice);
421
+ }
422
+ if (Option.filter)
423
+ {
424
+ notice = "filter mode";
425
+ if (Option.printTotals)
426
+ {
427
+ error (WARNING, "%s disables totals", notice);
428
+ Option.printTotals = FALSE;
429
+ }
430
+ if (Option.tagFileName != NULL)
431
+ error (WARNING, "%s ignores output tag file name", notice);
432
+ }
433
+ }
434
+
435
+ static void setEtagsMode (void)
436
+ {
437
+ Option.etags = TRUE;
438
+ Option.sorted = SO_UNSORTED;
439
+ Option.lineDirectives = FALSE;
440
+ Option.tagRelative = TRUE;
441
+ }
442
+
443
+ extern void testEtagsInvocation (void)
444
+ {
445
+ char* const execName = eStrdup (getExecutableName ());
446
+ char* const etags = eStrdup (ETAGS);
447
+ #ifdef CASE_INSENSITIVE_FILENAMES
448
+ toLowerString (execName);
449
+ toLowerString (etags);
450
+ #endif
451
+ if (strstr (execName, etags) != NULL)
452
+ {
453
+ verbose ("Running in etags mode\n");
454
+ setEtagsMode ();
455
+ }
456
+ eFree (execName);
457
+ eFree (etags);
458
+ }
459
+
460
+ /*
461
+ * Cooked argument parsing
462
+ */
463
+
464
+ static void parseShortOption (cookedArgs *const args)
465
+ {
466
+ args->simple [0] = *args->shortOptions++;
467
+ args->simple [1] = '\0';
468
+ args->item = args->simple;
469
+ if (! isCompoundOption (*args->simple))
470
+ args->parameter = "";
471
+ else if (*args->shortOptions == '\0')
472
+ {
473
+ argForth (args->args);
474
+ if (argOff (args->args))
475
+ args->parameter = NULL;
476
+ else
477
+ args->parameter = argItem (args->args);
478
+ args->shortOptions = NULL;
479
+ }
480
+ else
481
+ {
482
+ args->parameter = args->shortOptions;
483
+ args->shortOptions = NULL;
484
+ }
485
+ }
486
+
487
+ static void parseLongOption (cookedArgs *const args, const char *item)
488
+ {
489
+ const char* const equal = strchr (item, '=');
490
+ if (equal == NULL)
491
+ {
492
+ args->item = eStrdup (item); /* FIXME: memory leak. */
493
+ args->parameter = "";
494
+ }
495
+ else
496
+ {
497
+ const size_t length = equal - item;
498
+ args->item = xMalloc (length + 1, char); /* FIXME: memory leak. */
499
+ strncpy (args->item, item, length);
500
+ args->item [length] = '\0';
501
+ args->parameter = equal + 1;
502
+ }
503
+ Assert (args->item != NULL);
504
+ Assert (args->parameter != NULL);
505
+ }
506
+
507
+ static void cArgRead (cookedArgs *const current)
508
+ {
509
+ char* item;
510
+
511
+ Assert (current != NULL);
512
+ if (! argOff (current->args))
513
+ {
514
+ item = argItem (current->args);
515
+ current->shortOptions = NULL;
516
+ Assert (item != NULL);
517
+ if (strncmp (item, "--", (size_t) 2) == 0)
518
+ {
519
+ current->isOption = TRUE;
520
+ current->longOption = TRUE;
521
+ parseLongOption (current, item + 2);
522
+ Assert (current->item != NULL);
523
+ Assert (current->parameter != NULL);
524
+ }
525
+ else if (*item == '-')
526
+ {
527
+ current->isOption = TRUE;
528
+ current->longOption = FALSE;
529
+ current->shortOptions = item + 1;
530
+ parseShortOption (current);
531
+ }
532
+ else
533
+ {
534
+ current->isOption = FALSE;
535
+ current->longOption = FALSE;
536
+ current->item = item;
537
+ current->parameter = NULL;
538
+ }
539
+ }
540
+ }
541
+
542
+ extern cookedArgs* cArgNewFromString (const char* string)
543
+ {
544
+ cookedArgs* const result = xMalloc (1, cookedArgs);
545
+ memset (result, 0, sizeof (cookedArgs));
546
+ result->args = argNewFromString (string);
547
+ cArgRead (result);
548
+ return result;
549
+ }
550
+
551
+ extern cookedArgs* cArgNewFromArgv (char* const* const argv)
552
+ {
553
+ cookedArgs* const result = xMalloc (1, cookedArgs);
554
+ memset (result, 0, sizeof (cookedArgs));
555
+ result->args = argNewFromArgv (argv);
556
+ cArgRead (result);
557
+ return result;
558
+ }
559
+
560
+ extern cookedArgs* cArgNewFromFile (FILE* const fp)
561
+ {
562
+ cookedArgs* const result = xMalloc (1, cookedArgs);
563
+ memset (result, 0, sizeof (cookedArgs));
564
+ result->args = argNewFromFile (fp);
565
+ cArgRead (result);
566
+ return result;
567
+ }
568
+
569
+ extern cookedArgs* cArgNewFromLineFile (FILE* const fp)
570
+ {
571
+ cookedArgs* const result = xMalloc (1, cookedArgs);
572
+ memset (result, 0, sizeof (cookedArgs));
573
+ result->args = argNewFromLineFile (fp);
574
+ cArgRead (result);
575
+ return result;
576
+ }
577
+
578
+ extern void cArgDelete (cookedArgs* const current)
579
+ {
580
+ Assert (current != NULL);
581
+ argDelete (current->args);
582
+ memset (current, 0, sizeof (cookedArgs));
583
+ eFree (current);
584
+ }
585
+
586
+ static boolean cArgOptionPending (cookedArgs* const current)
587
+ {
588
+ boolean result = FALSE;
589
+ if (current->shortOptions != NULL)
590
+ if (*current->shortOptions != '\0')
591
+ result = TRUE;
592
+ return result;
593
+ }
594
+
595
+ extern boolean cArgOff (cookedArgs* const current)
596
+ {
597
+ Assert (current != NULL);
598
+ return (boolean) (argOff (current->args) && ! cArgOptionPending (current));
599
+ }
600
+
601
+ extern boolean cArgIsOption (cookedArgs* const current)
602
+ {
603
+ Assert (current != NULL);
604
+ return current->isOption;
605
+ }
606
+
607
+ extern const char* cArgItem (cookedArgs* const current)
608
+ {
609
+ Assert (current != NULL);
610
+ return current->item;
611
+ }
612
+
613
+ extern void cArgForth (cookedArgs* const current)
614
+ {
615
+ Assert (current != NULL);
616
+ Assert (! cArgOff (current));
617
+ if (cArgOptionPending (current))
618
+ parseShortOption (current);
619
+ else
620
+ {
621
+ Assert (! argOff (current->args));
622
+ argForth (current->args);
623
+ if (! argOff (current->args))
624
+ cArgRead (current);
625
+ else
626
+ {
627
+ current->isOption = FALSE;
628
+ current->longOption = FALSE;
629
+ current->shortOptions = NULL;
630
+ current->item = NULL;
631
+ current->parameter = NULL;
632
+ }
633
+ }
634
+ }
635
+
636
+ /*
637
+ * File extension and language mapping
638
+ */
639
+
640
+ static void addExtensionList (
641
+ stringList *const slist, const char *const elist, const boolean clear)
642
+ {
643
+ char *const extensionList = eStrdup (elist);
644
+ const char *extension = NULL;
645
+ boolean first = TRUE;
646
+
647
+ if (clear)
648
+ {
649
+ verbose (" clearing\n");
650
+ stringListClear (slist);
651
+ }
652
+ verbose (" adding: ");
653
+ if (elist != NULL && *elist != '\0')
654
+ {
655
+ extension = extensionList;
656
+ if (elist [0] == EXTENSION_SEPARATOR)
657
+ ++extension;
658
+ }
659
+ while (extension != NULL)
660
+ {
661
+ char *separator = strchr (extension, EXTENSION_SEPARATOR);
662
+ if (separator != NULL)
663
+ *separator = '\0';
664
+ verbose ("%s%s", first ? "" : ", ",
665
+ *extension == '\0' ? "(NONE)" : extension);
666
+ stringListAdd (slist, vStringNewInit (extension));
667
+ first = FALSE;
668
+ if (separator == NULL)
669
+ extension = NULL;
670
+ else
671
+ extension = separator + 1;
672
+ }
673
+ if (Option.verbose)
674
+ {
675
+ printf ("\n now: ");
676
+ stringListPrint (slist);
677
+ putchar ('\n');
678
+ }
679
+ eFree (extensionList);
680
+ }
681
+
682
+ static boolean isFalse (const char *parameter)
683
+ {
684
+ return (boolean) (
685
+ strcasecmp (parameter, "0" ) == 0 ||
686
+ strcasecmp (parameter, "n" ) == 0 ||
687
+ strcasecmp (parameter, "no" ) == 0 ||
688
+ strcasecmp (parameter, "off") == 0);
689
+ }
690
+
691
+ static boolean isTrue (const char *parameter)
692
+ {
693
+ return (boolean) (
694
+ strcasecmp (parameter, "1" ) == 0 ||
695
+ strcasecmp (parameter, "y" ) == 0 ||
696
+ strcasecmp (parameter, "yes") == 0 ||
697
+ strcasecmp (parameter, "on" ) == 0);
698
+ }
699
+
700
+ /* Determines whether the specified file name is considered to be a header
701
+ * file for the purposes of determining whether enclosed tags are global or
702
+ * static.
703
+ */
704
+ extern boolean isIncludeFile (const char *const fileName)
705
+ {
706
+ boolean result = FALSE;
707
+ const char *const extension = fileExtension (fileName);
708
+ if (Option.headerExt != NULL)
709
+ result = stringListExtensionMatched (Option.headerExt, extension);
710
+ return result;
711
+ }
712
+
713
+ /*
714
+ * Specific option processing
715
+ */
716
+
717
+ static void processEtagsInclude (
718
+ const char *const option, const char *const parameter)
719
+ {
720
+ if (! Option.etags)
721
+ error (FATAL, "Etags must be enabled to use \"%s\" option", option);
722
+ else
723
+ {
724
+ vString *const file = vStringNewInit (parameter);
725
+ if (Option.etagsInclude == NULL)
726
+ Option.etagsInclude = stringListNew ();
727
+ stringListAdd (Option.etagsInclude, file);
728
+ FilesRequired = FALSE;
729
+ }
730
+ }
731
+
732
+ static void processExcludeOption (
733
+ const char *const option __unused__, const char *const parameter)
734
+ {
735
+ const char *const fileName = parameter + 1;
736
+ if (parameter [0] == '\0')
737
+ freeList (&Excluded);
738
+ else if (parameter [0] == '@')
739
+ {
740
+ stringList* const sl = stringListNewFromFile (fileName);
741
+ if (sl == NULL)
742
+ error (FATAL | PERROR, "cannot open \"%s\"", fileName);
743
+ if (Excluded == NULL)
744
+ Excluded = sl;
745
+ else
746
+ stringListCombine (Excluded, sl);
747
+ verbose (" adding exclude patterns from %s\n", fileName);
748
+ }
749
+ else
750
+ {
751
+ vString *const item = vStringNewInit (parameter);
752
+ if (Excluded == NULL)
753
+ Excluded = stringListNew ();
754
+ stringListAdd (Excluded, item);
755
+ verbose (" adding exclude pattern: %s\n", parameter);
756
+ }
757
+ }
758
+
759
+ extern boolean isExcludedFile (const char* const name)
760
+ {
761
+ const char* base = baseFilename (name);
762
+ boolean result = FALSE;
763
+ if (Excluded != NULL)
764
+ {
765
+ result = stringListFileMatched (Excluded, base);
766
+ if (! result && name != base)
767
+ result = stringListFileMatched (Excluded, name);
768
+ }
769
+ #ifdef AMIGA
770
+ /* not a good solution, but the only one which works often */
771
+ if (! result)
772
+ result = (boolean) (strcmp (name, TagFile.name) == 0);
773
+ #endif
774
+ return result;
775
+ }
776
+
777
+ static void processExcmdOption (
778
+ const char *const option, const char *const parameter)
779
+ {
780
+ switch (*parameter)
781
+ {
782
+ case 'm': Option.locate = EX_MIX; break;
783
+ case 'n': Option.locate = EX_LINENUM; break;
784
+ case 'p': Option.locate = EX_PATTERN; break;
785
+ default:
786
+ error (FATAL, "Invalid value for \"%s\" option", option);
787
+ break;
788
+ }
789
+ }
790
+
791
+ static void processExtraTagsOption (
792
+ const char *const option, const char *const parameter)
793
+ {
794
+ struct sInclude *const inc = &Option.include;
795
+ const char *p = parameter;
796
+ boolean mode = TRUE;
797
+ int c;
798
+
799
+ if (*p != '+' && *p != '-')
800
+ {
801
+ inc->fileNames = FALSE;
802
+ inc->qualifiedTags = FALSE;
803
+ #if 0
804
+ inc->fileScope = FALSE;
805
+ #endif
806
+ }
807
+ while ((c = *p++) != '\0') switch (c)
808
+ {
809
+ case '+': mode = TRUE; break;
810
+ case '-': mode = FALSE; break;
811
+
812
+ case 'f': inc->fileNames = mode; break;
813
+ case 'q': inc->qualifiedTags = mode; break;
814
+ #if 0
815
+ case 'F': inc->fileScope = mode; break;
816
+ #endif
817
+
818
+ default: error(WARNING, "Unsupported parameter '%c' for \"%s\" option",
819
+ c, option);
820
+ break;
821
+ }
822
+ }
823
+
824
+ static void processFieldsOption (
825
+ const char *const option, const char *const parameter)
826
+ {
827
+ struct sExtFields *field = &Option.extensionFields;
828
+ const char *p = parameter;
829
+ boolean mode = TRUE;
830
+ int c;
831
+
832
+ if (*p != '+' && *p != '-')
833
+ {
834
+ field->access = FALSE;
835
+ field->fileScope = FALSE;
836
+ field->implementation = FALSE;
837
+ field->inheritance = FALSE;
838
+ field->kind = FALSE;
839
+ field->kindKey = FALSE;
840
+ field->kindLong = FALSE;
841
+ field->language = FALSE;
842
+ field->scope = FALSE;
843
+ field->typeRef = FALSE;
844
+ }
845
+ while ((c = *p++) != '\0') switch (c)
846
+ {
847
+ case '+': mode = TRUE; break;
848
+ case '-': mode = FALSE; break;
849
+
850
+ case 'a': field->access = mode; break;
851
+ case 'f': field->fileScope = mode; break;
852
+ case 'm': field->implementation = mode; break;
853
+ case 'i': field->inheritance = mode; break;
854
+ case 'k': field->kind = mode; break;
855
+ case 'K': field->kindLong = mode; break;
856
+ case 'l': field->language = mode; break;
857
+ case 'n': field->lineNumber = mode; break;
858
+ case 's': field->scope = mode; break;
859
+ case 'S': field->signature = mode; break;
860
+ case 'z': field->kindKey = mode; break;
861
+ case 't': field->typeRef = mode; break;
862
+
863
+ default: error(WARNING, "Unsupported parameter '%c' for \"%s\" option",
864
+ c, option);
865
+ break;
866
+ }
867
+ }
868
+
869
+ static void processFilterTerminatorOption (
870
+ const char *const option __unused__, const char *const parameter)
871
+ {
872
+ freeString (&Option.filterTerminator);
873
+ Option.filterTerminator = stringCopy (parameter);
874
+ }
875
+
876
+ static void processFormatOption (
877
+ const char *const option, const char *const parameter)
878
+ {
879
+ unsigned int format;
880
+
881
+ if (sscanf (parameter, "%u", &format) < 1)
882
+ error (FATAL, "Invalid value for \"%s\" option",option);
883
+ else if (format <= (unsigned int) MaxSupportedTagFormat)
884
+ Option.tagFileFormat = format;
885
+ else
886
+ error (FATAL, "Unsupported value for \"%s\" option", option);
887
+ }
888
+
889
+ static void printInvocationDescription (void)
890
+ {
891
+ printf (INVOCATION, getExecutableName ());
892
+ }
893
+
894
+ static void printOptionDescriptions (const optionDescription *const optDesc)
895
+ {
896
+ int i;
897
+ for (i = 0 ; optDesc [i].description != NULL ; ++i)
898
+ {
899
+ if (! Option.etags || optDesc [i].usedByEtags)
900
+ puts (optDesc [i].description);
901
+ }
902
+ }
903
+
904
+ static void printFeatureList (void)
905
+ {
906
+ int i;
907
+
908
+ for (i = 0 ; Features [i] != NULL ; ++i)
909
+ {
910
+ if (i == 0)
911
+ printf (" Optional compiled features: ");
912
+ printf ("%s+%s", (i>0 ? ", " : ""), Features [i]);
913
+ #ifdef CUSTOM_CONFIGURATION_FILE
914
+ if (strcmp (Features [i], "custom-conf") == 0)
915
+ printf ("=%s", CUSTOM_CONFIGURATION_FILE);
916
+ #endif
917
+ }
918
+ if (i > 0)
919
+ putchar ('\n');
920
+ }
921
+
922
+ static void printProgramIdentification (void)
923
+ {
924
+ printf ("%s %s, %s %s\n",
925
+ PROGRAM_NAME, PROGRAM_VERSION,
926
+ PROGRAM_COPYRIGHT, AUTHOR_NAME);
927
+ printf (" Compiled: %s, %s\n", __DATE__, __TIME__);
928
+ printf (" Addresses: <%s>, %s\n", AUTHOR_EMAIL, PROGRAM_URL);
929
+ printFeatureList ();
930
+ }
931
+
932
+ static void processHelpOption (
933
+ const char *const option __unused__,
934
+ const char *const parameter __unused__)
935
+ {
936
+ printProgramIdentification ();
937
+ putchar ('\n');
938
+ printInvocationDescription ();
939
+ putchar ('\n');
940
+ printOptionDescriptions (LongOptionDescription);
941
+ exit (0);
942
+ }
943
+
944
+ static void processLanguageForceOption (
945
+ const char *const option, const char *const parameter)
946
+ {
947
+ langType language;
948
+ if (strcasecmp (parameter, "auto") == 0)
949
+ language = LANG_AUTO;
950
+ else
951
+ language = getNamedLanguage (parameter);
952
+
953
+ if (strcmp (option, "lang") == 0 || strcmp (option, "language") == 0)
954
+ error (WARNING,
955
+ "\"--%s\" option is obsolete; use \"--language-force\" instead",
956
+ option);
957
+ if (language == LANG_IGNORE)
958
+ error (FATAL, "Unknown language \"%s\" in \"%s\" option", parameter, option);
959
+ else
960
+ Option.language = language;
961
+ }
962
+
963
+ static void processStdinFileName (
964
+ const char *const option, const char *const parameter)
965
+ {
966
+ if (strlen(parameter) == 0) {
967
+ error (FATAL, "No filename specified for --stdin-filename");
968
+ }
969
+
970
+ Option.stdinFileName = stringCopy(parameter);
971
+ }
972
+
973
+ static char* skipPastMap (char* p)
974
+ {
975
+ while (*p != EXTENSION_SEPARATOR &&
976
+ *p != PATTERN_START && *p != ',' && *p != '\0')
977
+ ++p;
978
+ return p;
979
+ }
980
+
981
+ /* Parses the mapping beginning at `map', adds it to the language map, and
982
+ * returns first character past the map.
983
+ */
984
+ static char* addLanguageMap (const langType language, char* map)
985
+ {
986
+ char* p = NULL;
987
+ const char first = *map;
988
+ if (first == EXTENSION_SEPARATOR) /* extension map */
989
+ {
990
+ ++map;
991
+ p = skipPastMap (map);
992
+ if (*p == '\0')
993
+ {
994
+ verbose (" .%s", map);
995
+ addLanguageExtensionMap (language, map);
996
+ p = map + strlen (map);
997
+ }
998
+ else
999
+ {
1000
+ const char separator = *p;
1001
+ *p = '\0';
1002
+ verbose (" .%s", map);
1003
+ addLanguageExtensionMap (language, map);
1004
+ *p = separator;
1005
+ }
1006
+ }
1007
+ else if (first == PATTERN_START) /* pattern map */
1008
+ {
1009
+ ++map;
1010
+ for (p = map ; *p != PATTERN_STOP && *p != '\0' ; ++p)
1011
+ {
1012
+ if (*p == '\\' && *(p + 1) == PATTERN_STOP)
1013
+ ++p;
1014
+ }
1015
+ if (*p == '\0')
1016
+ error (FATAL, "Unterminated file name pattern for %s language",
1017
+ getLanguageName (language));
1018
+ else
1019
+ {
1020
+ *p++ = '\0';
1021
+ verbose (" (%s)", map);
1022
+ addLanguagePatternMap (language, map);
1023
+ }
1024
+ }
1025
+ else
1026
+ error (FATAL, "Badly formed language map for %s language",
1027
+ getLanguageName (language));
1028
+ return p;
1029
+ }
1030
+
1031
+ static char* processLanguageMap (char* map)
1032
+ {
1033
+ char* const separator = strchr (map, ':');
1034
+ char* result = NULL;
1035
+ if (separator != NULL)
1036
+ {
1037
+ langType language;
1038
+ char *list = separator + 1;
1039
+ boolean clear = FALSE;
1040
+ *separator = '\0';
1041
+ language = getNamedLanguage (map);
1042
+ if (language != LANG_IGNORE)
1043
+ {
1044
+ const char *const deflt = "default";
1045
+ char* p;
1046
+ if (*list == '+')
1047
+ ++list;
1048
+ else
1049
+ clear = TRUE;
1050
+ for (p = list ; *p != ',' && *p != '\0' ; ++p) /*no-op*/ ;
1051
+ if ((size_t) (p - list) == strlen (deflt) &&
1052
+ strncasecmp (list, deflt, p - list) == 0)
1053
+ {
1054
+ verbose (" Restoring default %s language map: ", getLanguageName (language));
1055
+ installLanguageMapDefault (language);
1056
+ list = p;
1057
+ }
1058
+ else
1059
+ {
1060
+ if (clear)
1061
+ {
1062
+ verbose (" Setting %s language map:", getLanguageName (language));
1063
+ clearLanguageMap (language);
1064
+ }
1065
+ else
1066
+ verbose (" Adding to %s language map:", getLanguageName (language));
1067
+ while (list != NULL && *list != '\0' && *list != ',')
1068
+ list = addLanguageMap (language, list);
1069
+ verbose ("\n");
1070
+ }
1071
+ if (list != NULL && *list == ',')
1072
+ ++list;
1073
+ result = list;
1074
+ }
1075
+ }
1076
+ return result;
1077
+ }
1078
+
1079
+ static void processLanguageMapOption (
1080
+ const char *const option, const char *const parameter)
1081
+ {
1082
+ char *const maps = eStrdup (parameter);
1083
+ char *map = maps;
1084
+
1085
+ if (strcmp (parameter, "default") == 0)
1086
+ {
1087
+ verbose (" Restoring default language maps:\n");
1088
+ installLanguageMapDefaults ();
1089
+ }
1090
+ else while (map != NULL && *map != '\0')
1091
+ {
1092
+ char* const next = processLanguageMap (map);
1093
+ if (next == NULL)
1094
+ error (WARNING, "Unknown language \"%s\" in \"%s\" option", parameter, option);
1095
+ map = next;
1096
+ }
1097
+ eFree (maps);
1098
+ }
1099
+
1100
+ static void processLanguagesOption (
1101
+ const char *const option, const char *const parameter)
1102
+ {
1103
+ char *const langs = eStrdup (parameter);
1104
+ enum { Add, Remove, Replace } mode = Replace;
1105
+ boolean first = TRUE;
1106
+ char *lang = langs;
1107
+ const char* prefix = "";
1108
+ verbose (" Enabled languages: ");
1109
+ while (lang != NULL)
1110
+ {
1111
+ char *const end = strchr (lang, ',');
1112
+ if (lang [0] == '+')
1113
+ {
1114
+ ++lang;
1115
+ mode = Add;
1116
+ prefix = "+ ";
1117
+ }
1118
+ else if (lang [0] == '-')
1119
+ {
1120
+ ++lang;
1121
+ mode = Remove;
1122
+ prefix = "- ";
1123
+ }
1124
+ if (mode == Replace)
1125
+ enableLanguages (FALSE);
1126
+ if (end != NULL)
1127
+ *end = '\0';
1128
+ if (lang [0] != '\0')
1129
+ {
1130
+ if (strcmp (lang, "all") == 0)
1131
+ enableLanguages ((boolean) (mode != Remove));
1132
+ else
1133
+ {
1134
+ const langType language = getNamedLanguage (lang);
1135
+ if (language == LANG_IGNORE)
1136
+ error (WARNING, "Unknown language \"%s\" in \"%s\" option", lang, option);
1137
+ else
1138
+ enableLanguage (language, (boolean) (mode != Remove));
1139
+ }
1140
+ verbose ("%s%s%s", (first ? "" : ", "), prefix, lang);
1141
+ prefix = "";
1142
+ first = FALSE;
1143
+ if (mode == Replace)
1144
+ mode = Add;
1145
+ }
1146
+ lang = (end != NULL ? end + 1 : NULL);
1147
+ }
1148
+ verbose ("\n");
1149
+ eFree (langs);
1150
+ }
1151
+
1152
+ static void processLicenseOption (
1153
+ const char *const option __unused__,
1154
+ const char *const parameter __unused__)
1155
+ {
1156
+ printProgramIdentification ();
1157
+ puts ("");
1158
+ puts (License1);
1159
+ puts (License2);
1160
+ exit (0);
1161
+ }
1162
+
1163
+ static void processListKindsOption (
1164
+ const char *const option, const char *const parameter)
1165
+ {
1166
+ if (parameter [0] == '\0' || strcasecmp (parameter, "all") == 0)
1167
+ printLanguageKinds (LANG_AUTO);
1168
+ else
1169
+ {
1170
+ langType language = getNamedLanguage (parameter);
1171
+ if (language == LANG_IGNORE)
1172
+ error (FATAL, "Unknown language \"%s\" in \"%s\" option", parameter, option);
1173
+ else
1174
+ printLanguageKinds (language);
1175
+ }
1176
+ exit (0);
1177
+ }
1178
+
1179
+ static void processListMapsOption (
1180
+ const char *const __unused__ option,
1181
+ const char *const __unused__ parameter)
1182
+ {
1183
+ if (parameter [0] == '\0' || strcasecmp (parameter, "all") == 0)
1184
+ printLanguageMaps (LANG_AUTO);
1185
+ else
1186
+ {
1187
+ langType language = getNamedLanguage (parameter);
1188
+ if (language == LANG_IGNORE)
1189
+ error (FATAL, "Unknown language \"%s\" in \"%s\" option", parameter, option);
1190
+ else
1191
+ printLanguageMaps (language);
1192
+ }
1193
+ exit (0);
1194
+ }
1195
+
1196
+ static void processListLanguagesOption (
1197
+ const char *const option __unused__,
1198
+ const char *const parameter __unused__)
1199
+ {
1200
+ printLanguageList ();
1201
+ exit (0);
1202
+ }
1203
+
1204
+ static void processOptionFile (
1205
+ const char *const option, const char *const parameter)
1206
+ {
1207
+ if (parameter [0] == '\0')
1208
+ error (WARNING, "no option file supplied for \"%s\"", option);
1209
+ else if (! parseFileOptions (parameter))
1210
+ error (FATAL | PERROR, "cannot open option file \"%s\"", parameter);
1211
+ }
1212
+
1213
+ static void processSortOption (
1214
+ const char *const option, const char *const parameter)
1215
+ {
1216
+ if (isFalse (parameter))
1217
+ Option.sorted = SO_UNSORTED;
1218
+ else if (isTrue (parameter))
1219
+ Option.sorted = SO_SORTED;
1220
+ else if (strcasecmp (parameter, "f") == 0 ||
1221
+ strcasecmp (parameter, "fold") == 0 ||
1222
+ strcasecmp (parameter, "foldcase") == 0)
1223
+ Option.sorted = SO_FOLDSORTED;
1224
+ else
1225
+ error (FATAL, "Invalid value for \"%s\" option", option);
1226
+ }
1227
+
1228
+ static void installHeaderListDefaults (void)
1229
+ {
1230
+ Option.headerExt = stringListNewFromArgv (HeaderExtensions);
1231
+ if (Option.verbose)
1232
+ {
1233
+ printf (" Setting default header extensions: ");
1234
+ stringListPrint (Option.headerExt);
1235
+ putchar ('\n');
1236
+ }
1237
+ }
1238
+
1239
+ static void processHeaderListOption (const int option, const char *parameter)
1240
+ {
1241
+ /* Check to make sure that the user did not enter "ctags -h *.c"
1242
+ * by testing to see if the list is a filename that exists.
1243
+ */
1244
+ if (doesFileExist (parameter))
1245
+ error (FATAL, "-%c: Invalid list", option);
1246
+ if (strcmp (parameter, "default") == 0)
1247
+ installHeaderListDefaults ();
1248
+ else
1249
+ {
1250
+ boolean clear = TRUE;
1251
+
1252
+ if (parameter [0] == '+')
1253
+ {
1254
+ ++parameter;
1255
+ clear = FALSE;
1256
+ }
1257
+ if (Option.headerExt == NULL)
1258
+ Option.headerExt = stringListNew ();
1259
+ verbose (" Header Extensions:\n");
1260
+ addExtensionList (Option.headerExt, parameter, clear);
1261
+ }
1262
+ }
1263
+
1264
+ /*
1265
+ * Token ignore processing
1266
+ */
1267
+
1268
+ /* Determines whether or not "name" should be ignored, per the ignore list.
1269
+ */
1270
+ extern boolean isIgnoreToken (
1271
+ const char *const name, boolean *const pIgnoreParens,
1272
+ const char **const replacement)
1273
+ {
1274
+ boolean result = FALSE;
1275
+
1276
+ if (Option.ignore != NULL)
1277
+ {
1278
+ const size_t nameLen = strlen (name);
1279
+ unsigned int i;
1280
+
1281
+ if (pIgnoreParens != NULL)
1282
+ *pIgnoreParens = FALSE;
1283
+
1284
+ for (i = 0 ; i < stringListCount (Option.ignore) ; ++i)
1285
+ {
1286
+ vString *token = stringListItem (Option.ignore, i);
1287
+
1288
+ if (strncmp (vStringValue (token), name, nameLen) == 0)
1289
+ {
1290
+ const size_t tokenLen = vStringLength (token);
1291
+
1292
+ if (nameLen == tokenLen)
1293
+ {
1294
+ result = TRUE;
1295
+ break;
1296
+ }
1297
+ else if (tokenLen == nameLen + 1 &&
1298
+ vStringChar (token, tokenLen - 1) == '+')
1299
+ {
1300
+ result = TRUE;
1301
+ if (pIgnoreParens != NULL)
1302
+ *pIgnoreParens = TRUE;
1303
+ break;
1304
+ }
1305
+ else if (vStringChar (token, nameLen) == '=')
1306
+ {
1307
+ if (replacement != NULL)
1308
+ *replacement = vStringValue (token) + nameLen + 1;
1309
+ break;
1310
+ }
1311
+ }
1312
+ }
1313
+ }
1314
+ return result;
1315
+ }
1316
+
1317
+ static void saveIgnoreToken (vString *const ignoreToken)
1318
+ {
1319
+ if (Option.ignore == NULL)
1320
+ Option.ignore = stringListNew ();
1321
+ stringListAdd (Option.ignore, ignoreToken);
1322
+ verbose (" ignore token: %s\n", vStringValue (ignoreToken));
1323
+ }
1324
+
1325
+ static void readIgnoreList (const char *const list)
1326
+ {
1327
+ char* newList = stringCopy (list);
1328
+ const char *token = strtok (newList, IGNORE_SEPARATORS);
1329
+
1330
+ while (token != NULL)
1331
+ {
1332
+ vString *const entry = vStringNewInit (token);
1333
+
1334
+ saveIgnoreToken (entry);
1335
+ token = strtok (NULL, IGNORE_SEPARATORS);
1336
+ }
1337
+ eFree (newList);
1338
+ }
1339
+
1340
+ static void addIgnoreListFromFile (const char *const fileName)
1341
+ {
1342
+ stringList* tokens = stringListNewFromFile (fileName);
1343
+ if (tokens == NULL)
1344
+ error (FATAL | PERROR, "cannot open \"%s\"", fileName);
1345
+ if (Option.ignore == NULL)
1346
+ Option.ignore = tokens;
1347
+ else
1348
+ stringListCombine (Option.ignore, tokens);
1349
+ }
1350
+
1351
+ static void processIgnoreOption (const char *const list)
1352
+ {
1353
+ if (strchr ("@./\\", list [0]) != NULL)
1354
+ {
1355
+ const char* fileName = (*list == '@') ? list + 1 : list;
1356
+ addIgnoreListFromFile (fileName);
1357
+ }
1358
+ #if defined (MSDOS) || defined (WIN32) || defined (OS2)
1359
+ else if (isalpha (list [0]) && list [1] == ':')
1360
+ addIgnoreListFromFile (list);
1361
+ #endif
1362
+ else if (strcmp (list, "-") == 0)
1363
+ {
1364
+ freeList (&Option.ignore);
1365
+ verbose (" clearing list\n");
1366
+ }
1367
+ else
1368
+ readIgnoreList (list);
1369
+ }
1370
+
1371
+ static void processVersionOption (
1372
+ const char *const option __unused__,
1373
+ const char *const parameter __unused__)
1374
+ {
1375
+ printProgramIdentification ();
1376
+ exit (0);
1377
+ }
1378
+
1379
+ /*
1380
+ * Option tables
1381
+ */
1382
+
1383
+ static parametricOption ParametricOptions [] = {
1384
+ { "etags-include", processEtagsInclude, FALSE },
1385
+ { "exclude", processExcludeOption, FALSE },
1386
+ { "excmd", processExcmdOption, FALSE },
1387
+ { "extra", processExtraTagsOption, FALSE },
1388
+ { "fields", processFieldsOption, FALSE },
1389
+ { "filter-terminator", processFilterTerminatorOption, TRUE },
1390
+ { "format", processFormatOption, TRUE },
1391
+ { "help", processHelpOption, TRUE },
1392
+ { "lang", processLanguageForceOption, FALSE },
1393
+ { "language", processLanguageForceOption, FALSE },
1394
+ { "language-force", processLanguageForceOption, FALSE },
1395
+ { "languages", processLanguagesOption, FALSE },
1396
+ { "langdef", processLanguageDefineOption, FALSE },
1397
+ { "langmap", processLanguageMapOption, FALSE },
1398
+ { "license", processLicenseOption, TRUE },
1399
+ { "list-kinds", processListKindsOption, TRUE },
1400
+ { "list-maps", processListMapsOption, TRUE },
1401
+ { "list-languages", processListLanguagesOption, TRUE },
1402
+ { "options", processOptionFile, FALSE },
1403
+ { "sort", processSortOption, TRUE },
1404
+ { "version", processVersionOption, TRUE },
1405
+ { "stdin-filename", processStdinFileName, FALSE }
1406
+ };
1407
+
1408
+ static booleanOption BooleanOptions [] = {
1409
+ { "append", &Option.append, TRUE },
1410
+ { "file-scope", &Option.include.fileScope, FALSE },
1411
+ { "file-tags", &Option.include.fileNames, FALSE },
1412
+ { "filter", &Option.filter, TRUE },
1413
+ { "if0", &Option.if0, FALSE },
1414
+ { "kind-long", &Option.kindLong, TRUE },
1415
+ { "line-directives",&Option.lineDirectives, FALSE },
1416
+ { "links", &Option.followLinks, FALSE },
1417
+ #ifdef RECURSE_SUPPORTED
1418
+ { "recurse", &Option.recurse, FALSE },
1419
+ #endif
1420
+ { "tag-relative", &Option.tagRelative, TRUE },
1421
+ { "totals", &Option.printTotals, TRUE },
1422
+ { "verbose", &Option.verbose, FALSE },
1423
+ };
1424
+
1425
+ /*
1426
+ * Generic option parsing
1427
+ */
1428
+
1429
+ static void checkOptionOrder (const char* const option)
1430
+ {
1431
+ if (NonOptionEncountered)
1432
+ error (FATAL, "-%s option may not follow a file name", option);
1433
+ }
1434
+
1435
+ static boolean processParametricOption (
1436
+ const char *const option, const char *const parameter)
1437
+ {
1438
+ const int count = sizeof (ParametricOptions) / sizeof (parametricOption);
1439
+ boolean found = FALSE;
1440
+ int i;
1441
+
1442
+ for (i = 0 ; i < count && ! found ; ++i)
1443
+ {
1444
+ parametricOption* const entry = &ParametricOptions [i];
1445
+ if (strcmp (option, entry->name) == 0)
1446
+ {
1447
+ found = TRUE;
1448
+ if (entry->initOnly)
1449
+ checkOptionOrder (option);
1450
+ (entry->handler) (option, parameter);
1451
+ }
1452
+ }
1453
+ return found;
1454
+ }
1455
+
1456
+ static boolean getBooleanOption (
1457
+ const char *const option, const char *const parameter)
1458
+ {
1459
+ boolean selection = TRUE;
1460
+
1461
+ if (parameter [0] == '\0')
1462
+ selection = TRUE;
1463
+ else if (isFalse (parameter))
1464
+ selection = FALSE;
1465
+ else if (isTrue (parameter))
1466
+ selection = TRUE;
1467
+ else
1468
+ error (FATAL, "Invalid value for \"%s\" option", option);
1469
+
1470
+ return selection;
1471
+ }
1472
+
1473
+ static boolean processBooleanOption (
1474
+ const char *const option, const char *const parameter)
1475
+ {
1476
+ const int count = sizeof (BooleanOptions) / sizeof (booleanOption);
1477
+ boolean found = FALSE;
1478
+ int i;
1479
+
1480
+ for (i = 0 ; i < count && ! found ; ++i)
1481
+ {
1482
+ booleanOption* const entry = &BooleanOptions [i];
1483
+ if (strcmp (option, entry->name) == 0)
1484
+ {
1485
+ found = TRUE;
1486
+ if (entry->initOnly)
1487
+ checkOptionOrder (option);
1488
+ *entry->pValue = getBooleanOption (option, parameter);
1489
+ }
1490
+ }
1491
+ return found;
1492
+ }
1493
+
1494
+ static void processLongOption (
1495
+ const char *const option, const char *const parameter)
1496
+ {
1497
+ Assert (parameter != NULL);
1498
+ if (parameter == NULL && parameter [0] == '\0')
1499
+ verbose (" Option: --%s\n", option);
1500
+ else
1501
+ verbose (" Option: --%s=%s\n", option, parameter);
1502
+
1503
+ if (processBooleanOption (option, parameter))
1504
+ ;
1505
+ else if (processParametricOption (option, parameter))
1506
+ ;
1507
+ else if (processKindOption (option, parameter))
1508
+ ;
1509
+ else if (processRegexOption (option, parameter))
1510
+ ;
1511
+ #ifndef RECURSE_SUPPORTED
1512
+ else if (strcmp (option, "recurse") == 0)
1513
+ error (WARNING, "%s option not supported on this host", option);
1514
+ #endif
1515
+ else
1516
+ error (FATAL, "Unknown option: --%s", option);
1517
+ }
1518
+
1519
+ static void processShortOption (
1520
+ const char *const option, const char *const parameter)
1521
+ {
1522
+ if (parameter == NULL || parameter [0] == '\0')
1523
+ verbose (" Option: -%s\n", option);
1524
+ else
1525
+ verbose (" Option: -%s %s\n", option, parameter);
1526
+
1527
+ if (isCompoundOption (*option) && (parameter == NULL || parameter [0] == '\0'))
1528
+ error (FATAL, "Missing parameter for \"%s\" option", option);
1529
+ else switch (*option)
1530
+ {
1531
+ case '?':
1532
+ processHelpOption ("?", NULL);
1533
+ exit (0);
1534
+ break;
1535
+ case 'a':
1536
+ checkOptionOrder (option);
1537
+ Option.append = TRUE;
1538
+ break;
1539
+ #ifdef DEBUG
1540
+ case 'b':
1541
+ if (atol (parameter) < 0)
1542
+ error (FATAL, "-%s: Invalid line number", option);
1543
+ Option.breakLine = atol (parameter);
1544
+ break;
1545
+ case 'D':
1546
+ Option.debugLevel = strtol (parameter, NULL, 0);
1547
+ if (debug (DEBUG_STATUS))
1548
+ Option.verbose = TRUE;
1549
+ break;
1550
+ #endif
1551
+ case 'B':
1552
+ Option.backward = TRUE;
1553
+ break;
1554
+ case 'e':
1555
+ checkOptionOrder (option);
1556
+ setEtagsMode ();
1557
+ break;
1558
+ case 'f':
1559
+ case 'o':
1560
+ checkOptionOrder (option);
1561
+ if (Option.tagFileName != NULL)
1562
+ {
1563
+ error (WARNING,
1564
+ "-%s option specified more than once, last value used",
1565
+ option);
1566
+ freeString (&Option.tagFileName);
1567
+ }
1568
+ else if (parameter [0] == '-' && parameter [1] != '\0')
1569
+ error (FATAL, "output file name may not begin with a '-'");
1570
+ Option.tagFileName = stringCopy (parameter);
1571
+ break;
1572
+ case 'F':
1573
+ Option.backward = FALSE;
1574
+ break;
1575
+ case 'h':
1576
+ processHeaderListOption (*option, parameter);
1577
+ break;
1578
+ case 'I':
1579
+ processIgnoreOption (parameter);
1580
+ break;
1581
+ case 'L':
1582
+ if (Option.fileList != NULL)
1583
+ {
1584
+ error (WARNING,
1585
+ "-%s option specified more than once, last value used",
1586
+ option);
1587
+ freeString (&Option.fileList);
1588
+ }
1589
+ Option.fileList = stringCopy (parameter);
1590
+ break;
1591
+ case 'n':
1592
+ Option.locate = EX_LINENUM;
1593
+ break;
1594
+ case 'N':
1595
+ Option.locate = EX_PATTERN;
1596
+ break;
1597
+ case 'R':
1598
+ #ifdef RECURSE_SUPPORTED
1599
+ Option.recurse = TRUE;
1600
+ #else
1601
+ error (WARNING, "-%s option not supported on this host", option);
1602
+ #endif
1603
+ break;
1604
+ case 'u':
1605
+ checkOptionOrder (option);
1606
+ Option.sorted = SO_UNSORTED;
1607
+ break;
1608
+ case 'V':
1609
+ Option.verbose = TRUE;
1610
+ break;
1611
+ case 'w':
1612
+ /* silently ignored */
1613
+ break;
1614
+ case 'x':
1615
+ checkOptionOrder (option);
1616
+ Option.xref = TRUE;
1617
+ break;
1618
+ default:
1619
+ error (FATAL, "Unknown option: -%s", option);
1620
+ break;
1621
+ }
1622
+ }
1623
+
1624
+ extern void parseOption (cookedArgs* const args)
1625
+ {
1626
+ Assert (! cArgOff (args));
1627
+ if (args->isOption)
1628
+ {
1629
+ if (args->longOption)
1630
+ processLongOption (args->item, args->parameter);
1631
+ else
1632
+ {
1633
+ const char *parameter = args->parameter;
1634
+ while (*parameter == ' ')
1635
+ ++parameter;
1636
+ processShortOption (args->item, parameter);
1637
+ }
1638
+ cArgForth (args);
1639
+ }
1640
+ }
1641
+
1642
+ extern void parseOptions (cookedArgs* const args)
1643
+ {
1644
+ NonOptionEncountered = FALSE;
1645
+ while (! cArgOff (args) && cArgIsOption (args))
1646
+ parseOption (args);
1647
+ if (! cArgOff (args) && ! cArgIsOption (args))
1648
+ NonOptionEncountered = TRUE;
1649
+ }
1650
+
1651
+ static const char *CheckFile;
1652
+ static boolean checkSameFile (const char *const fileName)
1653
+ {
1654
+ return isSameFile (CheckFile, fileName);
1655
+ }
1656
+
1657
+ static boolean parseFileOptions (const char* const fileName)
1658
+ {
1659
+ boolean fileFound = FALSE;
1660
+ const char* const format = "Considering option file %s: %s\n";
1661
+ CheckFile = fileName;
1662
+ if (stringListHasTest (OptionFiles, checkSameFile))
1663
+ verbose (format, fileName, "already considered");
1664
+ else
1665
+ {
1666
+ FILE* const fp = fopen (fileName, "r");
1667
+ if (fp == NULL)
1668
+ verbose (format, fileName, "not found");
1669
+ else
1670
+ {
1671
+ cookedArgs* const args = cArgNewFromLineFile (fp);
1672
+ vString* file = vStringNewInit (fileName);
1673
+ stringListAdd (OptionFiles, file);
1674
+ verbose (format, fileName, "reading...");
1675
+ parseOptions (args);
1676
+ if (NonOptionEncountered)
1677
+ error (WARNING, "Ignoring non-option in %s\n", fileName);
1678
+ cArgDelete (args);
1679
+ fclose (fp);
1680
+ fileFound = TRUE;
1681
+ }
1682
+ }
1683
+ return fileFound;
1684
+ }
1685
+
1686
+ /* Actions to be taken before reading any other options */
1687
+ extern void previewFirstOption (cookedArgs* const args)
1688
+ {
1689
+ while (cArgIsOption (args))
1690
+ {
1691
+ if (strcmp (args->item, "V") == 0 || strcmp (args->item, "verbose") == 0)
1692
+ parseOption (args);
1693
+ else if (strcmp (args->item, "options") == 0 &&
1694
+ strcmp (args->parameter, "NONE") == 0)
1695
+ {
1696
+ fprintf (stderr, "No options will be read from files or environment\n");
1697
+ SkipConfiguration = TRUE;
1698
+ cArgForth (args);
1699
+ }
1700
+ else
1701
+ break;
1702
+ }
1703
+ }
1704
+
1705
+ static void parseConfigurationFileOptionsInDirectoryWithLeafname (const char* directory, const char* leafname)
1706
+ {
1707
+ vString* const pathname = combinePathAndFile (directory, leafname);
1708
+ parseFileOptions (vStringValue (pathname));
1709
+ vStringDelete (pathname);
1710
+ }
1711
+
1712
+ static void parseConfigurationFileOptionsInDirectory (const char* directory)
1713
+ {
1714
+ parseConfigurationFileOptionsInDirectoryWithLeafname (directory, ".ctags");
1715
+ #ifdef MSDOS_STYLE_PATH
1716
+ parseConfigurationFileOptionsInDirectoryWithLeafname (directory, "ctags.cnf");
1717
+ #endif
1718
+ }
1719
+
1720
+ static void parseConfigurationFileOptions (void)
1721
+ {
1722
+ /* We parse .ctags on all systems, and additionally ctags.cnf on DOS. */
1723
+ const char* const home = getenv ("HOME");
1724
+ #ifdef CUSTOM_CONFIGURATION_FILE
1725
+ parseFileOptions (CUSTOM_CONFIGURATION_FILE);
1726
+ #endif
1727
+ #ifdef MSDOS_STYLE_PATH
1728
+ parseFileOptions ("/ctags.cnf");
1729
+ #endif
1730
+ parseFileOptions ("/etc/ctags.conf");
1731
+ parseFileOptions ("/usr/local/etc/ctags.conf");
1732
+ if (home != NULL)
1733
+ {
1734
+ parseConfigurationFileOptionsInDirectory (home);
1735
+ }
1736
+ else
1737
+ {
1738
+ #ifdef MSDOS_STYLE_PATH
1739
+ /*
1740
+ * Windows users don't usually set HOME.
1741
+ * The OS sets HOMEDRIVE and HOMEPATH for them.
1742
+ */
1743
+ const char* homeDrive = getenv ("HOMEDRIVE");
1744
+ const char* homePath = getenv ("HOMEPATH");
1745
+ if (homeDrive != NULL && homePath != NULL)
1746
+ {
1747
+ vString* const windowsHome = vStringNew ();
1748
+ vStringCatS (windowsHome, homeDrive);
1749
+ vStringCatS (windowsHome, homePath);
1750
+ parseConfigurationFileOptionsInDirectory (vStringValue (windowsHome));
1751
+ vStringDelete (windowsHome);
1752
+ }
1753
+ #endif
1754
+ }
1755
+ parseConfigurationFileOptionsInDirectory (".");
1756
+ }
1757
+
1758
+ static void parseEnvironmentOptions (void)
1759
+ {
1760
+ const char *envOptions = NULL;
1761
+ const char* var = NULL;
1762
+
1763
+ if (Option.etags)
1764
+ {
1765
+ var = ETAGS_ENVIRONMENT;
1766
+ envOptions = getenv (var);
1767
+ }
1768
+ if (envOptions == NULL)
1769
+ {
1770
+ var = CTAGS_ENVIRONMENT;
1771
+ envOptions = getenv (var);
1772
+ }
1773
+ if (envOptions != NULL && envOptions [0] != '\0')
1774
+ {
1775
+ cookedArgs* const args = cArgNewFromString (envOptions);
1776
+ verbose ("Reading options from $CTAGS\n");
1777
+ parseOptions (args);
1778
+ cArgDelete (args);
1779
+ if (NonOptionEncountered)
1780
+ error (WARNING, "Ignoring non-option in %s variable", var);
1781
+ }
1782
+ }
1783
+
1784
+ extern void readOptionConfiguration (void)
1785
+ {
1786
+ if (! SkipConfiguration)
1787
+ {
1788
+ parseConfigurationFileOptions ();
1789
+ parseEnvironmentOptions ();
1790
+ }
1791
+ }
1792
+
1793
+ /*
1794
+ * Option initialization
1795
+ */
1796
+
1797
+ extern void initOptions (void)
1798
+ {
1799
+ OptionFiles = stringListNew ();
1800
+ verbose ("Setting option defaults\n");
1801
+ installHeaderListDefaults ();
1802
+ verbose (" Installing default language mappings:\n");
1803
+ installLanguageMapDefaults ();
1804
+
1805
+ /* always excluded by default */
1806
+ verbose (" Installing default exclude patterns:\n");
1807
+ processExcludeOption (NULL, "{arch}");
1808
+ processExcludeOption (NULL, ".arch-ids");
1809
+ processExcludeOption (NULL, ".arch-inventory");
1810
+ processExcludeOption (NULL, "autom4te.cache");
1811
+ processExcludeOption (NULL, "BitKeeper");
1812
+ processExcludeOption (NULL, ".bzr");
1813
+ processExcludeOption (NULL, ".bzrignore");
1814
+ processExcludeOption (NULL, "CVS");
1815
+ processExcludeOption (NULL, ".cvsignore");
1816
+ processExcludeOption (NULL, "_darcs");
1817
+ processExcludeOption (NULL, ".deps");
1818
+ processExcludeOption (NULL, "EIFGEN");
1819
+ processExcludeOption (NULL, ".git");
1820
+ processExcludeOption (NULL, ".hg");
1821
+ processExcludeOption (NULL, "PENDING");
1822
+ processExcludeOption (NULL, "RCS");
1823
+ processExcludeOption (NULL, "RESYNC");
1824
+ processExcludeOption (NULL, "SCCS");
1825
+ processExcludeOption (NULL, ".svn");
1826
+ }
1827
+
1828
+ extern void freeOptionResources (void)
1829
+ {
1830
+ freeString (&Option.tagFileName);
1831
+ freeString (&Option.fileList);
1832
+ freeString (&Option.filterTerminator);
1833
+ freeString (&Option.stdinFileName);
1834
+
1835
+ freeList (&Excluded);
1836
+ freeList (&Option.ignore);
1837
+ freeList (&Option.headerExt);
1838
+ freeList (&Option.etagsInclude);
1839
+ freeList (&OptionFiles);
1840
+ }
1841
+
1842
+ /* vi:set tabstop=4 shiftwidth=4: */