⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 options.c

📁 ultraEdit的Ctag标签工具的实现源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	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 + -