From f5ec3d13ad215c488ea6a3838054711b8d9a0733 Mon Sep 17 00:00:00 2001 From: Simon Fels Date: Mon, 6 Feb 2017 07:42:28 +0100 Subject: [PATCH] Add BoolSwitchFlag class to model boolean input parameters --- src/anbox/cli.cpp | 7 ++-- src/anbox/cli.h | 87 ++++++++++++++++++++++++++++++++++------------- 2 files changed, 68 insertions(+), 26 deletions(-) diff --git a/src/anbox/cli.cpp b/src/anbox/cli.cpp index c40be65..2e828bc 100644 --- a/src/anbox/cli.cpp +++ b/src/anbox/cli.cpp @@ -44,9 +44,10 @@ static constexpr const char* option = " --%1% %2%"; void add_to_desc_for_flags(po::options_description& desc, const std::set& flags) { for (auto flag : flags) { - auto v = po::value()->notifier( - [flag](const std::string& s) { flag->notify(s); }); - desc.add_options()(flag->name().as_string().c_str(), v, + po::value_semantic *spec = nullptr; + flag->specify_option(spec); + if (!spec) continue; + desc.add_options()(flag->name().as_string().c_str(), spec, flag->description().as_string().c_str()); } } diff --git a/src/anbox/cli.h b/src/anbox/cli.h index 64b2951..b5c58fc 100644 --- a/src/anbox/cli.h +++ b/src/anbox/cli.h @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2016 Canonical, Ltd. * * This program is free software; you can redistribute it and/or modify @@ -31,6 +31,8 @@ #include "anbox/do_not_copy_or_move.h" #include "anbox/optional.h" +#include + namespace anbox { namespace cli { @@ -76,16 +78,19 @@ typedef SizeConstrainedString<80> Description; /// @brief Flag models an input parameter to a command. class Flag : public DoNotCopyOrMove { public: + typedef boost::program_options::value_semantic* Specification; + // Safe us some typing. typedef std::shared_ptr Ptr; - /// @brief notify announces a new value to the flag. - virtual void notify(const std::string& value) = 0; /// @brief name returns the name of the Flag. const Name& name() const; /// @brief description returns a human-readable description of the flag. const Description& description() const; + /// @brief specify the program option of the flag. + virtual void specify_option(Specification& spec) = 0; + protected: /// @brief Flag creates a new instance, initializing name and description /// from the given values. @@ -115,12 +120,15 @@ class TypedFlag : public Flag { /// @brief value returns the optional value associated with the flag. const Optional& value() const { return value_; } - /// @brief notify tries to unwrap a value of type T from value. - void notify(const std::string& s) override { - std::stringstream ss{s}; - T value; - ss >> value; - value_ = value; + /// @brief Option generated by specify_option tries to unwrap a value + /// of type T from value. + void specify_option(Flag::Specification& spec) override { + spec = boost::program_options::value()->notifier([&](const std::string& s) { + std::stringstream ss{s}; + T value; + ss >> value; + value_ = value; + }); } private: @@ -141,11 +149,15 @@ class TypedReferenceFlag : public Flag { TypedReferenceFlag(const Name& name, const Description& description, T& value) : Flag{name, description}, value_{value} {} - /// @brief notify tries to unwrap a value of type T from value, - /// relying on operator>> to read from given string s. - void notify(const std::string& s) override { - std::stringstream ss{s}; - ss >> value_.get(); + /// @brief Option generated by specify_option tries to unwrap a value of type T + /// from value, relying on operator>> to read from given string s. + void specify_option(Flag::Specification& spec) override { + spec = boost::program_options::value()->notifier([&](const std::string& s) { + std::stringstream ss{s}; + T value; + ss >> value; + value_ = value; + }); } private: @@ -153,9 +165,8 @@ class TypedReferenceFlag : public Flag { }; /// @brief OptionalTypedReferenceFlag handles Optional references, making -/// sure that -/// a value is always read on notify, even if the Optional wasn't initialized -/// previously. +/// sure that a value is always read on notify, even if the Optional wasn't +/// initialized previously. template class OptionalTypedReferenceFlag : public Flag { public: @@ -165,18 +176,40 @@ class OptionalTypedReferenceFlag : public Flag { Optional& value) : Flag{name, description}, value_{value} {} - /// @brief notify tries to unwrap a value of type T from value. - void notify(const std::string& s) override { - std::stringstream ss{s}; - T value; - ss >> value; - value_.get() = value; + /// @brief Option generated by specify_option tries to unwrap a value of + /// type T from value. + void specify_option(Flag::Specification& spec) override { + spec = boost::program_options::value()->notifier([&](const std::string& s) { + std::stringstream ss{s}; + T value; + ss >> value; + value_.get() = value; + }); } private: std::reference_wrapper> value_; }; +/// @brief BoolSwitchFlag implements Flag, updating the given mutable reference +/// to a boolean value. +class BoolSwitchFlag : public Flag { + public: + typedef std::shared_ptr Ptr; + + BoolSwitchFlag(const Name& name, const Description& description, bool& value) + : Flag{name, description}, value_(value) {} + + /// @brief Option generated by specify_option tries to unwrap a boolean + /// value from value. + void specify_option(Flag::Specification& spec) override { + spec = boost::program_options::bool_switch(&value_.get()); + } + + private: + std::reference_wrapper value_; +}; + /// @brief Command abstracts an individual command available from the daemon. class Command : public DoNotCopyOrMove { public: @@ -337,6 +370,14 @@ typename OptionalTypedReferenceFlag::Ptr make_flag(const Name& name, return std::make_shared>(name, desc, value); } +/// @brief make_flag returns a flag with the given name and description, +/// updating the given boolean value. +inline BoolSwitchFlag::Ptr make_flag(const Name& name, + const Description &desc, + bool &value) { + return std::make_shared(name, desc, value); +} + } // namespace cli } // namespace anbox