📄 options.c
字号:
toLowerString (etags);
#endif
if (strstr (execName, etags) != NULL)
{
verbose ("Running in etags mode\n");
setEtagsMode ();
}
}
/*
* Cooked argument parsing
*/
static void parseShortOption (cookedArgs *const args)
{
args->simple [0] = *args->shortOptions++;
args->simple [1] = '\0';
args->item = args->simple;
if (! isCompoundOption (*args->simple))
args->parameter = "";
else if (*args->shortOptions == '\0')
{
argForth (args->args);
if (argOff (args->args))
args->parameter = NULL;
else
args->parameter = argItem (args->args);
args->shortOptions = NULL;
}
else
{
args->parameter = args->shortOptions;
args->shortOptions = NULL;
}
}
static void parseLongOption (cookedArgs *const args, const char *item)
{
const char* const equal = strchr (item, '=');
if (equal == NULL)
{
args->item = eStrdup (item);
args->parameter = "";
}
else
{
const size_t length = equal - item;
args->item = xMalloc (length + 1, char);
strncpy (args->item, item, length);
args->item [length] = '\0';
args->parameter = equal + 1;
}
Assert (args->item != NULL);
Assert (args->parameter != NULL);
}
static void cArgRead (cookedArgs *const current)
{
char* item;
Assert (current != NULL);
if (! argOff (current->args))
{
item = argItem (current->args);
current->shortOptions = NULL;
Assert (item != NULL);
if (strncmp (item, "--", (size_t) 2) == 0)
{
current->isOption = TRUE;
current->longOption = TRUE;
parseLongOption (current, item + 2);
Assert (current->item != NULL);
Assert (current->parameter != NULL);
}
else if (*item == '-')
{
current->isOption = TRUE;
current->longOption = FALSE;
current->shortOptions = item + 1;
parseShortOption (current);
}
else
{
current->isOption = FALSE;
current->longOption = FALSE;
current->item = item;
current->parameter = NULL;
}
}
}
extern cookedArgs* cArgNewFromString (const char* string)
{
cookedArgs* const result = xMalloc (1, cookedArgs);
memset (result, 0, sizeof (cookedArgs));
result->args = argNewFromString (string);
cArgRead (result);
return result;
}
extern cookedArgs* cArgNewFromArgv (char* const* const argv)
{
cookedArgs* const result = xMalloc (1, cookedArgs);
memset (result, 0, sizeof (cookedArgs));
result->args = argNewFromArgv (argv);
cArgRead (result);
return result;
}
extern cookedArgs* cArgNewFromFile (FILE* const fp)
{
cookedArgs* const result = xMalloc (1, cookedArgs);
memset (result, 0, sizeof (cookedArgs));
result->args = argNewFromFile (fp);
cArgRead (result);
return result;
}
extern cookedArgs* cArgNewFromLineFile (FILE* const fp)
{
cookedArgs* const result = xMalloc (1, cookedArgs);
memset (result, 0, sizeof (cookedArgs));
result->args = argNewFromLineFile (fp);
cArgRead (result);
return result;
}
extern void cArgDelete (cookedArgs* const current)
{
Assert (current != NULL);
argDelete (current->args);
memset (current, 0, sizeof (cookedArgs));
eFree (current);
}
static boolean cArgOptionPending (cookedArgs* const current)
{
boolean result = FALSE;
if (current->shortOptions != NULL)
if (*current->shortOptions != '\0')
result = TRUE;
return result;
}
extern boolean cArgOff (cookedArgs* const current)
{
Assert (current != NULL);
return (boolean) (argOff (current->args) && ! cArgOptionPending (current));
}
extern boolean cArgIsOption (cookedArgs* const current)
{
Assert (current != NULL);
return current->isOption;
}
extern const char* cArgItem (cookedArgs* const current)
{
Assert (current != NULL);
return current->item;
}
extern void cArgForth (cookedArgs* const current)
{
Assert (current != NULL);
Assert (! cArgOff (current));
if (cArgOptionPending (current))
parseShortOption (current);
else
{
Assert (! argOff (current->args));
argForth (current->args);
if (! argOff (current->args))
cArgRead (current);
else
{
current->isOption = FALSE;
current->longOption = FALSE;
current->shortOptions = NULL;
current->item = NULL;
current->parameter = NULL;
}
}
}
/*
* File extension and language mapping
*/
static void addExtensionList (stringList *const slist,
const char *const elist, const boolean clear)
{
char *const extensionList = eStrdup (elist);
const char *extension = NULL;
boolean first = TRUE;
if (clear)
{
verbose (" clearing\n");
stringListClear (slist);
}
verbose (" adding: ");
if (elist != NULL && *elist != '\0')
{
extension = extensionList;
if (elist [0] == EXTENSION_SEPARATOR)
++extension;
}
while (extension != NULL)
{
char *separator = strchr (extension, EXTENSION_SEPARATOR);
if (separator != NULL)
*separator = '\0';
verbose ("%s%s", first ? "" : ", ",
*extension == '\0' ? "(NONE)" : extension);
stringListAdd (slist, vStringNewInit (extension));
first = FALSE;
if (separator == NULL)
extension = NULL;
else
extension = separator + 1;
}
if (Option.verbose)
{
printf ("\n now: ");
stringListPrint (slist);
putchar ('\n');
}
eFree (extensionList);
}
static boolean isFalse (const char *parameter)
{
return (boolean) (
strcasecmp (parameter, "0" ) == 0 ||
strcasecmp (parameter, "n" ) == 0 ||
strcasecmp (parameter, "no" ) == 0 ||
strcasecmp (parameter, "off") == 0);
}
static boolean isTrue (const char *parameter)
{
return (boolean) (
strcasecmp (parameter, "1" ) == 0 ||
strcasecmp (parameter, "y" ) == 0 ||
strcasecmp (parameter, "yes") == 0 ||
strcasecmp (parameter, "on" ) == 0);
}
/* Determines whether the specified file name is considered to be a header
* file for the purposes of determining whether enclosed tags are global or
* static.
*/
extern boolean isIncludeFile (const char *const fileName)
{
boolean result = FALSE;
const char *const extension = fileExtension (fileName);
if (Option.headerExt != NULL)
result = stringListExtensionMatched (Option.headerExt, extension);
return result;
}
/*
* Specific option processing
*/
static void processEtagsInclude (
const char *const option, const char *const parameter)
{
if (! Option.etags)
error (FATAL, "Etags must be enabled to use \"%s\" option", option);
else
{
vString *const file = vStringNewInit (parameter);
if (Option.etagsInclude == NULL)
Option.etagsInclude = stringListNew ();
stringListAdd (Option.etagsInclude, file);
FilesRequired = FALSE;
}
}
static void processExcludeOption (
const char *const option __unused__, const char *const parameter)
{
const char *const fileName = parameter + 1;
if (parameter [0] == '\0')
freeList (&Excluded);
else if (parameter [0] == '@')
{
stringList* const sl = stringListNewFromFile (fileName);
if (sl == NULL)
error (FATAL | PERROR, "cannot open \"%s\"", fileName);
if (Excluded == NULL)
Excluded = sl;
else
stringListCombine (Excluded, sl);
verbose (" adding exclude patterns from %s\n", fileName);
}
else
{
vString *const item = vStringNewInit (parameter);
if (Excluded == NULL)
Excluded = stringListNew ();
stringListAdd (Excluded, item);
verbose (" adding exclude pattern: %s\n", parameter);
}
}
extern boolean isExcludedFile (const char* const name)
{
const char* base = baseFilename (name);
boolean result = FALSE;
if (Excluded != NULL)
{
result = stringListFileMatched (Excluded, base);
if (! result && name != base)
result = stringListFileMatched (Excluded, name);
}
#ifdef AMIGA
/* not a good solution, but the only one which works often */
if (! result)
result = (boolean) (strcmp (name, TagFile.name) == 0);
#endif
return result;
}
static void processExcmdOption (
const char *const option, const char *const parameter)
{
switch (*parameter)
{
case 'm': Option.locate = EX_MIX; break;
case 'n': Option.locate = EX_LINENUM; break;
case 'p': Option.locate = EX_PATTERN; break;
default:
error (FATAL, "Invalid value for \"%s\" option", option);
break;
}
}
static void processExtraTagsOption (
const char *const option, const char *const parameter)
{
struct sInclude *const inc = &Option.include;
const char *p = parameter;
boolean mode = TRUE;
int c;
if (*p != '+' && *p != '-')
{
inc->fileNames = FALSE;
inc->qualifiedTags = FALSE;
#if 0
inc->fileScope = FALSE;
#endif
}
while ((c = *p++) != '\0') switch (c)
{
case '+': mode = TRUE; break;
case '-': mode = FALSE; break;
case 'f': inc->fileNames = mode; break;
case 'q': inc->qualifiedTags = mode; break;
#if 0
case 'F': inc->fileScope = mode; break;
#endif
default: error(WARNING, "Unsupported parameter '%c' for \"%s\" option",
c, option);
break;
}
}
static void processFieldsOption (
const char *const option, const char *const parameter)
{
struct sExtFields *field = &Option.extensionFields;
const char *p = parameter;
boolean mode = TRUE;
int c;
if (*p != '+' && *p != '-')
{
field->access = FALSE;
field->fileScope = FALSE;
field->implementation = FALSE;
field->inheritance = FALSE;
field->kind = FALSE;
field->kindKey = FALSE;
field->kindLong = FALSE;
field->language = FALSE;
field->scope = FALSE;
}
while ((c = *p++) != '\0') switch (c)
{
case '+': mode = TRUE; break;
case '-': mode = FALSE; break;
case 'a': field->access = mode; break;
case 'f': field->fileScope = mode; break;
case 'm': field->implementation = mode; break;
case 'i': field->inheritance = mode; break;
case 'k': field->kind = mode; break;
case 'K': field->kindLong = mode; break;
case 'l': field->language = mode; break;
case 'n': field->lineNumber = mode; break;
case 's': field->scope = mode; break;
case 'S': field->signature = mode; break;
case 'z': field->kindKey = mode; break;
default: error(WARNING, "Unsupported parameter '%c' for \"%s\" option",
c, option);
break;
}
}
static void processFilterTerminatorOption (
const char *const option __unused__, const char *const parameter)
{
freeString (&Option.filterTerminator);
Option.filterTerminator = stringCopy (parameter);
}
static void processFormatOption (
const char *const option, const char *const parameter)
{
unsigned int format;
if (sscanf (parameter, "%u", &format) < 1)
error (FATAL, "Invalid value for \"%s\" option",option);
else if (format <= (unsigned int) MaxSupportedTagFormat)
Option.tagFileFormat = format;
else
error (FATAL, "Unsupported value for \"%s\" option", option);
}
static void printInvocationDescription (void)
{
printf (INVOCATION, getExecutableName ());
}
static void printOptionDescriptions (const optionDescription *const optDesc)
{
int i;
for (i = 0 ; optDesc [i].description != NULL ; ++i)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -