#include #include #include #include #include "cmt_pattern.h" #include "cmt_use.h" #include "cmt_database.h" #include "cmt_error.h" //---------------------------------------------------------- // // 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) { Use::UsePtrVector& uses = Use::uses (); Use* use = &(Use::current ()); Pattern* p; p = find (name, use); if (p != 0) return (p); for (int i = 0; i < uses.size (); i++) { use = uses[i]; p = find (name, use); if (p != 0) return (p); } return (0); } //---------------------------------------------------------- Pattern* Pattern::find (const cmt_string& name, Use* use) { static PatternVector& Patterns = patterns (); int pattern_index; Pattern* pattern; if (Patterns.size () == 0) return (0); for (pattern_index = 0; pattern_index < Patterns.size (); pattern_index++) { pattern = &(Patterns[pattern_index]); if ((pattern->name == name) && (pattern->use) == use) { return (pattern); } } return (0); } //---------------------------------------------------------- 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; pattern = &p; } else { pattern->clear (); } // // 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->package == "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]; cout << "# " << p.use->package << " " << 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; } Use* use = &(Use::current ()); for (i = 0; i < use->apply_patterns.size (); i++) { const ApplyPattern& apply_pattern = use->apply_patterns[i]; cout << "# " << use->package << " applies pattern " << apply_pattern.name << " => "; apply_pattern.show (); } } /** * 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->package << " applies pattern " << apply_pattern.name << " => "; apply_pattern.show (); } } //---------------------------------------------------------- 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. for (i = 0; i < Patterns.size (); i++) { Pattern& p = Patterns[i]; if (p.name == name) { found = true; cout << "# " << p.use->package << " " << 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; } } if (!found) { CmtError::set (CmtError::pattern_not_found, name); return; } // // Then show the packages which explicitly apply the pattern. // Use* use; ApplyPattern* apply_pattern = 0; Use::UsePtrVector& uses = Use::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 << "# " << use->package << " " << use->version << " applies pattern " << name; cout << " => "; apply_pattern->show (); } } } 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->package << " " << use->version << " applies pattern " << name; cout << " => "; apply_pattern->show (); } } } //---------------------------------------------------------- Pattern::Pattern () { } //---------------------------------------------------------- Pattern::~Pattern () { } //---------------------------------------------------------- void Pattern::clear () { global = false; name = ""; use = 0; words.clear (); } /** * Applies a pattern to all uses except CMT itself. */ void Pattern::apply () const { Use::UsePtrVector& uses = Use::uses (); Use* current = &(Use::current()); Use::UsePtrVector list; 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 ((u->package != "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 != "") { Cmt::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->package.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 [