//-----------------------------------------------------------
// Copyright Christian Arnault LAL-Orsay CNRS
// arnault@lal.in2p3.fr
// Modified by garonne@lal.in2p3.fr
// Modified by Grigory Rybkin
// See the complete license in cmt_license.txt "http://www.cecill.info". 
//-----------------------------------------------------------

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "cmt_use.h"
#include "cmt_system.h"
#include "cmt_symbol.h"
#include "cmt_error.h"
#include "cmt_database.h"
#include "cmt_syntax.h"
#include "cmt_log.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 <cmt_string, bool> 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 = Unspecified;
    //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);
  }

  static State mask_auto_imports (State context_state, State auto_imports)
  {
    switch (auto_imports)
      {
      case Unspecified:
	return context_state;
	break;
      case Off:
	return Off;
	break;
      case On:
	if (context_state != Off)
	  return On;
	else
	  return context_state;
	break;
      // warning C4715: 'UseContext::mask_auto_imports' : not all control paths return a value
      // on Visual Studio .NET 2003
      default:
          return context_state;
        break;
      }
  }

private:
  State m_auto_imports;
};


class BestFitSelector
{
public:
  Use* operate (Use* ref_use, Use* new_use);
};

//----------------------------------------------------------

typedef enum
  {
    IdenticalIds,

    IncompatibleMajorIds,
    NewMajorIdGreaterThanOld,
    OldMajorIdGreaterThanNew,
    ExplicitOldMajorIdWinsAgainstWildarded,
    ExplicitNewMajorIdWinsAgainstWildarded,

    ExplicitOldMinorIdWinsAgainstWildarded,
    ExplicitNewMinorIdWinsAgainstWildarded,
    NewMinorIdGreaterThanOld,

    ExplicitOldPatchIdWinsAgainstWildarded,
    ExplicitNewPatchIdWinsAgainstWildarded,
    NewPatchIdGreaterThanOld
  } CompareStatus;

static CompareStatus compare_versions (const cmt_string& ref_version, const cmt_string& new_version, bool match = false)
{
  CompareStatus result = IdenticalIds;

  if (match)
    {
      if (ref_version == "" ||
	  ref_version == "*" ||
	  ref_version == "v*")
	return IdenticalIds;

      int wild_card = ref_version.find ('*');
      if (wild_card != cmt_string::npos)
	{
	  cmt_string ref_ver (ref_version.substr (0, wild_card));
	  if (ref_ver.size () > new_version.size ())
	    return IncompatibleMajorIds;
	  else if (strncmp (ref_ver.c_str (), new_version.c_str (), wild_card) == 0)
	    return IdenticalIds;
	  else
	    return IncompatibleMajorIds;
	}
      else if (ref_version == new_version)
	    return IdenticalIds;
      else
	    return IncompatibleMajorIds;
    }

  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 ())
	{
	cerr << "#1 Required version " << new_version <<
	" incompatible with selected version " << ref_version <<
	endl;
	}
      */

      if (new_v > old_v)
	{
	  result = NewMajorIdGreaterThanOld;
	}
      else
	{
	  result = OldMajorIdGreaterThanNew;
	}
      //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 ())
	    {
	    cerr << "#2 Select version " << new_version <<
	    " instead of existing " << ref_version <<
	    endl;
	    }
	  */

          result = ExplicitNewMajorIdWinsAgainstWildarded;
	}
      else
	{
	  /*
	    if (!Cmt::get_quiet ())
	    cerr << "#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 ())
	    {
	    cerr << "#4 Select release " << new_version
	    << " instead of existing " << ref_version
	    << endl;
	    }
	  */

          result = ExplicitNewMinorIdWinsAgainstWildarded;
	}
      else
	{
	  /*
	    if (!Cmt::get_quiet ())
	    cerr << "#5 keep release " << ref_version <<
	    " (ignore release " << new_version << ")" <<
	    endl;
	  */

          result = ExplicitOldMinorIdWinsAgainstWildarded;
	}
    }
  else if (new_r > old_r)
    {
      /*
	if (!Cmt::get_quiet ())
        {
	cerr << "#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 ())
	    {
	    cerr << "#7 Select patch " << new_version <<
	    " instead of existing " << ref_version <<
	    endl;
	    }
	  */

	  result = ExplicitNewPatchIdWinsAgainstWildarded;
	}
      else
	{
	  /*
	    if (!Cmt::get_quiet ())
	    cerr << "#8 keep patch " << ref_version <<
	    " (ignore version " << new_version << ")" <<
	    endl;
	  */

	  result = ExplicitOldPatchIdWinsAgainstWildarded;
	}
    }
  else if (new_p > old_p)
    {
      /*
	if (!Cmt::get_quiet ())
        {
	cerr << "#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, ostream& out, PrintMode mode)
//void Use::show_all (bool skip_discarded, ostream& out)
//void Use::show_all (bool skip_discarded)
{
  show_all ("use ", skip_discarded, out, mode);
  //  show_all ("use ", skip_discarded, out);
}

//----------------------------------------------------------
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, ostream& out, PrintMode mode)
//void Use::show_all (const cmt_string& prefix, bool skip_discarded, ostream& out)
//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 ();
  cmt_map <Use*, bool> visited;
  if (!Cmt::get_quiet () && mode != Xml) use->show_sub_uses (visited, "", use->auto_imports, skip_discarded, out);

  if (uses.size () > 0)
    {
      if (!Cmt::get_quiet () && mode != Xml)
        {
          out << "#\n";
          out << "# 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);

      switch (mode)
	{
	case Xml :
	  Cmt::print_xml_prolog ("uses", out);
	  out << "<uses>";
	  break;
        default:
	  break;
	}
      
      for (number = uses.size () - 1; number >= 0; number--)
        {
          use = uses[number];

          if (use->discarded) continue;
          if (use->m_hidden) continue;

          if (!use->located ())
            {
	      CmtMessage::warning ("package " + use->get_package_name ()
				   + " " + use->version + " " + use->path
				   + " not found");
	      /*
              if (!Cmt::get_quiet ())
                {
                  out << "# package " << use->get_package_name () <<
		    " " << use->version << " " << use->path << 
		    " not found" <<
		    endl;
                }
	      */
              CmtError::set (CmtError::package_not_found, use->get_package_name ());
            }
          else
            {
	      switch (mode)
		{
		case Xml :
		  Symbol* s;
		  out << "<package"
		      << (use->auto_imports == Off ? " auto_imports=\"no\"" : "")
		      << ">";
		  // out << "<order>" << use->get_index () << "</order>";
		  out << "<name>" << use->get_package_name ()
		      << "</name><version>" << use->version << "</version>";
		  out << "<offset>" <<
		    ( (s = Symbol::find (use->get_package_name () + "_offset"))
		      ? s->build_macro_value ()
		      : (CmtMessage::warning
			 (CmtError::get_error_name (CmtError::symbol_not_found)
			  + ": macro " + use->get_package_name () + "_offset")
			 , "") )
		      << "</offset>";
		  out << "<cmtpath>" <<
		    ( (s = Symbol::find (use->get_package_name () + "_cmtpath"))
		      ? s->build_macro_value ()
		      : (CmtMessage::warning
			 (CmtError::get_error_name (CmtError::symbol_not_found)
			  + ": macro " + use->get_package_name () + "_cmtpath")
			 , "") )
		      << "</cmtpath>";
		  //out << "<offset>" << use->path << "</offset>";
		  //out << "<cmtpath>" << p << "</cmtpath>";
		  out << "<root>" << use->get_full_path () << "</root>";
                  //if (use->auto_imports == Off)
		  //out << "<no_auto_imports/>";
		  out << "</package>";
		  break;
		default :
              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)
		    {
		      if (pos > 0 &&
			  p[pos - 1] == CmtSystem::file_separator ())
			{
			  // strip trailing file separator
			  p.erase (pos - 1);
			}
		      else
			p.erase (pos);
		    }
		}

              out << prefix << use->get_package_name ()
		   << " " << use->version;

	      if (CmtSystem::absolute_path (use->path))
		{
		  if (!Cmt::get_quiet ()) 
		    {
		      out << " (" << use->path << ")";
		    }
		}
	      else
		{
		  out << " " << use->path;
		}

              if (!Cmt::get_quiet ()) 
                {
                  if (p != "") out << " (" << p << ")";
                  if (use->auto_imports == Off) out << " (no_auto_imports)";
                }

              out << endl;
		  break;
		}
            }
        }

      Use* suse = Use::find (CmtSystem::get_home_package ());
      if (suse != 0 && !suse->discarded && !suse->m_hidden && suse->located ())
	{
	  switch (mode)
	    {
	    case Xml :
	      out << "<package>";
	      out << "<name>" << suse->get_package_name ()
		  << "</name><version>" << suse->version << "</version>";
	      out << "<offset></offset>";
	      out << "<cmtpath>" << suse->path << "</cmtpath>";
	      out << "<root>" << suse->path << "</root>";
	      out << "</package>";
	      break;
	    default :
	  out << prefix << suse->get_package_name ()
	       << " " << suse->version;
	  if (!Cmt::get_quiet ()) 
	    {
	      out << " (" << suse->path << ")";
	    }
	  out << endl;
	      break;
	    }
	}
      suse = Use::find (CmtSystem::get_user_context_package ());
      if (suse != 0 && !suse->discarded && !suse->m_hidden && suse->located ())
	{
	  switch (mode)
	    {
	    case Xml :
	      out << "<package>";
	      out << "<name>" << suse->get_package_name ()
		  << "</name><version>" << suse->version << "</version>";
	      out << "<offset></offset>";
	      out << "<cmtpath>" << suse->path << "</cmtpath>";
	      out << "<root>" << suse->path << "</root>";
	      out << "</package>";
	      break;
	    default :
	  out << prefix << suse->get_package_name ()
	       << " " << suse->version;
	  if (!Cmt::get_quiet ()) 
	    {
	      out << " (" << suse->path << ")";
	    }
	  out << endl;
	      break;
	    }
	}

      switch (mode)
	{
	case Xml :
	  out << "</uses>" << endl;
	  break;
        default:
	  break;
	}
      /*
      if (Cmt::get_cmt_home () != "")
        {
          out << prefix << CmtSystem::get_home_package () << " v0";
	  if (!Cmt::get_quiet ()) 
	    {
	      out << " (" << Cmt::get_cmt_home () << ")";
	    }
	  out << endl;
        }

      if (Cmt::get_cmt_user_context () != "")
        {
          out << prefix << CmtSystem::get_user_context_package () << " v0";
	  if (!Cmt::get_quiet ()) 
	    {
	      out << " (" << Cmt::get_cmt_user_context () << ")";
	    }
	  out << endl;
        }
      */
    }
 
  const UseVector& instances = get_instances ();
  for (int use_index = 0; use_index < instances.size (); use_index++)
    {
      Use* use = &(instances[use_index]);
      //Use* use = uses[j];
      
      if (use->discarded) continue;
      if (use->m_hidden) continue;
      
      if (!use->located ())
	{
	  if (use->get_package_name () == "cmt_standalone") continue;
	  CmtError::set (CmtError::package_not_found, use->get_info ());
	}
    }
}

/**
 *   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.find (0, "-native_version=") != -1)
      {
	native_version = w.substr (16);
      }
    else 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;
          default:
	    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 << "(" << version << ")" << " ";

	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.
     */
    //UseContext::set_current (UseContext::mask_auto_imports (UseContext::get_current_auto_imports (), auto_imports));
    /*
    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, native_version,
                                 parent, auto_imports);

        if (new_use != 0)
          {
            if (Cmt::get_debug ())
              {
                cout << "after adding1 " << package
		     << "> auto_imports=" << new_use->auto_imports << endl;

		//show_packages ();
              }
	    /*
	    if (&(Use::current()) == parent)
	      {
		cmt_map <Use*, bool> visited;
		static bool yes (true);
		visited.add (&(Use::current()), yes);
		new_use->set_auto_imports
		  (UseContext::mask_auto_imports (Use::current().auto_imports,
						  auto_imports),
		   auto_imports, visited);
	      }
	    */
	    //new_use->set_auto_imports (UseContext::get_current_auto_imports (),
	    //		       auto_imports);
	    /*
            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 () != 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 (UseContext::get_current_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;
              }
          }
	/*
        else // new_use == 0
          {
	    cerr << "action: " << action << " new_use: " <<  new_use
		 << " package: " <<  package << endl;

	    CmtError::set (CmtError::package_not_found, package);
	  }
	*/

        return (new_use);
  }

private:

  enum
    {
      need_package,
      need_version,
      need_path,
      need_version_alias,
      need_path_alias,
      finished
    } state;
  
  State auto_imports;
  cmt_string native_version;
  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 <package> <version> <path> <-native_version=<version>>"  
  // minimal syntax  : "use <package>"
  //
  //  o if <version> is omitted then take any version available
  //  o <version> can be specified using "v*" or "v<n>r*" or "v<n>r<m>p*"
  //
  //  o the notation "v*" is preferred to omission (particularly since
  //    omission does not permit <path>)
  //
  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);
}

//----------------------------------------------------------
/**
 *    Find by @package@ Use-object that is
 *    o not discarded
 *    o in ordereded Uses list (i.e., has non-negative m_index)
 */
//----------------------------------------------------------
Use* Use::find_valid (const cmt_string& package)
{
  Package* p = Package::find (package);
  if (p == 0) return (0);

  UsePtrVector& uses = p->get_uses ();

  for (int use_index = 0; use_index < uses.size (); use_index++)
    {
      Use* use = uses[use_index];

      if (use->discarded) continue;
      if (use->m_index < 0) continue;
      // take the first not discarded and ordered
      // there should not be more than one
      return use;
    }

  return (0);
}

//----------------------------------------------------------
void Use::set_auto_imports_state (const Use::UsePtrVector& uses,
				  cmt_vector<bool>& auto_imports_states)
{
  if (0 == uses.size ()) return;

  static int level (0);
  if (level == 0)
    {
      unselect_all ();
      Use::current().select ();
    }

  if (Cmt::get_debug ())
    {
      cout << "Use::set_auto_imports_state>|";
      for (int i = level; i > 0; i--) cout << "-";
      for (int i = 0; i < uses.size (); i++)
      //for (int i = uses.size () - 1; i >= 0; i--)
	{
	  cout << " " << uses[i]->get_package_name ()
	       << "(" << uses[i]->auto_imports << ")";
	}
      cout << ">" << endl;
    }

  for (int i = 0; i < uses.size (); i++)
  //for (int i = uses.size () - 1; i >= 0; i--)
    {
      const Use* use = uses[i];
      if (!auto_imports_states[use->m_index])
	auto_imports_states[use->m_index] = true;
    }

  Use::UsePtrVector subuses;
  for (int k = 0; k < uses.size (); k++)
  //for (int i = uses.size () - 1; i >= 0; i--)
    {
      Use* use = uses[k];
      if (use->is_selected ()) continue;
      use->select ();
      for (int i = 0; i < use->sub_uses.size (); i++)
	{
	  if (use->sub_uses[i]->m_index >= 0 && !use->sub_uses[i]->discarded)
	    {
	      if (use->sub_use_auto_imports[i] != Off
		  && !use->sub_uses[i]->is_selected ())
		{
		  subuses.push_back (use->sub_uses[i]);
		}
	    }
	  else
	    {
	      if (Cmt::get_debug ())
		{
		  cout << "Use::set_auto_imports_state> " << use->get_package_name ()
		       << " -> sub_use " << use->sub_uses[i]->get_package_name ()
		       << "[" << use->sub_uses[i] << ", discarded="
		       << use->sub_uses[i]->discarded << ", m_index="
		       << use->sub_uses[i]->m_index << " : invalid]" << endl;
		}
	      Use* au (find_valid (use->sub_uses[i]->get_package_name ()));
	      if (au)
		{
		  if (Cmt::get_debug ())
		    {
		      cout << "Use::set_auto_imports_state> " << use->get_package_name ()
			   << " -> sub_use " << au->get_package_name ()
			   << "[" << au << ", discarded="
			   << au->discarded << ", m_index="
			   << au->m_index << " : valid]" << endl;
		    }
		  if (use->sub_use_auto_imports[i] != Off
		      && !au->is_selected ())
		    {
		      subuses.push_back (au);
		    }
		}
	      else
		{
		  use->sub_uses[i]->select ();
		}
	    }
	}
    }

  level++;
  Use::set_auto_imports_state (subuses, auto_imports_states);
  level--;

  if (Cmt::get_debug ())
    {
      cout << "Use::set_auto_imports_state><";
      for (int i = level; i > 0; i--) cout << "-";
      for (int i = 0; i < uses.size (); i++)
      //for (int i = uses.size () - 1; i >= 0; i--)
	{
	  cout << " " << uses[i]->get_package_name ()
	       << "(" << (auto_imports_states[uses[i]->m_index] ? "+" : "-") << ")";
	}
      cout << "|" << endl;
    }

  return;
}

