diff options
Diffstat (limited to 'option.cc')
-rw-r--r-- | option.cc | 189 |
1 files changed, 83 insertions, 106 deletions
@@ -1,4 +1,5 @@ #include "option.h" +#include "config.h" #include "debug.h" #include <iostream> @@ -6,149 +7,125 @@ #include "util.h" -void add_option_handler(std::list<option_t>& options, - const std::string& label, - const std::string& opt_chars, - option_handler& option) -{ - option_t opt; - - char buf[128]; - char * p = buf; - for (const char * q = label.c_str(); - *q && p - buf < 128; - q++) - if (*q == '_') - *p++ = '-'; - else - *p++ = *q; - *p = '\0'; - opt.long_opt = buf; - - if (! opt_chars.empty()) { - if (opt_chars[0] != ':') - opt.short_opt = opt_chars[0]; - - if (opt_chars[opt_chars.length() - 1] == ':') - opt.wants_arg = true; +namespace { + inline void process_option(option_t * opt, const char * arg = NULL) { + if (! opt->handled) { + opt->handler(arg); + opt->handled = true; + } } - opt.handler = &option; - - options.push_front(opt); -} - -namespace { - inline void process_option(const option_t& opt, - const char * arg = NULL) { - if (! opt.handler->handled) { - (*opt.handler)(arg); - opt.handler->handled = true; + option_t * search_options(option_t * array, const char * name) + { + int first = 0; + int last = CONFIG_OPTIONS_SIZE; + while (first <= last) { + int mid = (first + last) / 2; // compute mid point. + + int result; + if ((result = (int)name[0] - (int)array[mid].long_opt[0]) == 0) + result = std::strcmp(name, array[mid].long_opt); + + if (result > 0) + first = mid + 1; // repeat search in top half. + else if (result < 0) + last = mid - 1; // repeat search in bottom half. + else + return &array[mid]; } + return NULL; + } + + option_t * search_options(option_t * array, const char letter) + { + for (int i = 0; i < CONFIG_OPTIONS_SIZE; i++) + if (letter == array[i].short_opt) + return &array[i]; + return NULL; } } -bool process_option(std::list<option_t>& options, - const std::string& opt, const char * arg) +bool process_option(option_t * options, const std::string& name, + const char * arg) { - for (std::list<option_t>::iterator i = options.begin(); - i != options.end(); - i++) - if ((*i).long_opt == opt) { - if (! (*i).handler->handled) { - (*(*i).handler)(arg); - (*i).handler->handled = true; - return true; - } - break; - } - + option_t * opt = search_options(options, name.c_str()); + if (opt != NULL && ! opt->handled) { + opt->handler(arg); + opt->handled = true; + return true; + } return false; } -void process_arguments(std::list<option_t>& options, - int argc, char ** argv, const bool anywhere, - std::list<std::string>& args) +void process_arguments(option_t * options, int argc, char ** argv, + const bool anywhere, std::list<std::string>& args) { int index = 0; - for (char ** i = argv; index < argc; i++, index++) { + for (char ** i = argv; *i; i++) { if ((*i)[0] != '-') { if (anywhere) { args.push_back(*i); continue; } else { - for (; index < argc; i++, index++) + for (; *i; i++) args.push_back(*i); break; } } - // --long-option + // --long-option or -s again: + option_t * opt = NULL; + char * value = NULL; + if ((*i)[1] == '-') { if ((*i)[2] == '\0') break; - for (std::list<option_t>::iterator j = options.begin(); - j != options.end(); - j++) - if ((*j).wants_arg) { - if (const char * p = std::strchr(*i + 2, '=')) { - if ((*j).long_opt == std::string(*i + 2, p - (*i + 2))) { - process_option(*j, p + 1); - goto next; - } - } - else if ((*j).long_opt == *i + 2) { - if (++index >= argc) - throw option_error(std::string("missing option argument for ") + - *i); - process_option(*j, argv[index]); - i++; - goto next; - } - } - else if ((*j).long_opt == *i + 2) { - process_option(*j); - goto next; - } - - throw option_error(std::string("illegal option ") + *i); + char * name = *i + 2; + if (char * p = std::strchr(name, '=')) { + *p++ = '\0'; + value = p; + } + + opt = search_options(options, name); + if (opt == NULL) + throw option_error(std::string("illegal option --") + name); + + if (opt->wants_arg && value == NULL) { + value = *++i; + if (value == NULL) + throw option_error(std::string("missing option argument for --") + + name); + } + process_option(opt, value); } else { - for (std::list<option_t>::iterator j = options.begin(); - j != options.end(); - j++) - if ((*i)[1] == (*j).short_opt) { - if ((*j).wants_arg) { - if (++index >= argc) - throw option_error(std::string("missing argument for option ") + - *i); - process_option(*j, argv[index]); - i++; - goto next; - } else { - process_option(*j); - if ((*i)[2]) { - std::strcpy(*i + 1, *i + 2); - goto again; - } - goto next; - } - } - - throw option_error(std::string("illegal option -- ") + (*i)[1]); + char c = (*i)[1]; + opt = search_options(options, c); + if (opt == NULL) + throw option_error(std::string("illegal option -") + c); + + if (opt->wants_arg) { + value = *++i; + if (value == NULL) + throw option_error(std::string("missing option argument for -") + c); + } } + assert(opt); + assert(value == NULL || opt->wants_arg); + process_option(opt, value); + next: ; } } -void process_environment(std::list<option_t>& options, - char ** envp, const std::string& tag) +void process_environment(option_t * options, char ** envp, + const std::string& tag) { const char * tag_p = tag.c_str(); - int tag_len = tag.length(); + unsigned int tag_len = tag.length(); for (char ** p = envp; *p; p++) if (! tag_p || std::strncmp(*p, tag_p, tag_len) == 0) { |