#include #include #include #include #include "cmt_tag.h" #include "cmt_database.h" /*----------------------------------------------------------*/ /* */ /* Operations on Tags */ /* */ /*----------------------------------------------------------*/ /*----------------------------------------------------------*/ void Tag::unmark () { if (!selected) return; if ((priority == PriorityDefault) || (priority == PrioritySite) || (priority == PriorityUname)) return; /* if (!Cmt::quiet) { cerr << "Unmarking tag " << name << " p=" << priority << endl; show (0); } */ selected = false; def_use = 0; } /*----------------------------------------------------------*/ void Tag::unmark_all () { static TagPtrVector& Tags = tags (); int tag_number; for (tag_number = 0; tag_number < Tags.size (); tag_number++) { Tag* tag = Tags[tag_number]; if (tag->selected) tag->unmark (); } } /** * Restore the tag tree after cleaning up one tag and * its local tree. */ void Tag::restore_tree () { static TagPtrVector& Tags = tags (); int tag_number; for (tag_number = 0; tag_number < Tags.size (); tag_number++) { Tag* tag = Tags[tag_number]; if (tag->selected) { if (tag->tag_refs.size () > 0) { int number; for (number = 0; number < tag->tag_refs.size (); number++) { Tag* ref = tag->tag_refs[number]; ref->mark (); } } } } } /*----------------------------------------------------------*/ void Tag::mark () { if (selected) return; if (tag_excludes.size () > 0) { int number; for (number = 0; number < tag_excludes.size (); number++) { Tag* ref = tag_excludes[number]; if (ref->selected) { if (priority > ref->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 " << name << " p=" << priority << " because " << ref->name << "(" << ref->priority << ")" << endl; show (0); } */ return; } } } } selected = true; /* if (!Cmt::quiet) { cerr << "Marking tag " << name << " p=" << priority << endl; show (0); } */ if (tag_refs.size () > 0) { int number; for (number = 0; number < tag_refs.size (); number++) { Tag* ref = tag_refs[number]; ref->mark (); } } } /*----------------------------------------------------------*/ void Tag::action (const CmtSystem::cmt_string_vector& words, Use* use) { cmt_string name; Tag* tag; Tag* ref; name = words[1]; if (name == "") return; tag = add (name, PriorityUserTag, "use", use); if (tag->tag_refs.size () == 0) { int priority = PriorityUserTag; if (tag->priority > priority) { priority = tag->priority; } tag->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->selected) // it was previously selected { ref->mark (); } } } } /*----------------------------------------------------------*/ void Tag::action_exclude (const CmtSystem::cmt_string_vector& words, Use* use) { cmt_string name; Tag* tag; Tag* ref; name = words[1]; if (name == "") return; tag = add (name, PriorityUserTag, "use", use); if (tag->tag_excludes.size () == 0) { tag->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->priority << ") from tag " << name << "(" << tag->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->selected) { count++; winner = tag; winner_count = 1; } for (i = 0; i < tag->tag_excludes.size (); i++) { Tag* ref = tag->tag_excludes[i]; if (ref == 0) continue; if (ref->selected) { count++; if ((winner == 0) || (ref->priority > winner->priority)) { winner = ref; winner_count = 1; } else if (ref->priority == winner->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->tag_excludes.size (); i++) { Tag* ref = tag->tag_excludes[i]; if (ref == 0) continue; if (ref == winner) continue; ref->unmark (); } } } } /*----------------------------------------------------------*/ Tag* Tag::find (const cmt_string& name) { static TagPtrVector& Tags = tags (); int tag_index; Tag* tag; if (Tags.size () == 0) return (0); for (tag_index = 0; tag_index < Tags.size (); tag_index++) { tag = Tags[tag_index]; if ((tag != 0) && (tag->name == name)) { return (tag); } } return (0); } /*----------------------------------------------------------*/ Tag* Tag::add (const cmt_string& name, int priority, const cmt_string& context, Use* use) { static TagPtrVector& Tags = tags (); static TagVector& AllTags = all_tags (); Tag* tag; if (name == "") return (0); /* if (Cmt::debug) { cmt_string t = "Tag::add> "; t += name; Database::dump (t, Database::key_tag); } */ tag = find (name); if (tag != 0) { if (priority > tag->priority) { tag->priority = priority; /* if (!Cmt::quiet) { cerr << "increasing priority of " << name << " p=" << priority << endl; } */ } else { /* if (!Cmt::quiet) { cerr << "keeping priority of " << name << " p=" << tag->priority << endl; } */ } if (Cmt::debug) { cout << "Tag::add3> tag=" << tag << endl; } return (tag); } /* if (!Cmt::quiet) { cerr << "adding tag " << name << " p=" << priority << endl; } */ Tag& tag_object = AllTags.add (); tag = &tag_object; Tags.push_back (tag); tag->clear (); tag->name = name; tag->selected = false; tag->priority = priority; tag->def_use = use; tag->context = context; /* if (Cmt::debug) { cmt_string t = "Tag::add4> "; t += name; Database::dump (t, Database::key_tag); cout << "Tag::add5> tag=" << tag << endl; } */ return (tag); } /*----------------------------------------------------------*/ int Tag::tag_number () { static TagPtrVector& Tags = tags (); return (Tags.size ()); } /*----------------------------------------------------------*/ Tag* Tag::tag (int index) { static TagPtrVector& Tags = tags (); return (Tags[index]); } /*----------------------------------------------------------*/ void Tag::clear_all () { static TagPtrVector& Tags = tags (); static TagVector& AllTags = all_tags (); /* if (Cmt::debug) { cmt_string t = "Tag::clear_all> "; Database::dump (t, Database::key_tag); } */ int tag_index; for (tag_index = 0; tag_index < AllTags.size (); tag_index++) { Tag& tag = AllTags[tag_index]; tag.clear (); } Tags.clear (); AllTags.clear (); /* if (Cmt::debug) { cmt_string t = "Tag::clear_all 2> "; Database::dump (t, Database::key_tag); } */ } /*----------------------------------------------------------*/ Tag::TagVector& Tag::all_tags () { static Database& db = Database::instance (); static TagVector& AllTags = db.all_tags (); return (AllTags); } /*----------------------------------------------------------*/ Tag::TagPtrVector& Tag::tags () { static Database& db = Database::instance (); static TagPtrVector& Tags = db.tags (); return (Tags); } /*----------------------------------------------------------*/ Tag* Tag::get_default () { static Tag* default_tag = 0; if (default_tag == 0) { default_tag = add ("Default", PriorityDefault, "Default", 0); default_tag->selected = true; } return (default_tag); } /*----------------------------------------------------------*/ Tag::Tag () { } /*----------------------------------------------------------*/ Tag::~Tag () { } /*----------------------------------------------------------*/ void Tag::clear () { name = ""; tag_refs.clear (); tag_excludes.clear (); priority = PriorityUserTag; selected = false; def_use = 0; set_use = 0; context = ""; } /*----------------------------------------------------------*/ void Tag::add_tag_ref (Tag* ref) { if (ref == 0) return; if (tag_refs.size () > 0) { int number; for (number = 0; number < tag_refs.size (); number++) { Tag* t = tag_refs[number]; if (t == ref) return; } } tag_refs.push_back (ref); } /*----------------------------------------------------------*/ void Tag::add_tag_exclude (Tag* ref) { if (ref == 0) return; /* if (selected && ref->selected) { static TagPtrVector& Tags = tags (); int tag_index; for (tag_index = 0; tag_index < Tags.size (); tag_index++) { Tag* t = Tags[tag_index]; if (t == this) { ref->unmark (); break; } if (t == ref) { unmark (); break; } } } */ if (tag_excludes.size () > 0) { int number; for (number = 0; number < tag_excludes.size (); number++) { Tag* t = tag_excludes[number]; if (t == ref) return; } } tag_excludes.push_back (ref); } /*----------------------------------------------------------*/ void Tag::show (bool quiet) const { static const cmt_string priority_text[] = { "Lowest", "Default", "Uname", "Config", "UserTag", "PrimaryUserTag", "Tag" }; if (selected) { cout << name; if (!quiet) { //cout << "context=" << context << " use=" << def_use << endl; if ((context == "use") || (def_use != 0)) { if (def_use != 0) { cout << " (from "; if (context != "use") cout << context; cout << "package " << def_use->package << ")"; } } else { cout << " (from " << context << ")"; } //cout << " (" << priority_text[priority] << ")"; if (tag_refs.size () > 0) { int number; if (set_use != 0) { cout << " package " << set_use->package; } cout << " implies ["; for (number = 0; number < tag_refs.size (); number++) { Tag* ref = tag_refs[number]; if (number > 0) cout << " "; cout << ref->name; } cout << "]"; } if (tag_excludes.size () > 0) { int number; if (set_use != 0) { cout << " package " << set_use->package; } cout << " excludes ["; for (number = 0; number < tag_excludes.size (); number++) { Tag* ref = tag_excludes[number]; if (number > 0) cout << " "; cout << ref->name; } cout << "]"; } } cout << endl; } } /*----------------------------------------------------------*/ bool Tag::is_selected () const { return (selected); }