📄 options.c
字号:
const char *const option, const char *const parameter){ if (parameter [0] == '\0') error (WARNING, "no option file supplied for \"%s\"", option); else if (! parseFileOptions (parameter)) error (FATAL | PERROR, "cannot open option file \"%s\"", parameter);}static void processSortOption ( const char *const option, const char *const parameter){ if (isFalse (parameter)) Option.sorted = SO_UNSORTED; else if (isTrue (parameter)) Option.sorted = SO_SORTED; else if (strcasecmp (parameter, "f") == 0 || strcasecmp (parameter, "fold") == 0 || strcasecmp (parameter, "foldcase") == 0) Option.sorted = SO_FOLDSORTED; else error (FATAL, "Invalid value for \"%s\" option", option);}static void installHeaderListDefaults (void){ Option.headerExt = stringListNewFromArgv (HeaderExtensions); if (Option.verbose) { printf (" Setting default header extensions: "); stringListPrint (Option.headerExt); putchar ('\n'); }}static void processHeaderListOption (const int option, const char *parameter){ /* Check to make sure that the user did not enter "ctags -h *.c" * by testing to see if the list is a filename that exists. */ if (doesFileExist (parameter)) error (FATAL, "-%c: Invalid list", option); if (strcmp (parameter, "default") == 0) installHeaderListDefaults (); else { boolean clear = TRUE; if (parameter [0] == '+') { ++parameter; clear = FALSE; } if (Option.headerExt == NULL) Option.headerExt = stringListNew (); verbose (" Header Extensions:\n"); addExtensionList (Option.headerExt, parameter, clear); }}/* * Token ignore processing *//* Determines whether or not "name" should be ignored, per the ignore list. */extern boolean isIgnoreToken ( const char *const name, boolean *const pIgnoreParens, const char **const replacement){ boolean result = FALSE; if (Option.ignore != NULL) { const size_t nameLen = strlen (name); unsigned int i; if (pIgnoreParens != NULL) *pIgnoreParens = FALSE; for (i = 0 ; i < stringListCount (Option.ignore) ; ++i) { vString *token = stringListItem (Option.ignore, i); if (strncmp (vStringValue (token), name, nameLen) == 0) { const size_t tokenLen = vStringLength (token); if (nameLen == tokenLen) { result = TRUE; break; } else if (tokenLen == nameLen + 1 && vStringChar (token, tokenLen - 1) == '+') { result = TRUE; if (pIgnoreParens != NULL) *pIgnoreParens = TRUE; break; } else if (vStringChar (token, nameLen) == '=') { if (replacement != NULL) *replacement = vStringValue (token) + nameLen + 1; break; } } } } return result;}static void saveIgnoreToken (vString *const ignoreToken){ if (Option.ignore == NULL) Option.ignore = stringListNew (); stringListAdd (Option.ignore, ignoreToken); verbose (" ignore token: %s\n", vStringValue (ignoreToken));}static void readIgnoreList (const char *const list){ char* newList = stringCopy (list); const char *token = strtok (newList, IGNORE_SEPARATORS); while (token != NULL) { vString *const entry = vStringNewInit (token); saveIgnoreToken (entry); token = strtok (NULL, IGNORE_SEPARATORS); } eFree (newList);}static void addIgnoreListFromFile (const char *const fileName){ stringList* tokens = stringListNewFromFile (fileName); if (tokens == NULL) error (FATAL | PERROR, "cannot open \"%s\"", fileName); if (Option.ignore == NULL) Option.ignore = tokens; else stringListCombine (Option.ignore, tokens);}static void processIgnoreOption (const char *const list){ if (strchr ("@./\\", list [0]) != NULL) { 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=4 shiftwidth=4: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -