aboutsummaryrefslogtreecommitdiff
path: root/fesvr/option_parser.cc
diff options
context:
space:
mode:
Diffstat (limited to 'fesvr/option_parser.cc')
-rw-r--r--fesvr/option_parser.cc51
1 files changed, 51 insertions, 0 deletions
diff --git a/fesvr/option_parser.cc b/fesvr/option_parser.cc
new file mode 100644
index 0000000..72daec4
--- /dev/null
+++ b/fesvr/option_parser.cc
@@ -0,0 +1,51 @@
+// See LICENSE for license details.
+
+#include "option_parser.h"
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <cassert>
+
+void option_parser_t::option(char c, const char* s, int arg, std::function<void(const char*)> action)
+{
+ opts.push_back(option_t(c, s, arg, action));
+}
+
+const char* const* option_parser_t::parse(const char* const* argv0)
+{
+ assert(argv0);
+ const char* const* argv = argv0 + 1;
+ for (const char* opt; (opt = *argv) != NULL && opt[0] == '-'; argv++)
+ {
+ bool found = false;
+ for (auto it = opts.begin(); !found && it != opts.end(); it++)
+ {
+ size_t slen = it->str ? strlen(it->str) : 0;
+ bool chr_match = opt[1] != '-' && it->chr && opt[1] == it->chr;
+ bool str_match = opt[1] == '-' && slen && strncmp(opt+2, it->str, slen) == 0;
+ if (chr_match || (str_match && (opt[2+slen] == '=' || opt[2+slen] == '\0')))
+ {
+ const char* optarg =
+ chr_match ? (opt[2] ? &opt[2] : NULL) :
+ opt[2+slen] ? &opt[3+slen] :
+ it->arg ? *(++argv) : NULL;
+ if (optarg && !it->arg)
+ error("no argument allowed for option", *argv0, opt);
+ if (!optarg && it->arg)
+ error("argument required for option", *argv0, opt);
+ it->func(optarg);
+ found = true;
+ }
+ }
+ if (!found)
+ error("unrecognized option", *argv0, opt);
+ }
+ return argv;
+}
+
+void option_parser_t::error(const char* msg, const char* argv0, const char* arg)
+{
+ fprintf(stderr, "%s: %s %s\n", argv0, msg, arg ? arg : "");
+ if (helpmsg) helpmsg();
+ exit(1);
+}