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

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

#include "cmt_parser.h"
#include "cmt_version.h"

#include "cmt_database.h"
#include "cmt_include.h"
#include "cmt_script.h"
#include "cmt_generator.h"
#include "cmt_system.h"
#include "cmt.h"
#include "cmt_error.h"
#include "cmt_cvs.h"
#include "cmt_lock.h"
#include "cmt_triggers.h"
#include "cmt_model.h"
#include "cmt_awk.h"

//----------------------------------------------------------
//
//  Static object definitions for the Cmt class.
//

ActionType Cmt::m_action;
bool Cmt::m_build_nmake;
cmt_string Cmt::m_cmt_config;
CmtSystem::cmt_string_vector Cmt::m_cmt_path;
CmtSystem::cmt_string_vector Cmt::m_cmt_path_pwds;
CmtSystem::cmt_string_vector Cmt::m_cmt_path_sources;
cmt_string Cmt::m_cmt_root;
cmt_string Cmt::m_cmt_home;
cmt_string Cmt::m_cmt_user_context;
cmt_string Cmt::m_cmt_site;
cmt_string Cmt::m_cmt_version;
int Cmt::m_current_build_strategy = DefaultBuildStrategy;

cmt_string Cmt::m_current_dir;
cmt_string Cmt::m_current_package;
cmt_string Cmt::m_current_config;
cmt_string Cmt::m_current_path;
cmt_string Cmt::m_current_prefix;

AccessMode Cmt::m_current_access = UserMode;
VersionStrategy Cmt::m_current_strategy = BestFit;
CmtDirStyle Cmt::m_current_style = cmt_style;

cmt_string Cmt::m_current_tag;
cmt_string Cmt::m_current_target;
cmt_string Cmt::m_current_version;

cmt_string Cmt::m_extra_tags;

cmt_string Cmt::m_configure_error;

bool Cmt::m_debug;

cmt_string Cmt::m_default_path;
cmt_string Cmt::m_filtered_text;
bool Cmt::m_quiet;
bool Cmt::m_recursive;
ScopeType Cmt::m_scope;
bool Cmt::m_simulation;
bool Cmt::m_standard_macros_done;
//----------------------------------------------------------


//----------------------------------------------------------
//
//   Utility classes
//
//----------------------------------------------------------



/**
 *  This scans a path and looks for CMT packages.
 *  Whenever it finds one, it applies the specified actor to it.
 */
class FileScanner
{
public:
  class actor
  {
  public:
    virtual void run (const cmt_string& package,
                      const cmt_string& version,
                      const cmt_string& path)
    {
    }
  };

  FileScanner ();
  bool scan_path (const cmt_string& path, actor& a);
  bool scan_package (const cmt_string& path, const cmt_string& package);

private:
  void scan_path (const cmt_string& path, int level, actor& a);

  bool _running;
  int _level;
};


/**
 *  This FileScanner actor simply displays the package name/version/path
 */
class PackageViewer : public FileScanner::actor
{
public:
  void run (const cmt_string& package,
            const cmt_string& version,
            const cmt_string& path);
};


/**
 *  This FileScanner actor accumulates all found packages into a cmt_string_vector
 */
class PackageSelector : public FileScanner::actor
{
public:
  PackageSelector (CmtSystem::cmt_string_vector& uses);
  void run (const cmt_string& package,
            const cmt_string& version,
            const cmt_string& path);
private:
  CmtSystem::cmt_string_vector& m_uses;
};



/**
 *  This FileScanner actor collects all packages clients of the specified one
 */
class PackageCollector : public FileScanner::actor
{
public:
  PackageCollector (const cmt_string& package,
                    const cmt_string& version);
  void run (const cmt_string& package,
            const cmt_string& version,
            const cmt_string& path);
  int count ();

private:
  const cmt_string& m_package;
  const cmt_string& m_version;
  int m_count;
};


//----------------------------------------------------------
FileScanner::FileScanner ()
{
  _running = false;
  _level = 0;
}

//----------------------------------------------------------
bool FileScanner::scan_path (const cmt_string& path, actor& a)
{
  if (_running) return (false);

  _level = 0;
  _running = true;
  scan_path (path, 0, a);
  _running = false;
  _level = 0;

  return (true);
}

//----------------------------------------------------------
void FileScanner::scan_path (const cmt_string& path, int level, actor& a)
{
  //
  // Only do something if it is a directory.
  //

  if (!CmtSystem::test_directory (path)) return;

  CmtSystem::cmt_string_vector list;

  CmtSystem::scan_dir (path, list);

  if (list.size () == 0) return;

  _level++;

  // Will be set if at least one directory is a version directory
  bool has_package = false;

  cmt_string pack;
  CmtSystem::basename (path, pack);

  int i;
  for (i = 0; i < list.size (); i++)
    {
      const cmt_string& name = list[i];

      //cout << "scan> level=" << level << " name=" << name;

      cmt_string version;
      CmtSystem::basename (name, version);

      //
      //  All entries at this level may be "legal" version directories.
      //
      //  So we go down but no more then one level deep.
      //  The next level we request that the entry is a version
      //  and that there is a mgr/requirements file below.
      //

      if (level == 0)
        {
          //cout << " -> down" << endl;
          scan_path (name, level + 1, a);
        }
      else if (CmtSystem::is_version_directory (version))
        {
          cmt_string req;

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

          if (CmtSystem::test_file (req))
            {
              //cout << " -> cmt" << endl;

              a.run (pack, version, path);

              has_package = true;
            }
          else
            {
              //cout << " -> no cmt" << endl;
              req = name;
              req += CmtSystem::file_separator ();
              req += "mgr";
              req += CmtSystem::file_separator ();
              req += "requirements";

              if (CmtSystem::test_file (req))
                {
                  //cout << " -> cmt" << endl;

                  a.run (pack, version, path);

                  has_package = true;
                }
              else
                {
                  //cout << " -> no mgr" << endl;
                }
            }
        }
      else
        {
          //cout << " -> stop" << endl;
        }
    }

  if (has_package)
    {
      //
      // At least one version was found here.
      //
      scan_path (path, 0, a);
    }

  _level--;
}


//----------------------------------------------------------
bool FileScanner::scan_package (const cmt_string& path,
                                const cmt_string& package)
{
  //
  // Only do something if it is a directory.
  //

  if (!CmtSystem::test_directory (path)) return (false);

  cmt_string pattern = path;
  pattern += CmtSystem::file_separator ();
  pattern += package;

  if (!CmtSystem::test_directory (pattern)) return (false);

  CmtSystem::cmt_string_vector list;

  CmtSystem::scan_dir (pattern, list);

  if (list.size () == 0) return (false);

  bool result = false;

  int i;
  for (i = 0; i < list.size (); i++)
    {
      const cmt_string& name = list[i];

      cmt_string version;
      CmtSystem::basename (name, version);

      if (CmtSystem::is_version_directory (version))
        {
          cmt_string req;

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

          if (CmtSystem::test_file (req))
            {
              //cout << " -> cmt" << endl;

              cout << package << " " << version << " " << path << endl;

              result = true;
            }
          else
            {
              //cout << " -> no cmt" << endl;

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

              if (CmtSystem::test_file (req))
                {
                  //cout << " -> mgr" << endl;

                  cout << package << " " << version << " " << path << endl;

                  result = true;
                }
              else
                {
                  //cout << " -> no mgr" << endl;
                }
            }
        }
      else
        {
          //cout << " -> stop" << endl;
        }
    }

  return (result);
}

//----------------------------------------------------------
void PackageViewer::run (const cmt_string& package,
                         const cmt_string& version,
                         const cmt_string& path)
{
  cout << package << " " << version << " " << path << endl;
}

//----------------------------------------------------------
PackageSelector::PackageSelector (CmtSystem::cmt_string_vector& uses) : m_uses(uses)
{
}

//----------------------------------------------------------
void PackageSelector::run (const cmt_string& package,
                           const cmt_string& version,
                           const cmt_string& path)
{
  cmt_string temp;

  temp = path;
  //temp += "/";
  //temp += package;
  temp += "/";
  temp += version;
  temp += "/cmt/requirements";

  if (!CmtSystem::test_file (temp))
    {
      temp.replace ("/cmt/", "/mgr/");
      if (!CmtSystem::test_file (temp))
        {
          return;
        }
    }
        
  temp.replace ("/requirements", "");
  cmt_string& use = m_uses.add ();
  use = temp;
}

//----------------------------------------------------------
PackageCollector::PackageCollector (const cmt_string& package,
                                    const cmt_string& version) :
  m_package (package), m_version (version), m_count (0)
{
}

//----------------------------------------------------------
void PackageCollector::run (const cmt_string& package,
                            const cmt_string& version,
                            const cmt_string& path)
{
  cmt_string dir = path;
  dir += CmtSystem::file_separator ();
  dir += version;
  dir += CmtSystem::file_separator ();

  cmt_string req;

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

  cmt_string requirements;
  cmt_string line;
  CmtSystem::cmt_string_vector words;

  if (CmtSystem::test_file (req))
    {
      requirements.read (req);
    }
  else
    {
      req = dir;
      req += "mgr";
      req += CmtSystem::file_separator ();
      req += "requirements";
      if (CmtSystem::test_file (req))
        {
          requirements.read (req);
        }
    }

  if (requirements != "")
    {
      int pos = 0;
      int max_pos = requirements.size ();

      while (pos < max_pos)
        {
          int cr = requirements.find (pos, "\r\n");
          int nl = requirements.find (pos, '\n');
          int first = nl;
          int length = 1;
                
          if (cr != cmt_string::npos)
            {
              if (nl == cmt_string::npos)
                {
                  first = cr;
                  length = 2;
                }
              else
                {
                  first = (nl < cr) ? nl : cr;
                  length = (nl < cr) ? 1 : 2;
                }
            }
                
          if (first == cmt_string::npos)
            {
              requirements.substr (pos, line);
              pos = max_pos;
            }
          else if (first > pos)
            {
              requirements.substr (pos, first - pos, line);
              pos = first + length;
            }
          else
            {
              line.erase (0);
              pos += length;
            }

          CmtSystem::split (line, " \t", words);

          if ((words.size () > 2) && (words[0] == "use")) 
            {
              if ((words[1] == m_package) && 
                  ((words[2] == m_version) || (m_version == "")))
                {
                  cout << "# " << package << " " << version << " " << path;
                  if (m_version == "")
                    {
                      cout << " (use version " << words[2] << ")";
                    }
                  cout << endl;
                  m_count++;
                }
            }
        }
    }
}

//----------------------------------------------------------
int PackageCollector::count ()
{
  return (m_count);
}




//----------------------------------------------------------
//
//   The Cmt methods
//
//----------------------------------------------------------



/**
 *   Append "CONFIG" to the prefix
 */
void Cmt::build_config (const cmt_string& prefix,
                        cmt_string& config)
{
  /*
    Building the config from <prefix> 
  */

  config = prefix;
  config += "CONFIG";
}

//----------------------------------------------------------
void Cmt::build_makefile (const cmt_string& target)
{
  Constituent* constituent = 0;

  if (target.size () > 0)
    {
      /*
        Do genmake for one specific target.
      */
      constituent = Constituent::find (target);
      if (constituent != 0)
        {
          constituent->build_makefile (m_simulation);
        }
    }
  else
    {
      /*
        Do genmake for all possible targets.
      */
      Constituent::build_all_makefiles (m_simulation);
    }
}

//----------------------------------------------------------
void Cmt::build_msdev_file (const cmt_string& target)
{
  Constituent* constituent = 0;

  set_standard_macros ();

  if (target != "")
    {
      /*
        Do genmsdev for one specific target.
      */
      constituent = Constituent::find (target);
      if (constituent != 0)
        {
          constituent->build_msdev_file (m_simulation);
        }
    }
  else
    {
      /*
        Do genmsdev for all possible targets.
      */
      Constituent::build_all_msdev_files (m_simulation);
    }
}

//----------------------------------------------------------
bool Cmt::build_nmake ()
{
  return (m_build_nmake);
}

//----------------------------------------------------------
void Cmt::build_OS9_makefile (const cmt_string& target)
{
  build_makefile (target);
}

/**
 *   Convert a package name to its upper case copy
 */
void Cmt::build_prefix (const cmt_string& package, cmt_string& prefix)
{
  int pos;
  char c;

  /*
    Building the prefix from <package> 
  */

  prefix = package;

  for (pos = 0; pos < package.size (); pos++)
    {
      c = package[pos];
      prefix[pos] = toupper (c);
    }
}

//----------------------------------------------------------
void Cmt::clear ()
{
  m_action         = action_none;
  m_build_nmake    = false;
  m_cmt_config     = "";
  m_cmt_path.clear ();
  m_cmt_path_pwds.clear ();
  m_cmt_path_sources.clear ();
  m_cmt_root       = "";
  m_cmt_version    = "";
  m_current_build_strategy = DefaultBuildStrategy;
  m_current_dir     = "";
  m_current_package = "";
  m_current_config  = "";
  m_current_path    = "";
  m_current_prefix  = "";
  m_current_access   = DeveloperMode;
  m_current_strategy = BestFit;

  m_current_tag      = "";
  m_current_target   = "";
  m_current_version  = "";
  m_default_path     = "";
  m_quiet            = false;
  m_recursive        = false;

  m_scope            = ScopePublic;
  m_simulation       = false;

  m_filtered_text    = "";
  m_standard_macros_done = false;

  Database::clear ();
  Include::clear_all ();
  Script::clear_all ();
  CmtError::clear ();
}

//----------------------------------------------------------
void Cmt::configure ()
{
  static bool configured = false;

  if (configured) return;

  m_cmt_version   = "";
  m_current_dir     = "";
  m_current_package = "";
  m_current_prefix  = "";
  m_current_config  = "";
  m_current_path    = "";

  m_current_tag     = "";
  m_current_version = "";

  m_configure_error = "";

  m_debug = false;
  if (getenv ("CMTDEBUG") != 0) m_debug = true;

  m_default_path    = "";

  configure_default_path ();
  configure_uname_tag ();
  configure_hosttype_tag ();
  configure_config_tag ();
  configure_site_tag (0);
  configure_cmt_path (0);
  configure_current_dir ();
  configure_current_package ();
  configure_home (0);
  configure_user_context (0);

  Use& use = Use::current();

  use.set (m_current_package,
           m_current_version,
           m_current_path,
           "",
           "");

  use.style = m_current_style;

  use.change_path (m_current_path);

  if (CmtError::has_pending_error ()) 
    {
      m_configure_error = CmtError::get_last_error ();
    }
}

//----------------------------------------------------------
void Cmt::configure_cmt_path (Use* use)
{
  cmt_string s;

  Symbol* symbol = Symbol::find ("CMTPATH");
  if (symbol != 0)
    {
      bool show_set_hidden = false;

      if (Cmt::m_action == action_show_set)
        {
          show_set_hidden = true;
          Cmt::m_action = action_none;
        }

      s = symbol->build_macro_value ();
      Symbol::expand (s);

      if (show_set_hidden)
        {
          show_set_hidden = false;
          Cmt::m_action = action_show_set;
        }
    }

  CmtSystem::get_cmt_paths (m_cmt_path, 
                            m_cmt_path_pwds, 
                            m_cmt_path_sources, s);
}

//----------------------------------------------------------
void Cmt::configure_config_tag ()
{
  m_cmt_config = CmtSystem::get_cmt_config ();
  if (m_cmt_config != "")
    {
      Tag* tag;

      tag = Tag::add (m_cmt_config, PriorityConfig, "CMTCONFIG", 0);
      tag->mark ();
    }
}

//----------------------------------------------------------
void Cmt::configure_current_dir ()
{
  cmt_string file_name;

  /*
    Building current_dir :

    o we first get the physical value (using getwd)
    o then this value is possibly filtered using the
    cmt_mount_filter file.
  */

  m_current_dir.erase (0);

  file_name = m_default_path;
  if (file_name != "")
    {
      file_name += CmtSystem::file_separator ();
      file_name += "CMT";
      file_name += CmtSystem::file_separator ();
      file_name += m_cmt_version;
      file_name += CmtSystem::file_separator ();
      file_name += "mgr";
      file_name += CmtSystem::file_separator ();
    }

  file_name += "cmt_mount_filter";

  m_current_dir = CmtSystem::pwd ();

  {
    cmt_string text;
    cmt_string line;
    CmtSystem::cmt_string_vector words;

    text.read (file_name);

    int pos = 0;
    int max_pos = text.size ();

    for (pos = 0; pos < max_pos; )
      {
        int cr = text.find (pos, "\r\n");
        int nl = text.find (pos, '\n');
        int first = nl;
        int length = 1;

        if (cr != cmt_string::npos)
          {
            if (nl == cmt_string::npos)
              {
                first = cr;
                length = 2;
              }
            else
              {
                first = (nl < cr) ? nl : cr;
                length = (nl < cr) ? 1 : 2;
              }
          }
        
        if (first == cmt_string::npos)
          {
            text.substr (pos, line);
            pos = max_pos;
          }
        else if (first > pos)
          {
            text.substr (pos, first - pos, line);
            pos = first + length;
          }
        else
          {
            line.erase (0);
            pos += length;
          }

        CmtSystem::split (line, " \t", words);

        if (words.size () >= 2)
          {
            cmt_string& path_name = words[0];
            cmt_string& replacement = words[1];

            if (m_current_dir.find (path_name) != cmt_string::npos)
              {
                m_current_dir.replace (path_name, replacement);
                break;
              }
          }
      }
  }
}

//----------------------------------------------------------
void Cmt::configure_current_package ()
{
  /*
    Build current_package and current_prefix.

    This is only possible if we are within the cmt/mgr branch of a
    standard directory tree (i.e. <package>/<version>/cmt or mgr)
  */

  if (CmtSystem::test_file ("../cmt/requirements"))
    {
      m_current_style = cmt_style;
    }
  else if (CmtSystem::test_file ("../mgr/requirements"))
    {
      m_current_style = mgr_style;
    }
  else
    {
      m_current_style = none_style;
    }

  if (m_current_style != none_style)
    {
      CmtSystem::dirname (m_current_dir, m_current_path);
      CmtSystem::basename (m_current_path, m_current_version);
      CmtSystem::dirname (m_current_path, m_current_path);
      CmtSystem::basename (m_current_path, m_current_package);
      CmtSystem::dirname (m_current_path, m_current_path);
      build_prefix (m_current_package, m_current_prefix);
      build_config (m_current_prefix, m_current_config);
    }
  else
    {
      m_current_package = "cmt_standalone";
      m_current_version = "";
      m_current_path = m_current_dir;
      build_prefix (m_current_package, m_current_prefix);
      build_config (m_current_prefix, m_current_config);
    }

  //cout << "configure_current_package> current style=" << m_current_style << endl;
}

//----------------------------------------------------------
void Cmt::configure_default_path ()
{
  m_default_path = CmtSystem::get_cmt_root ();
  CmtSystem::get_cmt_version (m_cmt_version);
  m_cmt_root = m_default_path;
  m_cmt_root += CmtSystem::file_separator ();
  m_cmt_root += "CMT";
  m_cmt_root += CmtSystem::file_separator ();
  m_cmt_root += m_cmt_version;
}

//----------------------------------------------------------
void Cmt::configure_home (Use* use)
{
  m_cmt_home = "";

  Symbol* symbol = Symbol::find ("CMTHOME");
  if (symbol != 0)
    {
      m_cmt_home = symbol->build_macro_value ();
    }
  else if (CmtSystem::testenv ("CMTHOME"))
    {
      m_cmt_home = CmtSystem::getenv ("CMTHOME");
    }

  if ((m_cmt_home != "") && !CmtSystem::test_directory (m_cmt_home))
    {
      m_cmt_home = "";
    }
}

//----------------------------------------------------------
void Cmt::configure_user_context (Use* use)
{
  m_cmt_user_context = "";

  Symbol* symbol = Symbol::find ("CMTUSERCONTEXT");
  if (symbol != 0)
    {
      m_cmt_user_context = symbol->build_macro_value ();
    }
  else if (CmtSystem::testenv ("CMTUSERCONTEXT"))
    {
      m_cmt_user_context = CmtSystem::getenv ("CMTUSERCONTEXT");
    }

  if ((m_cmt_user_context != "") && !CmtSystem::test_directory (m_cmt_user_context))
    {
      m_cmt_user_context = "";
    }
}

//----------------------------------------------------------
void Cmt::configure_hosttype_tag ()
{
  cmt_string hosttype;

  CmtSystem::get_hosttype (hosttype);

  if (hosttype != "")
    {
      Tag* tag;

      tag = Tag::add (hosttype, PriorityUname, "HOSTTYPE", 0);
      tag->mark ();
    }
}

//----------------------------------------------------------
void Cmt::configure_site_tag (Use* use)
{
  Symbol* symbol = Symbol::find ("CMTSITE");
  if (symbol != 0)
    {
      m_cmt_site = symbol->build_macro_value ();
    }
  else
    {
      m_cmt_site = CmtSystem::get_cmt_site ();
    }

  if (m_cmt_site != "")
    {
      cmt_string s = "CMTSITE";

      if (use != 0)
        {
          s += " in ";
        }

      Tag* tag;

      tag = Tag::add (m_cmt_site, PrioritySite, s, use);
      tag->mark ();
    }
}

//----------------------------------------------------------
void Cmt::restore_all_tags (Use* use)
{
    //cerr << "restore_all_tags" << endl;

  Cmt::configure_tags (use);

    /*
      Then get existing extra tags
     */

  if (CmtSystem::testenv ("CMTEXTRATAGS"))
    {
      cmt_string s = "CMTEXTRATAGS";

      if (use != 0)
        {
          s += " in ";
        }

      Tag* tag;
      CmtSystem::cmt_string_vector words;
      
      cmt_string tags = CmtSystem::getenv ("CMTEXTRATAGS");
      
      CmtSystem::split (tags, " \t,", words);

      Cmt::m_extra_tags = "";
      
      for (int i = 0; i < words.size (); i++)
        {
          const cmt_string& a = words[i];

          Cmt::m_extra_tags += a;
          Cmt::m_extra_tags += ",";
          
          tag = Tag::add (a, PriorityUserTag, s, use);
          
          tag->mark ();
        }
    }
}

//----------------------------------------------------------
void Cmt::configure_tags (Use* use)
{
  cmt_string config_tag;
  
  if (m_debug) cerr << "configure_tags0> current_tag=" << m_current_tag << endl;

  Symbol* symbol = Symbol::find ("CMTCONFIG");
  if (symbol != 0)
    {
      bool show_set_hidden = false;

      if (Cmt::m_action == action_show_set)
        {
          show_set_hidden = true;
          Cmt::m_action = action_none;
        }

      config_tag = symbol->build_macro_value ();

      if (show_set_hidden)
        {
          show_set_hidden = false;
          Cmt::m_action = action_show_set;
        }
    }
  else if (CmtSystem::testenv ("CMTCONFIG"))
    {
      config_tag = CmtSystem::getenv ("CMTCONFIG");
    }
  else if (CmtSystem::testenv ("CMTBIN"))
    {
      config_tag = CmtSystem::getenv ("CMTBIN");
    }

  if (config_tag == "")
    {
      CmtSystem::get_uname (config_tag);
    }

  if (m_debug) cerr << "configure_tags> current_tag=" << m_current_tag << endl;

  cmt_string s = "CMTCONFIG";

  if (use != 0)
    {
      s += " in ";
    }

  Tag* tag;

  tag = Tag::add (config_tag, PriorityConfig, s, use);
  tag->mark ();

    //m_current_tag = config_tag;
}

//----------------------------------------------------------
void Cmt::configure_uname_tag ()
{
  cmt_string uname;

  CmtSystem::get_uname (uname);

  if (uname != "")
    {
      Tag* tag;

      tag = Tag::add (uname, PriorityUname, "uname", 0);
      tag->mark ();
    }
}

//----------------------------------------------------------
//
//   Actions
//
//----------------------------------------------------------

class AwkActor : public Awk
{
public:

  void filter (const cmt_string& line)
      {
        cout << line << endl;
      }
};

//----------------------------------------------------------
void Cmt::do_awk (const CmtSystem::cmt_string_vector& arguments)
{
  if (arguments.size () < 1)
    {
      cout << "> cmt broadcast <file> <pattern>" << endl;
      return;
    }

  const cmt_string& file = arguments[0];
  const cmt_string& pattern = arguments[1];
  cmt_string text;

  text.read (file);

  static AwkActor a;

  cmt_regexp exp (pattern);

  a.run (text, exp);
}

//----------------------------------------------------------
void Cmt::do_broadcast (const CmtSystem::cmt_string_vector& arguments,
                        int argc,
                        char* argv[])
{
  Use::UsePtrVector& Uses = Use::uses ();

  CmtSystem::cmt_string_vector uses;
  CmtSystem::cmt_string_vector path_selections;
  CmtSystem::cmt_string_vector selections;
  CmtSystem::cmt_string_vector exclusions;
  cmt_string begin;
  cmt_string command;
  bool is_cmt = false;
  int first = 0;
  int i;
  bool ignore_errors = false;
  bool all_packages = false;

  bool local = true;

  for (i = 0; i < arguments.size (); i++)
    {
      const cmt_string& w = arguments[i];

      if (command == "")
        {
          if (w.substr (0, 13) == "-all_packages")
            {
              local = false;
              all_packages = true;
            }
          else if (w.substr (0, 7) == "-depth=")
            {
              local = false;

              cmt_string depth_str;
              int depth_value = 0;
                          
              w.substr (7, depth_str);
              if ((sscanf (depth_str.c_str (), "%d", &depth_value) < 1) ||
                  (depth_value < 1))
                {
                  // Syntax error
                  //  We shall restrict to packages found within 
                  // the <depth_value> first elements of CMTPATH.
                  //  If CMTPATH is empty, nothing is selected.
                  // depth=1 is equivalent to local
                }

              int i = 0;
              while (i < m_cmt_path.size ())
                {
                  cmt_string& p = m_cmt_path[i];
                  cmt_string& pwd = m_cmt_path_pwds[i];
                  cmt_string& src = m_cmt_path_sources[i];

                  if (src == "current package")
                    {
                      cmt_string& s1 = path_selections.add ();
                      s1 = p;
                      cmt_string& s2 = path_selections.add ();
                      s2 = pwd;
                    }
                  else if (src != "default path")
                    {
                      if (depth_value > 0)
                        {
                          cmt_string& s1 = path_selections.add ();
                          s1 = p;
                          cmt_string& s2 = path_selections.add ();
                          s2 = pwd;
                          depth_value--;
                        }
                    }
                  i++;
                }
            }
          else if (w.substr (0, 9) == "-exclude=")
            {
              cmt_string exclusion;

              w.substr (9, exclusion);

              int size = exclusion.size ();
              
              if (size >= 2)
                {
                  if (((exclusion[0] == '"') && (exclusion[size - 1] == '"')) ||
                      ((exclusion[0] == '\'') && (exclusion[size - 1] == '\'')))
                    {
                      exclusion.erase (size - 1);
                      exclusion.erase (0, 1);
                    }

                  CmtSystem::split (exclusion, " \t", exclusions);
                }
            }
          else if (w.substr (0, 7) == "-global")
            {
              path_selections.clear ();
              local = false;
            }
          else if (w.substr (0, 6) == "-local")
            {
              local = true;
            }
          else if (w.substr (0, 8) == "-select=")
            {
              cmt_string selection;

              w.substr (8, selection);

              int size = selection.size ();
              
              if (size >= 2)
                {
                  if (((selection[0] == '"') && (selection[size - 1] == '"')) ||
                      ((selection[0] == '\'') && (selection[size - 1] == '\'')))
                    {
                      selection.erase (size - 1);
                      selection.erase (0, 1);
                    }

                  CmtSystem::split (selection, " \t", selections);
                }
            }
          else if (w.substr (0, 7) == "-begin=")
            {
              w.substr (7, begin);
            }
          else
            {
              command = w;
            }
        }
      else
        {
          command += " ";
          command += w;
        }

    }

  if (local)
    {
      int depth_value = 1;

      int i = 0;
      while (i < m_cmt_path.size ())
        {
          cmt_string& p = m_cmt_path[i];
          cmt_string& pwd = m_cmt_path_pwds[i];
          cmt_string& src = m_cmt_path_sources[i];

          if (src == "current package")
            {
              cmt_string& s1 = path_selections.add ();
              s1 = p;
              cmt_string& s2 = path_selections.add ();
              s2 = pwd;
            }
          else if (src != "default path")
            {
              if (depth_value > 0)
                {
                  cmt_string& s1 = path_selections.add ();
                  s1 = p;
                  cmt_string& s2 = path_selections.add ();
                  s2 = pwd;
                  depth_value--;
                }
            }
          i++;
        }
    }

  if (command[0] == '-')
    {
      ignore_errors = true;
      command.erase (0, 1);
    }

  //if (command.substr (0, 3) == "cmt") is_cmt = true;

  if (all_packages)
    {
      PackageSelector selector (uses);
      FileScanner scanner;
          
      for (i = 0; i < m_cmt_path.size (); i++)
        {
          cmt_string& p = m_cmt_path[i];
          scanner.scan_path (p, selector);
        }
    }
  else
    {
      for (i = Uses.size () - 1; i >= 0; i--)
        {
          Use* use = Uses[i];
                  
          if (use->discarded) continue;

          if (!use->located ())
            {
              if (!Cmt::m_quiet)
                {
                  cout << "# package " << use->package <<
                      " " << use->version << " " << use->path <<
                      " not found" <<
                      endl;
                }
            }
          else
            {
              if (use->package != "CMT")
                {
                  cmt_string& s = uses.add ();
                                  
                  if (use->real_path == "") s = CmtSystem::pwd ();
                  else s = use->real_path;
                  s += CmtSystem::file_separator ();
                  s += use->package;
                  s += CmtSystem::file_separator ();
                  s += use->version;
                  s += CmtSystem::file_separator ();
                                  
                  if (use->style == mgr_style) s += "mgr";
                  else s += "cmt";

                  //cout << ">>> adding " << s << " to selection" << endl;
                }
            }
        }
          
      {
        cmt_string& s = uses.add ();
                  
        Use* use = &(Use::current ());

        if (use->package.find ("cmt_standalone") != cmt_string::npos)
          {
            s = CmtSystem::pwd ();
          }
        else
          {
            if (use->real_path == "") s = CmtSystem::pwd ();
            else s = use->real_path;
            s += CmtSystem::file_separator ();
            s += use->package;
            s += CmtSystem::file_separator ();
            s += use->version;
            s += CmtSystem::file_separator ();
                  
            if (use->style == mgr_style) s += "mgr";
            else s += "cmt";
          }

        //cout << ">>> adding current " << s << " to selection" << endl;
      }
    }

  bool started = false;

  if (begin == "") started = true;

  for (i = 0; i < uses.size (); i++)
    {
      const cmt_string& s = uses[i];
      bool ok = true;
      bool selected = true;
      bool excluded = false;

      if (path_selections.size () > 0)
        {
          selected = false;

          for (int j = 0; j < path_selections.size (); j++)
            {
              const cmt_string& sel = path_selections[j];
              
              if (s.find (sel) != cmt_string::npos) 
                {
                  selected = true;
                  break;
                }
            }

          ok = selected;
        }

      if (ok)
        {
          if (selections.size () > 0)
            {
              selected = false;
              
              for (int j = 0; j < selections.size (); j++)
                {
                  const cmt_string& sel = selections[j];
                  
                  if (s.find (sel) != cmt_string::npos) 
                    {
                      selected = true;
                      break;
                    }
                }
              
              ok = selected;
            }
        }

      if (ok && !started)
        {
          if (s.find (begin) != cmt_string::npos)
            {
              started = true;
              ok = true;
            }
          else
            {
              ok = false;
            }
        }


      if (ok)
        {
          excluded = false;

          for (int j = 0; j < exclusions.size (); j++)
            {
              const cmt_string& exc = exclusions[j];
              
              if (s.find (exc) != cmt_string::npos) 
                {
                  excluded = true;
                  break;
                }
            }

          if (excluded) ok = false;
        }

      if (!ok) 
        {
          continue;
        }



      if (!CmtSystem::cd (s))
        {
          if (s.find ("cmt_standalone") != cmt_string::npos)
            {
              cout << "# Currently not in a CMT package" << endl;
            }
          else
            {
              cout << "# Cannot move to the package in " << s << " (" << i+1 << "/" 
                   << uses.size () << ")"<< endl;
            }

          if (!ignore_errors) break;

          continue;
        }

      if (CmtLock::check () == CmtLock::locked_by_another_user)
        {
          cout << "# Ignore locked package in " << s << " (" << i+1 << "/" 
               << uses.size () << ")" << endl;
          continue;
        }

      cout << "#--------------------------------------------------------------" << endl;
      cout << "# Now trying [" << command << "] in " << s << " (" << i+1 << "/" << uses.size () 
           << ")" << endl;
      cout << "#--------------------------------------------------------------" << endl;

      if (is_cmt)
        {
          //
          //  There is a bug in the recursive use of the parser. Macros are not set correctly.
          //  Thus the recursive optimization is now discarded.
          //
          if (parser (command) != 0)
            {
              CmtError::set (CmtError::execution_error, command);
              break;
            }
        }
      else
        {
          int status = CmtSystem::execute (command);

          //cerr << "do_broadcast> status=" << status << " ignore_errors=" << ignore_errors << endl;

          if (((status != 0) && !ignore_errors) || (status == 2))
              //if ((status != 0) && !ignore_errors)
            {
              if (status != 2) CmtError::set (CmtError::execution_error, command);
              break;
            }
        }
    }
}

//----------------------------------------------------------
void Cmt::do_build_constituent_makefile (const CmtSystem::cmt_string_vector& arguments,
                                         int argc,
                                         char* argv[])
{
  if (CmtLock::check () == CmtLock::locked_by_another_user)
    {
      CmtError::set (CmtError::conflicting_lock, "build_constituent_makefile>");
      return;
    }
  if (arguments.size () > 0) 
    {
      set_standard_macros ();
      Generator::build_constituent_makefile (arguments[0]);
    }
}

//----------------------------------------------------------
void Cmt::do_build_constituents_makefile (const CmtSystem::cmt_string_vector& arguments,
                                          int argc,
                                          char* argv[])
{
  if (CmtLock::check () == CmtLock::locked_by_another_user)
    {
      CmtError::set (CmtError::conflicting_lock, "build_constituents_makefile>");
      return;
    }
  set_standard_macros ();
  Generator::build_constituents_makefile (m_current_package);
}

//----------------------------------------------------------
void Cmt::do_build_dependencies (const CmtSystem::cmt_string_vector& arguments,
                                 int argc,
                                 char* argv[])
{
  if (CmtLock::check () == CmtLock::locked_by_another_user)
    {
      CmtError::set (CmtError::conflicting_lock, "build_dependencies>");
      return;
    }
  if (arguments.size () > 0)
    {
      set_standard_macros ();

      while (argc > 0)
        {
          if (strcmp (argv[0], "dependencies") != 0)
            {
              argc--;
              argv++;
            }
          else
            {
              argc--;
              argv++;
              argc--;
              argv++;

              Generator::build_dependencies (arguments[0], argc, argv);

              break;
            }
        }
    }
}

//----------------------------------------------------------
void Cmt::do_build_library_links ()
{
  if (CmtLock::check () == CmtLock::locked_by_another_user)
    {
      CmtError::set (CmtError::conflicting_lock, "build_library_links>");
      return;
    }

  set_standard_macros ();

  Use::UsePtrVector& Uses = Use::uses ();
  Use& current_use = Use::current ();
  int i;
  cmt_string shlibsuffix;
  cmt_string bin;

  {
    Symbol* macro = Symbol::find ("shlibsuffix");
    if (macro == 0) return;
    shlibsuffix = macro->build_macro_value ();
  }

  for (i = 0; i < Uses.size (); i++)
    {
      Use* use = Uses[i];

      if (use->discarded) continue;

      if (!use->located ())
        {
          if (!m_quiet)
            {
              cout << "# package " << use->package <<
                  " " << use->version << " " << use->path << 
                  " not found" <<
                  endl;
            }
        }
      else
        {
          if (use->package == "CMT") continue;
          if (use->package == current_use.package) continue;

          cmt_string s;

          s = use->package;
          s += "_libraries";

          Symbol* libraries_macro = Symbol::find (s);

          if (libraries_macro == 0) continue;

          cmt_string libraries = libraries_macro->build_macro_value ();
          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 (CmtSystem::absolute_path (libname))
                {
                  /**
                   *   We assume here that "library" contains a complete path.
                   *   (including the complete syntax libxxx.so)
                   */

                  cmt_string suffix;
                  CmtSystem::basename (library, name);
                }
              else
                {
                  /**
                   *   Here we expect that only the base name of the library
                   *   is given : ie it should not contain the "lib" prefix, 
                   *   nor the suffix .so, nor any path prefix.
                   *    This of course should generally correspond to a constituent name.
                   */
                  libname = "${";
                  libname += use->prefix;
                  libname += "ROOT}/${";
                  libname += use->package;
                  libname += "_tag}/lib";
                  libname += library;
                  libname += ".";
                  libname += shlibsuffix;

                  name = "lib";
                  name += library;
                  name += ".";
                  name += shlibsuffix;
                }

              Symbol::expand (libname);

              s = "../$(";
              s += current_use.package;
              s += "_tag)/";
              s += name;

              Symbol::expand (s);

              if (!m_quiet) cout << "   Symlinking " << libname << " to " << s << endl;

              if (!CmtSystem::create_symlink (libname, s))
                {
                  cout << "Cannot create a symbolic link to " << libname << endl;

                  break;
                }
            }
        }
    }
}

//----------------------------------------------------------
void Cmt::do_build_make_setup ()
{
  if (CmtLock::check () == CmtLock::locked_by_another_user)
    {
      CmtError::set (CmtError::conflicting_lock, "build_make_setup>");
      return;
    }
  set_standard_macros ();
  Generator::build_make_setup (m_current_package);
}

//----------------------------------------------------------
void Cmt::do_build_msdev (const CmtSystem::cmt_string_vector& arguments)
{
  if (CmtLock::check () == CmtLock::locked_by_another_user)
    {
      CmtError::set (CmtError::conflicting_lock, "build_msdev>");
      return;
    }

  if (true)
    {
      set_standard_macros ();
      if (arguments.size () > 0) build_msdev_file (arguments[0]);
      else build_msdev_file ("");
    }
}

//----------------------------------------------------------
void Cmt::do_build_os9_makefile (const CmtSystem::cmt_string_vector& arguments)
{
  if (CmtLock::check () == CmtLock::locked_by_another_user)
    {
      CmtError::set (CmtError::conflicting_lock, "build_os9_makefile>");
      return;
    }

  if (arguments.size () > 0) 
    {
      set_standard_macros ();
      build_OS9_makefile (arguments[0]);
    }
}

//----------------------------------------------------------
void Cmt::do_build_prototype (const CmtSystem::cmt_string_vector& arguments)
{
  if (CmtLock::check () == CmtLock::locked_by_another_user)
    {
      CmtError::set (CmtError::conflicting_lock, "build_prototype>");
      return;
    }

  if (arguments.size () > 0) 
    {
      set_standard_macros ();
      Generator::build_prototype (arguments[0]);
    }
}

//----------------------------------------------------------
void Cmt::do_build_readme (const CmtSystem::cmt_string_vector& arguments)
{
  if (CmtLock::check () == CmtLock::locked_by_another_user)
    {
      CmtError::set (CmtError::conflicting_lock, "build_readme>");
      return;
    }

  set_standard_macros ();
  Generator::build_readme (arguments);
}

//----------------------------------------------------------
void Cmt::do_build_tag_makefile ()
{
  if (CmtLock::check () == CmtLock::locked_by_another_user)
    {
      CmtError::set (CmtError::conflicting_lock, "build_tag_makefile>");
      return;
    }

  print_macros (Make);
}

//----------------------------------------------------------
void Cmt::do_build_temporary_name ()
{
  cmt_string name = CmtSystem::get_temporary_name ();
  cout << name << endl;
}

//----------------------------------------------------------
void Cmt::do_build_triggers (const CmtSystem::cmt_string_vector& arguments)
{
  if (CmtLock::check () == CmtLock::locked_by_another_user)
    {
      CmtError::set (CmtError::conflicting_lock, "build_tag_makefile>");
      return;
    }

  if (arguments.size () > 0) 
    {
      set_standard_macros ();
      TriggerGenerator::run (arguments[0]);
    }
}

//----------------------------------------------------------
void Cmt::do_build_windefs (const CmtSystem::cmt_string_vector& arguments)
{
  if (CmtLock::check () == CmtLock::locked_by_another_user)
    {
      CmtError::set (CmtError::conflicting_lock, "build_windefs>");
      return;
    }

  if (arguments.size () > 0) 
    {
      set_standard_macros ();
      Generator::build_windefs (arguments[0]);
    }
}

//----------------------------------------------------------
void Cmt::do_check_configuration ()
{
}

//----------------------------------------------------------
void Cmt::do_check_files (const CmtSystem::cmt_string_vector& arguments)
{
  if (arguments.size () >= 2) 
    {
      cmt_string first_file = arguments[0];
      cmt_string second_file = arguments[1];
          
      if (first_file == "") return;
      if (second_file == "") return;
          
      CmtSystem::compare_and_update_files (first_file, second_file);
    }
}

//----------------------------------------------------------
void Cmt::do_check_version (const CmtSystem::cmt_string_vector& arguments)
{
  if (arguments.size () > 0)
    {
      cmt_string name = arguments[0];
          
      if (name == "") return;
      int v = 0;
      int r = 0;
      int p = 0;
          
      bool ok = CmtSystem::is_version_directory (name, v, r, p);
          
      if (ok)
        {
          cout << "# " << name << " is version " << v << " release " << r << " patch " << p << endl;
        }
      else
        {
          cout << "# " << name << " is not a version tag" << endl;
        }
    }
}

//----------------------------------------------------------
void Cmt::do_checkout (const CmtSystem::cmt_string_vector& arguments)
{
  Cvs::checkout (arguments);
}

//----------------------------------------------------------
void Cmt::do_cleanup (PrintMode& mode)
{
  print_clean (mode);
}

//----------------------------------------------------------
void Cmt::do_config ()
{
  if (CmtLock::check () == CmtLock::locked_by_another_user)
    {
      CmtError::set (CmtError::conflicting_lock, "config>");
      return;
    }

    //Use::UsePtrVector& Uses = Use::uses ();

  /*
    cout << "pwd " << CmtSystem::pwd () << endl;
    cout << "current_dir " << m_current_dir << endl;
    cout << "default_path " << m_default_path << endl;
    cout << "cmt config " <<
    m_current_package << " " <<
    m_current_version << " " <<
    m_current_path << endl;
  */

  if (m_current_package == "CMT") return;
  if (m_current_package == "methods") return;

  cmt_string branch;

  CmtSystem::basename (m_current_dir, branch);

  if ((branch != "mgr") && (branch != "cmt"))
    {
      if (CmtSystem::test_file ("requirements"))
        {
          cout << "------------------------------------------" << endl;
          cout << "Configuring environment for standalone package." << endl;
          cout << "CMT version " << m_cmt_version << "." << endl;
          cout << "System is " << m_cmt_config << endl;
          cout << "------------------------------------------" << endl;

          install_test_setup_scripts ();
          install_test_cleanup_scripts ();

          Generator::build_default_makefile ();
        }
      else
        {
          cout << "==============================================" << endl;
          cout << "cmt config must be operated either upon "
            "an existing package" << endl;
          cout << " (ie. when a requirements file already exists)" << endl;
          cout << "   > cd ..." << endl;
          cout << "   > cmt config" << endl;
          cout << "or to create a new package" << endl;
          cout << "   > cmt config <package> <version> [<path>]" << endl;
          cout << "==============================================" << endl;
        }

      return;
    }

  if (branch == "cmt") m_current_style = cmt_style;
  else if (branch == "mgr") m_current_style = mgr_style;
  else m_current_style = none_style;

  Generator::build_default_makefile ();

  CmtSystem::cmt_string_vector makes;
  cmt_regexp expression ("[.]n?make(sav)?$");

  CmtSystem::scan_dir (".", expression, makes);

  if (makes.size () > 0)
    {
      cout << "Removing all previous make fragments from " << branch << endl;

      for (int i = 0; i < makes.size (); i++)
        {
          const cmt_string& s = makes[i];
          CmtSystem::remove_file (s);
        }
    }

  CmtSystem::cd ("..");

  CmtSystem::scan_dir (m_cmt_config, expression, makes); 
    
  if (makes.size () > 0) 
    {
      cout << "Removing all previous make fragments from "
           << m_cmt_config << endl; 

      for (int i = 0; i < makes.size (); i++) 
        { 
          const cmt_string& s = makes[i]; 
          CmtSystem::remove_file (s); 
        }    
    } 
    
  CmtSystem::cd (branch); 
    

  /*
    if (!load (m_current_path, m_current_package, m_current_version))
    {
    cout << "Cannot read the requirements file" << endl;
    return;
    }
  */

  CmtSystem::dirname (m_current_dir, m_current_path);
  CmtSystem::basename (m_current_path, m_current_version);
  CmtSystem::dirname (m_current_path, m_current_path);
  CmtSystem::basename (m_current_path, m_current_package);
  CmtSystem::dirname (m_current_path, m_current_path);

  Use& use = Use::current ();

  use.set (m_current_package,
           m_current_version,
           m_current_path,
           "",
           "");

  use.change_path (m_current_path);
  use.style     = m_current_style;

  //cout << "do_config> current style=" << m_current_style << endl;

  if (!reach_current_package ())
    {
      cout << "Cannot read the requirements file" << endl;
      return;
    }

  install_setup_scripts ();
  install_cleanup_scripts ();

  CmtSystem::cd ("..");

  Branch::BranchVector& branches = Branch::branches ();

  int i;

  for (i = 0; i < branches.size (); i++)
    {
      const Branch& branch = branches[i];
      const cmt_string& branch_name = branch.name ();

      if (!CmtSystem::test_directory (branch_name))
        {
          if (!CmtSystem::mkdir (branch_name))
            {
              cout << "Cannot create the " << branch_name <<" branch" << endl;
            }
          else
            {
              cout << "Installing the " << branch_name << " directory" << endl;
            }
        }
      else
        {
          cout << branch_name << " directory already installed" << endl;
        }
    }
}

//----------------------------------------------------------
void Cmt::do_create (const CmtSystem::cmt_string_vector& arguments)
{
  if (arguments.size () < 2) return;

  const cmt_string& package = arguments[0];
  const cmt_string& version = arguments[1];
  cmt_string offset;
  if (arguments.size () >= 3) offset = arguments[2];

  if (m_debug)
    {
      cout << "do_create>m_current_package=" << m_current_package << endl;
      cout << "do_create>package=" << package << endl;
    }

    //if (m_current_package == "CMT") return;
    //if (m_current_package == "methods") return;

  cmt_string the_path;

  the_path = CmtSystem::pwd ();

  if (offset != "")
    {
      if (!CmtSystem::absolute_path (offset))
        {
          // offset is really a relative offset
          the_path += CmtSystem::file_separator ();
          the_path += offset;
        }
      else // absolute path
        {
          the_path = offset;
        }
    }

  CmtSystem::compress_path (the_path);

  // Now 'the_path' contains the complete path where the package will be created

  cout << "------------------------------------------" << endl;
  cout << "Configuring environment for package " << package <<
    " version " << version << "." << endl;
  cout << "CMT version " << m_cmt_version << "." << endl;
  cout << "Root set to " << the_path << "." << endl;
  cout << "System is " << m_cmt_config << endl;
  cout << "------------------------------------------" << endl;

  if (!CmtSystem::test_directory (the_path))
    {
      if (!CmtSystem::mkdir (the_path))
        {
          cout << "Cannot create the path directory" << endl;
          return;
        }
      else
        {
          cout << "Installing the path directory" << endl;
        }
    }

  CmtSystem::cd (the_path);

  if (!CmtSystem::test_directory (package))
    {
      if (!CmtSystem::mkdir (package))
        {
          cout << "Cannot create the package directory" << endl;
          return;
        }
      else
        {
          cout << "Installing the package directory" << endl;
        }
    }
  else
    {
      cout << "Package directory already installed" << endl;
    }

  CmtSystem::cd (package);

  if (!CmtSystem::test_directory (version))
    {
      if (!CmtSystem::mkdir (version))
        {
          cout << "Cannot create the version directory" << endl;
          return;
        }
      else
        {
          cout << "Installing the version directory" << endl;
        }
    }
  else
    {
      cout << "Version directory already installed" << endl;
    }

  CmtSystem::cd (version);

  if (!CmtSystem::test_directory ("cmt"))
    {
      if (!CmtSystem::test_directory ("mgr"))
        {
          if (!CmtSystem::mkdir ("cmt"))
            {
              cout << "Cannot create the cmt directory" << endl;
              return;
            }
          else
            {
              m_current_style = cmt_style;
              cout << "Installing the cmt directory" << endl;
            }
        }
      else
        {
          m_current_style = mgr_style;
          cout << "Mgr directory already installed" << endl;
        }
    }
  else
    {
      m_current_style = cmt_style;
      cout << "Cmt directory already installed" << endl;
    }

  if (!CmtSystem::test_directory ("src"))
    {
      if (!CmtSystem::mkdir ("src"))
        {
          cout << "Cannot create the src directory" << endl;
          return;
        }
      else
        {
          cout << "Installing the src directory" << endl;
        }
    }
  else
    {
      cout << "src directory already installed" << endl;
    }

  switch (m_current_style)
    {
    case cmt_style:
      CmtSystem::cd ("cmt");
      break;
    case mgr_style:
      CmtSystem::cd ("mgr");
      break;
    }

  Generator::build_default_makefile ();

  if (!CmtSystem::test_file ("requirements"))
    {
      // create an empty requirement file.
      ofstream f ("requirements");
      if (f)
        {
          f << "package " << package << endl;
          f << endl;
          f.close ();
        }
    }

  m_current_package = package;
  m_current_version = version;
  m_current_path    = the_path;
  m_current_dir     = CmtSystem::pwd ();

  do_config ();
}

//----------------------------------------------------------
void Cmt::do_cvsbranches (const CmtSystem::cmt_string_vector& arguments)
{
  Cvs::branches (arguments[0]);
}

//----------------------------------------------------------
void Cmt::do_cvssubpackages (const CmtSystem::cmt_string_vector& arguments)
{
  Cvs::subpackages (arguments[0]);
}

//----------------------------------------------------------
void Cmt::do_cvstags (const CmtSystem::cmt_string_vector& arguments)
{
  Cvs::tags (arguments);
}

//----------------------------------------------------------
void Cmt::do_expand_model (const CmtSystem::cmt_string_vector& arguments)
{
  set_standard_macros ();
  CmtModel::expand (arguments[0]);
}

/**
 *  Handle free filtering of text files containing $(xxx) or ${xxx} patterns
 *
 *  Substitution is performed against CMT macros and environment variables.
 *
 *  Arguments:
 *
 *    cmt filter input-file-name output-file-name
 *
 */
void Cmt::do_filter (const CmtSystem::cmt_string_vector& arguments)
{
  if (arguments.size () < 2) return;

  cmt_string& input = arguments[0];
  cmt_string& output = arguments[1];

  if (!CmtSystem::test_file (input))
    {
      cout << "#CMT> File " << input << " not found" << endl;
      return;
    }

  cmt_string text;

  text.read (input);

  set_standard_macros ();

  Symbol::expand (text);

  FILE* file = fopen (output, "wb");
  if (file == NULL)
    {
      cout << "#CMT> Cannot write filtered file " << output << endl;
    }
  else
    {
      text.write (file);
      fclose (file);
    }
}

//----------------------------------------------------------
void Cmt::do_help ()
{
  cout << "> cmt command [option...]" << endl;
  cout << " command :" << endl;
  cout << "   broadcast [-select=list] [-exclude=list] [-local] [-global] [-begin=pattern] [-depth=n] <command> : apply a command to [some of] the used packages" << endl;
  cout << "" << endl;
  cout << "   build <key>             : build various components :" << endl;
  cout << "         constituent_makefile <constituent>  : generate constituent Makefile fragment" << endl;
  cout << "         constituents_makefile : generate constituents.make" << endl;
  cout << "         dependencies      : generate dependencies" << endl;
  cout << "         library_links     : build symbolic links towards all imported libraries" << endl;
  cout << "         make_setup        : build a compiled version of setup scripts" << endl;
  cout << "         msdev             : generate MSDEV files" << endl;
  cout << "         os9_makefile      : generate Makefile for OS9" << endl;
  cout << "         prototype         : generate prototype file" << endl;
  cout << "         readme            : generate README.html" << endl;
  cout << "         tag_makefile      : generate tag specific Makefile" << endl;
  cout << "         triggers <constituent> : generate library trigger file" << endl;
  cout << "         windefs <library_name> : generate def file for Windows shared libraries" << endl;
  cout << "" << endl;
  cout << "   check <key>             : perform various checks" << endl;
  cout << "         configuration     : check configuration" << endl;
  cout << "         files <old> <new> : compare two files and overrides <old> by <new> if different" << endl;
  cout << "         version <name>    : check if a name follows a version tag syntax " << endl;
  cout << "   check_files <old> <new> : compare two files and overrides <old> by <new> if different" << endl;
  cout << "   checkout                : perform a cvs checkout over a CMT package" << endl;
  cout << "   co                      : perform a cvs checkout over a CMT package" << endl;
  cout << "   cleanup [-csh|-sh|-bat] : generate a cleanup script" << endl;
  cout << "   config                  : generate setup and cleanup scripts" << endl;
  cout << "   create <package> <version> [<path>] : create and configure a new package" << endl;
  cout << "   filter <in> <out>       : filter a file against CMT macros and env. variables" << endl;
  cout << "   help                    : display this help" << endl;
  cout << "   lock [<p> <v> [<path>]] : lock a package" << endl;
  cout << "   remove <package> <version> [<path>] : remove a package version" << endl;
  cout << "   remove library_links    : remove symbolic links towards all imported libraries" << endl;
  cout << "   run <command>           : apply a command" << endl;
  cout << "   setup [-csh|-sh|-bat]   : generate a setup script" << endl;
  cout << "   show <key>              : display various infos on :" << endl;
  cout << "         all_tags          :  all defined tags" << endl;
  cout << "         applied_patterns  :  all patterns actually applied" << endl;
  cout << "         author            :  package author" << endl;
  cout << "         branches          :  added branches" << endl;
  cout << "         clients           :  package clients" << endl;
  cout << "         constituent_names :  constituent names" << endl;
  cout << "         constituents      :  constituent definitions" << endl;
  cout << "         uses              :  the use tree" << endl;
  cout << "         fragment <name>   :  one fragment definition" << endl;
  cout << "         fragments         :  fragment definitions" << endl;
  cout << "         groups            :  group definitions" << endl;
  cout << "         languages         :  language definitions" << endl;
  cout << "         macro <name>      :  a formatted macro definition" << endl;
  cout << "         macro_value <name>  :  a raw macro definition" << endl;
  cout << "         macros            :  all macro definitions" << endl;
  cout << "         manager           :  package manager" << endl;
  cout << "         packages          :  packages reachable from the current context" << endl;
  cout << "         path              :  the package search list" << endl;
  cout << "         pattern <name>    :  the pattern definition and usages" << endl;
  cout << "         pattern_names     :  pattern names" << endl;
  cout << "         patterns          :  the pattern definitions" << endl;
  cout << "         pwd               :  filtered current directory" << endl;
  cout << "         set_value <name>  :  a raw set definition" << endl;
  cout << "         set <name>        :  a formatted set definition" << endl;
  cout << "         sets              :  set definitions" << endl;
  cout << "         strategies        :  all strategies (build & version)" << endl;
  cout << "         tags              :  all currently active tags" << endl;
  cout << "         uses              :  used packages" << endl;
  cout << "         version           :  version of the current package" << endl;
  cout << "         versions <name>   :  visible versions of the selected package" << endl;
  cout << "" << endl;
  cout << "   system                  : display the system tag" << endl;
  cout << "   unlock [<p> <v> [<path>]] : unlock a package" << endl;
  cout << "   version                 : version of CMT" << endl;
  cout << "" << endl;
  cout << "   cvstags <module>         : display the CVS tags for a module" << endl;
  cout << "   cvsbranches <module>     : display the subdirectories for a module" << endl;
  cout << "   cvssubpackagess <module> : display the subpackages for a module" << endl;

  cout << " global options :" << endl;

  cout << "   -quiet                  : don't print errors" << endl;
  cout << "   -use=<p>:<v>:<path>     : set package version path" << endl;
  cout << "   -pack=<package>         : set package" << endl;
  cout << "   -version=<version>      : set version" << endl;
  cout << "   -path=<path>            : set root path" << endl;
  cout << "   -f=<requirement-file>   : set input file" << endl;
  cout << "   -e=<statement>          : add a one line statement" << endl;
  cout << "   -tag=<tag-list>         : select a new tag-set" << endl;
  cout << "   -tag_add=<tag-list>     : add specific comma-separated tag(s)" << endl;
  cout << "   -tag_remove=<tag-list>  : remove specific comma-separated tag(s)" << endl;
}

//----------------------------------------------------------
void Cmt::do_lock (const cmt_string& package,
                   const cmt_string& version,
                   const cmt_string& path)
{
  //(unsused) Use& use = Use::current();

  cout << "try to lock package " << package << " in " << CmtSystem::pwd () << endl;

  set_standard_macros ();

  CmtLock::status status = CmtLock::lock ();
}

//----------------------------------------------------------
void Cmt::do_remove (const cmt_string& package,
                     const cmt_string& version,
                     const cmt_string& path)
{
    //Use::UsePtrVector& Uses = Use::uses ();

  if (m_current_package == "CMT") return;
  if (m_current_package == "methods") return;

  cmt_string the_path;

  //the_path = m_default_path;
  the_path = CmtSystem::pwd ();

  if (path != "")
    {
      if (!CmtSystem::absolute_path (path))
        {
          // path is just a suffix
          the_path += CmtSystem::file_separator ();
          the_path += path;
        }
      else // absolute path
        {
          the_path = path;
        }
    }

  CmtSystem::compress_path (the_path);

  cout << "------------------------------------------" << endl;
  cout << "Removing package " << package <<
    " version " << version << "." << endl;
  cout << "CMT version " << m_cmt_version << "." << endl;
  cout << "Root set to " << the_path << "." << endl;
  cout << "System is " << m_cmt_config << endl;
  cout << "------------------------------------------" << endl;

  the_path += CmtSystem::file_separator ();
  the_path += package;

  if (CmtSystem::cd (the_path) && 
      CmtSystem::test_directory (version))
    {
      if (CmtSystem::remove_directory (version))
        {
          cout << "Version " << version << " has been removed from " << the_path << endl;
          CmtSystem::cmt_string_vector contents;
          CmtSystem::scan_dir (".", contents);
          if (contents.size () == 0)
            {
              CmtSystem::cd ("..");
              if (CmtSystem::remove_directory (package))
                {
                  cout << "Package " << package << " has no more versions. Thus it has been removed."<< endl;
                }
            }
        }
      else
        {
          cout << "Impossible to remove version " << version << " from " << the_path << endl;
        }
    }
  else
    {
      cout << "Version " << version << " not found" << endl;
    }
}

//----------------------------------------------------------
void Cmt::do_remove_library_links ()
{
  if (CmtLock::check () == CmtLock::locked_by_another_user)
    {
      CmtError::set (CmtError::conflicting_lock, "remove_library_links>");
      return;
    }

  set_standard_macros ();

  Use::UsePtrVector& Uses = Use::uses ();
  Use& current_use = Use::current ();
  int i;
  cmt_string shlibsuffix;
  cmt_string symunlink;

  {
    Symbol* macro = Symbol::find ("shlibsuffix");
    if (macro == 0) return;
    shlibsuffix = macro->build_macro_value ();
  }

  {
    Symbol* macro = Symbol::find ("symunlink");
    if (macro == 0) return;
    symunlink = macro->build_macro_value ();
  }

  for (i = 0; i < Uses.size (); i++)
    {
      Use* use = Uses[i];

      if (use->discarded) continue;

      if (!use->located ())
        {
          if (!m_quiet)
            {
              cout << "# package " << use->package <<
                  " " << use->version << " " << use->path << 
                  " not found" <<
                  endl;
            }
        }
      else
        {
          if (use->package == "CMT") continue;
          if (use->package == current_use.package) continue;

          cmt_string s;

          s = use->package;
          s += "_libraries";

          Symbol* libraries_macro = Symbol::find (s);

          if (libraries_macro == 0) continue;

          cmt_string libraries = libraries_macro->build_macro_value ();
          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 (CmtSystem::absolute_path (libname))
                {
                  /**
                   *   We assume here that "library" contains a complete path.
                   *   (including the complete syntax libxxx.so)
                   */

                  cmt_string suffix;
                  CmtSystem::basename (library, name);
                }
              else
                {
                  /**
                   *   Here we expect that only the base name of the library
                   *   is given : ie it should not contain the "lib" prefix, 
                   *   nor the suffix .so, nor any path prefix.
                   *    This of course should generally correspond to a constituent name.
                   */

                  name = "lib";
                  name += libname;
                  name += ".";
                  name += shlibsuffix;
                }

              s = symunlink;
              s += " ../$(";
              s += current_use.package;
              s += "_tag)/";
              s += name;

              Symbol::expand (s);

              if (!m_quiet) cout << s << endl;
              int status = CmtSystem::execute (s);

              if (status != 0)
                {
                  if (status != 2) CmtError::set (CmtError::execution_error, s);

                  cout << "Cannot remove the symbolic link " << s << endl;

                  break;
                }
            }
        }
    }
}

//----------------------------------------------------------
void Cmt::do_run (const CmtSystem::cmt_string_vector& arguments)
{
  if (arguments.size () > 0) CmtSystem::execute (arguments[0]);
}

/**
 *  This very simplified sequence interpreter is meant for 
 *  internal use only, for driving demo or test scenarios.
 *   This is run as follows:
 *
 *      > cd ../demo
 *      > cmt run_sequence xxx.cmt
 *
 *   where xxx.cmt is a text file containing descriptions of sequence steps:
 *
 *   sequence_step :
 *       package-creation
 *     | file-description
 *     | package-access
 *     | cmt-action
 *     | comment
 *
 *   package-creation :
 *       "%%package" <package-name> requirements-file
 *
 *          This creates a package from the current location, at version v1
 *         structuration style is considered.
 *          Requirements file follows the statement.
 *
 *   requirements-file :
 *       file-contents
 *
 *   file-description :
 *       "%%file" <file-path> file-contents
 *
 *           Create a files relatively to the last created package.
 *
 *   package-access :
 *       "%%cdpackage" <package-name>
 *
 *           Move to the cmt directory of the specified package
 *
 *   cmt-action :
 *       "%%cmt" <arguments>
 *
 *           Perform the specified cmt action.
 *
 *   file-contents :
 *       line ...
 *
 *   comment :
 *       %%% ...
 *
 */
class SequenceRunner : public FAwk
{
public:

  SequenceRunner ()
  {
  }

  void begin ()
  {
    started = false;
    running = false;
    if (style == CmtSystem::getenv ("CMTSTRUCTURINGSTYLE"))
      {
        vdir = CmtSystem::file_separator (); 
        vdir += "v1"; 
      } 
    else
      {
        vdir = ""; 
      }
    package = "";
    filename = "";
    buffer = "";
    pwd = "";
  }

  void filter (const cmt_string& line)
  {
    //cout << "line=[" << line << "]" << endl;

    CmtSystem::cmt_string_vector words;

    CmtSystem::split (line, " \t", words);

    cmt_string verb;

    if (words.size () > 0) verb = words[0];

    if (verb.substr (0, 2) == "%%")
      {
	if (verb.substr (0, 3) == "%%%") return;

        if (running)
          {
            buffer.write (filename);
            //cout << "%%Writing file " << filename << endl;
            //cout << buffer << endl;
            buffer = "";

            running = false;
          }
      }

    if (verb == "%%package")
      {
        package = words[1];

        cmt_string command = "cmt create ";
        command += package;
        command += " v1";

        CmtSystem::execute (command);
        //cout << "%% creating package " << package << " with command [" << command << "]" << endl;

        filename = package;
        filename += vdir;
        filename += CmtSystem::file_separator ();
        filename += "cmt";
        filename += CmtSystem::file_separator ();
        filename += "requirements";

        started = true;
      }
    else if (verb == "%%file") 
      {
        cmt_string file = words[1];

        cmt_string d = package;
        d += vdir;
        d += CmtSystem::file_separator ();
        d += file;
        CmtSystem::dirname (d, d);
        
        CmtSystem::mkdir (d);
        //cout << "%% creating directory " << d << endl;

        buffer = "";

        filename = package;
        filename += vdir;
        filename += CmtSystem::file_separator ();
        filename += file; 
        started = true;
      }
    else if (verb == "%%cdpackage") 
      {
        package = words[1];

        pwd = package;
        pwd += vdir;
        pwd += CmtSystem::file_separator ();
        pwd += "cmt";
      }
    else if (verb == "%%cmt") 
      {
        cmt_string command;

        if (pwd != "")
          {
            command = "cd ";
            command += pwd;
            command += " ";
            command += CmtSystem::command_separator ();
            command += " ";
          }

        command += line;
        command.replace ("%%", "");

        CmtSystem::execute (command);
      }
    else
      {
        buffer += line;
        buffer += "\n";
      }

    if (started)
      {
        started = false;
        running = true;
      }
  }

  void end ()
  {
    if (running)
      {
        if (buffer != "")
          {
            buffer.write (filename);
            //cout << "%%Writing file " << filename << endl;
            //cout << buffer << endl;
            buffer = "";
          }
        running = false;
      }
  }

private:
  bool started;
  bool running;
  cmt_string style;
  cmt_string vdir;
  cmt_string package;
  cmt_string filename;
  cmt_string buffer;
  cmt_string pwd;
};

//----------------------------------------------------------
void Cmt::do_run_sequence (const CmtSystem::cmt_string_vector& arguments)
{
  if (arguments.size () == 0) cout << "# cmt run_sequence: no sequence specified" << endl;

  SequenceRunner runner;

  cout << "# cmt run_sequence: sequence " << arguments[0] << endl;

  runner.run (arguments[0]);
}

//----------------------------------------------------------
void Cmt::do_setup (PrintMode& mode)
{
  print (mode);
}

//----------------------------------------------------------
void Cmt::do_show_all_tags ()
{
  Tag::TagPtrVector tags = Tag::tags ();
  int index;

  set_standard_macros ();

  for (index = 0; index < tags.size (); index++)
    {
      const Tag* tag = tags[index];
      if (tag != 0)
        {
          tag->show_definition (true);
        }
    }
}

//----------------------------------------------------------
void Cmt::do_show_applied_patterns ()
{
  Pattern::show_all_applied_patterns ();
}

//----------------------------------------------------------
void Cmt::do_show_author ()
{
  Use& use = Use::current();

  cout << use.author << endl;
}

//----------------------------------------------------------
void Cmt::do_show_branches (PrintMode& mode)
{
  Branch::print_all (mode);
}

//----------------------------------------------------------
void Cmt::do_show_clients (const CmtSystem::cmt_string_vector& arguments)
{
  cmt_string package;
  cmt_string version;
  cmt_string path_name;

  if (arguments.size () >= 1) package = arguments[0];
  if (arguments.size () >= 2) version = arguments[1];
  if (arguments.size () >= 3) path_name = arguments[2];

  FileScanner scanner;
  PackageCollector collector (package, version);

  clear ();
  configure ();

  cout << "# ----------- Clients of " << package <<
    " " << version <<
    " " << path_name <<
    endl;

  if (path_name == "")
    {
      int path_index;

      for (path_index = 0; path_index < m_cmt_path.size (); path_index++)
        {
          const cmt_string& path = m_cmt_path[path_index];

          scanner.scan_path (path, collector);
        }
    }
  else
    {
      scanner.scan_path (path_name, collector);
    }
  cout << "# ----------- " << collector.count () << " clients found." << endl;
}

//----------------------------------------------------------
void Cmt::do_show_constituent (const CmtSystem::cmt_string_vector& arguments)
{
  if (arguments.size () > 0) 
    {
      set_standard_macros ();
      Constituent::show (arguments[0]);
    }
}

//----------------------------------------------------------
void Cmt::do_show_constituent_names ()
{
  set_standard_macros ();
  Constituent::show_names ();
}

//----------------------------------------------------------
void Cmt::do_show_constituents ()
{
  set_standard_macros ();
  Constituent::show_all ();
}

//----------------------------------------------------------
void Cmt::do_show_fragment (const CmtSystem::cmt_string_vector& arguments)
{
  if (arguments.size () > 0) Fragment::show (arguments[0]);
}

//----------------------------------------------------------
void Cmt::do_show_fragments ()
{
  Fragment::show_all ();
}

//----------------------------------------------------------
void Cmt::do_show_groups ()
{
  Group::show_all ();
}

//----------------------------------------------------------
void Cmt::do_show_include_dirs ()
{
  cmt_string temp;

  Use& use = Use::current();

  set_standard_macros ();

  if (use.include_path == "")
    {
      temp += "$(src) ";
    }
  else if (use.include_path != "none")
    {
      temp += use.include_path;
      temp += " ";
    }

  for (int include_number = 0;
       include_number < use.includes.size ();
       include_number++)
    {
      Include& incl = use.includes[include_number];
      
      temp += incl.name;
      temp += " ";
    }

  cout << temp << endl;
}

//----------------------------------------------------------
void Cmt::do_show_language (const CmtSystem::cmt_string_vector& arguments)
{
  if (arguments.size () > 0) 
    {
      set_standard_macros ();
      Language::show (arguments[0]);
    }
}

//----------------------------------------------------------
void Cmt::do_show_languages ()
{
  set_standard_macros ();
  Language::show_all ();
}

//----------------------------------------------------------
void Cmt::do_show_macro (const CmtSystem::cmt_string_vector& arguments,
                         PrintMode& mode)
{
  cmt_string target;

  if (arguments.size () > 0) target = arguments[0];

  Symbol* symbol;

  set_standard_macros ();

  symbol = Symbol::find (target);

  if (symbol == 0) 
    {
      cmt_string t = " ";
      t += target;
      t += " is not a ";

      if ((m_action == action_show_macro) ||
          (m_action == action_show_macro_value))
        {
          t += "macro";
        }
      else if ((m_action == action_show_set) ||
               (m_action == action_show_set_value))
        {
          t += "set";
        }

      CmtError::set (CmtError::symbol_not_found, t);

      return;
    }
  else
    {
      cmt_string t = " ";
      t += target;
      t += " is not a ";

      if ((m_action == action_show_macro) ||
          (m_action == action_show_macro_value))
	{
	  if ((symbol->command != CommandMacro) &&
	      (symbol->command != CommandMacroAppend) &&
	      (symbol->command != CommandMacroPrepend) &&
	      (symbol->command != CommandMacroRemove) &&
	      (symbol->command != CommandMacroRemoveAll))
	    {
	      t += "macro";

	      CmtError::set (CmtError::symbol_not_found, t);

	      return;
	    }
	}
      else if ((m_action == action_show_set) ||
               (m_action == action_show_set_value))
        {
	  if ((symbol->command != CommandSet) &&
	      (symbol->command != CommandSetAppend) &&
	      (symbol->command != CommandSetPrepend) &&
	      (symbol->command != CommandSetRemove) &&
	      (symbol->command != CommandPath) &&
	      (symbol->command != CommandPathAppend) &&
	      (symbol->command != CommandPathPrepend) &&
	      (symbol->command != CommandPathRemove))
	    {
	      t += "set";

	      CmtError::set (CmtError::symbol_not_found, t);

	      return;
	    }
        }
    }

  if (symbol->value_lists.size () < 1) return;

  symbol->show_macro (mode);
}

//----------------------------------------------------------
void Cmt::do_show_macro_names (const CmtSystem::cmt_string_vector& arguments,
                               PrintMode& mode)
{
  if (arguments.size () > 0)
    {
      const cmt_string& pattern = arguments[0];
      print_symbol_names (mode, pattern);
    }
  else
    {
      print_symbol_names (mode);
    }
}

//----------------------------------------------------------
void Cmt::do_show_macro_value (const CmtSystem::cmt_string_vector& arguments,
                               PrintMode& mode)
{
  do_show_macro (arguments, mode);
}

//----------------------------------------------------------
void Cmt::do_show_macros (const CmtSystem::cmt_string_vector& arguments,
			  PrintMode& mode)
{
  if (arguments.size () > 0)
    {
      const cmt_string& pattern = arguments[0];
      print_macros (mode, pattern);
    }
  else
    {
      print_macros (mode);
    }
}

//----------------------------------------------------------
void Cmt::do_show_manager ()
{
  Use& use = Use::current();

  cout << use.manager << endl;
}

//----------------------------------------------------------
void Cmt::do_show_packages (const CmtSystem::cmt_string_vector& arguments)
{
  cmt_string path_name;

  if (arguments.size () > 0) path_name = arguments[0];

  FileScanner scanner;
  PackageViewer viewer;

  if (path_name == "")
    {
      int path_index;

      for (path_index = 0; path_index < m_cmt_path.size (); path_index++)
        {
          const cmt_string& path = m_cmt_path[path_index];

          scanner.scan_path (path, viewer);
        }
    }
  else
    {
      scanner.scan_path (path_name, viewer);
    }
}

//----------------------------------------------------------
void Cmt::do_show_path ()
{
  int path_index;

  if (!m_quiet)
    {
      for (path_index = 0; path_index < m_cmt_path.size (); path_index++)
        {
          const cmt_string& path   = m_cmt_path[path_index];
          const cmt_string& source = m_cmt_path_sources[path_index];

          cout << "# Add path " << path << " from " << source << endl;
        }

      cout << "#" << endl;
    }

  for (path_index = 0; path_index < m_cmt_path.size (); path_index++)
    {
      const cmt_string& path   = m_cmt_path[path_index];
      const cmt_string& source = m_cmt_path_sources[path_index];

      if (path_index > 0) cout << CmtSystem::path_separator ();

      cout << path;
    }

  cout << endl;
}

//----------------------------------------------------------
void Cmt::do_show_pattern (const CmtSystem::cmt_string_vector& arguments)
{
  cmt_string name;
  if (arguments.size () > 0) name = arguments[0];
  Pattern::show (name);
}

//----------------------------------------------------------
void Cmt::do_show_pattern_names ()
{
  Pattern::show_all_names ();
}

//----------------------------------------------------------
void Cmt::do_show_patterns ()
{
  Pattern::show_all ();
}

//----------------------------------------------------------
void Cmt::do_show_pwd ()
{
  cout << m_current_dir << endl;
}

//----------------------------------------------------------
void Cmt::do_show_set (const CmtSystem::cmt_string_vector& arguments,
                       PrintMode& mode)
{
  do_show_macro (arguments, mode);
}

//----------------------------------------------------------
void Cmt::do_show_set_names (const CmtSystem::cmt_string_vector& arguments,
                             PrintMode& mode)
{
  if (arguments.size () > 0)
    {
      const cmt_string& pattern = arguments[0];
      print_symbol_names (mode, pattern);
    }
  else
    {
      print_symbol_names (mode);
    }
}

//----------------------------------------------------------
void Cmt::do_show_set_value (const CmtSystem::cmt_string_vector& arguments,
                             PrintMode& mode)
{
  do_show_macro (arguments, mode);
}

//----------------------------------------------------------
void Cmt::do_show_sets (const CmtSystem::cmt_string_vector& arguments,
			PrintMode& mode)
{
  if (arguments.size () > 0)
    {
      const cmt_string& pattern = arguments[0];
      print_macros (mode, pattern);
    }
  else
    {
      print_macros (mode);
    }
}

//----------------------------------------------------------
void Cmt::do_show_strategies ()
{
  cout << "Version strategy : ";

  switch (m_current_strategy)
    {
    case BestFit :
      cout << "BestFit";
      break;
    case BestFitNoCheck :
      cout << "BestFitNoCheck";
      break;
    case FirstChoice :
      cout << "FirstChoice";
      break;
    case LastChoice :
      cout << "LastChoice";
      break;
    case KeepAll :
      cout << "KeepAll";
      break;
    default :
      cout << "BestFit";
      break;
    }
  
  cout << endl;
  
  cout << "Build strategy   : ";
  
  if ((m_current_build_strategy & PrototypesMask) == Prototypes)
    {
      cout << "prototypes";
    }
  else
    {
      cout << "no_prototypes";
    }
  
  if ((m_current_build_strategy & KeepMakefilesMask) == KeepMakefiles)
    {
      cout << " keep_makefiles";
    }
  else
    {
      cout << " rebuild_makefiles";
    }
  
  cout << endl;
}

//----------------------------------------------------------
void Cmt::do_show_tags ()
{
  Tag::TagPtrVector tags = Tag::tags ();
  int index;

  set_standard_macros ();

  for (index = 0; index < tags.size (); index++)
    {
      const Tag* tag = tags[index];
      if (tag != 0)
        {
          tag->show (m_quiet);
        }
    }
}

//----------------------------------------------------------
void Cmt::do_show_uses ()
{
  Use::show_all ();

/*
  {
    Use::UsePtrVector& Uses = Use::uses ();

    Use& cu = Use::current ();

    for (int i = 0; i < Uses.size (); i++)
      {
        Use* use = Uses[i];
        
        if (use == 0) continue;
        if (use->discarded) continue;
        
        Use::UsePtrVector list;
        
        cu.get_paths (use, list);

        cout << " to " << use->package << endl;

        for (int j = list.size (); j >= 0; j--)
          {
            Use* u = list[j];
            if (u == 0) continue;
            cout << "  " << u->package << endl;
          }
      }
  }
*/
}

//----------------------------------------------------------
void Cmt::do_show_version ()
{
  cout << m_current_version << endl;
}

//----------------------------------------------------------
void Cmt::do_show_versions (const CmtSystem::cmt_string_vector& arguments)
{
  cmt_string package_name;

  if (arguments.size () > 0) package_name = arguments[0];

  FileScanner scanner;

  int path_index;

  for (path_index = 0; path_index < m_cmt_path.size (); path_index++)
    {
      const cmt_string& path   = m_cmt_path[path_index];

      scanner.scan_package (path, package_name);
    }
}

//----------------------------------------------------------
void Cmt::do_show_system ()
{
  cout << CmtSystem::get_cmt_config () << endl;
}

//----------------------------------------------------------
void Cmt::do_unlock (const cmt_string& package,
                     const cmt_string& version,
                     const cmt_string& path)
{
  // (unused??) Use& use = Use::current();

  cout << "try to unlock package " << package << " in " << CmtSystem::pwd () << endl;

  set_standard_macros ();

  CmtLock::status status = CmtLock::unlock ();
}

//----------------------------------------------------------
void Cmt::do_version ()
{
  cout << CMTVERSION << endl;
}



//----------------------------------------------------------
ActionType Cmt::get_action ()
{
  return (m_action);
}

const CmtSystem::cmt_string_vector& Cmt::get_cmt_path ()
{
  return (m_cmt_path);
}

const cmt_string& Cmt::get_cmt_home ()
{
  return (m_cmt_home);
}

const cmt_string& Cmt::get_cmt_user_context ()
{
  return (m_cmt_user_context);
}

const cmt_string& Cmt::get_current_dir ()
{
  return (m_current_dir);
}

const cmt_string& Cmt::get_current_package ()
{
  return (m_current_package);
}

AccessMode Cmt::get_current_access ()
{
  return (m_current_access);
}

VersionStrategy Cmt::get_current_strategy ()
{
  return (m_current_strategy);
}

const cmt_string& Cmt::get_current_version ()
{
  return (m_current_version);
}

const cmt_string& Cmt::get_current_target ()
{
  return (m_current_target);
}

bool Cmt::get_debug ()
{
  return (m_debug);
}

bool Cmt::get_quiet ()
{
  return (m_quiet);
}

bool Cmt::get_recursive ()
{
  return (m_recursive);
}

ScopeType Cmt::get_scope ()
{
  return (m_scope);
}

//----------------------------------------------------------
const cmt_string& Cmt::filter_dir (const cmt_string& dir)
{
  static cmt_string newdir;

  CmtSystem::compress_path (dir, newdir);

  return (newdir);
}

//----------------------------------------------------------
void Cmt::install_cleanup_scripts ()
{
#ifdef WIN32
  static const int modes = 1;
  static const cmt_string suffix[1]   = {"bat"};
  static const PrintMode  mode[1]     = {Bat};
#else
  static const int modes = 2;
  static const cmt_string suffix[2]   = {"csh", "sh"};
  static const PrintMode  mode[2]     = {Csh, Sh};
#endif

  cout << "Creating cleanup scripts." << endl;

  cmt_string temp;
  int i;

  for (i = 0; i < modes; i++)
    {
      cmt_string file_name = "cleanup";
      file_name += ".";
      file_name += suffix[i];
      file_name += ".";
      file_name += "new";

      FILE* f = fopen (file_name.c_str (), "wb");
      if (f != NULL)
        {
          if (mode[i] == Csh)
            {
              fprintf (f, "set tempfile=`${CMTROOT}/mgr/cmt build temporary_name -quiet`\n");
              fprintf (f, "if $status != 0 then\n  set tempfile=/tmp/cmt.$$\nendif\n");
              fprintf (f, "${CMTROOT}/mgr/cmt -quiet cleanup -%s "
                       "-pack=%s -version=%s -path=%s $* >${tempfile}; "
                       "source ${tempfile}\n",
                       suffix[i].c_str (),
                       m_current_package.c_str (),
                       m_current_version.c_str (),
                       m_current_path.c_str ());
              fprintf (f, "/bin/rm -f ${tempfile}\n");
            }
          else if (mode[i] == Sh)
            {
              fprintf (f, "tempfile=`${CMTROOT}/mgr/cmt build temporary_name -quiet`\n");
              fprintf (f, "if test ! $? = 0 ; then tempfile=/tmp/cmt.$$; fi\n");
              fprintf (f, "${CMTROOT}/mgr/cmt -quiet cleanup -%s "
                       "-pack=%s -version=%s -path=%s $* >${tempfile}; "
                       ". ${tempfile}\n",
                       suffix[i].c_str (),
                       m_current_package.c_str (),
                       m_current_version.c_str (),
                       m_current_path.c_str ());
              fprintf (f, "/bin/rm -f ${tempfile}\n");
            }
          else if (mode[i] == Bat)
            {
              fprintf (f, "set tempfile=%%HOMEDRIVE%%%%HOMEPATH%%tmpsetup.bat\n");
              fprintf (f, "%%CMTROOT%%\\%%CMTBIN%%\\cmt.exe -quiet cleanup -%s "
                       "-path=%s "
		       "%%1 %%2 %%3 %%4 %%5 %%6 %%7 %%8 %%9 >%%tempfile%%\n",
                       suffix[i].c_str (),
                       m_current_path.c_str ());
              fprintf (f, "if exist %%tempfile%% call %%tempfile%%\n");
              fprintf (f, "if exist %%tempfile%% del %%tempfile%%\n");
            }

          fprintf (f, "\n");

          fclose (f);

          cmt_string old_file_name = "cleanup";
          old_file_name += ".";
          old_file_name += suffix[i];

          CmtSystem::compare_and_update_files (file_name, old_file_name);
        }
    }
}

//----------------------------------------------------------
void Cmt::install_setup_scripts ()
{
#ifdef WIN32
  static const int modes = 1;
  static const cmt_string suffix[1]   = {"bat"};
  static const PrintMode  mode[1]     = {Bat};
#else
  static const int modes = 2;
  static const cmt_string suffix[2]   = {"csh", "sh"};
  static const PrintMode  mode[2]     = {Csh, Sh};
#endif

  cout << "Creating setup scripts." << endl;

  cmt_string temp;
  int i;

  for (i = 0; i < modes; i++)
    {
      cmt_string file_name = "setup";
      file_name += ".";
      file_name += suffix[i];
      file_name += ".";
      file_name += "new";

      FILE* f = fopen (file_name.c_str (), "wb");
      if (f != NULL)
        {
          if (mode[i] == Csh)
            {
              fprintf (f, "# echo \"Setting %s %s in %s\"\n",
                       m_current_package.c_str (),
                       m_current_version.c_str (),
                       m_current_path.c_str ());
              fprintf (f, "\n");

              fprintf (f, "setenv CMTROOT %s\n", m_cmt_root.c_str ());
              fprintf (f, "source ${CMTROOT}/mgr/setup.csh\n");
              fprintf (f, "\n");
              fprintf (f, "set tempfile=`${CMTROOT}/mgr/cmt build temporary_name -quiet`\n");
              fprintf (f, "if $status != 0 then\n  set tempfile=/tmp/cmt.$$\nendif\n");
              fprintf (f, "${CMTROOT}/mgr/cmt -quiet setup -%s "
                       "-pack=%s -version=%s -path=%s $* >${tempfile}; "
                       "source ${tempfile}\n",
                       suffix[i].c_str (),
                       m_current_package.c_str (),
                       m_current_version.c_str (),
                       m_current_path.c_str ());
              fprintf (f, "/bin/rm -f ${tempfile}\n");
            }
          else if (mode[i] == Sh)
            {
              fprintf (f, "# echo \"Setting %s %s in %s\"\n",
                       m_current_package.c_str (),
                       m_current_version.c_str (),
                       m_current_path.c_str ());
              fprintf (f, "\n");

              fprintf (f, "CMTROOT=%s; export CMTROOT\n", m_cmt_root.c_str ());
              fprintf (f, ". ${CMTROOT}/mgr/setup.sh\n");
              fprintf (f, "\n");
              fprintf (f, "tempfile=`${CMTROOT}/mgr/cmt build temporary_name -quiet`\n");
              fprintf (f, "if test ! $? = 0 ; then tempfile=/tmp/cmt.$$; fi\n");
              fprintf (f, "${CMTROOT}/mgr/cmt -quiet setup -%s "
                       "-pack=%s -version=%s -path=%s $* >${tempfile}; "
                       ". ${tempfile}\n",
                       suffix[i].c_str (),
                       m_current_package.c_str (),
                       m_current_version.c_str (),
                       m_current_path.c_str ());
              fprintf (f, "/bin/rm -f ${tempfile}\n");
            }
          else if (mode[i] == Bat)
            {
              fprintf (f, "rem Setting %s %s in %s\n",
                       m_current_package.c_str (),
                       m_current_version.c_str (),
                       m_current_path.c_str ());
              fprintf (f, "@echo off\n");

              fprintf (f, "set CMTROOT=%s\n", m_cmt_root.c_str ());
              fprintf (f, "call %%CMTROOT%%\\mgr\\setup.bat\n");
              fprintf (f, "\n");
              fprintf (f, "set tempfile=%%HOMEDRIVE%%%%HOMEPATH%%tmpsetup.bat\n");
              fprintf (f, "%%CMTROOT%%\\%%CMTBIN%%\\cmt.exe -quiet setup -%s "
                       "-pack=%s -version=%s -path=%s "
		       "%%1 %%2 %%3 %%4 %%5 %%6 %%7 %%8 %%9 >%%tempfile%%\n",
                       suffix[i].c_str (),
                       m_current_package.c_str (),
                       m_current_version.c_str (),
                       m_current_path.c_str ());
              fprintf (f, "if exist %%tempfile%% call %%tempfile%%\n");
              fprintf (f, "if exist %%tempfile%% del %%tempfile%%\n");
            }

          fprintf (f, "\n");

          fclose (f);

          cmt_string old_file_name = "setup";
          old_file_name += ".";
          old_file_name += suffix[i];

          CmtSystem::compare_and_update_files (file_name, old_file_name);
        }
    }
}

//----------------------------------------------------------
void Cmt::install_test_cleanup_scripts ()
{
#ifdef WIN32
  static const int modes = 1;
  static const cmt_string suffix[1]   = {"bat"};
  static const PrintMode  mode[1]     = {Bat};
#else
  static const int modes = 2;
  static const cmt_string suffix[2]   = {"csh", "sh"};
  static const PrintMode  mode[2]     = {Csh, Sh};
#endif

  cout << "Creating cleanup scripts." << endl;

  cmt_string temp;
  int i;

  for (i = 0; i < modes; i++)
    {
      cmt_string file_name = "cleanup";
      file_name += ".";
      file_name += suffix[i];
      file_name += ".";
      file_name += "new";

      FILE* f = fopen (file_name.c_str (), "wb");
      if (f != NULL)
        {
          if (mode[i] == Csh)
            {
              fprintf (f, "setenv CMTROOT %s\n", m_cmt_root.c_str ());
              fprintf (f, "source ${CMTROOT}/mgr/setup.csh\n");
              fprintf (f, "set tempfile=`${CMTROOT}/mgr/cmt build temporary_name -quiet`\n");
              fprintf (f, "if $status != 0 then\n  set tempfile=/tmp/cmt.$$\nendif\n");
              fprintf (f, "${CMTROOT}/mgr/cmt -quiet cleanup -%s -pack=cmt_standalone -path=%s $* >${tempfile}; "
                       "source ${tempfile}\n",
                       suffix[i].c_str (),
                       m_current_path.c_str ());
              fprintf (f, "/bin/rm -f ${tempfile}\n");
            }
          else if (mode[i] == Sh)
            {
              fprintf (f, "CMTROOT=%s; export CMTROOT\n", m_cmt_root.c_str ());
              fprintf (f, ". ${CMTROOT}/mgr/setup.sh\n");
              fprintf (f, "tempfile=`${CMTROOT}/mgr/cmt build temporary_name -quiet`\n");
              fprintf (f, "if test ! $? = 0 ; then tempfile=/tmp/cmt.$$; fi\n");
              fprintf (f, "${CMTROOT}/mgr/cmt -quiet cleanup -%s -pack=cmt_standalone -path=%s $* >${tempfile}; "
                       ". ${tempfile}\n",
                       suffix[i].c_str (),
                       m_current_path.c_str ());
              fprintf (f, "/bin/rm -f ${tempfile}\n");
            }
          else
            {
              fprintf (f, "set CMTROOT=%s\n", m_cmt_root.c_str ());
              fprintf (f, "call %%CMTROOT%%\\mgr\\setup.bat\n");
              fprintf (f, "set tempfile=%%HOMEDRIVE%%%%HOMEPATH%%tmpsetup.bat\n");
              fprintf (f, "%%CMTROOT%%\\%%CMTBIN%%\\cmt.exe -quiet cleanup -%s "
                       "-pack=cmt_standalone -path=%s "
		       "%%1 %%2 %%3 %%4 %%5 %%6 %%7 %%8 %%9 >%%tempfile%%\n",
                       suffix[i].c_str (),
                       m_current_path.c_str ());
              fprintf (f, "if exist %%tempfile%% call %%tempfile%%\n");
              fprintf (f, "if exist %%tempfile%% del %%tempfile%%\n");
            }

          fprintf (f, "\n");

          fclose (f);

          cmt_string old_file_name = "cleanup";
          old_file_name += ".";
          old_file_name += suffix[i];

          CmtSystem::compare_and_update_files (file_name, old_file_name);
        }
    }
}

//----------------------------------------------------------
void Cmt::install_test_setup_scripts ()
{
#ifdef WIN32
  static const int modes = 1;
  static const cmt_string suffix[1]   = {"bat"};
  static const PrintMode  mode[1]     = {Bat};
#else
  static const int modes = 2;
  static const cmt_string suffix[2]   = {"csh", "sh"};
  static const PrintMode  mode[2]     = {Csh, Sh};
#endif

  cout << "Creating setup scripts." << endl;

  cmt_string temp;
  int i;

  for (i = 0; i < modes; i++)
    {
      cmt_string file_name = "setup";
      file_name += ".";
      file_name += suffix[i];
      file_name += ".";
      file_name += "new";

      FILE* f = fopen (file_name.c_str (), "wb");
      if (f != NULL)
        {
          if (mode[i] == Csh)
            {
              fprintf (f, "# echo \"Setting standalone package\"\n");
              fprintf (f, "\n");

              fprintf (f, "setenv CMTROOT %s\n", m_cmt_root.c_str ());
              fprintf (f, "source ${CMTROOT}/mgr/setup.csh\n");
              fprintf (f, "set tempfile=`${CMTROOT}/mgr/cmt build temporary_name -quiet`\n");
              fprintf (f, "if $status != 0 then\n  set tempfile=/tmp/cmt.$$\nendif\n");
              fprintf (f, "${CMTROOT}/mgr/cmt -quiet setup -%s -pack=cmt_standalone -path=%s $* >${tempfile}; "
                       "source ${tempfile}\n",
                       suffix[i].c_str (),
                       m_current_path.c_str ());
              fprintf (f, "/bin/rm -f ${tempfile}\n");
            }
          else if (mode[i] == Sh)
            {
              fprintf (f, "# echo \"Setting standalone package\"\n");
              fprintf (f, "\n");

              fprintf (f, "CMTROOT=%s; export CMTROOT\n", m_cmt_root.c_str ());
              fprintf (f, ". ${CMTROOT}/mgr/setup.sh\n");
              fprintf (f, "\n");
              fprintf (f, "tempfile=`${CMTROOT}/mgr/cmt build temporary_name -quiet`\n");
              fprintf (f, "if test ! $? = 0 ; then tempfile=/tmp/cmt.$$; fi\n");
              fprintf (f, "${CMTROOT}/mgr/cmt -quiet setup -%s -pack=cmt_standalone -path=%s $* >${tempfile}; "
                       ". ${tempfile}\n",
                       suffix[i].c_str (),
                       m_current_path.c_str ());
              fprintf (f, "/bin/rm -f ${tempfile}\n");
            }
          else
            {
              fprintf (f, "rem Setting standalone package\n");
              fprintf (f, "@echo off\n");

              fprintf (f, "set CMTROOT=%s\n", m_cmt_root.c_str ());
              fprintf (f, "call %%CMTROOT%%\\mgr\\setup.bat\n");
              fprintf (f, "\n");
              fprintf (f, "set tempfile=%%HOMEDRIVE%%%%HOMEPATH%%tmpsetup.bat\n");
              fprintf (f, "%%CMTROOT%%\\%%CMTBIN%%\\cmt.exe -quiet setup -%s "
                       "-pack=cmt_standalone -path=%s "
		       "%%1 %%2 %%3 %%4 %%5 %%6 %%7 %%8 %%9 >%%tempfile%%\n",
                       suffix[i].c_str (),
                       m_current_path.c_str ());
              fprintf (f, "if exist %%tempfile%% call %%tempfile%%\n");
              fprintf (f, "if exist %%tempfile%% del %%tempfile%%\n");
            }

          fprintf (f, "\n");

          fclose (f);

          cmt_string old_file_name = "setup";
          old_file_name += ".";
          old_file_name += suffix[i];

          CmtSystem::compare_and_update_files (file_name, old_file_name);
        }
    }
}

/**
 *    load is only called from the Windows GUI which pretends to access directly
 *   the internal data model.
 *    This is considered to be rather unsafe, and should be replaced by query functions.
 */
bool Cmt::load (const cmt_string& path,
                const cmt_string& package,
                const cmt_string& version,
                const cmt_string& tag_name)
{
  clear ();
  configure ();

  m_action  = action_load;
  m_recursive = true;

  if (((package != "") && (version != "")) || (m_current_package == ""))
    {
      //
      //  Here we want to connect to a new package, or to the current package
      //  but with another tag.
      //
      //   the 'package' argument may include a directory offset. Thus 'path'
      //  is only expected to hold the base directory.
      //
      cmt_string offset;
      cmt_string package_name;
      
      CmtSystem::dirname (package, offset);
      CmtSystem::basename (package, package_name);
      
      if (offset != "")
        {
          m_current_path = path;
          m_current_path += CmtSystem::file_separator ();
          m_current_path += offset;
        }
      else
        {
          m_current_path = path;
        }
      
      m_current_package = package_name;
      m_current_version = version;
    }

  if (tag_name != "")
    {
      Tag* tag;

      Tag::unmark_all ();
      configure_site_tag (0);
      configure_uname_tag ();
      configure_hosttype_tag ();

      m_current_tag = tag_name;

      //if (!m_quiet) cerr << "load1> current_tag=" << m_current_tag << endl;

      tag = Tag::add (tag_name, PriorityTag, "load", 0);
      tag->mark ();
    }

  /*
    Set to developer mode if positioned into the package
    (which is detected since we were able to retreive the
    Version, Package and Path)
  */

  if ((m_current_path == "") ||
      (m_current_package == "") ||
      (m_current_version == ""))
    {
      m_current_access = UserMode;
    }
  else
    {
      m_current_access = DeveloperMode;
    }

  use_cmt ();

  cmt_string dir;

  /*
    Try to access the package.
  */

  if (m_current_path != "")
    {
      dir = m_current_path;
    }
  else
    {
      dir = m_default_path;
    }

  if (!CmtSystem::cd (m_current_path))
    {
      if (!m_quiet)
        {
          cout << "#CMT> Cannot reach the directory " <<
            m_current_path << endl;
        }
      CmtError::set (CmtError::package_not_found, "Load> Cannot reach the path directory");
      CmtSystem::cd (m_current_dir);

      return (false);
    }

  dir += CmtSystem::file_separator ();
  dir += m_current_package;

  if (!CmtSystem::cd (m_current_package))
    {
      if (!m_quiet)
        {
          cout << "#CMT::load> Cannot reach the package " <<
            m_current_package << endl;
        }
      CmtError::set (CmtError::package_not_found, "Load> Cannot reach the package directory");
      CmtSystem::cd (m_current_dir);

      return (false);
    }

  dir += CmtSystem::file_separator ();
  dir += m_current_version;

  if (!CmtSystem::cd (m_current_version))
    {
      if (!m_quiet)
        {
          cout << "#CMT> Cannot reach the version " <<
            m_current_version << endl;
        }
      CmtError::set (CmtError::package_not_found, "Load> Cannot reach the version directory");
      CmtSystem::cd (m_current_dir);

      return (false);
    }

  if (CmtSystem::cd ("cmt"))
    {
      dir += CmtSystem::file_separator ();
      dir += "cmt";
      m_current_style = cmt_style;
    }
  else
    {
      /*
        if (!m_quiet)
        {
        cout << "Cannot reach the cmt branch" << endl;
        }
      */

      if (CmtSystem::cd ("mgr"))
        {
          dir += CmtSystem::file_separator ();
          dir += "mgr";
          m_current_style = mgr_style;
        }
      else
        {
          if (!m_quiet)
            {
              cout << "#CMT> Cannot reach the mgr branch" << endl;
            }

          CmtError::set (CmtError::package_not_found,
                         "Load> Cannot reach the mgr/cmt directory");
          CmtSystem::cd (m_current_dir);

          return (false);
        }
    }

  /*
    Check Tag is always set up
  */

  if (m_current_tag == "")
    {
      char* env;

      env = getenv (m_current_config.c_str ());
      if (env != 0)
        {
          Tag* tag;

          tag = Tag::add (env, PriorityConfig, "load", 0);
          tag->mark ();
          m_current_tag = env;

          //if (!m_quiet) cerr << "load2> current_tag=" << m_current_tag << endl;

        }
      else
        {
          m_current_tag = m_cmt_config;

          //if (!m_quiet) cerr << "load3> current_tag=" << m_current_tag << endl;

        }
    }

  if (m_debug)
    {
      cout << "pwd = " << CmtSystem::pwd () << endl;
    }

  configure_current_dir ();
  build_prefix (m_current_package, m_current_prefix);
  build_config (m_current_prefix, m_current_config);

  Use* use = &(Use::current());
  use->path    = m_current_path;
  use->package = m_current_package;
  use->version = m_current_version;
  use->prefix  = m_current_prefix;
  use->done    = false;

  /*
    Work on the requirements file.
  */

  dir += CmtSystem::file_separator ();
  dir += "requirements";
  parse_requirements (dir, use);

  if (CmtError::has_pending_error ()) return (false);

    /**
     * See reach_current_package for an explanation of this call
     */
  Pattern::apply_all_globals ();

  /*
    Select all possible tags
  */

  Tag::restore_tree ();

  return (true);
}

//----------------------------------------------------------
bool Cmt::need_prototypes ()
{
  if ((m_current_build_strategy & PrototypesMask) == Prototypes) return (true);
  else return (false);
}

//----------------------------------------------------------
void Cmt::parse_arguments (int argc, char* argv[],
                           CmtSystem::cmt_string_vector& arguments,
                           cmt_string& extra_line,
                           cmt_string& extra_file,
                           PrintMode& mode)
{
  /*
    Decoding arguments.

    While decoding all arguments, no requirements analysis should
    occur. Every new option, or parameter should be saved and
    used later at actual analysis time.
  */

  cmt_string arg;

  m_action = action_none;

  arguments.clear ();
  extra_line.erase (0);
  extra_file.erase (0);
  mode = Csh;

    /*
      Tag management.
      ---------------

      Tag settings may come from :

      - existing environment variables:

          1) CMTCONFIG

          2) CMTEXTRATAGS for addons

      - arguments:

          -tag=<tag-list>
          -tag_add=<tag-list>
          -tag_remove=<tag-list>

       o Arguments should take precedence over environment variables.
       o when nothing is specified:

          - primary tag = CMTCONFIG
          - tag set is empty


     */


  restore_all_tags (0);

#ifdef WIN32
  m_build_nmake = true;
#endif

  while (argc > 1)
    {
      int lf;

      arg = argv[1];
      lf = arg.find ('\r');
      if (lf != cmt_string::npos) arg.erase (lf);

      if ((arg[0] == '\"') && (arg[arg.size () - 1] == '\"'))
        {
          arg.erase (0, 1);
          arg.erase (arg.size () - 1, 1);
        }

      //fprintf (stderr, "arg=[%s]\n", arg.c_str ());

      switch (arg[0])
        {
        case 'a' :
          if (arg == "awk")
            {
              argc--;
              argv++;
              while (argc > 1)
                {
                  cmt_string& s = arguments.add ();
                  s = argv[1];
                  argc--;
                  argv++;
                }

              m_action = action_awk;
            }
          break;
        case 'b' :
          if ((arg == "b") ||
              (arg == "br") ||
              (arg == "bro") ||
              (arg == "broa") ||
              (arg == "broad") ||
              (arg == "broadc") ||
              (arg == "broadca") ||
              (arg == "broadcas") ||
              (arg == "broadcast"))
            {
              argc--;
              argv++;
              while (argc > 1)
                {
                  cmt_string& s = arguments.add ();
                  s = argv[1];
                  argc--;
                  argv++;
                }

              m_action = action_broadcast;
            }
          else if (arg == "build")
            {
              argc--;
              argv++;

              if (argc > 1)
                {
                  arg = argv[1];

                  if (arg == "-nmake")
                    {
                      m_build_nmake = true;
                      argc--;
                      argv++;
                    }
                }

              if (argc > 1)
                {
                  arg = argv[1];

                  if (arg == "-nmake")
                    {
                      argc--;
                      argv++;
                    }

                  if (arg == "constituent_makefile")
                    {
                      argc--;
                      argv++;
                      if (argc > 1)
                        {
                          cmt_string& s = arguments.add ();
                          s = argv[1];

                          m_action = action_build_constituent_makefile;
                        }
                      else
                        {
                          if (!m_quiet) cout << "#CMT> syntax error : constituent name missing" << endl;
                        }
                    }
                  else if (arg == "constituents_makefile")
                    {
                      m_action = action_build_constituents_makefile;
                    }
                  else if (arg == "dependencies")
                    {
                      argc--;
                      argv++;
                      if (argc > 1)
                        {
                          cmt_string& s = arguments.add ();
                          s = argv[1];

                          m_action = action_build_dependencies;
                        }
                      else
                        {
                          if (!m_quiet) cout << "#CMT> syntax error : arguments missing " << endl;
                        }

                      argc = 0;
                    }
                  else if (arg == "library_links")
                    {
                      m_action = action_build_library_links;
                    }
                  else if (arg == "make_setup")
                    {
                      m_action = action_build_make_setup;
                    }
                  else if (arg == "msdev")
                    {
                      argc--;
                      argv++;

                      if (argc > 1)
                        {
                          cmt_string& s = arguments.add ();
                          s = argv[1];
                          if (s[0] == '-')
                            {
                              s = "";
                              argc++;
                              argv--;
                            }
                        }

                      m_action = action_build_msdev;
                    }
                  else if (arg == "os9_makefile")
                    {
                      argc--;
                      argv++;
                      if (argc > 1)
                        {
                          cmt_string& s = arguments.add ();
                          s = argv[1];

                          m_action = action_build_os9_makefile;
                        }
                      else
                        {
                          if (!m_quiet) cout << "#CMT> syntax error : arguments missing " << endl;
                        }
                    }
                  else if (arg == "prototype")
                    {
                      argc--;
                      argv++;
                      if (argc > 1)
                        {
                          cmt_string& s = arguments.add ();
                          s = argv[1];

                          m_action = action_build_prototype;
                        }
                      else
                        {
                          if (!m_quiet) cout << "#CMT> syntax error : arguments missing" << endl;
                        }
                    }
                  else if (arg == "readme")
                    {
                      m_action = action_build_readme;

                      argc--;
                      argv++;
                      while (argc > 1)
                        {
                          cmt_string& s = arguments.add ();
                          s = argv[1];
                          argc--;
                          argv++;
                        }
                    }
                  else if (arg == "tag_makefile")
                    {
                      m_action = action_build_tag_makefile;
                    }
                  else if (arg == "temporary_name")
                    {
                      m_action = action_build_temporary_name;
                    }
                  else if (arg == "triggers")
                    {
                      argc--;
                      argv++;
                      if (argc > 1)
                        {
                          cmt_string& s = arguments.add ();
                          s = argv[1];

                          m_action = action_build_triggers;
                        }
                      else
                        {
                          if (!m_quiet) cout << "#CMT> syntax error : arguments missing" << endl;
                        }
                    }
                  else if (arg == "windefs")
                    {
                      argc--;
                      argv++;
                      if (argc > 1)
                        {
                          cmt_string& s = arguments.add ();
                          s = argv[1];

                          m_action = action_build_windefs;
                        }
                      else
                        {
                          if (!m_quiet) cout << "#CMT> syntax error : arguments missing" << endl;
                        }
                    }
                }
              else
                {
                  if (!m_quiet) cout << "#CMT> syntax error : don't know what to build" << endl;
                }
            }
          else
            {
              if (!m_quiet) cout << "#CMT> syntax error : bad verb " << arg << endl;
            }
          break;
        case 'c' :
          if (arg == "check")
            {
              argc--;
              argv++;

              if (argc > 1)
                {
                  arg = argv[1];

                  if (arg == "configuration")
                    {
                      m_action = action_check_configuration;
                    }
                  else if (arg == "files")
                    {
                      argc--;
                      argv++;
                      if (argc > 1)
                        {
                          cmt_string& s = arguments.add ();
                          s = argv[1];
                          argc--;
                          argv++;
                          if (argc > 1)
                            {
                              cmt_string& s = arguments.add ();
                              s = argv[1];

                              m_action = action_check_files;
                            }
                          else
                            {
                              if (!m_quiet) cout << "#CMT> syntax error : reference file name missing" 
                                                 << endl;
                            }
                        }
                      else
                        {
                          if (!m_quiet) cout << "#CMT> syntax error : file name missing" << endl;
                        }
                    }
                  else if (arg == "version")
                    {
                      argc--;
                      argv++;
                      if (argc > 1)
                        {
                          cmt_string& s = arguments.add ();
                          s = argv[1];

                          m_action = action_check_version;
                        }
                      else
                        {
                          if (!m_quiet) cout << "#CMT> syntax error : package name missing" << endl;
                        }
                    }
                  else
                    {
                      if (!m_quiet) cout << "#CMT> syntax error : bad check option" << endl;
                    }
                }
              else
                {
                  if (!m_quiet) cout << "#CMT> syntax error : don't know what to check" << endl;
                }
            }
          else if (arg == "check_files")
            {
              argc--;
              argv++;
              if (argc > 1)
                {
                  cmt_string& s = arguments.add ();
                  s = argv[1];
                  argc--;
                  argv++;
                  if (argc > 1)
                    {
                      cmt_string& s = arguments.add ();
                      s = argv[1];

                      m_action = action_check_files;
                    }
                  else
                    {
                      if (!m_quiet) cout << "#CMT> syntax error : reference file missing" << endl;
                    }
                }
              else
                {
                  if (!m_quiet) cout << "#CMT> syntax error : file name missing" << endl;
                }
            }
          else if ((arg == "co") ||
                   (arg == "checkout"))
            {
              // handle all of the command line arguments in a vector
              argc--;
              argv++;
              if (argc > 1)
                {
                  m_action = action_checkout;

                  while (argc > 1)
                    {
                      cmt_string& s = arguments.add ();
                      s = argv[1];
                      argc--;
                      argv++;
                    }
                }
              else
                {
                  if (!m_quiet) cout << "#CMT> syntax error : checkout arguments missing" << endl;
                }
            }
          else if (arg == "cleanup")
            {
              m_action = action_cleanup;
            }
          else if (arg == "config")
            {
              argc--;
              argv++;
              if (argc > 1)
                {
                  cout << "#---------------------------------------------------------" << endl;
                  cout << "# Warning : using 'cmt config ...' to create a package is "
                      "becoming obsolete" << endl;
                  cout << "# Please use 'cmt create ...' instead" << endl;
                  cout << "#---------------------------------------------------------" << endl;

                  m_current_package = argv[1];
                  m_current_version.erase (0);
                  m_current_path.erase (0);

                  argc--;
                  argv++;
                  if (argc > 1)
                    {
                      m_current_version = argv[1];

                      {
                        cmt_string& s = arguments.add ();
                        s = m_current_package;
                      }
                      {
                        cmt_string& s = arguments.add ();
                        s = m_current_version;
                      }

                      argc--;
                      argv++;
                      if (argc > 1)
                        {
                          m_current_path = argv[1];
                          if (m_current_path[0] == '-')
                            {
                              m_current_path.erase (0);
                            }
                        }

                      m_action = action_create;
                    }
                  else
                    {
                      if (!m_quiet) cout << "#CMT> syntax error : create arguments missing" << endl;
                    }
                }
              else
                {
                  m_action = action_config;
                }
            }
          else if (arg == "create")
            {
              argc--;
              argv++;

              if (argc > 1)
                {
                  while (argc > 1)
                    {
                      cmt_string& s = arguments.add ();
                      s = argv[1];
                      argc--;
                      argv++;
                    }

                  m_action = action_create;
                }
              else
                {
                  if (!m_quiet) cout << "#CMT> syntax error : create arguments missing" << endl;
                }
            }
          else if (arg == "cvsbranches")
            {
              argc--;
              argv++;
              if (argc > 1)
                {
                  cmt_string& s = arguments.add ();
                  s = argv[1];
                  argc--;
                  argv++;

                  m_action = action_cvsbranches;
                }
              else
                {
                  if (!m_quiet) cout << "#CMT> syntax error : cvsbranches arguments missing" << endl;
                }
            }
          else if (arg == "cvssubpackages")
            {
              argc--;
              argv++;
              if (argc > 1)
                {
                  cmt_string& s = arguments.add ();
                  s = argv[1];
                  argc--;
                  argv++;

                  m_action = action_cvssubpackages;
                }
              else
                {
                  if (!m_quiet) cout << "#CMT> syntax error : cvssubpackages arguments missing" << endl;
                }
            }
          else if (arg == "cvstags")
            {
              argc--;
              argv++;
              if (argc > 1)
                {
                  while (argc > 1)
                    {
                      cmt_string& s = arguments.add ();
                      s = argv[1];
                      argc--;
                      argv++;
                    }

                  m_action = action_cvstags;
                }
              else
                {
                  if (!m_quiet) cout << "#CMT> syntax error : package name missing" << endl;
                }
            }
          else
            {
              if (!m_quiet) cout << "#CMT> syntax error : bad verb " << arg << endl;
            }
          break;
        case 'e' :
          if (arg == "expand")
            {
              argc--;
              argv++;

              if (argc > 1)
                {
                  arg = argv[1];

                  if (arg == "model")
                    {
                      argc--;
                      argv++;

                      if (argc > 1)
                        {
                          while (argc > 1)
                            {
                              cmt_string& s = arguments.add ();
                              s = argv[1];
                              argc--;
                              argv++;
                            }

                          m_action = action_expand_model;
                        }
                      else
                        {
                          if (!m_quiet) cout << "#CMT> syntax error : model not specified" << endl;
                        }
                    }
                  else
                    {
                      if (!m_quiet) cout << "#CMT> syntax error : bad expand option" << endl;
                    }
                }
              else
                {
                  if (!m_quiet) cout << "#CMT> syntax error : don't know what to expand" << endl;
                }
            }
          else
            {
              if (!m_quiet) cout << "#CMT> syntax error : bad verb " << arg << endl;
            }
          break;
        case 'f' :
          if ((arg == "f") ||
              (arg == "fi") ||
              (arg == "fil") ||
              (arg == "filt") ||
              (arg == "filte") ||
              (arg == "filter"))
            {
              // handle all of the command line arguments in a vector
              argc--;
              argv++;
              while (argc > 1)
                {
                  cmt_string& s = arguments.add ();
                  s = argv[1];
                  argc--;
                  argv++;
                }

              m_action = action_filter;
            }
          else
            {
              if (!m_quiet) cout << "#CMT> syntax error : bad verb " << arg << endl;
            }
          break;
        case 'h' :
          if ((arg == "h") ||
              (arg == "he") ||
              (arg == "hel") ||
              (arg == "help"))
            {
              m_action = action_help;
            }
          else
            {
              if (!m_quiet) cout << "#CMT> syntax error : bad verb " << arg << endl;
            }
          break;
        case 'l' :
          if (arg == "lock")
            {
              argc--;
              argv++;
              if (argc > 1)
                {
                  m_current_package = argv[1];
                  {
                    cmt_string& s = arguments.add ();
                    s = m_current_package;
                  }

                  m_current_version.erase (0);
                  m_current_path.erase (0);

                  argc--;
                  argv++;
                  if (argc > 1)
                    {
                      m_current_version = argv[1];

                      {
                        cmt_string& s = arguments.add ();
                        s = m_current_version;
                      }
                    
                      m_action = action_lock;

                      argc--;
                      argv++;
                      if (argc > 1)
                        {
                          m_current_path = argv[1];
                          if (m_current_path[0] == '-')
                            {
                              m_current_path.erase (0);
                            }
                        }

                      m_current_access = UserMode;
                      (Use::current()).set (m_current_package, 
                                            m_current_version, 
                                            m_current_path);

                    }
                  else
                    {
                      if (!m_quiet) cout << "#CMT> syntax error : version missing" << endl;
                    }
                }
              else
                {
                  m_action = action_lock;
                }
            }
          else
            {
              if (!m_quiet) cout << "#CMT> syntax error : bad verb " << arg << endl;
            }
          break;
        case 'r' :
          if (arg == "remove")
            {
              argc--;
              argv++;

              if (argc > 1)
                {
                  arg = argv[1];

                  if (arg == "library_links")
                    {
                      m_action = action_remove_library_links;
                    }
                  else
                    {
                      m_current_package = argv[1];
                      {
                        cmt_string& s = arguments.add ();
                        s = m_current_package;
                      }
                      
                      m_current_version.erase (0);
                      m_current_path.erase (0);
                      
                      argc--;
                      argv++;
                      if (argc > 1)
                        {
                          m_current_version = argv[1];
                          
                          {
                            cmt_string& s = arguments.add ();
                            s = m_current_version;
                          }
                          
                          argc--;
                          argv++;
                          if (argc > 1)
                            {
                              m_current_path = argv[1];
                              if (m_current_path[0] == '-')
                                {
                                  m_current_path.erase (0);
                                }
                            }
                            
                          m_action = action_remove;
                        }
                      else
                        {
                          if (!m_quiet) cout << "#CMT> syntax error : version missing" << endl;
                        }
                    }
                }
              else
                {
                  if (!m_quiet) cout << "#CMT> syntax error : don't know what to remove" << endl;
                }
            }
          else if (arg == "run")
            {
              argc--;
              argv++;
              if (argc > 1)
                {
                  cmt_string& s = arguments.add ();
                  s = argv[1];

                  m_action = action_run;
                }
              else
                {
                  if (!m_quiet) cout << "#CMT> syntax error : run arguments missing" << endl;
                }
            }
          else if (arg == "run_sequence")
            {
              argc--;
              argv++;
              if (argc > 1)
                {
                  cmt_string& s = arguments.add ();
                  s = argv[1];

                  m_action = action_run_sequence;
                }
              else
                {
                  if (!m_quiet) cout << "#CMT> syntax error : run_sequence arguments missing" << endl;
                }
            }
          else
            {
              if (!m_quiet) cout << "#CMT> syntax error : bad verb " << arg << endl;
            }
          break;
        case 's' :
          if (arg == "setup")
            {
              m_action = action_setup;
            }
          else if ((arg == "s") ||
                   (arg == "sh") ||
                   (arg == "sho") ||
                   (arg == "show"))
            {
              argc--;
              argv++;
              if (argc > 1)
                {
                  arg = argv[1];

                  if (arg == "all_tags")
                    {
                      m_action = action_show_all_tags;
                    }
                  else if (arg == "applied_patterns")
                    {
                      m_action = action_show_applied_patterns;
                    }
                  else if (arg == "author")
                    {
                      m_action = action_show_author;
                    }
                  else if (arg == "branches")
                    {
                      m_action = action_show_branches;
                    }
                  else if (arg == "clients")
                    {
                      argc--;
                      argv++;
                      if (argc > 1)
                        {
                          cmt_string& s = arguments.add ();
                          s = argv[1];
                          m_current_target = argv[1];

                          m_action = action_show_clients;

                          argc--;
                          argv++;
                          if (argc > 1)
                            {
                              cmt_string& s = arguments.add ();
                              s = argv[1];

                              argc--;
                              argv++;
                              if (argc > 1)
                                {
                                  cmt_string& s = arguments.add ();
                                  s = argv[1];
                                }
                            }
                        }
                      else
                        {
                          if (!m_quiet) cout << "#CMT> syntax error : package name missing" << endl;
                        }
                    }
                  else if (arg == "constituent")
                    {
                      argc--;
                      argv++;
                      if (argc > 1)
                        {
                          cmt_string& s = arguments.add ();
                          s = argv[1];
                          m_current_target = argv[1];

                          m_action = action_show_constituent;
                        }
                      else
                        {
                          if (!m_quiet) cout << "#CMT> syntax error : constituent name missing" << endl;
                        }
                    }
                  else if (arg == "constituent_names")
                    {
                      m_action = action_show_constituent_names;
                    }
                  else if (arg == "constituents")
                    {
                      m_action = action_show_constituents;
                    }
                  else if (arg == "fragment")
                    {
                      argc--;
                      argv++;
                      if (argc > 1)
                        {
                          cmt_string& s = arguments.add ();
                          s = argv[1];
                          m_current_target = argv[1];

                          m_action = action_show_fragment;
                        }
                      else
                        {
                          if (!m_quiet) cout << "#CMT> syntax error : fragment name missing" << endl;
                        }
                    }
                  else if (arg == "fragments")
                    {
                      m_action = action_show_fragments;
                    }
                  else if (arg == "groups")
                    {
                      m_action = action_show_groups;
                    }
                  else if (arg == "include_dirs")
                    {
                      m_action = action_show_include_dirs;
                    }
                  else if (arg == "language")
                    {
                      argc--;
                      argv++;
                      if (argc > 1)
                        {
                          cmt_string& s = arguments.add ();
                          s = argv[1];
                          m_current_target = argv[1];

                          m_action = action_show_language;
                        }
                      else
                        {
                          if (!m_quiet) cout << "#CMT> syntax error : language name missing" << endl;
                        }
                    }
                  else if (arg == "languages")
                    {
                      m_action = action_show_languages;
                    }
                  else if (arg == "macro")
                    {
                      argc--;
                      argv++;
                      if (argc > 1)
                        {
                          cmt_string& s = arguments.add ();
                          s = argv[1];
                          m_current_target = argv[1];

                          m_action = action_show_macro;
                        }
                      else
                        {
                          if (!m_quiet) cout << "#CMT> syntax error : macro name missing" << endl;
                        }
                    }
                  else if (arg == "macro_names")
                    {
                      argc--;
                      argv++;
                      if (argc > 1)
                        {
                          cmt_string& s = arguments.add ();
                          s = argv[1];
                        }

                      m_action = action_show_macro_names;
                    }
                  else if (arg == "macro_value")
                    {
                      m_quiet = true;
                      argc--;
                      argv++;
                      if (argc > 1)
                        {
                          cmt_string& s = arguments.add ();
                          s = argv[1];
                          m_current_target = argv[1];

                          m_action = action_show_macro_value;
                        }
                      else
                        {
                          if (!m_quiet) cout << "#CMT> syntax error : macro name missing" << endl;
                        }
                    }
                  else if (arg == "macros")
                    {
                      argc--;
                      argv++;
                      if (argc > 1)
                        {
                          cmt_string& s = arguments.add ();
                          s = argv[1];
                        }

		      m_action = action_show_macros;
                    }
                  else if (arg == "manager")
                    {
                      m_action = action_show_manager;
                    }
                  else if (arg == "packages")
                    {
                      argc--;
                      argv++;
                      if (argc > 1)
                        {
                          cmt_string& s = arguments.add ();
                          s = argv[1];
                          m_current_target = argv[1];
                        }

                      m_action = action_show_packages;
                    }
                  else if (arg == "path")
                    {
                      m_action = action_show_path;
                    }
                  else if (arg == "pattern")
                    {
                      argc--;
                      argv++;
                      if (argc > 1)
                        {
                          cmt_string& s = arguments.add ();
                          s = argv[1];
                          m_current_target = argv[1];

                          m_action = action_show_pattern;
                        }
                      else
                        {
                          if (!m_quiet) cout << "#CMT> syntax error : pattern name missing" << endl;
                        }
                    }
                  else if (arg == "pattern_names")
                    {
                      m_action = action_show_pattern_names;
                    }
                  else if (arg == "patterns")
                    {
                      m_action = action_show_patterns;
                    }
                  else if (arg == "pwd")
                    {
                      m_action = action_show_pwd;
                    }
                  else if (arg == "set_names")
                    {
                      argc--;
                      argv++;
                      if (argc > 1)
                        {
                          cmt_string& s = arguments.add ();
                          s = argv[1];
                        }

                      m_action = action_show_set_names;
                    }
                  else if (arg == "set_value")
                    {
                      m_quiet = true;
                      argc--;
                      argv++;
                      if (argc > 1)
                        {
                          cmt_string& s = arguments.add ();
                          s = argv[1];
                          m_current_target = argv[1];

                          m_action = action_show_set_value;
                        }
                      else
                        {
                          if (!m_quiet) cout << "#CMT> syntax error : set name missing" << endl;
                        }
                    }
                  else if (arg == "set")
                    {
                      argc--;
                      argv++;
                      if (argc > 1)
                        {
                          cmt_string& s = arguments.add ();
                          s = argv[1];
                          m_current_target = argv[1];

                          m_action = action_show_set;
                        }
                      else
                        {
                          if (!m_quiet) cout << "#CMT> syntax error : set name missing" << endl;
                        }
                    }
                  else if (arg == "sets")
                    {
                      argc--;
                      argv++;
                      if (argc > 1)
                        {
                          cmt_string& s = arguments.add ();
                          s = argv[1];
                        }

                      m_action = action_show_sets;
                    }
                  else if (arg == "strategies")
                    {
                      m_action = action_show_strategies;
                    }
                  else if (arg == "tags")
                    {
                      m_action = action_show_tags;
                    }
                  else if ((arg == "u") ||
                           (arg == "us") ||
                           (arg == "use") ||
                           (arg == "uses"))
                    {
                      m_action = action_show_uses;
                    }
                  else if (arg == "version")
                    {
                      m_action = action_show_version;
                    }
                  else if (arg == "versions")
                    {
                      argc--;
                      argv++;
                      if (argc > 1)
                        {
                          cmt_string& s = arguments.add ();
                          s = argv[1];
                          m_current_target = argv[1];

                          m_action = action_show_versions;
                        }
                      else
                        {
                          if (!m_quiet) cout << "#CMT> syntax error : package name missing" << endl;
                        }
                    }
                  else
                    {
                      if (!m_quiet) cout << "#CMT> syntax error : bad show argument" << endl;
                    }
                }
              else
                {
                  if (!m_quiet) cout << "#CMT> syntax error : don't know what to show" << endl;
                }
            }
          else if (arg == "system")
            {
              m_action = action_system;
            }
          else
            {
              if (!m_quiet) cout << "#CMT> syntax error : bad verb " << arg << endl;
            }

          break;
        case 'u' :
          if (arg == "unlock")
            {
              argc--;
              argv++;
              if (argc > 1)
                {
                  m_current_package = argv[1];
                  {
                    cmt_string& s = arguments.add ();
                    s = m_current_package;
                  }

                  m_current_version.erase (0);
                  m_current_path.erase (0);
                                        
                  argc--;
                  argv++;
                  if (argc > 1)
                    {
                      m_current_version = argv[1];

                      {
                        cmt_string& s = arguments.add ();
                        s = m_current_version;
                      }
                                                
                      m_action = action_unlock;

                      argc--;
                      argv++;
                      if (argc > 1)
                        {
                          m_current_path = argv[1];
                          if (m_current_path[0] == '-')
                            {
                              m_current_path.erase (0);
                            }
                        }
                                                
                      m_current_access = UserMode;
                      (Use::current()).set (m_current_package, 
                                            m_current_version, 
                                            m_current_path);

                    }
                  else
                    {
                      if (!m_quiet) cout << "#CMT> syntax error : version missing" << endl;
                    }
                }
              else
                {
                  m_action = action_unlock;
                }
            }
          else
            {
              if (!m_quiet) cout << "#CMT> syntax error : bad verb " << arg << endl;
            }

          break;
        case 'v' :
          if ((arg == "v") ||
              (arg == "ve") ||
              (arg == "ver") ||
              (arg == "vers") ||
              (arg == "versi") ||
              (arg == "versio") ||
              (arg == "version"))
            {
              m_action = action_version;
            }
          else
            {
              if (!m_quiet) cout << "#CMT> syntax error : bad verb " << arg << endl;
            }
          break;
        case '+' :
          if (arg.substr (0, 6) == "+path=")
            {
              arg.erase (0, 6);
              CmtSystem::add_cmt_path (arg, "argument",
                                       m_cmt_path, 
                                       m_cmt_path_pwds, 
                                       m_cmt_path_sources);
            }
          else
            {
              if (!m_quiet) cout << "#CMT> syntax error : bad verb " 
                               << arg << endl;
            }

          break;
        case '-' :
          if (arg == "-n")
            {
              m_simulation = true;
            }
          else if ((arg == "-q") ||
                   (arg == "-qu") ||
                   (arg == "-qui") ||
                   (arg == "-quie") ||
                   (arg == "-quiet"))
            {
              m_quiet = true;
            }
          else if (arg == "-csh")
            {
              mode = Csh;
            }
          else if (arg == "-sh")
            {
              mode = Sh;
            }
          else if (arg == "-bat")
            {
              mode = Bat;
            }
          else if (arg.substr (0, 5) == "-use=")
            {
              arg.erase (0, 5);

              if (m_action != action_create)
                {
                  CmtSystem::cmt_string_vector words;

                  CmtSystem::split (arg, ":", words);

                  m_current_access = UserMode;

                  if (words.size () > 0) m_current_package = words[0];
                  if (words.size () > 1) m_current_version = words[1];
                  if (words.size () > 2) m_current_path    = words[2];
                  (Use::current()).set (m_current_package, 
                                        m_current_version, 
                                        m_current_path);
                }
            }
          else if (arg.substr (0, 6) == "-pack=")
            {
              arg.erase (0, 6);
              if ((m_action != action_create) && (m_current_package != arg))
                {
                  //CmtSystem::cd (m_default_path);

                  m_current_access = UserMode;

                  m_current_package = arg;
                  m_current_version = "";
                  m_current_path    = m_default_path;

                  (Use::current()).set (m_current_package, 
                                        m_current_version, 
                                        m_current_path);
                }
            }
          else if (arg.substr (0, 9) == "-version=")
            {
              arg.erase (0, 9);
              if ((m_action != action_create) && (m_current_version != arg))
                {
                  m_current_access = UserMode;
                  m_current_version = arg;
                  (Use::current()).set (m_current_package, 
                                        m_current_version, 
                                        m_current_path);
                }
            }
          else if (arg.substr (0, 6) == "-path=")
            {
              arg.erase (0, 6);

	      /*
              cerr << "-path=" << arg << 
                " cp=" << m_current_package <<
                " cv=" << m_current_version <<
                " cp=" << m_current_path << endl;
	      */

              if ((m_action != action_create) && (m_current_path != arg))
                {
                  m_current_access = UserMode;
                  m_current_path = arg;
                  (Use::current()).set (m_current_package, 
                                        m_current_version, 
                                        m_current_path);

                  CmtSystem::add_cmt_path (m_current_path, "argument",
                                           m_cmt_path, 
                                           m_cmt_path_pwds, 
                                           m_cmt_path_sources);
                }
            }
          else if (arg.substr (0, 3) == "-f=")
            {
              arg.substr (3, extra_file);
            }
          else if (arg.substr (0, 3) == "-e=")
            {
              cout << "extra statement = " << arg << endl;
              arg.substr (3, extra_line);
            }
          else if (arg.substr (0, 6) == "-home=")
            {
              arg.erase (0, 6);
	      if (CmtSystem::test_directory (arg))
		{
		  m_cmt_home = arg;
		}
            }
          else if (arg.substr (0, 5) == "-tag=")
            {
                /*
                  Here we are going to change the complete tag set
                */

              Tag* tag;
	      CmtSystem::cmt_string_vector words;
              
                /// First forget about all existing tags
              Tag::clear_all ();
              Cmt::m_extra_tags = "";

                /// Then restore CMTSITE
              configure_site_tag (0);
	      configure_uname_tag ();
	      configure_hosttype_tag ();
              configure_config_tag ();

              arg.erase (0, 5);

	      CmtSystem::split (arg, " \t,", words);

	      for (int i = 0; i < words.size (); i++)
		{
		  const cmt_string& a = words[i];

                  cmt_string s = a;
                  s += ",";

		  if (i == 0)
		    {
		      m_current_tag = a;

                      if (CmtSystem::testenv ("TAGDEBUG")) cerr 
                          << "parse_argument(tag_add)> current_tag=" << m_current_tag << endl;
		    }

                  if (Cmt::m_extra_tags.find (s) == cmt_string::npos)
                    {
                      //if (!m_quiet) cerr << "  a=[" << a << "]" << endl;
                      
                        /// Then restore uname if the specified tag is CMTCONFIG
                      if (a == CmtSystem::get_cmt_config ())
                        {
                          configure_uname_tag ();
                        }
                      
                      tag = Tag::add (a, PriorityArgument, "arguments", 0);
                      
                      tag->mark ();

                      Cmt::m_extra_tags += a;
                      Cmt::m_extra_tags += ",";
                    }
                }
            }
          else if (arg.substr (0, 9) == "-tag_add=")
            {
              Tag* tag;
	      CmtSystem::cmt_string_vector words;
              
              arg.erase (0, 9);

              //if (!m_quiet) cerr << "-tag_add=" << arg << endl;

	      CmtSystem::split (arg, " \t,", words);

	      for (int i = 0; i < words.size (); i++)
		{
		  const cmt_string& a = words[i];

                  cmt_string s = a;
                  s += ",";

                  if (Cmt::m_extra_tags.find (s) == cmt_string::npos)
                    {
                        //if (!m_quiet) cerr << "  a=[" << a << "]" << endl;

                        /// Then restore uname if the specified tag is CMTCONFIG
                      if (a == CmtSystem::get_cmt_config ())
                        {
                          configure_uname_tag ();
                        }
                      
                      tag = Tag::add (a, PriorityUserTag, "arguments", 0);
                      
                      tag->mark ();

                      Cmt::m_extra_tags += a;
                      Cmt::m_extra_tags += ",";
                    }
                }
            }
          else if (arg.substr (0, 12) == "-tag_remove=")
            {
              Tag::TagPtrVector tags = Tag::tags ();
              int i;
              Tag* tag;

	      /*
              for (i = 0; i < tags.size (); i++)
                {
                  tag = tags[i];
                  if ((tag != 0) &&
                      (tag->selected))
                    {
                        if (!m_quiet) cerr << "  original tag_list=" << tag->name << tag->priority << endl;
                    }
                }
	      */

	      CmtSystem::cmt_string_vector words;

              arg.erase (0, 12);

	      //if (!m_quiet) cerr << "-arg_remove=" << arg << endl;

	      CmtSystem::split (arg, " \t,", words);

                //
                // Now erase all entries in the old list that match
                // the specified tags 
                //

	      for (i = 0; i < words.size (); i++)
		{
		  const cmt_string& a = words[i];

                  cmt_string s = a;
                  s += ",";

                  int pos;

                  pos = Cmt::m_extra_tags.find (s);

                  if (pos != cmt_string::npos)
                    {
                      Cmt::m_extra_tags.erase (pos, s.size ());
                    }

		  //if (!m_quiet) cerr << "  tag_list=[" << tag_list << "]" << endl;
		}

                //
                // Now reinject the purged list of tags into the database
                // exactly as when using -tag=<tag-list>
                //

                /// First forget about all existing tags
              Tag::unmark_all ();

                /// Then restore CMTSITE
	      configure_site_tag (0);
	      configure_uname_tag ();
	      configure_hosttype_tag ();
              
	      CmtSystem::split (Cmt::m_extra_tags, " \t,", words);

	      for (i = 0; i < words.size (); i++)
		{
		  const cmt_string& a = words[i];

		  //fprintf (stderr, "  a=[%s]\n", a.c_str ());

		  /// Then restore uname if the specified tag is CMTCONFIG
		  if (a == CmtSystem::get_cmt_config ())
		    {
		      configure_uname_tag ();
		    }

		  if (i == 0)
		    {
		      m_current_tag = a;

                      //if (!m_quiet) cerr << "parse_argument(tag_remove)> current_tag=" 
                        //<< m_current_tag << endl;

		      tag = Tag::add (a, PriorityTag, "restore configuration", 0);
		    }
		  else
		    {
		      tag = Tag::add (a, PriorityUserTag, "restore configuration", 0);
		    }

		  tag->mark ();
		}
            }
          else if (arg.substr (0, 14) == "-user_context=")
            {
              arg.erase (0, 14);
	      if (CmtSystem::test_directory (arg))
		{
		  m_cmt_user_context = arg;
		}
            }
          else
            {
              if (!m_quiet) cout << "#CMT> syntax error : bad verb " << arg << endl;
            }

          break;
        default:
          if (!m_quiet) cout << "#CMT> syntax error : bad command parameter " << arg << endl;
          break;
        }

      argc--;
      argv++;
    }
}

/**
 *  Parse the input file, rejecting comments and
 * rebuilding complete lines (from sections separated by
 *  \ characters.
 *
 *  Each reformatted line is parsed by filter_line
 */
void Cmt::parse_requirements (const cmt_string& file_name, Use* use)
{
  cmt_string actual_file_name = file_name;
  cmt_string text;

  CmtError::clear ();

  if (use == 0) use = &(Use::current ());

  if (!CmtSystem::test_file (actual_file_name))
    {
      actual_file_name = "..";
      actual_file_name += CmtSystem::file_separator ();
      actual_file_name += "cmt";
      actual_file_name += CmtSystem::file_separator ();
      actual_file_name += file_name;

      if (!CmtSystem::test_file (actual_file_name))
        {
          actual_file_name = "..";
          actual_file_name += CmtSystem::file_separator ();
          actual_file_name += "mgr";
          actual_file_name += CmtSystem::file_separator ();
          actual_file_name += file_name;

          if (!CmtSystem::test_file (actual_file_name))
            {
                /*
              cmt_string text;

              text = "Package ";
              text += use->package;
              text += " version ";
              text += use->specified_version;
              text += " path ";
              text += use->specified_path;
              text += " file ";
              text += actual_file_name;

              CmtError::set (CmtError::file_access_error, text);
                */

              return;
            }
        }
    }

  text.read (actual_file_name);

    /**
     *
     *    We have to preserve m_current_access since it reflects whether
     *   the current cmt action is run in the context of the current package.
     *   (the opposite is when the cmt command specifies the current package
     *    in its arguments -use=... therefore the pwd is NOT the directory
     *    of the current package)
     *
     *   m_current_access is Developer when pwd =  current
     *                       User      when pwd != current
     *
     *    Therefore, as soon as we reach a used package, this must be switched to User
     *
     *   On the other hand, Cmt::scope reflects the status of the public/private 
     *  statements. By default, we are in public context when entering a new requirements
     *  file.
     *
     */

  AccessMode saved_current_access;
  ScopeType saved_scope;

  saved_current_access = Cmt::m_current_access;
  saved_scope          = Cmt::m_scope;

  if (use != &(Use::current ()))
    {
      Cmt::m_current_access = UserMode;
    }
  else
    {
      Cmt::m_current_access = DeveloperMode;
    }

  Cmt::m_scope = ScopePublic;

  parse_requirements_text (text, actual_file_name, use);

    //Pattern::apply_all_globals (use);

  Cmt::m_current_access = saved_current_access;
  Cmt::m_scope          = saved_scope;
}

/**
 *  Apply the basic parser to one single line :
 *
 *   o Append to global text if previous back_slash
 *   o Split into words
 *   o Apply the generic Select operator
 */
void Cmt::parse_requirements_line (const cmt_string& line,
                                   Use* use,
                                   const cmt_string& file_name,
                                   int line_number)
{
  int length;
  int nl;
  int back_slash;
  cmt_string temp_line = line;

  if (temp_line.size () == 0) return;
  if (temp_line[0] == '#') return;

  nl = temp_line.find_last_of ('\n');
  if (nl != cmt_string::npos) temp_line.erase (nl);

  length = temp_line.size ();
  if (length == 0) return;

  //
  // We scan the line for handling backslashes.
  //
  // o Really terminating backslashes (ie those only followed by spaces/tabs
  // mean continued line
  //
  //

  bool finished = true;

  length = temp_line.size ();

  back_slash = temp_line.find_last_of ('\\');

  if (back_slash != cmt_string::npos)
    {
      //
      // This is the last backslash
      // check if there are only space chars after it
      //
      
      bool at_end = true;

      for (int i = (back_slash + 1); i < length; i++)
        {
          char c = temp_line[i];
          if ((c != ' ') && (c != '\t'))
            {
              at_end = false;
              break;
            }
        }

      if (at_end)
        {
          temp_line.erase (back_slash);
          finished = false;
        }
      else
        {
          // This was not a trailing backslash.
          finished = true;
        }
    }

  m_filtered_text += temp_line;

  if (!finished)
    {
      // We still need to accumulate forthcoming lines
      // before parsing the resulting text.
      return;
    }

  /*
    Here a full line (possibly accumulating several lines
    ended by backslashes) is parsed :
    
    o Special characters are filtered now :
    
    <cmt:tab/>  \t
    <cmt:cr/>   \r
    <cmt:lf/>   \n
    
    o Split into words (a word is a string not containing
    spaces or enclosed in quotes)

    o Parse the word array (function Select)

  */

  m_filtered_text.replace_all ("<cmt:tab/>", "\t");
  m_filtered_text.replace_all ("<cmt:cr/>",  "\r");
  m_filtered_text.replace_all ("<cmt:lf/>",  "\n");

  if (m_debug)
    {
      cout << "parse_requirements_line [" << m_filtered_text << "]" << endl;
    }
  
  static CmtSystem::cmt_string_vector words;
  
  CmtSystem::split (m_filtered_text, " \t", words);
  
  if (words.size () != 0)
    {
      select (words, use, file_name, line_number);
    }
  
  m_filtered_text.erase (0);
}

/**
 *  Parse a text, rejecting comments and
 * rebuilding complete lines (from sections separated by
 *  \ characters.
 *
 *  Each reformatted line is parsed by filter_line
 */
void Cmt::parse_requirements_text (const cmt_string& text,
                                   const cmt_string& file_name,
                                   Use* use)
{
  cmt_string line;
  int pos;
  int max_pos;
  int line_number = 1;

  if (use == 0) use = &(Use::current ());

  m_filtered_text.erase (0);

  pos = 0;
  max_pos = text.size ();

  for (pos = 0; pos < max_pos;)
    {
      int cr = text.find (pos, "\r\n");
      int nl = text.find (pos, '\n');
      int first = nl;
      int length = 1;

      if (cr != cmt_string::npos)
        {
          if (nl == cmt_string::npos)
            {
              first = cr;
              length = 2;
            }
          else
            {
              first = (nl < cr) ? nl : cr;
              length = (nl < cr) ? 1 : 2;
            }
        }

      if (first == cmt_string::npos)
        {
          text.substr (pos, line);
          pos = max_pos;
        }
      else if (first > pos)
        {
          text.substr (pos, first - pos, line);
          pos = first + length;
        }
      else
        {
          line.erase (0);
          pos += length;
        }

      parse_requirements_line (line, use, file_name, line_number);

      if ((m_action == action_check_configuration) && CmtError::has_pending_error ())
        {
          break;
        }

      line_number++;
    }
}

//----------------------------------------------------------
int Cmt::parser (const cmt_string& command_line)
{
  CmtSystem::cmt_string_vector v;

  CmtSystem::split (command_line, " \t", v);

  int argc = v.size ();

  char** argv = (char**) malloc ((argc + 1) * sizeof (char*));

  int i;
  for (i = 0; i < argc; i++)
    {
      argv[i] = (char*) v[i].c_str ();
    }
  argv[argc] = 0;

  int status = parser (argc, argv);

  free (argv);

  return (status);
}

//----------------------------------------------------------
int Cmt::parser (int argc, char* argv[])
{
  PrintMode mode = Csh;
  CmtSystem::cmt_string_vector arguments;
  cmt_string extra_line;
  cmt_string extra_file;

  if (argc <= 1)
    {
      do_help ();
      exit (0);
    }

  clear ();
  configure ();

  CmtError::clear ();

  /*
    Set private if positioned inside the package
    (which is detected since we were able to retreive the
    Version, Package and Path)
  */

  if ((m_current_path.size () == 0) ||
      (m_current_package.size () == 0) ||
      (m_current_version.size () == 0))
    {
      m_current_access = UserMode;
    }
  else
    {
      m_current_access = DeveloperMode;
    }

  parse_arguments (argc, argv, arguments,
                   extra_line, extra_file, mode);

  if (m_configure_error != "")
    {
      if (!m_quiet) cout << "# CMT>" << m_configure_error << endl;
    }

  if (CmtError::has_pending_error ())
    {
      int code = CmtError::get_last_error_code ();
      if (!m_quiet) CmtError::print ();
      clear ();

      return (code);
    }

  if (m_debug)
    {
      cout << "After parse_argument> pack=" << m_current_package
           << " m_current_tag=" << m_current_tag
           << endl;
    }

  /*
    Now actual requirements analysis can take place.

    Extra lines or files are analysed first.
  */

  if (strlen (extra_file.c_str ()) > 0) parse_requirements (extra_file, 0);
  if (strlen (extra_line.c_str ()) > 0) parse_requirements_line (extra_line, 0);

  //
  //  For some of the actions, the CMT package must be automatically
  //  included
  //

  if (m_debug) cerr << "parser1> current_tag=" << m_current_tag << endl;

  switch (m_action)
    {
      // case action_none :
    case action_awk :
    case action_broadcast :
    case action_build_constituent_makefile :
    case action_build_constituents_makefile :
    case action_build_dependencies :
    case action_build_library_links :
    case action_build_make_setup :
    case action_build_msdev :
    case action_build_os9_makefile :
      // case action_build_prototype :
    case action_build_readme :
    case action_build_tag_makefile :
      // case action_build_temporary_name :
    case action_build_triggers :
    case action_build_windefs :
    case action_check_configuration :
      // case action_check_files :
      // case action_check_version :
    case action_checkout :
    case action_cleanup :
    case action_config :
    case action_create :
      // case action_cvsbranches :
      // case action_cvssubpackages :
      // case action_cvstags :
    case action_expand_model :
    case action_filter :
      // case action_help :
    case action_load :
    case action_lock :
    case action_remove :
    case action_remove_library_links :
    case action_run :
    case action_run_sequence :
    case action_setup :
    case action_show_all_tags :
    case action_show_applied_patterns :
      // case action_show_author :
      // case action_show_branches :
      // case action_show_clients :
      // case action_show_constituent :
      // case action_show_constituent_names :
      // case action_show_constituents :
    case action_show_fragment :
    case action_show_fragments :
    case action_show_groups :
    case action_show_include_dirs :
    case action_show_language :
    case action_show_languages :
    case action_show_macro :
    case action_show_macro_names :
    case action_show_macro_value :
    case action_show_macros :
      // case action_show_manager :
      // case action_show_packages :
    case action_show_path :
    case action_show_pattern :
    case action_show_pattern_names :
    case action_show_patterns :
      // case action_show_pwd :
    case action_show_set :
    case action_show_set_names :
    case action_show_set_value :
    case action_show_sets :
    case action_show_strategies :
    case action_show_tags :
    case action_show_uses :
    case action_show_version :
      // case action_show_versions :
      // case action_system :
    case action_unlock :
    case action_version :
      use_cmt ();
        //
        // Now parse the requirements file stored in ${CMTHOME}
        //
      
      use_home_requirements ();

      break;
    default:
      break;
    }

  if (m_debug) cerr << "parser2> current_tag=" << m_current_tag << endl;

  //
  // Setting up recursive actions
  //

  switch (m_action)
    {
      // case action_none :
    case action_awk :
    case action_broadcast :
    case action_build_constituent_makefile :
    case action_build_constituents_makefile :
    case action_build_dependencies :
    case action_build_library_links :
    case action_build_make_setup :
    case action_build_msdev :
    case action_build_os9_makefile :
      // case action_build_prototype :
    case action_build_readme :
    case action_build_tag_makefile :
      // case action_build_temporary_name :
    case action_build_triggers :
    case action_build_windefs :
    case action_check_configuration :
      // case action_check_files :
      // case action_check_version :
      // case action_checkout :
    case action_cleanup :
    case action_config :
      // case action_create :
      // case action_cvsbranches :
      // case action_cvssubpackages :
      // case action_cvstags :
    case action_expand_model :
    case action_filter :
      // case action_help :
    case action_load :
      // case action_lock :
      // case action_remove :
    case action_remove_library_links :
      // case action_run :
    case action_run_sequence :
    case action_setup :
    case action_show_all_tags :
    case action_show_applied_patterns :
      // case action_show_author :
      // case action_show_branches :
      // case action_show_clients :
    case action_show_constituent :
    case action_show_constituent_names :
    case action_show_constituents :
    case action_show_fragment :
    case action_show_fragments :
    case action_show_groups :
    case action_show_include_dirs :
    case action_show_language :
    case action_show_languages :
    case action_show_macro :
    case action_show_macro_names :
    case action_show_macro_value :
    case action_show_macros :
      // case action_show_manager :
      // case action_show_packages :
    case action_show_path :
    case action_show_pattern :
    case action_show_pattern_names :
    case action_show_patterns :
      // case action_show_pwd :
    case action_show_set :
    case action_show_set_names :
    case action_show_set_value :
    case action_show_sets :
    case action_show_strategies :
    case action_show_tags :
    case action_show_uses :
      // case action_show_version :
      // case action_show_versions :
      // case action_system :
      // case action_unlock :
      // case action_version :
      m_recursive = true;
      break;
    default:
      m_recursive = false;
      break;
    }

  //
  //  Actions for which the context of the package is checked,
  //  and the requirements file is analysed.
  //

  switch (m_action)
    {
    case action_none :
    case action_awk :
    case action_broadcast :
    case action_build_constituent_makefile :
    case action_build_constituents_makefile :
    case action_build_dependencies :
    case action_build_library_links :
    case action_build_make_setup :
    case action_build_msdev :
    case action_build_os9_makefile :
      // case action_build_prototype :
    case action_build_readme :
    case action_build_tag_makefile :
      // case action_build_temporary_name :
    case action_build_triggers :
    case action_build_windefs :
    case action_check_configuration :
      // case action_check_files :
      // case action_check_version :
      // case action_checkout :
    case action_cleanup :
    case action_config :
      // case action_create :
      // case action_cvsbranches :
      // case action_cvssubpackages :
      // case action_cvstags :
    case action_expand_model :
    case action_filter :
    case action_help :
    case action_load :
    case action_lock :
      // case action_remove :
    case action_remove_library_links :
    case action_run :
      // case action_run_sequence :
    case action_setup :
    case action_show_all_tags :
    case action_show_applied_patterns :
    case action_show_author :
    case action_show_branches :
      // case action_show_clients :
    case action_show_constituent :
    case action_show_constituent_names :
    case action_show_constituents :
    case action_show_fragment :
    case action_show_fragments :
    case action_show_groups :
    case action_show_include_dirs :
    case action_show_language :
    case action_show_languages :
    case action_show_macro :
    case action_show_macro_names :
    case action_show_macro_value :
    case action_show_macros :
    case action_show_manager :
      // case action_show_packages :
    case action_show_path :
    case action_show_pattern :
    case action_show_pattern_names :
    case action_show_patterns :
    case action_show_pwd :
    case action_show_set :
    case action_show_set_names :
    case action_show_set_value :
    case action_show_sets :
    case action_show_strategies :
    case action_show_tags :
    case action_show_uses :
    case action_show_version :
      // case action_show_versions :
      // case action_system :
    case action_unlock :
      // case action_version :
      reach_current_package ();
      use_user_context_requirements ();
      break;
    default:
      break;
    }

  if (m_debug) cerr << "parser3> current_tag=" << m_current_tag << endl;

  //
  // Perform some actions even if there is an error
  //

  if (CmtError::has_pending_error ())
    {
      int code = CmtError::get_last_error_code ();
      if (!m_quiet) CmtError::print ();

      switch (m_action)
        {
          // case action_none :
          // case action_awk :
          // case action_broadcast :
        case action_build_constituent_makefile :
        case action_build_constituents_makefile :
        case action_build_dependencies :
        case action_build_library_links :
        case action_build_make_setup :
        case action_build_msdev :
        case action_build_os9_makefile :
        case action_build_prototype :
        case action_build_readme :
        case action_build_tag_makefile :
          // case action_build_temporary_name :
        case action_build_triggers :
        case action_build_windefs :
        case action_check_configuration :
          // case action_check_files :
          // case action_check_version :
          // case action_checkout :
        case action_cleanup :
          // case action_config :
          // case action_create :
          // case action_cvsbranches :
          // case action_cvssubpackages :
          // case action_cvstags :
          // case action_expand_model :
          // case action_filter :
          // case action_help :
        case action_load :
        case action_lock :
        case action_remove :
        case action_remove_library_links :
          // case action_run :
        case action_run_sequence :
        case action_setup :
          // case action_show_all_tags :
          // case action_show_applied_patterns :
          // case action_show_author :
          // case action_show_branches :
          // case action_show_clients :
          // case action_show_constituent :
          // case action_show_constituent_names :
          // case action_show_constituents :
          // case action_show_fragment :
          // case action_show_fragments :
          // case action_show_groups :
          // case action_show_include_dirs :
          // case action_show_language :
          // case action_show_languages :
          // case action_show_macro :
          // case action_show_macro_names :
          // case action_show_macro_value :
          // case action_show_macros :
          // case action_show_manager :
          // case action_show_packages :
          // case action_show_path :
          // case action_show_pattern :
          // case action_show_pattern_names :
          // case action_show_patterns :
          // case action_show_pwd :
          // case action_show_set :
          // case action_show_set_names :
          // case action_show_set_value :
          // case action_show_sets :
          // case action_show_strategies :
          // case action_show_tags :
          // case action_show_uses :
          // case action_show_version :
          // case action_show_versions :
          // case action_system :
        case action_unlock :
          // case action_version :
          clear ();
          return (code);
        default:
          CmtError::clear ();
          break;
        }
    }

  //
  // Perform actions
  //

  switch (m_action)
    {
    case action_none :
      CmtError::set (CmtError::syntax_error, "ParseArguments> ");
      break;
    case action_awk :
      do_awk (arguments);
      break;
    case action_broadcast :
      do_broadcast (arguments, argc, argv);
      break;
    case action_build_constituent_makefile :
      do_build_constituent_makefile (arguments, argc, argv);
      break;
    case action_build_constituents_makefile :
      do_build_constituents_makefile (arguments, argc, argv);
      break;
    case action_build_dependencies :
      do_build_dependencies (arguments, argc, argv);
      break;
    case action_build_library_links :
      do_build_library_links ();
      break;
    case action_build_make_setup :
      do_build_make_setup ();
      break;
    case action_build_msdev :
      do_build_msdev (arguments);
      break;
    case action_build_os9_makefile :
      do_build_os9_makefile (arguments);
      break;
    case action_build_prototype :
      do_build_prototype (arguments);
      break;
    case action_build_readme :
      do_build_readme (arguments);
      break;
    case action_build_tag_makefile :
      do_build_tag_makefile ();
      break;
    case action_build_temporary_name :
      do_build_temporary_name ();
      break;
    case action_build_triggers :
      do_build_triggers (arguments);
      break;
    case action_build_windefs :
      do_build_windefs (arguments);
      break;
    case action_check_configuration :
      do_check_configuration ();
      break;
    case action_check_files :
      do_check_files (arguments);
      break;
    case action_check_version :
      do_check_version (arguments);
      break;
    case action_checkout :
      do_checkout (arguments);
      break;
    case action_cleanup :
      do_cleanup (mode);
      break;
    case action_config :
      do_config ();
      break;
    case action_create :
      do_create (arguments);
      break;
    case action_cvsbranches :
      do_cvsbranches (arguments);
      break;
    case action_cvssubpackages :
      do_cvssubpackages (arguments);
      break;
    case action_cvstags :
      do_cvstags (arguments);
      break;
    case action_expand_model :
      do_expand_model (arguments);
      break;
    case action_filter :
      do_filter (arguments);
      break;
    case action_help :
      do_help ();
      break;
    case action_load :
      cout << "#CMT> action not implemented" << endl;
      break;
    case action_lock :
      do_lock (m_current_package, m_current_version, m_current_path);
      break;
    case action_remove :
      do_remove (m_current_package, m_current_version, m_current_path);
      break;
    case action_remove_library_links :
      do_remove_library_links ();
      break;
    case action_run :
      do_run (arguments);
      break;
    case action_run_sequence :
      do_run_sequence (arguments);
      break;
    case action_setup :
      do_setup (mode);
      break;
    case action_show_all_tags :
      do_show_all_tags ();
      break;
    case action_show_applied_patterns :
      do_show_applied_patterns ();
      break;
    case action_show_author :
      do_show_author ();
      break;
    case action_show_branches :
      do_show_branches (mode);
      break;
    case action_show_clients :
      do_show_clients (arguments);
      break;
    case action_show_constituent :
      do_show_constituent (arguments);
      break;
    case action_show_constituent_names :
      do_show_constituent_names ();
      break;
    case action_show_constituents :
      do_show_constituents ();
      break;
    case action_show_fragment :
      do_show_fragment (arguments);
      break;
    case action_show_fragments :
      do_show_fragments ();
      break;
    case action_show_groups :
      do_show_groups ();
      break;
    case action_show_include_dirs :
      do_show_include_dirs ();
      break;
    case action_show_language :
      do_show_language (arguments);
      break;
    case action_show_languages :
      do_show_languages ();
      break;
    case action_show_macro :
      do_show_macro (arguments, mode);
      break;
    case action_show_macro_names :
      do_show_macro_names (arguments, mode);
      break;
    case action_show_macro_value :
      do_show_macro_value (arguments, mode);
      break;
    case action_show_macros :
      do_show_macros (arguments, mode);
      break;
    case action_show_manager :
      do_show_manager ();
      break;
    case action_show_packages :
      do_show_packages (arguments);
      break;
    case action_show_path :
      do_show_path ();
      break;
    case action_show_pattern :
      do_show_pattern (arguments);
      break;
    case action_show_pattern_names :
      do_show_pattern_names ();
      break;
    case action_show_patterns :
      do_show_patterns ();
      break;
    case action_show_pwd :
      do_show_pwd ();
      break;
    case action_show_set :
      do_show_set (arguments, mode);
      break;
    case action_show_set_names :
      do_show_set_names (arguments, mode);
      break;
    case action_show_set_value :
      do_show_set_value (arguments, mode);
      break;
    case action_show_sets :
      do_show_sets (arguments, mode);
      break;
    case action_show_strategies :
      do_show_strategies ();
      break;
    case action_show_tags :
      do_show_tags ();
      break;
    case action_show_uses :
      do_show_uses ();
      break;
    case action_show_version :
      do_show_version ();
      break;
    case action_show_versions :
      do_show_versions (arguments);
      break;
    case action_system :
      do_show_system ();
      break;
    case action_unlock :
      do_unlock (m_current_package, m_current_version, m_current_path);
      break;
    case action_version :
      do_version ();
      break;
    default:
      CmtError::set (CmtError::syntax_error, "ParseArguments>");
      break;
    }

  if (CmtError::has_pending_error ())
    {
      int code = CmtError::get_last_error_code ();
      if (!m_quiet) CmtError::print ();
      clear ();
      return (code);
    }
  else
    {
      clear ();
      return (0);
    }
}

//----------------------------------------------------------
/**
 * Format as one single line a set of 'setenv' statements
 * joined with semi-colons to form one shell command.
 */
void Cmt::print (PrintMode mode)
{
  Use::UsePtrVector& Uses = Use::uses ();

  cmt_string tag;

  set_standard_macros ();

    //cerr << "# current_tag=" << m_current_tag << endl;
    //cerr << "# current_config=" << m_current_config << endl;

  if (m_current_tag == "")
    {
      if (mode == Bat) tag = "%CMTCONFIG%";
      else tag = "${CMTCONFIG}";
    }
  else
    {
      tag = m_current_tag;
    }

  if (m_current_access == DeveloperMode)
    {
      m_scope = ScopePrivate;
    }
  else
    {
      m_scope = ScopePublic;
    }

    //
    //  Now check if all extra tags are still valid. Some of them
    //  may be discarded du to some conflict with highest priority
    //  tags, or with exclude statements
    //

  {
    CmtSystem::cmt_string_vector words;
      
    cmt_string tags;

    tags = Cmt::m_extra_tags;
      
    CmtSystem::split (tags, " \t,", words);

    Cmt::m_extra_tags = "";
      
    for (int i = 0; i < words.size (); i++)
      {
        Tag* tag;
        const cmt_string& a = words[i];

        tag = Tag::find (a);

        if ((tag != 0) && (tag->is_selected ()))
          {
            Cmt::m_extra_tags += a;
            Cmt::m_extra_tags += ",";
          }
      }
  }

  if (Uses.size () > 0)
    {
      int number;

      for (number = 0; number < Uses.size (); number++)
        {
          Use& use = *(Uses[number]);

          if (use.discarded) continue;

          print_context (use, mode, tag);
        }
    }

  print_context (Use::current (), mode, tag);

  Symbol::all_print (mode);
  // Script::all_print (mode);

  cout << endl;
}

//----------------------------------------------------------
void Cmt::print_clean (PrintMode mode)
{
  Use::UsePtrVector& Uses = Use::uses ();

  set_standard_macros ();

  Script::all_print_clean (mode);
  Symbol::all_print_clean (mode);

  switch (mode)
    {
    case Csh :
      if (m_current_package != "CMT")
        {
          cout << "unsetenv " << m_current_prefix << "ROOT" << endl;
          cout << "unsetenv " << m_current_prefix << "CONFIG" << endl;
        }
      break;
    case Sh :
      if (m_current_package != "CMT")
        {
          cout << "unset " << m_current_prefix << "ROOT" << endl;
          cout << "unset " << m_current_prefix << "CONFIG" << endl;
        }
      break;
    case Bat :
      if (m_current_package != "CMT")
        {
          cout << "set " << m_current_prefix << "ROOT=" << endl;
          cout << "set " << m_current_prefix << "CONFIG=" << endl;
        }
      break;
    }

  if (Uses.size () > 0)
    {
      int number;

      for (number = 0; number < Uses.size (); number++)
        {
          Use* use = Uses[number];

          if (use->package == "CMT") continue;
          if (use->package == "methods") continue;
          if (use->discarded) continue;

          switch (mode)
            {
            case Csh :
              cout << "unsetenv " << use->prefix << "ROOT" << endl;
              cout << "unsetenv " << use->prefix << "CONFIG" << endl;
              break;
            case Sh :
              cout << "unset " << use->prefix << "ROOT" << endl;
              cout << "unset " << use->prefix << "CONFIG" << endl;
              break;
            case Bat :
              cout << "set " << use->prefix << "ROOT=" << endl;
              cout << "set " << use->prefix << "CONFIG" << endl;
              break;
            }
        }
    }

  switch (mode)
    {
    case Csh :
      cout << "unsetenv CMTEXTRATAGS" << endl;
      break;
    case Sh :
      cout << "unset CMTEXTRATAGS" << endl;
      break;
    case Bat :
      cout << "set CMTEXTRATAGS=" << endl;
      break;
    }

  cout << endl;
}

//----------------------------------------------------------
void Cmt::print_context (Use& use, PrintMode mode, const cmt_string& tag)
{
  if (use.package == "cmt_standalone") return;

  cmt_string fs = CmtSystem::file_separator ();

  use.real_path.replace_all (CmtSystem::file_separator (), fs);

  cmt_string system = CmtSystem::get_cmt_config ();

  switch (mode)
    {
    case Csh :
      cout << "setenv " << use.prefix << "ROOT \"" <<
        use.real_path << fs <<
        use.package << fs <<
        use.version << "\"" << endl;
        
      if (use.package == "CMT")
        {
            //cout << "setenv CMTCONFIG `${CMTROOT}/mgr/cmt system`; " << endl;
          cout << "setenv CMTCONFIG " << system << endl;
          //cout << "setenv CMTEXTRATAGS " << Cmt::m_extra_tags << endl;
        }
      else
        {
          cout << "setenv " << use.prefix << "CONFIG \"" << tag << "\"" << endl;
        }
        
      break;
    case Sh :
      cout << use.prefix << "ROOT=\"" <<
        use.real_path << fs <<
        use.package << fs <<
        use.version << "\"; export " <<
        use.prefix << "ROOT" << endl;
        
      if (use.package == "CMT")
        {
          //cout << "CMTCONFIG=`${CMTROOT}/mgr/cmt system`; export CMTCONFIG; ";
          cout << "CMTCONFIG=" << system << "; export CMTCONFIG" << endl;
          //cout << "CMTEXTRATAGS=" << Cmt::m_extra_tags << "; export CMTEXTRATAGS" << endl;
        }
      else
        {
          cout << use.prefix << "CONFIG=\"" <<
            tag << "\"; export " <<
            use.prefix << "CONFIG" << endl;
        }
        
      break;
    case Bat :
      cout << "set " << use.prefix << "ROOT=" <<
        use.real_path << fs <<
        use.package << fs <<
        use.version << endl;
        
      if (use.package == "CMT")
        {
          //cout << "set CMTCONFIG=VisualC" << endl;
          cout << "set CMTCONFIG=" << system << endl;
          //cout << "set CMTEXTRATAGS=" << Cmt::m_extra_tags << endl;
        }
      else
        {
          cout << "set " << use.prefix << "CONFIG=" << tag << endl;
        }
        
      break;
    }
}

/**
 *  Format a set of make macro definitions (one per line)
 * Each macro value is provided enclosed in single quotes
 *
 *  Take the macro values from the macro statements found
 * in recursively read requirements files.
 */
void Cmt::print_macros (PrintMode mode, const cmt_string& pattern)
{
  int number;

  set_standard_macros ();

  cmt_regexp expression (pattern);

  bool has_pattern = (pattern != "");

  for (number = 0; number < Symbol::symbol_number (); number++)
    {
      Symbol& symbol = Symbol::symbol (number);

      if (has_pattern)
	{
	  if (!expression.match (symbol.name)) continue;
	}

      if (m_action == action_show_macros)
        {
          // Only keep macros.
          if ((symbol.command == CommandSet) ||
              (symbol.command == CommandSetAppend) ||
              (symbol.command == CommandSetPrepend) ||
              (symbol.command == CommandSetRemove) ||
              (symbol.command == CommandAlias) ||
              (symbol.command == CommandPath) ||
              (symbol.command == CommandPathAppend) ||
              (symbol.command == CommandPathPrepend) ||
              (symbol.command == CommandPathRemove)) continue;
        }
      else if (m_action == action_show_sets)
        {
          // Exclude macros.
          if ((symbol.command == CommandMacro) ||
              (symbol.command == CommandMacroAppend) ||
              (symbol.command == CommandMacroPrepend) ||
              (symbol.command == CommandMacroRemove) ||
              (symbol.command == CommandMacroRemoveAll)) continue;
        }
      else if (m_action == action_build_tag_makefile)
        {
          // Exclude scripts.
          if ((symbol.command == CommandSetupScript) ||
              (symbol.command == CommandCleanupScript)) continue;
        }

      if (symbol.value_lists.size () < 1) continue;

      symbol.show_macro (mode);
    }
}

/**
 *  Format a set of make macro definitions (one per line)
 * Each macro value is provided enclosed in single quotes
 *
 *  Take the macro values from the macro statements found
 * in recursively read requirements files.
 */
void Cmt::print_symbol_names (PrintMode mode, const cmt_string& pattern)
{
  int number;

  set_standard_macros ();

  cmt_regexp expression (pattern);

  bool has_pattern = (pattern != "");

  for (number = 0; number < Symbol::symbol_number (); number++)
    {
      Symbol& symbol = Symbol::symbol (number);

      if (has_pattern)
	{
	  if (!expression.match (symbol.name)) continue;
	}

      if (m_action == action_show_macro_names)
        {
          // Only keep macros.
          if ((symbol.command == CommandSet) ||
              (symbol.command == CommandSetAppend) ||
              (symbol.command == CommandSetPrepend) ||
              (symbol.command == CommandSetRemove) ||
              (symbol.command == CommandAlias) ||
              (symbol.command == CommandPath) ||
              (symbol.command == CommandPathAppend) ||
              (symbol.command == CommandPathPrepend) ||
              (symbol.command == CommandPathRemove)) continue;
        }
      else if (m_action == action_show_set_names)
        {
          // Exclude macros.
          if ((symbol.command == CommandMacro) ||
              (symbol.command == CommandMacroAppend) ||
              (symbol.command == CommandMacroPrepend) ||
              (symbol.command == CommandMacroRemove) ||
              (symbol.command == CommandMacroRemoveAll)) continue;
        }

      cout << symbol.name << endl;
    }
}

//----------------------------------------------------------
void Cmt::print_tabs (int tabs)
{
  while (tabs > 0)
    {
      cout << "  ";
      tabs--;
    }
}

//----------------------------------------------------------
int Cmt::reach_current_package ()
{
  Use& use = Use::current ();
  cmt_string dir;

  if (m_debug)
    {
      cout << "Cmt::reach_current_package> pwd = " <<
        CmtSystem::pwd () <<
        " path=" << m_current_path <<
        endl;
    }

  /*
    Try to access the package.
  */

  if (m_current_package == "cmt_standalone")
    {
      if ((m_current_path != "") && (m_current_path != CmtSystem::pwd ()))
        {
          if (!CmtSystem::cd (m_current_path))
            {
              CmtError::set (CmtError::package_not_found,
                             "ReachCurrentPackage> Cannot reach the path directory");
              return (0);
            }
        }

      if (!CmtSystem::test_file ("requirements"))
        {
          if (!m_quiet)
            {
              cout << "#CMT> Cannot reach the requirements file" << endl;
            }
              
          CmtError::set (CmtError::package_not_found,
                         "ReachCurrentPackage> Cannot reach the requirements file");
          return (0);
        }
    }
  else if (m_current_package != "")
    {
      if (!use.move_to ())
        {
          CmtError::set (CmtError::package_not_found,
                         "ReachCurrentPackage> Cannot reach the path directory");
          return (0);
        }

      m_current_path = use.real_path;

      cmt_string parent = m_current_path;
      cmt_string d = m_current_path;

      for (;;)
        {
          d += "/../";
          if (!CmtSystem::is_package_directory (d))
            {
              CmtSystem::add_cmt_path (parent, "current package",
                                       m_cmt_path, 
                                       m_cmt_path_pwds, 
                                       m_cmt_path_sources);
              break;
            }
          parent = d;
        }
    }
  else
    {
      //
      // The cmt command has been given without explicit search for 
      // a package. Thus it is expected that we are in the context of a
      // true package.
      //
      //  This means that there should be a requirements file visible.
      //
      //  If this is not true, we'll make a try into ../cmt and then
      // a last try into ../mgr
      //

      if (!CmtSystem::test_file ("requirements"))
        {
          if (CmtSystem::cd ("../cmt") && 
              CmtSystem::test_file ("requirements"))
            {
              m_current_style = cmt_style;
            }
          else if (CmtSystem::cd ("../mgr") && 
                   CmtSystem::test_file ("requirements"))
            {
              m_current_style = mgr_style;
            }
          else
            {
              if (!m_quiet)
                {
                  cout << "#CMT> Cannot reach the mgr branch" << endl;
                }
              
              CmtError::set (CmtError::package_not_found,
                             "ReachCurrentPackage> Cannot reach the mgr/cmt directory");
              return (0);
            }
        }

      dir = CmtSystem::pwd ();

      CmtSystem::dirname (dir, m_current_path);
      CmtSystem::basename (m_current_path, m_current_version);
      CmtSystem::dirname (m_current_path, m_current_path);
      CmtSystem::basename (m_current_path, m_current_package);
      CmtSystem::dirname (m_current_path, m_current_path);
      
      Use& use = Use::current ();
      
      use.package = m_current_package;
      use.version = m_current_version;
      use.path    = m_current_path;
      use.style   = m_current_style;
    }

  configure_current_dir ();

  /*
    Check Tag is always set up
  */

  if (m_debug) cerr << "reach_current_package0> current_tag=" << m_current_tag << endl;

  if (m_current_tag == "")
    {
      cmt_string env;

      env = CmtSystem::getenv (m_current_config);
      if (env != "")
        {
          Tag* tag;

          tag = Tag::add (env, PriorityConfig, "reach current package", 0);
          tag->mark ();
            //m_current_tag = env;

          //if (!m_quiet) cerr << "reach_current_package1> current_tag=" << m_current_tag << endl;

        }
    }

  if (m_debug)
    {
      cout << "pwd = " << CmtSystem::pwd () << endl;
    }

  /*
    Work on the requirements file.
  */

  if (dir != "") dir += CmtSystem::file_separator ();
  dir += "requirements";
  parse_requirements (dir, 0);

  if (m_debug) cerr << "reach_current_package2> current_tag=" << m_current_tag << endl;

    /**
     *   It would be useful to change this mechanism. Instead of
     *  applying all global patterns at once to all use contexts, it
     *  would be much better to apply it at the end of each
     *  requirements file parsing, and only in the context the
     *  appropriate Use.
     *
     *   This would avoid the current flaw which is that when a global
     *  pattern specifies a "private" definition, it is actually
     *  applied in the scope context of the Current Use and not in
     *  each individual Use. Therefore the private is lost.
     *
     *   However, this induces problems since some pattern definitions
     *  are done AFTER the use statements, which will NOT receive the
     *  pattern aplications.
     *
     *   Therefore it is decided to leave this "bad" mechanism until
     *  everybody is aware of this constraint.
     *
     * 
     */
  Pattern::apply_all_globals ();

  /*
    Select all possible tags
  */

  Tag::restore_tree ();

  return (1);
}

/**
 *  Parse a line reformatted into a set of words.
 *
 *  Specific action are taken according to the keyword
 */
void Cmt::select (const CmtSystem::cmt_string_vector& words,
                  Use* use,
                  const cmt_string& file_name,
                  int line_number)
{
  cmt_string command;
  CommandType command_type = CommandNone;
  int i;

  CmtError::clear ();

  if (words.size () == 0) return;

  command = words[0];

  if (command.size () == 0) return;

  //
  // First analyze the syntax
  //

  switch (command[0])
    {
    case 'a':
      if (command == "alias")
        {
          command_type = CommandAlias;
        }
      else if (command == "application")
        {
          command_type = CommandApplication;
        }
      else if (command == "apply_pattern")
        {
          command_type = CommandApplyPattern;
        }
      else if (command == "author")
        {
          command_type = CommandAuthor;
        }
      else
        {
          CmtError::set (CmtError::syntax_error, "ParseRequirements> ");
        }
      break;
    case 'b':
      if (command == "branches")
        {
          command_type = CommandBranches;
        }
      else if (command == "build_strategy")
        {
          command_type = CommandBuildStrategy;
        }
      else
        {
          CmtError::set (CmtError::syntax_error, "ParseRequirements> ");
        }
      break;
    case 'c':
      if (command == "cleanup_script")
        {
          command_type = CommandCleanupScript;
        }
      else
        {
          CmtError::set (CmtError::syntax_error, "ParseRequirements> ");
        }
      break;
    case 'd':
      if (command == "document")
        {
          command_type = CommandDocument;
        }
      else
        {
          CmtError::set (CmtError::syntax_error, "ParseRequirements> ");
        }
      break;
    case 'i':
      if (command == "ignore_pattern")
        {
          command_type = CommandIgnorePattern;
        }
      else if (command == "include_dirs")
        {
          command_type = CommandIncludeDirs;
        }
      else if (command == "include_path")
        {
          command_type = CommandIncludePath;
        }
      else
        {
          CmtError::set (CmtError::syntax_error, "ParseRequirements> ");
        }
      break;
    case 'l':
      if (command == "language")
        {
          command_type = CommandLanguage;
        }
      else if (command == "library")
        {
          command_type = CommandLibrary;
        }
      else
        {
          CmtError::set (CmtError::syntax_error, "ParseRequirements> ");
        }
      break;
    case 'm':
      if (command == "macro")
        {
          command_type = CommandMacro;
        }
      else if (command == "macro+")
        {
          command_type = CommandMacroAppend;
        }
      else if (command == "macro_prepend")
        {
          command_type = CommandMacroPrepend;
        }
      else if ((command == "macro_append") ||
               (command == "macro+"))
        {
          command_type = CommandMacroAppend;
        }
      else if (command == "macro_remove")
        {
          command_type = CommandMacroRemove;
        }
      else if (command == "macro_remove_all")
        {
          command_type = CommandMacroRemoveAll;
        }
      else if (command == "make_fragment")
        {
          command_type = CommandMakeFragment;
        }
      else if (command == "manager")
        {
          command_type = CommandManager;
        }
      else
        {
          CmtError::set (CmtError::syntax_error, "ParseRequirements> ");
        }
      break;
    case 'p':
      if (command == "package")
        {
          command_type = CommandPackage;
        }
      else if (command == "path")
        {
          command_type = CommandPath;
        }
      else if (command == "path_append")
        {
          command_type = CommandPathAppend;
        }
      else if (command == "path_prepend")
        {
          command_type = CommandPathPrepend;
        }
      else if (command == "path_remove")
        {
          command_type = CommandPathRemove;
        }
      else if (command == "pattern")
        {
          command_type = CommandPattern;
        }
      else if (command == "public")
        {
          command_type = CommandPublic;
        }
      else if (command == "private")
        {
          command_type = CommandPrivate;
        }
      else
        {
          CmtError::set (CmtError::syntax_error, "ParseRequirements> ");
        }
      break;
    case 's':
      if (command == "set")
        {
          command_type = CommandSet;
        }
      else if (command == "set_append")
        {
          command_type = CommandSetAppend;
        }
      else if (command == "set_prepend")
        {
          command_type = CommandSetPrepend;
        }
      else if (command == "set_remove")
        {
          command_type = CommandSetRemove;
        }
      else if (command == "setup_script")
        {
          command_type = CommandSetupScript;
        }
      else
        {
          CmtError::set (CmtError::syntax_error, "ParseRequirements> ");
        }
      break;
    case 't':
      if (command == "tag")
        {
          command_type = CommandTag;
        }
      else if (command == "tag_exclude")
        {
          command_type = CommandTagExclude;
        }
      else
        {
          CmtError::set (CmtError::syntax_error, "ParseRequirements> ");
        }
      break;
    case 'u':
      if (command == "use")
        {
          command_type = CommandUse;
        }
      else
        {
          CmtError::set (CmtError::syntax_error, "ParseRequirements> ");
        }
      break;
    case 'v':
      if (command == "version_strategy")
        {
          command_type = CommandVersionStrategy;
        }
      else if (command == "version")
        {
          command_type = CommandVersion;
        }
      else
        {
          CmtError::set (CmtError::syntax_error, "ParseRequirements> ");
        }
      break;
    default:
      CmtError::set (CmtError::syntax_error, "ParseRequirements> ");
      break;
    }

  if (CmtError::has_pending_error ())
    {
      if (!m_quiet)
        {
          cout << "#CMT> bad syntax in requirements of " << use->package
               << " " << use->version 
               << " " << use->specified_path 
               << " line #" << line_number;
          cout << " [" << command << " ...]" << endl;
        }

      return;
    }


  //
  // Then interpret the action
  //

  switch (command_type)
    {
    case CommandAlias :
      Symbol::action (words, command_type, use);
      break;
    case CommandApplication :
      if (use == &(Use::current ()))
        {
          Constituent::action (Application, words);
        }
      break;
    case CommandApplyPattern :
      ApplyPattern::action (words, use);
      break;
    case CommandAuthor :
      use->author_action (words);
      break;
    case CommandBranches :
      if (use == &(Use::current ())) Branch::action (words);
      break;
    case CommandBuildStrategy :
      m_current_build_strategy = DefaultBuildStrategy;

      for (i = 1; i < words.size (); i++)
        {
          const cmt_string& w = words[i];

          if (w == "prototypes")
            {
              m_current_build_strategy |= Prototypes;
            }
          else if (w == "no_prototypes")
            {
              m_current_build_strategy |= NoPrototypes;
            }
          else if (w == "keep_makefiles")
            {
              m_current_build_strategy |= KeepMakefiles;
            }
          else if (w == "rebuild_makefiles")
            {
              m_current_build_strategy |= RebuildMakefiles;
            }

          if ((m_action == action_show_strategies) && !m_quiet)
            {
              cout << "# Package " << use->package <<
                " adds " << w << " to build strategy" << endl;
            }
        }
      break;
    case CommandCleanupScript :
      Script::action (words, CleanupScript, use);
      Symbol::action (words, command_type, use);
      break;
    case CommandDocument :
      if (use == &(Use::current ()))
        Constituent::action (Document, words);
      break;
    case CommandIgnorePattern :
      IgnorePattern::action (words, use);
      break;
    case CommandIncludeDirs :
      Include::action (words, use);
      break;
    case CommandIncludePath :
      if (words.size () > 1)
        {
          use->set_include_path (words[1]);
        }
      break;
    case CommandLanguage :
      Language::action (words);
      break;
    case CommandLibrary :
      if (use == &(Use::current ()))
        Constituent::action (Library, words);
      break;
    case CommandMacro :
    case CommandMacroPrepend :
    case CommandMacroAppend :
    case CommandMacroRemove :
    case CommandMacroRemoveAll :
      Symbol::action (words, command_type, use);
      break;
    case CommandMakeFragment :
      Fragment::action (words, use);
      break;
    case CommandManager :
      use->manager_action (words);
      break;
    case CommandPackage :
      if (words.size () > 1)
        {
          if (use == &(Use::current()))
            {
              m_current_package = words[1];
              build_prefix (m_current_package, m_current_prefix);

              if ((use->package != "") &&
                  (use->package != m_current_package))
                {
                  /*
                    Unknown keyword : just ignore the line
                  */
                  if (!m_quiet)
                    {
                      cout << "#CMT> package name mismatch in requirements of " <<
                        use->package << " " <<
                        use->version << " line #" << line_number;
                      cout << " : " << m_current_package << " versus " <<
                        use->package << endl;
                    }
                }

              use->set (m_current_package,
                        m_current_version,
                        m_current_path,
                        "",
                        "");

              use->change_path (m_current_path);
	      use->style = m_current_style;
            }
        }
      break;
    case CommandPath :
    case CommandPathAppend :
    case CommandPathPrepend :
    case CommandPathRemove :
      Symbol::action (words, command_type, use);
      break;
    case CommandPattern :
      Pattern::action (words, use);
      break;
    case CommandPrivate :
      m_scope = ScopePrivate;
      break;
    case CommandPublic :
      m_scope = ScopePublic;
      break;
    case CommandSet :
    case CommandSetAppend :
    case CommandSetPrepend :
    case CommandSetRemove :
      Symbol::action (words, command_type, use);
      break;
    case CommandSetupScript :
      Script::action (words, SetupScript, use);
      Symbol::action (words, command_type, use);
      break;
    case CommandTag :
      Tag::action (words, use);
      break;
    case CommandTagExclude :
      Tag::action_exclude (words, use);
      break;
    case CommandUse :
      Use::action (words, use);
      break;
    case CommandVersionStrategy :
      if (words.size () > 1)
        {
          const cmt_string& w = words[1];

          if (w == "best_fit")
            {
              m_current_strategy = BestFit;
            }
          else if (w == "best_fit_no_check")
            {
              m_current_strategy = BestFitNoCheck;
            }
          else if (w == "first_choice")
            {
              m_current_strategy = FirstChoice;
            }
          else if (w == "last_choice")
            {
              m_current_strategy = LastChoice;
            }
          else if (w == "keep_all")
            {
              m_current_strategy = KeepAll;
            }

          if ((m_action == action_show_strategies) && !m_quiet)
            {
              cout << "# Package " << use->package <<
                " sets version strategy to " << w << endl;
            }
        }
      break;
    case CommandVersion :
      /*
        m_current_version = words[1];
      */
      break;
    default:
      /*
        Unknown keyword : just ignore the line
      */
      if (!m_quiet)
        {
          cout << "#CMT> bad syntax in requirements of " << use->package
               << " " << use->version << " line #" << line_number;
          cout << " [" << command << "...]" << endl;
        }

      CmtError::set (CmtError::syntax_error, "ParseRequirements> ");

      return;
    }
}

static cmt_string get_best_form (const CmtSystem::cmt_string_vector& pwd,
                                 const cmt_string& path)
{
  static cmt_string fs = CmtSystem::file_separator ();
  cmt_string result;

    /*
    //if (CmtSystem::getenv ("CMTTESTPREFIX") != "")
    {
    */

    //
    //  If there is a common prefix between
    //  use->real_path and pwd
    //  we have 
    //  use->real_path = /<prefix>/aaa
    //  pwd            = /<prefix>/bbb
    //
    //  Then use->real_path may be expressed as:
    //  ../..../../aaa
    //   where ../..../../ moves up to /<prefix>
    //
    //   Then we try to find the shortest between
    //
    //     /<prefix> and ../..../..
    //
  cmt_string a = path;
  
  CmtSystem::cmt_string_vector va;
  
  va.clear ();
  
  CmtSystem::split (a, fs, va);
  
  int m = va.size ();
  if (pwd.size () < m) m = pwd.size ();
  
  int i;
  
    //cout << "Package " << use->package << endl;
  
  for (i = 0; i < m; i++)
    {
      const cmt_string& fa = va[i];
      const cmt_string& fb = pwd[i];
      
        //cout << "  fa=" << fa << " fb=" << fb << endl;
      
      if (fa != fb) break;
    }
  
  cmt_string ups = "";
  
  if (i > 0)
    {
        // We have the prefix.
        // if we count what remains from pwd, then 
        // we have the number of ../ required to 
        // move to /<prefix>
      int j;
      
      for (j = i; j < pwd.size (); j++)
        {
          if (j > i) ups += fs;
          ups += "..";
        }

      for (j = i; j < va.size (); j++)
        {
          ups += fs;
          ups += va[j];
        }
    }
  
    //
    // Here ups contains the ../..../../aaa form
    // for the use->real_path or is empty when there
    // were no common prefix.
    //
  
    //if (ups != "")
  if ((ups != "") &&
      (ups.size () < path.size ()))
    {
      result = ups;
    }
  else
    {
      result = path;
    }

  return (result);
}

/**
 *   This completely local class holds primitive actions for building
 *   standard macros.
 */
class StandardMacroBuilder
{
public:

  StandardMacroBuilder (const cmt_string& tag,
                        const cmt_string& package,
                        const cmt_string& version,
                        const cmt_string& prefix,
                        CmtDirStyle style)
  {
    fs = CmtSystem::file_separator ();
    buffer = "";
    pwd = CmtSystem::pwd ();
    CmtSystem::split (pwd, fs, vb);
    current_use = &(Use::current ());
    current_tag = tag;
    current_package = package;
    current_version = version;
    current_prefix = prefix;
    current_style = style;
  }

  void apply ()
  {
    Cmt::parse_requirements_line (buffer, current_use);
    buffer = "";
  }

  /**
   *   tag
   */
  void fill_for_tag ()
  {
    static bool tag_debug = CmtSystem::testenv ("TAGDEBUG");

    if (!Symbol::is_selected ("tag"))
      {
        if (tag_debug) cerr << "set_standard_macro2.1> current_tag=" << current_tag << endl;

        if (current_tag == "")
          {
            buffer = "macro tag \"$(CMTCONFIG)\"";
          }
        else
          {
            buffer = "macro tag \"";
            buffer += current_tag;
            buffer += "\"";
          }
        
        if (tag_debug) cerr << " define tag: " << buffer << endl;
        
        apply ();
      }
  }

  /**
   *   <package>_tag
   */
  void fill_for_package_tag ()
  {
    cmt_string package_tag = current_package;
    package_tag += "_tag";
    
    if (!Symbol::is_selected (package_tag))
      {
        buffer  = "macro ";
        buffer += package_tag;
        buffer += " \"$(tag)\"";

        apply ();
      }
  }

  /**
   *   <PACKAGE>ROOT
   *   PACKAGE_ROOT
   *   <package>_root
   *   <PACKAGE>VERSION
   */
  void fill_for_package (const cmt_string& current_dir)
  {
    cmt_string PACKAGE_ROOT = current_prefix;
    PACKAGE_ROOT += "ROOT";
    
    if (!Symbol::is_selected (PACKAGE_ROOT))
      {
        if (current_use->path == "")
          {
            buffer = "macro ";
            buffer += PACKAGE_ROOT;
            buffer += " \"";
            buffer += current_dir;
            buffer += "\"";
          }
        else
          {
            current_use->path.replace_all (CmtSystem::file_separator (), fs);
            
            buffer = "macro ";
            buffer += PACKAGE_ROOT;
            buffer += " \"";
            buffer += current_use->path;
            buffer += fs;
            buffer += current_use->package;
	    buffer += fs;
	    buffer += current_use->version;
            buffer += "\"";
          }
        
        apply ();
      }

    if (!Symbol::is_selected ("PACKAGE_ROOT"))
      {
        buffer = "macro PACKAGE_ROOT \"$(";
        buffer += PACKAGE_ROOT;
        buffer += ")\"";

        apply ();
      }

    cmt_string package_root = current_use->package;
    package_root += "_root";
    
    if (!Symbol::is_selected (package_root))
      {
        buffer = "macro ";
        buffer += package_root;
        buffer += " \"";

        if (current_use->path == "")
          {
            buffer += current_dir;
          }
        else
          {
            current_use->path.replace_all (CmtSystem::file_separator (), fs);

            buffer += get_best_form (vb, current_use->path);
            buffer += fs;
            buffer += current_use->package;
	    buffer += fs;
	    buffer += current_use->version;
          }
        buffer += "\"";

        apply ();
      }

    cmt_string package_version = current_prefix;
    package_version += "VERSION";

    if (!Symbol::is_selected (package_version))
      {
        buffer = "macro ";
        buffer += package_version;
        buffer += " \"";
        buffer += current_use->version;
        buffer += "\"";

        apply ();
      }
  }

  /**
   *   srcdir
   *   src       =$(srcdir)/
   *   inc
   *   mgrdir
   *   mgr       =../$(mgrdir)/
   *   bin
   *   javabin
   *   doc
   *   version
   *   package
   */
  void fill_for_branches ()
  {
    /**
     *    Basic macros  (src, mgr, ...)
     */
    
    if (current_style == none_style)
      {
        buffer = "macro srcdir \".";
        buffer += "\"";
        apply ();

        buffer = "macro src \".";
        buffer += fs;
        buffer += "\"";
        apply ();

        buffer = "macro inc \".";
        buffer += fs;
        buffer += "\"";
        apply ();

        buffer = "macro mgr \".";
        buffer += fs;
        buffer += "\"";
        apply ();

        buffer = "macro bin \".";
        buffer += fs;
        buffer += "\"";
        apply ();

        buffer = "macro javabin \".";
        buffer += fs;
        buffer += "\"";
        apply ();

        buffer = "macro doc \".";
        buffer += fs;
        buffer += "\"";
        apply ();

        buffer = "macro version \"\"";
        apply ();

        buffer = "macro package \"";
        buffer += current_package;
        buffer += "\"";
        apply ();
      }
    else
      {
        if (!Symbol::is_selected ("srcdir"))
          {
            buffer = "macro srcdir \"..";
            buffer += fs;
            buffer += "src";
            buffer += "\"";
            apply ();
          }
        
        if (!Symbol::is_selected ("src"))
          {
            buffer = "macro src \"..";
            buffer += fs;
            buffer += "src";
            buffer += fs;
            buffer += "\"";
            apply ();
          }
        
        if (!Symbol::is_selected ("inc"))
          {
            buffer = "macro inc \"..";
            buffer += fs;
            buffer += "src";
            buffer += fs;
            buffer += "\"";
            apply ();
          }
        
        if (!Symbol::is_selected ("doc"))
          {
            buffer = "macro doc \"..";
            buffer += fs;
            buffer += "doc";
            buffer += fs;
            buffer += "\"";
            apply ();
          }
        
        if (!Symbol::is_selected ("bin"))
          {
            cmt_string package_tag = current_package;
            package_tag += "_tag";

            buffer = "macro bin \"..";
            buffer += fs;
            buffer += "$(";
            buffer += package_tag;
            buffer += ")";
            buffer += fs;
            buffer += "\"";
            apply ();
          }

        if (!Symbol::is_selected ("javabin"))
          {
            buffer = "macro javabin \"..";
            buffer += fs;
            buffer += "classes";
            buffer += fs;
            buffer += "\"";
            apply ();
          }
        
        if (current_style == mgr_style)
          {
            buffer = "macro mgrdir \"mgr\"";
            apply ();

            buffer = "macro mgr \"..";
            buffer += fs;
            buffer += "mgr";
            buffer += fs;
            buffer += "\"";
            apply ();
          }
        else
          {
            buffer = "macro mgrdir \"cmt\"";
            apply ();

            buffer = "macro mgr \"..";
            buffer += fs;
            buffer += "cmt";
            buffer += fs;
            buffer += "\"";
            apply ();
          }
        
        buffer = "macro version \"";
        buffer += current_version;
        buffer += "\"";
        apply ();

        buffer = "macro package \"";
        buffer += current_package;
        buffer += "\"";
        apply ();
      }
  }

  /**
   *   <used_package>_tag
   */
  void fill_for_use_tag (Use* use)
  {
    cmt_string package_tag = use->package + "_tag";

    if (!Symbol::is_selected (package_tag))
      {
        buffer  = "macro ";
        buffer += package_tag;
        buffer += " \"$(tag)\"";
        apply ();
      }
  }

  /**
   *   <USEDPACKAGE>ROOT
   */
  void fill_for_use_ROOT (Use* use)
  {
    cmt_string PACKAGE_ROOT = use->prefix;
    PACKAGE_ROOT += "ROOT";

    if (!Symbol::is_selected (PACKAGE_ROOT))
      {
        if (use->located ())
          {
            buffer  = "macro ";
            buffer += PACKAGE_ROOT;
            buffer += " \"";
            buffer += use->get_full_path ();
            buffer += "\"";
            apply ();
          }
      }
  }

  /**
   *   <USEDPACKAGE>_root
   */
  void fill_for_use_root (Use* use)
  {
    cmt_string package_root = use->package;
    package_root += "_root";

    if (!Symbol::is_selected (package_root))
      {
        if (use->located ())
          {
            buffer  = "macro ";
            buffer += package_root;
            buffer += " \"";
            buffer += get_best_form (vb, use->real_path);
            buffer += fs;
            buffer += use->package;
	    buffer += fs;
	    buffer += use->version;
            buffer += "\"";
            apply ();
          }
      }
  }

  /**
   *   <USEDPACKAGE>VERSION
   */
  void fill_for_use_version (Use* use)
  {
    cmt_string package_version = use->prefix;
    package_version += "VERSION";
    
    if (!Symbol::is_selected (package_version))
      {
        buffer  = "macro ";
        buffer += package_version;
        buffer += " \"";
        buffer += use->version;
        buffer += "\"";
        apply ();
      }
  }

  void fill_for_uses ()
  {
    Use::UsePtrVector& Uses = Use::uses ();

    if (Uses.size () == 0) return;

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

        if (use->package == "CMT") continue;
        if (use->package == "methods") continue;
        if (use->discarded) continue;

        fill_for_use_tag (use);
        fill_for_use_ROOT (use);
        fill_for_use_root (use);
        fill_for_use_version (use);
      }
  }

  /**
   *   use_requirements
   */
  void fill_for_use_requirements ()
  {
    Use::UsePtrVector& Uses = Use::uses ();

    if (Uses.size () == 0) return;

    if (!Symbol::is_selected ("use_requirements"))
      {
        buffer  = "macro use_requirements \"";
        buffer += "requirements ";
        
        for (int number = 0; number < Uses.size (); number++)
          {
            Use* use = Uses[number];
            
            if (use->discarded) continue;
            
            if (use->located ())
              {
                buffer += "$(";
                buffer += use->prefix;
                buffer += "ROOT)";
                buffer += fs;
                
                if (use->style == mgr_style) buffer += "mgr";
                else buffer += "cmt";
                
                buffer += fs;
                buffer += "requirements ";
              }
          }
        
        buffer += "\"";
        
        apply ();
      }
  }

  /**
   *   use_includes
   */
  void fill_for_use_includes ()
  {
    Use::UsePtrVector& Uses = Use::uses ();

    if (Uses.size () == 0) return;

    if (!Symbol::is_selected ("use_includes"))
      {
        buffer = "macro_append use_includes \' ";
        
        for (int number = 0; number < Uses.size (); number++)
          {
            Use* use = Uses[number];
            
            if (use->package == "CMT") continue;
            if (use->package == "methods") continue;
            
            if (Cmt::get_debug ())
              {
                cout << "fill use_includes for " << use->package 
                     << " discarded=" << use->discarded
                     << " auto_imports=" << use->auto_imports << endl;
              }
            
            if (use->discarded) continue;
            if (use->auto_imports == Off) continue;
            
            use->fill_includes_macro (buffer);
          }
        
        buffer += "\'";
        
        apply ();
      }
  }

  /**
   *   use_fincludes
   */
  void fill_for_use_fincludes ()
  {
    Use::UsePtrVector& Uses = Use::uses ();

    if (Uses.size () == 0) return;

    if (!Symbol::is_selected ("use_fincludes"))
      {
        buffer = "macro_append use_fincludes \" $(use_includes)\"";
        apply ();
      }
  }

  /**
   *   use_stamps
   */
  void fill_for_use_stamps ()
  {
    Use::UsePtrVector& Uses = Use::uses ();

    if (Uses.size () == 0) return;

    if (!Symbol::is_selected ("use_stamps"))
      {
        buffer = "macro use_stamps \"";
        (Use::current()).fill_macro (buffer, "stamps");
        
        for (int number = 0; number < Uses.size (); number++)
          {
            Use* use = Uses[number];
            
            if (use->package == "CMT") continue;
            if (use->package == "methods") continue;
            if (use->discarded) continue;
            
            use->fill_macro (buffer, "stamps");
          }
        
        buffer += "\"";
        
        apply ();
      }
  }

  /**
   *   use_cflags
   */
  void fill_for_use_cflags ()
  {
    Use::UsePtrVector& Uses = Use::uses ();

    if (Uses.size () == 0) return;

    if (!Symbol::is_selected ("use_cflags"))
      {
        Use::fill_macro_all (buffer, "cflags");
        apply ();
      }
  }

  /**
   *   use_pp_cflags
   */
  void fill_for_use_pp_cflags ()
  {
    Use::UsePtrVector& Uses = Use::uses ();

    if (Uses.size () == 0) return;

    if (!Symbol::is_selected ("use_pp_cflags"))
      {
        Use::fill_macro_all (buffer, "pp_cflags");
        apply ();
      }
  }

  /**
   *   use_cppflags
   */
  void fill_for_use_cppflags ()
  {
    Use::UsePtrVector& Uses = Use::uses ();

    if (Uses.size () == 0) return;

    if (!Symbol::is_selected ("use_cppflags"))
      {
        Use::fill_macro_all (buffer, "cppflags");
        apply ();
      }
  }

  /**
   *   use_pp_cppflags
   */
  void fill_for_use_pp_cppflags ()
  {
    Use::UsePtrVector& Uses = Use::uses ();

    if (Uses.size () == 0) return;

    if (!Symbol::is_selected ("use_pp_cppflags"))
      {
        Use::fill_macro_all (buffer, "pp_cppflags");
        apply ();
      }
  }

  /**
   *   use_fflags
   */
  void fill_for_use_fflags ()
  {
    Use::UsePtrVector& Uses = Use::uses ();

    if (Uses.size () == 0) return;

    if (!Symbol::is_selected ("use_fflags"))
      {
        Use::fill_macro_all (buffer, "fflags");
        apply ();
      }
  }

  /**
   *   use_pp_fflags
   */
  void fill_for_use_pp_fflags ()
  {
    Use::UsePtrVector& Uses = Use::uses ();

    if (Uses.size () == 0) return;

    if (!Symbol::is_selected ("use_pp_fflags"))
      {
        Use::fill_macro_all (buffer, "pp_fflags");
        apply ();
      }
  }

  /**
   *   use_linkopts
   */
  void fill_for_use_linkopts ()
  {
    Use::UsePtrVector& Uses = Use::uses ();

    if (Uses.size () == 0) return;

    if (!Symbol::is_selected ("use_linkopts"))
      {
        Use::fill_macro_all (buffer, "linkopts");
        apply ();
      }
  }

  /**
   *   use_libraries
   */
  void fill_for_use_libraries ()
  {
    Use::UsePtrVector& Uses = Use::uses ();

    if (Uses.size () == 0) return;

    if (!Symbol::is_selected ("use_libraries"))
      {
        buffer  = "macro use_libraries \"";

        for (int number = 0; number < Uses.size (); number++)
          {
            Use* use = Uses[number];
            
            if (use->package == "CMT") continue;
            if (use->package == "methods") continue;
            if (use->discarded) continue;
            
            use->fill_macro (buffer, "libraries");
          }
        
        buffer += "\"";
        
        apply ();
      }
  }

  /**
   *   includes
   */
  void fill_for_includes ()
  {
    Use::UsePtrVector& Uses = Use::uses ();

    if (Uses.size () == 0) return;

    if (!Symbol::is_selected ("includes"))
      {
        buffer = "macro_append includes \' ";

        Use& use = Use::current();

        if (use.include_path == "")
          {
            buffer += "$(ppcmd)\"$(srcdir)\" ";
          }
        else if (use.include_path != "none")
          {
            buffer += "$(ppcmd)\"";
            buffer += use.include_path;
            buffer += "\" ";
          }
        
        for (int include_number = 0;
             include_number < use.includes.size ();
             include_number++)
          {
            Include& incl = use.includes[include_number];
            
            buffer += "$(ppcmd)\"";
            buffer += incl.name;
            buffer += "\" ";
          }
        
        buffer += "$(use_includes)\'";
        
        apply ();
      }
  }

  /**
   *   fincludes
   */
  void fill_for_fincludes ()
  {
    Use::UsePtrVector& Uses = Use::uses ();

    if (Uses.size () == 0) return;

    if (!Symbol::is_selected ("fincludes"))
      {
        buffer = "macro_append fincludes \" $(includes)\"";
        apply ();
      }
  }

  /**
   *  Macros specific to constituents.
   *  This includes the compiler flags
   *  and fills in these macros from uses packages. This takes care
   *  of -no_auto_imports and -import= directives
   */
  void fill_for_all_constituents ()
  {
    /// First, finish the parsing of constituent parameters.
    Constituent::parse_all ();

    Use::UsePtrVector& Uses = Use::uses ();

    const Constituent::ConstituentVector& constituents =
      Constituent::constituents ();

  
    /// Prepare the auto_imports states in a vector

    cmt_vector<bool> base_auto_imports_states;

    base_auto_imports_states.resize (Uses.size ());

    int number;

    for (number = 0; number < Uses.size (); number++)
      {
        Use* use = Uses[number];
        base_auto_imports_states[number] = (use->auto_imports != Off);
      }

    /// Now scan all constituents

    for (number = 0; number < constituents.size (); number++)
      {
        const Constituent& constituent = constituents[number];

        Use::UsePtrVector imports;
        int i;

        /**
         *  Problem for imports in constituents.
         *
         *     1) use_xxx has holes due to the corresponding 
         *         -no_auto_imports options attached to some
         *        use statements (including the transitive ones)
         *
         *     2) the -import=yyy options provided to a given constituent
         *        should restore the appropriate holes as well as
         *        all transitive ones.
         *
         *     3) for use_linkopts, missing pieces must be filled at
         *        the right position. (for others, order is not relevant
	 *        while transitive access is required for all)
         *
         */

        if (constituent.type == Document) continue;
        if (constituent.imports.size () == 0) 
          {
            buffer = "macro_append ";
            buffer += constituent.name;
            buffer += "_use_linkopts ";
            buffer += " \" ";
	
            current_use->fill_macro (buffer, "linkopts");
	
            for (i = 0; i < Uses.size (); i++)
              {
                if (base_auto_imports_states[i])
                  {
                    Use* u = Uses[i];
		
                    if (u->package == "CMT") continue;
                    if (u->package == "methods") continue;
                    if (u->discarded) continue;
                    
                    u->fill_macro (buffer, "linkopts");
                  }
              }
            buffer += "\"";
            apply ();

          /*
            buffer = "macro_append ";
            buffer += constituent.name;
            buffer += "_use_linkopts ";
            buffer += " \" $(use_linkopts)\"";
            apply ();
          */

            continue;
          }

        /**
	 * Create a private copy of the state vector. This private copy
	 * will be updated according to -import=xxx modifiers for the
	 * current constituent.
	 */
        cmt_vector<bool> auto_imports_states (base_auto_imports_states);

        for (i = 0; i < constituent.imports.size (); i++)
          {
            const cmt_string& import = constituent.imports[i];
            
            //
            // Resolve the imported uses
            //

            int use_index = Use::find_index (import, "", "");

            if (use_index >= 0)
              {
                Use* u = Uses[use_index];
            
                if (u->package == "CMT") continue;
                if (u->package == "methods") continue;
                if (u->discarded) continue;
                if (u->auto_imports != Off) continue;

                Use::set_auto_imports_state (use_index, auto_imports_states);
              }
          }

	/**
	 *   Find all newly exposed packages and precompute this list inside
	 *   a vector.
	 */
	for (i = 0; i < base_auto_imports_states.size (); i++)
	  {
	    if (auto_imports_states[i] != base_auto_imports_states[i])
	      {
                Use* u = Uses[i];

                if (u->package == "CMT") continue;
                if (u->package == "methods") continue;
                if (u->discarded) continue;
                if (u->auto_imports != Off) continue;

                imports.push_back (u);
	      }
	  }
        
        if (imports.size () == 0) return;

	cmt_string prefix;
            
	//
	// Documents are not considered 
	//
	switch (constituent.type)
	  {
	  case Application:
	    prefix = "app_";
	    break;
	  case Library:
	    prefix = "lib_";
	    break;
	  }
            
	buffer = "macro_append ";
	buffer += prefix;
	buffer += constituent.name;
	buffer += "_cflags ";
	buffer += " \' ";
	for (i = 0; i < imports.size (); i++)
	  {
	    Use* u = imports[i];
	    
	    u->fill_includes_macro (buffer);
	    u->fill_macro (buffer, "cflags");
	  }
	buffer += "\'";
	apply ();
	
	buffer = "macro_append ";
	buffer += prefix;
	buffer += constituent.name;
	buffer += "_pp_cflags ";
	buffer += " \" ";
	for (i = 0; i < imports.size (); i++)
	  {
	    Use* u = imports[i];
	    
	    u->fill_macro (buffer, "pp_cflags");
	  }
	buffer += "\"";
	apply ();
	
	buffer = "macro_append ";
	buffer += prefix;
	buffer += constituent.name;
	buffer += "_cppflags ";
	buffer += " \' ";
	for (i = 0; i < imports.size (); i++)
	  {
	    Use* u = imports[i];
	    
	    u->fill_includes_macro (buffer);
	    u->fill_macro (buffer, "cppflags");
	  }
	buffer += "\'";
	apply ();
	
	buffer = "macro_append ";
	buffer += prefix;
	buffer += constituent.name;
	buffer += "_pp_cppflags ";
	buffer += " \" ";
	for (i = 0; i < imports.size (); i++)
	  {
	    Use* u = imports[i];
	    
	    u->fill_macro (buffer, "pp_cppflags");
	  }
	buffer += "\"";
	apply ();
	
	buffer = "macro_append ";
	buffer += prefix;
	buffer += constituent.name;
	buffer += "_fflags ";
	buffer += " \' ";
	for (i = 0; i < imports.size (); i++)
	  {
	    Use* u = imports[i];
	    
	    u->fill_includes_macro (buffer);
	    u->fill_macro (buffer, "fflags");
	  }
	buffer += "\'";
	apply ();
	
	buffer = "macro_append ";
	buffer += prefix;
	buffer += constituent.name;
	buffer += "_pp_fflags ";
	buffer += " \" ";
	for (i = 0; i < imports.size (); i++)
	  {
	    Use* u = imports[i];
	    
	    u->fill_macro (buffer, "pp_fflags");
	  }
	buffer += "\"";
	apply ();

          /**
           *  Setting ${CONSTITUENT}linkopts is a temporary solution
           *  until the backward compatibility solution for a proper 
           *  replacement of use_linkopts by ${CONSTITUENT}_use_linkopts
           *  is acheived.
           *
           */
	buffer = "macro_append ";
	buffer += constituent.name;
	buffer += "linkopts ";
	buffer += " \" ";
	for (i = 0; i < imports.size (); i++)
	  {
	    Use* u = imports[i];
	    
	    u->fill_macro (buffer, "linkopts");
	  }
	buffer += "\"";
	apply ();
	
	/**
	 *  Only for linkopts we take care of the order. This means
	 *  that ${CONSTITUENT}_use_linkopts should be used in place of use_linkopts.
         *
         *  (see the application fragments)
	 */
	buffer = "macro_append ";
	buffer += constituent.name;
	buffer += "_use_linkopts ";
	buffer += " \" ";
	
	current_use->fill_macro (buffer, "linkopts");
	
	for (i = 0; i < Uses.size (); i++)
	  {
	    if (auto_imports_states[i])
	      {
		Use* u = Uses[i];
		
		if (u->package == "CMT") continue;
		if (u->package == "methods") continue;
		if (u->discarded) continue;
		
		u->fill_macro (buffer, "linkopts");
	      }
	  }
	buffer += "\"";
	apply ();
      }
  }

private:
  cmt_string fs;
  cmt_string buffer;
  CmtSystem::cmt_string_vector vb;
  cmt_string pwd;
  Use* current_use;
  cmt_string current_tag; 
  cmt_string current_package; 
  cmt_string current_version; 
  cmt_string current_prefix; 
  CmtDirStyle current_style;
};

//----------------------------------------------------------
void Cmt::set_standard_macros ()
{
  if (m_standard_macros_done) return;

  m_standard_macros_done = true;

  int number;
  cmt_string temp;
  Use::UsePtrVector& Uses = Use::uses ();
  Use& current_use = Use::current ();

  cmt_string fs = CmtSystem::file_separator ();

  cmt_string pwd = CmtSystem::pwd ();

  if (CmtSystem::test_file ("../cmt/requirements")) m_current_style = cmt_style;
  else if (CmtSystem::test_file ("../mgr/requirements")) m_current_style = mgr_style;
  else m_current_style = none_style;

  // Prepare computation of the best form for relative path from current directory
  // to package directories.
  CmtSystem::cmt_string_vector vb;
  CmtSystem::split (pwd, fs, vb);


    /**
     *    TAG management
     */

  bool tag_debug = CmtSystem::testenv ("TAGDEBUG");

  if (tag_debug) cerr << "set_standard_macro0> current_tag=" << m_current_tag << endl;

  if (m_current_tag != "")
    {
        // this is when some -tag= argument was used.
      if (tag_debug) cerr << "set_standard_macro0.1> current_tag=" << m_current_tag << endl;
    }
  else if (Symbol::is_selected ("CMTCONFIG"))
    {
        // This is when CMTCONFIG has been set from some requirements file
      Symbol* macro = Symbol::find ("CMTCONFIG");
      if (macro != 0)
        {
          m_current_tag = macro->build_macro_value ();
          if (tag_debug) cerr << "set_standard_macro1> current_tag=" << m_current_tag << endl;
        }
    }
  else
    {
        // this is when no -tag= argument was used.
      if (tag_debug) cerr << "set_standard_macro(before2)> current_tag=" << m_current_tag << endl;
      if (current_use.package == "CMT")
        {
          m_current_tag = CmtSystem::getenv ("CMTBIN");
        }
      else
        {
          m_current_tag = CmtSystem::getenv ("CMTCONFIG");
        }

      if (tag_debug) cerr << "set_standard_macro2> current_tag=" << m_current_tag << endl;
    }

  if (m_debug)
    {
      cout << "set_standard_macro3>" << endl;
    }

  StandardMacroBuilder builder (m_current_tag,
                                m_current_package,
                                m_current_version,
                                m_current_prefix,
                                m_current_style);

  builder.fill_for_tag ();
  builder.fill_for_package_tag ();
  builder.fill_for_package (m_current_dir);
  builder.fill_for_branches ();
  builder.fill_for_uses ();
  builder.fill_for_use_requirements ();
  builder.fill_for_use_includes ();
  builder.fill_for_use_fincludes ();
  builder.fill_for_use_stamps ();
  builder.fill_for_use_cflags ();
  builder.fill_for_use_pp_cflags ();
  builder.fill_for_use_cppflags ();
  builder.fill_for_use_pp_cppflags ();
  builder.fill_for_use_fflags ();
  builder.fill_for_use_pp_fflags ();
  builder.fill_for_use_linkopts ();
  builder.fill_for_use_libraries ();
  builder.fill_for_includes ();
  builder.fill_for_fincludes ();
  builder.fill_for_all_constituents ();

    /**
     *   Macros implied or required to manage constituents.
     */

  const Constituent::ConstituentVector& constituents =
    Constituent::constituents ();
  
  if (!Symbol::is_selected ("constituents"))
    {
      temp = "macro_append constituents \" ";
      
      for (number = 0; number < constituents.size (); number++)
        {
          const Constituent& constituent = constituents[number];

          if (constituent.group == 0)
            {
              temp += constituent.name;
              temp += " ";
            }
        }
      
      temp += "\"";
      
      parse_requirements_line (temp, &current_use);
    }

  parse_requirements_line ("macro_append all_constituents \" $(constituents)\"", 
                           &current_use);

  if (!Symbol::is_selected ("constituentsclean"))
    {
      temp = "macro_append constituentsclean \" ";
      
      for (number = constituents.size () - 1; number >= 0 ; number--)
        {
          const Constituent& constituent = constituents[number];

          if (constituent.group == 0)
            {
              temp += constituent.name;
              temp += "clean ";
            }
        }
      
      temp += "\"";
      
      parse_requirements_line (temp, &current_use);
    }

  parse_requirements_line ("macro_append all_constituentsclean \" $(constituentsclean)\"", 
                           &current_use);

  const Group::GroupVector& groups = Group::groups ();
  
  for (number = 0; number < groups.size (); number++)
    {
      const Group& group = groups[number];

      temp = "macro_append ";
      temp += group.name ();
      temp += "_constituents \" ";

      int i;

      for (i = 0; i < constituents.size (); i++)
        {
          const Constituent& constituent = constituents[i];

          if ((constituent.group != 0) && 
              (group.name () == constituent.group->name ()))
            {
              temp += constituent.name;
              temp += " ";
            }
        }
      
      temp += "\"";
      
      parse_requirements_line (temp, &current_use);

      temp = "macro_append ";
      temp += group.name ();
      temp += "_constituentsclean \" ";
      
      for (i = constituents.size () - 1; i >= 0 ; i--)
        {
          const Constituent& constituent = constituents[i];

          if ((constituent.group != 0) && 
              (group.name () == constituent.group->name ()))
            {
              temp += constituent.name;
              temp += "clean ";
            }
        }
      
      temp += "\"";
      
      parse_requirements_line (temp, &current_use);
    }
}

//----------------------------------------------------------
void Cmt::use_cmt ()
{
  UseRef use;
  bool recursive_copy = m_recursive;
  bool debug_copy = m_debug;

  if (m_default_path.size () <= 0) return;
  if (m_current_package == "CMT") return;

  m_recursive = true;
  m_debug = false;
  use = Use::add (m_default_path, "CMT", m_cmt_version, "", "", 0);
  m_recursive = recursive_copy;
  m_debug = debug_copy;
}

//----------------------------------------------------------
void Cmt::use_home_requirements ()
{
  cmt_string f = m_cmt_home;

  if (f == "") 
    {
        //if (!m_quiet) cerr << "No CMTHOME" << endl;
      return;
    }

    //if (!m_quiet) cerr << "Using CMTHOME in " << f << endl;

  UseRef use;
  bool recursive_copy = m_recursive;

  if (m_default_path.size () <= 0) return;
  if (m_current_package == "CMT") return;

  m_recursive = true;

  cmt_string name = CmtSystem::get_home_package ();

  use = Use::add (f, name, "", "", "", 0);

  f += CmtSystem::file_separator ();
  f += "requirements";
  parse_requirements (f, use);

  m_recursive = recursive_copy;
}

//----------------------------------------------------------
void Cmt::use_user_context_requirements ()
{
  cmt_string f = m_cmt_user_context;

  if (f == "") 
    {
        //if (!m_quiet) cerr << "No CMTUSERCONTEXT" << endl;
      return;
    }

    //if (!m_quiet) cerr << "Using CMTUSERCONTEXT in " << f << endl;

  UseRef use;
  bool recursive_copy = m_recursive;

  if (m_default_path.size () <= 0) return;
  if (m_current_package == "CMT") return;

  m_recursive = true;

  cmt_string name = CmtSystem::get_user_context_package ();

  use = Use::add (f, name, "", "", "", 0);

  f += CmtSystem::file_separator ();
  f += "requirements";
  parse_requirements (f, use);

  m_recursive = recursive_copy;
}

//-------------------------------------------------
void Cmt::vector_to_string (const CmtSystem::cmt_string_vector& v,
                            const cmt_string& separator,
                            cmt_string& result)
{
  result.erase (0);

  for (int i = 0; i < v.size (); i++)
    {
      if (i > 0) result += separator;
      result += v[i];
    }
}

//-------------------------------------------------
cmt_string Cmt::vector_to_string (const CmtSystem::cmt_string_vector& v)
{
  cmt_string result;

  vector_to_string (v, " ", result);

  return (result);
}
