//----------------------------------------------------------- // 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_tag.h" #include "cmt_database.h" #include "cmt_log.h" /*----------------------------------------------------------*/ /* */ /* Operations on Tags */ /* */ /*----------------------------------------------------------*/ /*----------------------------------------------------------*/ void Tag::unmark () { if (!is_primary ()) return; if (!m_selected) return; Log; if ((m_priority == PriorityDefault) || (m_priority == PrioritySite) || (m_priority == PriorityUname)) return; log << "Unmarking tag[" << this << "] " << m_name << " p=" << m_priority << log_endl; m_selected = false; m_def_use = 0; } /*----------------------------------------------------------*/ void Tag::unmark_all () { static TagPtrVector& vector = tags (); int tag_number; for (tag_number = 0; tag_number < vector.size (); tag_number++) { Tag* tag = vector[tag_number]; tag->unmark (); } } /** * Restore the tag tree after cleaning up one tag and * its local tree. */ void Tag::restore_tree () { static TagPtrVector& vector = tags (); int tag_number; for (tag_number = 0; tag_number < vector.size (); tag_number++) { Tag* tag = vector[tag_number]; if (tag->is_primary () && tag->is_selected ()) { if (tag->m_tag_refs.size () > 0) { int number; for (number = 0; number < tag->m_tag_refs.size (); number++) { Tag* ref = tag->m_tag_refs[number]; ref->mark (); } } } } } /*----------------------------------------------------------*/ void Tag::mark () { if (!is_primary ()) return; if (m_selected) return; Log; if (m_tag_excludes.size () > 0) { int number; for (number = 0; number < m_tag_excludes.size (); number++) { Tag* ref = m_tag_excludes[number]; if (ref->is_selected ()) { if (m_priority > ref->m_priority) { // // Although this other contradictory tag is already selected, // its priority is lower. Therefore it will lose !! It has to be // unselected ... // ref->unmark (); } else { /* if (!Cmt::quiet) { cerr << "Cannot mark excluded tag " << m_name << " p=" << m_priority << " because " << ref->m_name << "(" << ref->m_priority << ")" << endl; show (0); } */ return; } } } } m_selected = true; log << "Marking tag[" << this << "] " << m_name << " p=" << m_priority << log_endl; if (m_tag_refs.size () > 0) { int number; for (number = 0; number < m_tag_refs.size (); number++) { Tag* ref = m_tag_refs[number]; ref->mark (); } } } /*----------------------------------------------------------*/ void Tag::action (const CmtSystem::cmt_string_vector& words, Use* use) { cmt_string name; Tag* tag; Tag* ref; if (words.size () < 1) return; name = words[1]; if (name == "") return; tag = add (name, PriorityUserTag, "use", use); int priority = PriorityUserTag; if (tag->m_priority > priority) { priority = tag->m_priority; } //if (tag->m_tag_refs.size () == 0) //{ tag->m_set_use = use; //} for (int i = 2; i < words.size (); i++) { name = words[i]; if (name == "") break; ref = add (name, priority, "use", use); tag->add_tag_ref (ref); if (tag->is_selected ()) // it was previously selected { ref->mark (); } } } /*----------------------------------------------------------*/ void Tag::action_apply (const CmtSystem::cmt_string_vector& words, Use* use) { cmt_string name; Tag* tag; if (words.size () < 1) return; name = words[1]; if (name == "") return; Symbol::expand (name); if (name == "") { if (!Cmt::get_quiet ()) { cerr << "#CMT> Warning: apply_tag with empty name [" << words[1] << "]" << endl; } } else { tag = find (name); if (tag == 0) { tag = add (name, PriorityUserTag, "use", use); } tag->mark (); } } /*----------------------------------------------------------*/ void Tag::action_exclude (const CmtSystem::cmt_string_vector& words, Use* use) { cmt_string name; Tag* tag; Tag* ref; if (words.size () < 1) return; name = words[1]; if (name == "") return; tag = add (name, PriorityUserTag, "use", use); if (tag->m_tag_excludes.size () == 0) { tag->m_set_use = use; int i; for (i = 2; i < words.size (); i++) { cmt_string n; n = words[i]; if (n == "") break; ref = add (n, PriorityUserTag, "use", use); /* if (!Cmt::quiet) { cerr << "Excluding tag " << n << "(" << ref->m_priority << ") from tag " << name << "(" << tag->m_priority << ")" << endl; } */ tag->add_tag_exclude (ref); ref->add_tag_exclude (tag); } // // We have to check that some of the excluded tags may be already selected. // Then we have to figure out which one has to win: // // the one with the highest priority // or the first that had been declared. // int count = 0; int winner_count = 0; Tag* winner = 0; if (tag->is_selected ()) { count++; winner = tag; winner_count = 1; } for (i = 0; i < tag->m_tag_excludes.size (); i++) { Tag* ref = tag->m_tag_excludes[i]; if (ref == 0) continue; if (ref->is_selected ()) { count++; if ((winner == 0) || (ref->m_priority > winner->m_priority)) { winner = ref; winner_count = 1; } else if (ref->m_priority == winner->m_priority) { winner_count++; } } } if (count > 1) { if (winner_count > 1) { // // Several contradictory tags are selected and have the same priority!! // } // // We have at least one selected, and one winner. // All others will be unselected. // if (tag != winner) { tag->unmark (); } for (i = 0; i < tag->m_tag_excludes.size (); i++) { Tag* ref = tag->m_tag_excludes[i]; if (ref == 0) continue; if (ref == winner) continue; ref->unmark (); } } } } /*----------------------------------------------------------*/ Tag* Tag::find (const cmt_string& name) { TagMap& map = tag_map (); Tag* result = map.find (name); return (result); /* TagPtrVector& vector = tags (); int tag_index; Tag* tag; if (vector.size () == 0) return (0); for (tag_index = 0; tag_index < vector.size (); tag_index++) { tag = vector[tag_index]; if ((tag != 0) && (tag->m_name == name)) { return (tag); } } return (0); */ } /*----------------------------------------------------------*/ Tag* Tag::find (const cmt_string& name, TagMap& instances) { Tag* result = instances.find (name); return (result); /* int tag_index; if (instances.size () == 0) return (0); for (tag_index = 0; tag_index < instances.size (); tag_index++) { Tag& tag = instances[tag_index]; if (tag.m_name == name) { return (&tag); } } return (0); */ } /*----------------------------------------------------------*/ Tag* Tag::add (const cmt_string& name, int priority, const cmt_string& context, Use* use) { Log; TagMap& map = tag_map (); TagPtrVector& vector = tags (); TagVector& instances = all_tags (); Tag* tag; if (name == "") return (0); tag = find (name); if (tag != 0) { if (priority > tag->m_priority) { tag->m_priority = priority; /* if (!Cmt::quiet) { cerr << "increasing priority of " << name << " p=" << priority << endl; } */ } else { /* if (!Cmt::quiet) { cerr << "keeping priority of " << name << " p=" << tag->m_priority << endl; } */ } log << "re-adding tag[" << tag << "] " << name << " p=" << priority << log_endl; return (tag); } Tag& tag_object = instances.add (); tag = &tag_object; vector.push_back (tag); map.add (name, tag_object); log << "adding tag[" << tag << "] " << name << " p=" << priority << log_endl; tag->clear (); tag->m_name = name; tag->m_priority = priority; tag->m_def_use = use; tag->m_context = context; int pos = 0; int length = name.size (); while (pos < length) { int and_pos = name.find (pos, "&"); if ((and_pos == cmt_string::npos) && (pos == 0)) break; cmt_string op_name; if (and_pos == cmt_string::npos) { name.substr (pos, op_name); } else { name.substr (pos, and_pos - pos, op_name); } if (op_name != "") { Tag* t = find (op_name); if (t == 0) { t = add (op_name, priority, context, use); } if (t != 0) { tag->m_and_operands.push_back (t); if (t->get_priority () > priority) { tag->m_priority = t->get_priority (); } } else { cerr << "#Tag::add> unknown tag " << op_name << " in tag expression" << endl; } } if (and_pos == cmt_string::npos) break; pos = and_pos + 1; } return (tag); } /*----------------------------------------------------------*/ int Tag::tag_number () { static TagPtrVector& vector = tags (); return (vector.size ()); } /*----------------------------------------------------------*/ Tag* Tag::tag (int index) { static TagPtrVector& vector = tags (); return (vector[index]); } /*----------------------------------------------------------*/ void Tag::clear_all () { TagMap& map = tag_map (); TagPtrVector& vector = tags (); TagVector& instances = all_tags (); int tag_index; for (tag_index = 0; tag_index < instances.size (); tag_index++) { Tag& tag = instances[tag_index]; tag.clear (); } map.clear (); vector.clear (); instances.clear (); } /*----------------------------------------------------------*/ Tag::TagMap& Tag::tag_map () { static Database& db = Database::instance (); TagMap& map = db.tag_map (); return (map); } /*----------------------------------------------------------*/ Tag::TagVector& Tag::all_tags () { static Database& db = Database::instance (); TagVector& vector = db.all_tags (); return (vector); } /*----------------------------------------------------------*/ Tag::TagPtrVector& Tag::tags () { static Database& db = Database::instance (); TagPtrVector& vector = db.tags (); return (vector); } /*----------------------------------------------------------*/ Tag* Tag::get_default () { static Tag* default_tag = 0; if (default_tag == 0) { default_tag = add ("Default", PriorityDefault, "Default", 0); default_tag->mark (); } return (default_tag); } /*----------------------------------------------------------*/ Tag::Tag () : m_name (""), m_selected (false), m_context (""), m_def_use (0), m_set_use (0), m_priority (0) { clear (); } /*----------------------------------------------------------*/ Tag::Tag (const Tag& other) { clear (); m_name = other.m_name; m_selected = other.m_selected; m_and_operands = other.m_and_operands; m_tag_refs = other.m_tag_refs; m_tag_excludes = other.m_tag_excludes; m_context = other.m_context; m_def_use = other.m_def_use; m_set_use = other.m_set_use; m_priority = other.m_priority; } /*----------------------------------------------------------*/ Tag& Tag::operator = (const Tag& other) { clear (); m_name = other.m_name; m_selected = other.m_selected; m_and_operands = other.m_and_operands; m_tag_refs = other.m_tag_refs; m_tag_excludes = other.m_tag_excludes; m_context = other.m_context; m_def_use = other.m_def_use; m_set_use = other.m_set_use; m_priority = other.m_priority; return (*this); } /*----------------------------------------------------------*/ Tag::~Tag () { } /*----------------------------------------------------------*/ void Tag::clear () { m_name = ""; m_tag_refs.clear (); m_tag_excludes.clear (); m_priority = PriorityUserTag; m_def_use = 0; m_set_use = 0; m_context = ""; m_selected = false; m_and_operands.clear (); } /*----------------------------------------------------------*/ void Tag::add_tag_ref (Tag* ref) { if (ref == 0) return; if (m_tag_refs.size () > 0) { int number; for (number = 0; number < m_tag_refs.size (); number++) { Tag* t = m_tag_refs[number]; if (t == ref) return; } } m_tag_refs.push_back (ref); } /*----------------------------------------------------------*/ void Tag::add_tag_exclude (Tag* ref) { if (ref == 0) return; if (m_tag_excludes.size () > 0) { int number; for (number = 0; number < m_tag_excludes.size (); number++) { Tag* t = m_tag_excludes[number]; if (t == ref) return; } } m_tag_excludes.push_back (ref); } /*----------------------------------------------------------*/ void Tag::show_definition (bool quiet) const { static const cmt_string priority_text[] = { "Lowest", "Default", "Uname", "Config", "UserTag", "PrimaryUserTag", "Tag" }; if (m_name == "Default") return; cout << m_name; if (!quiet) { //cout << "context=" << m_context << " use=" << m_def_use << endl; if ((m_context == "use") || (m_def_use != 0)) { if (m_def_use != 0) { cout << " (from "; if (m_context != "use") cout << m_context; cout << "package " << m_def_use->get_package_name () << ")"; } } else { cout << " (from " << m_context << ")"; } //cout << " (" << priority_text[m_priority] << ")"; if (m_tag_refs.size () > 0) { int number; if (m_set_use != 0) { cout << " package " << m_set_use->get_package_name (); } cout << " implies ["; for (number = 0; number < m_tag_refs.size (); number++) { Tag* ref = m_tag_refs[number]; if (number > 0) cout << " "; cout << ref->m_name; } cout << "]"; } if (m_tag_excludes.size () > 0) { int number; if (m_set_use != 0) { cout << " package " << m_set_use->get_package_name (); } cout << " excludes ["; for (number = 0; number < m_tag_excludes.size (); number++) { Tag* ref = m_tag_excludes[number]; if (number > 0) cout << " "; cout << ref->m_name; } cout << "]"; } } cout << endl; } /*----------------------------------------------------------*/ void Tag::show (bool quiet) const { if (is_primary () && is_selected ()) show_definition (quiet); } /*----------------------------------------------------------*/ bool Tag::is_selected () const { if (is_primary ()) { return (m_selected); } else { for (int i = 0; i < m_and_operands.size(); i++) { Tag* t = m_and_operands[i]; if (!t->is_selected ()) return (false); } return (true); } } /*----------------------------------------------------------*/ bool Tag::is_primary () const { return (m_and_operands.size() == 0); } /*----------------------------------------------------------*/ const cmt_string& Tag::get_name () const { return (m_name); } /*----------------------------------------------------------*/ int Tag::get_priority () const { return (m_priority); } /** * Recomputes all references to other tags using the new set of * instances. This concerns * * TagPtrVector m_and_operands; * TagPtrVector m_tag_refs; * TagPtrVector m_tag_excludes; * * The pointers stored in those reference vectors are pointing to Tag objects * in one collection * We want to convert these pointers to pointers to the same Tag objects but * stored in the other Tag collection provided in the argument. * */ void Tag::install (TagMap& instances) { int i; for (i = 0; i < m_and_operands.size (); i++) { Tag* t = m_and_operands[i]; if (t != 0) { t = find (t->m_name, instances); m_and_operands[i] = t; } } for (i = 0; i < m_tag_refs.size (); i++) { Tag* t = m_tag_refs[i]; if (t != 0) { t = find (t->m_name, instances); m_tag_refs[i] = t; } } for (i = 0; i < m_tag_excludes.size (); i++) { Tag* t = m_tag_excludes[i]; if (t != 0) { t = find (t->m_name, instances); m_tag_excludes[i] = t; } } }