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

#include "cmt_generators.h"
#include "cmt_awk.h"
#include "cmt_use.h"
#include "cmt_symbol.h"
#include "cmt_log.h"
#include "cmt_error.h"
#include <assert.h>
#include "cmt_project.h"

//--------------------------------------------------
AnyDocumentGenerator::AnyDocumentGenerator ()
{
  m_TITLE.set ("TITLE");
  m_STRUCTURED_OUTPUT.set ("STRUCTURED_OUTPUT");

  make_header_fragment.set ("make_header");
  cleanup_header_fragment.set ("cleanup_header");
  cleanup_fragment.set ("cleanup");
  dependencies_fragment.set ("dependencies");
  dependencies_and_triggers_fragment.set ("dependencies_and_triggers");
}

void AnyDocumentGenerator::reset ()
{
  CmtGenerator::reset ();
  m_TITLE = "";

  make_header_fragment.reset ();
  cleanup_header_fragment.reset ();
  cleanup_fragment.reset ();
  dependencies_fragment.reset ();
  dependencies_and_triggers_fragment.reset ();
}

//--------------------------------------------------
LibraryGenerator::LibraryGenerator ()
{
  library_header_fragment.set ("library_header");
  application_header_fragment.set ("application_header");
  java_header_fragment.set ("java_header");
  jar_header_fragment.set ("jar_header");
  protos_header_fragment.set ("protos_header");
  library_fragment.set ("library");
  library_no_share_fragment.set ("library_no_share");
  library_no_static_fragment.set ("library_no_static");
  application_fragment.set ("application");
  jar_fragment.set ("jar");
  java_fragment.set ("java");
  java_copy_fragment.set ("java_copy");
  cleanup_library_fragment.set ("cleanup_library");
  cleanup_application_fragment.set ("cleanup_application");
  cleanup_java_fragment.set ("cleanup_java");
  cleanup_objects_fragment.set ("cleanup_objects");
  buildproto_fragment.set ("buildproto");
  check_application_fragment.set ("check_application");
  check_java_fragment.set ("check_java");
}

//--------------------------------------------------
void LibraryGenerator::reset ()
{
  AnyDocumentGenerator::reset ();
  library_header_fragment.reset ();
  application_header_fragment.reset ();
  java_header_fragment.reset ();
  jar_header_fragment.reset ();
  protos_header_fragment.reset ();
  library_fragment.reset ();
  library_no_share_fragment.reset ();
  library_no_static_fragment.reset ();
  jar_fragment.reset ();
  application_fragment.reset ();
  java_fragment.reset ();
  java_copy_fragment.reset ();
  cleanup_library_fragment.reset ();
  cleanup_application_fragment.reset ();
  cleanup_java_fragment.reset ();
  cleanup_objects_fragment.reset ();
  buildproto_fragment.reset ();
  check_application_fragment.reset ();
  check_java_fragment.reset ();
}

//--------------------------------------------------
bool LibraryGenerator::analyze_file (const Constituent& constituent,
				     const cmt_string& file)
{
  static cmt_string suffix;
  static cmt_string name;
  static cmt_string obj;

  bool file_not_found = false;
  bool can_build = true;

  obj = file;

  if (Cmt::get_debug ())
    {
      cout << "CmtGenerator::analyze_file> constituent=" << 
	constituent.name <<
	" file=" << file << endl;
    }

  if (!CmtSystem::test_file (file) && !CmtSystem::test_directory (file))
    {
      file_not_found = true;
      CmtMessage::warning ("Source file " + file + " not found");
      //      cerr << "#CMT> Warning: Source file " << file << " not found" << endl;
    }

  CmtSystem::get_suffix (file, suffix);
  CmtSystem::basename (file, suffix, name);

  Language& language = Language::find_with_suffix (suffix);

  if (m_LINKMACRO == "")
    {
      m_LINKMACRO = language.linker;
    }

  if (language == "java")
    {
      static Packager packager;
      
      obj  = "$(javabin)";
      obj +=  m_CONSTITUENT;
      obj +=  CmtSystem::file_separator ();

      cmt_regexp exp ("^package[ \t][ \t]*[a-zA-Z0-9_.][a-zA-Z0-9_.][ \t]*;");
      
      packager.run (file, exp);
      if (packager.package_name () != "")
        {
          obj += packager.package_name ();
          obj += CmtSystem::file_separator ();
        }
      
      obj += name;
      obj += ".class";
    }
  else if (language != Language::null ())
    {
      obj  = "$(bin)";      

      if (CmtSystem::getenv("STRUCTURED_OUTPUT")!="" || Cmt::build_nmake ())
	{
          obj +=  m_CONSTITUENT;
          obj +=  CmtSystem::file_separator ();
	}

      obj += name;
      obj += language.output_suffix;
      obj += constituent.suffix;
      if (Cmt::build_nmake ()) obj += ".obj";
      else obj += ".o";
 
      for (int i = 0; i < language.extra_output_suffixes.size (); i++)
        {
          cmt_string& extra_suffix = language.extra_output_suffixes[i];

          obj += " $(bin)";
          obj += name;
          obj += extra_suffix;
          obj += language.output_suffix;
          obj += constituent.suffix;
          if (Cmt::build_nmake ()) obj += ".obj";
          else obj += ".o";
        }
    }
  else
    {
      if (m_LINKMACRO == "java")
        {
          obj  = "$(javabin)";
          obj +=  m_CONSTITUENT;
          obj +=  CmtSystem::file_separator ();
          obj += file;
          
          obj.replace ("../src/", "");
          obj.replace ("..\\src\\", "");
        }
      else if (file_not_found)
        {
	  can_build = false;
          obj  = "";
	  CmtMessage::warning ("Source file " + name + " cannot be rebuilt");
	  //	  cerr << "#CMT> Warning: Source file " << name << " cannot be rebuilt" << endl;
        }
      else
        {
          obj  = "";
        }
    }

  if (Cmt::get_debug ())
    {
      cout << "LibraryGenerator::analyze_file> constituent=" << 
	constituent.name <<
	" obj=" << obj << endl;
    }

  if (can_build)
    {
      SourceFile& source = m_source_files.add ();
      source.set (file, language, obj);
      return (true);
    }
  else
    {
      return (false);
    }
}

//--------------------------------------------------
void LibraryGenerator::java_file_action (SourceFile& file, const Constituent& constituent)
{
  static cmt_string suffix;

  m_FULLNAME = file.name ();
  m_OUTPUTNAME = file.output ();

  CmtSystem::get_dot_suffix (m_FULLNAME, suffix);
  
  CmtSystem::basename (m_FULLNAME, suffix, m_NAME.value);
  CmtSystem::basename (m_FULLNAME, m_FILENAME.value);
  
  //  if (CmtSystem::test_file (m_FULLNAME))
  //    {
      java_fragment.copy (m_output_file, constituent.variables, 5,
                          &m_NAME,
                          &m_FULLNAME,
                          &m_OUTPUTNAME,
                          &m_CONSTITUENT, 
                          &m_CONSTITUENTSUFFIX);
      /*
    }
  else
    {
      CmtMessage::warning ("file " + m_FULLNAME + " not found");
      //      cerr << "#CMT> Warning: file " << m_FULLNAME << " not found" << endl;
    }
      */
}

//--------------------------------------------------
void LibraryGenerator::proto_file_action (const cmt_string& file, const Constituent& constituent)
{
  static cmt_string suffix;

  CmtSystem::dirname (file, m_FILEPATH.value);
  if (m_FILEPATH.value != "") m_FILEPATH.value += CmtSystem::file_separator ();

  filter_path (m_FILEPATH.value);

  CmtSystem::basename (file, m_FILENAME.value);
  CmtSystem::get_dot_suffix (m_FILENAME, suffix);

  CmtSystem::basename (m_FILENAME, suffix, m_NAME.value);

  buildproto_fragment.copy (m_output_file, constituent.variables, 4,
			    &m_CONSTITUENT,
                            &m_NAME, 
                            &m_FILEPATH, 
                            &m_FILENAME);
}

//--------------------------------------------------
void LibraryGenerator::prepare_proto_file (const cmt_string& file)
{
  static cmt_string name;
  static cmt_string pp;

  CmtSystem::name (file, name);

  if (CmtSystem::test_file (file))
    {
      pp  = incdir;
      pp += name;
      pp += ".pp";

      if (!CmtSystem::test_file (pp))
        {
	  //Generator::build_prototype (file);
        }
    }

  protos += " ";
  protos += inc;
  protos += name;
  protos += ".ph";

  protonames += " ";
  protonames += name;
  protonames += ".ph";

  m_PROTOSTAMPS += " ";
  m_PROTOSTAMPS += inc;
  m_PROTOSTAMPS += name;
  m_PROTOSTAMPS += ".pp";
}

//--------------------------------------------------
void LibraryGenerator::module_file_action (SourceFile& file, const Constituent& constituent)
{
  cmt_string name = file.name ();
  Language& language = file.language ();

  static cmt_string suffix;
  static cmt_string prefix;
  static cmt_string preproc;

  m_FULLNAME = name;

  CmtSystem::get_dot_suffix (name, suffix);

  CmtSystem::basename (name, suffix, m_NAME.value);

  CmtSystem::dirname (name, prefix);
  CmtSystem::basename (name, m_FILENAME.value);

  FragmentHandle* fragment;

  if (language != Language::null ())
    {
      preproc = language.preprocessor_command;
      fragment = (is_library) ? &(language.library) : &(language.application);
      m_DEPENDENCIESOPTS = language.dependencies_options ();
    }
  else
    {
      //
      // What happens when the language is not known???
      // 
      //
      preproc = "-I";
      fragment = 0;
    }

  if ((prefix == "../src") || (prefix == "..\\src"))
    {
      m_ADDINCLUDE = "";
    }
  else if (prefix != "")
    {
      m_ADDINCLUDE  = preproc;
      m_ADDINCLUDE += prefix;
    }

  m_FILEPATH = prefix;
  if (m_FILEPATH.value != "") m_FILEPATH.value += CmtSystem::file_separator ();
  filter_path (m_FILEPATH.value);

  /*
  m_LINE = m_FULLNAME.value;
  m_LINE += " ";
  */

  filter_path (m_FULLNAME.value);

  CmtSystem::get_suffix (name, m_FILESUFFIX.value);

  if (fragment != 0)
    {
      //      fragment->copy (m_output_file, constituent.variables, 10,
      fragment->copy (m_output_file, constituent.variables, 11,
                      &m_CONSTITUENT, 
                      &m_CONSTITUENTSUFFIX, 
                      &m_FILENAME, 
                      &m_NAME, 
                      &m_LINE,
                      &m_ADDINCLUDE, 
                      &m_FULLNAME, 
                      &m_FILEPATH, 
                      &m_FILESUFFIX, 
                      &m_PACKAGE,
		      &m_DEPENDENCIESOPTS);
    }
  else if (file.output () != "")
    {
      m_OUTPUTNAME = file.output ();
      CmtSystem::dirname (m_OUTPUTNAME.value, m_FILEPATH.value);

      java_copy_fragment.copy (m_output_file, constituent.variables, 11,
                               &m_CONSTITUENT, 
                               &m_CONSTITUENTSUFFIX, 
                               &m_FILENAME, 
                               &m_NAME, 
                               &m_LINE,
                               &m_ADDINCLUDE, 
                               &m_FULLNAME, 
                               &m_FILEPATH, 
                               &m_FILESUFFIX, 
                               &m_PACKAGE, 
                               &m_OUTPUTNAME);
    }

  if (m_PACKOS9)
    {
      //      os9sources += m_LINE;
      os9sources += m_FULLNAME.value;
      os9sources += " ";
    }
}

//--------------------------------------------------
void LibraryGenerator::fill_names_outputs ()
{
  bool l_first = true;
  bool o_first = true;

  m_LINE = "";
  m_OBJS = "";

  for (int i = 0; i < m_source_files.size (); i++)
    {
      const SourceFile& file = m_source_files[i];
      const cmt_string name = file.name ();
      const cmt_string output = file.output ();
      Language& language = file.language ();

      if (output != "")
        {
          if (o_first)
            {
              o_first = false;
            }
          else
            {
              m_OBJS += " ";
            }
          m_OBJS += output;

	  if (language == Language::null () || !language.native_dependencies ())
	    {
	      if (l_first)
		{
		  l_first = false;
		}
	      else
		{
		  m_LINE += " ";
		}
	      m_LINE += name;
	    }
	}

      if (Cmt::get_debug ())
        {
          cout << "LibraryGenerator::fill_names_outputs>" << endl;
	  cout << "name=" << name << " LINE=" << m_LINE << endl;
	  cout << "output=" << output << " OBJS=" << m_OBJS << endl;
        }
    }

  filter_path (m_LINE.value);
}

//--------------------------------------------------
void LibraryGenerator::build (const cmt_string& package,
			      const Constituent& constituent,
			      bool& dependencies,
			      const cmt_string& file_name)
{
  //static cmt_string lib;
  static cmt_string allsources;
  static cmt_string file;
  static cmt_string full_name;
  static cmt_string compressed_name;
  static cmt_string suffix;
  int i;
  bool need_prototypes;

  reset ();

  if (!prepare_output (package, constituent, file_name)) return;

  switch (constituent.type)
    {
    case Application:
      is_library = false;
      is_application = true;
      m_TITLE = "Application";
      break;
    case Library:
      is_library = true;
      is_application = false;
      m_TITLE = "Library";
      break;
    default:
      break;
    }

  m_source_files.clear ();

  need_prototypes = constituent.need_prototypes;

  if (constituent.need_prototypes)
    {
      m_HASPROTOTYPES = "has_prototypes";
    }
  else
    {
      m_HASPROTOTYPES = "has_no_prototypes";
    }

  //  cout << m_TITLE << " " << m_CONSTITUENT << endl;
  CmtMessage::info (m_TITLE + " " + m_CONSTITUENT);

  /*
  lib  = "$(";
  lib += m_CONSTITUENT;
  lib += "lib)";
  */
  //
  // Prepare the include paths
  //

  const CmtSystem::cmt_string_vector& includes = constituent.includes;

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

      m_PACKINCLUDES += " -I";
      m_PACKINCLUDES += subdir;
    }

  //
  // Scan the sources.
  //

  const CmtSystem::cmt_string_vector& sources = constituent.modules;
  const cmt_vector<cmt_regexp>& excludes = constituent.exclude_exprs;
  const cmt_vector<cmt_regexp>& selects = constituent.select_exprs;

  //  m_LINE = "";

  for (i = 0; i < sources.size (); i++)
    {
      file = sources[i];

      set_full_name (full_name, file);
      if (full_name == "") continue;

      CmtSystem::compress_path (full_name, compressed_name);
      full_name = compressed_name;

      static CmtSystem::cmt_string_vector files;

      int count = get_all_files (full_name, excludes, selects, files);

      filter_path (full_name);

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

          if (name != "") 
            {
              if (!analyze_file (constituent, name)) 
		{
		  count = 0;
		  break;
		}
            }
        }

      /*
      if (count > 0)
        {
          m_LINE += full_name;
          m_LINE += " ";
        }
      */
    }

  fill_names_outputs ();
  //fill_outputs ();

  //prepare_use_context ();

  m_DATE = CmtSystem::now ();
  m_USER = CmtSystem::user ();
  m_PACKAGE = package;

  if (constituent.has_target_tag)
    {
      m_HASTARGETTAG = "has_target_tag";
    }
  else
    {
      m_HASTARGETTAG = "has_no_target_tag";
    }
    
  m_HASDEPENDENCIES = "has_dependencies";

  m_STRUCTURED_OUTPUT = "STRUCTURED_OUTPUT";

  make_header_fragment.copy (m_output_file, constituent.variables, 9, 
			     &m_TITLE,
                             &m_CONSTITUENT,
                             &m_CONSTITUENTSUFFIX,
			     &m_USER,
                             &m_DATE,
                             &m_PACKAGE,
			     &m_HASTARGETTAG,
			     &m_HASDEPENDENCIES,
			     &m_STRUCTURED_OUTPUT
			     );

  if (need_prototypes)
    {
      need_prototypes = false;

      for (i = 0; i < m_source_files.size (); i++)
        {
          const SourceFile& file = m_source_files[i];
          Language& language = file.language ();
          if (language.prototypes)
            {
              need_prototypes = true;
              break;
            }
        }
    }

  //-------------------------------------------
  //
  // Specific targets (application, library or java)
  // Prepare in case prototype files are needed
  //
  //-------------------------------------------

  m_PROTOTARGET = "";

  //if ((Cmt::current_build_strategy & PrototypesMask) == Prototypes)
  if (need_prototypes)
    {
      m_PROTOTARGET = m_CONSTITUENT;
      m_PROTOTARGET += "PROTOS";
    }

  if (m_LINKMACRO == "java")
    {
      if (is_library)
        {
          jar_header_fragment.copy (m_output_file, constituent.variables, 5,
				    &m_CONSTITUENT, 
                                    &m_CONSTITUENTSUFFIX,
				    &m_OBJS,
				    &m_PROTOTARGET,
				    &m_HASPROTOTYPES);
        }
      else
        {
          java_header_fragment.copy (m_output_file, constituent.variables, 5,
				     &m_CONSTITUENT,
                                     &m_CONSTITUENTSUFFIX,
				     &m_OBJS,
				     &m_PROTOTARGET,
				     &m_HASPROTOTYPES);
        }
    }
  else
    {
      if (is_library)
        {
          library_header_fragment.copy (m_output_file, constituent.variables, 5,
                                        &m_CONSTITUENT,
                                        &m_CONSTITUENTSUFFIX,
					&m_OBJS,
					&m_PROTOTARGET,
					&m_HASPROTOTYPES);
        }
      else
        {
          application_header_fragment.copy (m_output_file, constituent.variables, 5,
                                            &m_CONSTITUENT,
                                            &m_CONSTITUENTSUFFIX,
					    &m_OBJS,
					    &m_PROTOTARGET,
					    &m_HASPROTOTYPES);
        }
    }


  //----------------------------------------------------
  //
  // Preparing prototype files.
  //
  //----------------------------------------------------

  //if ((Cmt::current_build_strategy & PrototypesMask) == Prototypes)
  if (need_prototypes)
    {
      for (i = 0; i < m_source_files.size (); i++)
        {
          const SourceFile& file = m_source_files[i];
          Language& language = file.language ();
          if (language.prototypes)
            {
              prepare_proto_file (file.name ());
            }
        }

      if (m_PROTOSTAMPS != "")
        {
          protos_header_fragment.copy (m_output_file, constituent.variables, 4,
				       &m_CONSTITUENT,
                                       &m_CONSTITUENTSUFFIX,
                                       &m_PROTOSTAMPS,
				       &m_OBJS);
        }

      if (protonames != "")
        {
          for (i = 0; i < m_source_files.size (); i++)
            {
              const SourceFile& file = m_source_files[i];
              Language& language = file.language ();
              if (language.prototypes)
                {
                  proto_file_action (file.name (), constituent);
                }
            }
        }
    }

  //----------------------------------------------------
  //
  // Preparing the library.
  //
  //----------------------------------------------------

  if (m_OBJS != "")
    {
      if (m_LINKMACRO == "java")
        {
          if (is_library)
            {
	      cmt_string classes = m_OBJS.value;

	      classes.replace_all ("$(javabin)", "");
	      classes.replace_all (srcdir.c_str (), "");

	      m_CLASSES = classes;

              jar_fragment.copy (m_output_file, constituent.variables, 4, 
				 &m_CONSTITUENT,
                                 &m_CONSTITUENTSUFFIX,
                                 &m_OBJS,
                                 &m_CLASSES);
            }
        }
      else
        {
          if (is_library)
            {
              if (constituent.no_share && constituent.no_static)
		{
		  CmtMessage::warning (constituent.name + ": No shared or static library");
		}
              else if (constituent.no_share)
                {
                  library_no_share_fragment.copy (m_output_file, constituent.variables, 3, 
						  &m_CONSTITUENT,
                                                  &m_CONSTITUENTSUFFIX,
                                                  &m_OBJS);
                }
              else if (constituent.no_static)
                {
                  library_no_static_fragment.copy (m_output_file, constituent.variables, 3, 
						  &m_CONSTITUENT,
                                                  &m_CONSTITUENTSUFFIX,
                                                  &m_OBJS);
                }
              else
                {
                  library_fragment.copy (m_output_file, constituent.variables, 3, 
					 &m_CONSTITUENT,
                                         &m_CONSTITUENTSUFFIX,
                                         &m_OBJS);
                }
            }
          else
            {
              application_fragment.copy (m_output_file, constituent.variables, 4,
                                         &m_CONSTITUENT,
                                         &m_CONSTITUENTSUFFIX, 
					 &m_OBJS,
                                         &m_LINKMACRO);
            }
        }
    }

  bool need_dependencies = false;
  
  for (i = 0; i < m_source_files.size (); i++)
    {
      const SourceFile& file = m_source_files[i];
      Language& language = file.language ();
      if (language == Language::null () || !language.native_dependencies ())
	{
	  need_dependencies = true;
	  break;
	}
    }
  dependencies = need_dependencies;

  if (constituent.build_triggers)
    {
      dependencies_and_triggers_fragment.copy (m_output_file, 
                                               constituent.variables, 3,
                                               &m_CONSTITUENT, 
                                               &m_CONSTITUENTSUFFIX, 
                                               &m_LINE);
    }
  else
    {
      if (need_dependencies)
	{
	  dependencies_fragment.copy (m_output_file, 
				      constituent.variables, 3,
				      &m_CONSTITUENT, 
				      &m_CONSTITUENTSUFFIX, 
				      &m_LINE);
	}
    }

  //----------------------------------------------------
  //
  // Building actual individual targets.
  //
  //----------------------------------------------------

  for (i = 0; i < m_source_files.size (); i++)
    {
      SourceFile& file = m_source_files[i];
      Language& language = file.language ();

      if (language == "java")
        {
          java_file_action (file, constituent);
        }
      else
        {
          module_file_action (file, constituent);
        }
    }

  if (m_PACKOS9)
    {
      if (os9sources != "")
        {
	  //
	  // Generate transfers to the OS9 area.
	  //

          m_ALLOS9SOURCES = "";
          allsources = "";
        }
    }

  /*
    for file in `cmt_sort_line.csh ${os9sources}` ; do
    if test `echo ${file} | grep '$(src)'` ; then
    name=`echo ${file} | sed 's#$(src)##'`
    ALLOS9SOURCES="${ALLOS9SOURCES} ../OS9/${name}"
    allsources="${allsources} ${file}"
    elif test `echo ${file} | grep '$(inc)'` ; then
    name=`echo ${file} | sed 's#$(inc)##'`
    ALLOS9SOURCES="${ALLOS9SOURCES} ../OS9/${name}"
    allsources="${allsources} ${file}"
    fi
    done

    if test ! "${ALLOS9SOURCES}" = "" ; then

    sed -e "`subs_vars ALLOS9SOURCES`" \
    ${os9_header_fragment} \
    >>${output}

    for FULLNAME in ${allsources} ; do

    NAME=`echo ${FULLNAME} | sed -e 's#$(src)##' -e 's#$(inc)##'`

    sed -e "`subs_vars NAME FULLNAME`" \
    ${os9_fragment} \
    >>${output}

    done
    fi
    fi
    fi
  */

  //
  //  Generate package cleanup operations.
  //

  cleanup_header_fragment.copy (m_output_file, constituent.variables, 2, 
				&m_CONSTITUENT,
                                &m_CONSTITUENTSUFFIX);

  //if ((Cmt::current_build_strategy & PrototypesMask) == Prototypes)
  if (need_prototypes)
    {
      if (protos != "")
        {
          m_FULLNAME = protos;
          cleanup_fragment.copy (m_output_file, constituent.variables, 1, &m_FULLNAME);
          m_FULLNAME = m_PROTOSTAMPS;
          cleanup_fragment.copy (m_output_file, constituent.variables, 1, &m_FULLNAME);
        }
    }

  if (m_LINKMACRO == "java")
    {
      cleanup_java_fragment.copy (m_output_file, constituent.variables, 1, &m_OBJS);

      if (!is_library)
	{
          if (constituent.need_check)
            {
              check_java_fragment.copy (m_output_file, constituent.variables, 2, 
					&m_CONSTITUENT,
                                        &m_CONSTITUENTSUFFIX);
            }
	}
    }
  else
    {
      if (is_library)
        {
          cleanup_library_fragment.copy (m_output_file, constituent.variables, 2, 
					 &m_CONSTITUENT,
                                         &m_CONSTITUENTSUFFIX);
        }
      else
        {
          cleanup_application_fragment.copy (m_output_file, constituent.variables, 2, 
					     &m_CONSTITUENT,
                                             &m_CONSTITUENTSUFFIX);
          if (m_OBJS != "")
            {
              cleanup_objects_fragment.copy (m_output_file, constituent.variables, 3, 
					     &m_OBJS,
                                             &m_CONSTITUENT,
                                             &m_CONSTITUENTSUFFIX);
            }

          if (constituent.need_check)
            {
              check_application_fragment.copy (m_output_file, constituent.variables, 2, 
					       &m_CONSTITUENT,
                                               &m_CONSTITUENTSUFFIX);
            }
        }
    }

  terminate ();
}

//--------------------------------------------------
DocumentGenerator::DocumentGenerator ()
{
  m_FILEEXTENSION.set ("FILEEXTENSION");

  document_header_fragment.set ("document_header");
  dependency_fragment.set ("dependency");
}

//--------------------------------------------------
void DocumentGenerator::reset ()
{
  AnyDocumentGenerator::reset ();
  m_FILEEXTENSION = "";

  document_header_fragment.reset ();
  dependency_fragment.reset ();
}

//--------------------------------------------------
void DocumentGenerator::build (const cmt_string& package,
			       const Constituent& constituent,
			       bool& dependencies,
			       const cmt_string& file_name)
{
  static cmt_string names;
  static cmt_string output_dir;
  static cmt_string name;
  static cmt_string full_name;
  static cmt_string compressed_name;
  static cmt_string suffix;
  static cmt_string output_suffix;
  static cmt_string fragment_suffix;

  reset ();

  if (!prepare_output (package, constituent, file_name)) return;

  is_library = false;
  is_application = false;
  m_GENERATOR = constituent.generator;
  m_TITLE = "Document";

  int i;

  //  cout << m_TITLE << " " << m_CONSTITUENT << endl;
  CmtMessage::info (m_TITLE + " " + m_CONSTITUENT);

  //
  // Prepare the include paths.
  //

  const CmtSystem::cmt_string_vector& includes = constituent.includes;

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

      m_PACKINCLUDES += " -I";
      m_PACKINCLUDES += subdir;
    }

  //
  // Get the fragment associated with the document style
  //

  FragmentHandle fragment (m_GENERATOR);

  fragment_suffix = fragment.suffix ();

  output_suffix = ".";

  if (fragment_suffix == "")
    {
      output_suffix += fragment.name ();
    }
  else
    {
      output_suffix += fragment_suffix;
    }

  //
  // Scan the sources.
  //

  const CmtSystem::cmt_string_vector& sources = constituent.modules;
  const cmt_vector<cmt_regexp>& excludes = constituent.exclude_exprs;
  const cmt_vector<cmt_regexp>& selects = constituent.select_exprs;

  //  m_LINE = "";

  for (i = 0; i < sources.size (); i++)
    {
      cmt_string& file = sources[i];

      set_full_name (full_name, file);
      if (full_name == "") continue;

      CmtSystem::compress_path (full_name, compressed_name);
      full_name = compressed_name;

      static CmtSystem::cmt_string_vector files;

      int count = get_all_files (full_name, excludes, selects, files);

      //      filter_path (full_name);

      /*
      if (count > 0)
        {
          m_LINE += full_name;
          m_LINE += " ";
        }
      */

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

          if (name != "") 
            {
              analyze_file (name, constituent.name, output_suffix);
            }
        }
    }

  fill_names_outputs ();
  //  fill_outputs ();

  //  prepare_use_context ();

  m_DATE = CmtSystem::now ();
  m_USER = CmtSystem::user ();
  m_PACKAGE = package;

  if (constituent.has_target_tag)
    {
      m_HASTARGETTAG = "has_target_tag";
    }
  else
    {
      m_HASTARGETTAG = "has_no_target_tag";
    }

  m_HASDEPENDENCIES = fragment.need_dependencies () ? "has_dependencies" : "has_no_dependencies" ;

  make_header_fragment.copy (m_output_file, constituent.variables, 8,
			     &m_TITLE, 
                             &m_CONSTITUENT,
                             &m_CONSTITUENTSUFFIX,
			     &m_USER,
                             &m_DATE,
                             &m_PACKAGE,
			     &m_HASTARGETTAG,
			     &m_HASDEPENDENCIES
			     );

  const cmt_string& header = fragment.header ();

  //
  // If the document type specifies a header, use it . 
  // otherwise, use the default document header fragment.
  //
  if (header != "")
    {
      FragmentHandle header_fragment (header);
      header_fragment.copy (m_output_file, constituent.variables, 4, 
			    &m_CONSTITUENT,
                            &m_CONSTITUENTSUFFIX,
                            &m_OBJS,
			    &m_LINE);
    }
  else
    {
      document_header_fragment.copy (m_output_file, constituent.variables, 3, 
				     &m_CONSTITUENT,
                                     &m_CONSTITUENTSUFFIX,
                                     &m_OBJS);
    }

  dependencies = fragment.need_dependencies ();
  if (fragment.need_dependencies ())
    {
      dependencies_fragment.copy (m_output_file, constituent.variables, 3, 
				  &m_CONSTITUENT,
                                  &m_CONSTITUENTSUFFIX,
                                  &m_LINE);
    }
  else
    {
      /*
      for (i = 0; i < sources.size (); i++)
        {
          cmt_string& file = sources[i];
          
          set_full_name (full_name, file);
	  if (full_name == "") continue;
          
	  CmtSystem::compress_path (full_name, compressed_name);
	  full_name = compressed_name;

          static CmtSystem::cmt_string_vector files;
          
          get_all_files (full_name, excludes, selects, files);
          
          for (int j = 0; j < files.size (); j++)
            {
              const cmt_string& name = files[j];
      */              
      for (i = 0; i < m_source_files.size (); i++)
	{
	  SourceFile& file = m_source_files[i];
	  const cmt_string& name = file.name ();
              if (name != "") 
                {
                  static cmt_string s;
                  static cmt_string n;
                  
                  CmtSystem::get_dot_suffix (name, s);
                  CmtSystem::basename (name, s, n);
                  CmtSystem::get_suffix (name, s);
                  
                  fprintf (m_output_file, "%s_%s_dependencies = %s\n",
                           n.c_str (),
                           s.c_str (),
                           name.c_str ());
                }
	      //            }
        }
    }
  
  m_SUFFIX = fragment_suffix;
  for (i = 0; i < m_source_files.size (); i++)
    {
      SourceFile& file = m_source_files[i];
      const cmt_string& file_name = file.name ();
      m_OUTPUTNAME = file.output ();
      m_FULLNAME = file_name;
      CmtSystem::get_dot_suffix (file_name, suffix);
      CmtSystem::basename (file_name, suffix, m_NAME.value);
      CmtSystem::dirname (file_name, m_FILEPATH.value);
      if (m_FILEPATH.value != "") m_FILEPATH.value += CmtSystem::file_separator ();
      filter_path (m_FILEPATH.value);
      m_FILENAME.value = m_NAME.value + suffix;
      //CmtSystem::basename (file_name, m_FILENAME.value);
      m_FILESUFFIX.value = suffix;
      //CmtSystem::get_dot_suffix (m_FILENAME.value, m_FILESUFFIX.value);
      CmtSystem::get_suffix (m_FILENAME.value, m_FILEEXTENSION.value);
      /*
      if (!CmtSystem::test_file (file_name) && !CmtSystem::test_directory (file_name))
        {
          CmtMessage::warning ("Source file " + file_name + " not found");
        }
      */
      filter_path (m_FULLNAME.value);

      if (fragment.need_dependencies ())
	{
	  // ensure that ${CONSTITUENT}_dependencies.make gets rebuilt
	  // whenever source file OR its dependencies change
	  if (!dependency_fragment.copy (m_output_file, constituent.variables, 10,
					 &m_FILEPATH,
					 &m_SUFFIX,
					 &m_OUTPUTNAME,
					 &m_CONSTITUENT,
					 &m_CONSTITUENTSUFFIX,
					 &m_FILENAME,
					 &m_NAME,
					 &m_FULLNAME,
					 &m_FILESUFFIX,
					 &m_FILEEXTENSION)) return;
	}
      
      fragment.copy (m_output_file, constituent.variables, 10,
                     &m_FILEPATH,
                     &m_SUFFIX,
		     &m_OUTPUTNAME,
                     &m_CONSTITUENT,
                     &m_CONSTITUENTSUFFIX,
                     &m_FILENAME,
                     &m_NAME,
                     &m_FULLNAME,
                     &m_FILESUFFIX,
		     &m_FILEEXTENSION);
    }

  const cmt_string& trailer = fragment.trailer ();
  if (trailer != "")
    {
      FragmentHandle trailer_fragment (trailer);
      trailer_fragment.copy (m_output_file, constituent.variables, 4, 
			     &m_CONSTITUENT,
                             &m_CONSTITUENTSUFFIX,
			     &m_OBJS,
			     &m_LINE);
    }

  //
  //  Generate package cleanup operations.
  //

  cleanup_header_fragment.copy (m_output_file, constituent.variables, 2, 
				&m_CONSTITUENT,
                                &m_CONSTITUENTSUFFIX);

  terminate ();
}

//--------------------------------------------------
bool DocumentGenerator::analyze_file (const cmt_string& file,
				      const cmt_string& constituent_name,
				      const cmt_string& output_suffix)
{
  //static cmt_string output_dir;
  static cmt_string suffix;
  static cmt_string name;
  static cmt_string obj;

  if (!CmtSystem::test_file (file) && !CmtSystem::test_directory (file))
    {
      CmtMessage::warning ("Source file " + file + " not found");
    }

  //CmtSystem::dirname (file, output_dir);
  //output_dir += CmtSystem::file_separator ();

  //filter_path (output_dir);

  CmtSystem::get_suffix (file, suffix);
  CmtSystem::basename (file, suffix, name);

  //obj = output_dir;
  obj = "$(";
  obj += constituent_name;
  obj += "_output)";
  obj += name;
  obj += output_suffix;

  SourceFile& source = m_source_files.add ();
  source.set (file, Language::null (), obj);

  return (true);
}

//--------------------------------------------------
ReadmeGenerator::ReadmeGenerator ()
{
  readme_header_fragment.set ("readme_header");
  readme_fragment.set ("readme");
  readme_doc_fragment.set ("readme_doc");
  readme_use_fragment.set ("readme_use");
  readme_trailer_fragment.set ("readme_trailer");
}

void ReadmeGenerator::reset ()
{
  CmtGenerator::reset ();

  readme_header_fragment.reset ();
  readme_fragment.reset ();
  readme_doc_fragment.reset ();
  readme_use_fragment.reset ();
  readme_trailer_fragment.reset ();
}

//--------------------------------------------------
void ReadmeGenerator::build (const CmtSystem::cmt_string_vector& arguments)
{
  reset ();

  m_PACKAGE = Cmt::get_current_package ();
  m_VERSION = Cmt::get_current_version ();
  m_DATE = CmtSystem::now ();
  m_USER = CmtSystem::user ();

  cmt_string url;
  cmt_string doc;

  for (int i = 0; i < arguments.size (); i++)
    {
      cmt_string arg = arguments[i];

      if (arg.substr (0, 5) == "-url=")
        {
          arg.substr (5, url);
        }
      else if (arg.substr (0, 5) == "-doc=")
        {
          arg.substr (5, doc);
        }
    }

  m_output_file_name = cmtdir + "README.html";

  m_output_file = fopen (m_output_file_name.c_str (), "wb");
  if (m_output_file != NULL)
    {
      readme_header_fragment.copy (m_output_file, 2, 
                                   &m_PACKAGE, &m_VERSION);

      if (doc != "")
        {
          m_DOCPATH = doc;
          readme_doc_fragment.copy (m_output_file, 3,
                                    &m_PACKAGE,
                                    &m_VERSION,
                                    &m_DOCPATH);
        }

      readme_fragment.copy (m_output_file, 2,
                            &m_PACKAGE,
                            &m_VERSION);

      int number;
      const Use::UsePtrVector& uses = Use::get_ordered_uses ();

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

	  if (use == 0) continue;
          if (use->discarded) continue;

	  Package* p = use->get_package ();
	  if (p->is_cmt ()) continue;

	  cmt_string selected_path;

	  if (url == "")
	    {
	      selected_path = use->real_path;
	      
	      if (use->specified_path != "")
		{
		  int pos = selected_path.find_last_of (use->specified_path);
		  if (pos != cmt_string::npos)
		    {
		      selected_path.erase (pos);
		    }
		}
	    }
	  else
	    {
	      selected_path = url;
	      
	      if (use->specified_path != "")
		{
		  selected_path += CmtSystem::file_separator ();
		}
	    }
	  
	  m_PACKAGEPATH = selected_path;
	  m_PACKAGEPREFIX = use->specified_path;
	  m_PACKAGE = use->get_package_name ();
	  m_VERSION = use->version;
	  m_MGRSTYLE = (use->style == mgr_style) ? "mgr" : "cmt";
	  readme_use_fragment.copy (m_output_file, 5,
				    &m_PACKAGEPATH,
				    &m_PACKAGEPREFIX,
				    &m_PACKAGE,
				    &m_VERSION,
				    &m_MGRSTYLE);
        }

      m_PACKAGE = Cmt::get_current_package ();
      m_VERSION = Cmt::get_current_version ();
      readme_trailer_fragment.copy (m_output_file, 4, 
                                    &m_PACKAGE, 
                                    &m_VERSION, 
                                    &m_DATE, 
                                    &m_USER);

      terminate ();
    }
  else
    {
      CmtError::set (CmtError::file_access_error, m_output_file_name);
    }
}

//--------------------------------------------------
class Prototyper : public FAwk
{
public:
  Prototyper (bool static_functions = false) :
    m_static_functions(static_functions)
  {
    if (m_static_functions)
      {
	m_suffix = "_static.phnew";
	m_define_suffix = "_static_ph";
      }
    else
      {
	m_suffix = ".phnew";
	m_define_suffix = "_ph";
      }
  }

  void begin ()
  {
    m_running = false;

    static cmt_string suffix;
    static cmt_string name;

    CmtSystem::get_dot_suffix (m_file_name, suffix);
    CmtSystem::basename (m_file_name, suffix, name);

    m_out_file_name  = "";

    if (m_dir_name != "")
      {
	m_out_file_name  = m_dir_name;
	m_out_file_name += CmtSystem::file_separator ();
      }

    m_out_file_name += name;
    m_out_file_name += m_suffix;

    CmtSystem::basename (m_file_name, suffix, m_file_name);

    m_output = fopen (m_out_file_name.c_str (), "wb");

    if (m_output != 0)
      {
	fprintf (m_output, "#ifndef __%s%s__\n", m_file_name.c_str (),
		 m_define_suffix.c_str ());
	fprintf (m_output, "#define __%s%s__\n", m_file_name.c_str (),
		 m_define_suffix.c_str ());

	fprintf (m_output, "\n");
	fprintf (m_output, "#ifdef __cplusplus\n");
	fprintf (m_output, "extern \"C\" {\n");
	fprintf (m_output, "#endif\n");
	fprintf (m_output, "\n");
      }
    else
      {
	stop ();
      }
  }

  void filter (const cmt_string& line)
  {
    char c = line[0];

    if (!m_running)
      {
	if ((c == ' ') ||
	    (c == '/') ||
	    (c == '|') ||
	    (c == '\t') ||
	    (c == '#')) return;
	if (line.find ('(') == cmt_string::npos)
	  {
	    m_prev_line = line;
	    return;
	  }

	m_running = true;
	m_full_line = line;
	m_full_line.replace ("(", " (");

	static CmtSystem::cmt_string_vector words;

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

	const cmt_string& second = words[1];
	if (second[0] == '(')
	  {
	    m_full_line = m_prev_line;
	    m_full_line += " ";
	    m_full_line += line;

	    m_prev_line = "";
	  }
      }
    else
      {
	m_full_line += line;
      }
    if (line.find (')') == cmt_string::npos) return;
    m_running = false;

    if (m_full_line.find (';') != cmt_string::npos) return;
    if (m_full_line.find ("::") != cmt_string::npos) return;
    if (m_full_line.find ('<') != cmt_string::npos) return;
    if (m_full_line.find ('>') != cmt_string::npos) return;
    if (m_full_line.find ('{') != cmt_string::npos) return;
    if (m_full_line.find ('}') != cmt_string::npos) return;
    if (m_full_line.find ("typedef") != cmt_string::npos) return;
    if (m_full_line.find ("yy") != cmt_string::npos) return;
    if (m_full_line.find ("YY") != cmt_string::npos) return;
    if (m_static_functions)
      {
	if (m_full_line.find ("static") == cmt_string::npos) return;
      }
    else
      {
	if (m_full_line.find ("static") != cmt_string::npos) return;
      }

    m_full_line += ";";

    if (m_output != 0)
      {
	fprintf (m_output, "%s\n", m_full_line.c_str ());
      }
  }

  void end ()
  {
    if (m_output != 0)
      {
	fprintf (m_output, "\n");
	fprintf (m_output, "#ifdef __cplusplus\n");
	fprintf (m_output, "}\n");
	fprintf (m_output, "#endif\n");
	fprintf (m_output, "\n");
	fprintf (m_output, "#endif\n");
	fprintf (m_output, "\n");

	fclose (m_output);
      }

    CmtGenerator::check (m_out_file_name);
  }

private:
  bool m_running;
  cmt_string m_out_file_name;
  FILE* m_output;
  bool m_static_functions;
  cmt_string m_full_line;
  cmt_string m_prev_line;
  cmt_string m_suffix;
  cmt_string m_define_suffix;
};
//--------------------------------------------------

//--------------------------------------------------
void PrototypeGenerator::build (const cmt_string& file_name)
{
  Prototyper prototyper;

  reset ();

  prototyper.run (file_name);
}

//--------------------------------------------------
void DefaultMakefileGenerator::build ()
{
  cmt_string makefile;

  //reset ();

  //--- Build a simple Makefile if none is installed

#ifndef WIN32

  bool need_makefile = false;

  makefile = cmtdir + "Makefile";

  if (!CmtSystem::test_file (makefile))
    {
      need_makefile = true;
    }
  else
    {
      static cmt_string s;

      s.read (makefile);
      if ((s.find ("METHODSROOT") != cmt_string::npos) ||
          (s.find ("$(CMTROOT)/src/constituents.make") == cmt_string::npos))
        {
          static cmt_string backup = makefile;
          backup += "_backup";

          makefile += ".cmt";

          if (!CmtSystem::test_file (makefile))
            {
              FILE* file = fopen (backup.c_str (), "wb");
              if (file != NULL)
                {
                  CmtMessage::warning ("\n"
				       "# A Makefile already exists "
				       "but it does not provide\n"
				       "# the recommended features "
				       "for a full benefit of CMT\n"
				       "#\n"
				       "# CMT is now building "
				       "a new 'Makefile.cmt' which you can use\n"
				       "# to upgrade your current one.");
		  /*
                  cerr << "# " << endl;
                  cerr << "#CMT> Warning: " << endl;
                  cerr << "# A Makefile already exists "
		    "but it does not provides " << endl;
                  cerr << "# the recommended features "
		    "for a full benefit of CMT" << endl;
                  cerr << "# " << endl;
                  cerr << "# CMT is now building "
		    "a new 'Makefile.cmt' which you can use" << endl;
                  cerr << "# to upgrade your current one." << endl;
                  cerr << "# " << endl;
		  */
                  s.write (file);
		  CmtSystem::close_ostream (file, backup);
		  //  fclose (file);

                  need_makefile = true;
                }
	      else
		{
		  CmtError::set (CmtError::file_access_error, backup);
		}
            }
        }
    }

  if (need_makefile)
    {
      FILE* file = fopen (makefile.c_str (), "wb");
      if (file != NULL)
        {
          fprintf (file,
		   "include $(CMTROOT)/src/Makefile.header\n"
		   "\n"
		   "include $(CMTROOT)/src/constituents.make\n"
		   "\n");
	  CmtSystem::close_ostream (file, makefile);
	  //          fclose (file);
        }
      else
	{
	  CmtError::set (CmtError::file_access_error, makefile);
	}
    }

#endif

#ifdef WIN32

  makefile = cmtdir + "NMake";

  if (Cmt::get_debug ())
    {
      cout << "DefaultMakefileGenerator::build> pwd=" << CmtSystem::pwd () << " cmtdir=" << cmtdir << endl;
    }

  if (!CmtSystem::test_file (makefile))
    {
      FILE* file = fopen (makefile.c_str (), "wb");
      if (file != NULL)
        {
          fprintf (file,
		   "!include $(CMTROOT)\\src\\NMakefile.header\n"
		   "\n"
		   "!include $(CMTROOT)\\src\\constituents.nmake\n"
		   "\n");
	  CmtSystem::close_ostream (file, makefile);
	  //          fclose (file);
        }
      else
	{
	  CmtError::set (CmtError::file_access_error, makefile);
	}
    }

#endif

}

MSDEVGenerator::MSDEVGenerator ()
{
  dsw_header_fragment.set ("dsw_header");
  dsw_project_fragment.set ("dsw_project");
  dsw_all_project_header_fragment.set ("dsw_all_project_header");
  dsw_all_project_dependency_fragment.set ("dsw_all_project_dependency");
  dsw_all_project_trailer_fragment.set ("dsw_all_project_trailer");
  dsw_trailer_fragment.set ("dsw_trailer");

  dsp_all_fragment.set ("dsp_all");
  dsp_library_header_fragment.set ("dsp_library_header");
  dsp_application_header_fragment.set ("dsp_application_header");
  dsp_windows_header_fragment.set ("dsp_windows_header");
  dsp_contents_fragment.set ("dsp_contents");
  dsp_trailer_fragment.set ("dsp_trailer");
}

void MSDEVGenerator::reset ()
{
  CmtGenerator::reset ();

  dsw_header_fragment.reset ();
  dsw_project_fragment.reset ();
  dsw_all_project_header_fragment.reset ();
  dsw_all_project_dependency_fragment.reset ();
  dsw_all_project_trailer_fragment.reset ();
  dsw_trailer_fragment.reset ();

  dsp_all_fragment.reset ();
  dsp_library_header_fragment.reset ();
  dsp_application_header_fragment.reset ();
  dsp_windows_header_fragment.reset ();
  dsp_contents_fragment.reset ();
  dsp_trailer_fragment.reset ();

  CmtSystem::cd (Cmt::get_current_dir ());

  cmt_string branch = CmtSystem::current_branch ();

  if ((branch == "mgr") || (branch == "cmt"))
    {
#ifdef WIN32
      msdevdir = "..";
      msdevdir += CmtSystem::file_separator ();
      msdevdir += "Visual";
      
      if (!CmtSystem::test_directory (msdevdir))
        {
          CmtSystem::mkdir (msdevdir);
        }
      
      msdevdir += CmtSystem::file_separator ();
#endif
    }
  else
    {
#ifdef WIN32
      msdevdir = ".";
      msdevdir += CmtSystem::file_separator ();
#endif
    }

}

int MSDEVGenerator::build_workspace (const Constituent::ConstituentVector& constituents)
{
  reset ();

  const cmt_string& package = Cmt::get_current_package ();

  m_output_file_name = msdevdir + package + ".dswnew";

  m_output_file = fopen (m_output_file_name.c_str (), "wb");
  if (m_output_file != NULL)
    {
      m_PACKAGE = package;
      dsw_header_fragment.wincopy (m_output_file, 1,
                                   &m_PACKAGE);

      int i;

      dsw_all_project_header_fragment.wincopy (m_output_file, 1, 
                                               &m_PACKAGE);

      for (i = 0; i < constituents.size (); i++)
        {
          const Constituent& constituent = constituents[i];

          if (constituent.type == Library)
            {
              m_CONSTITUENT = constituent.name;
              m_CONSTITUENTSUFFIX = constituent.suffix;
              dsw_all_project_dependency_fragment.wincopy (m_output_file, constituent.variables, 3,
                                                           &m_PACKAGE,
                                                           &m_CONSTITUENT, 
                                                           &m_CONSTITUENTSUFFIX);
            }
	  else
	    {
	      m_CONSTITUENT = constituent.name;
	      m_CONSTITUENTSUFFIX = constituent.suffix;
	      dsw_all_project_dependency_fragment.wincopy (m_output_file, constituent.variables, 3,
                                                           &m_PACKAGE,
							   &m_CONSTITUENT, 
                                                           &m_CONSTITUENTSUFFIX);
	    }

        }

      dsw_all_project_trailer_fragment.wincopy (m_output_file,
                                                1, &m_PACKAGE);

      for (i = 0; i < constituents.size (); i++)
        {
          const Constituent& constituent = constituents[i];

          if (constituent.type == Library)
            {
              m_CONSTITUENT = constituent.name;
              m_CONSTITUENTSUFFIX = constituent.suffix;
              dsw_project_fragment.wincopy (m_output_file,
                                            constituent.variables, 3,
                                            &m_PACKAGE,
                                            &m_CONSTITUENT, 
                                            &m_CONSTITUENTSUFFIX);
            }
          else
            {
              m_CONSTITUENT = constituent.name;
              m_CONSTITUENTSUFFIX = constituent.suffix;
              dsw_project_fragment.wincopy (m_output_file, constituent.variables, 3, 
                                            &m_PACKAGE,
                                            &m_CONSTITUENT, 
                                            &m_CONSTITUENTSUFFIX);
            }
        }

      dsw_trailer_fragment.wincopy (m_output_file, 1, &m_PACKAGE);

      terminate ();
    }
  else
    {
      CmtError::set (CmtError::file_access_error, m_output_file_name);
    }

  m_output_file_name = msdevdir + "all.dspnew";

  m_output_file = fopen (m_output_file_name.c_str (), "wb");
  if (m_output_file != NULL)
    {
      dsp_all_fragment.wincopy (m_output_file, 1, &m_PACKAGE);
      terminate ();
    }
  else
    {
      CmtError::set (CmtError::file_access_error, m_output_file_name);
    }

  return (0);
}

//--------------------------------------------------
int MSDEVGenerator::build_project (const Constituent& constituent)
{
  reset ();

  const cmt_string& package = Cmt::get_current_package ();
  static cmt_string file;
  static cmt_string full_name;
  static cmt_string suffix;

  int i;

  m_CONSTITUENT = constituent.name;
  m_CONSTITUENTSUFFIX = constituent.suffix;

  for (i = 0; i < constituent.includes.size (); i++)
    {
      const cmt_string& include = constituent.includes[i];
      m_PACKINCLUDES += " -I" + include;
    }

  switch (constituent.type)
    {
    case Application:
      is_application = true;
      m_TITLE = "Application";
      break;
    case Library:
      is_library = true;
      m_TITLE = "Library";
      break;
    case Document:
      m_GENERATOR = constituent.generator;
      m_TITLE = "Document";
      break;
    }

  m_PACKOS9 = constituent.need_OS9;

  const CmtSystem::cmt_string_vector& sources = constituent.modules;
  const cmt_vector<cmt_regexp>& excludes = constituent.exclude_exprs;
  const cmt_vector<cmt_regexp>& selects = constituent.select_exprs;

  //--- Build the constituents fragment -----

  m_output_file_name = msdevdir + m_CONSTITUENT + ".dspnew";
  m_output_file = fopen (m_output_file_name.c_str (), "wb");

  if (m_output_file == NULL) return (0);

  m_PACKAGE = package;

  if (is_library)
    {
      if (constituent.no_share)
        {
          m_LIBRARYSUFFIX = "lib";
        }
      else
        {
          m_LIBRARYSUFFIX = "arc";
        }

      dsp_library_header_fragment.wincopy (m_output_file, constituent.variables, 4,
                                           &m_PACKAGE,
                                           &m_CONSTITUENT, 
                                           &m_CONSTITUENTSUFFIX, 
                                           &m_LIBRARYSUFFIX);
    }
  else
    {
      if (constituent.windows)
        {
          dsp_windows_header_fragment.wincopy (m_output_file, constituent.variables, 3,
                                               &m_PACKAGE,
                                               &m_CONSTITUENT, 
                                               &m_CONSTITUENTSUFFIX);
        }
      else
        {
          dsp_application_header_fragment.wincopy (m_output_file, constituent.variables, 3,
                                                   &m_PACKAGE,
                                                   &m_CONSTITUENT, 
                                                   &m_CONSTITUENTSUFFIX);
        }
    }

  for (i = 0; i < sources.size (); i++)
    {
      file = sources[i];

      set_full_name (full_name, file);
      if (full_name == "") continue;

      static CmtSystem::cmt_string_vector files;

      get_all_files (full_name, excludes, selects, files);

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

          if (name != "") 
            {
              m_FULLNAME = name;

              if (m_output_file != NULL)
                {
                  dsp_contents_fragment.wincopy (m_output_file, constituent.variables, 2, 
                                                 &m_PACKAGE, 
                                                 &m_FULLNAME);
                }
            }
        }
    }

  if (m_output_file != NULL)
    {
      dsp_trailer_fragment.wincopy (m_output_file, constituent.variables, 3,
                                    &m_PACKAGE,
				    &m_CONSTITUENT, 
                                    &m_CONSTITUENTSUFFIX);

      terminate ();
    }

  return (0);
}


VSNETGenerator::VSNETGenerator ()
{
  sln_header_fragment.set ("sln_header");
  sln_project_fragment.set ("sln_project");
  sln_dependency_header_fragment.set ("sln_dependency_header");
  sln_dependency_project_fragment.set ("sln_dependency_project");
  sln_dependency_trailer_fragment.set ("sln_dependency_trailer");
  sln_project_config_fragment.set ("sln_project_config");
  sln_trailer_fragment.set ("sln_trailer");

  vcproj_all_fragment.set ("vcproj_all");
  vcproj_library_header_fragment.set ("vcproj_library_header");
  vcproj_application_header_fragment.set ("vcproj_application_header");
  vcproj_windows_header_fragment.set ("vcproj_windows_header");
  vcproj_contents_fragment.set ("vcproj_contents");
  vcproj_directory_header_fragment.set ("vcproj_directory_header");
  vcproj_directory_trailer_fragment.set ("vcproj_directory_trailer");
  vcproj_trailer_fragment.set ("vcproj_trailer");
}

void VSNETGenerator::reset ()
{
  CmtGenerator::reset ();

  CmtSystem::cd (Cmt::get_current_dir ());

  cmt_string branch = CmtSystem::current_branch ();

  if ((branch == "mgr") || (branch == "cmt"))
    {
#ifdef WIN32
      vsnetdir = "..";
      vsnetdir += CmtSystem::file_separator ();
      vsnetdir += "Visual";
      
      if (!CmtSystem::test_directory (vsnetdir))
        {
          CmtSystem::mkdir (vsnetdir);
        }
      
      vsnetdir += CmtSystem::file_separator ();
#endif
    }
  else
    {
#ifdef WIN32
      vsnetdir = ".";
      vsnetdir += CmtSystem::file_separator ();
#endif
    }
}

void VSNETGenerator::pseudoGUID (const cmt_string& a, 
                                 const cmt_string& b, 
                                 const cmt_string& c, 
                                 cmt_string& d)
{
  char buf[64]; // make the guid in here
  static char hex[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
  int k = 0;
  int i;

  for (i = 0; (i < c.size()) && (k < sizeof(buf)); ++i, ++k) buf[k] = c[i];
  for (i = 0; (i < a.size()) && (k < sizeof(buf)); ++i, ++k) buf[k] = a[i];
  for (i = 0; (i < b.size()) && (k < sizeof(buf)); ++i, ++k) buf[k] = b[i];
  for (; k < sizeof(buf); ++k) buf[k] = 0;

  // now use the buffer to format the output string
  // example: {3FE091FC-3738-4F2E-9723-E846B43F77AB}
  d = '{';
  k = 0;

  for (i = 0; i < 4; ++i, ++k) { d += hex[buf[k]&15]; d += hex[buf[k] >> 4]; } d += '-';
  for (i = 0; i < 2; ++i, ++k) { d += hex[buf[k]&15]; d += hex[buf[k] >> 4]; } d += '-';
  for (i = 0; i < 2; ++i, ++k) { d += hex[buf[k]&15]; d += hex[buf[k] >> 4]; } d += '-';
  for (i = 0; i < 2; ++i, ++k) { d += hex[buf[k]&15]; d += hex[buf[k] >> 4]; } d += '-';
  for (i = 0; i < 6; ++i, ++k) { d += hex[buf[k]&15]; d += hex[buf[k] >> 4]; } d += '}';
}

int VSNETGenerator::build_workspace (const Constituent::ConstituentVector& constituents)
{
  reset ();

  const cmt_string& package = Cmt::get_current_package ();
  
  m_output_file_name = vsnetdir + package + ".slnnew";
  
  Variable PACKAGE_GUID ("PACKAGE_GUID");
  Variable CONSTITUENT_GUID ("CONSTITUENT_GUID");
  Variable NUMBER ("NUMBER");
  
  cmt_string guid;
  pseudoGUID (package, Cmt::get_current_version(), "", guid);
  PACKAGE_GUID = guid;
  
  m_output_file = fopen (m_output_file_name.c_str (), "wb");
  
  if (m_output_file != NULL)
    {
      m_PACKAGE = package;
      sln_header_fragment.wincopy (m_output_file, 2, 
                                   &m_PACKAGE,
                                   &PACKAGE_GUID);
      
      int i;
      
      for (i = 0; i < constituents.size (); i++)
	{
	  const Constituent& constituent = constituents[i];
	  
	  pseudoGUID (package, Cmt::get_current_version(), constituent.name, guid);
	  CONSTITUENT_GUID = guid;
	  
	  if (constituent.type == Library)
	    {
	      m_CONSTITUENT = constituent.name;
	      m_CONSTITUENTSUFFIX = constituent.suffix;
	      sln_project_fragment.wincopy (m_output_file,
					    constituent.variables, 4,
					    &m_PACKAGE,
					    &m_CONSTITUENT,
					    &PACKAGE_GUID,
					    &CONSTITUENT_GUID);
	    }
	  else
	    {
	      m_CONSTITUENT = constituent.name;
	      m_CONSTITUENTSUFFIX = constituent.suffix;
	      sln_project_fragment.wincopy (m_output_file, constituent.variables, 4,
					    &m_PACKAGE,
					    &m_CONSTITUENT,
					    &PACKAGE_GUID,
					    &CONSTITUENT_GUID);
	    }
	}
      
      sln_dependency_header_fragment.wincopy (m_output_file,
					      1, &m_PACKAGE);
      
      for (i = 0; i < constituents.size (); i++)
	{
	  const Constituent& constituent = constituents[i];
	  pseudoGUID (package, Cmt::get_current_version(), constituent.name, guid);
	  CONSTITUENT_GUID = guid;
	  
	  cmt_string num;
	  num = (char)('0' + i);
	  NUMBER = num;
	  if (constituent.type == Library)
	    {
	      m_CONSTITUENT = constituent.name;
	      m_CONSTITUENTSUFFIX = constituent.suffix;
	      
	      sln_dependency_project_fragment.wincopy (m_output_file, constituent.variables, 5,
						       &m_PACKAGE,
						       &m_CONSTITUENT,
						       &PACKAGE_GUID,
						       &CONSTITUENT_GUID,
						       &NUMBER);
	    }
 	  else
 	    {
 	      m_CONSTITUENT = constituent.name;
 	      m_CONSTITUENTSUFFIX = constituent.suffix;
 	      sln_dependency_project_fragment.wincopy (m_output_file, constituent.variables, 5,
						       &m_PACKAGE,
						       &m_CONSTITUENT,
						       &PACKAGE_GUID,
						       &CONSTITUENT_GUID, 
                                                       &NUMBER);
 	    }
	}
      
      sln_dependency_trailer_fragment.wincopy (m_output_file,
					       1, &m_PACKAGE);
      
      for (i = 0; i < constituents.size (); i++)
	{
	  const Constituent& constituent = constituents[i];
	  pseudoGUID (package, Cmt::get_current_version(), constituent.name, guid);
	  CONSTITUENT_GUID = guid;
	  
	  if (constituent.type == Library)
	    {
	      m_CONSTITUENT = constituent.name;
	      m_CONSTITUENTSUFFIX = constituent.suffix;
	      sln_project_config_fragment.wincopy (m_output_file,
						   constituent.variables, 3,
						   &m_PACKAGE,
						   &m_CONSTITUENT,
						   &CONSTITUENT_GUID);
	    }
	  else
	    {
	      m_CONSTITUENT = constituent.name;
	      m_CONSTITUENTSUFFIX = constituent.suffix;
	      sln_project_config_fragment.wincopy (m_output_file, constituent.variables, 3,
						   &m_PACKAGE,
						   &m_CONSTITUENT,
						   &CONSTITUENT_GUID);
	    }
	}
      
      sln_trailer_fragment.wincopy (m_output_file, 1, &m_PACKAGE);

      terminate ();
    }
  
  m_output_file_name = vsnetdir + "all.vcprojnew";
  
  m_output_file = fopen (m_output_file_name.c_str (), "wb");
  if (m_output_file != NULL)
    {
      vcproj_all_fragment.wincopy (m_output_file, 1, &m_PACKAGE);

      terminate ();
    }
  
  return (0);
}

int VSNETGenerator::build_project (const Constituent& constituent)
{
  reset ();
  
  const cmt_string& package = Cmt::get_current_package();
  static cmt_string file;
  static cmt_string full_name;
  static cmt_string suffix;
  
  static Variable GUID("GUID");
  int i;
  
  // Directory Support
  int dir_pos;
  int file_pos;
  int src_pos;
  int iSFFilter = 0;
  cmt_string directory;
  cmt_string new_dir;
  bool need_trailer = false;

  m_CONSTITUENT = constituent.name;
  // make up a pseudo-GUID from the constituent-pacakge-version combination
  
  cmt_string guid;
  pseudoGUID (package, Cmt::get_current_version(), constituent.name, guid);
  
  GUID = guid;
  
  for (i = 0; i < constituent.includes.size (); i++)
    {
      const cmt_string& include = constituent.includes[i];
      m_PACKINCLUDES += " -I" + include;
    }
  
  switch (constituent.type)
    {
    case Application:
      is_application = true;
      m_TITLE = "Application";
      break;
    case Library:
      is_library = true;
      m_TITLE = "Library";
      break;
    case Document:
      m_GENERATOR = constituent.generator;
      m_TITLE = "Document";
      break;
    }
  
  m_PACKOS9 = constituent.need_OS9;
  
  const CmtSystem::cmt_string_vector& sources = constituent.modules;
  const cmt_vector<cmt_regexp>& excludes = constituent.exclude_exprs;
  const cmt_vector<cmt_regexp>& selects = constituent.select_exprs;
  
  //--- Build the constituents fragment -----
  cmt_string output;
  
  m_output_file_name = vsnetdir + m_CONSTITUENT + ".vcprojnew";
  m_output_file = fopen (m_output_file_name.c_str (), "wb");
  
  if (m_output_file == NULL) return (0);
  
  m_PACKAGE = package;
  
  if (is_library)
    {
      if (constituent.no_share)
	{
	  m_LIBRARYSUFFIX = "lib";
	}
      else
	{
	  m_LIBRARYSUFFIX = "arc";
	}
      
      vcproj_library_header_fragment.wincopy (m_output_file, constituent.variables, 4,
					      &m_PACKAGE,
					      &m_CONSTITUENT,
					      &GUID,
					      &m_LIBRARYSUFFIX);
    }
  else
    {
      if (constituent.windows)
	{
	  vcproj_windows_header_fragment.wincopy (m_output_file, constituent.variables, 3,
						  &m_PACKAGE,
						  &m_CONSTITUENT,
						  &GUID);
	}
      else
	{
	  vcproj_application_header_fragment.wincopy (m_output_file, constituent.variables, 3,
						      &m_PACKAGE,
						      &m_CONSTITUENT,
						      &GUID);
	}
    }
  
  for (i = 0; i < sources.size (); i++)
    {
      file = sources[i];
      
      set_full_name (full_name, file);
      if (full_name == "") continue;
      
      static CmtSystem::cmt_string_vector files;
      
      get_all_files (full_name, excludes, selects, files);
      
      for (int j = 0; j < files.size (); j++)
	{
	  const cmt_string& name = files[j];
	  
	  if (name != "")
	    {
	      m_FULLNAME = name;

	      // Add Directory Support here
	      // Step 1: Parse into "..\src\" "directory" "\filename.cxx"

	      // find ..\ ;
	      src_pos = name.find('\\');
	      // Finds ..\src\ ;
	      dir_pos = name.find(src_pos+1, '\\') + 1;
	      // Finds ..\src\..\astro\ ;
	      file_pos = name.find_last_of('\\');
	      
	      // Debug only
	      //printf("%40s, %i, %i, %i;\n", name src_pos, dir_pos, file_pos);
	      // If dir_pos == file_pos, then we have ../src/filename.cxx
	      // If dir_pos >  file_pos, then we have ../filename.cxx or something odd.
			   
	      // Step 2: see if it is or is not a ../src/ directory.
	      if ((dir_pos < file_pos) && (dir_pos > src_pos))
		{
		  new_dir = name.substr (dir_pos, file_pos-dir_pos);
		  new_dir.replace( "..\\", ""); // All names are relative to package/Visual,
		                                // so we want to ditch the prevailing ..\ ;
                                                // which all of them have.
		}
	      else
		{
		  new_dir = "Source Files NN";
		}

	      // Step 3: Add directory structure to vcproj file.
	      if (new_dir != directory) // Detects a change in directory
		{
		  directory = new_dir;
		  // Step 3a: Add a </Filter> when neccessary.
		  if (need_trailer == false)
		    {
		      // Ensure that no trailing </Filter> is placed incorrectly.
		      need_trailer = true;
		    }
		  else
		    {
		      vcproj_directory_trailer_fragment.wincopy (m_output_file,
								 constituent.variables, 1,
								 &m_PACKAGE);
		    }

		  // Step 3b: Add a <Filter> when neccessary.
		  if ((dir_pos < file_pos) && (dir_pos > src_pos))
		    {
		      // Add <Filter Name="directory">
		      m_DIRNAME = new_dir;
		      vcproj_directory_header_fragment.wincopy (m_output_file, constituent.variables, 2,
								&m_PACKAGE,
								&m_DIRNAME);
		    }
		  else
		    {
		      // Ensure that no </Filter> is placed incorrectly.
		      // This is the case of the file being in ../src 
		      // which requires no directory. Thus no filter start or end tag is needed.

		      need_trailer = false;
		    }
		}

	      if (m_output_file != NULL)
		{
		  vcproj_contents_fragment.wincopy (m_output_file, constituent.variables, 2,
						    &m_PACKAGE,
						    &m_FULLNAME);
		}
	    }
	}
    }

  if (need_trailer == true)
    {
      // Add a trailing </Filter> for directory support.
      vcproj_directory_trailer_fragment.wincopy (m_output_file, constituent.variables, 1,
						 &m_PACKAGE);
    }

  if (m_output_file != NULL)
    {
      vcproj_trailer_fragment.wincopy (m_output_file, constituent.variables, 3,
				       &m_PACKAGE,
				       &m_CONSTITUENT,
				       &m_CONSTITUENTSUFFIX);

      terminate ();
    }

  return (0);
}

MakeSetupGenerator::MakeSetupGenerator ()
{
  make_setup_header_fragment.set ("make_setup_header");
  make_setup_fragment.set ("make_setup");
}

void MakeSetupGenerator::reset ()
{
  CmtGenerator::reset ();

  make_setup_header_fragment.reset ();
  make_setup_fragment.reset ();
}

void MakeSetupGenerator::build (const cmt_string& package)
{
  reset ();

  m_PACKAGE = package;

  cmt_string file_name = "setup.";

  if (Cmt::build_nmake ())
    {
      file_name += "nmake";
    }
  else
    {
      file_name += "make";
    }
  
  cmt_string new_file_name = file_name;
  new_file_name += "new";

  m_output_file = fopen (new_file_name, "wb");

  if (m_output_file != NULL)
    {
      int number;

      const Use::UsePtrVector& uses = Use::get_ordered_uses ();

      const Constituent::ConstituentVector& constituents =
	Constituent::constituents ();

      cmt_string temp;

      make_setup_header_fragment.copy (m_output_file, 1, &m_PACKAGE);

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

          if (use->discarded) continue;

          if (use->real_path != "")
            {
              temp  = use->prefix;
              temp += "ROOT = ";
              temp += use->get_full_path ();

              fprintf (m_output_file, "%s\n", temp.c_str());
            }
        }

      temp  = "use_requirements = ";
      temp += "requirements ";

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

          if (use->discarded) continue;

          if (use->real_path != "")
            {
              temp += "$(";
              temp += use->prefix;
              temp += "ROOT)";
              switch (use->style)
                {
		case cmt_style:
		  temp += CmtSystem::file_separator ();
		  temp += "cmt";
		  break;
		case mgr_style:
		  temp += CmtSystem::file_separator ();
		  temp += "mgr";
		  break;
                default:
		  break;
                }
              temp += CmtSystem::file_separator ();
              temp += "requirements ";
            }
        }

      fprintf (m_output_file, "%s\n", temp.c_str());

      temp  = "constituents = $(constituents)";
      Symbol::expand (temp);

      fprintf (m_output_file, "%s\n", temp.c_str());

      make_setup_fragment.copy (m_output_file, 1, &m_PACKAGE);

      CmtSystem::close_ostream (m_output_file, new_file_name);
      //  fclose (m_output_file);

      //--- Complete the operation --------------

      commit (new_file_name);
    }
  else
    {
      CmtError::set (CmtError::file_access_error, new_file_name);
    }

  /*
    for option in $*
    do
    case ${option} in
    args-tag=*)
    tag=${option}
    tag=`echo "${tag}" | sed -e 's/args.tag=//'`
    ;;
    -tag=*)
    tag=args${option}
    tag=`echo "${tag}" | sed -e 's/args.tag=//'`
    ;;
    esac
    done

    if test "${tag}" = "" ; then
    tag=${CMTCONFIG}
    fi

    build_shell_setup_files ${tag}

    now=`date`

  */
}

ConstituentsMakefileGenerator::ConstituentsMakefileGenerator ()
{
  constituents_header_fragment.set ("constituents_header");
  constituents_trailer_fragment.set ("constituents_trailer");
  group_fragment.set ("group");
  constituent_fragment.set ("constituent");
  constituent_lock_fragment.set ("constituent_lock");
  constituent_app_lib_fragment.set ("constituent_app_lib");
  check_application_header_fragment.set ("check_application_header");
}

void ConstituentsMakefileGenerator::reset ()
{
  CmtGenerator::reset ();
  constituents_header_fragment.reset ();
  constituents_trailer_fragment.reset ();
  group_fragment.reset ();
  constituent_fragment.reset ();
  constituent_lock_fragment.reset ();
  constituent_app_lib_fragment.reset ();
  check_application_header_fragment.reset ();
}

//--------------------------------------------------
void ConstituentsMakefileGenerator::build (const cmt_string& package,
					   const cmt_string& file)
//					   const CmtSystem::cmt_string_vector& arguments)
{
  reset ();

  cmt_string file_name (file);
    //, dir_name;

//   if (arguments.size () > 0)
//     {
//       cmt_string arg = arguments[0];
//       if (arg.substr (0, 5) == "-out=")
// 	{
// 	  arg.erase (0, 5);
// 	  file_name = arg;
// 	}
//       else if (arg.substr (0, 8) == "-outdir=")
// 	{
// 	  arg.erase (0, 8);
// 	  dir_name = arg;
// 	}
//     }

  if (file_name == "")
    {
      file_name = "constituents.";

      //--- Build the constituents fragment -----

      if (Cmt::build_nmake ())
	{
	  file_name += "nmake";
	}
      else
	{
	  file_name += "make";
	}
    }

//   if (dir_name != "")
//     {
//       if (dir_name [dir_name.size () - 1] != CmtSystem::file_separator ())
// 	dir_name += CmtSystem::file_separator ();
//       file_name = dir_name + file_name;
//     }

  cmt_string save_file_name = file_name;
  save_file_name += "cmtsave";

  if (CmtSystem::test_file (file_name))
    {
      rename (file_name, save_file_name);
    }

  cmt_string new_file_name = file_name;
  new_file_name += "new";

  m_output_file = fopen (new_file_name, "wb");
  if (m_output_file != NULL)
    {
      int number;
      const Constituent::ConstituentVector&
	constituents = Constituent::constituents ();

      m_PACKAGE = package;

      constituents_header_fragment.copy (m_output_file, 1, &m_PACKAGE);

      m_GROUP = "all";
      group_fragment.copy (m_output_file, 1, &m_GROUP);

      const Group::GroupVector& groups = Group::groups ();

      for (number = 0; number < groups.size (); number++)
        {
          const Group& group = groups[number];

          m_GROUP = group.name ();

          group_fragment.copy (m_output_file, 1, &m_GROUP);
        }
      
      bool lock = false;
      Symbol* lock_command_macro = Symbol::find ("lock_command");
      if (lock_command_macro != 0)
	{
	  cmt_string lock_command = lock_command_macro->resolve_macro_value ();
	  if (lock_command != "")
	    {
	      Symbol* unlock_command_macro = Symbol::find ("unlock_command");
	      if (unlock_command_macro != 0)
		{
		  cmt_string unlock_command = unlock_command_macro->resolve_macro_value ();
		  if (unlock_command != "")
		    {
		      lock = true;
		    }
		}
	    }
	}
      for (number = 0; number < constituents.size (); number++)
        {
          const Constituent& constituent = constituents[number];

          m_CONSTITUENT = constituent.name;
          m_CONSTITUENTSUFFIX = constituent.suffix;

          m_LINE = "";

	  if (constituent.has_target_tag)
	    {
	      m_HASTARGETTAG = "has_target_tag";
	    }
	  else
	    {
	      m_HASTARGETTAG = "has_no_target_tag";
	    }

	  switch (constituent.type)
	    {
	    case Application:
	    case Library:
	      m_HASDEPENDENCIES = "has_dependencies";
	      m_HASPROTOTYPES = constituent.need_prototypes ? "has_prototypes" : "has_no_prototypes" ;
	      break;
	    case Document:
	      m_HASDEPENDENCIES = FragmentHandle (constituent.generator).need_dependencies () ? "has_dependencies" : "has_no_dependencies" ;
	      break;
	    }

	  if (constituent.type == Document && lock == true)
	    {
	      constituent_lock_fragment.copy (m_output_file, constituent.variables,
					      6,
					      &m_PACKAGE,
					      &m_CONSTITUENT, 
					      &m_CONSTITUENTSUFFIX,
					      &m_LINE,
					      &m_HASDEPENDENCIES,
					      &m_HASTARGETTAG);
	    }
	  else if (constituent.type == Application ||
		   constituent.type == Library)
	    {
	      constituent_app_lib_fragment.copy (m_output_file, constituent.variables,
						 7,
						 &m_PACKAGE,
						 &m_CONSTITUENT, 
						 &m_CONSTITUENTSUFFIX,
						 &m_LINE,
						 &m_HASDEPENDENCIES,
						 &m_HASTARGETTAG,
						 &m_HASPROTOTYPES);
	    }
	  else
	    {
	      constituent_fragment.copy (m_output_file, constituent.variables,
					 6,
					 &m_PACKAGE,
					 &m_CONSTITUENT, 
					 &m_CONSTITUENTSUFFIX,
					 &m_LINE,
					 &m_HASDEPENDENCIES,
					 &m_HASTARGETTAG);
	    }

          if (constituent.need_check)
            {
	      if (constituent.group != 0 && 
		  constituent.group->name () == "check")
		m_ISCHECKGROUP = "is_check_group";
	      else
		m_ISCHECKGROUP = "is_not_check_group";

              check_application_header_fragment.copy (m_output_file, 
						      constituent.variables, 4,
						      &m_PACKAGE,
						      &m_CONSTITUENT,
                                                      &m_CONSTITUENTSUFFIX,
						      &m_ISCHECKGROUP);
            }
        }

      constituents_trailer_fragment.copy (m_output_file, 0);

      CmtSystem::close_ostream (m_output_file, new_file_name);
      //  fclose (m_output_file);

      commit (new_file_name);
    }
  else
    {
      CmtError::set (CmtError::file_access_error, new_file_name);
    }
}

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

PackagesMakefileGenerator::PackagesMakefileGenerator ()
{
  m_DEPENDENCIES.set ("DEPENDENCIES");
  m_PACKAGEMGRPATH.set ("PACKAGEMGRPATH");
  m_PACKAGEFULLNAME.set ("PACKAGEFULLNAME");
  m_ISLOCAL.set ("ISLOCAL");
  m_ISINCLUDED.set ("ISINCLUDED");

  packages_header_fragment.set ("packages_header");
  packages_trailer_fragment.set ("packages_trailer");
  package_fragment.set ("package");
}

void PackagesMakefileGenerator::reset ()
{
  CmtGenerator::reset ();
  m_DEPENDENCIES = "";
  m_PACKAGEMGRPATH = "";
  m_PACKAGEFULLNAME = "";
  m_ISLOCAL = "";
  m_ISINCLUDED = "";

  packages_header_fragment.reset ();
  packages_trailer_fragment.reset ();
  package_fragment.reset ();
}

//--------------------------------------------------
void PackagesMakefileGenerator::build (const cmt_string& package,
				       const cmt_string& file)
{
  reset ();

  cmt_string file_name (file);
  if (file_name == "")
    {
      file_name = "packages.";

      if (Cmt::build_nmake ())
	{
	  file_name += "nmake";
	}
      else
	{
	  file_name += "make";
	}
    }

  cmt_string save_file_name = file_name;
  save_file_name += "cmtsave";

  if (CmtSystem::test_file (file_name))
    {
      rename (file_name, save_file_name);
    }

  cmt_string new_file_name = file_name;
  new_file_name += "new";

  m_output_file = fopen (new_file_name, "wb");
  if (m_output_file != NULL)
    {
      m_PACKAGE = package;

      if (!packages_header_fragment.copy (m_output_file, 1, &m_PACKAGE)) return;

      const Project* p_cur (Project::get_current ());
      Use::UsePtrVector uses (Use::get_ordered_uses ());
      uses.push_back (&Use::current ());

      Project::ConstProjectPtrVector path_exclusions;
      Project::fill_exclusion (path_exclusions);

      cmt_string temp;
      for (int i = uses.size () - 1; i >= 0; i--)
	{
	  Use* use = uses[i];

	  if (use->discarded) continue;
	  if (use->m_hidden) continue;
	  if (!use->located ()) continue;
	  if (use->get_package ()->is_cmt ()) continue;

	  const Project* up = use->get_project ();

	  m_ISLOCAL = "is_not_local";
	  if (p_cur)
	    {
	      if (up)
		{
		  if (up == p_cur)
		    {
		      m_ISLOCAL = "is_local";
		    }
		}
	      else
		{
		  if (use->get_realpath ().find (p_cur->get_cmtpath_real ()) == 0)
		    {
		      m_ISLOCAL = "is_local";
		    }
		}
	    }
	  else if (use == &Use::current ())
	    {
	      m_ISLOCAL = "is_local";
	    }

	  m_ISINCLUDED = "is_included";
          for (int j = 0; j < path_exclusions.size (); j++)
            {
              const Project* sp = path_exclusions[j];
	      if (up)
		{
		  if (up == sp)
		    {
		      m_ISINCLUDED = "is_not_included";
		    }
		}
	      else
		{
		  if (use->get_realpath ().find (sp->get_cmtpath_real ()) == 0)
		    {
		      m_ISINCLUDED = "is_not_included";
		    }
		}
            }

	  temp = use->get_full_path ();
	  switch (use->style)
	    {
	    case cmt_style:
	      temp += CmtSystem::file_separator ();
	      temp += "cmt";
	      break;
	    case mgr_style:
	      temp += CmtSystem::file_separator ();
	      temp += "mgr";
	      break;
	    default:
	      break;
	    }
#ifdef WIN32
	  temp += " ";
#endif
	  m_PACKAGEMGRPATH = temp;

	  temp = "";
	  if (Symbol* s = Symbol::find (use->get_package_name () + "_offset"))
	    {
	      cmt_string o = s->build_macro_value ();
	      if (o != "")
		{
		  temp += o;
		  temp += CmtSystem::file_separator ();
		}
	    }
	  else
	    {
	      CmtMessage::warning
		(CmtError::get_error_name (CmtError::symbol_not_found)
		 + ": macro " + use->get_package_name () + "_offset");
	    }
	  temp += use->get_package_name ();
	  temp.replace_all (CmtSystem::file_separator (), "_");
#ifdef WIN32
	  temp += " ";
#endif
	  m_PACKAGEFULLNAME = temp;

	  m_PACKAGE = use->get_package_name ();
	  m_PACKAGEPREFIX = use->prefix;

	  Use::UsePtrVector subuses;
	  for (int i = 0; i < use->sub_uses.size (); i++)
	    {
	      if (use->sub_uses[i]->m_index >= 0 && !use->sub_uses[i]->discarded)
		{
		  if (use->sub_uses[i]->m_hidden) continue;
		  subuses.push_back (use->sub_uses[i]);
		}
	      else
		{
		  Use* au (Use::find_valid (use->sub_uses[i]->get_package_name ()));
		  if (au)
		    {
		      subuses.push_back (au);
		    }
		}
	    }
	  m_DEPENDENCIES = "";
	  for (int i = 0; i < subuses.size (); i++)
	    {
	      if (i != 0)
		{
		  m_DEPENDENCIES += " " + subuses[i]->get_package_name ();
		}
	      else
		{
		  m_DEPENDENCIES += subuses[i]->get_package_name ();
		}
	    }

	  if (!package_fragment.copy (m_output_file, 7,
				      &m_PACKAGE, &m_PACKAGEPREFIX,
				      &m_DEPENDENCIES,
				      &m_PACKAGEMGRPATH, &m_PACKAGEFULLNAME,
				      &m_ISLOCAL, &m_ISINCLUDED)) return;
	}

      if (Symbol* s = Symbol::find ("CMTINSTALLAREA"))
	{
	  cmt_string o = s->build_macro_value ();
	  Symbol::expand (o);
	  if (o != "")
	    {
	      temp  = "CMTINSTALLAREA=";
	      temp += o;
#ifdef WIN32
	      temp += " ";
#endif
	      fprintf (m_output_file, "%s\n", temp.c_str());
	    }
	}

      if (!packages_trailer_fragment.copy (m_output_file, 0)) return;

      CmtSystem::close_ostream (m_output_file, new_file_name);

      commit (new_file_name);
    }
  else
    {
      CmtError::set (CmtError::file_access_error, new_file_name);
    }
}

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

/**
   With this Awk filter, we analyze an existing dependency file.
   We get the source name in each line
   The list of sources is maintained in m_sources
   A source is stored in the form <name>_<suffix> (instead of <name>.<suffix>)
*/
class DependencyFilter : public Awk
{
public:
  DependencyFilter ()
  {
  }

  void begin ()
  {
    m_sources = "";
  }

  void filter (const cmt_string& line)
  {
    int pos = line.find ("_dependencies = ");
    if (pos == cmt_string::npos) return;

    cmt_string s = line;
    s.erase (pos);

    m_sources += " ";
    m_sources += s;
    m_sources += " ";

    //pos = s.find_last_of ("_");
    //if (pos != cmt_string::npos) s[pos] = "."
  }

  void add_source (const cmt_string& file_name)
  {
    static cmt_string suffix;
    static cmt_string name;

    CmtSystem::get_dot_suffix (file_name, suffix);
    CmtSystem::basename (file_name, suffix, name);
    CmtSystem::get_suffix (file_name, suffix);

    cmt_string s = " ";
    s += name;
    s += "_";
    s += suffix;
    s += " ";

    if (m_sources.find (s) == cmt_string::npos)
      {
	m_sources += s;
      }        
  }

  bool has_source (const cmt_string& file_name) const
  {
    static cmt_string suffix;
    static cmt_string name;

    CmtSystem::get_dot_suffix (file_name, suffix);
    CmtSystem::basename (file_name, suffix, name);
    CmtSystem::get_suffix (file_name, suffix);

    cmt_string s = " ";
    s += name;
    s += "_";
    s += suffix;
    s += " ";

    if (m_sources.find (s) == cmt_string::npos)
      {
	return (false);
      }
    else
      {
	return (true);
      }
  }

  cmt_string& get_sources ()
  {
    return (m_sources);
  }

private:
  cmt_string m_sources;
};

//--------------------------------------------------
void DependencyGenerator::reset ()
{
  CmtGenerator::reset ();
  m_deps_builder.clear ();
  m_stamps = true;
  m_name = "cmt_unnamed";
}

//--------------------------------------------------
void DependencyGenerator::prepare_includes ()
{
  cmt_string path;
  cmt_string substitution;

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

  //  m_deps_builder.clear ();

  if (use->include_path != "none")
    {
      if (use->include_path == "")
	{
	  m_deps_builder.add (incdir, "$(src)");
	}
      else
	{
	  substitution = use->include_path;
	  
	  path = substitution;
	  Symbol::expand (path);
	  
	  CmtSystem::reduce_file_separators (path);

          m_deps_builder.add (path, substitution);
	}
    }

  m_deps_builder.add_includes (*use);

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

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

      for (number = 0; number < uses.size (); number++)
        {
          use = uses[number];
          if (use->discarded) continue;

          if (use->real_path != "")
            {
	      if (use->include_path != "none")
		{
		  if (use->include_path == "")
		    {
		      use->get_full_path (path);
                      path += CmtSystem::file_separator ();
		      path += "src";

		      substitution = "$(";
		      substitution += use->prefix;
		      substitution += "ROOT)";
		      substitution += CmtSystem::file_separator ();
		      substitution += "src";
		      substitution += CmtSystem::file_separator ();
		    }
		  else
		    {
		      substitution = use->include_path;

		      path = substitution;
		      Symbol::expand (path);

                      CmtSystem::reduce_file_separators (path);
		    }

		  m_deps_builder.add (path, substitution);
		}

              m_deps_builder.add_includes (*use);
            }
        }
    }
}

//--------------------------------------------------
void DependencyGenerator::prepare_header_file_filters ()
{
  const Use* current_use = &Use::current ();
  Use::UsePtrVector uses (Use::get_ordered_uses ());
  uses.push_back (&Use::current ());
  bool current_only (true);
  for (int i = uses.size () - 1; i >= 0; i--)
    {
      const Use* use = uses[i];
      //cerr << "prepare_header_file_filters(0)> " << use->get_package_name () << "[" << use->get_index () << "]\n";
      if (use->discarded) continue;
      if (use->m_hidden) continue;
      if (!use->located ()) continue;

      if (current_only && use != current_use)
	current_only = false;

      cmt_string package_name = use->get_package_name ();
      if (package_name == "CMT") continue;

      const Symbol* filter_macro = Symbol::find (package_name + "_header_file_filter");
      if (filter_macro == 0) continue;
      const cmt_string filter_expr (filter_macro->resolve_macro_value ());
      if (filter_expr.size () == 0) continue;

      const Symbol* stamp_macro = Symbol::find (package_name + "_header_file_stamp");
      cmt_string stamp;
      if (stamp_macro != 0)
        {
          stamp = stamp_macro->resolve_macro_value ();
        }
      else
        {
          use->get_full_path (stamp);
	  switch (use->style)
	    {
	    case cmt_style:
	      stamp += CmtSystem::file_separator ();
	      stamp += "cmt";
	      break;
	    case mgr_style:
	      stamp += CmtSystem::file_separator ();
	      stamp += "mgr";
	      break;
            default:
	      break;
	    }
          stamp += CmtSystem::file_separator ();
          stamp += "cmt_header_file.stamp";
          //stamp += "cmt_all_headers.stamp";
          //<package>/cmt/cmt_all_headers.stamp
        }
      if (!CmtSystem::test_file (stamp)) continue;

      //cerr << "0: adding filter: " << use->get_package_name () << "[" << use->get_index () << "]\n";
      cmt_regexp* filter = new cmt_regexp (filter_expr);
      //cmt_regexp* filter = new cmt_regexp (filter_macro->resolve_macro_value ());
      assert (filter != 0);

      m_deps_builder.add_header_filter (use, filter, stamp);
    }

  if (current_only)
    { // we are most likely reading dependencies[_CONSTITUENT].in without CMT
      for (int number = 0; number < Symbol::symbol_number (); number++)
	{
	  const Symbol& symbol = Symbol::symbol (number);
	  if (symbol.type != Symbol::SymbolMacro) continue;
	  int r = symbol.name.find_last_of ("_header_file_filter");
	  if (r == cmt_string::npos ||
	      (r + 19) != symbol.name.size () ||
	      r == 0) continue;
	  const cmt_string filter_expr (symbol.resolve_macro_value ());
	  if (filter_expr.size () == 0) continue;

	  cmt_string package_name = symbol.name.substr(0, r);
	  const Use* use = Use::find (package_name);
	  if (use == current_use) continue;
	  if (0 != use && use->discarded) continue;
	  if (0 != use && use->m_hidden) continue;
	  if (0 != use && !use->located ()) continue;
	  
	  //Symbol* filter_macro = Symbol::find (package_name + "_header_file_filter");
	  //if (filter_macro == 0) continue;
	  
	  const Symbol* stamp_macro = Symbol::find (package_name + "_header_file_stamp");
	  cmt_string stamp;
	  if (stamp_macro != 0)
	    {
	      stamp = stamp_macro->resolve_macro_value ();
	    }
	  else if (0 != use)
	    {
	      use->get_full_path (stamp);
	      switch (use->style)
		{
		case cmt_style:
		  stamp += CmtSystem::file_separator ();
		  stamp += "cmt";
		  break;
		case mgr_style:
		  stamp += CmtSystem::file_separator ();
		  stamp += "mgr";
		  break;
                default:
		  break;
		}
	      stamp += CmtSystem::file_separator ();
	      stamp += "cmt_header_file.stamp";
	    }
	  if (!CmtSystem::test_file (stamp)) continue;
	  
	  //cerr << "1: adding filter: " << package_name << "\n";
	  cmt_regexp* filter = new cmt_regexp (filter_expr);
	  //cmt_regexp* filter = new cmt_regexp (symbol.resolve_macro_value ());
	  assert (filter != 0);
	  
	  m_deps_builder.add_header_filter (use, filter, stamp);
	}
    }
}

//--------------------------------------------------
void DependencyGenerator::build (const CmtSystem::cmt_string_vector& arguments)
{
  reset ();

  //
  // Parse arguments first
  //
  CmtSystem::cmt_string_vector cli_input, all;
  bool all_sources = false;
  bool config_files (false);
  bool start_all (false);

  for (int i = 0; i < arguments.size (); i++)
    {
      cmt_string file_name = arguments[i];

      //cerr << "i: " << i << " file_name=" << file_name << endl;

      if (file_name.substr (0, 5) == "-out=" ||
	  file_name.substr (0, 5) == "-out:" ||
	  file_name.substr (0, 5) == "/out:" ||
	  file_name.substr (0, 5) == "/out=")
        {
	  file_name.erase (0, 5);
	  m_output_file_name = file_name;
        }
      else if (file_name.substr (0, 6) == "-name=" ||
	       file_name.substr (0, 6) == "-name:" ||
	       file_name.substr (0, 6) == "/name:" ||
	       file_name.substr (0, 6) == "/name=")
        {
	  file_name.erase (0, 6);
	  m_name = file_name;
        }
      else if (file_name == "-all_sources" ||
	       file_name == "/all_sources") 
        {
          all_sources = true;
        }
      else if (file_name == "-no_stamps" ||
	       file_name == "/no_stamps") 
        {
	  m_stamps = false;
        }
      else if (file_name.substr (0, 2) == "-I" ||
	       file_name.substr (0, 2) == "/I")
	{
	  file_name.erase (0, 2);
	  //cerr << "include: " << file_name << endl;
	  m_deps_builder.add (file_name, file_name);
        }
      else if (file_name  == "-start_all" ||
	       file_name  == "/start_all")
	{
	  if (start_all)
	    {
	      CmtError::set(CmtError::syntax_error,
			    "Unexpected option " + file_name);
	      return;
	    }
	  start_all = true;
        }
      else if (file_name == "-end_all" ||
	       file_name == "/end_all")
	{
	  if (!start_all)
	    {
	      CmtMessage::warning
		(CmtError::get_error_name (CmtError::syntax_error)
		 + ": Unexpected option " + file_name);
	    }
	  start_all = false;
        }
      else if (file_name.substr (0, 1) == "-"
#ifdef WIN32
	       || file_name.substr (0, 1) == "/"
#endif
	       )
	{
	  if (CmtMessage::active (Verbose))
	    CmtMessage::warning
	      (CmtError::get_error_name (CmtError::warning)
	       + ": Unknown option " + file_name);
        }
      else if (file_name.substr (file_name.size () - 12) == "requirements" ||
	       file_name.substr (file_name.size () - 5) == ".make" ||
	       file_name.substr (file_name.size () - 3) == ".mk" ||
	       file_name.substr (file_name.size () - 6) == ".nmake" ||
	       file_name.substr (file_name.size () - 3) == ".in" ||
	       file_name.substr (file_name.size () - 6) == ".stamp")
	{
	  // Configuration changed,
	  // want to rebuild dependencies from scratch
	  if (!config_files) config_files = true;
          if (!all_sources) all_sources = true;
	}
      else if (start_all)
	{
	  all.push_back (file_name);
	}
      else
	{
	  cli_input.push_back (file_name);
	}
    }
  
  if (start_all)
    CmtMessage::warning
      (CmtError::get_error_name (CmtError::syntax_error)
       + ": Missing option -end_all");

  //cerr << "m_name: " << m_name << endl;
  /*
  if (m_name.size () == 0)
    {
      CmtError::set(CmtError::syntax_error,
		    "Name missing as first argument");
      return;
    }
  */
  //cerr << "config_files: " << config_files << endl;

  if (0 != m_name.size ())
    m_constituent = Constituent::find (m_name);

  if (!config_files && 0 == cli_input.size () &&
      0 == all.size () && 0 == m_constituent)
    {
      CmtError::set(CmtError::syntax_error,
		    m_name + ": Files arguments missing");
      return;
    }
  /*
  cerr << "cli_input:";
  for (int i = 0; i < cli_input.size (); i++)
    cerr << " " << cli_input[i];
  cerr << "\n";

  cerr << "all:";
  for (int i = 0; i < all.size (); i++)
    cerr << " " << all[i];
  cerr << "\n";
  */
  prepare_includes ();
  prepare_header_file_filters ();

  //
  // Now prepare the output file names
  //
  cmt_string branch = CmtSystem::current_branch ();

  if ((branch == "mgr") || (branch == "cmt"))
    {
      Use& current_use = Use::current ();

      Package* p = current_use.get_package ();

      if (p->is_cmt ())
        {
	  //          m_bin = "../";
          m_bin = "..";
          m_bin += CmtSystem::file_separator ();
          m_bin += CmtSystem::getenv ("CMTBIN");
          m_bin += CmtSystem::file_separator ();
        }
      else if (m_output_file_name != "")
	{
	  CmtSystem::dirname (m_output_file_name, m_bin);
	  if (m_bin == "")
	    {
	      m_bin = ".";
	    }
	  m_bin += CmtSystem::file_separator ();
	}
      else
        {
          m_bin = "${bin}";
        }

      Symbol::expand (m_bin);

      //cerr << "m_output_file_name=" << m_output_file_name << endl;
      //cerr << "current_tag=" << Cmt::current_tag << endl;
    }
  else
    {
      m_bin = ".";
      m_bin += CmtSystem::file_separator ();
    }

  if (m_output_file_name == "")
    {
      m_output_file_name = m_bin;
      m_output_file_name += m_name;
      m_output_file_name += "_";
      m_output_file_name += "dependencies.";
      if (Cmt::build_nmake ())
	{
	  m_output_file_name += "nmake";
	}
      else
	{
	  m_output_file_name += "make";
	}
    }

  //-------------------------------------------------------------------------------
  //
  // For Makefile, we need to select, from cli_input, source files only,
  // there may be dependencies of source files (typically, header files) as well
  //
  cmt_string dependencies;
  if (!all_sources)
    {
      // want to validate cli_input against
      //   either
      // o all cli sources
      //   or
      // o m_constituent sources
      if (int n = set_source_files (all))
	{
	  if (0 == validate (cli_input))
	    {
	      // cli_input contains source files ONLY
	      // calculate dependencies for them ONLY
	      if (CmtSystem::test_file (m_output_file_name))
		{
		  if (!dependencies.read (m_output_file_name))
		    {
		      CmtError::set (CmtError::file_access_error, m_output_file_name);
		      return;
		    }
		}
	      fill_dependencies (dependencies, cli_input);
	    }
	  else
	    {
	      all_sources = true;
	      // calculate dependencies for 
	      // all cli sources
	      // or
	      // m_constituent sources
	      fill_dependencies (dependencies);
	    }
	}
      else
	{
	  // calculate dependencies for all we have
	  fill_dependencies (dependencies, cli_input);
	}
      /*
      if (0 != all.size ())
	{
	  // o all cli sources
	  int n_invalid = 0;
	  for (int i = 0; i < cli_input.size (); i++)
	    {
	      bool valid = false;
	      for (int j = 0; j < all.size (); j++)
		if (cli_input[i] == all[j])
		  {
		    valid = true;
		    break;
		  }
	      if (!valid)
		{
		  n_invalid += 1;
		  break;
		}
	    }
	  if (0 == n_invalid)
	    {
	      // cli_input contains source files ONLY
	      // calculate dependencies for them ONLY
	      if (CmtSystem::test_file (m_output_file_name))
		{
		  if (!dependencies.read (m_output_file_name))
		    {
		      CmtError::set (CmtError::file_access_error, m_output_file_name);
		      return;
		    }
		}
	      fill_dependencies (dependencies, cli_input);
	    }
	  else
	    {
	      all_sources = true;
	      // calculate dependencies for all (all cli sources)
	      fill_dependencies (dependencies, all);
	    }
	}
      else // 0 == all.size ()
	{
	  //	  set_source_files ();
	  if (int n = set_source_files ())
	    //	  if (0 != m_source_files.size ())
	    {
	      // o m_constituent sources
	      int n_invalid = 0;
	      for (int i = 0; i < cli_input.size (); i++)
		{
		  bool valid = false;
		  for (int j = 0; j < n; j++)
		    if (cli_input[i] == m_source_files[j].name ())
		      {
			valid = true;
			break;
		      }
		  if (!valid)
		    {
		      n_invalid += 1;
		      break;
		    }
		}
	      if (0 == n_invalid)
		{
		  // cli_input contains source files ONLY
		  // calculate dependencies for them ONLY
		  if (CmtSystem::test_file (m_output_file_name))
		    {
		      if (!dependencies.read (m_output_file_name))
			{
			  CmtError::set (CmtError::file_access_error, m_output_file_name);
			  return;
			}
		    }
		  fill_dependencies (dependencies, cli_input);
		}
	      else
		{
		  all_sources = true;
		  // calculate dependencies for m_source_files
		  // (m_constituent sources)
		  fill_dependencies (dependencies);
		}
	    }
	  else // 0 == m_source_files.size ())
	    {
	      // no source files to validate against
	      fill_dependencies (dependencies, cli_input);
	    }
	}
      */
    }
  else // all_sources = true
    {
      if (int n = set_source_files (all))
	{
	  // calculate dependencies for m_source_files 
	  //   either
	  // o all cli sources
	  //   or
	  // o m_constituent sources
	  //   if any existing
	  fill_dependencies (dependencies);
	}
      else
	{
	  // calculate dependencies for all we have
	  fill_dependencies (dependencies, cli_input);
	}
      /*
      if (0 != all.size ())
	{
	  // calculate dependencies for all (all cli sources)
	  fill_dependencies (dependencies, all);
	}
      else
	{
	  if (int n = set_source_files ())
	    {
	      // calculate dependencies for m_source_files (m_constituent sources)
	      fill_dependencies (dependencies);
	    }
	  else
	    {
	      // calculate dependencies for all we have
	      fill_dependencies (dependencies, cli_input);
	    }
	}
      */
    }

  if (CmtError::has_pending_error ())
    {
      if (CmtError::get_last_error_code () == CmtError::path_not_found ||
	  CmtError::get_last_error_code () == CmtError::file_access_error ||
	  CmtError::get_last_error_code () == CmtError::execution_failed)
	return;
    }
  //-------------------------------------------------------------------------------

  FILE* f = fopen (m_output_file_name.c_str (), "wb");

  if (f != 0)
    {
      dependencies.write (f);
      CmtSystem::close_ostream (f, m_output_file_name);
    }
  else
    {
      CmtError::set (CmtError::file_access_error, m_output_file_name);
    }

//  m_deps_builder.clear ();
}

