static int ensureSetting ( OptionProcessingInformation *info, const OptionEntry *option, const char *value ) { unsigned char *ensured = &info->ensuredSettings[option->letter]; if (!*ensured) { *ensured = 1; if (option->argument) { if (option->setting.string) { if (option->flags & OPT_Extend) { if (!extendSetting(option->setting.string, value, 1)) return 0; } else { if (!(*option->setting.string = strdup(value))) { logMallocError(); return 0; } } } } else { if (option->setting.flag) { if (wordMeansTrue(value)) { *option->setting.flag = 1; } else if (wordMeansFalse(value)) { *option->setting.flag = 0; } else if (!(option->flags & OPT_Extend)) { logMessage(LOG_ERR, "%s: %s", gettext("invalid flag setting"), value); info->warning = 1; } else { int count; if (isInteger(&count, value) && (count >= 0)) { *option->setting.flag = count; } else { logMessage(LOG_ERR, "%s: %s", gettext("invalid counter setting"), value); info->warning = 1; } } } } } return 1; }
static void processCommandLine ( OptionProcessingInformation *info, int *argumentCount, char ***argumentVector, const char *argumentsSummary ) { int lastOptInd = -1; const char resetPrefix = '+'; const char *reset = NULL; int resetLetter; #ifdef ALLOW_DOS_OPTION_SYNTAX const char dosPrefix = '/'; int dosSyntax = 0; #endif /* ALLOW_DOS_OPTION_SYNTAX */ int optHelp = 0; int optHelpAll = 0; const OptionEntry *optionEntries[0X100]; char shortOptions[1 + (info->optionCount * 2) + 1]; #ifdef HAVE_GETOPT_LONG struct option longOptions[(info->optionCount * 2) + 1]; { struct option *opt = longOptions; for (unsigned int index=0; index<info->optionCount; ++index) { const OptionEntry *entry = &info->optionTable[index]; if (entry->word) { opt->name = entry->word; opt->has_arg = entry->argument? required_argument: no_argument; opt->flag = NULL; opt->val = entry->letter; opt += 1; if (!entry->argument && entry->setting.flag) { static const char *const noPrefix = "no-"; size_t noLength = strlen(noPrefix); char *name; if (strncasecmp(noPrefix, entry->word, noLength) == 0) { name = strdup(&entry->word[noLength]); } else { size_t size = noLength + strlen(entry->word) + 1; if ((name = malloc(size))) { snprintf(name, size, "%s%s", noPrefix, entry->word); } } if (name) { opt->name = name; opt->has_arg = no_argument; opt->flag = &resetLetter; opt->val = entry->letter; opt += 1; } else { logMallocError(); } } } } memset(opt, 0, sizeof(*opt)); } #endif /* HAVE_GETOPT_LONG */ for (unsigned int index=0; index<0X100; index+=1) { optionEntries[index] = NULL; } { char *opt = shortOptions; *opt++ = '+'; for (unsigned int index=0; index<info->optionCount; ++index) { const OptionEntry *entry = &info->optionTable[index]; optionEntries[entry->letter] = entry; *opt++ = entry->letter; if (entry->argument) *opt++ = ':'; if (entry->argument) { if (entry->setting.string) *entry->setting.string = NULL; } else { if (entry->setting.flag) *entry->setting.flag = 0; } } *opt = 0; } if (*argumentCount > 1) #ifdef ALLOW_DOS_OPTION_SYNTAX if (*(*argumentVector)[1] == dosPrefix) dosSyntax = 1; #endif /* ALLOW_DOS_OPTION_SYNTAX */ opterr = 0; optind = 1; while (1) { int option; char prefix = '-'; if (optind == *argumentCount) { option = -1; } else { char *argument = (*argumentVector)[optind]; #ifdef ALLOW_DOS_OPTION_SYNTAX if (dosSyntax) { prefix = dosPrefix; optind++; if (*argument != dosPrefix) { option = -1; } else { char *name = argument + 1; size_t nameLength = strcspn(name, ":"); char *value = (nameLength == strlen(name))? NULL: (name + nameLength + 1); const OptionEntry *entry; if (nameLength == 1) { entry = optionEntries[option = *name]; } else { int count = info->optionCount; entry = info->optionTable; option = -1; while (count--) { if (entry->word) { size_t wordLength = strlen(entry->word); if ((wordLength == nameLength) && (strncasecmp(entry->word, name, wordLength) == 0)) { option = entry->letter; break; } } entry++; } if (option < 0) { option = 0; entry = NULL; } } optopt = option; optarg = NULL; if (!entry) { option = '?'; } else if (entry->argument) { if (!(optarg = value)) option = ':'; } else if (value) { if (!entry->setting.flag) goto dosBadFlagValue; if (!wordMeansTrue(value)) { if (wordMeansFalse(value)) { resetLetter = option; option = 0; } else { dosBadFlagValue: option = '?'; } } } } } else #endif /* ALLOW_DOS_OPTION_SYNTAX */ if (reset) { prefix = resetPrefix; if (!(option = *reset++)) { reset = NULL; optind++; continue; } { const OptionEntry *entry = optionEntries[option]; if (entry && !entry->argument && entry->setting.flag) { resetLetter = option; option = 0; } else { optopt = option; option = '?'; } } } else { if (optind != lastOptInd) { lastOptInd = optind; if ((reset = (*argument == resetPrefix)? argument+1: NULL)) continue; } #ifdef HAVE_GETOPT_LONG option = getopt_long(*argumentCount, *argumentVector, shortOptions, longOptions, NULL); #else /* HAVE_GETOPT_LONG */ option = getopt(*argumentCount, *argumentVector, shortOptions); #endif /* HAVE_GETOPT_LONG */ } } if (option == -1) break; /* continue on error as much as possible, as often we are typing blind * and won't even see the error message unless the display comes up. */ switch (option) { default: { const OptionEntry *entry = optionEntries[option]; if (entry->argument) { if (!*optarg) { info->ensuredSettings[option] = 0; break; } if (entry->setting.string) { if (entry->flags & OPT_Extend) { extendStringSetting(entry->setting.string, optarg, 0); } else { changeStringSetting(entry->setting.string, optarg); } } } else { if (entry->setting.flag) { if (entry->flags & OPT_Extend) { *entry->setting.flag += 1; } else { *entry->setting.flag = 1; } } } info->ensuredSettings[option] = 1; break; } case 0: { const OptionEntry *entry = optionEntries[resetLetter]; *entry->setting.flag = 0; info->ensuredSettings[resetLetter] = 1; break; } case '?': logMessage(LOG_ERR, "%s: %c%c", gettext("unknown option"), prefix, optopt); info->syntaxError = 1; break; case ':': /* An invalid option has been specified. */ logMessage(LOG_ERR, "%s: %c%c", gettext("missing operand"), prefix, optopt); info->syntaxError = 1; break; case 'H': /* help */ optHelpAll = 1; case 'h': /* help */ optHelp = 1; break; } } *argumentVector += optind, *argumentCount -= optind; if (optHelp) { printHelp(info, stdout, 79, argumentsSummary, optHelpAll); info->exitImmediately = 1; } #ifdef HAVE_GETOPT_LONG { struct option *opt = longOptions; while (opt->name) { if (opt->flag) free((char *)opt->name); opt += 1; } } #endif /* HAVE_GETOPT_LONG */ }