diff options
Diffstat (limited to 'decoder/program_options.h')
-rwxr-xr-x | decoder/program_options.h | 283 |
1 files changed, 283 insertions, 0 deletions
diff --git a/decoder/program_options.h b/decoder/program_options.h new file mode 100755 index 00000000..251f5680 --- /dev/null +++ b/decoder/program_options.h @@ -0,0 +1,283 @@ +#ifndef PROGRAM_OPTIONS_H +#define PROGRAM_OPTIONS_H + +/* wraps boost options_description as printable_opts - show the options values used as well as defaults in usage or log messages. boost program options library lacks any concept of printing configured values; it only supports parsing them from strings */ + +#ifdef _WIN32 +#include <iso646.h> +#endif +#include <boost/program_options.hpp> +#include <boost/function.hpp> +#include <boost/shared_ptr.hpp> +#include <stdexcept> +#include <iosfwd> + + +template <class T> +boost::program_options::typed_value<T>* +defaulted_value(T *v) +{ + return boost::program_options::value<T>(v)->default_value(*v); +} + +inline void program_options_fatal(std::string const& msg) { + throw std::runtime_error(msg); +} + + +inline std::string const& get_single_arg(boost::any& v,std::vector<std::string> const& values) +{ + boost::program_options::validators::check_first_occurrence(v); + return boost::program_options::validators::get_single_string(values); +} + +template <class I> +void must_complete_read(I &in,std::string const& msg="Couldn't parse") +{ + char c; + if (in.bad()) + program_options_fatal(msg + " - failed input"); + if (in >> c) + program_options_fatal(msg + " - got extra char: " + std::string(c,1)); +} + +template <class Ostream> +struct any_printer : public boost::function<void (Ostream &,boost::any const&)> +{ + typedef boost::function<void (Ostream &,boost::any const&)> F; + + template <class T> + struct typed_print + { + void operator()(Ostream &o,boost::any const& t) const + { + o << *boost::any_cast<T const>(&t); + } + }; + + template <class T> + static + void typed_print_template(Ostream &o,boost::any const& t) + { + o << *boost::any_cast<T const>(&t); + } + + any_printer() {} + + any_printer(const any_printer& x) + : F(static_cast<F const&>(x)) + {} + + template <class T> + explicit any_printer(T const* tag) : F(typed_print<T>()) { + } + + template <class T> + void set() + { + F f(typed_print<T>()); + swap(f); + } +}; + +// have to wrap regular options_description and store our own tables because +// author didn't make enough stuff protected/public or add a virtual print +// method to value_semantic +template <class Ostream> +struct printable_options_description + : public boost::program_options::options_description +{ + typedef printable_options_description<Ostream> self_type; + typedef boost::program_options::options_description options_description; + typedef boost::program_options::option_description option_description; + typedef boost::shared_ptr<self_type> group_type; + typedef std::vector<group_type > groups_type; + + struct printable_option + { + typedef boost::shared_ptr<option_description> OD; + + any_printer<Ostream> print; + OD od; + bool in_group; + + std::string const& name() + { return od->long_name(); } + + std::string const& description() + { return od->description(); } + + std::string const& vmkey() + { + return od->key(name()); + } + template <class T> + printable_option(T *tag, OD const& od) : print(tag),od(od),in_group(false) {} + printable_option() : in_group(false) {} + }; + typedef std::vector<printable_option > options_type; + BOOST_STATIC_CONSTANT(unsigned,default_linewrap=80); // options_description::m_default_line_length + printable_options_description(unsigned line_length = default_linewrap) : + options_description(line_length) {} + + printable_options_description(const std::string& caption, + unsigned line_length = default_linewrap) + : options_description(caption,line_length), caption(caption) {} + + self_type &add_options() + { return *this; } + + template <class T,class C> + self_type & + operator()(char const* name, + boost::program_options::typed_value<T,C> *val, + char const*description=NULL) + { + printable_option opt((T *)0,simple_add(name,val,description)); + pr_options.push_back(opt); + return *this; + } + + self_type& + add(self_type const& desc) + { + options_description::add(desc); + groups.push_back(group_type(new self_type(desc))); + for (typename options_type::const_iterator i=desc.pr_options.begin(),e=desc.pr_options.end(); + i!=e;++i) { + pr_options.push_back(*i); + pr_options.back().in_group=true; + } + return *this; + } + + void print_option(Ostream &o, + printable_option &opt, + boost::program_options::variable_value const & var, + bool only_value=false) + { + using namespace boost; + using namespace boost::program_options; + using namespace std; + string const& name=opt.name(); + if (!only_value) { + if (var.defaulted()) + o << "#DEFAULTED# "; + if (var.empty()) { + o << "#EMPTY# "<<name; + return; + } + o << name<<" = "; + } + opt.print(o,var.value()); + } + + enum { SHOW_DEFAULTED=0x1 + , SHOW_EMPTY=0x2 + , SHOW_DESCRIPTION=0x4 + , SHOW_HIERARCHY=0x8 + , SHOW_ALL=0x0FFF + , SHOW_HELP=0x1000 + }; + + void print(Ostream &o, + boost::program_options::variables_map &vm, + int show_flags=SHOW_DESCRIPTION & SHOW_DEFAULTED & SHOW_HIERARCHY) + { + const bool show_defaulted=bool(show_flags & SHOW_DEFAULTED); + const bool show_description=bool(show_flags & SHOW_DESCRIPTION); + const bool hierarchy=bool(show_flags & SHOW_HIERARCHY); + const bool show_empty=bool(show_flags & SHOW_EMPTY); + const bool show_help=bool(show_flags & SHOW_HELP); + + using namespace boost::program_options; + using namespace std; + o << "### " << caption << endl; + for (typename options_type::iterator i=pr_options.begin(),e=pr_options.end(); + i!=e;++i) { + printable_option & opt=*i; + if (!show_help && opt.name()=="help") + continue; + if (hierarchy and opt.in_group) + continue; + variable_value const & var=vm[opt.vmkey()]; + if (var.defaulted() && !show_defaulted) + continue; + if (var.empty() && !show_empty) + continue; + if (show_description) + o << "# " << opt.description() << endl; + print_option(o,opt,var); + o << endl; + } + o << endl; + if (hierarchy) + for (typename groups_type::iterator i=groups.begin(),e=groups.end(); + i!=e;++i) + (*i)->print(o,vm,show_flags); + } + +/// parses arguments, then stores/notifies from opts->vm. returns unparsed +/// options and positional arguments, but if not empty, throws exception unless +/// allow_unrecognized_positional is true + std::vector<std::string> + parse_options(int argc,char **argv, + boost::program_options::variables_map &vm, + boost::program_options::positional_options_description *po=NULL, + bool allow_unrecognized_positional=false, + bool allow_unrecognized_opts=false) + { + using namespace boost::program_options; + using namespace std; + command_line_parser cl(argc,argv); + cl.options(*this); + if (po) + cl.positional(*po); + if (allow_unrecognized_opts) + cl.allow_unregistered(); + parsed_options parsed=cl.run(); + vector<string> unparsed=collect_unrecognized(parsed.options, + po ? exclude_positional : include_positional); + if (!allow_unrecognized_positional) { + if (!unparsed.empty()) + program_options_fatal("Unrecognized argument: "+unparsed.front()); + } + store(parsed,vm); + notify(vm); + return unparsed; + } + + std::vector<std::string> + parse_options(int argc,char const*argv[], + boost::program_options::variables_map &vm, + boost::program_options::positional_options_description *po=NULL, + bool allow_unrecognized_positional=false, + bool allow_unrecognized_opts=false) + { + return parse_options(argc,const_cast<char **>(argv),vm,po + ,allow_unrecognized_positional,allow_unrecognized_opts); + } + +private: + groups_type groups; + options_type pr_options; + std::string caption; + boost::shared_ptr<option_description> + simple_add(const char* name, + const boost::program_options::value_semantic* s, + const char * description = NULL) + { + typedef option_description OD; + boost::shared_ptr<OD> od( + (description ? new OD(name,s,description) : new OD(name,s)) + ); + options_description::add(od); + return od; + } +}; + +typedef printable_options_description<std::ostream> printable_opts; + + + +#endif |