Making "inline" behave like an attribute. Fixes #1
[arduino-ctags.git] / options.c
blob1bee61d6e23e33cb5a731eee9e3adb17a6292ce2
1 /*
2 * $Id: options.c 576 2007-06-30 04:16:23Z elliotth $
4 * Copyright (c) 1996-2003, Darren Hiebert
6 * This source code is released for free distribution under the terms of the
7 * GNU General Public License.
9 * This module contains functions to process command line options.
13 * INCLUDE FILES
15 #include "general.h" /* must always come first */
17 #include <stdlib.h>
18 #include <string.h>
19 #include <stdio.h>
20 #include <ctype.h> /* to declare isspace () */
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"
31 * MACROS
33 #define INVOCATION "Usage: %s [options] [file(s)]\n"
35 #define CTAGS_ENVIRONMENT "CTAGS"
36 #define ETAGS_ENVIRONMENT "ETAGS"
38 #define CTAGS_FILE "tags"
39 #define ETAGS_FILE "TAGS"
41 #ifndef ETAGS
42 # define ETAGS "etags" /* name which causes default use of to -e */
43 #endif
45 /* The following separators are permitted for list options.
47 #define EXTENSION_SEPARATOR '.'
48 #define PATTERN_START '('
49 #define PATTERN_STOP ')'
50 #define IGNORE_SEPARATORS ", \t\n"
52 #ifndef DEFAULT_FILE_FORMAT
53 # define DEFAULT_FILE_FORMAT 2
54 #endif
56 #if defined (HAVE_OPENDIR) || defined (HAVE_FINDFIRST) || defined (HAVE__FINDFIRST) || defined (AMIGA)
57 # define RECURSE_SUPPORTED
58 #endif
60 #define isCompoundOption(c) (boolean) (strchr ("fohiILpDb", (c)) != NULL)
63 * Data declarations
66 enum eOptionLimits {
67 MaxHeaderExtensions = 100, /* maximum number of extensions in -h option */
68 MaxSupportedTagFormat = 2
71 typedef struct sOptionDescription {
72 int usedByEtags;
73 const char *description;
74 } optionDescription;
76 typedef void (*parametricOptionHandler) (const char *const option, const char *const parameter);
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;
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;
91 * DATA DEFINITIONS
94 static boolean NonOptionEncountered;
95 static stringList *OptionFiles;
96 static stringList* Excluded;
97 static boolean FilesRequired = TRUE;
98 static boolean SkipConfiguration;
100 static const char *const HeaderExtensions [] = {
101 "h", "H", "hh", "hpp", "hxx", "h++", "inc", "def", NULL
104 optionValues Option = {
106 FALSE, /* --extra=f */
107 FALSE, /* --extra=q */
108 TRUE, /* --file-scope */
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 FALSE, /* -fields=T */
123 TRUE /* -fields=t */
125 NULL, /* -I */
126 FALSE, /* -a */
127 FALSE, /* -B */
128 FALSE, /* -e */
129 #ifdef MACROS_USE_PATTERNS
130 EX_PATTERN, /* -n, --excmd */
131 #else
132 EX_MIX, /* -n, --excmd */
133 #endif
134 FALSE, /* -R */
135 SO_SORTED, /* -u, --sort */
136 FALSE, /* -V */
137 FALSE, /* -x */
138 NULL, /* -L */
139 NULL, /* -o */
140 NULL, /* -h */
141 NULL, /* --etags-include */
142 DEFAULT_FILE_FORMAT,/* --format */
143 FALSE, /* --if0 */
144 FALSE, /* --kind-long */
145 LANG_AUTO, /* --lang */
146 TRUE, /* --links */
147 FALSE, /* --filter */
148 NULL, /* --filter-terminator */
149 FALSE, /* --tag-relative */
150 FALSE, /* --totals */
151 FALSE, /* --line-directives */
152 #ifdef DEBUG
153 0, 0 /* -D, -b */
154 #endif
158 - Locally used only
161 static optionDescription LongOptionDescription [] = {
162 {1," -a Append the tags to an existing tag file."},
163 #ifdef DEBUG
164 {1," -b <line>"},
165 {1," Set break line."},
166 #endif
167 {0," -B Use backward searching patterns (?...?)."},
168 #ifdef DEBUG
169 {1," -D <level>"},
170 {1," Set debug level."},
171 #endif
172 {0," -e Output tag file for use with Emacs."},
173 {1," -f <name>"},
174 {1," Write tags to specified file. Value of \"-\" writes tags to stdout"},
175 {1," [\"tags\"; or \"TAGS\" when -e supplied]."},
176 {0," -F Use forward searching patterns (/.../) (default)."},
177 {1," -h <list>"},
178 {1," Specify list of file extensions to be treated as include files."},
179 {1," [\".h.H.hh.hpp.hxx.h++\"]."},
180 {1," -I <list|@file>"},
181 {1," A list of tokens to be specially handled is read from either the"},
182 {1," command line or the specified file."},
183 {1," -L <file>"},
184 {1," A list of source file names are read from the specified file."},
185 {1," If specified as \"-\", then standard input is read."},
186 {0," -n Equivalent to --excmd=number."},
187 {0," -N Equivalent to --excmd=pattern."},
188 {1," -o Alternative for -f."},
189 #ifdef RECURSE_SUPPORTED
190 {1," -R Equivalent to --recurse."},
191 #else
192 {1," -R Not supported on this platform."},
193 #endif
194 {0," -u Equivalent to --sort=no."},
195 {1," -V Equivalent to --verbose."},
196 {1," -x Print a tabular cross reference file to standard output."},
197 {1," --append=[yes|no]"},
198 {1," Should tags should be appended to existing tag file [no]?"},
199 {1," --etags-include=file"},
200 {1," Include reference to 'file' in Emacs-style tag file (requires -e)."},
201 {1," --exclude=pattern"},
202 {1," Exclude files and directories matching 'pattern'."},
203 {0," --excmd=number|pattern|mix"},
204 #ifdef MACROS_USE_PATTERNS
205 {0," Uses the specified type of EX command to locate tags [pattern]."},
206 #else
207 {0," Uses the specified type of EX command to locate tags [mix]."},
208 #endif
209 {1," --extra=[+|-]flags"},
210 {1," Include extra tag entries for selected information (flags: \"fq\")."},
211 {1," --fields=[+|-]flags"},
212 {1," Include selected extension fields (flags: \"afmikKlnsStTz\") [fks]."},
213 {1," --file-scope=[yes|no]"},
214 {1," Should tags scoped only for a single file (e.g. \"static\" tags"},
215 {1," be included in the output [yes]?"},
216 {1," --filter=[yes|no]"},
217 {1," Behave as a filter, reading file names from standard input and"},
218 {1," writing tags to standard output [no]."},
219 {1," --filter-terminator=string"},
220 {1," Specify string to print to stdout following the tags for each file"},
221 {1," parsed when --filter is enabled."},
222 {0," --format=level"},
223 #if DEFAULT_FILE_FORMAT == 1
224 {0," Force output of specified tag file format [1]."},
225 #else
226 {0," Force output of specified tag file format [2]."},
227 #endif
228 {1," --help"},
229 {1," Print this option summary."},
230 {1," --if0=[yes|no]"},
231 {1," Should C code within #if 0 conditional branches be parsed [no]?"},
232 {1," --<LANG>-kinds=[+|-]kinds"},
233 {1," Enable/disable tag kinds for language <LANG>."},
234 {1," --langdef=name"},
235 {1," Define a new language to be parsed with regular expressions."},
236 {1," --langmap=map(s)"},
237 {1," Override default mapping of language to source file extension."},
238 {1," --language-force=language"},
239 {1," Force all files to be interpreted using specified language."},
240 {1," --languages=[+|-]list"},
241 {1," Restrict files scanned for tags to those mapped to langauges"},
242 {1," specified in the comma-separated 'list'. The list can contain any"},
243 {1," built-in or user-defined language [all]."},
244 {1," --license"},
245 {1," Print details of software license."},
246 {0," --line-directives=[yes|no]"},
247 {0," Should #line directives be processed [no]?"},
248 {1," --links=[yes|no]"},
249 {1," Indicate whether symbolic links should be followed [yes]."},
250 {1," --list-kinds=[language|all]"},
251 {1," Output a list of all tag kinds for specified language or all."},
252 {1," --list-languages"},
253 {1," Output list of supported languages."},
254 {1," --list-maps=[language|all]"},
255 {1," Output list of language mappings."},
256 {1," --options=file"},
257 {1," Specify file from which command line options should be read."},
258 {1," --recurse=[yes|no]"},
259 #ifdef RECURSE_SUPPORTED
260 {1," Recurse into directories supplied on command line [no]."},
261 #else
262 {1," Not supported on this platform."},
263 #endif
264 #ifdef HAVE_REGEX
265 {1," --regex-<LANG>=/line_pattern/name_pattern/[flags]"},
266 {1," Define regular expression for locating tags in specific language."},
267 #endif
268 {0," --sort=[yes|no|foldcase]"},
269 {0," Should tags be sorted (optionally ignoring case) [yes]?."},
270 {0," --tag-relative=[yes|no]"},
271 {0," Should paths be relative to location of tag file [no; yes when -e]?"},
272 {1," --totals=[yes|no]"},
273 {1," Print statistics about source and tag files [no]."},
274 {1," --verbose=[yes|no]"},
275 {1," Enable verbose messages describing actions on each source file."},
276 {1," --version"},
277 {1," Print version identifier to standard output."},
278 {1, NULL}
281 static const char* const License1 =
282 "This program is free software; you can redistribute it and/or\n"
283 "modify it under the terms of the GNU General Public License\n"
284 "as published by the Free Software Foundation; either version 2\n"
285 "of the License, or (at your option) any later version.\n"
286 "\n";
287 static const char* const License2 =
288 "This program is distributed in the hope that it will be useful,\n"
289 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
290 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
291 "GNU General Public License for more details.\n"
292 "\n"
293 "You should have received a copy of the GNU General Public License\n"
294 "along with this program; if not, write to the Free Software\n"
295 "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n";
297 /* Contains a set of strings describing the set of "features" compiled into
298 * the code.
300 static const char *const Features [] = {
301 #ifdef WIN32
302 "win32",
303 #endif
304 #ifdef DJGPP
305 "msdos_32",
306 #else
307 # ifdef MSDOS
308 "msdos_16",
309 # endif
310 #endif
311 #ifdef OS2
312 "os2",
313 #endif
314 #ifdef AMIGA
315 "amiga",
316 #endif
317 #ifdef VMS
318 "vms",
319 #endif
320 #ifdef HAVE_FNMATCH
321 "wildcards",
322 #endif
323 #ifdef HAVE_REGEX
324 "regex",
325 #endif
326 #ifndef EXTERNAL_SORT
327 "internal-sort",
328 #endif
329 #ifdef CUSTOM_CONFIGURATION_FILE
330 "custom-conf",
331 #endif
332 #if (defined (MSDOS) || defined (WIN32) || defined (OS2)) && defined (UNIX_PATH_SEPARATOR)
333 "unix-path-separator",
334 #endif
335 #ifdef DEBUG
336 "debug",
337 #endif
338 NULL
342 * FUNCTION PROTOTYPES
344 static boolean parseFileOptions (const char *const fileName);
347 * FUNCTION DEFINITIONS
350 extern void verbose (const char *const format, ...)
352 if (Option.verbose)
354 va_list ap;
355 va_start (ap, format);
356 vprintf (format, ap);
357 va_end (ap);
361 static char *stringCopy (const char *const string)
363 char* result = NULL;
364 if (string != NULL)
365 result = eStrdup (string);
366 return result;
369 static void freeString (char **const pString)
371 if (*pString != NULL)
373 eFree (*pString);
374 *pString = NULL;
378 extern void freeList (stringList** const pList)
380 if (*pList != NULL)
382 stringListDelete (*pList);
383 *pList = NULL;
387 extern void setDefaultTagFileName (void)
389 if (Option.tagFileName != NULL)
390 ; /* accept given name */
391 else if (Option.etags)
392 Option.tagFileName = stringCopy (ETAGS_FILE);
393 else
394 Option.tagFileName = stringCopy (CTAGS_FILE);
397 extern boolean filesRequired (void)
399 boolean result = FilesRequired;
400 if (Option.recurse)
401 result = FALSE;
402 return result;
405 extern void checkOptions (void)
407 const char* notice;
408 if (Option.xref)
410 notice = "xref output";
411 if (Option.include.fileNames)
413 error (WARNING, "%s disables file name tags", notice);
414 Option.include.fileNames = FALSE;
417 if (Option.append)
419 notice = "append mode is not compatible with";
420 if (isDestinationStdout ())
421 error (FATAL, "%s tags to stdout", notice);
423 if (Option.filter)
425 notice = "filter mode";
426 if (Option.printTotals)
428 error (WARNING, "%s disables totals", notice);
429 Option.printTotals = FALSE;
431 if (Option.tagFileName != NULL)
432 error (WARNING, "%s ignores output tag file name", notice);
436 static void setEtagsMode (void)
438 Option.etags = TRUE;
439 Option.sorted = SO_UNSORTED;
440 Option.lineDirectives = FALSE;
441 Option.tagRelative = TRUE;
444 extern void testEtagsInvocation (void)
446 char* const execName = eStrdup (getExecutableName ());
447 char* const etags = eStrdup (ETAGS);
448 #ifdef CASE_INSENSITIVE_FILENAMES
449 toLowerString (execName);
450 toLowerString (etags);
451 #endif
452 if (strstr (execName, etags) != NULL)
454 verbose ("Running in etags mode\n");
455 setEtagsMode ();
457 eFree (execName);
458 eFree (etags);
462 * Cooked argument parsing
465 static void parseShortOption (cookedArgs *const args)
467 args->simple [0] = *args->shortOptions++;
468 args->simple [1] = '\0';
469 args->item = args->simple;
470 if (! isCompoundOption (*args->simple))
471 args->parameter = "";
472 else if (*args->shortOptions == '\0')
474 argForth (args->args);
475 if (argOff (args->args))
476 args->parameter = NULL;
477 else
478 args->parameter = argItem (args->args);
479 args->shortOptions = NULL;
481 else
483 args->parameter = args->shortOptions;
484 args->shortOptions = NULL;
488 static void parseLongOption (cookedArgs *const args, const char *item)
490 const char* const equal = strchr (item, '=');
491 if (equal == NULL)
493 args->item = eStrdup (item); /* FIXME: memory leak. */
494 args->parameter = "";
496 else
498 const size_t length = equal - item;
499 args->item = xMalloc (length + 1, char); /* FIXME: memory leak. */
500 strncpy (args->item, item, length);
501 args->item [length] = '\0';
502 args->parameter = equal + 1;
504 Assert (args->item != NULL);
505 Assert (args->parameter != NULL);
508 static void cArgRead (cookedArgs *const current)
510 char* item;
512 Assert (current != NULL);
513 if (! argOff (current->args))
515 item = argItem (current->args);
516 current->shortOptions = NULL;
517 Assert (item != NULL);
518 if (strncmp (item, "--", (size_t) 2) == 0)
520 current->isOption = TRUE;
521 current->longOption = TRUE;
522 parseLongOption (current, item + 2);
523 Assert (current->item != NULL);
524 Assert (current->parameter != NULL);
526 else if (*item == '-')
528 current->isOption = TRUE;
529 current->longOption = FALSE;
530 current->shortOptions = item + 1;
531 parseShortOption (current);
533 else
535 current->isOption = FALSE;
536 current->longOption = FALSE;
537 current->item = item;
538 current->parameter = NULL;
543 extern cookedArgs* cArgNewFromString (const char* string)
545 cookedArgs* const result = xMalloc (1, cookedArgs);
546 memset (result, 0, sizeof (cookedArgs));
547 result->args = argNewFromString (string);
548 cArgRead (result);
549 return result;
552 extern cookedArgs* cArgNewFromArgv (char* const* const argv)
554 cookedArgs* const result = xMalloc (1, cookedArgs);
555 memset (result, 0, sizeof (cookedArgs));
556 result->args = argNewFromArgv (argv);
557 cArgRead (result);
558 return result;
561 extern cookedArgs* cArgNewFromFile (FILE* const fp)
563 cookedArgs* const result = xMalloc (1, cookedArgs);
564 memset (result, 0, sizeof (cookedArgs));
565 result->args = argNewFromFile (fp);
566 cArgRead (result);
567 return result;
570 extern cookedArgs* cArgNewFromLineFile (FILE* const fp)
572 cookedArgs* const result = xMalloc (1, cookedArgs);
573 memset (result, 0, sizeof (cookedArgs));
574 result->args = argNewFromLineFile (fp);
575 cArgRead (result);
576 return result;
579 extern void cArgDelete (cookedArgs* const current)
581 Assert (current != NULL);
582 argDelete (current->args);
583 memset (current, 0, sizeof (cookedArgs));
584 eFree (current);
587 static boolean cArgOptionPending (cookedArgs* const current)
589 boolean result = FALSE;
590 if (current->shortOptions != NULL)
591 if (*current->shortOptions != '\0')
592 result = TRUE;
593 return result;
596 extern boolean cArgOff (cookedArgs* const current)
598 Assert (current != NULL);
599 return (boolean) (argOff (current->args) && ! cArgOptionPending (current));
602 extern boolean cArgIsOption (cookedArgs* const current)
604 Assert (current != NULL);
605 return current->isOption;
608 extern const char* cArgItem (cookedArgs* const current)
610 Assert (current != NULL);
611 return current->item;
614 extern void cArgForth (cookedArgs* const current)
616 Assert (current != NULL);
617 Assert (! cArgOff (current));
618 if (cArgOptionPending (current))
619 parseShortOption (current);
620 else
622 Assert (! argOff (current->args));
623 argForth (current->args);
624 if (! argOff (current->args))
625 cArgRead (current);
626 else
628 current->isOption = FALSE;
629 current->longOption = FALSE;
630 current->shortOptions = NULL;
631 current->item = NULL;
632 current->parameter = NULL;
638 * File extension and language mapping
641 static void addExtensionList (
642 stringList *const slist, const char *const elist, const boolean clear)
644 char *const extensionList = eStrdup (elist);
645 const char *extension = NULL;
646 boolean first = TRUE;
648 if (clear)
650 verbose (" clearing\n");
651 stringListClear (slist);
653 verbose (" adding: ");
654 if (elist != NULL && *elist != '\0')
656 extension = extensionList;
657 if (elist [0] == EXTENSION_SEPARATOR)
658 ++extension;
660 while (extension != NULL)
662 char *separator = strchr (extension, EXTENSION_SEPARATOR);
663 if (separator != NULL)
664 *separator = '\0';
665 verbose ("%s%s", first ? "" : ", ",
666 *extension == '\0' ? "(NONE)" : extension);
667 stringListAdd (slist, vStringNewInit (extension));
668 first = FALSE;
669 if (separator == NULL)
670 extension = NULL;
671 else
672 extension = separator + 1;
674 if (Option.verbose)
676 printf ("\n now: ");
677 stringListPrint (slist);
678 putchar ('\n');
680 eFree (extensionList);
683 static boolean isFalse (const char *parameter)
685 return (boolean) (
686 strcasecmp (parameter, "0" ) == 0 ||
687 strcasecmp (parameter, "n" ) == 0 ||
688 strcasecmp (parameter, "no" ) == 0 ||
689 strcasecmp (parameter, "off") == 0);
692 static boolean isTrue (const char *parameter)
694 return (boolean) (
695 strcasecmp (parameter, "1" ) == 0 ||
696 strcasecmp (parameter, "y" ) == 0 ||
697 strcasecmp (parameter, "yes") == 0 ||
698 strcasecmp (parameter, "on" ) == 0);
701 /* Determines whether the specified file name is considered to be a header
702 * file for the purposes of determining whether enclosed tags are global or
703 * static.
705 extern boolean isIncludeFile (const char *const fileName)
707 boolean result = FALSE;
708 const char *const extension = fileExtension (fileName);
709 if (Option.headerExt != NULL)
710 result = stringListExtensionMatched (Option.headerExt, extension);
711 return result;
715 * Specific option processing
718 static void processEtagsInclude (
719 const char *const option, const char *const parameter)
721 if (! Option.etags)
722 error (FATAL, "Etags must be enabled to use \"%s\" option", option);
723 else
725 vString *const file = vStringNewInit (parameter);
726 if (Option.etagsInclude == NULL)
727 Option.etagsInclude = stringListNew ();
728 stringListAdd (Option.etagsInclude, file);
729 FilesRequired = FALSE;
733 static void processExcludeOption (
734 const char *const option __unused__, const char *const parameter)
736 const char *const fileName = parameter + 1;
737 if (parameter [0] == '\0')
738 freeList (&Excluded);
739 else if (parameter [0] == '@')
741 stringList* const sl = stringListNewFromFile (fileName);
742 if (sl == NULL)
743 error (FATAL | PERROR, "cannot open \"%s\"", fileName);
744 if (Excluded == NULL)
745 Excluded = sl;
746 else
747 stringListCombine (Excluded, sl);
748 verbose (" adding exclude patterns from %s\n", fileName);
750 else
752 vString *const item = vStringNewInit (parameter);
753 if (Excluded == NULL)
754 Excluded = stringListNew ();
755 stringListAdd (Excluded, item);
756 verbose (" adding exclude pattern: %s\n", parameter);
760 extern boolean isExcludedFile (const char* const name)
762 const char* base = baseFilename (name);
763 boolean result = FALSE;
764 if (Excluded != NULL)
766 result = stringListFileMatched (Excluded, base);
767 if (! result && name != base)
768 result = stringListFileMatched (Excluded, name);
770 #ifdef AMIGA
771 /* not a good solution, but the only one which works often */
772 if (! result)
773 result = (boolean) (strcmp (name, TagFile.name) == 0);
774 #endif
775 return result;
778 static void processExcmdOption (
779 const char *const option, const char *const parameter)
781 switch (*parameter)
783 case 'm': Option.locate = EX_MIX; break;
784 case 'n': Option.locate = EX_LINENUM; break;
785 case 'p': Option.locate = EX_PATTERN; break;
786 default:
787 error (FATAL, "Invalid value for \"%s\" option", option);
788 break;
792 static void processExtraTagsOption (
793 const char *const option, const char *const parameter)
795 struct sInclude *const inc = &Option.include;
796 const char *p = parameter;
797 boolean mode = TRUE;
798 int c;
800 if (*p != '+' && *p != '-')
802 inc->fileNames = FALSE;
803 inc->qualifiedTags = FALSE;
804 #if 0
805 inc->fileScope = FALSE;
806 #endif
808 while ((c = *p++) != '\0') switch (c)
810 case '+': mode = TRUE; break;
811 case '-': mode = FALSE; break;
813 case 'f': inc->fileNames = mode; break;
814 case 'q': inc->qualifiedTags = mode; break;
815 #if 0
816 case 'F': inc->fileScope = mode; break;
817 #endif
819 default: error(WARNING, "Unsupported parameter '%c' for \"%s\" option",
820 c, option);
821 break;
825 static void processFieldsOption (
826 const char *const option, const char *const parameter)
828 struct sExtFields *field = &Option.extensionFields;
829 const char *p = parameter;
830 boolean mode = TRUE;
831 int c;
833 if (*p != '+' && *p != '-')
835 field->access = FALSE;
836 field->fileScope = FALSE;
837 field->implementation = FALSE;
838 field->inheritance = FALSE;
839 field->kind = FALSE;
840 field->kindKey = FALSE;
841 field->kindLong = FALSE;
842 field->language = FALSE;
843 field->scope = FALSE;
844 field->typeRef = FALSE;
846 while ((c = *p++) != '\0') switch (c)
848 case '+': mode = TRUE; break;
849 case '-': mode = FALSE; break;
851 case 'a': field->access = mode; break;
852 case 'f': field->fileScope = mode; break;
853 case 'm': field->implementation = mode; break;
854 case 'i': field->inheritance = mode; break;
855 case 'k': field->kind = mode; break;
856 case 'K': field->kindLong = mode; break;
857 case 'l': field->language = mode; break;
858 case 'n': field->lineNumber = mode; break;
859 case 's': field->scope = mode; break;
860 case 'S': field->signature = mode; break;
861 case 'z': field->kindKey = mode; break;
862 case 't': field->typeRef = mode; break;
863 case 'T': field->returnType = mode; break;
865 default: error(WARNING, "Unsupported parameter '%c' for \"%s\" option",
866 c, option);
867 break;
871 static void processFilterTerminatorOption (
872 const char *const option __unused__, const char *const parameter)
874 freeString (&Option.filterTerminator);
875 Option.filterTerminator = stringCopy (parameter);
878 static void processFormatOption (
879 const char *const option, const char *const parameter)
881 unsigned int format;
883 if (sscanf (parameter, "%u", &format) < 1)
884 error (FATAL, "Invalid value for \"%s\" option",option);
885 else if (format <= (unsigned int) MaxSupportedTagFormat)
886 Option.tagFileFormat = format;
887 else
888 error (FATAL, "Unsupported value for \"%s\" option", option);
891 static void printInvocationDescription (void)
893 printf (INVOCATION, getExecutableName ());
896 static void printOptionDescriptions (const optionDescription *const optDesc)
898 int i;
899 for (i = 0 ; optDesc [i].description != NULL ; ++i)
901 if (! Option.etags || optDesc [i].usedByEtags)
902 puts (optDesc [i].description);
906 static void printFeatureList (void)
908 int i;
910 for (i = 0 ; Features [i] != NULL ; ++i)
912 if (i == 0)
913 printf (" Optional compiled features: ");
914 printf ("%s+%s", (i>0 ? ", " : ""), Features [i]);
915 #ifdef CUSTOM_CONFIGURATION_FILE
916 if (strcmp (Features [i], "custom-conf") == 0)
917 printf ("=%s", CUSTOM_CONFIGURATION_FILE);
918 #endif
920 if (i > 0)
921 putchar ('\n');
924 static void printProgramIdentification (void)
926 printf ("%s %s, %s %s\n",
927 PROGRAM_NAME, PROGRAM_VERSION,
928 PROGRAM_COPYRIGHT, AUTHOR_NAME);
929 printf (" Compiled: %s, %s\n", __DATE__, __TIME__);
930 printf (" Addresses: <%s>, %s\n", AUTHOR_EMAIL, PROGRAM_URL);
931 printFeatureList ();
934 static void processHelpOption (
935 const char *const option __unused__,
936 const char *const parameter __unused__)
938 printProgramIdentification ();
939 putchar ('\n');
940 printInvocationDescription ();
941 putchar ('\n');
942 printOptionDescriptions (LongOptionDescription);
943 exit (0);
946 static void processLanguageForceOption (
947 const char *const option, const char *const parameter)
949 langType language;
950 if (strcasecmp (parameter, "auto") == 0)
951 language = LANG_AUTO;
952 else
953 language = getNamedLanguage (parameter);
955 if (strcmp (option, "lang") == 0 || strcmp (option, "language") == 0)
956 error (WARNING,
957 "\"--%s\" option is obsolete; use \"--language-force\" instead",
958 option);
959 if (language == LANG_IGNORE)
960 error (FATAL, "Unknown language \"%s\" in \"%s\" option", parameter, option);
961 else
962 Option.language = language;
964 static char* skipPastMap (char* p)
966 while (*p != EXTENSION_SEPARATOR &&
967 *p != PATTERN_START && *p != ',' && *p != '\0')
968 ++p;
969 return p;
972 /* Parses the mapping beginning at `map', adds it to the language map, and
973 * returns first character past the map.
975 static char* addLanguageMap (const langType language, char* map)
977 char* p = NULL;
978 const char first = *map;
979 if (first == EXTENSION_SEPARATOR) /* extension map */
981 ++map;
982 p = skipPastMap (map);
983 if (*p == '\0')
985 verbose (" .%s", map);
986 addLanguageExtensionMap (language, map);
987 p = map + strlen (map);
989 else
991 const char separator = *p;
992 *p = '\0';
993 verbose (" .%s", map);
994 addLanguageExtensionMap (language, map);
995 *p = separator;
998 else if (first == PATTERN_START) /* pattern map */
1000 ++map;
1001 for (p = map ; *p != PATTERN_STOP && *p != '\0' ; ++p)
1003 if (*p == '\\' && *(p + 1) == PATTERN_STOP)
1004 ++p;
1006 if (*p == '\0')
1007 error (FATAL, "Unterminated file name pattern for %s language",
1008 getLanguageName (language));
1009 else
1011 *p++ = '\0';
1012 verbose (" (%s)", map);
1013 addLanguagePatternMap (language, map);
1016 else
1017 error (FATAL, "Badly formed language map for %s language",
1018 getLanguageName (language));
1019 return p;
1022 static char* processLanguageMap (char* map)
1024 char* const separator = strchr (map, ':');
1025 char* result = NULL;
1026 if (separator != NULL)
1028 langType language;
1029 char *list = separator + 1;
1030 boolean clear = FALSE;
1031 *separator = '\0';
1032 language = getNamedLanguage (map);
1033 if (language != LANG_IGNORE)
1035 const char *const deflt = "default";
1036 char* p;
1037 if (*list == '+')
1038 ++list;
1039 else
1040 clear = TRUE;
1041 for (p = list ; *p != ',' && *p != '\0' ; ++p) /*no-op*/ ;
1042 if ((size_t) (p - list) == strlen (deflt) &&
1043 strncasecmp (list, deflt, p - list) == 0)
1045 verbose (" Restoring default %s language map: ", getLanguageName (language));
1046 installLanguageMapDefault (language);
1047 list = p;
1049 else
1051 if (clear)
1053 verbose (" Setting %s language map:", getLanguageName (language));
1054 clearLanguageMap (language);
1056 else
1057 verbose (" Adding to %s language map:", getLanguageName (language));
1058 while (list != NULL && *list != '\0' && *list != ',')
1059 list = addLanguageMap (language, list);
1060 verbose ("\n");
1062 if (list != NULL && *list == ',')
1063 ++list;
1064 result = list;
1067 return result;
1070 static void processLanguageMapOption (
1071 const char *const option, const char *const parameter)
1073 char *const maps = eStrdup (parameter);
1074 char *map = maps;
1076 if (strcmp (parameter, "default") == 0)
1078 verbose (" Restoring default language maps:\n");
1079 installLanguageMapDefaults ();
1081 else while (map != NULL && *map != '\0')
1083 char* const next = processLanguageMap (map);
1084 if (next == NULL)
1085 error (WARNING, "Unknown language \"%s\" in \"%s\" option", parameter, option);
1086 map = next;
1088 eFree (maps);
1091 static void processLanguagesOption (
1092 const char *const option, const char *const parameter)
1094 char *const langs = eStrdup (parameter);
1095 enum { Add, Remove, Replace } mode = Replace;
1096 boolean first = TRUE;
1097 char *lang = langs;
1098 const char* prefix = "";
1099 verbose (" Enabled languages: ");
1100 while (lang != NULL)
1102 char *const end = strchr (lang, ',');
1103 if (lang [0] == '+')
1105 ++lang;
1106 mode = Add;
1107 prefix = "+ ";
1109 else if (lang [0] == '-')
1111 ++lang;
1112 mode = Remove;
1113 prefix = "- ";
1115 if (mode == Replace)
1116 enableLanguages (FALSE);
1117 if (end != NULL)
1118 *end = '\0';
1119 if (lang [0] != '\0')
1121 if (strcmp (lang, "all") == 0)
1122 enableLanguages ((boolean) (mode != Remove));
1123 else
1125 const langType language = getNamedLanguage (lang);
1126 if (language == LANG_IGNORE)
1127 error (WARNING, "Unknown language \"%s\" in \"%s\" option", lang, option);
1128 else
1129 enableLanguage (language, (boolean) (mode != Remove));
1131 verbose ("%s%s%s", (first ? "" : ", "), prefix, lang);
1132 prefix = "";
1133 first = FALSE;
1134 if (mode == Replace)
1135 mode = Add;
1137 lang = (end != NULL ? end + 1 : NULL);
1139 verbose ("\n");
1140 eFree (langs);
1143 static void processLicenseOption (
1144 const char *const option __unused__,
1145 const char *const parameter __unused__)
1147 printProgramIdentification ();
1148 puts ("");
1149 puts (License1);
1150 puts (License2);
1151 exit (0);
1154 static void processListKindsOption (
1155 const char *const option, const char *const parameter)
1157 if (parameter [0] == '\0' || strcasecmp (parameter, "all") == 0)
1158 printLanguageKinds (LANG_AUTO);
1159 else
1161 langType language = getNamedLanguage (parameter);
1162 if (language == LANG_IGNORE)
1163 error (FATAL, "Unknown language \"%s\" in \"%s\" option", parameter, option);
1164 else
1165 printLanguageKinds (language);
1167 exit (0);
1170 static void processListMapsOption (
1171 const char *const __unused__ option,
1172 const char *const __unused__ parameter)
1174 if (parameter [0] == '\0' || strcasecmp (parameter, "all") == 0)
1175 printLanguageMaps (LANG_AUTO);
1176 else
1178 langType language = getNamedLanguage (parameter);
1179 if (language == LANG_IGNORE)
1180 error (FATAL, "Unknown language \"%s\" in \"%s\" option", parameter, option);
1181 else
1182 printLanguageMaps (language);
1184 exit (0);
1187 static void processListLanguagesOption (
1188 const char *const option __unused__,
1189 const char *const parameter __unused__)
1191 printLanguageList ();
1192 exit (0);
1195 static void processOptionFile (
1196 const char *const option, const char *const parameter)
1198 if (parameter [0] == '\0')
1199 error (WARNING, "no option file supplied for \"%s\"", option);
1200 else if (! parseFileOptions (parameter))
1201 error (FATAL | PERROR, "cannot open option file \"%s\"", parameter);
1204 static void processSortOption (
1205 const char *const option, const char *const parameter)
1207 if (isFalse (parameter))
1208 Option.sorted = SO_UNSORTED;
1209 else if (isTrue (parameter))
1210 Option.sorted = SO_SORTED;
1211 else if (strcasecmp (parameter, "f") == 0 ||
1212 strcasecmp (parameter, "fold") == 0 ||
1213 strcasecmp (parameter, "foldcase") == 0)
1214 Option.sorted = SO_FOLDSORTED;
1215 else
1216 error (FATAL, "Invalid value for \"%s\" option", option);
1219 static void installHeaderListDefaults (void)
1221 Option.headerExt = stringListNewFromArgv (HeaderExtensions);
1222 if (Option.verbose)
1224 printf (" Setting default header extensions: ");
1225 stringListPrint (Option.headerExt);
1226 putchar ('\n');
1230 static void processHeaderListOption (const int option, const char *parameter)
1232 /* Check to make sure that the user did not enter "ctags -h *.c"
1233 * by testing to see if the list is a filename that exists.
1235 if (doesFileExist (parameter))
1236 error (FATAL, "-%c: Invalid list", option);
1237 if (strcmp (parameter, "default") == 0)
1238 installHeaderListDefaults ();
1239 else
1241 boolean clear = TRUE;
1243 if (parameter [0] == '+')
1245 ++parameter;
1246 clear = FALSE;
1248 if (Option.headerExt == NULL)
1249 Option.headerExt = stringListNew ();
1250 verbose (" Header Extensions:\n");
1251 addExtensionList (Option.headerExt, parameter, clear);
1256 * Token ignore processing
1259 /* Determines whether or not "name" should be ignored, per the ignore list.
1261 extern boolean isIgnoreToken (
1262 const char *const name, boolean *const pIgnoreParens,
1263 const char **const replacement)
1265 boolean result = FALSE;
1267 if (Option.ignore != NULL)
1269 const size_t nameLen = strlen (name);
1270 unsigned int i;
1272 if (pIgnoreParens != NULL)
1273 *pIgnoreParens = FALSE;
1275 for (i = 0 ; i < stringListCount (Option.ignore) ; ++i)
1277 vString *token = stringListItem (Option.ignore, i);
1279 if (strncmp (vStringValue (token), name, nameLen) == 0)
1281 const size_t tokenLen = vStringLength (token);
1283 if (nameLen == tokenLen)
1285 result = TRUE;
1286 break;
1288 else if (tokenLen == nameLen + 1 &&
1289 vStringChar (token, tokenLen - 1) == '+')
1291 result = TRUE;
1292 if (pIgnoreParens != NULL)
1293 *pIgnoreParens = TRUE;
1294 break;
1296 else if (vStringChar (token, nameLen) == '=')
1298 if (replacement != NULL)
1299 *replacement = vStringValue (token) + nameLen + 1;
1300 break;
1305 return result;
1308 static void saveIgnoreToken (vString *const ignoreToken)
1310 if (Option.ignore == NULL)
1311 Option.ignore = stringListNew ();
1312 stringListAdd (Option.ignore, ignoreToken);
1313 verbose (" ignore token: %s\n", vStringValue (ignoreToken));
1316 static void readIgnoreList (const char *const list)
1318 char* newList = stringCopy (list);
1319 const char *token = strtok (newList, IGNORE_SEPARATORS);
1321 while (token != NULL)
1323 vString *const entry = vStringNewInit (token);
1325 saveIgnoreToken (entry);
1326 token = strtok (NULL, IGNORE_SEPARATORS);
1328 eFree (newList);
1331 static void addIgnoreListFromFile (const char *const fileName)
1333 stringList* tokens = stringListNewFromFile (fileName);
1334 if (tokens == NULL)
1335 error (FATAL | PERROR, "cannot open \"%s\"", fileName);
1336 if (Option.ignore == NULL)
1337 Option.ignore = tokens;
1338 else
1339 stringListCombine (Option.ignore, tokens);
1342 static void processIgnoreOption (const char *const list)
1344 if (strchr ("@./\\", list [0]) != NULL)
1346 const char* fileName = (*list == '@') ? list + 1 : list;
1347 addIgnoreListFromFile (fileName);
1349 #if defined (MSDOS) || defined (WIN32) || defined (OS2)
1350 else if (isalpha (list [0]) && list [1] == ':')
1351 addIgnoreListFromFile (list);
1352 #endif
1353 else if (strcmp (list, "-") == 0)
1355 freeList (&Option.ignore);
1356 verbose (" clearing list\n");
1358 else
1359 readIgnoreList (list);
1362 static void processVersionOption (
1363 const char *const option __unused__,
1364 const char *const parameter __unused__)
1366 printProgramIdentification ();
1367 exit (0);
1371 * Option tables
1374 static parametricOption ParametricOptions [] = {
1375 { "etags-include", processEtagsInclude, FALSE },
1376 { "exclude", processExcludeOption, FALSE },
1377 { "excmd", processExcmdOption, FALSE },
1378 { "extra", processExtraTagsOption, FALSE },
1379 { "fields", processFieldsOption, FALSE },
1380 { "filter-terminator", processFilterTerminatorOption, TRUE },
1381 { "format", processFormatOption, TRUE },
1382 { "help", processHelpOption, TRUE },
1383 { "lang", processLanguageForceOption, FALSE },
1384 { "language", processLanguageForceOption, FALSE },
1385 { "language-force", processLanguageForceOption, FALSE },
1386 { "languages", processLanguagesOption, FALSE },
1387 { "langdef", processLanguageDefineOption, FALSE },
1388 { "langmap", processLanguageMapOption, FALSE },
1389 { "license", processLicenseOption, TRUE },
1390 { "list-kinds", processListKindsOption, TRUE },
1391 { "list-maps", processListMapsOption, TRUE },
1392 { "list-languages", processListLanguagesOption, TRUE },
1393 { "options", processOptionFile, FALSE },
1394 { "sort", processSortOption, TRUE },
1395 { "version", processVersionOption, TRUE },
1398 static booleanOption BooleanOptions [] = {
1399 { "append", &Option.append, TRUE },
1400 { "file-scope", &Option.include.fileScope, FALSE },
1401 { "file-tags", &Option.include.fileNames, FALSE },
1402 { "filter", &Option.filter, TRUE },
1403 { "if0", &Option.if0, FALSE },
1404 { "kind-long", &Option.kindLong, TRUE },
1405 { "line-directives",&Option.lineDirectives, FALSE },
1406 { "links", &Option.followLinks, FALSE },
1407 #ifdef RECURSE_SUPPORTED
1408 { "recurse", &Option.recurse, FALSE },
1409 #endif
1410 { "tag-relative", &Option.tagRelative, TRUE },
1411 { "totals", &Option.printTotals, TRUE },
1412 { "verbose", &Option.verbose, FALSE },
1416 * Generic option parsing
1419 static void checkOptionOrder (const char* const option)
1421 if (NonOptionEncountered)
1422 error (FATAL, "-%s option may not follow a file name", option);
1425 static boolean processParametricOption (
1426 const char *const option, const char *const parameter)
1428 const int count = sizeof (ParametricOptions) / sizeof (parametricOption);
1429 boolean found = FALSE;
1430 int i;
1432 for (i = 0 ; i < count && ! found ; ++i)
1434 parametricOption* const entry = &ParametricOptions [i];
1435 if (strcmp (option, entry->name) == 0)
1437 found = TRUE;
1438 if (entry->initOnly)
1439 checkOptionOrder (option);
1440 (entry->handler) (option, parameter);
1443 return found;
1446 static boolean getBooleanOption (
1447 const char *const option, const char *const parameter)
1449 boolean selection = TRUE;
1451 if (parameter [0] == '\0')
1452 selection = TRUE;
1453 else if (isFalse (parameter))
1454 selection = FALSE;
1455 else if (isTrue (parameter))
1456 selection = TRUE;
1457 else
1458 error (FATAL, "Invalid value for \"%s\" option", option);
1460 return selection;
1463 static boolean processBooleanOption (
1464 const char *const option, const char *const parameter)
1466 const int count = sizeof (BooleanOptions) / sizeof (booleanOption);
1467 boolean found = FALSE;
1468 int i;
1470 for (i = 0 ; i < count && ! found ; ++i)
1472 booleanOption* const entry = &BooleanOptions [i];
1473 if (strcmp (option, entry->name) == 0)
1475 found = TRUE;
1476 if (entry->initOnly)
1477 checkOptionOrder (option);
1478 *entry->pValue = getBooleanOption (option, parameter);
1481 return found;
1484 static void processLongOption (
1485 const char *const option, const char *const parameter)
1487 Assert (parameter != NULL);
1488 if (parameter == NULL && parameter [0] == '\0')
1489 verbose (" Option: --%s\n", option);
1490 else
1491 verbose (" Option: --%s=%s\n", option, parameter);
1493 if (processBooleanOption (option, parameter))
1495 else if (processParametricOption (option, parameter))
1497 else if (processKindOption (option, parameter))
1499 else if (processRegexOption (option, parameter))
1501 #ifndef RECURSE_SUPPORTED
1502 else if (strcmp (option, "recurse") == 0)
1503 error (WARNING, "%s option not supported on this host", option);
1504 #endif
1505 else
1506 error (FATAL, "Unknown option: --%s", option);
1509 static void processShortOption (
1510 const char *const option, const char *const parameter)
1512 if (parameter == NULL || parameter [0] == '\0')
1513 verbose (" Option: -%s\n", option);
1514 else
1515 verbose (" Option: -%s %s\n", option, parameter);
1517 if (isCompoundOption (*option) && (parameter == NULL || parameter [0] == '\0'))
1518 error (FATAL, "Missing parameter for \"%s\" option", option);
1519 else switch (*option)
1521 case '?':
1522 processHelpOption ("?", NULL);
1523 exit (0);
1524 break;
1525 case 'a':
1526 checkOptionOrder (option);
1527 Option.append = TRUE;
1528 break;
1529 #ifdef DEBUG
1530 case 'b':
1531 if (atol (parameter) < 0)
1532 error (FATAL, "-%s: Invalid line number", option);
1533 Option.breakLine = atol (parameter);
1534 break;
1535 case 'D':
1536 Option.debugLevel = strtol (parameter, NULL, 0);
1537 if (debug (DEBUG_STATUS))
1538 Option.verbose = TRUE;
1539 break;
1540 #endif
1541 case 'B':
1542 Option.backward = TRUE;
1543 break;
1544 case 'e':
1545 checkOptionOrder (option);
1546 setEtagsMode ();
1547 break;
1548 case 'f':
1549 case 'o':
1550 checkOptionOrder (option);
1551 if (Option.tagFileName != NULL)
1553 error (WARNING,
1554 "-%s option specified more than once, last value used",
1555 option);
1556 freeString (&Option.tagFileName);
1558 else if (parameter [0] == '-' && parameter [1] != '\0')
1559 error (FATAL, "output file name may not begin with a '-'");
1560 Option.tagFileName = stringCopy (parameter);
1561 break;
1562 case 'F':
1563 Option.backward = FALSE;
1564 break;
1565 case 'h':
1566 processHeaderListOption (*option, parameter);
1567 break;
1568 case 'I':
1569 processIgnoreOption (parameter);
1570 break;
1571 case 'L':
1572 if (Option.fileList != NULL)
1574 error (WARNING,
1575 "-%s option specified more than once, last value used",
1576 option);
1577 freeString (&Option.fileList);
1579 Option.fileList = stringCopy (parameter);
1580 break;
1581 case 'n':
1582 Option.locate = EX_LINENUM;
1583 break;
1584 case 'N':
1585 Option.locate = EX_PATTERN;
1586 break;
1587 case 'R':
1588 #ifdef RECURSE_SUPPORTED
1589 Option.recurse = TRUE;
1590 #else
1591 error (WARNING, "-%s option not supported on this host", option);
1592 #endif
1593 break;
1594 case 'u':
1595 checkOptionOrder (option);
1596 Option.sorted = SO_UNSORTED;
1597 break;
1598 case 'V':
1599 Option.verbose = TRUE;
1600 break;
1601 case 'w':
1602 /* silently ignored */
1603 break;
1604 case 'x':
1605 checkOptionOrder (option);
1606 Option.xref = TRUE;
1607 break;
1608 default:
1609 error (FATAL, "Unknown option: -%s", option);
1610 break;
1614 extern void parseOption (cookedArgs* const args)
1616 Assert (! cArgOff (args));
1617 if (args->isOption)
1619 if (args->longOption)
1620 processLongOption (args->item, args->parameter);
1621 else
1623 const char *parameter = args->parameter;
1624 while (*parameter == ' ')
1625 ++parameter;
1626 processShortOption (args->item, parameter);
1628 cArgForth (args);
1632 extern void parseOptions (cookedArgs* const args)
1634 NonOptionEncountered = FALSE;
1635 while (! cArgOff (args) && cArgIsOption (args))
1636 parseOption (args);
1637 if (! cArgOff (args) && ! cArgIsOption (args))
1638 NonOptionEncountered = TRUE;
1641 static const char *CheckFile;
1642 static boolean checkSameFile (const char *const fileName)
1644 return isSameFile (CheckFile, fileName);
1647 static boolean parseFileOptions (const char* const fileName)
1649 boolean fileFound = FALSE;
1650 const char* const format = "Considering option file %s: %s\n";
1651 CheckFile = fileName;
1652 if (stringListHasTest (OptionFiles, checkSameFile))
1653 verbose (format, fileName, "already considered");
1654 else
1656 FILE* const fp = fopen (fileName, "r");
1657 if (fp == NULL)
1658 verbose (format, fileName, "not found");
1659 else
1661 cookedArgs* const args = cArgNewFromLineFile (fp);
1662 vString* file = vStringNewInit (fileName);
1663 stringListAdd (OptionFiles, file);
1664 verbose (format, fileName, "reading...");
1665 parseOptions (args);
1666 if (NonOptionEncountered)
1667 error (WARNING, "Ignoring non-option in %s\n", fileName);
1668 cArgDelete (args);
1669 fclose (fp);
1670 fileFound = TRUE;
1673 return fileFound;
1676 /* Actions to be taken before reading any other options */
1677 extern void previewFirstOption (cookedArgs* const args)
1679 while (cArgIsOption (args))
1681 if (strcmp (args->item, "V") == 0 || strcmp (args->item, "verbose") == 0)
1682 parseOption (args);
1683 else if (strcmp (args->item, "options") == 0 &&
1684 strcmp (args->parameter, "NONE") == 0)
1686 fprintf (stderr, "No options will be read from files or environment\n");
1687 SkipConfiguration = TRUE;
1688 cArgForth (args);
1690 else
1691 break;
1695 static void parseConfigurationFileOptionsInDirectoryWithLeafname (const char* directory, const char* leafname)
1697 vString* const pathname = combinePathAndFile (directory, leafname);
1698 parseFileOptions (vStringValue (pathname));
1699 vStringDelete (pathname);
1702 static void parseConfigurationFileOptionsInDirectory (const char* directory)
1704 parseConfigurationFileOptionsInDirectoryWithLeafname (directory, ".ctags");
1705 #ifdef MSDOS_STYLE_PATH
1706 parseConfigurationFileOptionsInDirectoryWithLeafname (directory, "ctags.cnf");
1707 #endif
1710 static void parseConfigurationFileOptions (void)
1712 /* We parse .ctags on all systems, and additionally ctags.cnf on DOS. */
1713 const char* const home = getenv ("HOME");
1714 #ifdef CUSTOM_CONFIGURATION_FILE
1715 parseFileOptions (CUSTOM_CONFIGURATION_FILE);
1716 #endif
1717 #ifdef MSDOS_STYLE_PATH
1718 parseFileOptions ("/ctags.cnf");
1719 #endif
1720 parseFileOptions ("/etc/ctags.conf");
1721 parseFileOptions ("/usr/local/etc/ctags.conf");
1722 if (home != NULL)
1724 parseConfigurationFileOptionsInDirectory (home);
1726 else
1728 #ifdef MSDOS_STYLE_PATH
1730 * Windows users don't usually set HOME.
1731 * The OS sets HOMEDRIVE and HOMEPATH for them.
1733 const char* homeDrive = getenv ("HOMEDRIVE");
1734 const char* homePath = getenv ("HOMEPATH");
1735 if (homeDrive != NULL && homePath != NULL)
1737 vString* const windowsHome = vStringNew ();
1738 vStringCatS (windowsHome, homeDrive);
1739 vStringCatS (windowsHome, homePath);
1740 parseConfigurationFileOptionsInDirectory (vStringValue (windowsHome));
1741 vStringDelete (windowsHome);
1743 #endif
1745 parseConfigurationFileOptionsInDirectory (".");
1748 static void parseEnvironmentOptions (void)
1750 const char *envOptions = NULL;
1751 const char* var = NULL;
1753 if (Option.etags)
1755 var = ETAGS_ENVIRONMENT;
1756 envOptions = getenv (var);
1758 if (envOptions == NULL)
1760 var = CTAGS_ENVIRONMENT;
1761 envOptions = getenv (var);
1763 if (envOptions != NULL && envOptions [0] != '\0')
1765 cookedArgs* const args = cArgNewFromString (envOptions);
1766 verbose ("Reading options from $CTAGS\n");
1767 parseOptions (args);
1768 cArgDelete (args);
1769 if (NonOptionEncountered)
1770 error (WARNING, "Ignoring non-option in %s variable", var);
1774 extern void readOptionConfiguration (void)
1776 if (! SkipConfiguration)
1778 parseConfigurationFileOptions ();
1779 parseEnvironmentOptions ();
1784 * Option initialization
1787 extern void initOptions (void)
1789 OptionFiles = stringListNew ();
1790 verbose ("Setting option defaults\n");
1791 installHeaderListDefaults ();
1792 verbose (" Installing default language mappings:\n");
1793 installLanguageMapDefaults ();
1795 /* always excluded by default */
1796 verbose (" Installing default exclude patterns:\n");
1797 processExcludeOption (NULL, "{arch}");
1798 processExcludeOption (NULL, ".arch-ids");
1799 processExcludeOption (NULL, ".arch-inventory");
1800 processExcludeOption (NULL, "autom4te.cache");
1801 processExcludeOption (NULL, "BitKeeper");
1802 processExcludeOption (NULL, ".bzr");
1803 processExcludeOption (NULL, ".bzrignore");
1804 processExcludeOption (NULL, "CVS");
1805 processExcludeOption (NULL, ".cvsignore");
1806 processExcludeOption (NULL, "_darcs");
1807 processExcludeOption (NULL, ".deps");
1808 processExcludeOption (NULL, "EIFGEN");
1809 processExcludeOption (NULL, ".git");
1810 processExcludeOption (NULL, ".hg");
1811 processExcludeOption (NULL, "PENDING");
1812 processExcludeOption (NULL, "RCS");
1813 processExcludeOption (NULL, "RESYNC");
1814 processExcludeOption (NULL, "SCCS");
1815 processExcludeOption (NULL, ".svn");
1818 extern void freeOptionResources (void)
1820 freeString (&Option.tagFileName);
1821 freeString (&Option.fileList);
1822 freeString (&Option.filterTerminator);
1824 freeList (&Excluded);
1825 freeList (&Option.ignore);
1826 freeList (&Option.headerExt);
1827 freeList (&Option.etagsInclude);
1828 freeList (&OptionFiles);
1831 /* vi:set tabstop=4 shiftwidth=4: */