//----------------------------------------------------------
void Use::set_auto_imports_state (const Use::UsePtrVector& uses,
				  cmt_vector<bool>& auto_imports_states,
				  cmt_map <Use*, bool>& visited)
{
  if (0 == uses.size ()) return;
  static bool yes (true);

  static int level (-1);
  level++;
  if (level == 0)
    {
      unselect_all ();
    }

  if (Cmt::get_debug ())
    {
      cout << "Use::set_auto_imports_state>|";
      for (int i = level; i > 0; i--) cout << "-";
      for (int i = 0; i < uses.size (); i++)
      //for (int i = uses.size () - 1; i >= 0; i--)
	{
	  cout << " " << uses[i]->get_package_name ()
	       << "(" << uses[i]->auto_imports << ")";
	}
      cout << ">" << endl;
    }

  for (int i = 0; i < uses.size (); i++)
  //for (int i = uses.size () - 1; i >= 0; i--)
    {
      Use* use = uses[i];
      if (visited.has (use) &&
	  (0 != level || use->is_selected ()))
	// revisit uses specified explicitly with -import=<package> (level == 0)
	// encountered in constituent specification for the first time (selected == false)
	// to ensure <package> is imported
	{
	  continue;
	}

      visited.add (use, yes);
      if (0 == level) use->select ();

      if (!auto_imports_states[use->m_index])
	auto_imports_states[use->m_index] = true;
      //if (0 == level && use->is_selected ()) continue;

      Use::UsePtrVector subuses;
      for (int i = 0; i < use->sub_uses.size (); i++)
	{
	  if (use->sub_uses[i]->m_index >= 0 && !use->sub_uses[i]->discarded)
	    {
	      if (use->sub_use_auto_imports[i] != Off)
		{
		  subuses.push_back (use->sub_uses[i]);
		}
	      else
		{
		  visited.add (use->sub_uses[i], yes);
		}
	    }
	  else
	    {
	      if (Cmt::get_debug ())
		{
		  cout << "Use::set_auto_imports_state> " << use->get_package_name ()
		       << " -> sub_use " << use->sub_uses[i]->get_package_name ()
		       << "[" << use->sub_uses[i] << ", discarded="
		       << use->sub_uses[i]->discarded << ", m_index="
		       << use->sub_uses[i]->m_index << " : invalid]" << endl;
		}
	      Use* au (find_valid (use->sub_uses[i]->get_package_name ()));
	      if (au)
		{
		  if (Cmt::get_debug ())
		    {
		      cout << "Use::set_auto_imports_state> " << use->get_package_name ()
			   << " -> sub_use " << au->get_package_name ()
			   << "[" << au << ", discarded="
			   << au->discarded << ", m_index="
			   << au->m_index << " : valid]" << endl;
		    }
		  if (use->sub_use_auto_imports[i] != Off)
		    {
		      subuses.push_back (au);
		    }
		  else
		    {
		      visited.add (au, yes);
		    }
		}
	      else
		{
		  visited.add (use->sub_uses[i], yes);
		}
	    }
	}
      Use::set_auto_imports_state (subuses, auto_imports_states, visited);
    }

  if (Cmt::get_debug ())
    {
      cout << "Use::set_auto_imports_state><";
      for (int i = level; i > 0; i--) cout << "-";
      for (int i = 0; i < uses.size (); i++)
      //for (int i = uses.size () - 1; i >= 0; i--)
	{
	  cout << " " << uses[i]->get_package_name ()
	       << "(" << (auto_imports_states[uses[i]->m_index] ? "+" : "-") << ")";
	}
      cout << "|" << endl;
    }

  level--;
  return;
}

/**
 *   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<bool>& 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;
  auto_imports_states[use_index] = true;

  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;
  /*
  cmt_string s;
  static const cmt_string state_text[] = {"Unspecified", "Off", "On"};
  
  if (Cmt::get_debug ())
    {
      s = "Use::set_auto_imports_state>(";
      s += use->get_package_name ();
      s += ")";
      //cout << s << endl;
    }

  int 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 (Cmt::get_debug ())
	{
	  char num[32]; sprintf (num, "%#x", u);
	  s += " ";
	  s += use->sub_uses[i]->get_package_name ();
	  s += "(";
	  s += state_text[use->sub_use_auto_imports[i] + 1];
	  s += ")[p=";
	  s += num;
	  s += "]";
	}
      
      if (j >= 0)
	{
	  if (use->sub_use_auto_imports[i] != Off)
	    {
	      set_auto_imports_state (j, auto_imports_states);
	    }
  */
	  /*
	  if (u->sub_use_auto_imports[i] == Off)
	    {
	      set_auto_imports_state (j, auto_imports_states);
	    }
	  else
	    {
	      auto_imports_states[j] = true;
	    }
	    */
  /*
        }
      else
	{
	  if (Cmt::get_debug ())
	    {
	      cout << "Use::set_auto_imports_state> " << use->get_package_name ()
		   << ": sub_use " << u->get_package_name () << "[" << u
		   << "] invalid" << endl;
	    }
	}
    }
  if (Cmt::get_debug ())
    {
      cout << s << endl;
    }
}
  */
//----------------------------------------------------------
//
//  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
  //
  //cerr << "move-0> " << use->get_package_name () << "[" << use->m_index << "]" << endl;
  for (use_index++; use_index < size; use_index++)
    {
      Use* u = uses[use_index];
      u->m_index--;

      //cerr << "move-1> " << u->get_package_name () << "[" << u->m_index << "]" << endl;
      uses[use_index - 1] = uses[use_index];
    }

  //
  // use est donc replace en derniere position
  //

  use->m_index = size - 1;
  uses[size - 1] = use;
  //cerr << "move-2> " << use->get_package_name () << "[" << use->m_index << "]" << endl;
}

/**
 *   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 : <a a a P b b b C c c c>
  //                 ^       ^
  //                 ip      ic
  //
  //  1) move "P b b b" by one place to the right
  // thus :   <a a a P P b b b c c c>
  //
  //  2) move "C" to [ip]
  //
  // after  : <a a a C P b b b c c c>
  //
  
  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;
  native_version = "";

  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_project = 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;
    }
  m_project = 0;

  version   = "";
  author    = "";
  manager   = "";
  real_path = "";
  m_realpath = "";

  prefix    = "";
  style     = mgr_style;
  initial_scope = ScopePublic;
  done      = false;
  discarded = false;
  selected  = false;
  m_hidden  = 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 ();
  alternate_is_head_versions.clear ();

  m_head_version.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, const Project* project)
{
  // 
  // This methods changes real_path after an actual location
  // where this package/version has been found.
  //
  if (Cmt::get_debug ())
    {
      cout << "|Use::change_path> path: " << new_path
	   << " project: " << (project ? project->get_cmtpath () : "0")
	   << " use: " << get_info () << endl;
    }

  real_path = "";
  m_realpath = "";

  m_project = 0;

  if (new_path.size () != 0)
    //  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);
      if (!CmtSystem::realpath_ (real_path, m_realpath))
	{
	  CmtError::set (CmtError::file_access_error,
			 "Cannot compute real path `" + real_path + "': " +
			 get_info ());
	  CmtError::print ();
	  return;
	}
    }
  
  if (project)
    m_project = project;

  m_located = true;

  if (Cmt::get_debug ())
    {
      cout << "<Use::change_path| real_path: " << real_path
	   << " m_project: " << (m_project ? m_project->get_cmtpath () : "0")
	   << " use: " << get_info () << endl;
    }
}

//----------------------------------------------------------
int Use::reach_package (const cmt_string& from_path, const cmt_string& n_version)
{
  if (Cmt::get_debug ())
    {
      cout << "Use::reach_package> " << get_package_name ()
	   << "(" << version << ") from " << from_path << endl;
      cout << "Use::reach_package> native_version required "<<n_version<<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 (n_version != "")
	{
	  cmt_string path ("cmt");
	  path += CmtSystem::file_separator ();
	  path += "native_version.cmt";        
	  if (!CmtSystem::test_file (path)) return (0);

	  cmt_string nv;
	  if (!nv.read (path))
	    {
	      CmtError::set (CmtError::file_access_error,
			     CmtSystem::pwd () + CmtSystem::file_separator () + path);
	      return (0);
	    }
	  int pos = nv.find ('\n');
	  if (pos != cmt_string::npos) nv.erase (pos);
	  pos = nv.find ('\r');
	  if (pos != cmt_string::npos) nv.erase (pos);
	  if (Cmt::get_debug ())
	    {
	      cout << "Use::reach_package-6.0> native_version found " << nv << " (required " << n_version << ")" << endl;
	    }
	  if (nv != n_version) return (0);
	  this->native_version   = n_version;
	}

      cmt_string v;
      //      if (Package::get_version (v))
      if (Package::get_version (v, "cmt"))
	{
	  CompareStatus s = compare_versions (version, v, true);
	  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 OldMajorIdGreaterThanNew:
	    case NewMajorIdGreaterThanOld:
	      break;
	    case IncompatibleMajorIds:
	      if (!is_head_version (v))
		return (0);
	      break;
	    }
	  version = v;
	}
      else if (version == "")
	{
	  version = "v0";
	}
      CmtSystem::cd ("cmt");
      style = cmt_style;
      structuring_style = without_version_directory;
      return (1);
    }
  else if (!CmtSystem::cd (version) || (version == ""))
    //  else if (!CmtSystem::cd (version))
    {
      //
      // The specified version cannot be found per-se
      // There are alternate possibilities when it contains wild cards
      //
      if ((version.find ("*") != cmt_string::npos) || (version == ""))
      //      if ((version == "") || (version.find ("*") != cmt_string::npos))
      //      if (version.find ("*") != cmt_string::npos)
        {
          static CmtSystem::cmt_string_vector versions;
          static cmt_string name;

          name = ".";
          name += CmtSystem::file_separator ();
          if (version != "") name += version;
          else name += "*";
	  /*
          if (version == "") name += "*";
          else name += version;
	  */
	  //          name += version;
          CmtSystem::scan_dir (name, versions);
          if (n_version != "")
	    {
              CmtSystem::cmt_string_vector native_versions;           
              for (int i = 0; i < versions.size (); i++)
		{
                  cmt_string path;
                  if (CmtSystem::test_directory (versions[i]))
		    {
                      path  = versions[i];
                      path += CmtSystem::file_separator ();
                      path += "cmt";
		    }
                  else
		    {
                      path = "cmt";
		    }
                  path += CmtSystem::file_separator ();
                  path += "native_version.cmt";        
                                  
                  if (CmtSystem::test_file (path))
		    {
		      cmt_string nv;

		      nv.read (path);
		      int pos = nv.find ('\n');
		      if (pos != cmt_string::npos) nv.erase (pos);

		      pos = nv.find ('\r');
		      if (pos != cmt_string::npos) nv.erase (pos);

		      if (nv == n_version)
			{
			  cmt_string& name_entry = native_versions.add ();

			  // We have found at least one
			  // cout << "native_version :" << n_version << " ,version: " << versions[i] << endl;
			  this->native_version   = n_version;
			  name_entry            += versions[i];
			}
		    }                   
		}
              versions = native_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 cmt/requirements or mgr/requirements below)
                  */

                  cmt_string req;

                  req = name;
                  req += CmtSystem::file_separator ();
                  req += "cmt";
                  req += CmtSystem::file_separator ();
                  req += "requirements";

                  if (!CmtSystem::test_file (req))
                    {
                      req = name;
                      req += CmtSystem::file_separator ();
                      req += "mgr";
                      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;
                  bool& new_i = alternate_is_head_versions.add ();
                  new_i = is_head_version (name);

                  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"))
    {
      CmtSystem::cd ("cmt");
      style = cmt_style;
      structuring_style = with_version_directory;
    }
  else if (CmtSystem::test_file ("mgr/requirements"))
    {
      CmtSystem::cd ("mgr");
      style = mgr_style;
      structuring_style = with_version_directory;
    }
  else
    {
      return (0);
    }

  if (Cmt::get_debug ())
    {
      cout << "Use::reach_package-8>" << endl;
    }

  return (1);
}

class UseProjectAction : public IProjectAction
{
public:
  UseProjectAction (Use* use, cmt_string n_version="") : m_use (use), m_found (false), native_version(n_version)
  {
  }

  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 ();
    m_use->alternate_is_head_versions.clear ();

    if (m_use->reach_package (path, this->native_version))
      {
	if (Cmt::get_debug ())
	  {
	    cout << "move_to4> " << path << endl;
	  }
	
	m_use->change_path (path, &project);

	m_found = true;

	return (false);
      }
    else if (m_use->alternate_versions.size () > 0)
      {
	if (m_use->select_alternate (&project)) 
	  {
	    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;
  cmt_string native_version;
};

//----------------------------------------------------------
bool Use::move_to (const cmt_string& native_version, bool curdir)
//bool Use::move_to (const cmt_string& native_version)
{
  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, native_version);

      return (true);
    }

  cmt_string expanded_path = path;

  //
  // 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,  native_version))
        {
          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);
            }
        }
    }

  //
  // Try here.
  //
  if (curdir)
    {
//   if (expanded_path == "")
//     {
//       if (reach_package ("", native_version))

      cmt_string here = CmtSystem::pwd ();

      if (reach_package (here,  native_version))
        {
          if (Cmt::get_debug ())
            {
              cout << "move_to2> " << expanded_path << endl;
            }
          change_path (here);
          return (true);
        }
      else if (alternate_versions.size () > 0)
        {
          if (select_alternate ()) 
            {
              if (Cmt::get_debug ())
                {
                  cout << "move_to5> " << real_path << endl;
                }
              return (true);
            }
        }

      if (!CmtSystem::cd (here))
	{
	  CmtError::set (CmtError::file_access_error, here);
	}
      return (false);
//     }
    } // end of curdir      
      
  //
  // Second try is among the CMTPATHs
  //
  UseProjectAction pa (this, native_version);

  Project::broadcast (pa);

  if (pa.found ()) return (true);

  return (false);
}

//----------------------------------------------------------
bool Use::select_alternate (const Project* project)
{
  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 (i == 0)
        {
          CmtSystem::is_version_directory (name, v0, r0, p0);
          selected_index = 0;
        }
      else
        {
	  if (alternate_is_head_versions[selected_index] &&
	      alternate_is_head_versions[i])
	    {
	      if (strcmp(name.c_str (), alternate_versions[selected_index].c_str ()) > 0)
		{
		  selected_index = i;
		}
	      continue;
	    }
	  else if (alternate_is_head_versions[selected_index])
	    {
	      continue;
	    }
	  else if (alternate_is_head_versions[i])
	    {
	      selected_index = i;
	      continue;
	    }

          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 (Cmt::get_debug ())
                {
                  cout << "select_alternate> " << alternate_paths[selected_index] << endl;
                }

              change_path (alternate_paths[selected_index], project);
              return (true);
            }
        }
    }

  return (false);
}

//----------------------------------------------------------
bool Use::need_new (const cmt_string& path,
                    const cmt_string& package,
                    const cmt_string& version,
                    const cmt_string& n_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 = &current_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
	      if (n_version != use.native_version)
		{
	          if (Cmt::get_debug ())
		    {
		      cout << " ... but native_version differs (" << n_version << "!=" << use.native_version << ") !" << endl; 
		    }

	          do_need_new = true;    
		}	      
	    }
	  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_request && !Cmt::get_quiet ())
	{
	  if ((new_v != -1) && (req_v != -1) && (new_v != req_v))
	    {
              cerr << "# Required version " << version
		   << " of package " << package;

	      if (context_use != 0)
		{
		  cerr << " [from " << context_use->get_package_name () << "]";
		}

	      cerr << " incompatible with selected version " << use.version;

	      if (use.version != use.specified_version)
		{
		  cerr << " (" << use.specified_version << ")" ;
		}

	      cerr << 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
		  if (n_version != use.native_version)
		    {
		      if (Cmt::get_debug ())
			{
			  cout << " ... but native_version differs (" << n_version << "!=" << use.native_version << ") !" << endl;
			}

		      do_need_new = true;    
		    }
		  
		}
	      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_request && !Cmt::get_quiet ())
	    {
	      if ((new_v != -1) && (req_v != -1) && (new_v != req_v))
		{
		  cerr << "# Required version " << version
		       << " of package " << package;

		  if (context_use != 0)
		    {
		      cerr << " [from " << context_use->get_package_name () << "]";
		    }
	      
		  cerr << " incompatible with selected version " << use.version;

		  if (use.version != use.specified_version)
		    {
		      cerr << " (" << use.specified_version << ")" ;
		    }

		  cerr << 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,
                  const cmt_string& n_version)
{
  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) && use->native_version==n_version) 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,
               const cmt_string& native_version,
               Use* context_use,
               const 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, native_version, &old_use, context_use);

  if (Cmt::get_debug ())
    {
      if (old_use != 0 && !do_need_new)
	{
	  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, native_version);
    }
  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 (native_version);

  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)
    {
      CmtMessage::warning (CmtError::get_error_name (CmtError::package_not_found)
			   + ": " + use->get_info ()
			   + (native_version != "" ?
			      " -native_version=" + native_version : "")
			   + ( (context_use != 0) ?
			       " (requested by " + context_use->get_package_name () + ")" : "" )
			   );
      /*
      CmtMessage::warning ("package " + use->get_package_name ()
			   + " " + use->version + " " + use->path
			   + " not found"
			   + ( (context_use != 0) ?
			       " (requested by " + context_use->get_package_name () + ")" :
			       "" )
			   );
      */
      /*
      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->m_located = false;
      //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 << "] "<< use->version <<" 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->discard ();
          use = old_use;
	  if (context_use != 0)
	    {
	      context_use->sub_uses[context_use->sub_uses.size () - 1] = use;
	    }
          found = use->move_to (native_version);
        }
      else
        {
	  //
	  //  This new version is different from the old one
	  // thus we have to choose
	  //
	  bool old_use_is_head_version (use->is_head_version (old_use->version));
	  bool use_is_head_version (use->is_head_version (use->version));
	  Use* selected_use (old_use);
	  if (old_use_is_head_version && use_is_head_version)
	    {
	      if (strcmp(use->version.c_str (), old_use->version.c_str ()) > 0)
		{
		  selected_use = use;
		  if (Cmt::get_debug ())
		    {
		      cout << "add> new head version " << use->version
			   << " wins old head version " << old_use->version
			   << endl;
		    }
		}
	    }
	  else if (old_use_is_head_version)
	    {
	    }
	  else if (use_is_head_version)
	    {
	      selected_use = use;
	      if (Cmt::get_debug ())
		{
		  cout << "add> new head version " << use->version
		       << " wins old version " << old_use->version
		       << endl;
		}
	    }
	  else
	    {
	      static BestFitSelector selector;
	      selected_use = selector.operate (old_use, use);
	      if (Cmt::get_debug ())
		{
		  cout << "add> operate on old version " << old_use->version
		       << " and new version " << use->version
		       << endl;
		}
	    }

	  if (Cmt::get_debug ())
	    {
	      cout << "add> old=" << old_use << "i=" << old_use->m_index
		   << " new=" << use << "i=" << 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);
	      if (context_use != 0)
		{
		  context_use->sub_uses[context_use->sub_uses.size () - 1] = use;
		}
            }
          

          /*
           *   current directory is moved to the selected one
           */
          found = use->move_to (native_version);
        }
    }

  //
  // 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;

  if (style != none_style)
    {
      s += CmtSystem::file_separator ();
      s += get_package_name ();
    }
  
  //  if (style != no_version_style)
  if (structuring_style == with_version_directory)
    {
      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 ${<PACKAGE>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 = "";

  const Project* p (0);
  if (m_project)
    {
      p = m_project;
      cmtpath = p->get_cmtpath ();
    }
  else
    {
      cmtpath = m_realpath.size ()
	? Project::find_in_cmt_paths (m_realpath, true)
	: Project::find_in_cmt_paths (real_path)
	;
      p = Project::find_by_cmtpath (cmtpath);
  //  const Project* p = Project::find_by_cmtpath (cmtpath);
    }
  //  if (cmtpath != "")
  if (p != 0)
    {
      CmtSystem::compress_path (cmtpath);

      static const cmt_string empty_string;
      static const cmt_string fs = CmtSystem::file_separator ();
      
      // In case there are symlinks
      //      offset = real_path;
      //      offset.replace (cmtpath, empty_string);
      //cerr << "realpath_: get_cmtpath_and_offset" << endl;
      if (0 != m_realpath.size ())
	offset = m_realpath;
      else if (!CmtSystem::realpath_ (real_path, offset))
	{
	  CmtError::set (CmtError::file_access_error,
			 "Cannot compute real path `" + real_path + "': " +
			 get_info ());
	  CmtError::print ();
	  return;
	}
      offset.replace (p->get_cmtpath_real (), 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);
	}
    }
  else
    {
      offset = real_path;
    }
}

//------------------------------------------------------------
bool Use::get_strategy (const cmt_string& name) const
{
  const Project* p = get_project ();
    /*
    Project::find_by_cmtpath (m_realpath.size ()
			      ? Project::find_in_cmt_paths (m_realpath, true)
			      : Project::find_in_cmt_paths (real_path)
			      );
    */

  bool strategy;

  if (p == 0)
    {
      static const Project::ProjectPtrVector Ordered = Project::ordered_projects ();
      //static const Project::ProjectVector& projects = Project::projects ();

      if (Ordered.size () == 0) strategy = StrategyMgr::get_default_strategy (name);
      //if (projects.size () == 0) strategy = StrategyMgr::get_default_strategy (name);
      else
        {
          p = Ordered[0];
          //p = &(projects[0]);
          strategy = p->get_strategy (name);
        }
    }
  else
    {
      strategy = p->get_strategy (name);
    }

  return (strategy);
}

//----------------------------------------------------------
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];

      if (incl.name == "") continue;
      
      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 (m_located)
    //  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;
      if (style != none_style)
	{
	  buffer += fs;
	  buffer += package_name;
	}
      if (structuring_style == with_version_directory)
	{
	  buffer += fs;
	  buffer += version;
	}
      buffer += "\"";
      buffer += "\n";
    }

  if (action_setup == Cmt::get_action () &&
      Requirements == Cmt::get_print_mode ())
    {
      //cerr << "|Use::fill_standard_macros> Checking for " << prefix << "CONFIG" << endl;
      if (!discarded &&
	  get_package_name () != "cmt_standalone" &&
	  get_strategy ("SetupConfig"))
	{
	  buffer += "macro ";
	  buffer += prefix;
	  buffer += "CONFIG";
	  buffer += " \"";
	  buffer += CmtSystem::get_cmt_config ();
	  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";
  
  const Project* p = m_project
    ? m_project
    : Project::find_by_cmtpath (cmtpath)
    ;
  /*
  const Project* p (m_project);
  if (!p)
    p = Project::find_by_cmtpath (cmtpath);
  */

  buffer += "macro ";
  buffer += package_name;
  buffer += "_project";
  buffer += " \"";
  if (p != 0)
    {
      buffer += p->get_name ();
    }
  buffer += "\"";
  buffer += "\n";

  buffer += "macro ";
  buffer += package_name;
  buffer += "_project_release";
  buffer += " \"";
  if (p != 0)
    {
      buffer += p->get_release ();
    }
  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 (CmtMessage::active (Info))
	cerr << "   Creating reference file " << ref_file << endl;
	  //      if (!Cmt::get_quiet ()) cerr << "   Creating the reference file " << ref_file << endl;
      if (!text.write (ref_file))
	{
	  CmtError::set (CmtError::file_access_error, ref_file);
	  return false;
	}
    }
  else
    {
      if (current_use.style != none_style)
	{
	  s = "../$(";
	  s += current_use.get_package_name ();
	  s += "_tag)/";
	}
      else
	{
	  s = "./";
	}
      s += name;
    }

  Symbol::expand (s);

  cmt_string source;
  cmt_string dest;

  CmtSystem::dirname (libname, source);
  CmtSystem::dirname (s, dest);

  if (same_dirs (source, dest))
    {
      cmt_string lname;
      CmtSystem::basename (libname, lname);
      if (lname == name)
	return true;
    }

  //if (!Cmt::get_quiet ()) 
  if (CmtMessage::active (Info))
    cerr << "   Symlinking " << libname << " to " << s << endl;

  if (symlinkcmd == "")
    {
      if (!CmtSystem::create_symlink (libname, s))
	{
	  CmtError::set (CmtError::file_access_error, "Cannot create symbolic link to " + libname);
	  //CmtMessage::error ("Cannot create a symbolic link to " + libname);
	  //	  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)
	{
	  CmtError::set (CmtError::execution_error, "Cannot create symbolic link to " + libname);
	  //CmtMessage::error ("Cannot create a symbolic link to " + libname);
	  //	  cerr << "#CMT> Cannot create a symbolic link to " << libname << endl;
	  return (false);
	}
    }

  return (true);
}

//----------------------------------------------------------
static bool uninstall_library (const cmt_string& source_library_name, 
			       const cmt_string& dest_library_name, 
			       const cmt_string& cmtinstallarea, 
			       const cmt_string& tag, 
			       const cmt_string& symunlinkcmd)
{
  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 removing the reference file

      cmt_string r = s;
      r += ".cmtref";

      if (CmtMessage::active (Info))
	cerr << "   Removing reference file " << r << endl;
      if (!CmtSystem::remove_file (r))
	{
	  CmtError::set (CmtError::file_access_error, r);
	  return false;
	}
      /*
      if (symunlinkcmd == "")
	{
	  //if (!CmtSystem::remove_file (r) && CmtSystem::test_file(r))
	  if (!CmtSystem::remove_file (r))
	    {
	      CmtError::set (CmtError::file_access_error, r);
	      return false;
	    }
	}
      else
	{
	  cmt_string cmd (symunlinkcmd);
	  cmd += " ";
	  cmd += r;
	  int status = CmtSystem::execute (cmd);
	  if (status != 0)
	    {
	      //                  if (status != 2) CmtError::set (CmtError::execution_error, s);
	      CmtError::set (CmtError::execution_error, cmd);
	    }
	}
      */
    }
  else
    {
      if (current_use.style != none_style)
	{
	  s = "../$(";
	  s += current_use.get_package_name ();
	  s += "_tag)/";
	}
      else
	{
	  s = "./";
	}
      s += name;
    }

  Symbol::expand (s);

  cmt_string source;
  cmt_string dest;

  CmtSystem::dirname (libname, source);
  CmtSystem::dirname (s, dest);

  if (same_dirs (source, dest))
    {
      cmt_string lname;
      CmtSystem::basename (libname, lname);
      if (lname == name)
	return true;
    }

  //if (!Cmt::get_quiet ()) 
  if (CmtMessage::active (Info))
    cerr << "   Removing symlink " << s << " to " << libname << endl;

  if (symunlinkcmd == "")
    {
      //if (!CmtSystem::remove_file (s) && CmtSystem::test_file(s))
      if (!CmtSystem::remove_file (s))
	{
	  CmtError::set (CmtError::file_access_error, "Cannot remove symbolic link to " + libname);
	  return (false);
	}
    }
  else
    {
      cmt_string cmd = symunlinkcmd;
      cmd += " ";
      cmd += s;
      int status = CmtSystem::execute (cmd);
      if (status != 0)
	{
	  CmtError::set (CmtError::execution_error, "Cannot remove symbolic link to " + libname);
	  //CmtMessage::error ("Cannot create a symbolic link to " + libname);
	  //	  cerr << "#CMT> Cannot create a symbolic link to " << libname << endl;
	  return (false);
	}
    }
  
  return (true);
}

//----------------------------------------------------------
/**
 *  This function construct absolute library path
 *  for libraries specified via <package>_libraries macros
 *  to be used by build[remove]_library_links functions,
 *  and class Generator build_library_links_infile function, in particular.
 */
void Use::absolute_library_path (const cmt_string& libname,
				 const cmt_string& shlibsuffix, 
				 CmtSystem::cmt_string_vector& paths) const
{
  if (CmtSystem::absolute_path (libname))
    {
      paths.push_back (libname);
      return;
    }

  /**
   *   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.
   */
  cmt_string libpath;
  if (style != none_style)
    {
      libpath = "${";
      libpath += prefix;
      libpath += "ROOT}/${";
      libpath += get_package_name ();
      libpath += "_tag}/";
    }
  else
    {
      libpath = "${";
      libpath += prefix;
      libpath += "ROOT}/";
    }
  libpath += "$(library_prefix)";
  libpath += libname;
  libpath += "$(library_suffix)";
  libpath += ".";
  libpath += shlibsuffix;
  paths.push_back (libpath);

#ifdef __APPLE__
  if (style != none_style)
    {
      libpath = "${";
      libpath += prefix;
      libpath += "ROOT}/${";
      libpath += get_package_name ();
      libpath += "_tag}/";
    }
  else
    {
      libpath = "${";
      libpath += prefix;
      libpath += "ROOT}/";
    }
  libpath += libname;
  libpath += ".bundle";
  paths.push_back (libpath);
#endif
}

//----------------------------------------------------------
/**
 *   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 ())
    {
      CmtMessage::warning ("package " + get_package_name ()
			   + " " + version + " " + path
			   + " not found");
      /*
      if (!Cmt::get_quiet ())
	{
	  cerr << "# 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);
      if (0 == libname.size ()) continue;

      CmtSystem::cmt_string_vector paths;
      absolute_library_path (libname,
			     shlibsuffix, 
			     paths);

      for (int k = 0; k < paths.size (); k++)
	{
	  CmtSystem::basename (paths[k], name);
	  if (!install_library (paths[k], name, cmtinstallarea, tag, symlinkcmd))
	    {
	      CmtError::print ();
	    }
	}
    }
}
//----------------------------------------------------------
/**
 *   Centralize the removal of library links for this Use.
 */
void Use::remove_library_links (const cmt_string& cmtinstallarea, 
				const cmt_string& tag, 
				const cmt_string& shlibsuffix, 
				const cmt_string& symunlinkcmd) const
{
  if (!located ())
    {
      CmtMessage::warning ("package " + get_package_name ()
			   + " " + version + " " + path
			   + " not found");
      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);
      if (0 == libname.size ()) continue;

      CmtSystem::cmt_string_vector paths;
      absolute_library_path (libname,
			     shlibsuffix, 
			     paths);
      
      for (int k = 0; k < paths.size (); k++)
	{
	  CmtSystem::basename (paths[k], name);
	  if (!uninstall_library (paths[k], name, cmtinstallarea, tag, symunlinkcmd))
	    {
	      CmtError::print ();
	    }
	}
    }
}

/**
 *   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 ()
{
  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.

      if (Cmt::get_debug ())
	{
	  cout << "set_selected_version> Replace "
	       << get_package_name () << "(" << m_index << ")[" << this << "] with "
	       << selected_use->get_package_name () << "(" << selected_use->m_index << ")[" << selected_use << "]" << endl;
	}

      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 context_state, State specified_state,
			    cmt_map <Use*, bool>& visited)
{
  static int level (0);
  /*
  if (level == 0)
    {
      unselect_all ();
      selected = true;
    }
  */
  switch (context_state)
    {
    case Unspecified:
    case On:
      if (!visited.has (this) ||
	  // revisit uses that may be turned into Off != auto_imports
	  // via some other use(s)
	  // policy being use has Off != auto_imports,
	  // if it is (direct) sub-use without -no_auto_imports of
	  // either current use or sub-use with Off != auto_imports
	  (Off == auto_imports && Off != specified_state)
	  )
	{
	  auto_imports = specified_state;
	  context_state = UseContext::mask_auto_imports (context_state, auto_imports);
	}
      else
	{
	  return;
	}
      break;
    case Off:
      if (visited.has (this))
	{
	  return;
	}
      auto_imports = context_state;
      break;
    }

  if (Cmt::get_debug ())
    {
      cout << "Use::set_auto_imports>|";
      for (int i = level; i > 0; i--) cout << "-";
      cout << get_package_name () << "> " 
           << auto_imports << " -> " 
	   << "(" << context_state << ")" << specified_state << endl;
    }

  static bool yes (true);
  visited.add (this, yes);

  cmt_string s;
  static const cmt_string state_text[] = {"Unspecified", "Off", "On"};
  
  if (Cmt::get_debug ())
    {
      s = "Use::set_auto_imports><";
      for (int i = level; i > 0; i--) s += "-";
      s += get_package_name ();
      s += "|";
      //cout << s << endl;
    }
  
  level++;
  for (int i = 0; i < sub_uses.size (); i++)
  //for (int i = sub_uses.size () - 1; i >= 0; i--)
    {
      State state = sub_use_auto_imports[i];
      if (Cmt::get_debug ())
	{
	  s += " ";
	  s += sub_uses[i]->get_package_name ();
	  s += "(";
	  s += state_text[state + 1];
	  s += ")";
	}
      if (sub_uses[i]->m_index >= 0 && !sub_uses[i]->discarded)
	{
	  sub_uses[i]->set_auto_imports (context_state, state, visited);
	}
      else
	{
	  if (Cmt::get_debug ())
	    {
	      char num[32]; sprintf (num, "%p", sub_uses[i]);
	      char index[32]; sprintf (index, "%d", sub_uses[i]->m_index);
	      s += "[";
	      s += num;
	      s += ", discarded=";
	      s += (sub_uses[i]->discarded ? "1" : "0");
	      s += ", m_index=";
	      s += index;
	      s += " : invalid]";
	    }
	  Use* au (find_valid (sub_uses[i]->get_package_name ()));
	  if (au)
	    {
	      if (Cmt::get_debug ())
		{
		  char num[32]; sprintf (num, "%p", au);
		  char index[32]; sprintf (index, "%d", au->m_index);
		  s += "[";
		  s += num;
		  s += ", discarded=";
		  s += (au->discarded ? "1" : "0");
		  s += ", m_index=";
		  s += index;
		  s += " : valid]";
		}
	      au->set_auto_imports (context_state, state, visited);
	    }
	  else
	    {
	      visited.add (sub_uses[i], yes);
	    }
	}
    }
  level--;

  if (Cmt::get_debug ())
    {
      cout << s << endl;
    }

  return;
}
/*
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 + 1];
              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 = "";

  return m_package ? m_package->get_name () : 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)
    {
      //      CmtMessage::warning ("No access to " + to_name);
      return (false);
    }

  cmt_map <cmt_string, Use*> all_clients;
  cmt_map <cmt_string, Use*> 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 <cmt_string, Use*>& all_clients, 
			   cmt_map <cmt_string, Use*>& 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->m_hidden) 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);
}

//----------------------------------------------------------
void Use::show_sub_uses (cmt_map <Use*, bool>& visited,
			 const cmt_string& request, State specified_state,
			 bool skip_discarded, ostream& out)
//void Use::show_sub_uses (const cmt_string& request, bool skip_discarded, ostream& out)
{
  if (skip_discarded && discarded) return;
  if (m_hidden) return;

  Use* current = &(Use::current ());
  static State context_state (auto_imports);
  static int level (0);

  if (level == 0)
    {
      unselect_all ();
      selected = false;
    }

  if (level > 0)
    {
      out << "# ";
      for (int n = 0; n < (level-1); n++) out << "  ";

      if (request == "")
	{
	  out << "use " << get_package_name () << " " << specified_version;

	  if (this == current) 
	    {
	      out << " (current)";
	    }
	  else
	    {
	      if (specified_path != "") out << " " << specified_path;
	    }
	}
      else
	{
	  out << "use " << request;
	}

      if (version_alias != "")
        {
          out << " | " << version_alias << " " << path_alias;
        }

      if (initial_scope == ScopeUnspecified) out << " (unspecified)";
      else if (initial_scope != ScopePublic) out << " (private)";

      if (specified_state == Off) out << " (no_auto_imports)";
      //      if (auto_imports == Off) out << " (no_auto_imports)";

      if (structuring_style == without_version_directory) out << " (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 ();
              out << " (native_version=" << value << ")";
            }
        }

      out << endl;
    }

  //  if (selected) return;
  //  selected = true;

  State saved_context_state (context_state);

  switch (context_state)
    {
    case Unspecified:
    case On:
      if (!visited.has (this) ||
	  !selected)
	// selected == true means that
	// this use has been shown with its actual auto_imports
	// either Off != auto_imports or Off == auto_imports,
	// mark selected not to consider use again and thus avoid looping this way
	{
	  switch (specified_state)
	    {
	    case Unspecified:
	    case On:
	      if (Off != auto_imports)
		{
		  // this path to use is informative
		  // want to revisit sub-uses
		  // to possibly find Off != auto_imports paths to them
		  selected = true;
		}
	      break;
	    case Off:
	      if (Off == auto_imports)
		{
		  // this path to use is informative
		  // no point in revisiting sub-uses
		  selected = true;
		  if (visited.has (this)) return;
		}
	      else
		{
		  // this path to use is not informative
		  // no point in (re)visiting sub-uses
		  return;
		}
	      break;
	    }
	  context_state = UseContext::mask_auto_imports (context_state, specified_state);
	}
      else
	{
	  return;
	}
      break;
    case Off:
      if (!visited.has (this) ||
	  !selected)
	{
	  if (Off == auto_imports)
	    {
	      // this path to use is informative
	      // no point in revisiting sub-uses
	      selected = true;
	      if (visited.has (this)) return;
	    }
	  else
	    {
	      // this path to use is not informative
	      // no point in (re)visiting sub-uses
	      return;
	    }
	}
      else
	{
	  return;
	}
      break;
    }

  static bool yes (true);
  visited.add (this, yes);

  level++;
  for (int i = 0; i < sub_uses.size (); i++)
    {
      //if (use == 0) continue;
      Use* use;
      if (sub_uses[i]->m_index >= 0 && !sub_uses[i]->discarded)
	{
	  use = sub_uses[i];
	}
      else
	{
	  Use* au (find_valid (sub_uses[i]->get_package_name ()));
	  if (au)
	    {
	      use = au;
	    }
	  else
	    {
	      sub_uses[i]->select ();
	      visited.add (sub_uses[i], yes);
	      continue;
	    }
	}

      const cmt_string& request = requests[i];

      ScopeType saved_scope = use->initial_scope;
      //      State saved_state = use->auto_imports;

      use->initial_scope = sub_use_scopes[i];
      //      use->auto_imports = sub_use_auto_imports[i];

      use->show_sub_uses (visited, request, sub_use_auto_imports[i], skip_discarded, out);
      //use->show_sub_uses (request, skip_discarded, out);

      use->initial_scope = saved_scope;
      //      use->auto_imports = saved_state;
    }
  level--;

  context_state = saved_context_state;
}

//----------------------------------------------------------
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 ();
      */

      if (new_v > ref_v)
	{
	  if (verbose && !Cmt::get_quiet ())
	    {
	      cerr << "# Select " << new_vc << " version " << new_version 
		   << " of package " << ref_use->get_package_name () 
		   << " instead of existing " << ref_vc << " " << 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_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);
}


//----------------------------------------------------------
class VersionReader : public Awk
{
public:

  VersionReader ()
  {
  }
  
  const cmt_string& get_version () const
  {
    return (m_version);
  }
  
  void filter (const cmt_string& line)
  {
    if (0 == line.size () ||
	line[0] == '#') return;
    CmtSystem::cmt_string_vector words;
    CmtSystem::split (line, " \t", words);
    if (words[0] == "version")
      {
	m_version = words[1];
      }
  }
  
private:
  cmt_string m_version;
};

//----------------------------------------------------------
class PackageReader : public Awk
{
public:

  PackageReader ()
  {
  }
  
  const cmt_string& get_package () const
  {
    return (m_package);
  }
  
  void filter (const cmt_string& line)
  {
    if (0 == line.size () ||
	line[0] == '#') return;
    CmtSystem::cmt_string_vector words;
    CmtSystem::split (line, " \t", words);
    if (words[0] == "package")
      {
	m_package = words[1];
      }
  }
  
private:
  cmt_string m_package;
};

//----------------------------------------------------------
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 ();
}

//----------------------------------------------------------
bool Package::get_version (cmt_string& version, const cmt_string& path)
{
  cmt_string version_file = path;
  version_file += CmtSystem::file_separator ();
  version_file += get_version_file_name ();
  if (CmtSystem::test_file (version_file))
    {
      cmt_string v;
      if (v.read (version_file))
	{
	  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);
	  if (v != "")
	    {
	      version = v;
	      return true;
	    }
	}
      else
	{
	  CmtMessage::warning ("Could not read `" + version_file + "'.");
	}
    }

  version_file = path;
  version_file += CmtSystem::file_separator ();
  version_file += "requirements";
  cmt_string text;
  if (text.read (version_file))
    {
      VersionReader reader;
      reader.run (text);
      cmt_string v = reader.get_version ();
      if (v != "")
	{
	  version = v;
	  return true;
	}
    }
  else
    {
      CmtMessage::warning ("Could not read `" + version_file + "'.");
    }

  return false;
}

//----------------------------------------------------------
const cmt_string& Package::get_version_file_name ()
{
  static const cmt_string name = "version.cmt";

  return (name);
}

//----------------------------------------------------------
bool Package::get_name (cmt_string& name, const cmt_string& path)
{
  cmt_string name_file = path;
  name_file += CmtSystem::file_separator ();
  name_file += "requirements";
  cmt_string text;
  if (text.read (name_file))
    {
      PackageReader reader;
      reader.run (text);
      cmt_string v = reader.get_package ();
      if (v != "")
	{
	  name = v;
	  return true;
	}
    }
  else
    {
      CmtMessage::warning ("Could not read `" + name_file + "'.");
    }

  return false;
}

//----------------------------------------------------------
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;
}

//----------------------------------------------------------
const Project* Use::get_project () const
{    
  if (m_project)
    return m_project;

  return Project::find_by_cmtpath (m_realpath.size ()
				   ? Project::find_in_cmt_paths (m_realpath, true)
				   : Project::find_in_cmt_paths (real_path)
				   );
  /*
  cmt_string cmtpath = m_realpath.size ()
    ? Project::find_in_cmt_paths (m_realpath, true)
    : Project::find_in_cmt_paths (real_path)
    ;
  return Project::find_by_cmtpath (cmtpath);
  */
  /*
  Project* p;
  cmt_string cmtpath = "";
  cmt_string offset  = "";    
  get_cmtpath_and_offset (cmtpath, offset);
  p = Project::find_by_cmtpath (cmtpath);
  return p;   
  */
}

//----------------------------------------------------------
cmt_string Use::get_info () const
{    
  return get_package_name () + " " + (version != "" ? version : "*") +
    (path != "" ? " " + path : "") ;
  //  return get_package_name () + " " + version + (path != "" ? " " + path : "") ;
}

//----------------------------------------------------------
/**
 *    Check whether @version@
 *    is head version as specified by CMTHEADVERSION symbol/environment variable
 *    or equals HEAD|head
 */
//----------------------------------------------------------
bool Use::is_head_version (const cmt_string& version)
{
  if (!m_head_version.is_valid ())
    {
      cmt_string s (Symbol::get_env_value ("CMTHEADVERSION"));
      // strip the leading '!'
      // See mgr/cmt_svn_checkout.py:CmtContext::set_head_version
      if (0 != s.size () && '!' == s[0]) s = s.substr(1);
      static const cmt_string package_template = "<package>";
      s.replace_all (package_template, get_package_name ());
      static const cmt_string PACKAGE_template = "<PACKAGE>";
      s.replace_all (PACKAGE_template, prefix);
      static const cmt_string revision_template = "<revision>";
      s.replace_all (revision_template.c_str (), "[0-9]*");
      if (0 != s.size ())
	{
	  if ('^' != s[0]) s = "^" + s;
	  if ('$' != s[s.size () - 1]) s = s + "$";
	}
      else
	{
	  s = "^(HEAD|head)$";
	}
      m_head_version.set (s);
      if (!m_head_version.is_valid ())
	{
	  CmtMessage::warning
	    (CmtError::get_error_name (CmtError::configuration_error)
	     + ": CMTHEADVERSION regular expression invalid `" + s + "'");
	}
    }

  return m_head_version.match (version);
}