//--------------------------------------------------
//  o text contains lines with a pattern like :
//      key = value
//  o line follows the same pattern
//
//  This function
//    o if the key found in <line> is found in <text>, removes the first line in <text> with the key, if any
//    o appends <line> to <text>
//--------------------------------------------------
void DependencyGenerator::add_line_to_text (const cmt_string& line, cmt_string& text) const
{
  static const cmt_string empty;

  int pos = line.find (" = ");
  if (pos != cmt_string::npos)
    {
      static cmt_string key;
      line.substr (0, pos + 3, key);
      pos = text.find (key);
      if (pos != cmt_string::npos)
        {
	  // The key in line exists in text.
	  // Now check if the key is exactly the same.

          if ((pos == 0) || (text[pos -1] == '\n'))
            {
	      // The key is either in the first line or
	      // exactly matches '^key = ...'

              int nl = text.find (pos, "\n");
              if (nl != cmt_string::npos)
                {
                  static cmt_string old;
                  text.substr (pos, nl - pos + 1, old);
                  text.replace (old, empty);
                }
              else
                {
                  text.erase (pos);
                }
            }
        }
    }
  if (line != "")
    {
      text += line;
      text += "\n";
    }
}

//--------------------------------------------------
cmt_string DependencyGenerator::build (const cmt_string& file_name)
{
  Log;

  //  const Constituent& constituent = *m_constituent;

  static cmt_string full_name;
  static cmt_string suffix;
  static cmt_string name;
  static cmt_string line;

  full_name = "";
  line = "";

  /*
  if (!CmtSystem::absolute_path (file_name))
    {
      full_name = srcdir;
    }
  */

  full_name += file_name;

  CmtSystem::get_dot_suffix (full_name, suffix);
  CmtSystem::basename (full_name, suffix, name);
  CmtSystem::get_suffix (full_name, suffix);

  //  if (name == "requirements") return (line);

  const CmtSystem::cmt_string_vector& deps = m_deps_builder.run (full_name, m_name);
  if (CmtError::has_pending_error ())
    {
      return line;
    }
  //	  CmtError::set (CmtError::execution_failed, preprocessor, status);
  //      CmtError::set (CmtError::file_access_error, header_file_path);
  //      CmtError::set (CmtError::path_not_found, name);

  line  = name;
  line += "_";
  line += suffix;
  line += "_dependencies = ";

  filter_path (full_name);

#ifdef WIN32
  static const char quote = '\"';
#else
  static const char quote = ' ';
#endif

  line += quote;
  line += full_name;
  line += quote;

  for (int j = 0; j < deps.size (); j++)
    {
      cmt_string d = deps[j];

      log << "dep line = " << d << log_endl;

      filter_path (d);

      log << "filtered dep line = " << d << log_endl;

      line += " ";
      line += quote;
      line += d;
      line += quote;
    }

  Symbol::expand (line);

  if (m_stamps)
    {
      cmt_string stamp_output_base = m_name;
      //      cmt_string stamp_output_base = constituent.name;
      stamp_output_base += "_deps";

      cmt_string stamp_output = m_bin;
      stamp_output += stamp_output_base;

      if (!CmtSystem::mkdir (stamp_output))
	{
	  CmtError::set (CmtError::file_access_error, 
			 + "Cannot create directory " + stamp_output
			 + " for " + m_name);
	  return line;
	}

      stamp_output_base += CmtSystem::file_separator ();
      stamp_output_base += name;
      stamp_output_base += "_";
      stamp_output_base += suffix;
      stamp_output_base += ".stamp";

      stamp_output = m_bin;
      stamp_output += stamp_output_base;
      
      line += " $(bin)";
      line += stamp_output_base;
      
      cmt_string old_stamp;
      
      if (CmtSystem::test_file (stamp_output))
	{
	  if (!old_stamp.read (stamp_output))
	    {
	      CmtError::set (CmtError::file_access_error, stamp_output);
	      return line;
	    }
	  //	  old_stamp.read (stamp_output);
	}

      if (line != old_stamp.substr(0, old_stamp.size () - 1))
	{
	  if (!(line + "\n").write (stamp_output))
	    {
	      CmtError::set (CmtError::file_access_error, stamp_output);
	      return line;
	    }
	  //	  (line + "\n").write (stamp_output);
	}
    }

  return (line);
}

//--------------------------------------------------
int DependencyGenerator::fill_dependencies (cmt_string& dependencies)
{
  CmtSystem::cmt_string_vector sources;
  for (int i = 0; i < m_source_files.size (); i++)
    {
      const SourceFile& file = m_source_files[i];
      sources.push_back (file.name ());
    }
  return fill_dependencies (dependencies, sources);
}

//--------------------------------------------------
int DependencyGenerator::fill_dependencies (cmt_string& dependencies,
					    const CmtSystem::cmt_string_vector& sources)
{
  int retval (0);
  cmt_string file_name;
  cmt_string compressed_name;

  for (int i = 0; i < sources.size (); i++)
    {
      file_name = sources[i];
      //set_full_name (full_name, file_name);
      CmtSystem::reduce_file_separators (file_name);
      if (file_name == "") continue;
      CmtSystem::compress_path (file_name, compressed_name);
      file_name = compressed_name;
      //cerr << "file_name: " << file_name << endl;     
      if (file_name == "") continue;

      const cmt_string& line = build (file_name);
      if (CmtError::has_pending_error ())
	{
	  //	  if (CmtError::get_last_error_code () == CmtError::file_access_error)
	  return -1;
	}
      
      //cerr << "line: " << line << endl;     
      add_line_to_text (line, dependencies);
      //cerr << "dependencies: " << dependencies << endl;     
    }

  return retval;
}

//--------------------------------------------------
int DependencyGenerator::set_source_files (const CmtSystem::cmt_string_vector& files)
{
  m_source_files.clear ();

  for (int j = 0; j < files.size (); j++)
    {
      const cmt_string& name = files[j];
      if (name == "") continue;

      bool included = false;
      for (int k = m_source_files.size () - 1; k >= 0; k--)
	if (m_source_files[k].name () == name)
	  {
	    included = true;
	    break;
	  }
      if (included) continue;
      
      SourceFile& source = m_source_files.add ();
      source.set (name, Language::null (), "");
    }
      
  if (m_source_files.size ()) return m_source_files.size ();
  else return set_source_files ();
}

//--------------------------------------------------
int DependencyGenerator::set_source_files ()
{
  if (0 == m_constituent && 0 != m_name.size ())
    m_constituent = Constituent::find (m_name);
  if (0 == m_constituent) return 0;

  m_source_files.clear ();

  const CmtSystem::cmt_string_vector& sources = m_constituent->modules;
  const cmt_vector<cmt_regexp>& excludes = m_constituent->exclude_exprs;
  const cmt_vector<cmt_regexp>& selects = m_constituent->select_exprs;

  cmt_string file_name, full_name;
  cmt_string compressed_name;
  cmt_string visited, token;

  for (int i = 0; i < sources.size (); i++)
    {
      file_name = sources[i];
      set_full_name (full_name, file_name);
      if (full_name == "") continue;
      
      CmtSystem::compress_path (full_name, compressed_name);
      full_name = compressed_name;
      
      static CmtSystem::cmt_string_vector files;
      
      get_all_files (full_name, excludes, selects, files);
      
      for (int j = 0; j < files.size (); j++)
	{
	  const cmt_string& name = files[j];
              
	  if (name == "") continue;
	  
	  cmt_string suffix;
	  CmtSystem::get_suffix (name, suffix);
	  Language& language = Language::find_with_suffix (suffix);

	  if ((m_constituent->type == Application || m_constituent->type == Library)
	      && language != Language::null () && language.native_dependencies ())
	    continue;

	  bool included = false;
	  for (int k = m_source_files.size () - 1; k >= 0; k--)
	    if (m_source_files[k].name () == name)
	      {
		included = true;
		break;
	      }
	  if (included) continue;
	  
	  SourceFile& source = m_source_files.add ();
	  source.set (name, language, "");
	}
    }
  return m_source_files.size ();
}

//--------------------------------------------------
/**
 *  Returns 0, if each file in @files is found in m_source_files,
 *  otherwise returns 1
 */
//--------------------------------------------------
int DependencyGenerator::validate (const CmtSystem::cmt_string_vector& files) const
{
  int n_invalid = 0;
  for (int i = 0; i < files.size (); i++)
    {
      bool valid = false;
      for (int j = 0; j < m_source_files.size (); j++)
	if (files[i] == m_source_files[j].name ())
	  {
	    valid = true;
	    break;
	  }
      if (!valid)
	{
	  n_invalid += 1;
	  break;
	}
    }

  return n_invalid;
}
