📄 options.c
字号:
const char* fileName = (*list == '@') ? list + 1 : list;
addIgnoreListFromFile (fileName);
}
#if defined (MSDOS) || defined (WIN32) || defined (OS2)
else if (isalpha (list [0]) && list [1] == ':')
addIgnoreListFromFile (list);
#endif
else if (strcmp (list, "-") == 0)
{
freeList (&Option.ignore);
verbose (" clearing list\n");
}
else
readIgnoreList (list);
}
static void processVersionOption (
const char *const option __unused__,
const char *const parameter __unused__)
{
printProgramIdentification ();
exit (0);
}
/*
* Option tables
*/
static parametricOption ParametricOptions [] = {
{ "etags-include", processEtagsInclude, FALSE },
{ "exclude", processExcludeOption, FALSE },
{ "excmd", processExcmdOption, FALSE },
{ "extra", processExtraTagsOption, FALSE },
{ "fields", processFieldsOption, FALSE },
{ "filter-terminator", processFilterTerminatorOption, TRUE },
{ "format", processFormatOption, TRUE },
{ "help", processHelpOption, TRUE },
{ "lang", processLanguageForceOption, FALSE },
{ "language", processLanguageForceOption, FALSE },
{ "language-force", processLanguageForceOption, FALSE },
{ "languages", processLanguagesOption, FALSE },
{ "langdef", processLanguageDefineOption, FALSE },
{ "langmap", processLanguageMapOption, FALSE },
{ "license", processLicenseOption, TRUE },
{ "list-kinds", processListKindsOption, TRUE },
{ "list-maps", processListMapsOption, TRUE },
{ "list-languages", processListLanguagesOption, TRUE },
{ "options", processOptionFile, FALSE },
{ "sort", processSortOption, TRUE },
{ "version", processVersionOption, TRUE },
};
static booleanOption BooleanOptions [] = {
{ "append", &Option.append, TRUE },
{ "file-scope", &Option.include.fileScope, FALSE },
{ "file-tags", &Option.include.fileNames, FALSE },
{ "filter", &Option.filter, TRUE },
{ "if0", &Option.if0, FALSE },
{ "kind-long", &Option.kindLong, TRUE },
{ "line-directives",&Option.lineDirectives, FALSE },
{ "links", &Option.followLinks, FALSE },
#ifdef RECURSE_SUPPORTED
{ "recurse", &Option.recurse, FALSE },
#endif
{ "tag-relative", &Option.tagRelative, TRUE },
{ "totals", &Option.printTotals, TRUE },
{ "verbose", &Option.verbose, FALSE },
};
/*
* Generic option parsing
*/
static void checkOptionOrder (const char* const option)
{
if (NonOptionEncountered)
error (FATAL, "-%s option may not follow a file name", option);
}
static boolean processParametricOption (
const char *const option, const char *const parameter)
{
const int count = sizeof (ParametricOptions) / sizeof (parametricOption);
boolean found = FALSE;
int i;
for (i = 0 ; i < count && ! found ; ++i)
{
parametricOption* const entry = &ParametricOptions [i];
if (strcmp (option, entry->name) == 0)
{
found = TRUE;
if (entry->initOnly)
checkOptionOrder (option);
(entry->handler) (option, parameter);
}
}
return found;
}
static boolean getBooleanOption (
const char *const option, const char *const parameter)
{
boolean selection = TRUE;
if (parameter [0] == '\0')
selection = TRUE;
else if (isFalse (parameter))
selection = FALSE;
else if (isTrue (parameter))
selection = TRUE;
else
error (FATAL, "Invalid value for \"%s\" option", option);
return selection;
}
static boolean processBooleanOption (
const char *const option, const char *const parameter)
{
const int count = sizeof (BooleanOptions) / sizeof (booleanOption);
boolean found = FALSE;
int i;
for (i = 0 ; i < count && ! found ; ++i)
{
booleanOption* const entry = &BooleanOptions [i];
if (strcmp (option, entry->name) == 0)
{
found = TRUE;
if (entry->initOnly)
checkOptionOrder (option);
*entry->pValue = getBooleanOption (option, parameter);
}
}
return found;
}
static void processLongOption (
const char *const option, const char *const parameter)
{
Assert (parameter != NULL);
if (parameter == NULL && parameter [0] == '\0')
verbose (" Option: --%s\n", option);
else
verbose (" Option: --%s=%s\n", option, parameter);
if (processBooleanOption (option, parameter))
;
else if (processParametricOption (option, parameter))
;
else if (processKindOption (option, parameter))
;
else if (processRegexOption (option, parameter))
;
#ifndef RECURSE_SUPPORTED
else if (strcmp (option, "recurse") == 0)
error (WARNING, "%s option not supported on this host", option);
#endif
else
error (FATAL, "Unknown option: --%s", option);
}
static void processShortOption (
const char *const option, const char *const parameter)
{
if (parameter == NULL || parameter [0] == '\0')
verbose (" Option: -%s\n", option);
else
verbose (" Option: -%s %s\n", option, parameter);
if (isCompoundOption (*option) && (parameter == NULL || parameter [0] == '\0'))
error (FATAL, "Missing parameter for \"%s\" option", option);
else switch (*option)
{
case '?':
processHelpOption ("?", NULL);
exit (0);
break;
case 'a':
checkOptionOrder (option);
Option.append = TRUE;
break;
#ifdef DEBUG
case 'b':
if (atol (parameter) < 0)
error (FATAL, "-%s: Invalid line number", option);
Option.breakLine = atol (parameter);
break;
case 'D':
Option.debugLevel = strtol (parameter, NULL, 0);
if (debug (DEBUG_STATUS))
Option.verbose = TRUE;
break;
#endif
case 'B':
Option.backward = TRUE;
break;
case 'e':
checkOptionOrder (option);
setEtagsMode ();
break;
case 'f':
case 'o':
checkOptionOrder (option);
if (Option.tagFileName != NULL)
{
error (WARNING,
"-%s option specified more than once, last value used",
option);
freeString (&Option.tagFileName);
}
else if (parameter [0] == '-' && parameter [1] != '\0')
error (FATAL, "output file name may not begin with a '-'");
Option.tagFileName = stringCopy (parameter);
break;
case 'F':
Option.backward = FALSE;
break;
case 'h':
processHeaderListOption (*option, parameter);
break;
case 'I':
processIgnoreOption (parameter);
break;
case 'L':
if (Option.fileList != NULL)
{
error (WARNING,
"-%s option specified more than once, last value used",
option);
freeString (&Option.fileList);
}
Option.fileList = stringCopy (parameter);
break;
case 'n':
Option.locate = EX_LINENUM;
break;
case 'N':
Option.locate = EX_PATTERN;
break;
case 'R':
#ifdef RECURSE_SUPPORTED
Option.recurse = TRUE;
#else
error (WARNING, "-%s option not supported on this host", option);
#endif
break;
case 'u':
checkOptionOrder (option);
Option.sorted = SO_UNSORTED;
break;
case 'V':
Option.verbose = TRUE;
break;
case 'w':
/* silently ignored */
break;
case 'x':
checkOptionOrder (option);
Option.xref = TRUE;
break;
default:
error (FATAL, "Unknown option: -%s", option);
break;
}
}
extern void parseOption (cookedArgs* const args)
{
Assert (! cArgOff (args));
if (args->isOption)
{
if (args->longOption)
processLongOption (args->item, args->parameter);
else
{
const char *parameter = args->parameter;
while (*parameter == ' ')
++parameter;
processShortOption (args->item, parameter);
}
cArgForth (args);
}
}
extern void parseOptions (cookedArgs* const args)
{
NonOptionEncountered = FALSE;
while (! cArgOff (args) && cArgIsOption (args))
parseOption (args);
if (! cArgOff (args) && ! cArgIsOption (args))
NonOptionEncountered = TRUE;
}
static const char *CheckFile;
static boolean checkSameFile (const char *const fileName)
{
return isSameFile (CheckFile, fileName);
}
static boolean parseFileOptions (const char* const fileName)
{
boolean fileFound = FALSE;
const char* const format = "Considering option file %s: %s\n";
CheckFile = fileName;
if (stringListHasTest (OptionFiles, checkSameFile))
verbose (format, fileName, "already considered");
else
{
FILE* const fp = fopen (fileName, "r");
if (fp == NULL)
verbose (format, fileName, "not found");
else
{
cookedArgs* const args = cArgNewFromLineFile (fp);
vString* file = vStringNewInit (fileName);
stringListAdd (OptionFiles, file);
verbose (format, fileName, "reading...");
parseOptions (args);
if (NonOptionEncountered)
error (WARNING, "Ignoring non-option in %s\n", fileName);
cArgDelete (args);
fclose (fp);
fileFound = TRUE;
}
}
return fileFound;
}
/* Actions to be taken before reading any other options */
extern void previewFirstOption (cookedArgs* const args)
{
while (cArgIsOption (args))
{
if (strcmp (args->item, "V") == 0 || strcmp (args->item, "verbose") == 0)
parseOption (args);
else if (strcmp (args->item, "options") == 0 &&
strcmp (args->parameter, "NONE") == 0)
{
fprintf (stderr, "No options will be read from files or environment\n");
SkipConfiguration = TRUE;
cArgForth (args);
}
else
break;
}
}
static void parseConfigurationFileOptions (void)
{
const char* const home = getenv ("HOME");
const char* conf;
#ifdef CUSTOM_CONFIGURATION_FILE
parseFileOptions (CUSTOM_CONFIGURATION_FILE);
#endif
#ifdef MSDOS_STYLE_PATH
parseFileOptions ("/ctags.cnf");
conf = "ctags.cnf";
#else
conf = ".ctags";
#endif
parseFileOptions ("/etc/ctags.conf");
parseFileOptions ("/usr/local/etc/ctags.conf");
if (home != NULL)
{
vString* const homeFile = combinePathAndFile (home, conf);
parseFileOptions (vStringValue (homeFile));
vStringDelete (homeFile);
}
parseFileOptions (conf);
}
static void parseEnvironmentOptions (void)
{
const char *envOptions = NULL;
const char* var = NULL;
if (Option.etags)
{
var = ETAGS_ENVIRONMENT;
envOptions = getenv (var);
}
if (envOptions == NULL)
{
var = CTAGS_ENVIRONMENT;
envOptions = getenv (var);
}
if (envOptions != NULL && envOptions [0] != '\0')
{
cookedArgs* const args = cArgNewFromString (envOptions);
verbose ("Reading options from $CTAGS\n");
parseOptions (args);
cArgDelete (args);
if (NonOptionEncountered)
error (WARNING, "Ignoring non-option in %s variable", var);
}
}
extern void readOptionConfiguration (void)
{
if (! SkipConfiguration)
{
parseConfigurationFileOptions ();
parseEnvironmentOptions ();
}
}
/*
* Option initialization
*/
extern void initOptions (void)
{
OptionFiles = stringListNew ();
verbose ("Setting option defaults\n");
installHeaderListDefaults ();
verbose (" Installing default language mappings:\n");
installLanguageMapDefaults ();
/* always excluded by default */
verbose (" Installing default exclude patterns:\n");
processExcludeOption (NULL, "EIFGEN");
processExcludeOption (NULL, "SCCS");
processExcludeOption (NULL, "RCS");
processExcludeOption (NULL, "CVS");
}
extern void freeOptionResources (void)
{
freeString (&Option.tagFileName);
freeString (&Option.fileList);
freeString (&Option.filterTerminator);
freeList (&Excluded);
freeList (&Option.ignore);
freeList (&Option.headerExt);
freeList (&Option.etagsInclude);
freeList (&OptionFiles);
}
/* vi:set tabstop=8 shiftwidth=4: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -