//----------------------------------------------------------- // Copyright Christian Arnault LAL-Orsay CNRS // arnault@lal.in2p3.fr // See the complete license in cmt_license.txt "http://www.cecill.info". //----------------------------------------------------------- #include #include #include #include #include "cmt.h" #include "cmt_pattern.h" #include "cmt_use.h" #include "cmt_database.h" #include "cmt_error.h" #include "cmt_syntax.h" //---------------------------------------------------------- PatternList* PatternList::find (const cmt_string& name) { static PatternListMap& map = pattern_list_map (); return (map.find (name)); } Pattern* PatternList::find_pattern (const cmt_string& name) { PatternList* list = find (name); if (list == 0) return (0); Pattern::PatternPtrVector& vector = list->get_patterns (); if (vector.size () == 0) return (0); Pattern* p = vector[vector.size () - 1]; return (p); } Pattern* PatternList::find (const cmt_string& name, Use* use) { PatternList* list = find (name); if (list == 0) return (0); Pattern::PatternPtrVector& vector = list->get_patterns (); for (int i = 0; i < vector.size (); i++) { Pattern* p = vector[i]; if (p->use == use) return (p); } return (0); } PatternList* PatternList::add (const cmt_string& name) { PatternList* list = find (name); if (list != 0) return (list); static PatternListVector& vector = pattern_lists (); PatternList& pl = vector.add (); pl.m_name = name; static PatternListMap& map = pattern_list_map (); map.add (name, pl); return (&pl); } void PatternList::clear_all () { static PatternListVector& vector = pattern_lists (); static PatternListMap& map = pattern_list_map (); for (int i = 0; i < vector.size (); i++) { PatternList& p = vector[i]; p.clear (); } vector.clear (); map.clear (); } PatternList::PatternListMap& PatternList::pattern_list_map () { static Database& db = Database::instance (); static PatternListMap& map = db.pattern_list_map (); return (map); } PatternList::PatternListVector& PatternList::pattern_lists () { static Database& db = Database::instance (); static PatternListVector& vector = db.pattern_lists (); return (vector); } PatternList::PatternList () { } PatternList::PatternList (const cmt_string& name) : m_name (name) { } PatternList::~PatternList () { clear (); } Pattern::PatternPtrVector& PatternList::get_patterns () { return (m_patterns); } void PatternList::add_pattern (Pattern* pattern) { for (int i = 0; i < m_patterns.size (); i++) { Pattern* p = m_patterns[i]; if (p->use == pattern->use) { m_patterns[i] = pattern; return; } } m_patterns.push_back (pattern); } void PatternList::clear () { m_name = ""; m_patterns.clear (); } //---------------------------------------------------------- // // Operations on Patterns // //---------------------------------------------------------- //---------------------------------------------------------- void Pattern::action (const CmtSystem::cmt_string_vector& words, Use* use) { bool global = false; int start_index; if (words.size () < 2) return; // // expected syntax is: // // pattern [-global] pattern-name any-cmt-statement // // where any-cmt-statement may contain "templates" // // // // // // cmt_string& option = words[1]; if (option == "-global") { global = true; start_index = 2; } else { start_index = 1; } cmt_string& name = words[start_index]; start_index++; add (name, words, start_index, global, use); if (CmtSystem::testenv ("CMTTESTPATTERN")) { cout << "Pattern::action> add " << name << endl; } } /** * * Patterns are stored with two keys : and * * thus search must done against these two keys. * */ Pattern* Pattern::find (const cmt_string& name) { Pattern* p = PatternList::find_pattern (name); return (p); } //---------------------------------------------------------- Pattern* Pattern::find (const cmt_string& name, Use* use) { Pattern* p = PatternList::find (name, use); return (p); } //---------------------------------------------------------- void Pattern::add (const cmt_string& name, const CmtSystem::cmt_string_vector& words, int start_index, bool global, Use* use) { static PatternVector& Patterns = patterns (); Pattern* pattern; pattern = find (name, use); if (pattern == 0) { // No pattern for the pair exist yet. // create one. Pattern& p = Patterns.add (); p.clear (); p.name = name; p.use = use; PatternList* pl = PatternList::add (name); pl->add_pattern (&p); pattern = &p; } else { Pattern& p = *pattern; p.clear (); p.name = name; p.use = use; } pattern->line = ""; int first_word = start_index; // // Install the cmt-statement both as a vector of words and as a single line // for (int i = start_index; i < words.size (); i++) { bool need_quotes = (i > (first_word + 1)); //bool need_quotes = true; cmt_string& s = words[i]; if (i > start_index) pattern->line += " "; if (s == ";") first_word = i+1; if ((s == "\n") | (s == ";")) { pattern->line += "\n "; } else { cmt_string sep = "\""; if (s.find (sep) != cmt_string::npos) { sep = "\'"; } if (!need_quotes) sep = ""; pattern->line += sep; pattern->line += s; pattern->line += sep; } } pattern->global = global; } /** * Get the number of registered patterns */ int Pattern::pattern_number () { static PatternVector& Patterns = patterns (); return (Patterns.size ()); } /** * Get the index'th pattern in the database */ Pattern& Pattern::pattern (int index) { static PatternVector& Patterns = patterns (); return (Patterns[index]); } //---------------------------------------------------------- void Pattern::clear_all () { static PatternVector& Patterns = patterns (); for (int i = 0; i < Patterns.size (); i++) { Pattern& p = Patterns[i]; p.clear (); } Patterns.clear (); } //---------------------------------------------------------- Pattern::PatternVector& Pattern::patterns () { static Database& db = Database::instance (); static PatternVector& Patterns = db.patterns (); return (Patterns); } /** * Applies all global patterns to all uses */ void PatternList::apply_all_globals () { static PatternListVector& PatternLists = pattern_lists (); int i; for (i = 0; i < PatternLists.size (); i++) { PatternList& pl = PatternLists[i]; int n = pl.m_patterns.size (); if (n > 0) { Pattern* p = pl.m_patterns[n-1]; if ((p != 0) && (p->global)) p->apply (); } } } /** * Applies all global patterns to a given Use */ void PatternList::apply_all_globals (Use* use) { if (use->get_package_name () == "CMT") return; static PatternListVector& PatternLists = pattern_lists (); int i; for (i = 0; i < PatternLists.size (); i++) { PatternList& pl = PatternLists[i]; int n = pl.m_patterns.size (); if (n > 0) { Pattern* p = pl.m_patterns[n-1]; if ((p != 0) && (p->global)) { if (p->global) { if (IgnorePattern::find (p->name, use) == 0) p->apply (use); } } } } } /** * Show all patterns */ void PatternList::show_all_patterns () { static PatternListVector& PatternLists = pattern_lists (); int i; for (i = 0; i < PatternLists.size (); i++) { PatternList& pl = PatternLists[i]; int n = pl.m_patterns.size (); if (n > 0) { Pattern* p = pl.m_patterns[n-1]; if (p != 0) p->show (); } } } /** * Show all pattern names */ void PatternList::show_all_pattern_names () { bool empty = true; static PatternListVector& PatternLists = pattern_lists (); int i; for (i = 0; i < PatternLists.size (); i++) { PatternList& pl = PatternLists[i]; int n = pl.m_patterns.size (); if (n > 0) { Pattern* p = pl.m_patterns[n-1]; if (p != 0) { cout << p->name << " "; empty = false; } } } if (!empty) cout << endl; } /** * Applies all global patterns to all uses */ void Pattern::apply_all_globals () { PatternList::apply_all_globals (); } /** * Applies all global patterns to a given Use */ void Pattern::apply_all_globals (Use* use) { PatternList::apply_all_globals (); } /** * this is the cmt show patterns command * It just shows the pattern declarations. */ void Pattern::show_all () { PatternList::show_all_patterns (); show_all_applied_patterns (); } /** * this is the cmt show applied_patterns command * It just shows the pattern applications. */ void Pattern::show_all_applied_patterns () { Use* use = &(Use::current ()); for (int i = 0; i < use->apply_patterns.size (); i++) { const ApplyPattern& apply_pattern = use->apply_patterns[i]; cout << "# " << use->get_package_name () << " applies pattern " << apply_pattern.name << " => " << endl; apply_pattern.show (); cout << endl; } } //---------------------------------------------------------- void Pattern::show_all_names () { PatternList::show_all_pattern_names (); } /** * This is the cmt show pattern command * It shows both the pattern definition(s) and the places * where it is explicitly applied. */ void Pattern::show (const cmt_string& name) { static PatternVector& Patterns = patterns (); int i; int j; bool found = false; // First show the definitions. Pattern* p = Pattern::find (name); if (p == 0) { CmtError::set (CmtError::pattern_not_found, name); return; } p->show (); // // Then show the packages which explicitly apply the pattern. // Use* use; ApplyPattern* apply_pattern = 0; Use::UsePtrVector& uses = Use::get_ordered_uses (); for (i = 0; i < uses.size (); i++) { use = uses[i]; for (j = 0; j < use->apply_patterns.size (); j++) { apply_pattern = &(use->apply_patterns[j]); if (apply_pattern->name == name) { cout << "# applied by " << use->get_package_name () << " => " << endl; apply_pattern->show (); cout << endl; } } } use = &(Use::current ()); for (j = 0; j < use->apply_patterns.size (); j++) { apply_pattern = &(use->apply_patterns[j]); if (apply_pattern->name == name) { cout << "# " << use->get_package_name () << " " << use->version << " applies pattern " << name; cout << " => " << endl; apply_pattern->show (); cout << endl; } } } //---------------------------------------------------------- Pattern::Pattern () { } //---------------------------------------------------------- Pattern::~Pattern () { } //---------------------------------------------------------- void Pattern::clear () { global = false; name = ""; use = 0; line = ""; } //---------------------------------------------------------- void Pattern::show () const { if (use != 0) cout << "# " << use->get_package_name () << " " << use->version; else cout << "# ?? "; cout << " defines "; if (global) cout << "global "; cout << "pattern " << name << " as" << endl; cout << " " << line << endl; } //---------------------------------------------------------- class PatternCache { public: static PatternCache& instance () { static PatternCache me; return (me); } static bool update (Use* c, Use* t) { static PatternCache& me = instance (); return (me.do_update (c, t)); } static Use::UsePtrVector& get_list () { static PatternCache& me = instance (); return (me.list); } private: PatternCache () : current(0), target(0) { current_name = ""; target_name = ""; } bool do_update (Use* c, Use* t) { cmt_string c_name = c->get_package_name (); cmt_string t_name = t->get_package_name (); if ((current_name != c_name) || (target_name != t_name)) { if (CmtSystem::getenv ("TESTCACHE") != "") { cout << "update cache " << c->get_package_name () << "(" << c << ") " << t->get_package_name () << "(" << t << ")" << endl; } current = c; current_name = c_name; target = t; target_name = t_name; list.clear (); if (current != target) { if (!current->get_paths (target, list)) return (false); } else { list.push_back (current); } } else { if (CmtSystem::getenv ("TESTCACHE") != "") { cout << "keep cache" << endl; } } return (true); } Use* current; cmt_string current_name; Use* target; cmt_string target_name; Use::UsePtrVector list; }; /** * Applies a pattern to all uses (except CMT itself) between * current and the use that declared the pattern. */ void Pattern::apply () const { Use::UsePtrVector& uses = Use::get_ordered_uses (); Use* current = &(Use::current()); if (Cmt::get_debug ()) { cout << "Pattern(" << name << "::apply> " << " defined in " << use->get_package_name () << endl; } if (!PatternCache::update (current, use)) return; Use::UsePtrVector& list = PatternCache::get_list (); for (int i = 0; i < list.size (); i++) { Use* u = list[i]; if (Cmt::get_debug ()) { cout << "Pattern(" << name << "::apply> " << " to package " << u->get_package_name () << endl; } if ((u->get_package_name () != "CMT") && (IgnorePattern::find (name, u) == 0)) apply (u); } } //---------------------------------------------------------- void Pattern::apply (Use* context_use) const { static Template::TemplateVector dummy_templates; apply (context_use, dummy_templates); } /** * Applies a pattern to one particular use. */ void Pattern::apply (Use* context_use, const Template::TemplateVector& templates) const { cmt_string replacement; expand (context_use, templates, replacement); if (CmtSystem::testenv ("CMTTESTPATTERN")) { cout << "Pattern::apply> replacement=[" << replacement << "]" << endl; } if (replacement != "") { SyntaxParser::parse_requirements_text (replacement, "", context_use); } } //---------------------------------------------------------- void Pattern::expand (Use* context_use, const Template::TemplateVector& templates, cmt_string& replacement) const { if (context_use == 0) context_use = &(Use::current ()); if (CmtSystem::testenv ("CMTTESTPATTERN")) { cout << "Pattern::expand1> line=[" << line << "]" << endl; } replacement = line; if (replacement != "") { // Substitute templates from the cmt statement replacement.replace_all ("", context_use->get_package_name ().c_str ()); replacement.replace_all ("", context_use->prefix.c_str ()); replacement.replace_all ("", context_use->version.c_str ()); replacement.replace_all ("", context_use->real_path.c_str ()); for (int j = 0; j < templates.size (); j++) { Template& t = templates[j]; cmt_string s; s = "<"; s += t.name; s += ">"; replacement.replace_all (s, t.value); } for (;;) { int begin = replacement.find ("<"); if (begin == cmt_string::npos) break; int end = replacement.find (begin, ">"); if (end == cmt_string::npos) break; // Do not erase XML constructs if (replacement[end-1] == '/') break; replacement.erase (begin, end - begin + 1); } if (CmtSystem::testenv ("CMTTESTPATTERN")) { cout << "Pattern::expand2> repl=[" << replacement << "]" << endl; } } } //---------------------------------------------------------- // // Operations on ApplyPatterns // //---------------------------------------------------------- //---------------------------------------------------------- void ApplyPattern::action (const CmtSystem::cmt_string_vector& words, Use* use) { // // Expected syntax is // // apply_pattern [