/* Mantra - http://www.neuromancy.net/mantra * (c) 2007-2009 - The Neuromancy Society * * This code is released under the Artistic License 2.0. If you have not * received a copy of the license with this source code, you may find * this license at: * http://www.opensource.org/licenses/artistic-license-2.0.php * * $Id: command.h 611 2010-03-06 10:00:20Z prez $ */ #ifndef MANTRA_ADMIN_COMMAND_H #define MANTRA_ADMIN_COMMAND_H 1 #include #include #include #include #include #include #include namespace mantra { namespace admin { class session; class MANTRA_API command { typedef boost::variant, mantra::table, mantra::tree> help_data_type; boost::shared_ptr perm_set_; std::string perm_name_; std::string desc_; std::string domain_; std::vector help_; protected: command(const std::string &desc, const std::string &domain); virtual ~command() {} void set_permission(const boost::shared_ptr &in, const std::string &name); public: bool access(const boost::shared_ptr &sess, const boost::shared_ptr &ctx) const; const std::string &domain() const; std::string description(const std::locale &loc = std::locale()) const; enum error_code { no_error, //< Ready to execute command. no_terminator, //< No terminator found. handled_error, //< An error that we have already reported. unknown_error, //< ?! invalid_session, //< Problem with the session. parse_error, //< Could not split line into 'words'. no_such_command, //< No such command. incomplete_cmd, //< Continuation required (operator()) incomplete_help, //< Continuation required (help) permission_denied, //< Not allwed to execute command. not_enough_args, //< Incomplete command without continuation. invalid_arg, //< An argument is not valid/understood. sess_not_supp, //< Not supported in this session. sys_not_supp, //< Not supported on this system. NUM_ERROR_CODES }; class complete_replace { // Possible completions. If this is empty, no possible // completions exist. If there is more than one entry in // here, then multiple possibilities exist. std::vector poss_; std::string append_; size_t remove_; public: complete_replace() : remove_(0) {} complete_replace(size_t r, const std::string &app = std::string()) : append_(app), remove_(r) {} void add(const std::string &in); void add(const complete_replace &in); // Largest string that is common to all possibilities. std::string common() const; const std::string &append() const; size_t remove() const; const std::vector &poss() const; }; typedef complete_replace complete_type(const boost::shared_ptr &, const std::vector &, const std::string &, size_t, const boost::shared_ptr &ctx); // rv.first = what to insert into the string at offs. // rv.second = whether we found a unique completion. virtual complete_replace complete(const boost::shared_ptr &sess, const std::vector &prev, const std::string &rest, size_t offs, const boost::shared_ptr &ctx = boost::shared_ptr()); typedef std::pair > return_type; typedef return_type type(const boost::shared_ptr &sess, std::vector &prev, std::string &rest, const boost::shared_ptr &ctx = boost::shared_ptr()); virtual return_type operator()(const boost::shared_ptr &sess, std::vector &prev, std::string &rest, const boost::shared_ptr &ctx = boost::shared_ptr()) = 0; virtual return_type help(const boost::shared_ptr &sess, std::vector &prev, std::string &rest, const boost::shared_ptr &ctx = boost::shared_ptr()); }; // A generic command to handle HELP calls, it basically invokes the stored command's // HELP function (and completion command). In and of itself, its very stupid. class MANTRA_API command_help : public command { command &root_; public: command_help(command &root); command::complete_replace complete(const boost::shared_ptr &sess, const std::vector &prev, const std::string &rest, size_t offs, const boost::shared_ptr &ctx = boost::shared_ptr()); command::return_type operator()(const boost::shared_ptr &sess, std::vector &prev, std::string &rest, const boost::shared_ptr &ctx = boost::shared_ptr()); command::return_type help(const boost::shared_ptr &sess, std::vector &prev, std::string &rest, const boost::shared_ptr &ctx = boost::shared_ptr()); }; class MANTRA_API command_set : public command { std::string section_; properties *props_; public: command_set(const std::string &desc, const std::string &domain, const std::string §ion, mantra::properties *props = NULL); command::complete_replace complete(const boost::shared_ptr &sess, const std::vector &prev, const std::string &rest, size_t offs, const boost::shared_ptr &ctx = boost::shared_ptr()); command::return_type operator()(const boost::shared_ptr &sess, std::vector &prev, std::string &rest, const boost::shared_ptr &ctx = boost::shared_ptr()); command::return_type help(const boost::shared_ptr &sess, std::vector &prev, std::string &rest, const boost::shared_ptr &ctx = boost::shared_ptr()); }; class MANTRA_API command_property_proxy { public: typedef boost::optional get_property_func( const boost::shared_ptr &, const boost::shared_ptr &, const std::string &, const std::string &); typedef bool set_property_func(const boost::shared_ptr &, const boost::shared_ptr &, const std::string &, const std::string &, const property_value_type &); typedef void clear_property_func(const boost::shared_ptr &, const boost::shared_ptr &, const std::string &, const std::string &); command_property_proxy(const boost::function &gpf, const boost::function &spf = boost::function(), const boost::function &cpf = boost::function()); static void set_command_data(const boost::shared_ptr &s, const boost::shared_ptr &c = boost::shared_ptr()); static void clear_command_data(bool erase = false); boost::optional get_property(const std::string §ion, const std::string &key); bool set_property(const std::string §ion, const std::string &key, const property_value_type &value); void clear_property(const std::string §ion, const std::string &key); private: static boost::thread_specific_ptr, boost::shared_ptr > > ptr; boost::function get; boost::function set; boost::function clear; }; // This is just for convenience. #define DECLARE_PROPERTY(x) \ mantra::admin::command_property_proxy x##_proxy_; \ boost::optional x##_get( \ const boost::shared_ptr &sess, \ const boost::shared_ptr &ctx, \ const std::string §ion, const std::string &key) const; \ bool x##_set(const boost::shared_ptr &sess, \ const boost::shared_ptr &ctx, \ const std::string §ion, const std::string &key, \ const mantra::property_value_type value); \ void x##_clear(const boost::shared_ptr &sess, \ const boost::shared_ptr &ctx, \ const std::string §ion, const std::string &key); MANTRA_API std::string assemble_cmd(const std::vector &prev, const std::string &delim = " "); MANTRA_API command::error_code load_config(boost::property_tree::iptree &pt, const boost::shared_ptr &sess, const std::vector &prev, const std::string &rest); MANTRA_API command::complete_replace complete_config(const boost::shared_ptr &sess, const std::vector &prev, const std::string &rest, size_t offs, const boost::shared_ptr &ctx); MANTRA_API command::complete_replace complete_filename(const boost::shared_ptr &sess, const std::string &word, const boost::shared_ptr &ctx); // --------------------------------------------------------------------------- // inline functions // --------------------------------------------------------------------------- inline command::command(const std::string &desc, const std::string &domain) : desc_(desc), domain_(domain) { } inline const std::string &command::domain() const { return domain_; } inline std::string command::description(const std::locale &loc) const { return mantra::translate::get(domain_.c_str(), desc_, loc); } inline const std::string &command::complete_replace::append() const { return append_; } inline size_t command::complete_replace::remove() const { return remove_; } inline const std::vector &command::complete_replace::poss() const { return poss_; } // Default is no completion. inline command::complete_replace command::complete(const boost::shared_ptr &sess, const std::vector &prev, const std::string &rest, size_t offs, const boost::shared_ptr &ctx) { static_cast(sess); static_cast(prev); static_cast(rest); static_cast(offs); static_cast(ctx); return complete_replace(); } inline command_help::command_help(command &root) : command(INTL_N("Retrieve help on other commands"), MANTRA_DOMAIN), root_(root) { } inline command::return_type command_help::operator()(const boost::shared_ptr &sess, std::vector &prev, std::string &rest, const boost::shared_ptr &ctx) { prev.pop_back(); return root_.help(sess, prev, rest, ctx); } inline command::complete_replace command_help::complete(const boost::shared_ptr &sess, const std::vector &prev, const std::string &rest, size_t offs, const boost::shared_ptr &ctx) { return root_.complete(sess, prev, rest, offs, ctx); } inline command_property_proxy::command_property_proxy( const boost::function &gpf, const boost::function &spf, const boost::function &cpf) : get(gpf), set(spf), clear(cpf) { } inline boost::optional command_property_proxy::get_property(const std::string §ion, const std::string &key) { if (!get) return boost::optional(); return get(ptr->first, ptr->second, section, key); } inline bool command_property_proxy::set_property(const std::string §ion, const std::string &key, const property_value_type &value) { if (!set) return false; return set(ptr->first, ptr->second, section, key, value); } inline void command_property_proxy::clear_property(const std::string §ion, const std::string &key) { if (!clear) return; clear(ptr->first, ptr->second, section, key); } } } // namespace mantra::admin #endif // MANTRA_ADMIN_COMMAND_H