//----------------------------------------------------------- // 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 "cmt_use.h" #include "cmt_system.h" #include "cmt_symbol.h" #include "cmt_error.h" #include "cmt_database.h" #include "cmt_syntax.h" static void show_packages (); /* * Design. * * There is one central database of all Use objects. This in the Database using: * Database::instance().get_instances (); * * There is also a list of selected Use pointers available from * Database::instance().get_ordered_uses (); * * A new Use object is created when a new use statement requires it: * o if the specified version is specified for the first time * o if the specified path is specified for the first time * */ static bool add_request (const cmt_string& path, const cmt_string& package_name, const cmt_string& version) { static cmt_map requests; cmt_string request = package_name; request += " "; request += version; request += " "; request += path; static bool b = true; bool new_request = false; if (!requests.has ((const cmt_string&) request)) { new_request = true; requests.add ((const cmt_string&) request, b); } return (new_request); } class UseContext { public: static UseContext& current () { static UseContext me; return (me); } UseContext () { m_auto_imports = On; } UseContext (const UseContext& other) { m_auto_imports = other.m_auto_imports; } UseContext& operator = (const UseContext& other) { m_auto_imports = other.m_auto_imports; return (*this); } static void set_current (State auto_imports) { UseContext& c = current (); c.m_auto_imports = auto_imports; } static State get_current_auto_imports () { UseContext& c = current (); return (c.m_auto_imports); } private: State m_auto_imports; }; class BestFitSelector { public: Use* operate (Use* ref_use, Use* new_use); }; //---------------------------------------------------------- typedef enum { IdenticalIds, IncompatibleMajorIds, ExplicitOldMajorIdWinsAgainstWildarded, ExplicitNewMajorIdWinsAgainstWildarded, ExplicitOldMinorIdWinsAgainstWildarded, ExplicitNewMinorIdWinsAgainstWildarded, NewMinorIdGreaterThanOld, ExplicitOldPatchIdWinsAgainstWildarded, ExplicitNewPatchIdWinsAgainstWildarded, NewPatchIdGreaterThanOld } CompareStatus; static CompareStatus compare_versions (const cmt_string& ref_version, const cmt_string& new_version) { CompareStatus result = IdenticalIds; int old_v = -1; int old_r = -1; int old_p = -1; int new_v = -1; int new_r = -1; int new_p = -1; CmtSystem::is_version_directory (ref_version, old_v, old_r, old_p); CmtSystem::is_version_directory (new_version, new_v, new_r, new_p); if ((new_v != -1) && (old_v != -1) && (new_v != old_v)) { /* if (!Cmt::get_quiet ()) { cout << "#1 Required version " << new_version << " incompatible with selected version " << ref_version << endl; } */ result = IncompatibleMajorIds; } else if ((new_v == -1) || (old_v == -1)) { // // we plan to discard new_use, but if it was specified as explicit // and ref_use was wildcarded then new_use will win !! // // So then we'll have to understand where are the wild // cards... If they are on v or r, then we consider them. // // if ((old_v == -1) && (new_v != -1)) { /* if (!Cmt::get_quiet ()) { cout << "#2 Select version " << new_version << " instead of existing " << ref_version << endl; } */ result = ExplicitNewMajorIdWinsAgainstWildarded; } else { /* if (!Cmt::get_quiet ()) cout << "#3 keep version " << ref_version << " (ignore version " << new_version << ")" << endl; */ result = ExplicitOldMajorIdWinsAgainstWildarded; } } else if ((new_r == -1) || (old_r == -1) || (new_r < old_r)) { // // we plan to discard new_use, but if it was specified as explicit // and ref_use was wildcarded then new_use will win !! // // So then we'll have to understand where are the wild // cards... If they are on v or r, then we consider them. // // if ((old_r == -1) && (new_r != -1)) { // old has wild card and new has not => new wins /* if (!Cmt::get_quiet ()) { cout << "#4 Select release " << new_version << " instead of existing " << ref_version << endl; } */ result = ExplicitNewMinorIdWinsAgainstWildarded; } else { /* if (!Cmt::get_quiet ()) cout << "#5 keep release " << ref_version << " (ignore release " << new_version << ")" << endl; */ result = ExplicitOldMinorIdWinsAgainstWildarded; } } else if (new_r > old_r) { /* if (!Cmt::get_quiet ()) { cout << "#6 Select release " << new_version << " instead of existing " << ref_version << endl; } */ result = NewMinorIdGreaterThanOld; } else if ((new_p == -1) || (old_p == -1) || (new_p < old_p)) { // // we plan to discard new_use, but if it was specified as explicit // and ref_use was wildcarded then new_use will win !! // if ((old_p == -1) && (new_p != -1)) { /* if (!Cmt::get_quiet ()) { cout << "#7 Select patch " << new_version << " instead of existing " << ref_version << endl; } */ result = ExplicitNewPatchIdWinsAgainstWildarded; } else { /* if (!Cmt::get_quiet ()) cout << "#8 keep patch " << ref_version << " (ignore version " << new_version << ")" << endl; */ result = ExplicitOldPatchIdWinsAgainstWildarded; } } else if (new_p > old_p) { /* if (!Cmt::get_quiet ()) { cout << "#9 Select patch " << new_version << " instead of existing " << ref_version << endl; } */ result = NewPatchIdGreaterThanOld; } return (result); } //---------------------------------------------------------- // // Operations on Use // //---------------------------------------------------------- /** * Mark all clients of the current package. */ void Use::select_clients (const cmt_string& package, const cmt_string& version) { static UsePtrVector& uses = get_ordered_uses (); int number; Use* use = 0; unselect_all (); undiscard_all (); for (number = uses.size () - 1; number >= 0; number--) { use = uses[number]; if (use == 0) continue; if (use->is_selected ()) continue; use->select (); if (!use->is_client (package, version)) use->discard (); } } //---------------------------------------------------------- void Use::show_all (bool skip_discarded) { show_all ("use ", skip_discarded); } //---------------------------------------------------------- void Use::show_cycles () { static int level = 0; static UsePtrVector stack; int size = 0; if (level == 0) { unselect_all (); unselect (); stack.clear (); } //for (int i = 0; i < level; i++) cout << " "; //cout << "Use::show_cycles> " << level << " " << get_package_name () << endl; // Detect cycles. for (int k = 0; k < level; k++) { Use* u = stack[k]; if (u == this) { for (;k < level; k++) { u = stack[k]; cout << u->get_package_name () << " "; } cout << endl; return; } } // Save this to the stack. if (stack.size () <= level) { stack.push_back (this); } else { stack[level] = this; } if (selected) return; selected = true; size = sub_uses.size (); for (int n = 0; n < size; n++) { Use* use = sub_uses[n]; if (use == 0) continue; //for (int i = 0; i < level; i++) cout << " "; //cout << "Use::show_cycles> " << get_package_name () << " uses " << use->get_package_name () << endl; if (use->discarded) { Use* u; u = use->get_selected_version (); if (u == 0) continue; use = u; } level++; use->show_cycles (); level--; } } //---------------------------------------------------------- void Use::push_scope_section (ScopeType type) { scope_sections.push_back (type); } //---------------------------------------------------------- void Use::pop_scope_section () { scope_sections.pop_back (); } //---------------------------------------------------------- void Use::close_scope_sections () { scope_sections.clear (); } //---------------------------------------------------------- ScopeType Use::get_current_scope () const { if (scope_sections.size () == 0) return (initial_scope); const ScopeSection& s = scope_sections.back (); return (s.get_scope ()); } //---------------------------------------------------------- void Use::show_all (const cmt_string& prefix, bool skip_discarded) { static UsePtrVector& uses = get_ordered_uses (); Use* use; int number; if (Cmt::get_debug ()) { cout << "use::show_all-1> "; int i; for (i = 0; i < uses.size (); i++) { Use* u = uses[i]; cout << u->get_package_name () << "[" << u->get_index () << "]" << " "; } cout << endl; } unselect_all (); use = &(current ()); use->unselect (); if (!Cmt::get_quiet ()) use->show_sub_uses ("", skip_discarded); if (uses.size () > 0) { if (!Cmt::get_quiet ()) { cout << "#\n"; cout << "# Selection :\n"; } // // First move the CMT package to the end of the use set. // (ie. used by everybody) // use = Use::find ("CMT"); Use::move (use); for (number = uses.size () - 1; number >= 0; number--) { use = uses[number]; if (use->discarded) continue; if (!use->located ()) { if (!Cmt::get_quiet ()) { cout << "# package " << use->get_package_name () << " " << use->version << " " << use->path << " not found" << endl; } CmtError::set (CmtError::package_not_found, use->get_package_name ()); } else { static const cmt_string empty; cmt_string p = use->real_path; if (use->path != "") { int pos = p.find_last_of (use->path); if (pos != cmt_string::npos) { p.erase (pos); } } cout << prefix << use->get_package_name () << " " << use->version; if (CmtSystem::absolute_path (use->path)) { if (!Cmt::get_quiet ()) { cout << " (" << use->path << ")"; } } else { cout << " " << use->path; } if (!Cmt::get_quiet ()) { if (p != "") cout << " (" << p << ")"; if (use->auto_imports == Off) cout << " (no_auto_imports)"; } cout << endl; } } if (Cmt::get_cmt_home () != "") { cout << prefix << CmtSystem::get_home_package () << " v0"; if (!Cmt::get_quiet ()) { cout << " (" << Cmt::get_cmt_home () << ")"; } cout << endl; } if (Cmt::get_cmt_user_context () != "") { cout << prefix << CmtSystem::get_user_context_package () << " v0"; if (!Cmt::get_quiet ()) { cout << " (" << Cmt::get_cmt_user_context () << ")"; } cout << endl; } } } /** * This private class parses the use statement after macro expansion * This is a finite state machine. * It maintains the results of the parsing in terms of a package name, * a version, a path, and state variables (no_auto_imports) */ class use_action_iterator { public: use_action_iterator () { state = need_package; auto_imports = Unspecified; } void set (const cmt_string& w) { if (w == "-auto_imports") { auto_imports = On; } else if (w == "-no_auto_imports") { auto_imports = Off; } else if (w == "|") { state = need_version_alias; } else { switch (state) { case need_package: package = w; state = need_version; break; case need_version: version = w; state = need_path; break; case need_path: path = w; while (path[path.size() - 1] == '/') path.erase (path.size() - 1); while (path[path.size() - 1] == '\\') path.erase (path.size() - 1); state = finished; break; case need_version_alias: version_alias = w; state = need_path_alias; break; case need_path_alias: path_alias = w; while (path_alias[path_alias.size() - 1] == '/') path_alias.erase (path_alias.size() - 1); while (path_alias[path_alias.size() - 1] == '\\') path_alias.erase (path_alias.size() - 1); state = finished; break; } } } bool ok () { if (package == "") return (false); if (CmtSystem::is_home_package (package, version)) return (false); if (CmtSystem::is_user_context_package (package, version)) return (false); if (CmtSystem::is_project_package (package, version)) return (false); return (true); } /** * * Build or retreive the Use object corresponding to the parsed specification. * */ Use* get_use (Use* parent) { static Use::UsePtrVector& uses = Use::get_ordered_uses (); if (version == "") version = "*"; if (Cmt::get_debug ()) { int i; cout << "use::action1> current=" << parent->get_package_name () << " package=" << package << " "; for (i = 0; i < uses.size (); i++) { Use* u = uses[i]; cout << u->get_package_name () << " "; } cout << endl; } const Use& cu = Use::current (); /** * Do not continue the operations for private uses * accessed from an external context. * * Exceptions should be considered for * - cmt broadcast * - cmt show uses */ ActionType action = Cmt::get_action (); if (Cmt::get_debug ()) { cout << "before adding " << package <<"> auto_imports=" << auto_imports << " (current AI was " << UseContext::get_current_auto_imports () << ")" << " (Use::scope=" << parent->get_current_scope () << ")" << " (parent=" << parent->get_package_name () << ")" << endl; } bool hidden_by_scope = false; if (parent->get_current_scope () == ScopePrivate) { hidden_by_scope = true; // Do not hide immediate children of the current package. if ((parent == 0) || (parent->get_package () == cu.get_package ())) hidden_by_scope = false; // Override default rule according to the scope filtering mode. if (Cmt::get_scope_filtering_mode () == reach_private_uses) hidden_by_scope = false; } if (hidden_by_scope) { return (0); } // Here the version may contain wild cards UseContext save = UseContext::current (); /** * "auto_imports" is the state which is specified on the use statement * currently being parsed. */ switch (auto_imports) { case Unspecified: // unspecified => we forward the state saved in the current use context UseContext::set_current (UseContext::get_current_auto_imports ()); break; case Off: // off => the context becomes constrained to be off UseContext::set_current (Off); break; case On: // on => if current context is off it is kept off // otherwise it is forced to on if (UseContext::get_current_auto_imports () != Off) { UseContext::set_current (On); } break; } if (Cmt::get_debug ()) { cout << "about to add " << package << endl; show_packages (); } /// Now do create or retreive the Use object. Use* new_use = Use::add (path, package, version, version_alias, path_alias, parent, auto_imports); if (new_use != 0) { if (Cmt::get_debug ()) { cout << "after adding1 " << package << "> auto_imports=" << new_use->auto_imports << endl; show_packages (); } switch (new_use->auto_imports) { case Unspecified: new_use->auto_imports = UseContext::get_current_auto_imports (); if (new_use->auto_imports == Unspecified) { new_use->auto_imports = On; } break; case On: break; case Off: if (UseContext::get_current_auto_imports () == On) { /** * Warning : this Use had been previously specified as -no_auto_imports * Now this new specification tries to turn it to auto_imports. * It will be required to propagate the change, according to the * specifications: * * for all sub_uses: * if it is unspecified OR specified as auto_imports: * turn it to auto_imports * */ new_use->set_auto_imports (On); } break; } if (Cmt::get_debug ()) { cout << "after adding2 " << package << "> auto_imports=" << new_use->auto_imports << " "; cout << endl; } UseContext& c = UseContext::current (); c = save; Use::reorder (new_use, parent); if (Cmt::get_debug ()) { cout << "use::action2> current=" << parent->get_package_name () << " package=" << package << " "; int i; for (i = 0; i < uses.size (); i++) { Use* u = uses[i]; cout << u->get_package_name () << "[" << u->get_index () << "]" << " "; } cout << endl; } } return (new_use); } private: enum { need_package, need_version, need_path, need_version_alias, need_path_alias, finished } state; State auto_imports; cmt_string package; cmt_string version; cmt_string path; cmt_string version_alias; cmt_string path_alias; }; //---------------------------------------------------------- Use* Use::action (const CmtSystem::cmt_string_vector& words, Use* parent) { Use* new_use; // // complete syntax : "use " // minimal syntax : "use " // // o if is omitted then take any version available // o can be specified using "v*" or "vr*" or "vrp*" // // o the notation "v*" is preferred to omission (particularly since // omission does not permit ) // if (words.size () < 2) return (0); use_action_iterator it; for (int i = 1; i < words.size (); i++) { const cmt_string& w = words[i]; cmt_string ew = w; Symbol::expand (ew); if (ew != w) { CmtSystem::cmt_string_vector ws; CmtSystem::split (ew, " ", ws); for (int j = 0; j < ws.size (); ++j) { const cmt_string& ww = ws[j]; it.set (ww); } } else { it.set (ew); } } if (!it.ok ()) return (0); static int level = 0; level++; new_use = it.get_use (parent); level--; return (new_use); } //---------------------------------------------------------- void Use::author_action (const CmtSystem::cmt_string_vector& words) { if (author != "") author += "\n"; for (int i = 1; i < words.size (); i++) { const cmt_string& w = words[i]; if (i > 1) author += " "; author += w; } } //---------------------------------------------------------- void Use::manager_action (const CmtSystem::cmt_string_vector& words) { if (manager != "") manager += "\n"; for (int i = 1; i < words.size (); i++) { const cmt_string& w = words[i]; if (i > 1) manager += " "; manager += w; } } //---------------------------------------------------------- Use* Use::find (const cmt_string& package, const cmt_string& version, const cmt_string& path) { Package* p = Package::find (package); if (p == 0) return (0); UsePtrVector& uses = p->get_uses (); int use_index; int size = uses.size (); for (use_index = 0; use_index < size; use_index++) { Use& use = (*uses[use_index]); // If the version argument is omitted then // take the first registered version if (version == "") return (&use); // Otherwise compare against specified_version and path //if ((use.specified_version == version) && // (use.specified_path == path)) return (&use); // what about comparing wild cards? if (use.specified_version == version) return (&use); } return (0); } //---------------------------------------------------------- int Use::find_index (const cmt_string& package_name, const cmt_string& version, const cmt_string& path) { Package* package = Package::find (package_name); if (package == 0) return (-1); UsePtrVector& uses = package->get_uses (); int use_index; int size = uses.size (); for (use_index = 0; use_index < size; use_index++) { Use* use = uses[use_index]; if (Cmt::get_debug ()) { cout << "Use::find_index> " << package_name << " " << use << " " << use->m_index << endl; } // If the version argument is omitted then // take the first registered version if (version == "") return (use->m_index); // Otherwise compare against specified_version and path //if ((use.specified_version == version) && // (use.specified_path == path)) return (&use); // what about comparing wild cards? if (use->specified_version == version) return (use->m_index); } return (-1); } /** * 1) Given a Use object identified by its index in the ordered_uses() array, * 2) Given a vector of states containing the auto_imports states of all uses, * * we want to switch to 'On' the auto_imports states of all * sub_uses of the argument that were Off. * */ void Use::set_auto_imports_state (int use_index, cmt_vector& auto_imports_states) { // check boundaries (this should be an error when out bondaries) if ((use_index < 0) || (use_index >= auto_imports_states.size ())) return; Use::UsePtrVector& uses = Use::get_ordered_uses (); if (Cmt::get_debug ()) { int i; cout << "Use::set_auto_imports_state> use_index=" << use_index << " "; for (i = 0; i < auto_imports_states.size (); i++) { cout << (auto_imports_states[i] ? "|" : "o"); } for (i = 0; i < auto_imports_states.size (); i++) { cout << " " << (uses[i])->get_package_name (); } cout << endl; } // check if this is already done (recursivity ending) if (auto_imports_states[use_index]) return; Use* use = uses[use_index]; // We only have to deal with Use objects that were // actually turned Off if (use->auto_imports != Off) return; /** * Here, use points to a Use object which had been declared as * no_auto_imports. But we need to switch it On. Therefore, * * 1) the state in auto_imports_states has to be set On * 2) the operation has to be recursively propagated to all * sub_uses which also had no_auto_imports. (only to those) * */ auto_imports_states[use_index] = true; int size = 0; size = use->sub_uses.size (); for (int i = 0; i < size; i++) { Use* u = use->sub_uses[i]; // first find the index of this use. int j = u->m_index; if (j >= 0) { if (u->sub_use_auto_imports[i] == Off) { set_auto_imports_state (j, auto_imports_states); } else { auto_imports_states[j] = true; } } } } //---------------------------------------------------------- // // Move use to the end // //---------------------------------------------------------- void Use::move (Use* use) { if (use == 0) return; static UsePtrVector& uses = get_ordered_uses (); int size = uses.size (); if (size == 0) return; // // On se positionne sur le pointeur. // int use_index = use->m_index; if (use_index < 0) return; // // On deplace tous les pointeurs d'une case en arriere // for (use_index++; use_index < size; use_index++) { Use* u = uses[use_index]; u->m_index--; uses[use_index - 1] = uses[use_index]; } // // use est donc replace en derniere position // use->m_index = size - 1; uses[size - 1] = use; } /** * Reorder provider versus client in the UsePtrVector list, * so that the order reflects the fact that client makes use of provider. * The result should be that provider appears before client in the list. */ void Use::reorder (Use* provider, Use* client) { static UsePtrVector& uses = get_ordered_uses (); int use_index; int size = uses.size (); if (size == 0) return; if (provider == client) return; // // First locate the two use objects into the uses vector. // -> provider_index and client_index // int provider_index = -1; int client_index = -1; provider_index = provider->m_index; client_index = client->m_index; if (Cmt::get_debug ()) { cout << "Use::reorder> provider=" << provider_index << " client=" << client_index << endl; } // // Both objects must be installed in uses before acting. // if (provider_index == -1) return; if (client_index == -1) return; if (client_index < provider_index) { // // client is already before provider so job is finished // return; } // // before : // ^ ^ // ip ic // // 1) move "P b b b" by one place to the right // thus : // // 2) move "C" to [ip] // // after : // for (use_index = client_index - 1; use_index >= provider_index; use_index--) { Use* use = uses[use_index]; use->m_index++; uses[use_index + 1] = uses[use_index]; } uses[provider_index] = client; client->m_index = provider_index; } //---------------------------------------------------------- void Use::clear_all () { static UsePtrVector& uses = get_ordered_uses (); static UseVector& instances = get_instances (); int use_index; for (use_index = 0; use_index < instances.size (); use_index++) { Use& use = instances[use_index]; use.clear (); } uses.clear (); instances.clear (); } //---------------------------------------------------------- void Use::unselect_all () { static UsePtrVector& uses = get_ordered_uses (); int use_index; int size = uses.size (); if (size == 0) return; for (use_index = 0; use_index < size; use_index++) { Use* use = uses[use_index]; if (use != 0) { use->unselect (); } } } //---------------------------------------------------------- void Use::undiscard_all () { static UsePtrVector& uses = get_ordered_uses (); int use_index; if (uses.size () == 0) return; for (use_index = 0; use_index < uses.size (); use_index++) { Use* use = uses[use_index]; if (use != 0) { use->undiscard (); } } } //---------------------------------------------------------- void Use::fill_macro_all (cmt_string& buffer, const cmt_string& suffix) { UsePtrVector& uses = get_ordered_uses (); buffer = "macro_append use_"; buffer += suffix; buffer += " \" "; (Use::current()).fill_macro (buffer, suffix); for (int number = 0; number < uses.size (); number++) { Use* use = uses[number]; Package* p = use->get_package (); if (p->is_cmt ()) continue; if (use->discarded) continue; if (use->auto_imports == Off) continue; use->fill_macro (buffer, suffix); } buffer += "\""; } //---------------------------------------------------------- Use::Use () { done = false; discarded = false; auto_imports = Unspecified; m_package = 0; m_index = -1; clear (); } //---------------------------------------------------------- Use::Use (const cmt_string& new_package, const cmt_string& new_version, const cmt_string& new_path) { auto_imports = Unspecified; m_located = false; m_package = 0; m_index = -1; set (new_package, new_version, new_path); } //---------------------------------------------------------- Use::~Use () { clear (); } //---------------------------------------------------------- void Use::clear () { specified_path = ""; path = ""; if (m_package != 0) { m_package->remove_use (this); m_package = 0; } version = ""; author = ""; manager = ""; real_path = ""; prefix = ""; style = mgr_style; initial_scope = ScopePublic; done = false; discarded = false; selected = false; auto_imports = Unspecified; includes.clear (); include_path = ""; scripts.clear (); apply_patterns.clear (); ignore_patterns.clear (); sub_uses.clear (); sub_use_scopes.clear (); sub_use_auto_imports.clear (); requests.clear (); alternate_versions.clear (); alternate_paths.clear (); version_alias = ""; path_alias = ""; m_located = false; m_has_native_version = false; m_index = -1; } //---------------------------------------------------------- void Use::set (const cmt_string& new_package, const cmt_string& new_version, const cmt_string& new_path, const cmt_string& new_version_alias, const cmt_string& new_path_alias) { clear (); Package* p = Package::add (new_package); m_package = p; p->add_use (this); specified_path = new_path; // specified_path.replace_all ("\\", "/"); specified_version = new_version; version = new_version; path = specified_path; Symbol::expand (path); real_path = ""; style = mgr_style; initial_scope = ScopePublic; done = false; discarded = false; Cmt::build_prefix (new_package, prefix); version_alias = new_version_alias; path_alias = new_path_alias; } //---------------------------------------------------------- void Use::change_path (const cmt_string& new_path) { // // This methods changes real_path after an actual location // where this package/version has been found. // real_path = ""; if (new_path != "") { if ((path.size () > 0) && (!CmtSystem::absolute_path (path))) { real_path = new_path; real_path += CmtSystem::file_separator (); real_path += path; } else { real_path = new_path; } // real_path.replace_all ("\\", "/"); CmtSystem::compress_path (real_path); } m_located = true; } //---------------------------------------------------------- int Use::reach_package (const cmt_string& from_path) { if (Cmt::get_debug ()) { cout << "Use::reach_package> (" << get_package_name () << " " << version << ")from " << from_path << endl; } // // We try to reach a package/version starting from from_path // // check if from_path is at least real if ((from_path != "") && !CmtSystem::cd (from_path)) return (0); if (Cmt::get_debug ()) { cout << "Use::reach_package-2>" << endl; } // check in case from_path is a new search path if (from_path != real_path) { // Move to that prefix only if it is a relative path. if ((path.size () > 0) && (!CmtSystem::absolute_path (path))) { if (!CmtSystem::cd (path)) { return (0); } } } if (Cmt::get_debug ()) { cout << "Use::reach_package-3>" << endl; } // Special treatment for CMTHOME package... if (get_package_name () == CmtSystem::get_home_package ()) { discarded = 1; if (!CmtSystem::test_file ("requirements")) { return (0); } else { return (1); } } if (Cmt::get_debug ()) { cout << "Use::reach_package-4>" << endl; } // Special treatment for CMTUSERCONTEXT package... if (get_package_name () == CmtSystem::get_user_context_package ()) { discarded = 1; if (!CmtSystem::test_file ("requirements")) { return (0); } else { return (1); } } // Special treatment for PROJECT package... if (get_package_name () == CmtSystem::get_project_package ()) { discarded = 1; if (!CmtSystem::test_file ("project")) { return (0); } else { return (1); } } if (Cmt::get_debug ()) { cout << "Use::reach_package-5>" << endl; } // Now from_path exists, try if the package exists there if (!CmtSystem::cd (get_package_name ())) { return (0); } if (Cmt::get_debug ()) { cout << "Use::reach_package-6>" << endl; } if (CmtSystem::test_file ("cmt/requirements")) { CmtSystem::cd ("cmt"); style = no_version_style; if (CmtSystem::test_file ("version.cmt")) { cmt_string v; v.read ("version.cmt"); int pos; pos = v.find ('\n'); if (pos != cmt_string::npos) v.erase (pos); pos = v.find ('\r'); if (pos != cmt_string::npos) v.erase (pos); CompareStatus s = compare_versions (version, v); if (Cmt::get_debug ()) { cout << "Use::reach_package-6.1> version=" << version << " v=" << v << " s=" << s << endl; } switch (s) { case IdenticalIds: case ExplicitOldMajorIdWinsAgainstWildarded: case ExplicitOldMinorIdWinsAgainstWildarded: case ExplicitOldPatchIdWinsAgainstWildarded: break; case ExplicitNewMajorIdWinsAgainstWildarded: case ExplicitNewMinorIdWinsAgainstWildarded: case NewMinorIdGreaterThanOld: case ExplicitNewPatchIdWinsAgainstWildarded: case NewPatchIdGreaterThanOld: break; case IncompatibleMajorIds: return (0); } version = v; } else if (version == "") { version = "v0"; } return (1); } else if (!CmtSystem::cd (version)) { // // The specified version cannot be found per-se // There are alternate possibilities when it contains wild cards // if ((version == "") || (version.find ("*") != cmt_string::npos)) { static CmtSystem::cmt_string_vector versions; static cmt_string name; name = "."; name += CmtSystem::file_separator (); if (version == "") name += "*"; else name += version; CmtSystem::scan_dir (name, versions); int i; bool found = false; for (i = 0; i < versions.size (); i++) { const cmt_string& vers = versions[i]; if (Cmt::get_debug ()) { cout << " ... version " << vers << " exists" << endl; } CmtSystem::basename (vers, name); int v; int r; int p; if (CmtSystem::is_version_directory (name, v, r, p)) { /* This check is not sufficient !! We need to check in addition that the selected directory is really the start of a true CMT package (ie with either /mgr/requirements or /cmt/requirements below) */ cmt_string req; req = name; req += CmtSystem::file_separator (); req += "mgr"; req += CmtSystem::file_separator (); req += "requirements"; if (!CmtSystem::test_file (req)) { req = name; req += CmtSystem::file_separator (); req += "cmt"; req += CmtSystem::file_separator (); req += "requirements"; if (!CmtSystem::test_file (req)) continue; } cmt_string& new_v = alternate_versions.add (); new_v = name; cmt_string& new_p = alternate_paths.add (); new_p = from_path; found = true; } } if (!found) { if (CmtSystem::test_file ("cmt/requirements")) { CmtSystem::cd ("cmt"); style = no_version_style; return (1); } } } if (Cmt::get_debug ()) { cout << " ... end of version scan" << endl; } // // We have now the list of possible alternate versions. However // we return that the expected package/version was not found (yet). // return (0); } if (Cmt::get_debug ()) { cout << "Use::reach_package-7>" << endl; } //cerr << " ... version " << version << " exists" << endl; // Now we have met the exact specified version! if (!CmtSystem::test_file ("cmt/requirements")) { if (!CmtSystem::test_file ("mgr/requirements")) { return (0); } else { CmtSystem::cd ("mgr"); style = mgr_style; } } else { CmtSystem::cd ("cmt"); style = cmt_style; } if (Cmt::get_debug ()) { cout << "Use::reach_package-8>" << endl; } return (1); } class UseProjectAction : public IProjectAction { public: UseProjectAction (Use* use) : m_use (use), m_found (false) { } bool found () const { return (m_found); } bool run (const Project& project) { const cmt_string& path = project.get_cmtpath (); m_use->alternate_versions.clear (); m_use->alternate_paths.clear (); if (m_use->reach_package (path)) { if (Cmt::get_debug ()) { cout << "move_to4> " << path << endl; } m_use->change_path (path); m_found = true; return (false); } else if (m_use->alternate_versions.size () > 0) { if (m_use->select_alternate ()) { if (Cmt::get_debug ()) { cout << "move_to5> " << m_use->real_path << endl; } m_found = true; return (false); } } return (true); } private: Use* m_use; bool m_found; }; //---------------------------------------------------------- bool Use::move_to () { if (m_located) { // // The real path where this version/package can be found // has already been resolved. We thus first go there. // if (Cmt::get_debug ()) { cout << "move_to1> " << real_path << endl; } reach_package (real_path); return (true); } cmt_string expanded_path = path; // // Try here. // if (expanded_path == "") { if (reach_package ("")) { if (Cmt::get_debug ()) { cout << "move_to2> " << expanded_path << endl; } change_path (expanded_path); return (true); } else if (alternate_versions.size () > 0) { if (select_alternate ()) { if (Cmt::get_debug ()) { cout << "move_to5> " << real_path << endl; } return (true); } } } // // If the path specified in this use is a true absolute path, // then we search the package from there first. // if (CmtSystem::absolute_path (expanded_path)) { if (reach_package (expanded_path)) { if (Cmt::get_debug ()) { cout << "move_to3> " << expanded_path << endl; } change_path (expanded_path); return (true); } else if (alternate_versions.size () > 0) { if (select_alternate ()) { if (Cmt::get_debug ()) { cout << "move_to5> " << real_path << endl; } return (true); } } } // // Second try is among the CMTPATHs // UseProjectAction pa (this); Project::broadcast (pa); if (pa.found ()) return (true); return (false); } //---------------------------------------------------------- bool Use::select_alternate () { int i; int v0 = 0; int r0 = 0; int p0 = 0; int v = 0; int r = 0; int p = 0; int selected_index = -1; for (i = 0; i < alternate_versions.size (); i++) { cmt_string& name = alternate_versions[i]; /* if (CmtSystem::getenv ("CMTTESTUSEWILDCARDS") != "") { cout << "select_alternate[" << this << "]> package " << get_package_name () << " sv=" << specified_version << " v=" << version << " av[" << i << "]=" << name << endl; } */ if (i == 0) { CmtSystem::is_version_directory (name, v0, r0, p0); selected_index = 0; } else { CmtSystem::is_version_directory (name, v, r, p); if (v > v0) { selected_index = i; v0 = v; r0 = r; p0 = p; } else if (v == v0) { if (r > r0) { selected_index = i; r0 = r; p0 = p; } else if (r == r0) { if (p > p0) { selected_index = i; p0 = p; } } } } } if (selected_index >= 0) { if (CmtSystem::cd (alternate_paths[selected_index])) { version = alternate_versions[selected_index]; if (reach_package (alternate_paths[selected_index])) { /* if (CmtSystem::getenv ("CMTTESTUSEWILDCARDS") != "") { cout << "select_alternate2> package " << get_package_name () << " sv=" << specified_version << " v=" << version << endl; } */ if (Cmt::get_debug ()) { cout << "select_alternate> " << alternate_paths[selected_index] << endl; } change_path (alternate_paths[selected_index]); return (true); } } } return (false); } //---------------------------------------------------------- bool Use::need_new (const cmt_string& path, const cmt_string& package, const cmt_string& version, Use** old_use, Use* context_use) { bool new_request = add_request (path, package, version); Use& current_use = Use::current (); if (package == current_use.get_package_name ()) { if (Cmt::get_debug ()) { cout << " ... recursive use to current package" << endl; } if (old_use != 0) *old_use = ¤t_use; return (false); } Package* p = Package::add (package); UsePtrVector& uses = p->get_uses (); bool do_need_new = true; Use* found = 0; Use* registered = 0; int req_v = -1; int req_r = -1; int req_p = -1; CmtSystem::is_version_directory (version, req_v, req_r, req_p); if (Cmt::get_debug ()) { cout << "need_new> p=" << package << " v=" << version << " v=" << req_v << " r=" << req_r << " p=" << req_p << endl; } bool has_wild_card = (req_v == -1) || (req_r == -1) || (req_p == -1); int new_v = -1; int new_r = -1; int new_p = -1; int use_index; if (old_use != 0) *old_use = 0; // Acquire the registered use. for (use_index = 0; use_index < uses.size (); use_index++) { Use& use = (*uses[use_index]); if (use.m_index < 0) continue; registered = &use; break; } // Make a first try with the registered use if it exists. cmt_string decision; if (registered != 0) { Use& use = (*registered); found = &use; CmtSystem::is_version_directory (use.specified_version, new_v, new_r, new_p); bool use_has_wild_card = (new_v == -1) || (new_r == -1) || (new_p == -1); if (has_wild_card && !use_has_wild_card) { if (Cmt::get_debug ()) { cout << " ... wildcarded request loses against existing explicit" << endl; } do_need_new = false; // We don't need a new one } else { // here either !has_wild_card or use_has_wild_card if ((version == use.specified_version) && (path == use.specified_path)) { if (Cmt::get_debug ()) { cout << " ... exactly same version and path!" << endl; } do_need_new = false; // We don't need a new one } else if (version != use.specified_version) { if (Cmt::get_debug ()) { cout << "requested explicit wins against existing wildcarded" << endl; } // The registered use loses against the request } else { if (Cmt::get_debug ()) { cout << "only paths differ, consider the new one." << endl; } // The registered use loses against the request } } if (new_request && !Cmt::get_quiet () && (Cmt::get_action () == action_show_uses)) { if ((new_v != -1) && (req_v != -1) && (new_v != req_v)) { cout << "# Required version " << version << " of package " << package; if (context_use != 0) { cout << " [from " << context_use->get_package_name () << "]"; } cout << " incompatible with selected version " << use.version; if (use.version != use.specified_version) { cout << " (" << use.specified_version << ")" ; } cout << endl; } } if (Cmt::get_debug ()) { cout << "# " << package << " " << version; if (context_use != 0) { cout << " [from " << context_use->get_package_name () << "]"; } if (do_need_new) { cout << " > "; } else { cout << " < "; } cout << use.version; if (use.version != use.specified_version) { cout << " (" << use.specified_version << ")" ; } cout << " (r) "; cout << endl; } } if (do_need_new) { // Now try unregistered uses, since the registered one is not appropriate. // to see is any other existing use could match for (use_index = 0; use_index < uses.size (); use_index++) { Use& use = (*uses[use_index]); if (use.m_index >= 0) continue; // Always save the latest found. found = &use; CmtSystem::is_version_directory (use.specified_version, new_v, new_r, new_p); bool use_has_wild_card = (new_v == -1) || (new_r == -1) || (new_p == -1); if (has_wild_card && !use_has_wild_card) { if (Cmt::get_debug ()) { cout << " ... requested wildcarded loses against existing explicit" << endl; } do_need_new = false; // We don't need a new one } else { // here either !has_wild_card or use_has_wild_card if ((version == use.specified_version) && (path == use.specified_path)) { if (Cmt::get_debug ()) { cout << " ... exactly same version and path!" << endl; } do_need_new = false; // We don't need a new one } else if (version != use.specified_version) { if (Cmt::get_debug ()) { cout << "requested explicit wins against existing wildcarded" << endl; } // This use loses against the request } else { if (Cmt::get_debug ()) { cout << "only paths differ, consider the new one." << endl; } // This use loses against the request } } if (new_request && !Cmt::get_quiet () && (Cmt::get_action () == action_show_uses)) { if ((new_v != -1) && (req_v != -1) && (new_v != req_v)) { cout << "# Required version " << version << " of package " << package; if (context_use != 0) { cout << " [from " << context_use->get_package_name () << "]"; } cout << " incompatible with selected version " << use.version; if (use.version != use.specified_version) { cout << " (" << use.specified_version << ")" ; } cout << endl; } } if (Cmt::get_debug ()) { cout << "# " << package << " " << version; if (context_use != 0) { cout << " [from " << context_use->get_package_name () << "]"; } if (do_need_new) { cout << " > "; } else { cout << " < "; } if ((new_v != -1) && (req_v != -1) && (new_v != req_v)) { cout << "(incompatible) "; } cout << use.version; if (use.version != use.specified_version) { cout << " (" << use.specified_version << ")" ; } cout << endl; } } } if (old_use != 0) { if (registered != 0) *old_use = registered; else *old_use = found; } return (do_need_new); } //---------------------------------------------------------- // // Here the version which is provided here is the specified version. // It may contain wild cards or it may be simply empty. // //---------------------------------------------------------- Use* Use::create (const cmt_string& path, const cmt_string& package, const cmt_string& version, const cmt_string& version_alias, const cmt_string& path_alias) { Package* p = 0; p = Package::add (package); UsePtrVector& vector = p->get_uses (); // We first look in the database. for (int use_index = 0; use_index < vector.size (); use_index++) { Use* use = vector[use_index]; if ((use->specified_version == version) && (use->specified_path == path)) return (use); } // We now really create a new Use entry. static UseVector& instances = get_instances (); Use& use_object = instances.add (); use_object.set (package, version, path, version_alias, path_alias); return (&use_object); } //---------------------------------------------------------- // Add a use request into the database. // // o If a use request already exist in the database, // check the version compatibility // //---------------------------------------------------------- Use* Use::add (const cmt_string& path, const cmt_string& package_name, const cmt_string& version, const cmt_string& version_alias, const cmt_string& path_alias, Use* context_use, State specified_auto_imports) { bool do_need_new = false; Use* old_use = 0; Use* use = 0; do_need_new = need_new (path, package_name, version, &old_use, context_use); if (Cmt::get_debug ()) { if (old_use != 0) { cout << "add> old_use " << old_use->get_package_name () << " " << old_use->version << " " << old_use->path << endl; } } if (do_need_new) { use = create (path, package_name, version, version_alias, path_alias); } else { // Since we don't need a new Use, it means that old_use exists ! use = old_use; old_use = 0; } if (package_name == CmtSystem::get_home_package ()) { return (use); } if (package_name == CmtSystem::get_user_context_package ()) { return (use); } if (package_name == CmtSystem::get_project_package ()) { return (use); } cmt_string here = CmtSystem::pwd (); // // Store the specified sub_uses. Some of them may become discarded // later on. // if (context_use != 0) { context_use->sub_uses.push_back (use); context_use->sub_use_scopes.push_back (context_use->get_current_scope ()); context_use->sub_use_auto_imports.push_back (specified_auto_imports); cmt_string& request = context_use->requests.add (); request = package_name; request += " "; request += version; request += " "; request += path; if (Cmt::get_debug ()) { cout << "Use::add context(" << context_use->get_package_name () << ") " << "[u:" << package_name << " s:" << context_use->get_current_scope () << " ai:" << specified_auto_imports << "]" << endl; } } if (use == &(Use::current ())) { return (use); } /* * Now we have a Use object. If it is a new one, we have to * 1) understand if it exists physically * 2) it is better than the old ones. * * Here, we may have : * 1) old_use = 0 * there was no Use object before for this package * the existing one is fine * * 2) old_use != 0 * we have created a new Use (which has to be validated) */ bool found = use->move_to (); if (Cmt::get_debug ()) { cout << "add> use [" << use << "] " << use->get_package_name () << " " << use->version << " " << use->path << " found=" << found << " done=" << use->done << endl; show_packages (); } if (!found) { if (!Cmt::get_quiet ()) { cerr << "#CMT> Warning: package " << use->get_package_name () << " " << use->version << " " << use->path << " not found"; if (context_use != 0) { cerr << " (requested by " << context_use->get_package_name () << ")"; } cerr << endl; } //CmtError::set (CmtError::package_not_found, use->get_package_name ()); use = 0; } if ((old_use != 0) && (use != old_use)) { if (Cmt::get_debug ()) { cout << "There was another version of this Use. \n" << "But a new one was created due to some criteria. \n" << "Now we are going to apply the version strategy to make the final selection" << endl; } /* * There was another version of this Use. * But a new one was created due to some criteria. * Now we are going to apply the version strategy to make the final selection. */ if (Cmt::get_debug ()) { cout << "select? [" << use << "] vs old_use[" << old_use << "] " << old_use->get_package_name () << " " << old_use->version << " " << old_use->path << endl; } if (!found) { /* * This new Use does not correspond to any physical package. * let's simply discard it (and go back to old_use) */ if (use != 0) use->discard (); use = old_use; found = use->move_to (); } else { // // This new version is different from the old one // thus we have to choose // static BestFitSelector selector; Use* selected_use = selector.operate (old_use, use); if (Cmt::get_debug ()) { cout << "after operate old=" << old_use << "(" << old_use->m_index << ")" << " use=" << use << "(" << use->m_index << ")" << " => selected=" << selected_use << endl; } // // Some situations managed by selector.operate happen // to fail discarding the rejected Use. // if (use != selected_use) { use = use->set_selected_version (selected_use); } /* * current directory is moved to the selected one */ found = use->move_to (); } } // // The following statement is no longer considered as useful. // It is commented. But we should clarify why it was really needed! // //use->undiscard (); if (found) { static UsePtrVector& uses = get_ordered_uses (); bool registered = false; const Use& cu = Use::current (); Package* package = Package::find (package_name); // // A pointer to this new object is also added or replaced. // if ((use != &cu) && (package == cu.get_package ())) { // This is a recursive call to the current package!! registered = true; use->done = true; use->m_index = -1; } else { // // Now sort out the registration in ordered uses // // cases: // // use is not yet registered (m_index < 0) // o if another use of the same package is registered, // it must be substituted with the new one // o otherwise create a new entry at the end (it will be sorted // afterwards) // // use is already registered (m_index >= 0) // o if another use of the same package is registered, // it must be discarded, but this may mean that // two versions are simultaneously registered (bug?) // o otherwise we keep it in place // UsePtrVector& puses = package->get_uses (); if (use->m_index >= 0) registered = true; /* We look for all existing uses in that package. */ for (int i = 0; i < puses.size(); i++) { Use* u = puses[i]; if (Cmt::get_debug ()) { cout << "add> check registering between " << use << ":" << use->get_package_name () << "(" << use->m_index << ")" << " and " << u << ":" << u->get_package_name () << "(" << u->m_index << ")" << endl; } if ((u != use) && (u->m_index >= 0)) { // Another use of that package is already registered if (Cmt::get_debug ()) { cout << "add> Another use of that package is already registered " << " use(" << use->m_index << ")"; if (use->m_index >= 0) { cout << "[" << (uses[use->m_index])->get_package_name () << "]"; } cout << " u(" << u->m_index << ")"; if (u->m_index >= 0) { cout << "[" << (uses[u->m_index])->get_package_name () << "]"; } cout << endl; } if (use->m_index < 0) { /* the newly selected use (use) should replace the one which was registered (u) */ u->set_selected_version (use); registered = true; } else { // bug?? if (Cmt::get_debug ()) { cout << "Duplicate entry in ordered uses" << endl; } } } } if (Cmt::get_debug ()) { cout << "add> registering completed" << endl; show_packages (); } } if (!registered) { if (Cmt::get_debug ()) { cout << "add> We install use at the end the ordered list of uses" << endl; } uses.push_back (use); use->m_index = uses.size () - 1; } if (Cmt::get_debug ()) { for (int use_index = 0; use_index < uses.size (); use_index++) { Use* u = (Use*) uses[use_index]; cout << " use[" << use_index << "] p=(" << u << ")" << u->get_package_name () << " v=" << u->version << " discarded=" << u->discarded << " selected=" << u->selected << " done=" << u->done << " index=" << u->m_index << endl; } } if (!use->done && Cmt::get_recursive ()) { use->done = true; if (Cmt::get_debug ()) { cout << "Parsing requirements file at " << CmtSystem::pwd () << endl; } SyntaxParser::parse_requirements ("requirements", use); } else { if (Cmt::get_debug ()) { cout << "Requirements file at " << CmtSystem::pwd () << " already parsed" << endl; } } } CmtSystem::cd (here); return (use); } //---------------------------------------------------------- void Use::discard () { discarded = true; } //---------------------------------------------------------- void Use::undiscard () { discarded = false; } //---------------------------------------------------------- void Use::select () { selected = true; } //---------------------------------------------------------- void Use::unselect () { selected = false; } //---------------------------------------------------------- bool Use::is_selected () { return (selected); } /** * Check if the package makes use of the specified package/version * * The seach only considers the first level of uses (thus it is * NOT recursive) */ bool Use::is_client (const cmt_string& used_package, const cmt_string& used_version) { // A package is client of itself Package* package = Package::find (used_package); if ((get_package () == package) && (version == used_version)) return (true); if (discarded) return (false); int i; for (i = 0; i < sub_uses.size (); i++) { Use* use = sub_uses[i]; if (use == 0) continue; if ((use->get_package () == package) && (use->version == used_version)) return (true); /* if (use->is_client (used_package, used_version)) { return (true); } */ } return (false); } //---------------------------------------------------------- void Use::apply_global_patterns () { int i; Pattern::PatternVector& vector = Pattern::patterns (); for (i = 0; i < vector.size (); i++) { Pattern& p = vector[i]; if (p.global) { p.apply (this); } } } //---------------------------------------------------------- void Use::set_include_path (const cmt_string& new_path) { include_path = new_path; } /** * Compute the full real path of a found package. * Takes the structuring style into account * * Result is used to fill in the referenced string * Result does NOT include the trailing file_separator */ void Use::get_full_path (cmt_string& s) const { if (real_path == "") s = CmtSystem::pwd (); else s = real_path; s += CmtSystem::file_separator (); s += get_package_name (); if (style != no_version_style) { s += CmtSystem::file_separator (); s += version; } } /** * Compute the full real path of a found package. * Takes the structuring style into account */ cmt_string Use::get_full_path () const { cmt_string result; get_full_path (result); return (result); } /** * Considering a given path, try and reduce the part of it * that corresponds to the full path of this package into its * normal form ${ROOT} * The argument is modified if the pattern is exactly found. */ void Use::reduce_path (cmt_string& s) const { cmt_string pattern; get_full_path (pattern); pattern += CmtSystem::file_separator (); cmt_string replacement = "${"; replacement += prefix; replacement += "ROOT}"; replacement += CmtSystem::file_separator (); s.replace (pattern, replacement); } //---------------------------------------------------------- void Use::get_cmtpath_and_offset (cmt_string& cmtpath, cmt_string& offset) const { if (get_package_name () == CmtSystem::get_project_package ()) { offset = ""; CmtSystem::dirname (path, cmtpath); return; } else if (get_package_name () == CmtSystem::get_home_package ()) { offset = ""; cmtpath = path; return; } else if (get_package_name () == CmtSystem::get_user_context_package ()) { offset = ""; cmtpath = path; return; } cmtpath = ""; offset = ""; cmtpath = Project::find_in_cmt_paths (real_path); if (cmtpath != "") { CmtSystem::compress_path (cmtpath); static const cmt_string empty_string; static const cmt_string fs = CmtSystem::file_separator (); offset = real_path; offset.replace (cmtpath, empty_string); /** try to remove this current CMTPATH entry from path. This has a meaning when the specified path already contains an absolute path. */ if (offset[0] == CmtSystem::file_separator ()) { // Just in case there is a part left after removing the cmtpath entry offset.replace (fs, empty_string); } } } //---------------------------------------------------------- void Use::fill_includes_macro (cmt_string& buffer) const { if (include_path == "") { buffer += "$(ppcmd)\"$("; buffer += get_package_name (); buffer += "_root)"; buffer += CmtSystem::file_separator (); buffer += "src\" "; } else if (include_path != "none") { buffer += "$(ppcmd)\""; buffer += include_path; buffer += "\" "; } for (int i = 0; i < includes.size (); i++) { Include& incl = includes[i]; buffer += "$(ppcmd)\""; buffer += incl.name; buffer += "\" "; } } //---------------------------------------------------------- void Use::fill_macro (cmt_string& buffer, const cmt_string& suffix) const { buffer += " $("; buffer += get_package_name (); buffer += "_"; buffer += suffix; buffer += ") "; } //---------------------------------------------------------- void Use::fill_standard_macros (cmt_string& buffer) const { static cmt_string fs = CmtSystem::file_separator (); buffer = ""; cmt_string package_name = get_package_name (); buffer += "macro "; buffer += package_name; buffer += "_tag"; buffer += " \"$(tag)\""; buffer += "\n"; if (located ()) { buffer += "macro "; buffer += prefix; buffer += "ROOT"; buffer += " \""; buffer += get_full_path (); buffer += "\""; buffer += "\n"; buffer += "macro "; buffer += package_name; buffer += "_root"; buffer += " \""; buffer += real_path; buffer += fs; buffer += package_name; if (style != no_version_style) { buffer += fs; buffer += version; } buffer += "\""; buffer += "\n"; } buffer += "macro "; buffer += prefix; buffer += "VERSION"; buffer += " \""; buffer += version; buffer += "\""; buffer += "\n"; cmt_string cmtpath = ""; cmt_string offset = ""; get_cmtpath_and_offset (cmtpath, offset); buffer += "macro "; buffer += package_name; buffer += "_cmtpath"; buffer += " \""; buffer += cmtpath; buffer += "\""; buffer += "\n"; buffer += "macro "; buffer += package_name; buffer += "_offset"; buffer += " \""; buffer += offset; buffer += "\""; buffer += "\n"; Project* p = Project::find_by_cmtpath (cmtpath); buffer += "macro "; buffer += package_name; buffer += "_project"; buffer += " \""; if (p != 0) { buffer += p->get_name (); } buffer += "\""; } //---------------------------------------------------------- static bool same_dirs (const cmt_string& d1, const cmt_string& d2) { bool result = false; cmt_string here = CmtSystem::pwd (); cmt_string h1; if (CmtSystem::cd (d1)) h1 = CmtSystem::pwd (); CmtSystem::cd (here); cmt_string h2; if (CmtSystem::cd (d2)) h2 = CmtSystem::pwd (); result = (h1 == h2); CmtSystem::cd (here); return (result); } //---------------------------------------------------------- static bool install_library (const cmt_string& source_library_name, const cmt_string& dest_library_name, const cmt_string& cmtinstallarea, const cmt_string& tag, const cmt_string& symlinkcmd) { cmt_string libname = source_library_name; cmt_string name = dest_library_name; cmt_string s; Use& current_use = Use::current (); Symbol::expand (name); Symbol::expand (libname); if (cmtinstallarea != "") { s = cmtinstallarea; s += CmtSystem::file_separator (); s += tag; s += CmtSystem::file_separator (); s += "lib"; s += CmtSystem::file_separator (); s += name; // Now creating the reference file cmt_string ref_file = s; ref_file += ".cmtref"; cmt_string text = libname; text += "\n"; Symbol::expand (ref_file); Symbol::expand (text); if (!Cmt::get_quiet ()) cout << " Creating the reference file " << ref_file << endl; text.write (ref_file); } else { s = "../$("; s += current_use.get_package_name (); s += "_tag)/"; s += name; } Symbol::expand (s); cmt_string source; cmt_string dest; CmtSystem::dirname (libname, source); CmtSystem::dirname (s, dest); if (same_dirs (source, dest)) { return (false); } //if (!Cmt::get_quiet ()) cout << " Symlinking " << libname << " to " << s << endl; if (symlinkcmd == "") { if (!CmtSystem::create_symlink (libname, s)) { cerr << "#CMT> Cannot create a symbolic link to " << libname << endl; return (false); } } else { cmt_string cmd = symlinkcmd; cmd += " "; cmd += libname; cmd += " "; cmd += s; int status = CmtSystem::execute (cmd); if (status != 0) { cerr << "#CMT> Cannot create a symbolic link to " << libname << endl; return (false); } } return (true); } /** Centralize the construction of library links for this Use. */ void Use::build_library_links (const cmt_string& cmtinstallarea, const cmt_string& tag, const cmt_string& shlibsuffix, const cmt_string& symlinkcmd) const { if (!located ()) { if (!Cmt::get_quiet ()) { cout << "# package " << get_package_name () << " " << version << " " << path << " not found" << endl; } return; } cmt_string s; s = get_package_name (); s += "_libraries"; Symbol* libraries_macro = Symbol::find (s); if (libraries_macro == 0) return; cmt_string libraries = libraries_macro->build_macro_value (); Symbol::expand (libraries); static CmtSystem::cmt_string_vector values; CmtSystem::split (libraries, " \t", values); for (int j = 0; j < values.size (); j++) { const cmt_string& library = values[j]; static cmt_string libname; static cmt_string name; // Is it a simple name or a complete path? libname = library; Symbol::expand (libname); bool is_absolute = false; is_absolute = CmtSystem::absolute_path (libname); if (is_absolute) { /** * We assume here that "library" contains a complete path. * (including the complete syntax libxxx.so) */ cmt_string suffix; CmtSystem::basename (library, name); } else { /** * Here we expect that only the base name of the library * is given : ie it should not contain the "lib" prefix, * nor the suffix .so, nor any path prefix. * This of course should generally correspond to a constituent name. */ libname = "${"; libname += prefix; libname += "ROOT}/${"; libname += get_package_name (); libname += "_tag}/"; libname += "$(library_prefix)"; libname += library; libname += "$(library_suffix)"; libname += "."; libname += shlibsuffix; name = "$(library_prefix)"; name += library; name += "$(library_suffix)"; name += "."; name += shlibsuffix; } if (!install_library (libname, name, cmtinstallarea, tag, symlinkcmd)) { continue; } #ifdef __APPLE__ if (!is_absolute) { libname = "${"; libname += prefix; libname += "ROOT}/${"; libname += get_package_name (); libname += "_tag}/"; libname += library; libname += ".bundle"; name = library; name += ".bundle"; if (!install_library (libname, name, cmtinstallarea, tag, symlinkcmd)) { continue; } } #endif } } /** * This function tries to get the replacement of a Use when it has * been discarded by a better match to version constraints. */ Use* Use::get_selected_version () { //cout << "get_selected_version for package " << get_package_name () << endl; if (!discarded) return (this); Package* p = m_package; Use::UsePtrVector& uses = p->get_uses (); bool dbg = Cmt::get_debug (); int size = uses.size (); for (int i = 0; i < size; i++) { Use* u = uses[i]; if (u == 0) continue; if (u->discarded) continue; if (dbg) { cout << "Use::get_selected_version> for package " << get_package_name () << " got a version " << u << endl; } return (u); } return (0); } /** Switching from one use to another one, (better wrt various criteria). When switching, m_index and auto_imports are transfered from the un-selected to the newly selected. */ Use* Use::set_selected_version (Use* selected_use) { if (this == selected_use) return (this); static UsePtrVector& uses = get_ordered_uses (); if (m_index >= 0) { // This discarded package was registered. We have to substitute // it with the new one. selected_use->m_index = m_index; selected_use->auto_imports = auto_imports; selected_use->undiscard (); m_index = -1; uses[selected_use->m_index] = selected_use; } discard (); return (selected_use); } void Use::set_auto_imports (State new_state) { if (Cmt::get_debug ()) { cout << "Use::set_auto_imports>(" << get_package_name () << ") " << auto_imports << " -> " << new_state << endl; } if (auto_imports == new_state) return; State old_state = auto_imports; auto_imports = new_state; // We propagate only when we switch from Off to On if ((old_state == Off) && (new_state == On)) { cmt_string s; static const cmt_string state_text[] = {"Unspecified", "Off", "On"}; if (Cmt::get_debug ()) { s = "Use::set_auto_imports>("; s += get_package_name (); s += ") "; cout << s << endl; } for (int i = 0; i < sub_uses.size (); i++) { Use* u = sub_uses[i]; State state = sub_use_auto_imports[i]; if (Cmt::get_debug ()) { s += " "; s += u->get_package_name (); s += "("; s += state_text[state]; s += ")"; } if (state == Unspecified) { u->set_auto_imports (On); } } if (Cmt::get_debug ()) { cout << s << endl; } } } void Use::set_native_version (bool state) { m_has_native_version = state; } bool Use::has_native_version () const { return (m_has_native_version); } Package* Use::get_package () const { return (m_package); } const cmt_string& Use::get_package_name () const { static const cmt_string null = ""; Package* p = m_package; if (p == 0) return (null); return (p->get_name ()); } void Use::set_package_name (const cmt_string& name) { Package* p = Package::add (name); m_package = p; p->add_use (this); } int Use::get_index () const { return (m_index); } //---------------------------------------------------------- bool Use::get_all_clients (const cmt_string& to_name) { Use::UsePtrVector& uses = Use::get_ordered_uses (); Use* use = Use::find (to_name); if (use == 0) { cerr << "#CMT> No access to " << to_name << endl; return (false); } cmt_map all_clients; cmt_map all_clients_ok; const cmt_string& name = get_package_name (); Use* me = this; all_clients.add (name, me); all_clients_ok.add (name, me); bool status = get_all_clients (use, to_name, all_clients, all_clients_ok); return (status); } //---------------------------------------------------------- bool Use::get_all_clients (Use* to, const cmt_string& result, cmt_map & all_clients, cmt_map & all_clients_ok) { if (this == to) { cout << result << endl; return (true); } const cmt_string& to_name = to->get_package_name (); const cmt_string& to_version = to->version; //cout << "gac> from " << get_package_name () << " to " << to_name << " -> " << result << endl; if (all_clients.has (to_name)) { if (all_clients_ok.has (to_name)) { cout << " ..." << result << endl; return (true); } else { return (false); } } all_clients.add (to_name, to); bool status = false; Use::UsePtrVector& uses = Use::get_ordered_uses (); Use* use = 0; for (int n = 0; n < uses.size (); ++n) { use = uses[n]; if (use->discarded) continue; if (!use->located ()) continue; if (use == to) continue; if (use->is_client (to_name, to_version)) { const cmt_string& n = use->get_package_name (); cmt_string r; if ((use->initial_scope != ScopeUnspecified) && (use->initial_scope != ScopePublic)) { r += "(private)"; } if (use->auto_imports == Off) r += "(no_auto_imports)"; r += n; r += "."; r += result; //cout << "gac> " << n << " is client of " << to_name << endl; if (get_all_clients (use, r, all_clients, all_clients_ok)) { all_clients_ok.add (n, use); status = true; } } } use = this; if (use->is_client (to_name, to_version)) { const cmt_string& n = use->get_package_name (); cmt_string r; if ((use->initial_scope != ScopeUnspecified) && (use->initial_scope != ScopePublic)) { r += "(private)"; } if (use->auto_imports == Off) r += "(no_auto_imports)"; r += n; r += "."; r += result; //cout << "gac> " << n << " is client of " << to_name << endl; if (get_all_clients (use, r, all_clients, all_clients_ok)) { all_clients_ok.add (n, use); status = true; } } return (status); } /** Let's consider two packages in the use graph "this" and "to" This function finds all packages that are reached in between following all possible paths between "this" and "to" Result s accumulated into "list" */ bool Use::get_paths (Use* to, UsePtrVector& list) { bool is_in_path = false; bool cycle = false; bool already_in_path = false; bool dbg = Cmt::get_debug (); static int level = 0; int size = 0; if (level == 0) { unselect_all (); selected = false; } if (selected) { /** If this use is already in the list, we don't duplicate the entry. (protection duplicate paths in the graph) */ size = list.size (); for (int m = 0; m < size; m++) { Use* u = list[m]; if (u == this) { if (dbg) { for (int lll = 0; lll < level; lll++) cout << " "; cout << " Use::get_paths." << level << "> try1.2 sub=" << get_package_name () << " already_in_path " << endl; } return (true); } } return (false); } selected = true; if (dbg) { for (int lll = 0; lll < level; lll++) cout << " "; cout << "Use::get_paths." << level << ">" << get_package_name () << " to=" << to->get_package_name () << " list=["; for (int m = 0; m < list.size (); m++) { Use* u = list[m]; cout << u->get_package_name () << " "; } cout << "]" << endl; } /** Now "this" is a candidate new entry in the list */ // First figure out whether 'to' is used by 'this'. if (this->get_package_name () == to->get_package_name ()) { // We've reached the goal (for the first time) is_in_path = true; } else { /** Let's scan sub_uses now */ size = sub_uses.size (); if (dbg) { for (int lll = 0; lll < level; lll++) cout << " "; cout << " Use::get_paths." << level << "> size=" << size << endl; } for (int n = 0; n < size; n++) { Use* use = sub_uses[n]; if (use == 0) continue; if (dbg) { for (int lll = 0; lll < level; lll++) cout << " "; cout << " Use::get_paths." << level << "> try1 sub=" << use->get_package_name () << "(" << use << ") " << use->discarded << endl; } if (use->discarded) { Use* u; u = use->get_selected_version (); if (u == 0) { /** No way to find a valid use for this used package. Is that a bug? Anyway we don't pursue on that branch. */ continue; } use = u; } if (dbg) { for (int lll = 0; lll < level; lll++) cout << " "; cout << " Use::get_paths." << level << "> try2 sub=" << use->get_package_name () << " " << use->discarded << endl; } level++; bool r = use->get_paths (to, list); level--; if (r) { is_in_path = true; } } } if (is_in_path) { if (dbg) { for (int lll = 0; lll < level; lll++) cout << " "; cout << "Use::get_paths." << level << "> push " << get_package_name () << endl; } list.push_back (this); } return (is_in_path); } //---------------------------------------------------------- bool Use::located () const { return (m_located); } //---------------------------------------------------------- void Use::show_sub_uses (const cmt_string& request, bool skip_discarded) { Use* current = &(Use::current ()); int n; Use* use; static int level = 0; if (skip_discarded && discarded) return; if (level > 0) { cout << "# "; for (n = 0; n < (level-1); n++) cout << " "; if (request == "") { cout << "use " << get_package_name () << " " << specified_version; if (this == current) { cout << " (current)"; } else { if (specified_path != "") cout << " " << specified_path; } } else { cout << "use " << request; } if (version_alias != "") { cout << " | " << version_alias << " " << path_alias; } if (initial_scope == ScopeUnspecified) cout << " (unspecified)"; else if (initial_scope != ScopePublic) cout << " (private)"; if (auto_imports == Off) cout << " (no_auto_imports)"; if (style == no_version_style) cout << " (no_version_directory)"; if (m_has_native_version) { cmt_string n = get_package_name (); n += "_native_version"; Symbol* s = Symbol::find (n); if (s != 0) { cmt_string value = s->resolve_macro_value (); cout << " (native_version=" << value << ")"; } } cout << endl; } if (selected) return; selected = true; level++; for (n = 0; n < sub_uses.size (); n++) { use = sub_uses[n]; if (use == 0) continue; const cmt_string& request = requests[n]; ScopeType saved_scope = use->initial_scope; State saved_state = use->auto_imports; use->initial_scope = sub_use_scopes[n]; use->auto_imports = sub_use_auto_imports[n]; use->show_sub_uses (request, skip_discarded); use->initial_scope = saved_scope; use->auto_imports = saved_state; } level--; } //---------------------------------------------------------- Use& Use::current () { static UseVector& instances = get_instances (); static Use* current_use = 0; if ((current_use == 0) || (instances.size () == 0)) { Use& use_object = instances.add (); current_use = &use_object; } return (*current_use); } //---------------------------------------------------------- const Use& Use::const_current () { const Use& use = Use::current (); return (use); } //---------------------------------------------------------- Use::UseVector& Use::get_instances () { static Database& db = Database::instance (); static UseVector& instances = db.all_uses (); return (instances); } //---------------------------------------------------------- Use::UsePtrVector& Use::get_ordered_uses () { static Database& db = Database::instance (); static UsePtrVector& uses = db.uses (); return (uses); } //---------------------------------------------------------- //---------------------------------------------------------- // // Check if the specified version is better than the // current one. // //---------------------------------------------------------- Use* BestFitSelector::operate (Use* ref_use, Use* new_use) { Use* selected = ref_use; int ref_v = -1; int ref_r = -1; int ref_p = -1; cmt_string ref_pp; int new_v = -1; int new_r = -1; int new_p = -1; cmt_string new_pp; int alias_v = -1; int alias_r = -1; int alias_p = -1; cmt_string alias_pp; enum { no_alias, new_has_alias, ref_has_alias } has_alias = no_alias; // First analyze specified versions cmt_string ref_version = ref_use->specified_version; cmt_string new_version = new_use->specified_version; CmtSystem::is_version_directory (ref_version, ref_v, ref_r, ref_p); ref_pp = ref_use->path; CmtSystem::is_version_directory (new_version, new_v, new_r, new_p); new_pp = new_use->path; if (new_use->version_alias != "") { has_alias = new_has_alias; CmtSystem::is_version_directory (new_use->version_alias, alias_v, alias_r, alias_p); alias_pp = new_use->path_alias; } else if (ref_use->version_alias != "") { has_alias = ref_has_alias; CmtSystem::is_version_directory (ref_use->version_alias, alias_v, alias_r, alias_p); alias_pp = ref_use->path_alias; } ref_use->undiscard (); new_use->undiscard (); if (new_v != ref_v) { if (has_alias != no_alias) { if (has_alias == new_has_alias) { new_v = alias_v; new_r = alias_r; new_p = alias_p; new_pp = alias_pp; } else if (has_alias == ref_has_alias) { ref_v = alias_v; ref_r = alias_r; ref_p = alias_p; ref_pp = alias_pp; } } } bool ref_v_wildcarded = ((ref_v) == -1); bool ref_r_wildcarded = ((ref_r) == -1); bool ref_p_wildcarded = ((ref_p) == -1); bool ref_v_explicit = !ref_v_wildcarded; bool ref_r_explicit = !ref_r_wildcarded; bool ref_p_explicit = !ref_p_wildcarded; bool new_v_wildcarded = ((new_v) == -1); bool new_r_wildcarded = ((new_r) == -1); bool new_p_wildcarded = ((new_p) == -1); bool new_v_explicit = !new_v_wildcarded; bool new_r_explicit = !new_r_wildcarded; bool new_p_explicit = !new_p_wildcarded; bool verbose = (CmtSystem::getenv ("CMTVERBOSE") != ""); cmt_string ref_vc = ref_v_wildcarded ? "wildcarded" : "explicit"; cmt_string ref_rc = ref_r_wildcarded ? "wildcarded" : "explicit"; cmt_string ref_pc = ref_p_wildcarded ? "wildcarded" : "explicit"; cmt_string new_vc = new_v_wildcarded ? "wildcarded" : "explicit"; cmt_string new_rc = new_r_wildcarded ? "wildcarded" : "explicit"; cmt_string new_pc = new_p_wildcarded ? "wildcarded" : "explicit"; // Now compute effective version identifiers CmtSystem::is_version_directory (ref_use->version, ref_v, ref_r, ref_p); CmtSystem::is_version_directory (new_use->version, new_v, new_r, new_p); cmt_string new_selected_version = new_use->version; if (new_v_explicit && ref_v_explicit && (new_v != ref_v)) { if (verbose && !Cmt::get_quiet ()) { cerr << "# Required explicit version " << new_version << " of package " << ref_use->get_package_name () << " incompatible with selected explicit version " << ref_version << endl; } CmtError::set (CmtError::version_conflict, "BestFitSelector::operate> "); if (ref_use != new_use) new_use->discard (); } else if (new_v_wildcarded || ref_v_wildcarded) { // at least one of ref or new is wildcarded // // we plan to discard new_use, but if it was specified as explicit // and ref_use was wildcarded then new_use will win !! // // So then we'll have to understand where are the wild // cards... If they are on v or r, then we consider them. // // if (ref_v_wildcarded && new_v_explicit) { if ((ref_use->real_path != new_use->real_path) || (ref_use->version != new_use->version)) { if (ref_use != new_use) ref_use->discard (); selected = new_use; selected->done = false; // Will read the new requirements if (verbose && !Cmt::get_quiet ()) { cerr << "# Select explicit version " << new_version << "(" << new_use->version << ")" << " of package " << ref_use->get_package_name () << " instead of existing wildcarded " << ref_version << "(" << ref_use->version << ")" << endl; } } else { if (ref_use != new_use) new_use->discard (); //ref_use->version = new_selected_version; } } else { // ref is explicit or new is wildcarded /* if (verbose && !Cmt::get_quiet ()) { cerr << "# keep " << ref_vc << " version " << ref_version << " of package " << ref_use->get_package_name () << " (ignore " << new_vc << " version " << new_version << ")" << endl; } */ if (ref_use != new_use) new_use->discard (); } } else if (new_r_wildcarded || ref_r_wildcarded || (new_r < ref_r)) { // // we plan to discard new_use, but if it was specified as explicit // and ref_use was wildcarded then new_use will win !! // // So then we'll have to understand where are the wild // cards... If they are on v or r, then we consider them. // // if (ref_r_wildcarded && new_r_explicit) { // ref has wild card and new has not => new wins if ((ref_use->real_path != new_use->real_path) || (ref_use->version != new_use->version)) { if (ref_use != new_use) ref_use->discard (); selected = new_use; selected->done = false; // Will read the new requirements if (verbose && !Cmt::get_quiet ()) { cerr << "# Select explicit release " << new_version << " of package " << ref_use->get_package_name () << " instead of existing wildcarded " << ref_version << endl; } } else { // Just adapt version with new one. if (ref_use != new_use) new_use->discard (); //ref_use->version = new_selected_version; } } else { /* if (verbose &&!Cmt::get_quiet ()) { cerr << "# keep " << ref_rc << " release " << ref_version << " of package " << ref_use->get_package_name () << " (ignore " << new_rc << " release " << new_version << ")" << endl; } */ if (ref_use != new_use) new_use->discard (); } } else if (new_r > ref_r) { if (verbose && !Cmt::get_quiet ()) { cerr << "# Select " << new_rc << " release " << new_version << " of package " << ref_use->get_package_name () << " instead of existing " << ref_rc << " " << ref_version << endl; } if (ref_use != new_use) ref_use->discard (); selected = new_use; selected->done = false; // Will read the new requirements } else if (new_p_wildcarded || ref_p_wildcarded || (new_p < ref_p)) { // // we plan to discard new_use, but if it was specified as explicit // and ref_use was wildcarded then new_use will win !! // if (ref_p_wildcarded && new_p_explicit) { if ((ref_use->real_path != new_use->real_path) || (ref_use->version != new_use->version)) { if (ref_use != new_use) ref_use->discard (); selected = new_use; selected->done = false; // Will read the new requirements if (verbose && !Cmt::get_quiet ()) { cerr << "# Select explicit patch " << new_version << " of package " << ref_use->get_package_name () << " instead of existing wildcarded " << ref_version << endl; } } else { if (ref_use != new_use) new_use->discard (); ref_use->version = new_selected_version; } } else { /* if (verbose && !Cmt::get_quiet ()) { cerr << "# keep " << ref_pc << " patch " << ref_version << " [" << ref_use->specified_version << "]" << " of package " << ref_use->get_package_name () << " (ignore " << new_pc << " version " << new_version << ")" << " [" << new_use->specified_version << "]" << endl; } */ if (ref_use != new_use) new_use->discard (); } } else if (new_p > ref_p) { if (verbose && !Cmt::get_quiet ()) { cerr << "# Select " << new_pc << " patch " << new_version << " of package " << ref_use->get_package_name () << " instead of existing " << ref_pc << " " << ref_version << endl; } if (ref_use != new_use) ref_use->discard (); selected = new_use; selected->done = false; // Will read the new requirements } else if (new_pp != ref_pp) // same version-r-p but from different path { if (ref_use != new_use) ref_use->discard (); selected = new_use; selected->done = false; // Will read the new requirements } return (selected); } Package* Package::find (const cmt_string& name) { static PackageMap& PackageMap = package_map (); Package* result = 0; result = PackageMap.find (name); return (result); } Package* Package::add (const cmt_string& name) { static PackageVector& Packages = packages (); static PackageMap& PackageMap = package_map (); { Package* package; package = find (name); if (package != 0) return (package); } Package& package = Packages.add (); PackageMap.add (name, package); package.m_name = name; if (name == "CMT") { package.m_is_cmt = true; } else if (name == "methods") { package.m_is_cmt = true; } if (Cmt::get_debug ()) { cout << "Package::add (" << name << ")" << endl; } return (&package); } Package::PackageVector& Package::packages () { static Database& db = Database::instance (); static PackageVector& Packages = db.packages (); return (Packages); } Package::PackageMap& Package::package_map () { static Database& db = Database::instance (); static PackageMap& PackageMap = db.package_map (); return (PackageMap); } void Package::clear_all () { static PackageVector& Packages = packages (); static PackageMap& PackageMap = package_map (); PackageMap.clear (); Packages.clear (); } Package::Package () : m_is_cmt (false) { if (Cmt::get_debug ()) { cout << "Package::Package" << endl; } } Package::~Package () { m_name = ""; } const cmt_string& Package::get_name () const { return (m_name); } void Package::add_use (Use* use) { for (int i = 0; i < m_uses.size (); i++) { Use* u = m_uses[i]; if (u == use) return; } m_uses.push_back (use); } void Package::remove_use (Use* use) { if (Cmt::get_debug ()) { cout << "Package::remove_use (" << use->get_package_name () << ")" << endl; cout << " name=" << m_name << " uses=" << m_uses.size () << endl; } Use::UsePtrVector temp; temp = m_uses; m_uses.clear (); for (int i = 0; i < temp.size (); i++) { Use* u = temp[i]; if (u != use) { m_uses.push_back (u); } } } Use::UsePtrVector& Package::get_uses () { return (m_uses); } bool Package::is_cmt () { return (m_is_cmt); } static void show_packages () { Package::PackageVector& vector = Package::packages (); int i; int j; cout << "### Packages: "; for (i = 0; i < vector.size (); i++) { Package& p = vector[i]; cout << p.get_name () << "["; Use::UsePtrVector& uses = p.get_uses (); for (j = 0; j < uses.size (); j++) { Use* u = uses[j]; cout << u << ","; } cout << "] "; } cout << endl; { static Use::UsePtrVector& uses = Use::get_ordered_uses (); cout << "### Uses: "; for (i = 0; i < uses.size (); i++) { Use* u = uses[i]; cout << "[" << u << "]" << u->get_package_name () << " "; } } cout << endl; }