diff options
author | Determinant <[email protected]> | 2018-07-16 02:31:40 -0400 |
---|---|---|
committer | Determinant <[email protected]> | 2018-07-16 02:31:40 -0400 |
commit | 766ef262f1413eaef755ea567f69c25a1d26351d (patch) | |
tree | 9ed406a7cd824e99e7ed9348715b6f7b690e87f8 | |
parent | 9cd1d894ae108e93209aa12d2707613bd8bc47a9 (diff) |
improve argument parsing
-rw-r--r-- | include/salticidae/stream.h | 2 | ||||
-rw-r--r-- | include/salticidae/util.h | 52 | ||||
-rw-r--r-- | src/util.cpp | 70 |
3 files changed, 80 insertions, 44 deletions
diff --git a/include/salticidae/stream.h b/include/salticidae/stream.h index 7273882..efca394 100644 --- a/include/salticidae/stream.h +++ b/include/salticidae/stream.h @@ -275,7 +275,7 @@ class _Bits { using _impl_type = T; static const uint32_t bit_per_datum = sizeof(_impl_type) * 8; static const uint32_t shift_per_datum = log2<bit_per_datum>::value; - static_assert(bit_per_datum == 1 << shift_per_datum); + static_assert(bit_per_datum == 1 << shift_per_datum, "int type must have 2^n bits"); BoxObj<_impl_type[]> data; uint32_t nbits; uint32_t ndata; diff --git a/include/salticidae/util.h b/include/salticidae/util.h index ab052de..47a260a 100644 --- a/include/salticidae/util.h +++ b/include/salticidae/util.h @@ -63,19 +63,15 @@ class Logger { void write(const char *tag, const char *fmt, va_list ap); public: - Logger(const char *prefix): - output(stderr), opened(false), prefix(prefix) {} - Logger(const char *prefix, FILE *f): - output(f), opened(false), prefix(prefix) {} + Logger(const char *prefix, FILE *file = stderr): + output(file), opened(false), prefix(prefix) {} Logger(const char *prefix, const char *filename): opened(true), prefix(prefix) { if ((output = fopen(filename, "w")) == nullptr) - throw SalticidaeError("logger cannot open file"); + throw SalticidaeError("logger cannot open file %s", filename); } - ~Logger() { - if (opened) fclose(output); - } + ~Logger() { if (opened) fclose(output); } void debug(const char *fmt, ...); void info(const char *fmt, ...); @@ -237,27 +233,49 @@ class Config { }; private: + class OptValConf: public OptVal { + Config *config; + public: + template<typename... Args> + static RcObj<OptValConf> create(Args... args) { + return new OptValConf(args...); + } + OptValConf(Config *config): config(config) {} + void set_val(const std::string &fname) override { + if (config->load(fname)) + SALTICIDAE_LOG_INFO("loading extra configuration from %s", fname.c_str()); + else + SALTICIDAE_LOG_INFO("configuration file %s not found", fname.c_str()); + } + std::string &get() = delete; + }; + struct Opt { std::string optname; std::string optdoc; optval_t optval; Action action; struct option opt; + char short_opt; Opt(const std::string &optname, const std::string &optdoc, - const optval_t &optval, Action action, int idx); + const optval_t &optval, Action action, + char short_opt, + int idx); Opt(Opt &&other): optname(std::move(other.optname)), optdoc(std::move(other.optdoc)), optval(std::move(other.optval)), action(other.action), - opt(other.opt) { opt.name = this->optname.c_str(); } + opt(other.opt), + short_opt(other.short_opt) { + opt.name = this->optname.c_str(); + } }; - std::unordered_map<std::string, Opt> conf; - std::vector<Opt *> getopt_order; + std::unordered_map<std::string, Opt *> conf; + std::vector<BoxObj<Opt>> opts; std::string conf_fname; - RcObj<OptValStr> opt_val_conf; - int conf_idx; + RcObj<OptValConf> opt_val_conf; void update(const std::string &optname, const char *optval); void update(Opt &opt, const char *optval); @@ -265,14 +283,14 @@ class Config { public: Config(const std::string &conf_fname): conf_fname(conf_fname), - opt_val_conf(new OptValStr(this->conf_fname)) { - conf_idx = getopt_order.size(); - add_opt("conf", opt_val_conf, SET_VAL, "load options from a file"); + opt_val_conf(OptValConf::create(this)) { + add_opt("conf", opt_val_conf, SET_VAL, 'c', "load options from a file"); } ~Config() {} void add_opt(const std::string &optname, const optval_t &optval, Action action, + char short_opt = -1, const std::string &optdoc = ""); bool load(const std::string &fname); size_t parse(int argc, char **argv); diff --git a/src/util.cpp b/src/util.cpp index 580306c..2adb997 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -135,23 +135,30 @@ void ElapsedTime::stop(bool show_info) { } Config::Opt::Opt(const std::string &optname, const std::string &optdoc, - const optval_t &optval, Action action, int idx): - optname(optname), optdoc(optdoc), optval(optval), action(action) { + const optval_t &optval, Action action, + char short_opt, + int idx): + optname(optname), optdoc(optdoc), + optval(optval), action(action), + short_opt(short_opt) { opt.name = this->optname.c_str(); opt.has_arg = action == SWITCH_ON ? no_argument : required_argument; opt.flag = nullptr; - opt.val = idx; + opt.val = 0x100 + idx; } void Config::add_opt(const std::string &optname, const optval_t &optval, Action action, + char short_opt, const std::string &optdoc) { if (conf.count(optname)) throw SalticidaeError("option name already exists"); - auto it = conf.insert( - std::make_pair(optname, - Opt(optname, optdoc, - optval, action, getopt_order.size()))).first; - getopt_order.push_back(&it->second); + opts.push_back(new Opt(optname, optdoc, + optval, action, short_opt, + opts.size())); + auto opt = opts.back().get(); + conf.insert(std::make_pair(optname, opt)); + if (short_opt != -1) + conf.insert(std::make_pair(std::string(1, short_opt), opt)); } void Config::update(Opt &p, const char *optval) { @@ -167,7 +174,7 @@ void Config::update(Opt &p, const char *optval) { void Config::update(const std::string &optname, const char *optval) { assert(conf.count(optname)); - update(conf.find(optname)->second, optval); + update(*(conf.find(optname)->second), optval); } bool Config::load(const std::string &fname) { @@ -208,36 +215,47 @@ size_t Config::parse(int argc, char **argv) { if (load(conf_fname)) SALTICIDAE_LOG_INFO("loaded configuration from %s", conf_fname.c_str()); - size_t nopts = getopt_order.size(); + size_t nopts = opts.size(); struct option *longopts = (struct option *)malloc( sizeof(struct option) * (nopts + 1)); int ind; + std::string shortopts; for (size_t i = 0; i < nopts; i++) - longopts[i] = getopt_order[i]->opt; - longopts[nopts] = {0, 0, 0, 0}; - for (;;) { - int id = getopt_long(argc, argv, "", longopts, &ind); - if (id == -1 || id == '?') break; - update(*getopt_order[id], optarg); - if (id == conf_idx) + const auto &opt = opts[i]; + longopts[i] = opt->opt; + if (opt->short_opt != -1) { - auto &fname = opt_val_conf->get(); - if (load(fname)) - SALTICIDAE_LOG_INFO("loading extra configuration from %s", fname.c_str()); - else - SALTICIDAE_LOG_INFO("configuration file %s not found", fname.c_str()); + shortopts += opt->short_opt; + if (longopts[i].has_arg == required_argument) + shortopts += ":"; } } + longopts[nopts] = {0, 0, 0, 0}; + for (;;) + { + int id = getopt_long(argc, argv, shortopts.c_str(), longopts, &ind); + if (id == -1) + break; + if (id == '?') + throw SalticidaeError("invalid option format"); + if (id >= 0x100) + update(*(opts[id - 0x100]), optarg); + else + update(std::string(1, (char)id), optarg); + } return optind; } void Config::print_help(FILE *output) { - for (auto opt: getopt_order) + for (const auto &opt: opts) { - fprintf(output, "--%s\t\t%s\n", - opt->optname.c_str(), - opt->optdoc.c_str()); + fprintf(output, "--%s\t\t", opt->optname.c_str()); + if (opt->short_opt != -1) + fprintf(output, "-%c\t", opt->short_opt); + else + fprintf(output, "\t\t"); + fprintf(output, "%s\n", opt->optdoc.c_str()); } } |