aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDeterminant <ted.sybil@gmail.com>2018-07-16 02:31:40 -0400
committerDeterminant <ted.sybil@gmail.com>2018-07-16 02:31:40 -0400
commit766ef262f1413eaef755ea567f69c25a1d26351d (patch)
tree9ed406a7cd824e99e7ed9348715b6f7b690e87f8
parent9cd1d894ae108e93209aa12d2707613bd8bc47a9 (diff)
improve argument parsing
-rw-r--r--include/salticidae/stream.h2
-rw-r--r--include/salticidae/util.h52
-rw-r--r--src/util.cpp70
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());
}
}