diff options
author | John Wiegley <johnw@newartisans.com> | 2004-08-13 04:36:24 -0400 |
---|---|---|
committer | John Wiegley <johnw@newartisans.com> | 2004-08-13 04:36:24 -0400 |
commit | a3342146041a0ec0e5d58ba5b942944ee00e6d37 (patch) | |
tree | 3d272541c2b92aaaae6dd9233b2b334214b0a141 | |
parent | 152b10dbbd83535062ea467bd01afe4837975632 (diff) | |
download | fork-ledger-a3342146041a0ec0e5d58ba5b942944ee00e6d37.tar.gz fork-ledger-a3342146041a0ec0e5d58ba5b942944ee00e6d37.tar.bz2 fork-ledger-a3342146041a0ec0e5d58ba5b942944ee00e6d37.zip |
added option.cc and option.h
-rw-r--r-- | option.cc | 132 | ||||
-rw-r--r-- | option.h | 51 |
2 files changed, 183 insertions, 0 deletions
diff --git a/option.cc b/option.cc new file mode 100644 index 00000000..586037b1 --- /dev/null +++ b/option.cc @@ -0,0 +1,132 @@ +#include "option.h" + +#include <iostream> +#include <cstdarg> + +option_handler::option_handler(const std::string& label, + const std::string& opt_chars, + const bool _multiple) + : handled(false), multiple(_multiple) +{ + option_t opt; + + for (const char * q = label.c_str(); *q; q++) + if (*q == '_') + opt.long_opt += '-'; + else + opt.long_opt += *q; + + handlers.insert(option_handler_pair(opt.long_opt, this)); + + 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; + } + + opt.handler = this; + + options.push_back(opt); +} + +bool process_option(const std::string& opt, const char * arg) +{ + option_handler_map::iterator handler = option_handler::handlers.find(opt); + if (handler != option_handler::handlers.end() && + (! (*handler).second->handled || (*handler).second->multiple)) { + (*handler).second->handle_option(arg); + (*handler).second->handled = true; + return true; + } + return false; +} + +static inline void process_option(const option_t& opt, + const char * arg = NULL) { + if (! opt.handler->handled || opt.handler->multiple) { + opt.handler->handle_option(arg); + opt.handler->handled = true; + } +} + +void process_arguments(std::vector<char *>& args, int argc, char ** argv) +{ + int index = 1; + for (char ** i = argv + 1; index < argc; i++, index++) { + if ((*i)[0] != '-') { + args.push_back(*i); + continue; + } + + // --long-option + again: + if ((*i)[1] == '-') { + for (std::vector<option_t>::iterator j + = option_handler::options.begin(); + j != option_handler::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) { + process_option(*j, argv[++index]); + goto next; + } + } + else if ((*j).long_opt == *i + 2) { + process_option(*j); + goto next; + } + + std::cerr << "Error: illegal option " << *i << std::endl; + std::exit(1); + } else { + for (std::vector<option_t>::iterator j + = option_handler::options.begin(); + j != option_handler::options.end(); + j++) + if ((*i)[1] == (*j).short_opt) { + if ((*j).wants_arg) { + process_option(*j, argv[++index]); + goto next; + } else { + process_option(*j); + if ((*i)[2]) { + std::strcpy(*i + 1, *i + 2); + goto again; + } + goto next; + } + } + + std::cerr << "Error: illegal option -- " << (*i)[1] << std::endl; + std::exit(1); + } + + next: + ; + } +} + +void process_environment(char ** envp) +{ + for (char ** p = envp; *p; p++) + if (std::strncmp(*p, "LEDGER_", 7) == 0) { + std::string opt; + char * q; + for (q = *p + 7; *q && *q != '='; q++) + if (*q == '_') + opt += '-'; + else + opt += std::tolower(*q); + + if (*q == '=') + process_option(opt, q + 1); + } +} diff --git a/option.h b/option.h new file mode 100644 index 00000000..33b54933 --- /dev/null +++ b/option.h @@ -0,0 +1,51 @@ +#ifndef _OPTION_H +#define _OPTION_H + +#include <map> +#include <vector> +#include <string> + +struct option_handler; + +struct option_t { + char short_opt; + std::string long_opt; + bool wants_arg; + option_handler * handler; + + option_t() : short_opt(0), wants_arg(false) {} +}; + +typedef std::map<const std::string, option_handler *> option_handler_map; +typedef std::pair<const std::string, option_handler *> option_handler_pair; + +struct option_handler { + bool handled; + bool multiple; + + static std::vector<option_t> options; + static option_handler_map handlers; + + option_handler(const std::string& label, + const std::string& opt_chars, + const bool _multiple); + + virtual void handle_option(const char * arg = NULL) = 0; +}; + +bool process_option(const std::string& opt, const char * arg = NULL); +void process_arguments(std::vector<char *>& args, int argc, char ** argv); +void process_environment(char ** envp); + +#define DEF_OPT_HANDLERS() \ + std::vector<option_t> option_handler::options; \ + option_handler_map option_handler::handlers + +#define OPT_BEGIN(tag, chars, multi) \ + static struct tag ## _handler : public option_handler { \ + tag ## _handler() : option_handler(#tag, chars, multi) {} \ + virtual void handle_option(const char * optarg) + +#define OPT_END(tag) } tag ## _handler_obj + +#endif // _OPTION_H |