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

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

#include "cmt_use.h"
#include "cmt_symbol.h"
#include "cmt_system.h"
#include "cmt_database.h"
#include "cmt_log.h"

// Global inhibitor of any display
bool Symbol::m_inhibit_display = false;

//-------------------------------------------------------------
class SetBuilder : public ValueBuilder
{
public:
  const cmt_string build (const Symbol& symbol,
                          const cmt_string& tag_name = "");
  const cmt_string clean (const Symbol& symbol,
                          const cmt_string& tag_name = "")
      {
        static const cmt_string empty = "";
        return (empty);
      }
};
//-------------------------------------------------------------

//-------------------------------------------------------------
class PathBuilder : public ValueBuilder
{
public:
  const cmt_string build (const Symbol& symbol,
                          const cmt_string& tag_name = "");
  const cmt_string clean (const Symbol& symbol,
                          const cmt_string& tag_name = "");
};
//-------------------------------------------------------------

//-------------------------------------------------------------
class MacroBuilder : public ValueBuilder
{
public:
  const cmt_string build (const Symbol& symbol,
                          const cmt_string& tag_name = "");
  const cmt_string clean (const Symbol& symbol,
                          const cmt_string& tag_name = "")
      {
        static const cmt_string empty = "";
        return (empty);
      }
};
//-------------------------------------------------------------

//-------------------------------------------------------------
class ScriptBuilder : public ValueBuilder
{
public:
  const cmt_string build (const Symbol& symbol,
                          const cmt_string& tag_name = "");
  const cmt_string clean (const Symbol& symbol,
                          const cmt_string& tag_name = "")
      {
        static const cmt_string empty = "";
        return (empty);
      }
};
//-------------------------------------------------------------

//-------------------------------------------------------------
class ActionBuilder : public ValueBuilder
{
public:
  const cmt_string build (const Symbol& symbol,
                          const cmt_string& tag_name = "");
  const cmt_string clean (const Symbol& symbol,
                          const cmt_string& tag_name = "")
      {
        static const cmt_string empty = "";
        return (empty);
      }
};
//-------------------------------------------------------------

//-------------------------------------------------------------
class symbol_marker
{
public:
  symbol_marker ()
  {
    ptr = cmt_string::npos;
    pattern = 0;
    intro = 0;
  }

  symbol_marker (int a_ptr, char a_pattern, int a_intro)
  {
    ptr = a_ptr;
    pattern = a_pattern;
    intro = a_intro;
  }

  symbol_marker (const symbol_marker& other)
  {
    ptr = other.ptr;
    pattern = other.pattern;
    intro = other.intro;
  }

  void set (int a_ptr, char a_pattern, int a_intro)
  {
    ptr = a_ptr;
    pattern = a_pattern;
    intro = a_intro;
  }

  static symbol_marker& get_lowest (symbol_marker markers[], int count)
  {
    static symbol_marker result;
    int real_count = 0;
    int i;

      // Check that at least one marker has result

    for (i = 0; i < count; i++)
      {
        if (markers[i].ptr != cmt_string::npos) real_count++;
      }

    if (real_count == 0) return (result);

    // since we've passed the previous test, 
    // at least one entry is not npos.
    // Now discards other npos by moving them to the end
    
    for (i = 0; i < count;)
      {
        if (markers[i].ptr == cmt_string::npos)
          {
            markers[i] = markers[count-1];
            count--;
            if (count == 0) break;
          }
        else
          {
            i++;
          }
      }
    
    if (count == 0) return (result);
    
    // now all entries in [0, count-1] are not npos
    // let's sort the lowest one in [0]
    
    for (i = 1; i < count;)
      {
        if (markers[0].ptr > markers[i].ptr)
          {
            symbol_marker temp = markers[0];
            markers[0] = markers[i];
            markers[i] = temp;
            i = 1;
          }
        else
          {
            i++;
          }
      }
    
    return (markers[0]);
  }

  int ptr;
  char pattern;
  int intro;
};
//-------------------------------------------------------------

/**

   Attempt to substitute all occurrences of

      ${<symbol_name>}
      $(<symbol_name>)
      %<symbol_name>%    [on Windows only]

      by the specified value in the given text.

    This is for one symbol only

 */
static void resolve_value (cmt_string& text,
                           const cmt_string& symbol_name,
                           const cmt_string& value)
{
  static cmt_string pattern;

  pattern = "${";
  pattern += symbol_name;
  pattern += "}";

  text.replace_all (pattern, value);

  pattern = "$(";
  pattern += symbol_name;
  pattern += ")";

  text.replace_all (pattern, value);

#ifdef WIN32
  pattern = "%";
  pattern += symbol_name;
  pattern += "%";

  text.replace_all (pattern, value);
#endif
}

/**

   Attempt to substitute into the specified text all occurrences of

      ${xxx}
      $(xxx)
      `xxx`
      %xxx%    [on Windows only]

      by the appropriate value:

        for `xxx` : 

            xxx is considered as a shell command. Value is the result of its execution

        for other patterns:

            if xxx is a symbol name, its value is substituted to the pattern
            otherwise, xxx is tried as an environment variable


     ===> In all cases, the pattern is filtered away.


 */
static void resolve_value (cmt_string& text)
{
  //static cmt_regexp reg ("[$%`]");

  //if (!reg.match (text)) return;

  cmt_string pattern;
  cmt_string symbol_name;
  char end_pattern;

  int start = 0;

  for (;;)
    {
      int begin;
      int end;

      symbol_marker markers[4];
      int num = 0;

      markers[num].set (text.find (start, "$("), ')', 2); num++;
      markers[num].set (text.find (start, "${"), '}', 2); num++;
      markers[num].set (text.find (start, "`"), '`', 1); num++;

#ifdef WIN32
      markers[num].set (text.find (start, "%"), '%', 1); num++;
#endif

      // Find the first matching pattern

      symbol_marker& marker = symbol_marker::get_lowest (markers, num);

      begin = marker.ptr;

      if (begin == cmt_string::npos) break;

      end_pattern = marker.pattern;
      start = begin + marker.intro;

      end = text.find (start, end_pattern);
      if (end == cmt_string::npos)
        {
          // The pattern is a fake one (no ending!)
          start++;
          continue;
        }

      // This should never happen...
      if (end < begin) break;

      // Extract the complete pattern
      text.substr (begin, end - begin + 1, pattern);

      // Then only the symbol name
      text.substr (begin + marker.intro, end - begin - marker.intro, symbol_name);

      if (text[begin] == '`')
        {
          cmt_string command = symbol_name;
          resolve_value (command);

            // The value is a shell command that first needs
            // to be applied. The output of the command is then substituted

          cmt_string result;

          Symbol::all_set ();
          CmtSystem::execute (command, result);
          
          int pos;
          pos = result.find ('\n');
          if (pos != cmt_string::npos) result.erase (pos);
          pos = result.find ('\r');
          if (pos != cmt_string::npos) result.erase (pos);
          
          if (Cmt::get_debug ())
            {
              cout << "   Executing [" << command << "] to expand a symbol value =>[" 
                   << result << "]" << endl;
            }
          
          text.replace_all (pattern, result);

          // The substitution will restart from the same place
          // allowing for recursive replacements
          start = begin;
        }
      else
        {
          Symbol* symbol = Symbol::find (symbol_name);
          if (symbol != 0)
            {
                // Symbol found
              cmt_string value = symbol->resolve_macro_value ();
              text.replace_all (pattern, value);
              
                // The substitution will restart from the same place
                // allowing for recursive replacements
              start = begin;
            }
          else
            {
                // Symbol not found. Look for env. variable
              cmt_string value = CmtSystem::getenv (symbol_name);
              
                // When the env. variable is not defined, the replacement is empty
                // thus all $(xxx) ${xxx} %xxx% patterns are always filtered away.
              text.replace_all (pattern, value);
              
                // The substitution will restart from the same place
                // allowing for recursive replacements
              start = begin;
            }
        }
    }
}

/**

   Attempt to substitute all occurrences of

      ${xxx}
      $(xxx)
      `xxx`
      %xxx%    [on Windows only]

      by the appropriate value:

        for `xxx` : 

            xxx is considered as a shell command. Value is the result of its execution

        for other patterns:

            if xxx is a macro name, its value is substituted to the pattern

            if xxx is a set or a path, it is kept in place (after fixing the pattern
            according to the OS style)

            otherwise it is simply kept in place

 */
static void resolve_value_for_macros (cmt_string& text)
{
  cmt_string pattern;
  cmt_string symbol_name;
  char end_pattern;

  int start = 0;

  for (;;)
    {
      //
      // Try and substitute all ${xxx} $(xxx) or %xxx% patterns
      // using symbol values, only when the symbol is a macro.
      //

      int begin;
      int end;

      symbol_marker markers[4];
      int num = 0;

      markers[num].set (text.find (start, "$("), ')', 2); num++;
      markers[num].set (text.find (start, "${"), '}', 2); num++;

#ifdef WIN32
      markers[num].set (text.find (start, "%"), '%', 1); num++;
#endif

      markers[num].set (text.find (start, "`"), '`', 1); num++;

      // Find the first of three patterns

      symbol_marker& marker = symbol_marker::get_lowest (markers, num);

      begin = marker.ptr;

      if (begin == cmt_string::npos) break;

      end_pattern = marker.pattern;
      start = begin + marker.intro;

      end = text.find (start, end_pattern);
      if (end == cmt_string::npos)
        {
          // The pattern is a fake one (no ending!)
          start++;
          continue;
        }

      // This should never happen...
      if (end < begin) break;

      // Extract the complete pattern
      text.substr (begin, end - begin + 1, pattern);

      // Then only the macro name
      text.substr (begin + marker.intro, end - begin - marker.intro, symbol_name);

      if (text[begin] == '`')
        {
          cmt_string command = symbol_name;
          resolve_value (command);

            // The macro value is a shell command that first needs
            // to be applied. The output of the command is substituted

          cmt_string result;

          Symbol::all_set ();
          CmtSystem::execute (command, result);
          
          int pos;
          pos = result.find ('\n');
          if (pos != cmt_string::npos) result.erase (pos);
          pos = result.find ('\r');
          if (pos != cmt_string::npos) result.erase (pos);
          
          if (Cmt::get_debug ())
            {
              cout << "   Executing [" << command << "] to expand a macro value =>[" 
                   << result << "]" << endl;
            }
          
          text.replace_all (pattern, result);

          // The substitution will restart from the same place
          // allowing for recursive replacements
          start = begin;
        }
      else
        {
          Symbol* macro = Symbol::find (symbol_name);
          if ((macro != 0) && 
              (macro->type == Symbol::SymbolMacro))
            {
                // Macro found
              cmt_string value = macro->resolve_macro_value ();
              text.replace_all (pattern, value);

                // The substitution will restart from the same place
                // allowing for recursive replacements
              start = begin;
            }
          else if ((macro == 0) || 
                   ((macro->type == Symbol::SymbolSet) || (macro->type == Symbol::SymbolPath)))
            {
                // Set found
                // ensure that the delimiters will match the OS dependent
                // delimiters.
              
              cmt_string pattern_close = marker.pattern;
              
              if (pattern_close != CmtSystem::ev_close ())
                {
                  cmt_string new_pattern;
                  
                  new_pattern = CmtSystem::ev_open ();
                  new_pattern += symbol_name;
                  new_pattern += CmtSystem::ev_close ();
                  
                  text.replace (pattern, new_pattern);
                }
              
              start = end + 1;
            }
          else
            {
              start = end + 1;
            }
        }
    }
}

/**

   This function suppress all OS delimiters ie ${ } or % % and replaces them
   by the pure macro delimiters $( )

   `xxx` pattern is replaced by the result of the execution of the command

 */
static void suppress_OS_delimiters (cmt_string& text)
{
  cmt_string pattern;
  cmt_string symbol_name;
  char end_pattern;

  int start = 0;

  for (;;)
    {
      int begin;
      int end;

      symbol_marker markers[3];
      int num = 0;

      markers[num].set (text.find (start, "${"), '}', 2); num++;
      markers[num].set (text.find (start, "`"), '`', 1); num++;

#ifdef WIN32
      markers[num].set (text.find (start, "%"), '%', 1); num++;
#endif

      // Find the first of three patterns

      symbol_marker& marker = symbol_marker::get_lowest (markers, num);

      begin = marker.ptr;

      if (begin == cmt_string::npos) break;

      end_pattern = marker.pattern;
      start = begin + marker.intro;

      end = text.find (start, end_pattern);
      if (end == cmt_string::npos)
        {
          // The pattern is a fake one (no ending!)
          start++;
          continue;
        }

      // This should never happen...
      if (end < begin) break;

      // Extract the complete pattern
      text.substr (begin, end - begin + 1, pattern);

      // Then only the macro name
      text.substr (begin + marker.intro, end - begin - marker.intro, symbol_name);

      if (text[begin] == '`')
        {
          cmt_string command = symbol_name;
          resolve_value (command);

            // The macro value is a shell command that first needs
            // to be applied. The output of the command is substituted

          cmt_string result;

          Symbol::all_set ();
          CmtSystem::execute (command, result);
          
          int pos;
          pos = result.find ('\n');
          if (pos != cmt_string::npos) result.erase (pos);
          pos = result.find ('\r');
          if (pos != cmt_string::npos) result.erase (pos);
          
          if (Cmt::get_debug ())
            {
              cout << "   Executing [" << command << "] to expand a macro value =>[" 
                   << result << "]" << endl;
            }
          
          text.replace_all (pattern, result);

          // The substitution will restart from the same place
          // allowing for recursive replacements
          start = begin;
        }
      else
        {
          cmt_string new_pattern;

          new_pattern = "$(";
          new_pattern += symbol_name;
          new_pattern += ")";

          text.replace (pattern, new_pattern);

          start = begin;
        }
    }
}

//-------------------------------------------------------------
/*                                                          */
/*  Operations on SymbolValues                              */
/*                                                          */
//-------------------------------------------------------------

//-------------------------------------------------------------
SymbolValue::SymbolValue ()
{
  tag = 0;
}

//-------------------------------------------------------------
SymbolValue::~SymbolValue ()
{
  tag = 0;
}

//-------------------------------------------------------------
/*                                                          */
/*  Operations on Symbols                                   */
/*                                                          */
//-------------------------------------------------------------

//-------------------------------------------------------------
Symbol* Symbol::create (const cmt_string& name,
                        CommandType command,
                        Use* use)
{
  static SetBuilder Set;
  static PathBuilder Path;
  static MacroBuilder Macro;
  static ScriptBuilder Script;
  static ActionBuilder Action;

  static SymbolVector& Symbols = symbols ();
  static SymbolMap& SymbolMap = symbol_map ();

  SymbolType type = SymbolUndefined;

  switch (command)
    {
    case CommandSet:
    case CommandSetAppend:
    case CommandSetPrepend:
    case CommandSetRemove:
    case CommandSetRemoveRegexp:
      type = SymbolSet;
      break;
    case CommandPath:
    case CommandPathAppend:
    case CommandPathPrepend:
    case CommandPathRemove:
    case CommandPathRemoveRegexp:
      type = SymbolPath;
      break;
    case CommandMacro:
    case CommandMacroAppend:
    case CommandMacroPrepend:
    case CommandMacroRemove:
    case CommandMacroRemoveRegexp:
    case CommandMacroRemoveAll:
    case CommandMacroRemoveAllRegexp:
      type = SymbolMacro;
      break;
    case CommandAction:
      type = SymbolAction;
      break;
    case CommandAlias:
      type = SymbolAlias;
      break;
    case CommandSetupScript:
      type = SymbolSetupScript;
      break;
    case CommandCleanupScript:
      type = SymbolCleanupScript;
      break;
    }

  {
    Symbol* symbol;

    symbol = find (name);
    if (symbol != 0) 
      {
        if (symbol->type != type)
          {
            ActionType action = Cmt::get_action ();

            if ((!Cmt::get_quiet ()) &&
                (action != action_build_constituents_config) &&
                (action != action_build_constituent_config))
              {
                cmt_string s1;
                cmt_string s2;

                switch (symbol->type)
                  {
                  case SymbolSet:
                    s1 = "set";
                    break;
                  case SymbolPath:
                    s1 = "path";
                    break;
                  case SymbolMacro:
                    s1 = "macro";
                    break;
                  case SymbolSetupScript:
                    s1 = "setup_script";
                    break;
                  case SymbolCleanupScript:
                    s1 = "cleanup_script";
                    break;
                  case SymbolAction:
                    s1 = "action";
                    break;
                  case SymbolAlias:
                    s1 = "alias";
                    break;
                  } 

                switch (type)
                  {
                  case SymbolSet:
                    s2 = "set";   
                    break;
                  case SymbolPath:
                    s2 = "path";   
                    break;
                  case SymbolMacro:
                    s2 = "macro";   
                    break;
                  case SymbolSetupScript:
                    s2 = "setup_script";  
                    break;
                  case SymbolCleanupScript:
                    s2 = "cleanup_script";  
                    break;
                  case SymbolAction:
                    s2 = "action";
                    break;
                  case SymbolAlias:
                    s2 = "alias";
                    break;
                  } 
		// <PACKAGE>ROOT macro is defined in 
		// Use::fill_standard_macros <- SyntaxParser::parse_requirements
		// "cmt -requirements setup" may generate <PACKAGE>ROOT set
		// hence, warning
		// Symbol <PACKAGE>ROOT inconsistently redeclared from macro to set in package <package>
		// below, we suppress the warning for current package
		if (use != &(Use::current()) ||
		    (Use::current().prefix + "ROOT") != name ||
		    symbol->type != SymbolMacro ||
		    type != SymbolSet)
		  CmtMessage::warning ("Symbol " + name 
				       + " inconsistently redeclared from " + s1
				       + " to " + s2
				       + ( (use != 0) ?
					   " in package " + use->get_package_name () :
					   "" )
				       );
		/*
                cerr << "#CMT> Warning: Symbol " << name 
                     << " inconsistently redeclared from " << s1 << " to " << s2;
                if (use != 0) cerr << " in package " << use->get_package_name ();
                cerr << endl;
		*/
              }
          }

        return (symbol);
      }
  }

  Symbol& symbol = Symbols.add ();
  SymbolMap.add (name, symbol);

  symbol.name  = name;
  symbol.scope = use->get_current_scope ();
  symbol.type  = type;

  symbol.value_lists.clear ();

  switch (type)
    {
    case SymbolSet:
      symbol.builder = &Set;
      break;
    case SymbolPath:
      symbol.builder = &Path;
      break;
    case SymbolAlias:
      symbol.builder = &Set;
      break;
    case SymbolMacro:
      symbol.builder = &Macro;
      break;
    case SymbolSetupScript:
    case SymbolCleanupScript:
      symbol.builder = &Script;
      break;
    case SymbolAction:
      symbol.builder = &Action;
      break;
    }

  symbol.selected_value = -1;
  symbol.printed = false;

  return (&symbol);
}

//-------------------------------------------------------------
Symbol* Symbol::find (const cmt_string& name)
{
  static SymbolMap& SymbolMap = symbol_map ();

  Symbol* result = 0;

  result = SymbolMap.find (name);

  return (result);
}

//-------------------------------------------------------------
int Symbol::symbol_number ()
{
  static SymbolVector& Symbols = symbols ();

  return (Symbols.size ());
}

//-------------------------------------------------------------
Symbol::SymbolVector& Symbol::symbols ()
{
  static Database& db = Database::instance ();
  static SymbolVector& Symbols = db.symbols ();

  return (Symbols);
}

//-------------------------------------------------------------
Symbol::SymbolMap& Symbol::symbol_map ()
{
  static Database& db = Database::instance ();
  static SymbolMap& SymbolMap = db.symbol_map ();

  return (SymbolMap);
}

/**
   Filter out faulty items of a path-like symbol value
 */
void Symbol::filter_path_value (const cmt_string& name, cmt_string& text)
{

  CmtSystem::cmt_string_vector paths;
  CmtSystem::cmt_string_vector normalyzed_paths;   
                  
  CmtSystem::split (text, CmtSystem::path_separator (), paths);
                  
  for (int j = 0; j < paths.size (); ++j)
    {
      cmt_string& t = paths[j];

	    /*
	if (!CmtSystem::test_directory (t))
	      if (Cmt::get_warnings ())
	      {
	          cerr << "#CMT> Warning: Wrong path item " << t << " in " << name << endl;
	      }
	    */
	    
      int exist = 0;  
      for (int i = 0; i < j; ++i)
      {
          cmt_string& u = paths[i];
          if (u == t)
	    {
	      exist = 1;
	      break;
	    }
      }	  	  
      if (exist==0)
      {
          cmt_string& s = normalyzed_paths.add ();
          s = t;
	  if (CmtMessage::active (Verbose))
	    if (!CmtSystem::test_directory (t))
	      {
		CmtMessage::warning ("Non-existent directory " + t + " in " + name);
	      }
      }
    }
   
  Cmt::vector_to_string (normalyzed_paths, CmtSystem::path_separator (), text);

  for (;;)
    {
      int sz = text.size ();

      if (sz == 0) break;

      if ((text[0] == ';') || (text[0] == ':'))
	{
	  text.erase (0, 1);
	}
      else if ((text[sz-1] == ';') || (text[sz-1] == ':'))
	{
	  text.erase (sz-1, 1);
	}
      else
	{
	  break;
	}
    }

  text.replace_all ("::", ":");
  text.replace_all (";;", ";");
}


//-------------------------------------------------------------
Symbol& Symbol::symbol (int index)
{
  static SymbolVector& Symbols = symbols ();

  return (Symbols[index]);
}

//-------------------------------------------------------------
void Symbol::action (const CmtSystem::cmt_string_vector& words,
                     CommandType command_type,
                     Use* use)
{
  int number;
  Symbol* symbol;
  Tag* tag;

  if (words.size () < 1) return;
  cmt_string name = words[1];

  if ((command_type == CommandSetupScript) ||
      (command_type == CommandCleanupScript))
    {
      cmt_string full_name;

      Symbol::expand (name);

      if (name != "")
        {
          if (CmtSystem::absolute_path (name)) 
            {
              full_name = name;
            }
          else
            {
	      if (use->get_strategy ("SetupRoot") &&
		  use->get_package_name () != "cmt_standalone")
		{
#ifdef WIN32
              full_name = "%";
#else
              full_name = "${";
#endif
              full_name += CmtSystem::mangle (use->prefix);
              full_name += "ROOT";
#ifdef WIN32
              full_name += "%";
#else
              full_name += "}";
#endif
		}
	      else
		{
              full_name = use->get_full_path ();
		}
              if (use->style == cmt_style)
		{
		  full_name += CmtSystem::file_separator ();
		  full_name += "cmt";
		}
              else if (use->style == mgr_style)
		{
		  full_name += CmtSystem::file_separator ();
		  full_name += "mgr";
		}
	      //              else if (use->style == no_version_style) full_name += "cmt";
	      //              else full_name += "mgr";
              full_name += CmtSystem::file_separator ();
              full_name += name;
            }

          symbol = create (full_name, command_type, use);
          symbol->add_value_to_list (command_type, use,
                                     Tag::get_default (), full_name);
        }
    }
  else
    {
      if (words.size () < 2) return;
      const cmt_string& default_value = words[2];

      Cmt::reset_all_sets_done ();

      if (Cmt::get_debug ())
	{
	  cout << "Symbol::action> name:" << name 
	       << " access:" << Cmt::get_current_access () 
	       << " scope:" << use->get_current_scope () << endl;
	}

      if (Cmt::get_current_access () == UserMode)
	{
	  /*
	    The following statements mean that some symbols are 
	    always private.
	    This list is hardcoded. This should be replaced by a
	    database of "private" symbols.
	   */
	  if (name == "constituents") return;
	  if (name == "constituentscclean") return;

          if (use->get_current_scope () == ScopePrivate) return;
	}

      symbol = create (name, command_type, use);

      /*
        Parse the default value.
      */
      
      symbol->add_value_to_list (command_type, use,
                                 Tag::get_default (), default_value);
      
      /*
        Then parse all specific values
        
        <tag> <value>
        ...
      */
      
      number = 3;
      while (number < (words.size () - 1))
        {
          cmt_string tag_name = words[number];
          const cmt_string& value = words[number + 1];

	  expand (tag_name);

	  if (Cmt::get_debug ())
	    {
	      cout << "Symbol::action> tag_name=" << tag_name << endl;
	    }

	  tag = Tag::find (tag_name);
	  if (tag == 0)
	    {
	      tag = Tag::add (tag_name, PriorityUserTag, "use", use);
	    }

          symbol->add_value_to_list (command_type, use, tag, value);
          
          number += 2;
        }

      if (name == "CMTPATH")
        {
          Cmt::configure_cmt_path (use);
        }
      else if (name == "CMTPROJECTPATH")
        {
          Cmt::configure_cmt_path (use);
        }
      else if (name == "CMTSITE")
        {
          Cmt::configure_site_tag (use);
        }
      else if (name == "CMTCONFIG")
        {
            //cerr << "redefining CMTCONFIG" << endl;
          Cmt::configure_tags (use);
        }
      else if (name == "CMTHOME")
        {
          Cmt::configure_home (use);
        }
      else if (name == "CMTUSERCONTEXT")
        {
          Cmt::configure_user_context (use);
        }
      else if (name.find ("_native_version") != cmt_string::npos)
        {
          cmt_string n = use->get_package_name ();
          n += "_native_version";

          if (name == n)
            {
              use->set_native_version (true);
            }
        }
    }
}

//-------------------------------------------------------------
int Symbol::is_selected (const cmt_string& name)
{
  Symbol* symbol;
  int number;
  int value_number;

  symbol = find (name);
  if (symbol == 0) return (0);

  if (symbol->value_lists.size () == 0) return (0);

  for (number = 0;
       number < symbol->value_lists.size ();
       number++)
    {
      const SymbolValueList& value_list = symbol->value_lists[number];

      if (value_list.discarded) continue;

      if ((value_list.command_type == CommandMacro) ||
          (value_list.command_type == CommandSet) ||
          (value_list.command_type == CommandSetAppend) ||
          (value_list.command_type == CommandSetPrepend) ||
          (value_list.command_type == CommandSetRemove) ||
          (value_list.command_type == CommandSetRemoveRegexp) ||
          (value_list.command_type == CommandAlias) ||
          (value_list.command_type == CommandAction))
        {
          for (value_number = 0;
               value_number < value_list.values.size ();
               value_number++)
            {
              Tag* tag;

              SymbolValue& value = value_list.values[value_number];

              tag = value.tag;
              if ((tag == 0) ||
                  (tag == Tag::get_default ()) ||
                  (tag->is_selected () != 0))
                {
                  return (1);
                }
            }
        }
    }

  return (0);
}

//-------------------------------------------------------------
Symbol::Symbol ()
{
  name = "";
}

//-------------------------------------------------------------
Symbol::~Symbol ()
{
}

/**
 *  Characterizes if a value is provided as the reference to itself. 
 */
bool Symbol::value_is_reflexive (const cmt_string& text) const
{
  bool result = false;
  int text_length = text.size ();

  if (text_length == (name.size () + 3))
    {
      static cmt_string temp;
              
      if (text[0] == '$')
        {
          if (text[1] == '(')
            {
              temp = "$(";
              temp += name;
              temp += ")";
              
              if (text == temp)
                {
                  result = true;
                }
            }
          else if (text[1] == '{')
            {
              temp = "${";
              temp += name;
              temp += "}";
              
              if (text == temp)
                {
                  result = true;
                }
            }
        }
    }
  else if (text_length == (name.size () + 2))
    {
      static cmt_string temp;

      temp = "%";
      temp += name;
      temp += "%";

      if (text == temp)
        {
          result = true;
        }
    }

  return (result);
}

//-------------------------------------------------------------
void Symbol::add_value_to_list (CommandType command_type,
                                Use* use,
				Tag* tag,
                                const cmt_string& text)
{
  SymbolValueList* value_list = 0;
  bool is_reflexive = false;

    //
    // First pickup the most recent value_list
    //
  if (value_lists.size () > 0) value_list = &(value_lists.back ());

    //
    //  Create a new value list is we switch to another use or
    //  if we switch to a new command_type (eg. switching from
    //  macro to macro_append).
    //
  if ((value_list == 0) ||
      (use != value_list->use) ||
      (command_type != value_list->command_type) ||
      (tag == Tag::get_default ()))
    {
      value_list = &(value_lists.add ());
      value_list->use = use;
      value_list->command_type = command_type;
      value_list->values.clear ();
      value_list->discarded = false;
      value_list->is_reflexive = false;
    }

/*
  else
    {
        value_list = &(value_lists[value_lists.size () - 1]);
    }
*/

  is_reflexive = value_list->is_reflexive;

    //
    //  If the command_type is command_macro or command_set, 
    // this is considered as a full re-set of this symbol 
    //   In this case, we have to discard all previous values
    //
    //  However, we'd like to exclude from this logic the cases where
    //  the value is **exactly* 
    //
    //     $(<symbol>)
    //     ${<symbol>}
    //     %<symbol>%
    //
    //   which would then mean that we do not reset the value but rather
    //  override it.
    //

    //
    // Inside this value_list, we add this new tag-value pair.
    //

  if ((command_type == CommandMacro) ||
      (command_type == CommandSet) ||
      (command_type == CommandPath) ||
      (command_type == CommandAction))
    {
        //
        // Check whether we have to hide previous settings by this new definition
        //  (of course this is only useful if there WERE previous settings)
        //
      if ((value_lists.size () >= 1) && (!is_reflexive))
        {
          if (value_is_reflexive (text))
            {
              value_list->is_reflexive = true;
              is_reflexive = true;
            }
          else
            {
	      //cerr << "...discarding old values for symbol " << name << " text=[" << text << "]" << endl;
                  
              for (int i = 0; i < (value_lists.size () - 1); i++)
                {
                  SymbolValueList& vl = value_lists[i];
                  
                  if ((vl.use != 0) &&
                      (vl.use->discarded))
		    {
                      //vl.discarded = true;
		    }
                }
            }
        }
    }

  SymbolValue& value = value_list->values.add ();

  value.tag = tag;
  value.text = text;
  value.selected = 0;
}

/**
   Compute the current value of all environment variables and set them to the
   shell
 */
void Symbol::all_set ()
{
  //cerr << "all_set" << endl;

  static bool running = false;


  if (Cmt::get_debug ())
    {
      cout << "\nSymbol::all_set> done=" << running << endl;
    }

  if (Cmt::get_all_sets_done ()) return;

  if (running) return;

  running = true;
  Cmt::set_all_sets_done ();

  static SymbolVector& Symbols = symbols ();
  Use::UsePtrVector& Uses = Use::get_ordered_uses ();

  int number;

  if (Symbols.size () == 0) 
    {
      running = false;
      return;
    }

  cmt_string value;

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

      if (symbol.type != SymbolSet) continue;

      value = symbol.build_macro_value ();
      if (value != "")
	{
	  Symbol::expand (value);

	  CmtSystem::putenv (symbol.name, value);
	}
    }

  cmt_string cmtconfig = CmtSystem::get_cmt_config ();

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

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

          if (use.discarded) continue;

	  if (use.get_package_name () == "cmt_standalone") continue;

	  if (use.get_strategy ("SetupConfig"))
	    {
	      cmt_string temp;

	      temp = use.prefix;
	      temp += "CONFIG";

	      CmtSystem::putenv (temp, cmtconfig);
	    }

	  if (use.get_strategy ("SetupRoot"))
	    {
	      cmt_string temp;

	      temp = use.prefix;
	      temp += "ROOT";

	      CmtSystem::putenv (temp, use.get_full_path ());
	    }
        }
    }

  {
    Use& use = Use::current ();

    if (use.get_package_name () != "cmt_standalone")
      {
	if (use.get_strategy ("SetupConfig"))
	  {
	    cmt_string temp;

	    temp = use.prefix;
	    temp += "CONFIG";

	    CmtSystem::putenv (temp, cmtconfig);
	  }
	
	if (use.get_strategy ("SetupRoot"))
	  {
	    cmt_string temp;

	    temp = use.prefix;
	    temp += "ROOT";

	    CmtSystem::putenv (temp, use.get_full_path ());
	  }
      }
  }

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

      if ((symbol.type != SymbolPath)) continue;

      value = symbol.build_macro_value ();
      if (value != "")
	{
	  Symbol::expand (value);
	  filter_path_value (symbol.name, value);

#ifdef WIN32
	  value.replace_all ("/", "\\");
#endif

          if (Cmt::get_debug ())
            {
              cerr << "Symbol::all_set-2> " << symbol.name << " = " << value << endl;
            }

	  CmtSystem::putenv (symbol.name, value);
	}
    }

  running = false;
}

//-------------------------------------------------------------
void Symbol::all_print (PrintMode mode)
{
  static SymbolVector& Symbols = symbols ();

  int number;

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

  switch (mode)
    {
    case Requirements :
      for (number = 0; number < Symbol::symbol_number (); number++)
	{
	  Symbol& symbol = Symbol::symbol (number);

	  if ((symbol.type == SymbolSet) ||
	      (symbol.type == SymbolAlias) ||
	      (symbol.type == SymbolSetupScript) ||
	      (symbol.type == SymbolPath) ||
	      (symbol.type == SymbolMacro))
	    {
	      if (symbol.print_macro (mode))
		{
		  //		  cout << endl;
		}
	    }
	}
      break;
    default :
      for (number = 0; number < Symbol::symbol_number (); number++)
	{
	  Symbol& symbol = Symbol::symbol (number);
	  
	  if ((symbol.type == SymbolSet) ||
	      (symbol.type == SymbolAlias) ||
	      (symbol.type == SymbolSetupScript) ||
	      (symbol.type == SymbolPath))
	    {
	      if (symbol.print (mode))
		{
		  if (mode == Bat)
		    {
		      cout << endl;
		    }
		  else if (mode == Xml)
		    {
		      //		      cout << endl;
		    }
		  else
		    {
		      cout << endl;
		    }
		}
	    }
	}
      break;
    }
}

//-------------------------------------------------------------
void Symbol::check_all_paths ()
{
  static SymbolVector& Symbols = symbols ();

  int number;

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

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

      if (symbol.type == SymbolPath)
        {
	  cmt_string temp;

	  temp = symbol.build_macro_value ();
	  expand (temp);

	  Symbol::filter_path_value (symbol.name, temp);
        }
    }
}

//-------------------------------------------------------------
void Symbol::all_print_clean (PrintMode mode)
{
  static SymbolVector& Symbols = symbols ();

  int number;

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

  for (number = Symbols.size () - 1; number >= 0; number--)
    {
      Symbol& symbol = Symbols[number];

      if ((symbol.type == SymbolSet) ||
          (symbol.type == SymbolAlias) ||
          (symbol.type == SymbolCleanupScript))
        {
          if (symbol.print_clean (mode))
            {
              cout << endl;
            }
        }
    }

  for (number = Symbols.size () - 1; number >= 0; number--)
    {
      Symbol& symbol = Symbols[number];

      if ((symbol.type != SymbolPath)) continue;

      if (symbol.print_clean (mode))
        {
          cout << endl;
        }
    }
}

//-------------------------------------------------------------
int Symbol::print_clean (PrintMode mode)
{
  int result = 0;
  static cmt_string temp;

  if (name == "CMTCONFIG") return (0);

  cmt_string _name;
  switch (type)
    {
    case SymbolSet :
    case SymbolPath :
      if (0 != CmtSystem::mangle (name, _name))
	CmtMessage::info ("Replace " + name + " with " + _name);
      break;
    }

  switch (type)
    {
    case SymbolSet :
      switch (mode)
        {
        case Csh :
          cout << "unsetenv " << _name;
          result = 1;
          break;
        case Sh :
          cout << "[ -z ${" << _name << "+CMT} ] || unset " << _name;
	  //          cout << "unset " << _name;
          result = 1;
          break;
        case Bat :
          cout << "set " << _name << "=";
          result = 1;
          break;
        }
      break;
    case SymbolAlias :
      switch (mode)
        {
          case Csh :
            cout << "unalias " << name;
            result = 1;
            break;
          case Sh :
	    cout << "[ -z ${" << name << "+CMT} ] || unset " << name;
	  //            cout << "unset " << name;
            result = 1;
            break;
        }
      break;
    case SymbolPath :
      temp = clean_macro_value ();
      switch (mode)
        {
        case Csh :
	  if (temp == "")
	    {
	      cout << "unsetenv " << _name;
	    }
	  else
	    {
	      cout << "setenv " << _name << " " << CmtSystem::quote (temp, " \t");
	    }
          result = 1;
          break;
        case Sh :
          cout << _name << "=" << CmtSystem::quote (temp, " \t") << "; export " << _name;
          result = 1;
          break;
        case Bat :
          cout << "set " << _name << "=" << CmtSystem::quote (temp, " \t");
          result = 1;
          break;
        }
      break;
    case SymbolCleanupScript :
      switch (mode)
        {
        case Csh :
          cout << "if ( -f " << CmtSystem::quote (name, " \t") << ".csh ) then" << endl;
          cout << "  source " << CmtSystem::quote (name, " \t") << ".csh" << endl;
          cout <<
	    "if ( $status != 0 ) then\n"
	    "    set cmtcleanupstatus=1\n"
	    "endif\n";
          cout << "endif" << endl;
          result = 1;
          break;
        case Sh :
          cout << "if test -f " << CmtSystem::quote (name, " \t") << ".sh; then" << endl;
          cout << "  . " << CmtSystem::quote (name, " \t") << ".sh" << endl;
          cout <<
	    "if test $? != 0; then\n"
	    "    cmtcleanupstatus=1\n"
	    "fi\n";
          cout << "fi" << endl;
          result = 1;
          break;
        case Bat :
          cout << "call " << CmtSystem::quote (name, " \t");
          result = 1;
          break;
        }
      break;
    }

  return (result);
}

//-------------------------------------------------------------
int Symbol::print (PrintMode mode)
{
  int result = 0;

  cmt_string temp = build_macro_value ();
  bool empty = (temp.size () == 0) ? true : false;

  if (type == SymbolPath)
    {
      expand (temp);
      Symbol::filter_path_value (name, temp);
    }

  cmt_string _name;
  switch (type)
    {
      case SymbolSet :
      case SymbolPath :
	if (0 != CmtSystem::mangle (name, _name))
	  CmtMessage::info ("Replace " + name + " with " + _name);
        switch (mode)
          {
            case Csh :
              if (empty) cout << "unsetenv " << _name;
              else cout << "setenv " << _name << " \"" << temp << "\"";
              //else cout << "setenv " << name << " " << CmtSystem::quote (temp, " \t");

              result = 1;
              break;
            case Sh :
              if (empty) cout << "[ -z ${" << _name << "+CMT} ] || unset " << _name;
	      //              if (empty) cout << "unset " << _name;
              else cout << _name << "=\"" << temp << "\"; export " << _name;
              //else cout << name << "=" << CmtSystem::quote (temp, " \t") << "; export " << name;

              result = 1;
              break;
            case Bat :
              temp.replace_all ("/", "\\");
              cout << "set " << _name << "=" << CmtSystem::quote (temp, " \t");
              //cout << "set " << name << "=" << temp;
              result = 1;
              break;
            case Xml :
              cout << "<variable><name>" << _name << "</name>"
		   << "<value>" << temp << "</value></variable>";
              result = 1;
              break;
          }
        break;
      case SymbolAlias :
        switch (mode)
          {
            case Csh :
              cout << "alias " << name <<
		" \"" << temp << "\"";
	      //CmtSystem::quote (temp, " \t");
              result = 1;
              break;
            case Sh :
              cout << "alias " << name <<
		"=\"" << temp << "\"";
	      //"=" << CmtSystem::quote (temp, " \t");
              result = 1;
              break;
            case Bat :
              cout << "set " << name <<
		"=" << CmtSystem::quote (temp, " \t");
	      //"=" << temp;
              result = 1;
              break;
            case Xml :
              cout << "<alias><name>" << name << "</name>"
		   << "<value>" << temp << "</value></alias>";
              result = 1;
              break;
          }
        break;
      default :
        break;
    }

  if (temp != "")
    {
      switch (type)
        {
          case SymbolSetupScript :
            switch (mode)
              {
                case Csh :
                  cout << "if ( -f " << CmtSystem::quote (name, " \t") << ".csh ) then" << endl;
                  cout << "  source " << CmtSystem::quote (name, " \t") << ".csh" << endl;
                  cout <<
		    "if ( $status != 0 ) then\n"
		    "    set cmtsetupstatus=1\n"
		    "endif\n";
                  cout << "endif" << endl;
                  result = 1;
                  break;
                case Sh :
                  cout << "if test -f " << CmtSystem::quote (name, " \t") << ".sh; then" << endl;
                  cout << "  . " << CmtSystem::quote (name, " \t") << ".sh" << endl;
                  cout <<
		    "if test $? != 0; then\n"
		    "    cmtsetupstatus=1\n"
		    "fi\n";
                  cout << "fi" << endl;
                  result = 1;
                  break;
                case Bat :
                  cout << "call " << CmtSystem::quote (name, " \t");
                  result = 1;
                  break;
                case Xml :
                  cout << "<script>" << name << "</script>";
                  result = 1;
                  break;
              }
            break;
          default:
            break;
        }
    }

  return (result);
}

//-------------------------------------------------------------
cmt_string Symbol::build_macro_value (bool display_it) const
{
  cmt_string temp;

  if (display_it)
    {
      temp = builder->build_and_display (*this);
    }
  else
    {
      temp = builder->build (*this);
    }

  return (temp);
}

//-------------------------------------------------------------
int Symbol::print_macro (PrintMode mode, ostream& out) const
{
  if (mode != Requirements || printed) return 0;
  return builder->print (*this, out);
}

//-------------------------------------------------------------
cmt_string Symbol::clean_macro_value () const
{
  cmt_string temp;

  temp = builder->clean (*this);

  return (temp);
}

/**

   Attempt to substitute into the symbol value all occurrences of

      ${xxx}
      $(xxx)
      `xxx`
      %xxx%    [on Windows only]

      by the appropriate value:

        for `xxx` : 

            xxx is considered as a shell command. Value is the result of its execution

        for other patterns:

            if xxx is a symbol name, its value is substituted to the pattern
            otherwise, xxx is tried as an environment variable


     ===> In all cases, the pattern is filtered away.

  */
cmt_string Symbol::resolve_macro_value (const cmt_string& tag_name) const
{
  cmt_string temp = builder->build (*this, tag_name);

  resolve_value (temp);

  return (temp);
}

//-------------------------------------------------------------
void Symbol::show_macro (PrintMode mode, ostream& out)
//void Symbol::show_macro (PrintMode mode)
{
  if (Cmt::get_debug ())
    {
      cout << "Symbol::show_macro> " << name << endl;
    }

  ActionType action = Cmt::get_action ();

  cmt_string value = build_macro_value (true);

  if ((!Cmt::get_quiet ()) &&
      (action != action_build_tag_makefile) &&
      (action != action_build_constituents_config) &&
      (action != action_build_constituent_config) &&
      (action != action_build_broadcast_config) &&
      (action != action_show_macros) &&
      (action != action_show_actions) &&
      (action != action_show_aliases) &&
      (action != action_show_sets))
    {
      out << "#" << endl;
      out << "# Selection : " << endl;
    }

  if (value.size () > 0)
    {
      if ((action == action_show_macro) ||
          (action == action_show_macros) ||
          (action == action_show_sets) ||
          (action == action_show_set) ||
          (action == action_show_actions) ||
          (action == action_show_action) ||
          (action == action_show_alias) ||
          (action == action_show_aliases) ||
          (action == action_build_tag_makefile) ||
          (action == action_build_constituents_config) ||
          (action == action_build_constituent_config) ||
          (action == action_build_broadcast_config) ||
          (action == action_load) ||
          (!Cmt::get_quiet ()))
        {
          if (mode == Make)
            {
              out << name << "=";
            }
          else
            {
              out << name << "='";
            }
        }

      if ((action == action_show_macro_value) ||
          (action == action_show_set_value) ||
          (action == action_show_action_value) ||
          (action == action_show_alias_value))
        {
          expand (value);
        }
      else if (action == action_build_tag_makefile ||
	       action == action_build_constituents_config ||
	       action == action_build_constituent_config ||
	       action == action_build_broadcast_config)
        {
            /* 
               Unfortunately, the %xxx% pattern has to be kept on Unix. Therefore
               we cannot force all patterns to become $(xxx)

               This was useful on Windows so as to only keep $(xxx)
             */
#ifdef WIN32
	  suppress_OS_delimiters (value);
#endif
        }

      out << value;

      if ((action == action_show_macro) ||
          (action == action_show_macros) ||
          (action == action_show_sets) ||
          (action == action_show_set) ||
          (action == action_show_actions) ||
          (action == action_show_action) ||
          (action == action_show_alias) ||
          (action == action_show_aliases) ||
          (action == action_build_tag_makefile) ||
          (action == action_build_constituents_config) ||
          (action == action_build_constituent_config) ||
          (action == action_build_broadcast_config) ||
          (action == action_load) ||
          (!Cmt::get_quiet ()))
        {
          if (mode != Make)
            {
              out << "'";
            }
#ifdef WIN32
	  else
	    {
              out << " ";
	    }
#endif
        }

      out << endl;
    }
}

//-------------------------------------------------------------
void Symbol::clear_all ()
{
  static SymbolVector& Symbols = symbols ();
  static SymbolMap& SymbolMap = symbol_map ();

  SymbolMap.clear ();
  Symbols.clear ();
}

//-------------------------------------------------------------
void Symbol::expand (cmt_string& text)
{
  static cmt_regexp reg ("[$%`]");

  if (!reg.match (text)) return;

  resolve_value (text);
}

//-------------------------------------------------------------
ValueBuilder::ValueBuilder ()
{
  m_display_it = false;
}

//-------------------------------------------------------------
const cmt_string ValueBuilder::build_and_display (const Symbol& symbol)
{
  cmt_string temp;

  m_display_it = true;
  temp = build (symbol);
  m_display_it = false;

  return (temp);
}

//-------------------------------------------------------------
int ValueBuilder::print (const Symbol& symbol, ostream& out)
{
  int result (0);

  bool first_definition = true;
  
  for (int i = 0; i < symbol.value_lists.size (); i++)
    {
      const SymbolValueList& value_list = symbol.value_lists[i];

      if ((value_list.use != 0) &&
          (value_list.use->discarded)) continue;

      const int selected = value_list.select_first ();

      if (selected < 0) continue;

      SymbolValue& value = value_list.values[selected];

      result += value_list.print (symbol, value, first_definition);
    }

  return result;
}

//-------------------------------------------------------------
const cmt_string SetBuilder::build (const Symbol& symbol,
                                    const cmt_string& /*tag_name*/)
{
    // Control of recursivity
  static int level = 0;

  bool show_it = false;

  cmt_string temp;
  cmt_string previous_temp;
  cmt_string new_value;
  static const cmt_string empty;

  ActionType action = Cmt::get_action ();

  if (action == action_show_set)
    {
      if (symbol.name == Cmt::get_current_target ())
        {
             // Should not display on recursive calls
          if (level == 0) show_it = m_display_it;
        }
    }

  level++;

  temp = "";

  bool first_definition = true;

  for (int i = 0; i < symbol.value_lists.size (); i++)
    {
      const SymbolValueList& value_list = symbol.value_lists[i];

      if ((value_list.use != 0) &&
          (value_list.use->discarded)) continue;

      const int selected = value_list.select_first ();

      if (selected < 0) continue;

      SymbolValue& value = value_list.values[selected];

      if (show_it && !Symbol::get_inhibit_display())
        {
          value_list.show (symbol, value, first_definition);
        }
      
      if (value_list.discarded) continue;

        //
        // One should accumulate values if it refers to
        // itself.
        //
      
      new_value = value.text;
      
      resolve_value_for_macros (new_value);
      
      switch (value_list.command_type)
        {
          case CommandSet :

            if (!value_list.is_reflexive || 
                !symbol.value_is_reflexive (value.text))
              {
                resolve_value (new_value, symbol.name, temp);
                temp = new_value;
              }
            else if (temp == "")
              {
                temp = CmtSystem::getenv (symbol.name);
              }

            break;
          case CommandSetAppend :
            
            if (new_value != "")
              {
                temp += new_value;
              }
            
            break;
          case CommandSetPrepend :
            
            if (new_value != "")
              {
                previous_temp = temp;
                temp = new_value;
                temp += previous_temp;
              }
            
            break;
          case CommandSetRemove :
            
            if (new_value != "")
              {
                temp.replace_all (new_value, empty);
              }
            
            break;
          case CommandSetRemoveRegexp :
            
            if (new_value != "")
              {
		cmt_regexp e (new_value);
		cmt_regexp::iterator it;

		for (;;)
		  {
		    it = e.begin (temp);
		    if (it == e.end ()) break;

		    temp.erase (it._pos, it._length);
		  }
              }
            
            break;
          case CommandAlias :
            
            resolve_value (new_value, symbol.name, temp);
            temp = new_value;
            
            break;
        }
    }

  level--;

  return (temp);
}

static bool find_path_entry (const CmtSystem::cmt_string_vector& items, const cmt_string& value)
{
  static const cmt_string path_separator = CmtSystem::path_separator ();
  static cmt_vmap <cmt_string, cmt_string> realpaths;

  if (value.size () == 0) return true;

  cmt_string rvalue;
  const cmt_string * prvalue;

  if (!(prvalue = realpaths.find (value)))
    {
      if (!CmtSystem::realpath_ (value, rvalue))
	{
	  rvalue = value;
	  CmtSystem::compress_path (rvalue);
	}
      prvalue = &rvalue;
      realpaths.add (value, rvalue);
      //      cerr << "realpaths.add: " << value << " , " << rvalue << endl;
    }

  //  CmtSystem::cmt_string_vector items;
  //  CmtSystem::split (paths, path_separator, items);

  bool found = false;

  for (int i = 0; i < items.size (); i++)
    {
      const cmt_string& item = items[i];
      if (item.size () == 0) continue;
      cmt_string ritem;
      const cmt_string * pritem;

      if (!(pritem = realpaths.find (item)))
	{
	  if (!CmtSystem::realpath_ (item, ritem))
	    {
	      ritem = item;
	      CmtSystem::compress_path (ritem);
	    }
	  pritem = &ritem;
	  realpaths.add (item, ritem);
	  //  cerr << "realpaths.add: " << item << " , " << ritem << endl;
	}
      if (*pritem == *prvalue)
	{
	  found = true;
	  break;
	}
    }

  return (found);
}

static bool find_path_entry (const cmt_string& paths, const cmt_string& value)
{
  static const cmt_string path_separator = CmtSystem::path_separator ();
  static cmt_vmap <cmt_string, cmt_string> realpaths;

  cmt_string rvalue;
  const cmt_string * prvalue;

  if (!(prvalue = realpaths.find (value)))
    {
      if (!CmtSystem::realpath_ (value, rvalue))
	{
	  rvalue = value;
	  CmtSystem::compress_path (rvalue);
	}
      prvalue = &rvalue;
      realpaths.add (value, rvalue);
      //      cerr << "realpaths.add: " << value << " , " << rvalue << endl;
    }

  CmtSystem::cmt_string_vector items;
  CmtSystem::split (paths, path_separator, items);

  bool found = false;

  for (int i = 0; i < items.size (); i++)
    {
      const cmt_string& item = items[i];
      cmt_string ritem;
      const cmt_string * pritem;

      if (!(pritem = realpaths.find (item)))
	{
	  if (!CmtSystem::realpath_ (item, ritem))
	    {
	      ritem = item;
	      CmtSystem::compress_path (ritem);
	    }
	  pritem = &ritem;
	  realpaths.add (item, ritem);
	  //  cerr << "realpaths.add: " << item << " , " << ritem << endl;
	}
      if (*pritem == *prvalue)
	{
	  found = true;
	  break;
	}
    }

  return (found);
}

//-------------------------------------------------------------
const cmt_string PathBuilder::build (const Symbol& symbol,
                                     const cmt_string& /*tag_name*/)
{
    // Control of recursivity
  static int level = 0;

  bool show_it = false;

  cmt_string temp;
  CmtSystem::cmt_string_vector temp_vector;
  //  cmt_string previous_temp;
  CmtSystem::cmt_string_vector new_value_vector;
  cmt_string new_value;
  static const cmt_string empty;

  static cmt_string path_separator = CmtSystem::path_separator ();

  ActionType action = Cmt::get_action ();

  if (action == action_show_set)
    {
      if (symbol.name == Cmt::get_current_target ())
        {
            // Should not display on recursive calls
          if (level == 0) show_it = m_display_it;
        }
    }

  level++;

  CmtSystem::split (CmtSystem::getenv (symbol.name), path_separator, temp_vector);
  //temp = CmtSystem::getenv (symbol.name);

  bool first_definition = true;

  for (int i = 0; i < symbol.value_lists.size (); i++)
    {
      const SymbolValueList& value_list = symbol.value_lists[i];

      if ((value_list.use != 0) &&
          (value_list.use->discarded)) continue;

      const int selected = value_list.select_first ();
      
      if (selected < 0) continue;
 
      SymbolValue& value = value_list.values[selected];
          
      if (show_it && !Symbol::get_inhibit_display())
        {
          value_list.show (symbol, value, first_definition);
        }
          
      if (value_list.discarded) continue;

      new_value = value.text;
          
          //resolve_value (new_value);
      resolve_value_for_macros (new_value);
          
      switch (value_list.command_type)
        {
          case CommandPath :
            
            if (!value_list.is_reflexive || 
                !symbol.value_is_reflexive (value.text))
              {
                Cmt::vector_to_string (temp_vector, path_separator, temp);
                resolve_value (new_value, symbol.name, temp);
		CmtSystem::split (new_value, path_separator, temp_vector);
                //temp = new_value;
              }

            break;
          case CommandPathAppend :
              
            if (new_value != "")
              {
		CmtSystem::split (new_value, path_separator, new_value_vector);
		for (int i = 0; i < new_value_vector.size (); i++)
		  if (!find_path_entry (temp_vector, new_value_vector[i]))
		    //if (!find_path_entry (temp, new_value))
		    {
		      temp_vector.push_back (new_value_vector[i]);
		      /*
			if (temp != "") temp += path_separator;
			
			temp += new_value;
		      */
		    }
              }
                  
            break;
          case CommandPathPrepend :
              
            if (new_value != "")
              {
		CmtSystem::split (new_value, path_separator, new_value_vector);
		int n (new_value_vector.size ());
		temp_vector.resize (temp_vector.size () + n);
		for (int i = temp_vector.size () - 1; i > n - 1; i--)
		  temp_vector [i] = temp_vector [i - n];
		for (int i = 0; i < new_value_vector.size (); i++)
		  if (!find_path_entry (temp_vector, new_value_vector[i]))
		    //if (!find_path_entry (temp, new_value))
		    {
		      temp_vector [i] = new_value_vector[i];
		      /*
			previous_temp = temp;
			temp = new_value;
			if (previous_temp != "") temp += path_separator;
			temp += previous_temp;
		      */
		    }
		  else
		    temp_vector [i] = "";
              }
	    
            break;
          case CommandPathRemove :
              
            if (new_value != "")
              {
                for (int j = 0; j < temp_vector.size (); ++j)
                  {
                    cmt_string& s = temp_vector[j];
                    
                    if (s.find (new_value) != cmt_string::npos)
                      {
                        s = "";
                      }
                  }
		/*
                CmtSystem::cmt_string_vector paths;
                  
                CmtSystem::split (temp, path_separator, paths);
                  
                for (int j = 0; j < paths.size (); ++j)
                  {
                    cmt_string& s = paths[j];
                      
                    if (s.find (new_value) != cmt_string::npos)
                      {
                        s = "";
                      }
                  }

                Cmt::vector_to_string (paths, path_separator, temp);
		*/
              }
              
            break;
          case CommandPathRemoveRegexp :

            if (new_value != "")
              {
		cmt_regexp e (new_value);

                for (int j = 0; j < temp_vector.size (); ++j)
                  {
                    cmt_string& s = temp_vector[j];

		    if (Cmt::get_debug () &&
			CmtSystem::getenv ("TESTPRR") != "")
		      {
			cerr << "PRR> s=[" << s << "]";
		      }

                    if (e.match (s))
                      {
                        s = "";

			if (Cmt::get_debug () &&
			    CmtSystem::getenv ("TESTPRR") != "")
			  {
			    cerr << " match ";
			  }
                      }
		    else
                      {
			if (Cmt::get_debug () &&
			    CmtSystem::getenv ("TESTPRR") != "")
			  {
			    cerr << " no match ";
			  }
                      }

		    if (Cmt::get_debug () &&
			CmtSystem::getenv ("TESTPRR") != "")
		      {
			cerr << endl;
		      }
                  }

		/*
                CmtSystem::cmt_string_vector paths;
                  
                CmtSystem::split (temp, path_separator, paths);
                  
                for (int j = 0; j < paths.size (); ++j)
                  {
                    cmt_string& s = paths[j];

		    if (CmtSystem::getenv ("TESTPRR") != "")
		      {
			cerr << "PRR> s=[" << s << "]";
		      }

                    if (e.match (s))
                      {
                        s = "";

			if (CmtSystem::getenv ("TESTPRR") != "")
			  {
			    cerr << " match ";
			  }
                      }
		    else
                      {
			if (CmtSystem::getenv ("TESTPRR") != "")
			  {
			    cerr << " no match ";
			  }
                      }

		    if (CmtSystem::getenv ("TESTPRR") != "")
		      {
			cerr << endl;
		      }
                  }

                Cmt::vector_to_string (paths, path_separator, temp);
		*/
              }
              
            break;
        }

    }

  Cmt::vector_to_string (temp_vector, path_separator, temp);

  level--;

  for (;;)
    {
      int sz = temp.size ();

      if (sz == 0) break;

      if ((temp[0] == ';') || (temp[0] == ':'))
	{
	  temp.erase (0, 1);
	}
      else if ((temp[sz-1] == ';') || (temp[sz-1] == ':'))
	{
	  temp.erase (sz-1, 1);
	}
      else
	{
	  break;
	}
    }

  temp.replace_all ("::", ":");
  temp.replace_all (";;", ";");
  
  return (temp);
}

//-------------------------------------------------------------
const cmt_string PathBuilder::clean (const Symbol& symbol,
                                     const cmt_string& /*tag_name*/)
{
    // Control of recursivity
  static int level = 0;

  cmt_string temp;
  cmt_string new_value;
  static const cmt_string empty;

  static cmt_string path_separator = CmtSystem::path_separator ();

  temp = CmtSystem::getenv (symbol.name);

    //cerr << "#####1 temp=" << temp << endl;

  for (int i = 0; i < symbol.value_lists.size (); i++)
    {
      const SymbolValueList& value_list = symbol.value_lists[i];

      if (value_list.discarded) continue;

      if ((value_list.use != 0) &&
          (value_list.use->discarded)) continue;

      const int selected = value_list.select_first ();
      
      if (selected < 0) continue;
 
      SymbolValue& value = value_list.values[selected];
          
      new_value = value.text;
          
          //resolve_value (new_value);

        //cerr << "#####1 new_value=" << new_value << endl;

      resolve_value_for_macros (new_value);
      resolve_value (new_value);
          
        //cerr << "#####2 new_value=" << new_value << endl;

      switch (value_list.command_type)
        {
          case CommandPath :
            
            temp = "";
            
            break;
          case CommandPathAppend :
          case CommandPathPrepend :
          case CommandPathRemove :

            if (new_value != "")
              {
                CmtSystem::cmt_string_vector paths;
                  
                CmtSystem::split (temp, path_separator, paths);
                  
                for (int j = 0; j < paths.size (); ++j)
                  {
                    cmt_string& s = paths[j];
                      
                    if (s.find (new_value) != cmt_string::npos)
                      {
                        s = "";
                      }

                    if (j > 0)
                      {
                        cmt_string& s2 = paths[j-1];
                        if (s2 == s)
                          {
                            s2 = "";
                          }
                      }
                  }

                Cmt::vector_to_string (paths, path_separator, temp);
                temp.replace_all ("::", ":");
                temp.replace_all (";;", ";");
              }
              
            break;
          case CommandPathRemoveRegexp :

            if (new_value != "")
              {
		cmt_regexp e (new_value);

                CmtSystem::cmt_string_vector paths;
                  
                CmtSystem::split (temp, path_separator, paths);
                  
                for (int j = 0; j < paths.size (); ++j)
                  {
                    cmt_string& s = paths[j];
                      
                    if (e.match (s))
                      {
                        s = "";
                      }

                    if (j > 0)
                      {
                        cmt_string& s2 = paths[j-1];
                        if (s2 == s)
                          {
                            s2 = "";
                          }
                      }
                  }

                Cmt::vector_to_string (paths, path_separator, temp);
                temp.replace_all ("::", ":");
                temp.replace_all (";;", ";");
              }
              
            break;
        }
    }

    //cerr << "#####2 temp=" << temp << endl;
  
  return (temp);
}

//-------------------------------------------------------------
const cmt_string MacroBuilder::build (const Symbol& symbol,
                                      const cmt_string& tag_name)
{
    // Control of recursivity
  static int level = 0;

  cmt_string temp;
  cmt_string previous_temp;
  static const cmt_string empty;
  bool show_it = false;

  ActionType action = Cmt::get_action ();

  if (action == action_show_macro)
    {
      if (symbol.name == Cmt::get_current_target ())
        {
             // Should not display on recursive calls
          if (level == 0) show_it = m_display_it;
        }
    }

  level++;

  temp = "";

  int i;

  bool first_definition = true;

  for (i = 0; i < symbol.value_lists.size (); i++)
    {
      const SymbolValueList& value_list = symbol.value_lists[i];

      if ((value_list.use != 0) &&
          (value_list.use->discarded)) continue;

      if (value_list.command_type != CommandMacroPrepend) continue;

      const int selected = value_list.select_first (tag_name);

      if (selected < 0) continue;

      SymbolValue& value = value_list.values[selected];

      if (show_it && !Symbol::get_inhibit_display())
        {
          value_list.show (symbol, value, first_definition);
        }

      if (value_list.discarded) continue;

      previous_temp = temp;
      temp = value.text;
      temp += previous_temp;
    }

  previous_temp = temp;
  temp = "";

  first_definition = true;

  for (i = 0; i < symbol.value_lists.size (); i++)
    {
      const SymbolValueList& value_list = symbol.value_lists[i];

      if ((value_list.use != 0) &&
          (value_list.use->discarded)) continue;

      if (value_list.command_type != CommandMacro) continue;

      const int selected = value_list.select_first (tag_name);

      if (selected < 0) continue;

      SymbolValue& value = value_list.values[selected];

      if (show_it && !Symbol::get_inhibit_display())
        {
          value_list.show (symbol, value, first_definition);
        }

      // WARNING:
      // Commented just for a test : should be uncommented after the test
      if (value_list.discarded) continue;
      
      if (!value_list.is_reflexive || 
          !symbol.value_is_reflexive (value.text))
        {
          temp = value.text;
        }
    }

  previous_temp += temp;
  temp = previous_temp;

  for (i = 0; i < symbol.value_lists.size (); i++)
    {
      const SymbolValueList& value_list = symbol.value_lists[i];

      if ((value_list.use != 0) &&
          (value_list.use->discarded)) continue;

      if (value_list.command_type != CommandMacroAppend) continue;

      const int selected = value_list.select_first (tag_name);

      if (selected < 0) continue;

      SymbolValue& value = value_list.values[selected];

      if (show_it && !Symbol::get_inhibit_display())
        {
          value_list.show (symbol, value, first_definition);
        }

      if (value_list.discarded) continue;

      temp += value.text;
    }

  for (i = 0; i < symbol.value_lists.size (); i++)
    {
      const SymbolValueList& value_list = symbol.value_lists[i];

      if ((value_list.use != 0) &&
          (value_list.use->discarded)) continue;

      if ((value_list.command_type != CommandMacroRemove) &&
          (value_list.command_type != CommandMacroRemoveRegexp) &&
          (value_list.command_type != CommandMacroRemoveAll) &&
          (value_list.command_type != CommandMacroRemoveAllRegexp)) continue;

      const int selected = value_list.select_first (tag_name);

      if (selected < 0) continue;

      SymbolValue& value = value_list.values[selected];

      if (show_it && !Symbol::get_inhibit_display())
        {
          value_list.show (symbol, value, first_definition);
        }

      if (value_list.discarded) continue;

      switch (value_list.command_type)
        {
          case CommandMacroRemove :
            temp.replace (value.text, empty);
            break;
          case CommandMacroRemoveRegexp :
            if (value.text != "")
              {
		cmt_regexp e (value.text);
		cmt_regexp::iterator it;

		it = e.begin (temp);
		if (it != e.end ())
		  {
		    temp.erase (it._pos, it._length);
		  }
              }
            break;
          case CommandMacroRemoveAll :
            temp.replace_all (value.text, empty);
            break;
          case CommandMacroRemoveAllRegexp :
            if (value.text != "")
              {
		cmt_regexp e (value.text);
		cmt_regexp::iterator it;

		for (;;)
		  {
		    it = e.begin (temp);
		    if (it != e.end ())
		      {
			temp.erase (it._pos, it._length);
		      }
		    else
		      {
			break;
		      }
		  }
              }
            break;
        }
    }

  level--;

  return (temp);
}

//-------------------------------------------------------------
const cmt_string ScriptBuilder::build (const Symbol& symbol,
                                       const cmt_string& tag_name)
{
    // Control of recursivity
  static int level = 0;

  static const cmt_string empty = "";

  if (symbol.value_lists.size () > 0)
    {
      const SymbolValueList& value_list = symbol.value_lists[0];

      if (value_list.discarded) return (empty);

      if ((value_list.use != 0) &&
          (value_list.use->discarded)) return (empty);
    }

  return (symbol.name);
}

//-------------------------------------------------------------
const cmt_string ActionBuilder::build (const Symbol& symbol,
				       const cmt_string& tag_name)
{
    // Control of recursivity
  static int level = 0;

  cmt_string temp;
  cmt_string previous_temp;
  static const cmt_string empty;
  bool show_it = false;

  ActionType action = Cmt::get_action ();

  if (action == action_show_action)
    {
      if (symbol.name == Cmt::get_current_target ())
        {
             // Should not display on recursive calls
          if (level == 0) show_it = m_display_it;
        }
    }

  level++;

  int i;

  bool first_definition = true;

  temp = "";

  for (i = 0; i < symbol.value_lists.size (); i++)
    {
      const SymbolValueList& value_list = symbol.value_lists[i];

      if ((value_list.use != 0) &&
          (value_list.use->discarded)) continue;

      if (value_list.command_type != CommandAction) continue;

      const int selected = value_list.select_first (tag_name);

      if (selected < 0) continue;

      SymbolValue& value = value_list.values[selected];

      if (show_it && !Symbol::get_inhibit_display())
        {
          value_list.show (symbol, value, first_definition);
        }

      // WARNING:
      // Commented just for a test : should be uncommented after the test
      if (value_list.discarded) continue;
      
      if (!value_list.is_reflexive || 
          !symbol.value_is_reflexive (value.text))
        {
          temp = value.text;
        }
    }

  level--;

  return (temp);
}

//-------------------------------------------------------------
int SymbolValueList::select_first (const cmt_string& tag_name) const
{
  int priority = 0;
  int value_number;
  int selected = -1;

  Tag* the_tag = 0;

  if (tag_name != "") the_tag = Tag::find (tag_name);

  for (value_number = 0;
       value_number < values.size ();
       value_number++)
    {
      const SymbolValue& value = values[value_number];

      const Tag* tag = value.tag;

      if (the_tag == 0)
        {
          if (!tag->is_selected ()) continue;
          selected = value_number;
	  if (tag == Tag::get_default ())
	    continue;
        }
      else
        {
          if (tag != the_tag) continue;
          selected = value_number;
        }

      //
      // Only the value for the first alternative (i.e. non-default)
      // matching tag expression is
      // selected (which means the selection stops here)
      //
      break;

      //
      // Only the first value at a given priority is
      // selected (which implies the '>' test instead
      // of '>=')
      //
      /*
      if (tag->get_priority () > priority)
        {
          priority = tag->get_priority ();
          selected = value_number;
        }
      */
    }

  return (selected);
}

//-------------------------------------------------------------
int SymbolValueList::select_last () const
{
  int priority = 0;
  int value_number;
  int selected = -1;

  for (value_number = 0;
       value_number < values.size ();
       value_number++)
    {
      SymbolValue& value = values[value_number];

      const Tag* tag = value.tag;

      if (tag->is_selected ())
        {
          //
          // The last value at a given priority is
          // selected (which implies the '>=' test instead
          // of '>')
          //

          if (tag->get_priority () >= priority)
            {
              priority = tag->get_priority ();
              selected = value_number;
            }
        }
    }

  return (selected);
}

//-------------------------------------------------------------
void SymbolValueList::show (const Symbol& symbol, 
                            const SymbolValue& value, 
                            bool& first_definition) const
{
  cmt_string discarded_text;
  cmt_string define_text;
  ActionType action = Cmt::get_action ();

  switch (command_type)
    {
      //case CommandSet :
      case CommandSetAppend :
      case CommandSetPrepend :
      case CommandSetRemove :
      case CommandSetRemoveRegexp :
	//case CommandAlias :
	//case CommandPath :
      case CommandPathAppend :
      case CommandPathPrepend :
      case CommandPathRemove :
      case CommandPathRemoveRegexp :
      case CommandMacroPrepend :
	//case CommandMacro :
      case CommandMacroAppend :
      case CommandMacroRemove :
      case CommandMacroRemoveRegexp :
      case CommandMacroRemoveAll :
      case CommandMacroRemoveAllRegexp :
	//case CommandAction :
	if (value.text == "") return;
        break;
    }

  if (discarded) discarded_text = " (discarded by override)";
  else discarded_text = "";

  if (first_definition) define_text = "defines";
  else define_text = "overrides";

  cout << "# Package ";
  if (use != 0)
    {
      cout << use->get_package_name () << " " << use->version;
    }

  switch (command_type)
    {
      case CommandSet :
        cout << " " << define_text << " set " << symbol.name << " as ";
        first_definition = false;
        break;
      case CommandSetAppend :
        cout << " appends to set " << symbol.name << " : ";
        break;
      case CommandSetPrepend :
        cout << " prepends to set " << symbol.name << " : ";
        break;
      case CommandSetRemove :
        cout << " removes from set " << symbol.name << " : ";
        break;
      case CommandSetRemoveRegexp :
        cout << " removes RE from set " << symbol.name << " : ";
        break;
      case CommandAlias :
        cout << " " << define_text << " alias " << symbol.name << " as ";
        first_definition = false;
        break;
      case CommandPath :
        cout << " " << define_text << " path " << symbol.name << " as ";
        first_definition = false;
        break;
      case CommandPathAppend :
        cout << " appends to path " << symbol.name << " : ";
        break;
      case CommandPathPrepend :
        cout << " prepends to path " << symbol.name << " : ";
        break;
      case CommandPathRemove :
        cout << " removes from path " << symbol.name << " : ";
        break;
      case CommandPathRemoveRegexp :
        cout << " removes RE from path " << symbol.name << " : ";
        break;
      case CommandMacroPrepend :
        cout << " prepends to macro " << symbol.name << " : ";
        break;
      case CommandMacro :
        cout << " " << define_text << " macro " << symbol.name << " as ";
        break;
      case CommandMacroAppend :
        cout << " appends to macro " << symbol.name << " : ";
        break;
      case CommandMacroRemove :
        cout << " remove from macro " << symbol.name << " : ";
        break;
      case CommandMacroRemoveRegexp :
        cout << " remove RE from macro " << symbol.name << " : ";
        break;
      case CommandMacroRemoveAll :
        cout << " remove all from macro " << symbol.name << " : ";
        break;
      case CommandMacroRemoveAllRegexp :
        cout << " remove all RE from macro " << symbol.name << " : ";
        break;
      case CommandAction :
        cout << " " << define_text << " action " << symbol.name << " as ";
        first_definition = false;
        break;
    }

  cout << "'" << value.text << "'";
          
  Tag* selected_tag = value.tag;
          
  if ((selected_tag == 0) ||
      (selected_tag == Tag::get_default ()))
    {
      cout << " for default tag";
    }
  else
    {
      cout << " for tag '" << selected_tag->get_name () << "'";
    }
  
  cout << discarded_text << endl;
}

