Updated Spanish translation
[anjuta-git-plugin.git] / tagmanager / options.c
blob90de12bb1b69f559a7a0e517bf466198caa12e37
1 /*
2 * $Id$
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 TRUE /* -fields=t */
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
157 - Locally used only
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}
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n";
296 /* Contains a set of strings describing the set of "features" compiled into
297 * the code.
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
341 * FUNCTION PROTOTYPES
343 static boolean parseFileOptions (const char *const fileName);
346 * FUNCTION DEFINITIONS
349 extern void verbose (const char *const format, ...)
351 if (1/*Option.verbose*/)
353 va_list ap;
354 va_start (ap, format);
355 vprintf (format, ap);
356 va_end (ap);
360 static char *stringCopy (const char *const string)
362 char* result = NULL;
363 if (string != NULL)
364 result = eStrdup (string);
365 return result;
368 static void freeString (char **const pString)
370 if (*pString != NULL)
372 eFree (*pString);
373 *pString = NULL;
377 extern void freeList (stringList** const pList)
379 if (*pList != NULL)
381 stringListDelete (*pList);
382 *pList = NULL;
386 extern void setDefaultTagFileName (void)
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);
396 extern boolean filesRequired (void)
398 boolean result = FilesRequired;
399 if (Option.recurse)
400 result = FALSE;
401 return result;
404 extern void checkOptions (void)
406 const char* notice;
407 if (Option.xref)
409 notice = "xref output";
410 if (Option.include.fileNames)
412 error (WARNING, "%s disables file name tags", notice);
413 Option.include.fileNames = FALSE;
416 if (Option.append)
418 notice = "append mode is not compatible with";
419 if (isDestinationStdout ())
420 error (FATAL, "%s tags to stdout", notice);
422 if (Option.filter)
424 notice = "filter mode";
425 if (Option.printTotals)
427 error (WARNING, "%s disables totals", notice);
428 Option.printTotals = FALSE;
430 if (Option.tagFileName != NULL)
431 error (WARNING, "%s ignores output tag file name", notice);
435 static void setEtagsMode (void)
437 Option.etags = TRUE;
438 Option.sorted = SO_UNSORTED;
439 Option.lineDirectives = FALSE;
440 Option.tagRelative = TRUE;
443 extern void testEtagsInvocation (void)
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)
453 verbose ("Running in etags mode\n");
454 setEtagsMode ();
459 * Cooked argument parsing
462 static void parseShortOption (cookedArgs *const args)
464 args->simple [0] = *args->shortOptions++;
465 args->simple [1] = '\0';
466 args->item = args->simple;
467 if (! isCompoundOption (*args->simple))
468 args->parameter = "";
469 else if (*args->shortOptions == '\0')
471 argForth (args->args);
472 if (argOff (args->args))
473 args->parameter = NULL;
474 else
475 args->parameter = argItem (args->args);
476 args->shortOptions = NULL;
478 else
480 args->parameter = args->shortOptions;
481 args->shortOptions = NULL;
485 static void parseLongOption (cookedArgs *const args, const char *item)
487 const char* const equal = strchr (item, '=');
488 if (equal == NULL)
490 args->item = eStrdup (item);
491 args->parameter = "";
493 else
495 const size_t length = equal - item;
496 args->item = xMalloc (length + 1, char);
497 strncpy (args->item, item, length);
498 args->item [length] = '\0';
499 args->parameter = equal + 1;
501 Assert (args->item != NULL);
502 Assert (args->parameter != NULL);
505 static void cArgRead (cookedArgs *const current)
507 char* item;
509 Assert (current != NULL);
510 if (! argOff (current->args))
512 item = argItem (current->args);
513 current->shortOptions = NULL;
514 Assert (item != NULL);
515 if (strncmp (item, "--", (size_t) 2) == 0)
517 current->isOption = TRUE;
518 current->longOption = TRUE;
519 parseLongOption (current, item + 2);
520 Assert (current->item != NULL);
521 Assert (current->parameter != NULL);
523 else if (*item == '-')
525 current->isOption = TRUE;
526 current->longOption = FALSE;
527 current->shortOptions = item + 1;
528 parseShortOption (current);
530 else
532 current->isOption = FALSE;
533 current->longOption = FALSE;
534 current->item = item;
535 current->parameter = NULL;
540 extern cookedArgs* cArgNewFromString (const char* string)
542 cookedArgs* const result = xMalloc (1, cookedArgs);
543 memset (result, 0, sizeof (cookedArgs));
544 result->args = argNewFromString (string);
545 cArgRead (result);
546 return result;
549 extern cookedArgs* cArgNewFromArgv (char* const* const argv)
551 cookedArgs* const result = xMalloc (1, cookedArgs);
552 memset (result, 0, sizeof (cookedArgs));
553 result->args = argNewFromArgv (argv);
554 cArgRead (result);
555 return result;
558 extern cookedArgs* cArgNewFromFile (FILE* const fp)
560 cookedArgs* const result = xMalloc (1, cookedArgs);
561 memset (result, 0, sizeof (cookedArgs));
562 result->args = argNewFromFile (fp);
563 cArgRead (result);
564 return result;
567 extern cookedArgs* cArgNewFromLineFile (FILE* const fp)
569 cookedArgs* const result = xMalloc (1, cookedArgs);
570 memset (result, 0, sizeof (cookedArgs));
571 result->args = argNewFromLineFile (fp);
572 cArgRead (result);
573 return result;
576 extern void cArgDelete (cookedArgs* const current)
578 Assert (current != NULL);
579 argDelete (current->args);
580 memset (current, 0, sizeof (cookedArgs));
581 eFree (current);
584 static boolean cArgOptionPending (cookedArgs* const current)
586 boolean result = FALSE;
587 if (current->shortOptions != NULL)
588 if (*current->shortOptions != '\0')
589 result = TRUE;
590 return result;
593 extern boolean cArgOff (cookedArgs* const current)
595 Assert (current != NULL);
596 return (boolean) (argOff (current->args) && ! cArgOptionPending (current));
599 extern boolean cArgIsOption (cookedArgs* const current)
601 Assert (current != NULL);
602 return current->isOption;
605 extern const char* cArgItem (cookedArgs* const current)
607 Assert (current != NULL);
608 return current->item;
611 extern void cArgForth (cookedArgs* const current)
613 Assert (current != NULL);
614 Assert (! cArgOff (current));
615 if (cArgOptionPending (current))
616 parseShortOption (current);
617 else
619 Assert (! argOff (current->args));
620 argForth (current->args);
621 if (! argOff (current->args))
622 cArgRead (current);
623 else
625 current->isOption = FALSE;
626 current->longOption = FALSE;
627 current->shortOptions = NULL;
628 current->item = NULL;
629 current->parameter = NULL;
635 * File extension and language mapping
638 static void addExtensionList (
639 stringList *const slist, const char *const elist, const boolean clear)
641 char *const extensionList = eStrdup (elist);
642 const char *extension = NULL;
643 boolean first = TRUE;
645 if (clear)
647 verbose (" clearing\n");
648 stringListClear (slist);
650 verbose (" adding: ");
651 if (elist != NULL && *elist != '\0')
653 extension = extensionList;
654 if (elist [0] == EXTENSION_SEPARATOR)
655 ++extension;
657 while (extension != NULL)
659 char *separator = strchr (extension, EXTENSION_SEPARATOR);
660 if (separator != NULL)
661 *separator = '\0';
662 verbose ("%s%s", first ? "" : ", ",
663 *extension == '\0' ? "(NONE)" : extension);
664 stringListAdd (slist, vStringNewInit (extension));
665 first = FALSE;
666 if (separator == NULL)
667 extension = NULL;
668 else
669 extension = separator + 1;
671 if (Option.verbose)
673 printf ("\n now: ");
674 stringListPrint (slist);
675 putchar ('\n');
677 eFree (extensionList);
680 static boolean isFalse (const char *parameter)
682 return (boolean) (
683 strcasecmp (parameter, "0" ) == 0 ||
684 strcasecmp (parameter, "n" ) == 0 ||
685 strcasecmp (parameter, "no" ) == 0 ||
686 strcasecmp (parameter, "off") == 0);
689 static boolean isTrue (const char *parameter)
691 return (boolean) (
692 strcasecmp (parameter, "1" ) == 0 ||
693 strcasecmp (parameter, "y" ) == 0 ||
694 strcasecmp (parameter, "yes") == 0 ||
695 strcasecmp (parameter, "on" ) == 0);
698 /* Determines whether the specified file name is considered to be a header
699 * file for the purposes of determining whether enclosed tags are global or
700 * static.
702 extern boolean isIncludeFile (const char *const fileName)
704 boolean result = FALSE;
705 const char *const extension = fileExtension (fileName);
706 if (Option.headerExt != NULL)
707 result = stringListExtensionMatched (Option.headerExt, extension);
708 return result;
712 * Specific option processing
715 static void processEtagsInclude (
716 const char *const option, const char *const parameter)
718 if (! Option.etags)
719 error (FATAL, "Etags must be enabled to use \"%s\" option", option);
720 else
722 vString *const file = vStringNewInit (parameter);
723 if (Option.etagsInclude == NULL)
724 Option.etagsInclude = stringListNew ();
725 stringListAdd (Option.etagsInclude, file);
726 FilesRequired = FALSE;
730 static void processExcludeOption (
731 const char *const option __unused__, const char *const parameter)
733 const char *const fileName = parameter + 1;
734 if (parameter [0] == '\0')
735 freeList (&Excluded);
736 else if (parameter [0] == '@')
738 stringList* const sl = stringListNewFromFile (fileName);
739 if (sl == NULL)
740 error (FATAL | PERROR, "cannot open \"%s\"", fileName);
741 if (Excluded == NULL)
742 Excluded = sl;
743 else
744 stringListCombine (Excluded, sl);
745 verbose (" adding exclude patterns from %s\n", fileName);
747 else
749 vString *const item = vStringNewInit (parameter);
750 if (Excluded == NULL)
751 Excluded = stringListNew ();
752 stringListAdd (Excluded, item);
753 verbose (" adding exclude pattern: %s\n", parameter);
757 extern boolean isExcludedFile (const char* const name)
759 const char* base = baseFilename (name);
760 boolean result = FALSE;
761 if (Excluded != NULL)
763 result = stringListFileMatched (Excluded, base);
764 if (! result && name != base)
765 result = stringListFileMatched (Excluded, name);
767 #ifdef AMIGA
768 /* not a good solution, but the only one which works often */
769 if (! result)
770 result = (boolean) (strcmp (name, TagFile.name) == 0);
771 #endif
772 return result;
775 static void processExcmdOption (
776 const char *const option, const char *const parameter)
778 switch (*parameter)
780 case 'm': Option.locate = EX_MIX; break;
781 case 'n': Option.locate = EX_LINENUM; break;
782 case 'p': Option.locate = EX_PATTERN; break;
783 default:
784 error (FATAL, "Invalid value for \"%s\" option", option);
785 break;
789 static void processExtraTagsOption (
790 const char *const option, const char *const parameter)
792 struct sInclude *const inc = &Option.include;
793 const char *p = parameter;
794 boolean mode = TRUE;
795 int c;
797 if (*p != '+' && *p != '-')
799 inc->fileNames = FALSE;
800 inc->qualifiedTags = FALSE;
801 #if 0
802 inc->fileScope = FALSE;
803 #endif
805 while ((c = *p++) != '\0') switch (c)
807 case '+': mode = TRUE; break;
808 case '-': mode = FALSE; break;
810 case 'f': inc->fileNames = mode; break;
811 case 'q': inc->qualifiedTags = mode; break;
812 #if 0
813 case 'F': inc->fileScope = mode; break;
814 #endif
816 default: error(WARNING, "Unsupported parameter '%c' for \"%s\" option",
817 c, option);
818 break;
822 static void processFieldsOption (
823 const char *const option, const char *const parameter)
825 struct sExtFields *field = &Option.extensionFields;
826 const char *p = parameter;
827 boolean mode = TRUE;
828 int c;
830 if (*p != '+' && *p != '-')
832 field->access = FALSE;
833 field->fileScope = FALSE;
834 field->implementation = FALSE;
835 field->inheritance = FALSE;
836 field->kind = FALSE;
837 field->kindKey = FALSE;
838 field->kindLong = FALSE;
839 field->language = FALSE;
840 field->scope = FALSE;
841 field->typeRef = FALSE;
843 while ((c = *p++) != '\0') switch (c)
845 case '+': mode = TRUE; break;
846 case '-': mode = FALSE; break;
848 case 'a': field->access = mode; break;
849 case 'f': field->fileScope = mode; break;
850 case 'm': field->implementation = mode; break;
851 case 'i': field->inheritance = mode; break;
852 case 'k': field->kind = mode; break;
853 case 'K': field->kindLong = mode; break;
854 case 'l': field->language = mode; break;
855 case 'n': field->lineNumber = mode; break;
856 case 's': field->scope = mode; break;
857 case 'S': field->signature = mode; break;
858 case 'z': field->kindKey = mode; break;
859 case 't': field->typeRef = mode; break;
861 default: error(WARNING, "Unsupported parameter '%c' for \"%s\" option",
862 c, option);
863 break;
867 static void processFilterTerminatorOption (
868 const char *const option __unused__, const char *const parameter)
870 freeString (&Option.filterTerminator);
871 Option.filterTerminator = stringCopy (parameter);
874 static void processFormatOption (
875 const char *const option, const char *const parameter)
877 unsigned int format;
879 if (sscanf (parameter, "%u", &format) < 1)
880 error (FATAL, "Invalid value for \"%s\" option",option);
881 else if (format <= (unsigned int) MaxSupportedTagFormat)
882 Option.tagFileFormat = format;
883 else
884 error (FATAL, "Unsupported value for \"%s\" option", option);
887 static void printInvocationDescription (void)
889 printf (INVOCATION, getExecutableName ());
892 static void printOptionDescriptions (const optionDescription *const optDesc)
894 int i;
895 for (i = 0 ; optDesc [i].description != NULL ; ++i)
897 if (! Option.etags || optDesc [i].usedByEtags)
898 puts (optDesc [i].description);
902 static void printFeatureList (void)
904 int i;
906 for (i = 0 ; Features [i] != NULL ; ++i)
908 if (i == 0)
909 printf (" Optional compiled features: ");
910 printf ("%s+%s", (i>0 ? ", " : ""), Features [i]);
911 #ifdef CUSTOM_CONFIGURATION_FILE
912 if (strcmp (Features [i], "custom-conf") == 0)
913 printf ("=%s", CUSTOM_CONFIGURATION_FILE);
914 #endif
916 if (i > 0)
917 putchar ('\n');
920 static void printProgramIdentification (void)
922 printf ("%s %s, Copyright (C) 1996-2004 %s\n",
923 PROGRAM_NAME, PROGRAM_VERSION, AUTHOR_NAME);
924 printf (" Compiled: %s, %s\n", __DATE__, __TIME__);
925 printf (" Addresses: <%s>, %s\n", AUTHOR_EMAIL, PROGRAM_URL);
926 printFeatureList ();
929 static void processHelpOption (
930 const char *const option __unused__,
931 const char *const parameter __unused__)
933 printProgramIdentification ();
934 putchar ('\n');
935 printInvocationDescription ();
936 putchar ('\n');
937 printOptionDescriptions (LongOptionDescription);
938 exit (0);
941 static void processLanguageForceOption (
942 const char *const option, const char *const parameter)
944 langType language;
945 if (strcasecmp (parameter, "auto") == 0)
946 language = LANG_AUTO;
947 else
948 language = getNamedLanguage (parameter);
950 if (strcmp (option, "lang") == 0 || strcmp (option, "language") == 0)
951 error (WARNING,
952 "\"--%s\" option is obsolete; use \"--language-force\" instead",
953 option);
954 if (language == LANG_IGNORE)
955 error (FATAL, "Unknown language specified in \"%s\" option", option);
956 else
957 Option.language = language;
959 static char* skipPastMap (char* p)
961 while (*p != EXTENSION_SEPARATOR &&
962 *p != PATTERN_START && *p != ',' && *p != '\0')
963 ++p;
964 return p;
967 /* Parses the mapping beginning at `map', adds it to the language map, and
968 * returns first character past the map.
970 static char* addLanguageMap (const langType language, char* map)
972 char* p = NULL;
973 const char first = *map;
974 if (first == EXTENSION_SEPARATOR) /* extension map */
976 ++map;
977 p = skipPastMap (map);
978 if (*p == '\0')
980 verbose (" .%s", map);
981 addLanguageExtensionMap (language, map);
982 p = map + strlen (map);
984 else
986 const char separator = *p;
987 *p = '\0';
988 verbose (" .%s", map);
989 addLanguageExtensionMap (language, map);
990 *p = separator;
993 else if (first == PATTERN_START) /* pattern map */
995 ++map;
996 for (p = map ; *p != PATTERN_STOP && *p != '\0' ; ++p)
998 if (*p == '\\' && *(p + 1) == PATTERN_STOP)
999 ++p;
1001 if (*p == '\0')
1002 error (FATAL, "Unterminated file name pattern for %s language",
1003 getLanguageName (language));
1004 else
1006 *p++ = '\0';
1007 verbose (" (%s)", map);
1008 addLanguagePatternMap (language, map);
1011 else
1012 error (FATAL, "Badly formed language map for %s language",
1013 getLanguageName (language));
1014 return p;
1017 static char* processLanguageMap (char* map)
1019 char* const separator = strchr (map, ':');
1020 char* result = NULL;
1021 if (separator != NULL)
1023 langType language;
1024 char *list = separator + 1;
1025 boolean clear = FALSE;
1026 *separator = '\0';
1027 language = getNamedLanguage (map);
1028 if (language != LANG_IGNORE)
1030 const char *const deflt = "default";
1031 char* p;
1032 if (*list == '+')
1033 ++list;
1034 else
1035 clear = TRUE;
1036 for (p = list ; *p != ',' && *p != '\0' ; ++p) /*no-op*/ ;
1037 if ((size_t) (p - list) == strlen (deflt) &&
1038 strncasecmp (list, deflt, p - list) == 0)
1040 verbose (" Restoring default %s language map: ", getLanguageName (language));
1041 installLanguageMapDefault (language);
1042 list = p;
1044 else
1046 if (clear)
1048 verbose (" Setting %s language map:", getLanguageName (language));
1049 clearLanguageMap (language);
1051 else
1052 verbose (" Adding to %s language map:", getLanguageName (language));
1053 while (list != NULL && *list != '\0' && *list != ',')
1054 list = addLanguageMap (language, list);
1055 verbose ("\n");
1057 if (list != NULL && *list == ',')
1058 ++list;
1059 result = list;
1062 return result;
1065 static void processLanguageMapOption (
1066 const char *const option, const char *const parameter)
1068 char *const maps = eStrdup (parameter);
1069 char *map = maps;
1071 if (strcmp (parameter, "default") == 0)
1073 verbose (" Restoring default language maps:\n");
1074 installLanguageMapDefaults ();
1076 else while (map != NULL && *map != '\0')
1078 char* const next = processLanguageMap (map);
1079 if (next == NULL)
1080 error (WARNING, "Unknown language specified in \"%s\" option", option);
1081 map = next;
1083 eFree (maps);
1086 static void processLanguagesOption (
1087 const char *const option, const char *const parameter)
1089 char *const langs = eStrdup (parameter);
1090 enum { Add, Remove, Replace } mode = Replace;
1091 boolean first = TRUE;
1092 char *lang = langs;
1093 const char* prefix = "";
1094 verbose (" Enabled languages: ");
1095 while (lang != NULL)
1097 char *const end = strchr (lang, ',');
1098 if (lang [0] == '+')
1100 ++lang;
1101 mode = Add;
1102 prefix = "+ ";
1104 else if (lang [0] == '-')
1106 ++lang;
1107 mode = Remove;
1108 prefix = "- ";
1110 if (mode == Replace)
1111 enableLanguages (FALSE);
1112 if (end != NULL)
1113 *end = '\0';
1114 if (lang [0] != '\0')
1116 if (strcmp (lang, "all") == 0)
1117 enableLanguages ((boolean) (mode != Remove));
1118 else
1120 const langType language = getNamedLanguage (lang);
1121 if (language == LANG_IGNORE)
1122 error (WARNING, "Unknown language specified in \"%s\" option", option);
1123 else
1124 enableLanguage (language, (boolean) (mode != Remove));
1126 verbose ("%s%s%s", (first ? "" : ", "), prefix, lang);
1127 prefix = "";
1128 first = FALSE;
1129 if (mode == Replace)
1130 mode = Add;
1132 lang = (end != NULL ? end + 1 : NULL);
1134 verbose ("\n");
1135 eFree (langs);
1138 static void processLicenseOption (
1139 const char *const option __unused__,
1140 const char *const parameter __unused__)
1142 printProgramIdentification ();
1143 puts ("");
1144 puts (License1);
1145 puts (License2);
1146 exit (0);
1149 static void processListKindsOption (
1150 const char *const option, const char *const parameter)
1152 if (parameter [0] == '\0' || strcasecmp (parameter, "all") == 0)
1153 printLanguageKinds (LANG_AUTO);
1154 else
1156 langType language = getNamedLanguage (parameter);
1157 if (language == LANG_IGNORE)
1158 error (FATAL, "Unknown language specified in \"%s\" option",option);
1159 else
1160 printLanguageKinds (language);
1162 exit (0);
1165 static void processListMapsOption (
1166 const char *const __unused__ option,
1167 const char *const __unused__ parameter)
1169 if (parameter [0] == '\0' || strcasecmp (parameter, "all") == 0)
1170 printLanguageMaps (LANG_AUTO);
1171 else
1173 langType language = getNamedLanguage (parameter);
1174 if (language == LANG_IGNORE)
1175 error (FATAL, "Unknown language specified in \"%s\" option",option);
1176 else
1177 printLanguageMaps (language);
1179 exit (0);
1182 static void processListLanguagesOption (
1183 const char *const option __unused__,
1184 const char *const parameter __unused__)
1186 printLanguageList ();
1187 exit (0);
1190 static void processOptionFile (
1191 const char *const option, const char *const parameter)
1193 if (parameter [0] == '\0')
1194 error (WARNING, "no option file supplied for \"%s\"", option);
1195 else if (! parseFileOptions (parameter))
1196 error (FATAL | PERROR, "cannot open option file \"%s\"", parameter);
1199 static void processSortOption (
1200 const char *const option, const char *const parameter)
1202 if (isFalse (parameter))
1203 Option.sorted = SO_UNSORTED;
1204 else if (isTrue (parameter))
1205 Option.sorted = SO_SORTED;
1206 else if (strcasecmp (parameter, "f") == 0 ||
1207 strcasecmp (parameter, "fold") == 0 ||
1208 strcasecmp (parameter, "foldcase") == 0)
1209 Option.sorted = SO_FOLDSORTED;
1210 else
1211 error (FATAL, "Invalid value for \"%s\" option", option);
1214 static void installHeaderListDefaults (void)
1216 Option.headerExt = stringListNewFromArgv (HeaderExtensions);
1217 if (Option.verbose)
1219 printf (" Setting default header extensions: ");
1220 stringListPrint (Option.headerExt);
1221 putchar ('\n');
1225 static void processHeaderListOption (const int option, const char *parameter)
1227 /* Check to make sure that the user did not enter "ctags -h *.c"
1228 * by testing to see if the list is a filename that exists.
1230 if (doesFileExist (parameter))
1231 error (FATAL, "-%c: Invalid list", option);
1232 if (strcmp (parameter, "default") == 0)
1233 installHeaderListDefaults ();
1234 else
1236 boolean clear = TRUE;
1238 if (parameter [0] == '+')
1240 ++parameter;
1241 clear = FALSE;
1243 if (Option.headerExt == NULL)
1244 Option.headerExt = stringListNew ();
1245 verbose (" Header Extensions:\n");
1246 addExtensionList (Option.headerExt, parameter, clear);
1251 * Token ignore processing
1254 /* Determines whether or not "name" should be ignored, per the ignore list.
1256 extern boolean isIgnoreToken (
1257 const char *const name, boolean *const pIgnoreParens,
1258 const char **const replacement)
1260 boolean result = FALSE;
1262 if (Option.ignore != NULL)
1264 const size_t nameLen = strlen (name);
1265 unsigned int i;
1267 if (pIgnoreParens != NULL)
1268 *pIgnoreParens = FALSE;
1270 for (i = 0 ; i < stringListCount (Option.ignore) ; ++i)
1272 vString *token = stringListItem (Option.ignore, i);
1274 if (strncmp (vStringValue (token), name, nameLen) == 0)
1276 const size_t tokenLen = vStringLength (token);
1278 if (nameLen == tokenLen)
1280 result = TRUE;
1281 break;
1283 else if (tokenLen == nameLen + 1 &&
1284 vStringChar (token, tokenLen - 1) == '+')
1286 result = TRUE;
1287 if (pIgnoreParens != NULL)
1288 *pIgnoreParens = TRUE;
1289 break;
1291 else if (vStringChar (token, nameLen) == '=')
1293 if (replacement != NULL)
1294 *replacement = vStringValue (token) + nameLen + 1;
1295 break;
1300 return result;
1303 static void saveIgnoreToken (vString *const ignoreToken)
1305 if (Option.ignore == NULL)
1306 Option.ignore = stringListNew ();
1307 stringListAdd (Option.ignore, ignoreToken);
1308 verbose (" ignore token: %s\n", vStringValue (ignoreToken));
1311 static void readIgnoreList (const char *const list)
1313 char* newList = stringCopy (list);
1314 const char *token = strtok (newList, IGNORE_SEPARATORS);
1316 while (token != NULL)
1318 vString *const entry = vStringNewInit (token);
1320 saveIgnoreToken (entry);
1321 token = strtok (NULL, IGNORE_SEPARATORS);
1323 eFree (newList);
1326 void addIgnoreListFromFile (const char *const fileName)
1328 stringList* tokens = stringListNewFromFile (fileName);
1329 if (tokens == NULL)
1330 error (FATAL | PERROR, "cannot open \"%s\"", fileName);
1331 if (Option.ignore == NULL)
1332 Option.ignore = tokens;
1333 else
1334 stringListCombine (Option.ignore, tokens);
1337 static void processIgnoreOption (const char *const list)
1339 if (strchr ("@./\\", list [0]) != NULL)
1341 const char* fileName = (*list == '@') ? list + 1 : list;
1342 addIgnoreListFromFile (fileName);
1344 #if defined (MSDOS) || defined (WIN32) || defined (OS2)
1345 else if (isalpha (list [0]) && list [1] == ':')
1346 addIgnoreListFromFile (list);
1347 #endif
1348 else if (strcmp (list, "-") == 0)
1350 freeList (&Option.ignore);
1351 verbose (" clearing list\n");
1353 else
1354 readIgnoreList (list);
1357 static void processVersionOption (
1358 const char *const option __unused__,
1359 const char *const parameter __unused__)
1361 printProgramIdentification ();
1362 exit (0);
1366 * Option tables
1369 static parametricOption ParametricOptions [] = {
1370 { "etags-include", processEtagsInclude, FALSE },
1371 { "exclude", processExcludeOption, FALSE },
1372 { "excmd", processExcmdOption, FALSE },
1373 { "extra", processExtraTagsOption, FALSE },
1374 { "fields", processFieldsOption, FALSE },
1375 { "filter-terminator", processFilterTerminatorOption, TRUE },
1376 { "format", processFormatOption, TRUE },
1377 { "help", processHelpOption, TRUE },
1378 { "lang", processLanguageForceOption, FALSE },
1379 { "language", processLanguageForceOption, FALSE },
1380 { "language-force", processLanguageForceOption, FALSE },
1381 { "languages", processLanguagesOption, FALSE },
1382 { "langdef", processLanguageDefineOption, FALSE },
1383 { "langmap", processLanguageMapOption, FALSE },
1384 { "license", processLicenseOption, TRUE },
1385 { "list-kinds", processListKindsOption, TRUE },
1386 { "list-maps", processListMapsOption, TRUE },
1387 { "list-languages", processListLanguagesOption, TRUE },
1388 { "options", processOptionFile, FALSE },
1389 { "sort", processSortOption, TRUE },
1390 { "version", processVersionOption, TRUE },
1393 static booleanOption BooleanOptions [] = {
1394 { "append", &Option.append, TRUE },
1395 { "file-scope", &Option.include.fileScope, FALSE },
1396 { "file-tags", &Option.include.fileNames, FALSE },
1397 { "filter", &Option.filter, TRUE },
1398 { "if0", &Option.if0, FALSE },
1399 { "kind-long", &Option.kindLong, TRUE },
1400 { "line-directives",&Option.lineDirectives, FALSE },
1401 { "links", &Option.followLinks, FALSE },
1402 #ifdef RECURSE_SUPPORTED
1403 { "recurse", &Option.recurse, FALSE },
1404 #endif
1405 { "tag-relative", &Option.tagRelative, TRUE },
1406 { "totals", &Option.printTotals, TRUE },
1407 { "verbose", &Option.verbose, FALSE },
1411 * Generic option parsing
1414 static void checkOptionOrder (const char* const option)
1416 if (NonOptionEncountered)
1417 error (FATAL, "-%s option may not follow a file name", option);
1420 static boolean processParametricOption (
1421 const char *const option, const char *const parameter)
1423 const int count = sizeof (ParametricOptions) / sizeof (parametricOption);
1424 boolean found = FALSE;
1425 int i;
1427 for (i = 0 ; i < count && ! found ; ++i)
1429 parametricOption* const entry = &ParametricOptions [i];
1430 if (strcmp (option, entry->name) == 0)
1432 found = TRUE;
1433 if (entry->initOnly)
1434 checkOptionOrder (option);
1435 (entry->handler) (option, parameter);
1438 return found;
1441 static boolean getBooleanOption (
1442 const char *const option, const char *const parameter)
1444 boolean selection = TRUE;
1446 if (parameter [0] == '\0')
1447 selection = TRUE;
1448 else if (isFalse (parameter))
1449 selection = FALSE;
1450 else if (isTrue (parameter))
1451 selection = TRUE;
1452 else
1453 error (FATAL, "Invalid value for \"%s\" option", option);
1455 return selection;
1458 static boolean processBooleanOption (
1459 const char *const option, const char *const parameter)
1461 const int count = sizeof (BooleanOptions) / sizeof (booleanOption);
1462 boolean found = FALSE;
1463 int i;
1465 for (i = 0 ; i < count && ! found ; ++i)
1467 booleanOption* const entry = &BooleanOptions [i];
1468 if (strcmp (option, entry->name) == 0)
1470 found = TRUE;
1471 if (entry->initOnly)
1472 checkOptionOrder (option);
1473 *entry->pValue = getBooleanOption (option, parameter);
1476 return found;
1479 static void processLongOption (
1480 const char *const option, const char *const parameter)
1482 Assert (parameter != NULL);
1483 if (parameter == NULL && parameter [0] == '\0')
1484 verbose (" Option: --%s\n", option);
1485 else
1486 verbose (" Option: --%s=%s\n", option, parameter);
1488 if (processBooleanOption (option, parameter))
1490 else if (processParametricOption (option, parameter))
1492 else if (processKindOption (option, parameter))
1494 else if (processRegexOption (option, parameter))
1496 #ifndef RECURSE_SUPPORTED
1497 else if (strcmp (option, "recurse") == 0)
1498 error (WARNING, "%s option not supported on this host", option);
1499 #endif
1500 else
1501 error (FATAL, "Unknown option: --%s", option);
1504 static void processShortOption (
1505 const char *const option, const char *const parameter)
1507 if (parameter == NULL || parameter [0] == '\0')
1508 verbose (" Option: -%s\n", option);
1509 else
1510 verbose (" Option: -%s %s\n", option, parameter);
1512 if (isCompoundOption (*option) && (parameter == NULL || parameter [0] == '\0'))
1513 error (FATAL, "Missing parameter for \"%s\" option", option);
1514 else switch (*option)
1516 case '?':
1517 processHelpOption ("?", NULL);
1518 exit (0);
1519 break;
1520 case 'a':
1521 checkOptionOrder (option);
1522 Option.append = TRUE;
1523 break;
1524 #ifdef DEBUG
1525 case 'b':
1526 if (atol (parameter) < 0)
1527 error (FATAL, "-%s: Invalid line number", option);
1528 Option.breakLine = atol (parameter);
1529 break;
1530 case 'D':
1531 Option.debugLevel = strtol (parameter, NULL, 0);
1532 if (debug (DEBUG_STATUS))
1533 Option.verbose = TRUE;
1534 break;
1535 #endif
1536 case 'B':
1537 Option.backward = TRUE;
1538 break;
1539 case 'e':
1540 checkOptionOrder (option);
1541 setEtagsMode ();
1542 break;
1543 case 'f':
1544 case 'o':
1545 checkOptionOrder (option);
1546 if (Option.tagFileName != NULL)
1548 error (WARNING,
1549 "-%s option specified more than once, last value used",
1550 option);
1551 freeString (&Option.tagFileName);
1553 else if (parameter [0] == '-' && parameter [1] != '\0')
1554 error (FATAL, "output file name may not begin with a '-'");
1555 Option.tagFileName = stringCopy (parameter);
1556 break;
1557 case 'F':
1558 Option.backward = FALSE;
1559 break;
1560 case 'h':
1561 processHeaderListOption (*option, parameter);
1562 break;
1563 case 'I':
1564 processIgnoreOption (parameter);
1565 break;
1566 case 'L':
1567 if (Option.fileList != NULL)
1569 error (WARNING,
1570 "-%s option specified more than once, last value used",
1571 option);
1572 freeString (&Option.fileList);
1574 Option.fileList = stringCopy (parameter);
1575 break;
1576 case 'n':
1577 Option.locate = EX_LINENUM;
1578 break;
1579 case 'N':
1580 Option.locate = EX_PATTERN;
1581 break;
1582 case 'R':
1583 #ifdef RECURSE_SUPPORTED
1584 Option.recurse = TRUE;
1585 #else
1586 error (WARNING, "-%s option not supported on this host", option);
1587 #endif
1588 break;
1589 case 'u':
1590 checkOptionOrder (option);
1591 Option.sorted = SO_UNSORTED;
1592 break;
1593 case 'V':
1594 Option.verbose = TRUE;
1595 break;
1596 case 'w':
1597 /* silently ignored */
1598 break;
1599 case 'x':
1600 checkOptionOrder (option);
1601 Option.xref = TRUE;
1602 break;
1603 default:
1604 error (FATAL, "Unknown option: -%s", option);
1605 break;
1609 extern void parseOption (cookedArgs* const args)
1611 Assert (! cArgOff (args));
1612 if (args->isOption)
1614 if (args->longOption)
1615 processLongOption (args->item, args->parameter);
1616 else
1618 const char *parameter = args->parameter;
1619 while (*parameter == ' ')
1620 ++parameter;
1621 processShortOption (args->item, parameter);
1623 cArgForth (args);
1627 extern void parseOptions (cookedArgs* const args)
1629 NonOptionEncountered = FALSE;
1630 while (! cArgOff (args) && cArgIsOption (args))
1631 parseOption (args);
1632 if (! cArgOff (args) && ! cArgIsOption (args))
1633 NonOptionEncountered = TRUE;
1636 static const char *CheckFile;
1637 static boolean checkSameFile (const char *const fileName)
1639 return isSameFile (CheckFile, fileName);
1642 static boolean parseFileOptions (const char* const fileName)
1644 boolean fileFound = FALSE;
1645 const char* const format = "Considering option file %s: %s\n";
1646 CheckFile = fileName;
1647 if (stringListHasTest (OptionFiles, checkSameFile))
1648 verbose (format, fileName, "already considered");
1649 else
1651 FILE* const fp = fopen (fileName, "r");
1652 if (fp == NULL)
1653 verbose (format, fileName, "not found");
1654 else
1656 cookedArgs* const args = cArgNewFromLineFile (fp);
1657 vString* file = vStringNewInit (fileName);
1658 stringListAdd (OptionFiles, file);
1659 verbose (format, fileName, "reading...");
1660 parseOptions (args);
1661 if (NonOptionEncountered)
1662 error (WARNING, "Ignoring non-option in %s\n", fileName);
1663 cArgDelete (args);
1664 fclose (fp);
1665 fileFound = TRUE;
1668 return fileFound;
1671 /* Actions to be taken before reading any other options */
1672 extern void previewFirstOption (cookedArgs* const args)
1674 while (cArgIsOption (args))
1676 if (strcmp (args->item, "V") == 0 || strcmp (args->item, "verbose") == 0)
1677 parseOption (args);
1678 else if (strcmp (args->item, "options") == 0 &&
1679 strcmp (args->parameter, "NONE") == 0)
1681 fprintf (stderr, "No options will be read from files or environment\n");
1682 SkipConfiguration = TRUE;
1683 cArgForth (args);
1685 else
1686 break;
1690 static void parseConfigurationFileOptions (void)
1692 const char* const home = getenv ("HOME");
1693 const char* conf;
1694 #ifdef CUSTOM_CONFIGURATION_FILE
1695 parseFileOptions (CUSTOM_CONFIGURATION_FILE);
1696 #endif
1697 #ifdef MSDOS_STYLE_PATH
1698 parseFileOptions ("/ctags.cnf");
1699 conf = "ctags.cnf";
1700 #else
1701 conf = ".ctags";
1702 #endif
1703 parseFileOptions ("/etc/ctags.conf");
1704 parseFileOptions ("/usr/local/etc/ctags.conf");
1705 if (home != NULL)
1707 vString* const homeFile = combinePathAndFile (home, conf);
1708 parseFileOptions (vStringValue (homeFile));
1709 vStringDelete (homeFile);
1711 parseFileOptions (conf);
1714 static void parseEnvironmentOptions (void)
1716 const char *envOptions = NULL;
1717 const char* var = NULL;
1719 if (Option.etags)
1721 var = ETAGS_ENVIRONMENT;
1722 envOptions = getenv (var);
1724 if (envOptions == NULL)
1726 var = CTAGS_ENVIRONMENT;
1727 envOptions = getenv (var);
1729 if (envOptions != NULL && envOptions [0] != '\0')
1731 cookedArgs* const args = cArgNewFromString (envOptions);
1732 verbose ("Reading options from $CTAGS\n");
1733 parseOptions (args);
1734 cArgDelete (args);
1735 if (NonOptionEncountered)
1736 error (WARNING, "Ignoring non-option in %s variable", var);
1740 extern void readOptionConfiguration (void)
1742 if (! SkipConfiguration)
1744 parseConfigurationFileOptions ();
1745 parseEnvironmentOptions ();
1750 * Option initialization
1753 extern void initOptions (void)
1755 OptionFiles = stringListNew ();
1756 verbose ("Setting option defaults\n");
1757 installHeaderListDefaults ();
1758 verbose (" Installing default language mappings:\n");
1759 installLanguageMapDefaults ();
1761 /* always excluded by default */
1762 verbose (" Installing default exclude patterns:\n");
1763 processExcludeOption (NULL, "EIFGEN");
1764 processExcludeOption (NULL, "SCCS");
1765 processExcludeOption (NULL, "RCS");
1766 processExcludeOption (NULL, "CVS");
1770 extern void freeOptionResources (void)
1772 freeString (&Option.tagFileName);
1773 freeString (&Option.fileList);
1774 freeString (&Option.filterTerminator);
1776 freeList (&Excluded);
1777 freeList (&Option.ignore);
1778 freeList (&Option.headerExt);
1779 freeList (&Option.etagsInclude);
1780 freeList (&OptionFiles);
1783 /* vi:set tabstop=4 shiftwidth=4: */