|
Boost Users : |
From: Bryan Green (bgreen_at_[hidden])
Date: 2007-07-20 03:29:37
Bryan Green writes:
> Vladimir Prus writes:
> >
> > I assume you mean that, for example
> >
> > --foobar=10
> >
> > explicitly provides a value of 'foobar', and
> >
> > --foobar
>
> Precisely.
>
> Would it not be that, if not given, vm.count("arg") == 0; and if it was
> given, vm["arg"] would either be user-specified, or a default?
> Something like this perhaps:
>
> desc.add_options()
> ("listen,l", po::value<int>()->optional_token()->default_value(5555),
> "listen on a port")
> ;
> ...
> bool do_listening = false;
> if (vm.count() != 0) {
> do_listening = true;
> listen_port = vm["listen"].as<int>();
> }
Here is my (working) extension of program_options to support
GNU-longopt-style optional arguments.
It requires two components: an 'extra_parser', and an extended 'typed_value'.
It would be nice to see program_options modified in such a way that the
'extra_parser' was not necessary here (something I'd be happy to attempt).
I could have overridden the 'validate' function instead of extending
'typed_value', but I wanted a solution that was type-independent, and could
therefore be incorporated into the program_options library.
<code>
namespace po_ext {
template <class T, class charT = char>
class typed_value : public po::typed_value<T,charT>
{
public:
typed_value(T* store_to)
: po::typed_value<T,charT>(store_to) {}
typed_value* optional_token(const T &v)
{
m_optional_default_value = boost::any(v);
m_optional_default_value_as_text =
boost::lexical_cast<std::string>(v);
return this;
}
typed_value* optional_token(const T &v, const std::string& textual)
{
m_optional_default_value = boost::any(v);
m_optional_default_value_as_text = textual;
return this;
}
public: // value semantic overrides
std::string name() const {
if (!m_optional_default_value.empty() &&
!m_optional_default_value_as_text.empty())
{
return "[=" + m_optional_default_value_as_text + "]";
}
else
return po::typed_value<T,charT>::name();
}
unsigned min_tokens() const
{
if (!m_optional_default_value.empty())
return 0;
else
return po::typed_value<T,charT>::min_tokens();
}
void xparse(boost::any& value_store,
const std::vector<std::basic_string<charT> >& new_tokens)
const
{
if (!new_tokens.empty() || m_optional_default_value.empty())
po::validate(value_store, new_tokens, (T*)0, 0);
}
bool apply_default(boost::any& value_store) const
{
if (!m_optional_default_value.empty())
return false;
else
return po::typed_value<T,charT>::apply_default(value_store);
}
void notify(const boost::any& value_store) const {
if (!m_optional_default_value.empty() && value_store.empty())
po::typed_value<T,charT>::notify(m_optional_default_value);
else
po::typed_value<T,charT>::notify(value_store);
}
private:
boost::any m_optional_default_value;
std::string m_optional_default_value_as_text;
};
template <class T>
typed_value<T>*
value(T *v)
{
typed_value<T>* r = new typed_value<T>(v);
return r;
}
}
pair<string, string> parse_opt(const string& s)
{
if (s.find("--proxy=") == 0) {
return make_pair(string("proxy"), s.substr(8));
} else {
return make_pair(string(), string());
}
}
enum { DefaultProxyPort = 8869u };
int main(int argc,char *argv[])
{
uint16_t proxy_port;
po::options_description desc("options");
desc.add_options()
("proxy,p",
po_ext::value<uint16_t>(&proxy_port)->optional_token(DefaultProxyPort),
"run the proxy service")
;
po::variables_map vm;
try {
po::store(po::command_line_parser(argc, argv).options(desc)
.extra_parser(parse_opt).run(), vm);
po::notify(vm);
} catch (exception &e) {
cout << e.what() << endl;
return EXIT_FAILURE;
}
if (vm.count("proxy"))
enable_the_proxy(proxy_port);
do_your_thing();
return EXIT_SUCCESS;
}
</code>
Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net