// ------------------------------------------------------------------------ // eca-object-map: A virtual base for dynamic object maps // Copyright (C) 2000-2004,2009 Kai Vehmanen // // Attributes: // eca-style-version: 3 // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // ------------------------------------------------------------------------ #include #include #include #include #include #include #include "eca-object-map.h" #include "eca-logger.h" using std::find; using std::map; using std::string; using std::list; ECA_OBJECT_MAP::ECA_OBJECT_MAP(void) : expr_case_sensitive_rep(false) { } ECA_OBJECT_MAP::~ECA_OBJECT_MAP(void) { map::iterator p = object_map.begin(); while(p != object_map.end()) { if (p->second != 0) { ECA_OBJECT* next_obj = p->second; // std::cerr << "Deleting " << next_obj->name() << "." << std::endl; map::iterator q = p; ++q; while(q != object_map.end()) { if (q->second != 0 && q->second == p->second) { // std::cerr << "Deleting sub-object with keyword " << q->first << "." << std::endl; q->second = 0; } ++q; } p->second = 0; delete next_obj; } ++p; } } void ECA_OBJECT_MAP::toggle_case_sensitive_expressions(bool v) { expr_case_sensitive_rep = v; } bool ECA_OBJECT_MAP::case_sensitive_expressions(void) const { return expr_case_sensitive_rep; } /** * Registers a new object to the object map. Map object will take care * of deleting the registered objects. Notice that it's possible * to register the same physical object with different keywords. * Object map will take care that objects with multiple registered * keywords are destructed properly. * * @arg keyword tag string that identifies the registered object * @arg expr regex that is used to map strings to objects * (note! 'keyword' should match 'expr') */ void ECA_OBJECT_MAP::register_object(const string& keyword, const string& expr, ECA_OBJECT* object) { object_keywords_rep.push_back(keyword); object_map[keyword] = object; object_expr_map[keyword] = expr; if (expr_to_keyword(keyword) != keyword && object != 0) { ECA_LOG_MSG(ECA_LOGGER::info, "WARNING: Registered keyword " + keyword + " doesn't match the associated regex " + expr + ", for object '" + object->name() + "' (" + expr_to_keyword(expr) + ")."); } } /** * Unregisters object with keyword 'keyword'. Does not physically * delete the assigned object, because one object can be * registered with multiple keywords. */ void ECA_OBJECT_MAP::unregister_object(const string& keyword) { object_keywords_rep.remove(keyword); object_map[keyword] = 0; object_expr_map[keyword] = ""; } /** * Returns a list of registered objects. */ const list& ECA_OBJECT_MAP::registered_objects(void) const { return object_keywords_rep; } bool ECA_OBJECT_MAP::has_keyword(const std::string& keyword) const { if (find(object_keywords_rep.begin(), object_keywords_rep.end(), keyword) == object_keywords_rep.end()) return false; return true; } bool ECA_OBJECT_MAP::has_object(const ECA_OBJECT* obj) const { map::const_iterator p = object_map.begin(); while(p != object_map.end()) { if (obj->name() == p->second->name()) { return true; } ++p; } return false; } /** * Returns the object identified by 'keyword'. If no keyword * matches, 0 is returned. * * As a const object pointer is returned, clone() and new_expr() * methods should be used to create new non-const objects of * the returned type. */ const ECA_OBJECT* ECA_OBJECT_MAP::object(const string& keyword) const { const ECA_OBJECT* object = 0; if (object_map.find(keyword) != object_map.end()) { object = object_map[keyword]; } return object; } /** * A convenience function which directly returns an object matching * search string 'input'. */ const ECA_OBJECT* ECA_OBJECT_MAP::object_expr(const string& input) const { return object(expr_to_keyword(input)); } /** * Returns the identifying keyword for input string 'input'. * * If 'case_sensitive_expressions() != true', the pattern * matching will be case insensitive. */ string ECA_OBJECT_MAP::expr_to_keyword(const string& input) const { map::const_iterator p = object_expr_map.begin(); regex_t preg; string result; while(p != object_expr_map.end()) { int cflags = REG_EXTENDED | REG_NOSUB; if (case_sensitive_expressions() != true) cflags |= REG_ICASE; regcomp(&preg, p->second.c_str(), cflags); if (regexec(&preg, input.c_str(), 0, 0, 0) == 0) { ECA_LOG_MSG(ECA_LOGGER::functions, "match (1): " + input + " to regexp " + p->second); result = p->first; regfree(&preg); break; } regfree(&preg); ++p; } return result; } /** * Returns the identifying keyword that matches the expression 'expr'. */ string ECA_OBJECT_MAP::keyword_to_expr(const string& keyword) const { if (object_expr_map.find(keyword) != object_expr_map.end()) return object_expr_map[keyword]; return ""; } /** * Returns the matching identifying keyword for 'object'. */ string ECA_OBJECT_MAP::object_identifier(const ECA_OBJECT* object) const { map::const_iterator p = object_map.begin(); while(p != object_map.end()) { if (object->name() == p->second->name()) { return p->first; } ++p; } return ""; }