summaryrefslogtreecommitdiff
path: root/option.cc
diff options
context:
space:
mode:
Diffstat (limited to 'option.cc')
-rw-r--r--option.cc189
1 files changed, 83 insertions, 106 deletions
diff --git a/option.cc b/option.cc
index c9000a20..043d51dc 100644
--- a/option.cc
+++ b/option.cc
@@ -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) {