//-----------------------------------------------------------
// Copyright Christian Arnault LAL-Orsay CNRS
// arnault@lal.in2p3.fr
// 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"

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

  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");
  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 ();
  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;
      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 (Cmt::build_nmake ()) obj +=  m_CONSTITUENT;
      if (Cmt::build_nmake ()) 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
    {
        //cout << "#CMT> analyze_file file=" << file << " no language" << endl;

      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  = "";
	  cerr << "#CMT> Warning: Source file " << name << " cannot be rebuilt" << endl;
        }
      else
        {
          obj  = "";
        }
    }

  if (Cmt::get_debug ())
    {
      cout << "CmtGenerator::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
    {
      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, 3, 
                            &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);
    }
  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);
  filter_path (m_LINE.value);

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

  if (fragment != 0)
    {
      fragment->copy (m_output_file, constituent.variables, 10,
                      &m_CONSTITUENT, 
                      &m_CONSTITUENTSUFFIX, 
                      &m_FILENAME, 
                      &m_NAME, 
                      &m_LINE,
                      &m_ADDINCLUDE, 
                      &m_FULLNAME, 
                      &m_FILEPATH, 
                      &m_FILESUFFIX, 
                      &m_PACKAGE);
    }
  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 += " ";
    }
}

//--------------------------------------------------
void LibraryGenerator::build (const cmt_string& package,
                              const Constituent& constituent)
{
  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)) 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;
    }

  m_source_files.clear ();

  need_prototypes = constituent.need_prototypes;

  cout << m_TITLE << " " << m_CONSTITUENT << endl;

  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_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";
    }

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

  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, 3, 
				    &m_CONSTITUENT, 
                                    &m_CONSTITUENTSUFFIX,
                                    &m_OBJS);
        }
      else
        {
          java_header_fragment.copy (m_output_file, constituent.variables, 3, 
				     &m_CONSTITUENT,
                                     &m_CONSTITUENTSUFFIX,
                                     &m_OBJS);
        }
    }
  else
    {
      if (is_library)
        {
          library_header_fragment.copy (m_output_file, constituent.variables, 3,
                                        &m_CONSTITUENT,
                                        &m_CONSTITUENTSUFFIX,
                                        &m_PROTOTARGET);
        }
      else
        {
          application_header_fragment.copy (m_output_file, constituent.variables, 3,
                                            &m_CONSTITUENT, 
                                            &m_CONSTITUENTSUFFIX, 
					    &m_PROTOTARGET);
        }
    }


  //----------------------------------------------------
  //
  // 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, 3, 
				       &m_CONSTITUENT,
                                       &m_CONSTITUENTSUFFIX,
                                       &m_PROTOSTAMPS);
        }

      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)
                {
                  library_no_share_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);
            }
        }
    }

  if (constituent.build_triggers)
    {
      dependencies_and_triggers_fragment.copy (m_output_file, 
                                               constituent.variables, 3,
                                               &m_CONSTITUENT, 
                                               &m_CONSTITUENTSUFFIX, 
                                               &m_LINE);
    }
  else
    {
      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 ()
{
  document_header_fragment.set ("document_header");
}

//--------------------------------------------------
void DocumentGenerator::reset ()
{
  AnyDocumentGenerator::reset ();
  document_header_fragment.reset ();
}

//--------------------------------------------------
void DocumentGenerator::build (const cmt_string& package,
                               const Constituent& constituent)
{
  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)) return;

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

  int i;

  cout << m_TITLE << " " << m_CONSTITUENT << endl;

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

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

  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, 3, 
			    &m_CONSTITUENT,
                            &m_CONSTITUENTSUFFIX,
                            &m_OBJS);
    }
  else
    {
      document_header_fragment.copy (m_output_file, constituent.variables, 3, 
				     &m_CONSTITUENT,
                                     &m_CONSTITUENTSUFFIX,
                                     &m_OBJS);
    }

  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];
              
              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_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);
      CmtSystem::basename (file_name, m_FILENAME.value);
      CmtSystem::get_dot_suffix (m_FILENAME.value, m_FILESUFFIX.value);

      if (!CmtSystem::test_file (file_name) && !CmtSystem::test_directory (file_name))
        {
          cerr << "#CMT> Warning: Source file " << file_name << " not found" << endl;
        }

      filter_path (m_FULLNAME.value);

      fragment.copy (m_output_file, constituent.variables, 8,
                     &m_FILEPATH,
                     &m_SUFFIX,
                     &m_CONSTITUENT,
                     &m_CONSTITUENTSUFFIX,
                     &m_FILENAME,
                     &m_NAME,
                     &m_FULLNAME,
                     &m_FILESUFFIX);
    }

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

  //
  //  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))
    {
      cerr << "#CMT> Warning: Source file " << file << " not found" << endl;
    }

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

//--------------------------------------------------
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)
                {
                  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);
                  fclose (file);

                  need_makefile = true;
                }
            }
        }
    }

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

