/* 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: selector.h 616 2010-03-11 06:23:14Z prez $ */ #ifndef MANTRA_ADMIN_SELECTOR_H #define MANTRA_ADMIN_SELECTOR_H 1 #include #include #include #include #include #include #include namespace mantra { namespace admin { // For now, this is just a way to classify selectors. class MANTRA_API selector : public command { protected: boost::shared_ptr extractor_; std::string post_complete_; // What to do if rest is empty (or we cannot extract anything selectable from it). boost::function default_act_; virtual command::error_code find(const boost::shared_ptr &sess, const std::string &word, boost::shared_ptr &cmd, const boost::shared_ptr &ctx) const = 0; virtual command::complete_replace complete(const boost::shared_ptr &sess, const std::string &word, const boost::shared_ptr &ctx) const = 0; virtual void help(const boost::shared_ptr &sess, const boost::shared_ptr &ctx) const = 0; selector(const std::string &desc, const std::string &domain, const boost::shared_ptr &pe, const std::string &pc); public: // Make it public, since it is not a hand-crafted command :) using command::set_permission; void default_action(const boost::function &in); 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()); 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()); }; class MANTRA_API command_name { std::string value_; bool complete_; public: command_name(const std::string &value, bool complete = true) : value_(value), complete_(complete) { } operator const std::string &() const { return value_; } const std::string &value() const { return value_; } bool complete() const { return complete_; } bool operator<(const command_name &rhs) const { return value_ < rhs.value_; } bool operator==(const command_name &rhs) const { return value_ == rhs.value_; } bool operator<(const std::string &rhs) const { return value_ < rhs; } bool operator==(const std::string &rhs) const { return value_ == rhs; } }; class MANTRA_API map_selector : public selector { typedef std::map > > select_type; bool nocase_; select_type select_; MANTRA_LOCAL command::error_code find(const boost::shared_ptr &sess, const std::string &word, boost::shared_ptr &cmd, const boost::shared_ptr &ctx) const; MANTRA_LOCAL command::complete_replace complete(const boost::shared_ptr &sess, const std::string &word, const boost::shared_ptr &ctx) const; MANTRA_LOCAL void help(const boost::shared_ptr &sess, const boost::shared_ptr &ctx) const; public: map_selector(const std::string &desc, const std::string &domain, const boost::shared_ptr &pe, const std::string &pc, bool case_insensitive = true); using selector::complete; using selector::help; void add(const command_name &in, const boost::shared_ptr &cmd); void add(const char *in, const boost::shared_ptr &cmd) { return add(std::string(in), cmd); } void del(const std::string &in); typedef void visit_func(const command_name &, const boost::shared_ptr &); template void visit(T &cmd) const; template void visit(const std::string &key, T &cmd) const; }; class MANTRA_API regex_selector : public selector { typedef std::vector > > > select_type; bool nocase_; select_type select_; MANTRA_LOCAL command::error_code find(const boost::shared_ptr &sess, const std::string &word, boost::shared_ptr &cmd, const boost::shared_ptr &ctx) const; MANTRA_LOCAL command::complete_replace complete(const boost::shared_ptr &sess, const std::string &word, const boost::shared_ptr &ctx) const; MANTRA_LOCAL void help(const boost::shared_ptr &sess, const boost::shared_ptr &ctx) const; public: regex_selector(const std::string &desc, const std::string &domain, const boost::shared_ptr &pe, const std::string &pc, bool case_insensitive = true); using selector::complete; using selector::help; void add(const std::string &in, const command_name &name, const boost::shared_ptr &cmd); void add(const std::string &in, const char *name, const boost::shared_ptr &cmd) { return add(in, std::string(name), cmd); } void del(const std::string &in); typedef void visit_func(const boost::regex &, const command_name &, const boost::shared_ptr &); template void visit(T &cmd) const; }; class MANTRA_API glob_selector : public selector { typedef std::vector > > > select_type; bool nocase_; select_type select_; MANTRA_LOCAL command::error_code find(const boost::shared_ptr &sess, const std::string &word, boost::shared_ptr &cmd, const boost::shared_ptr &ctx) const; MANTRA_LOCAL command::complete_replace complete(const boost::shared_ptr &sess, const std::string &word, const boost::shared_ptr &ctx) const; MANTRA_LOCAL void help(const boost::shared_ptr &sess, const boost::shared_ptr &ctx) const; public: glob_selector(const std::string &desc, const std::string &domain, const boost::shared_ptr &pe, const std::string &pc, bool case_insensitive = true); using selector::complete; using selector::help; void add(const std::string &in, const command_name &name, const boost::shared_ptr &cmd); void add(const std::string &in, const char *name, const boost::shared_ptr &cmd) { return add(in, std::string(name), cmd); } void del(const std::string &in); typedef void visit_func(const std::string &, const command_name &, const boost::shared_ptr &); template void visit(T &cmd) const; }; // What we use internally as the default selector. typedef regex_selector default_selector; // --------------------------------------------------------------------------- // Inline Functions // --------------------------------------------------------------------------- inline selector::selector(const std::string &desc, const std::string &domain, const boost::shared_ptr &pe, const std::string &pc) : command(desc, domain), extractor_(pe), post_complete_(pc) { } inline void selector::default_action(const boost::function &in) { default_act_ = in; } inline map_selector::map_selector(const std::string &desc, const std::string &domain, const boost::shared_ptr &pe, const std::string &pc, bool case_insensitive) : selector(desc, domain, pe, pc), nocase_(case_insensitive) { } inline void map_selector::add(const command_name &in, const boost::shared_ptr &cmd) { std::pair rv = select_.insert(std::make_pair(nocase_ ? command_name(boost::algorithm::to_upper_copy(in.value()), in.complete()) : in, std::vector >())); rv.first->second.push_back(cmd); } inline void map_selector::del(const std::string &in) { select_.erase(nocase_ ? boost::algorithm::to_upper_copy(in) : in); } template inline void map_selector::visit(T &cmd) const { MT_FB(cmd); select_type::const_iterator i; for (i = select_.begin(); i != select_.end(); ++i) { for (size_t j = 0; j < i->second.size(); ++j) (cmd)(i->first, i->second[j]); } MT_FE(); } template inline void map_selector::visit(const std::string &key, T &cmd) const { MT_FB(key << cmd); select_type::const_iterator i = select_.lower_bound(nocase_ ? boost::algorithm::to_upper_copy(key) : key); if (i != select_.end()) for (size_t j = 0; j < i->second.size(); ++j) (cmd)(i->first, i->second[j]); MT_FE(); } inline regex_selector::regex_selector(const std::string &desc, const std::string &domain, const boost::shared_ptr &pe, const std::string &pc, bool case_insensitive) : selector(desc, domain, pe, pc), nocase_(case_insensitive) { } inline void regex_selector::add(const std::string &in, const command_name &name, const boost::shared_ptr &cmd) { select_.push_back(std::make_pair(boost::regex(in, boost::regex::normal | (nocase_ ? boost::regex::icase : 0)), std::make_pair(name, cmd))); } template inline void regex_selector::visit(T &cmd) const { MT_FB(cmd); select_type::const_iterator i; for (i = select_.begin(); i != select_.end(); ++i) (cmd)(i->first, i->second.first, i->second.second); MT_FE(); } inline glob_selector::glob_selector(const std::string &desc, const std::string &domain, const boost::shared_ptr &pe, const std::string &pc, bool case_insensitive) : selector(desc, domain, pe, pc), nocase_(case_insensitive) { } inline void glob_selector::add(const std::string &in, const command_name &name, const boost::shared_ptr &cmd) { select_.push_back(std::make_pair(in, std::make_pair(name, cmd))); } template inline void glob_selector::visit(T &cmd) const { MT_FB(cmd); select_type::const_iterator i; for (i = select_.begin(); i != select_.end(); ++i) (cmd)(i->first, i->second.first, i->second.second); MT_FE(); } } } // namespace mantra::admin #endif // MANTRA_ADMIN_SELECTOR_H