Boost logo

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