#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");
          fprintf (file, "\n");
          fprintf (file, "!include $(CMTROOT)\\src\\constituents.nmake\n");
          fprintf (file, "\n");
          fclose (file);
        }
    }

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

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

  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)";
              temp += CmtSystem::file_separator ();
              switch (use->style)
                {
		case cmt_style:
		  temp += "cmt";
		  break;
		case mgr_style:
		  temp += "mgr";
		  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);

      fclose (m_output_file);

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

      commit (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");
  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 ();
  check_application_header_fragment.reset ();
}

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

  cmt_string file_name;

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

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

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

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

  cmt_string save_file_name = file_name;
  save_file_name += "sav";

  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);
        }
      
      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";
	    }

          constituent_fragment.copy (m_output_file, constituent.variables, 5, 
				     &m_PACKAGE,
				     &m_CONSTITUENT, 
                                     &m_CONSTITUENTSUFFIX,
                                     &m_LINE,
				     &m_HASTARGETTAG);

          if (constituent.need_check)
            {
              check_application_header_fragment.copy (m_output_file, 
						      constituent.variables, 3,
						      &m_PACKAGE,
						      &m_CONSTITUENT,
                                                      &m_CONSTITUENTSUFFIX);
            }
        }

      constituents_trailer_fragment.copy (m_output_file, 0);

      fclose (m_output_file);

      commit (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::build (const CmtSystem::cmt_string_vector& arguments)
{
  reset ();
  prepare_use_context ();

  m_stamps = true;

  const cmt_string& name = arguments[0];

  //cerr << "name=" << name << endl;

  m_constituent = Constituent::find (name);
  if (m_constituent == 0)
    {
      // Error : wrong constituent name...
      
      return;
    }

  const Constituent& constituent = *m_constituent;

  cmt_string file_name;
  cmt_string full_name;
  cmt_string compressed_name;
  cmt_string suffix;
  cmt_string dependencies;

  //
  // 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 += CmtSystem::getenv ("CMTBIN");
          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 ();
    }

  m_output_file_name = m_bin;
  m_output_file_name += 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";
    }

  //
  // New read the existing dependency file if any and filter it to
  // extract the source names
  //
  static DependencyFilter filter;

  dependencies.read (m_output_file_name);

  filter.run (dependencies);

  //
  // Scan the sources.
  //

  //
  //  We have to rebuild the dependencies for :
  //
  //   o all sources if the parameter -all_sources has been received
  //   o otherwise,
  //      + all source names provided in the argument list (if any)
  //      + all source names missing from the existing dependency file (if any)
  //

  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;

  bool all_sources = false;

  int source_number = arguments.size ();
  int i;

  //cerr << "source_number=" << source_number << endl;

  for (i = source_number-1; i >= 0; i--)
    {
      file_name = arguments[i];

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

        // Get rid of files that may come from the makefile fragment
      if (file_name.find ("requirements") != cmt_string::npos) source_number--;
      else if (file_name.find (".make") != cmt_string::npos) source_number--;
      else if (file_name == "-all_sources") 
        {
          source_number = sources.size ();
          all_sources = true;
        }
      else if (file_name == "-no_stamps") 
        {
          source_number--;
	  m_stamps = false;
        }
    }


  if (all_sources)
    {
      for (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 != "") 
                {
                  const cmt_string& line = build (name);
                  
		  //cout << ">>> line=[" << line << "]" << endl;
                  
                  add_line_to_text (line, dependencies);
                }
            }
        }
    }
  else
    {
      for (i = 1; i < source_number; i++)
        {
          file_name = arguments[i];

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

          CmtSystem::compress_path (full_name, compressed_name);
          full_name = compressed_name;
          
          const cmt_string& line = build (full_name);
                  
            //cout << ">>> name2=" << full_name << endl;
                  
          add_line_to_text (line, dependencies);

            //cout << ">>from deps : " << filter.get_sources () << endl;
          filter.add_source (full_name);

        }

        //cout << ">>from deps : " << filter.get_sources () << endl;

        // Now : are there still any missing source file in dependencies??

      for (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 != "") 
                {
                  if (!filter.has_source (name))
                    {
                      const cmt_string& line = build (name);
                  
                        //cout << ">>> name3=" << name << endl;
                  
                      add_line_to_text (line, dependencies);
                    }
                }
            }
        }
    }

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

  if (f == 0)
    {
      cerr << "Cannot open " << m_output_file_name << " for write" << endl;
    }
  else
    {
      dependencies.write (f);
      fclose (f);
    }
}

//--------------------------------------------------
//  o text contains lines with a pattern like :
//      key = xxxxx
//
//  o line follows the same pattern
//
//   This function appends <line> to <text> only if the key found in
//  <line> is not found in <text>
//--------------------------------------------------
void DependencyGenerator::add_line_to_text (const cmt_string& line, cmt_string& text)
{
  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);

  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 = constituent.name;
      stamp_output_base += "_deps";

      cmt_string stamp_output = m_bin;
      stamp_output += stamp_output_base;

      if (!CmtSystem::mkdir (stamp_output))
	{
	  cerr << "Cannot create the binary output directory for this constituent" << endl;
	}

      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))
	{
	  old_stamp.read (stamp_output);
	}

      if (line != old_stamp)
	{
	  line.write (stamp_output);
	}
    }

  return (line);
}