//-------------------------------------------------------------
int SymbolValueList::print (const Symbol& symbol, 
			    const SymbolValue& value, 
			    bool& first_definition) const
{
  int result (0);

  //if (use->get_package_name () == "CMT") return result;

  cmt_string discarded_text;
  cmt_string define_text;
  ActionType action = Cmt::get_action ();

  switch (command_type)
    {
      //case CommandSet :
      case CommandSetAppend :
      case CommandSetPrepend :
      case CommandSetRemove :
      case CommandSetRemoveRegexp :
	//case CommandAlias :
	//case CommandPath :
      case CommandPathAppend :
      case CommandPathPrepend :
      case CommandPathRemove :
      case CommandPathRemoveRegexp :
      case CommandMacroPrepend :
	//case CommandMacro :
      case CommandMacroAppend :
      case CommandMacroRemove :
      case CommandMacroRemoveRegexp :
      case CommandMacroRemoveAll :
      case CommandMacroRemoveAllRegexp :
	//case CommandAction :
	if (value.text == "") return result;
        break;
    }

  if (discarded) discarded_text = " (discarded by override)";
  else discarded_text = "";

  if (first_definition) define_text = "defines";
  else define_text = "overrides";

  if (CmtMessage::active (Verbose))
    cout << "# Package " << (use != 0 ? use->get_package_name () + " " + use->version : "");
  /*
  if (use != 0)
    {
      cout << use->get_package_name () << " " << use->version;
    }
  */

  switch (command_type)
    {
      case CommandSet :
	if (CmtMessage::active (Verbose))
	  cout << " " << define_text << " set " << symbol.name << " as " << endl;
	//        cout << " " << define_text << " set " << symbol.name << " as ";
        cout << "set " << symbol.name;
        first_definition = false;
	result = 1;
        break;
      case CommandSetAppend :
	if (CmtMessage::active (Verbose))
	  cout << " appends to set " << symbol.name << " : " << endl;
	//        cout << " appends to set " << symbol.name << " : ";
        cout << "set_append " << symbol.name;
	result = 1;
        break;
      case CommandSetPrepend :
	if (CmtMessage::active (Verbose))
	  cout << " prepends to set " << symbol.name << " : " << endl;
	//        cout << " prepends to set " << symbol.name << " : ";
        cout << "set_prepend " << symbol.name;
	result = 1;
        break;
      case CommandSetRemove :
	if (CmtMessage::active (Verbose))
	  cout << " removes from set " << symbol.name << " : " << endl;
	//        cout << " removes from set " << symbol.name << " : ";
        cout << "set_remove " << symbol.name;
	result = 1;
        break;
      case CommandSetRemoveRegexp :
	if (CmtMessage::active (Verbose))
	  cout << " removes RE from set " << symbol.name << " : " << endl;
	//        cout << " removes RE from set " << symbol.name << " : ";
        cout << "set_remove_regexp " << symbol.name;
	result = 1;
        break;
      case CommandAlias :
	if (CmtMessage::active (Verbose))
	  cout << " " << define_text << " alias " << symbol.name << endl;
	//        cout << " " << define_text << " alias " << symbol.name << " as ";
        cout << "alias " << symbol.name;
        first_definition = false;
	result = 1;
        break;
      case CommandPath :
	if (CmtMessage::active (Verbose))
	  cout << " " << define_text << " path " << symbol.name << endl;
	//        cout << " " << define_text << " path " << symbol.name << " as ";
        cout << "path " << symbol.name;
        first_definition = false;
	result = 1;
        break;
      case CommandPathAppend :
	if (CmtMessage::active (Verbose))
	  cout << " appends to path " << symbol.name << endl;
	//        cout << " appends to path " << symbol.name << " : ";
        cout << "path_append " << symbol.name;
	result = 1;
        break;
      case CommandPathPrepend :
	if (CmtMessage::active (Verbose))
	  cout << " prepends to path " << symbol.name << " : " << endl;
	//        cout << " prepends to path " << symbol.name << " : ";
        cout << "path_prepend " << symbol.name;
	result = 1;
        break;
      case CommandPathRemove :
	if (CmtMessage::active (Verbose))
	  cout << " removes from path " << symbol.name << " : " << endl;
	//        cout << " removes from path " << symbol.name << " : ";
        cout << "path_remove " << symbol.name;
	result = 1;
        break;
      case CommandPathRemoveRegexp :
	if (CmtMessage::active (Verbose))
	  cout << " removes RE from path " << symbol.name << " : " << endl;
	//        cout << " removes RE from path " << symbol.name << " : ";
        cout << "path_remove_regexp " << symbol.name;
	result = 1;
        break;
      case CommandMacro :
	if (CmtMessage::active (Verbose))
	  cout << " " << define_text << " macro " << symbol.name << " as " << endl;
	//        cout << " " << define_text << " macro " << symbol.name << " as ";
        cout << "macro " << symbol.name;
	result = 1;
        break;
      case CommandMacroPrepend :
	if (CmtMessage::active (Verbose))
	  cout << " prepends to macro " << symbol.name << " : " << endl;
	//        cout << " prepends to macro " << symbol.name << " : ";
        cout << "macro_prepend " << symbol.name;
	result = 1;
        break;
      case CommandMacroAppend :
	if (CmtMessage::active (Verbose))
	  cout << " appends to macro " << symbol.name << " : " << endl;
	//        cout << " appends to macro " << symbol.name << " : ";
        cout << "macro_append " << symbol.name;
	result = 1;
        break;
      case CommandMacroRemove :
	if (CmtMessage::active (Verbose))
	  cout << " remove from macro " << symbol.name << " : " << endl;
	//        cout << " remove from macro " << symbol.name << " : ";
        cout << "macro_remove " << symbol.name;
	result = 1;
        break;
      case CommandMacroRemoveRegexp :
	if (CmtMessage::active (Verbose))
	  cout << " remove RE from macro " << symbol.name << " : " << endl;
	//        cout << " remove RE from macro " << symbol.name << " : ";
        cout << "macro_remove_regexp " << symbol.name;
	result = 1;
        break;
      case CommandMacroRemoveAll :
	if (CmtMessage::active (Verbose))
	  cout << " remove all from macro " << symbol.name << " : " << endl;
	//        cout << " remove all from macro " << symbol.name << " : ";
        cout << "macro_remove_all " << symbol.name;
	result = 1;
        break;
      case CommandMacroRemoveAllRegexp :
	if (CmtMessage::active (Verbose))
	  cout << " remove all RE from macro " << symbol.name << " : " << endl;
	//        cout << " remove all RE from macro " << symbol.name << " : ";
        cout << "macro_remove_all_regexp " << symbol.name;
	result = 1;
        break;
      case CommandSetupScript :
	if (CmtMessage::active (Verbose))
	  cout << " " << define_text << " setup script " << symbol.name << endl;
	//       cout << " " << define_text << " action " << symbol.name << " as ";
        cout << "setup_script" /* << symbol.name */;
        first_definition = false;
	result = 1;
        break;
	/*
      case CommandAction :
        cout << " " << define_text << " action " << symbol.name << " as ";
        first_definition = false;
        break;
	*/
    }

  cout << " " << CmtSystem::quote (value.text, " \t");
  //  cout << "'" << value.text << "'";
          
  /*
  Tag* selected_tag = value.tag;
          
  if ((selected_tag == 0) ||
      (selected_tag == Tag::get_default ()))
    {
      cout << " for default tag";
    }
  else
    {
      cout << " for tag '" << selected_tag->get_name () << "'";
    }
  */

  cout << endl;
  //  cout << discarded_text << endl;
  return result;
}

//-------------------------------------------------------------
bool Symbol::check_tag_used (const Tag* tag)
{
  if (tag == 0) return (false);

  static SymbolVector& Symbols = symbols ();

  if (Symbols.size () == 0) 
    {
      return (false);
    }

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

      for (int i = 0; i < symbol.value_lists.size (); i++)
	{
	  const SymbolValueList& value_list = symbol.value_lists[i];

	  for (int j = 0; j < value_list.values.size (); j++)
	    {
	      const SymbolValue& value = value_list.values[j];
	      Tag* t = value.tag;

	      if (t != 0)
		{
		  if (t->use_operand (tag)) return (true);
		}
	    }
	}
    }

  return (false);
}

//-------------------------------------------------------------
cmt_string Symbol::get_env_value (const cmt_string& name)
{
  cmt_string s;

  Symbol* symbol = Symbol::find (name);
  if (symbol != 0)
    {
      m_inhibit_display = true;

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

      m_inhibit_display = false;
    }
  else
    {
      s = CmtSystem::getenv (name);
    }

  return (s);
}

bool Symbol::get_inhibit_display ()
{
  return (m_inhibit_display);
}

