#include #include #include #include #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; } // // Install the cmt-statement as a vector of words. // for (int i = start_index; i < words.size (); i++) { cmt_string& s = pattern->words.add (); s = words[i]; } 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 Pattern::apply_all_globals () { static PatternVector& Patterns = patterns (); int i; for (i = 0; i < Patterns.size (); i++) { Pattern& p = Patterns[i]; if (p.global) p.apply (); } } /** * Applies all global patterns to a given Use */ void Pattern::apply_all_globals (Use* use) { if (use->get_package_name () == "CMT") return; static PatternVector& Patterns = patterns (); int i; for (i = 0; i < Patterns.size (); i++) { Pattern& p = Patterns[i]; if (p.global) { if (IgnorePattern::find (p.name, use) == 0) p.apply (use); } } } /** * this is the cmt show patterns command * It just shows the pattern declarations. */ void Pattern::show_all () { static PatternVector& Patterns = patterns (); int i; for (i = 0; i < Patterns.size (); i++) { Pattern& p = Patterns[i]; if (p.use != 0) cout << "# " << p.use->get_package_name () << " " << p.use->version; else cout << "# ?? "; cout << " defines "; if (p.global) cout << "global "; cout << "pattern " << p.name << " as ["; for (int wi = 0; wi < p.words.size (); wi++) { const cmt_string& s = p.words[wi]; if (wi > 0) cout << " "; cout << s; } cout << "]" << endl; } Use* use = &(Use::current ()); for (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 << " => "; apply_pattern.show (); cout << endl; } } /** * 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 << " => "; apply_pattern.show (); cout << endl; } } //---------------------------------------------------------- void Pattern::show_all_names () { static PatternVector& Patterns = patterns (); if (Patterns.size () > 0) { for (int i = 0; i < Patterns.size (); i++) { Pattern& p = Patterns[i]; cout << p.name << " "; } cout << endl; } } /** * 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; } cout << "# " << p->use->get_package_name () << " " << p->use->version << " defines "; if (p->global) cout << "global "; cout << "pattern " << p->name << " as ["; for (int wi = 0; wi < p->words.size (); wi++) { const cmt_string& s = p->words[wi]; if (wi > 0) cout << " "; cout << s; } cout << "]" << endl; // // 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 << " => "; apply_pattern->show (); cout << endl; } } } //---------------------------------------------------------- Pattern::Pattern () { } //---------------------------------------------------------- Pattern::~Pattern () { } //---------------------------------------------------------- void Pattern::clear () { global = false; name = ""; use = 0; words.clear (); } /** * 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()); Use::UsePtrVector list; if (Cmt::get_debug ()) { cout << "Pattern(" << name << "::apply> " << " defined in " << use->get_package_name () << endl; } if (current != use) { if (!current->get_paths (use, list)) return; } else { list.push_back (current); } 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 line; expand (context_use, templates, line); if (line != "") { SyntaxParser::parse_requirements_text (line, "", context_use); } } //---------------------------------------------------------- void Pattern::expand (Use* context_use, const Template::TemplateVector& templates, cmt_string& line) const { line = ""; // First re-create the cmt statement as one line. for (int i = 0; i < words.size (); i++) { const cmt_string& w = words[i]; if (i > 0) line += " "; if ((w == "\n") | (w == ";")) { line += "\n"; } else { line += "\""; line += w; line += "\""; } } if (context_use == 0) context_use = &(Use::current ()); if (line != "") { // Substitute templates from the cmt statement line.replace_all ("", context_use->get_package_name ().c_str ()); line.replace_all ("", context_use->prefix.c_str ()); line.replace_all ("", context_use->version.c_str ()); line.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 += ">"; line.replace_all (s, t.value); } for (;;) { int begin = line.find ("<"); if (begin == cmt_string::npos) break; int end = line.find (begin, ">"); if (end == cmt_string::npos) break; // Do not erase XML constructs if (line[end-1] == '/') break; line.erase (begin, end - begin + 1); } } } //---------------------------------------------------------- // // Operations on ApplyPatterns // //---------------------------------------------------------- //---------------------------------------------------------- void ApplyPattern::action (const CmtSystem::cmt_string_vector& words, Use* use) { // // Expected syntax is // // apply_pattern [