#include <errno.h>
#include <stdio.h>

#ifndef WIN32
#include <unistd.h>
#endif

#include "cmt_use.h"
#include "cmt_fragment.h"
#include "cmt_symbol.h"
#include "cmt_system.h"
#include "cmt.h"
#include "cmt_deps_builder.h"
#include "cmt_generator.h"
#include "cmt_constituent.h"
#include "cmt_language.h"
#include "cmt_awk.h"

static Variable DOCPATH            ("DOCPATH");
static Variable PACKAGEPATH        ("PACKAGEPATH");
static Variable PACKAGEPREFIX      ("PACKAGEPREFIX");
static Variable PACKAGE            ("PACKAGE");
static Variable VERSION            ("VERSION");
static Variable MGRSTYLE           ("MGRSTYLE");
static Variable TITLE              ("TITLE");
static Variable GROUP              ("GROUP");
static Variable CONSTITUENT        ("CONSTITUENT");
static Variable CONSTITUENTSUFFIX  ("CONSTITUENTSUFFIX");
static Variable LIBRARYSUFFIX      ("LIBRARYSUFFIX");
static Variable USER               ("USER");
static Variable DATE               ("DATE");
static Variable PROTOTARGET        ("PROTOTARGET");
static Variable OBJS               ("OBJS");
static Variable CLASSES            ("CLASSES");
static Variable PROTOSTAMPS        ("PROTOSTAMPS");
static Variable NAME               ("NAME");
static Variable FILEPATH           ("FILEPATH");
static Variable FILESUFFIX         ("FILESUFFIX");
static Variable SUFFIX             ("SUFFIX");
static Variable FILENAME           ("FILENAME");
static Variable LINKMACRO          ("LINKMACRO");
static Variable LINE               ("LINE");
static Variable ADDINCLUDE         ("ADDINCLUDE");
static Variable FULLNAME           ("FULLNAME");
static Variable OUTPUTNAME         ("OUTPUTNAME");
static Variable ALLOS9SOURCES      ("ALLOS9SOURCES");
static Variable NODEBUGUSELINKOPTS ("NODEBUGUSELINKOPTS");
static Variable DEBUGUSELINKOPTS   ("DEBUGUSELINKOPTS");
static Variable USEINCLUDES        ("USEINCLUDES");
//------------------------------------------------------------------------

//------------------------------------------------------------------------
class SourceFile
{
public:
  void set (const cmt_string name, Language& language, const cmt_string output)
  {
    m_name = name;
    m_language = &language;
    m_output = output;

    char sep = CmtSystem::file_separator ();
    if (sep == '/') m_name.replace_all ("\\", sep);
    else m_name.replace_all ("/", sep);
  }

  cmt_string name () const
  {
    return (m_name);
  }

  Language& language () const
  {
    return (*m_language);
  }

  cmt_string output () const
  {
    return (m_output);
  }

private:
  cmt_string m_name;
  Language* m_language;
  cmt_string m_output;
};
//------------------------------------------------------------------------

//------------------------------------------------------------------------
class MakefileGenerator
{
public:

  void analyze_file (const Constituent& constituent,
		     const cmt_string& file);
  void analyze_document_file (const cmt_string& file,
                              const cmt_string& constituent_name,
                              const cmt_string& output_suffix);
  void reset ();

  void prepare_proto_file (const cmt_string& file);
  void proto_file_action (const cmt_string& file, const Constituent& constituent);
  void module_file_action (SourceFile& file, const Constituent& constituent);
  void java_file_action (SourceFile& file, const Constituent& constituent);

  void fill_outputs ();

  void build_application_makefile (const cmt_string& package,
                                   const Constituent& constituent);

  void build_library_makefile (const cmt_string& package,
                               const Constituent& constituent);

  void build_document_makefile (const cmt_string& package,
                                const Constituent& constituent);

  void prepare_use_context ();

  void set_full_name (cmt_string& full_name, cmt_string& file);

  cmt_string PACKINCLUDES;
  bool PACKOS9;

  cmt_string GENERATOR;
  bool is_library;
  bool is_application;
  bool is_document;
  cmt_string srcdir;
  cmt_string docdir;
  cmt_string cmtdir;
  cmt_string incdir;
  cmt_string msdevdir;
  cmt_string src;
  cmt_string doc;
  cmt_string inc;
  cmt_string mgr;
  cmt_string cmt;
  cmt_string protos;
  cmt_string protonames;
  cmt_string os9sources;

  cmt_vector<SourceFile> source_files;

  FILE* output_file;

  DepsBuilder deps_builder;
};
//------------------------------------------------------------------------

//------------------------------------------------------------------------
static MakefileGenerator Context;

static FragmentHandle buildproto_fragment ("buildproto");
static FragmentHandle dependencies_fragment ("dependencies");
static FragmentHandle dependencies_and_triggers_fragment ("dependencies_and_triggers");

static FragmentHandle make_header_fragment ("make_header");
static FragmentHandle library_header_fragment ("library_header");
static FragmentHandle application_header_fragment ("application_header");
static FragmentHandle document_header_fragment ("document_header");
static FragmentHandle java_header_fragment ("java_header");
static FragmentHandle jar_header_fragment ("jar_header");
static FragmentHandle protos_header_fragment ("protos_header");
static FragmentHandle library_fragment ("library");
static FragmentHandle library_no_share_fragment ("library_no_share");
static FragmentHandle application_fragment ("application");
static FragmentHandle jar_fragment ("jar");
static FragmentHandle java_fragment ("java");
static FragmentHandle cleanup_header_fragment ("cleanup_header");
static FragmentHandle cleanup_fragment ("cleanup");
static FragmentHandle cleanup_library_fragment ("cleanup_library");
static FragmentHandle cleanup_application_fragment ("cleanup_application");
static FragmentHandle cleanup_java_fragment ("cleanup_java");
static FragmentHandle cleanup_objects_fragment ("cleanup_objects");

static FragmentHandle dsw_header_fragment ("dsw_header");
static FragmentHandle dsw_project_fragment ("dsw_project");
static FragmentHandle dsw_all_project_header_fragment ("dsw_all_project_header");
static FragmentHandle dsw_all_project_dependency_fragment ("dsw_all_project_dependency");
static FragmentHandle dsw_all_project_trailer_fragment ("dsw_all_project_trailer");
static FragmentHandle dsw_trailer_fragment ("dsw_trailer");

static FragmentHandle dsp_all_fragment ("dsp_all");
static FragmentHandle dsp_library_header_fragment ("dsp_library_header");
//static FragmentHandle dsp_shared_library_header_fragment ("dsp_shared_library_header");
static FragmentHandle dsp_application_header_fragment ("dsp_application_header");
static FragmentHandle dsp_windows_header_fragment ("dsp_windows_header");
static FragmentHandle dsp_contents_fragment ("dsp_contents");
static FragmentHandle dsp_trailer_fragment ("dsp_trailer");

static FragmentHandle make_setup_header_fragment ("make_setup_header");
static FragmentHandle make_setup_fragment ("make_setup");

static FragmentHandle constituents_header_fragment ("constituents_header");
static FragmentHandle constituent_fragment ("constituent");

static FragmentHandle readme_header_fragment ("readme_header");
static FragmentHandle readme_fragment ("readme");
static FragmentHandle readme_doc_fragment ("readme_doc");
static FragmentHandle readme_use_fragment ("readme_use");
static FragmentHandle readme_trailer_fragment ("readme_trailer");

static FragmentHandle check_application_fragment ("check_application");
static FragmentHandle check_java_fragment ("check_java");
static FragmentHandle check_application_header_fragment ("check_application_header");
//------------------------------------------------------------------------

//--------------------------------------------------
class Packager : public FAwk
{
public:
  void begin ();
  void filter (const cmt_string& line);
  cmt_string& package_name ();
private:
  cmt_string m_package_name;
};
//--------------------------------------------------

//--------------------------------------------------
static void filter_paths (cmt_string& text)
{
  static CmtSystem::cmt_string_vector ps;

  CmtSystem::split (text, " ", ps);

  text = "";

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

      CmtSystem::compress_path (s);

        //cout << "   filter_paths " << s << endl;

      if (i > 0) text += " ";
      text += s;
    }

  text.replace_all ("./../src/", "$(src)");
  text.replace_all (".\\..\\src\\", "$(src)");
  text.replace_all ("../src/", "$(src)");
  text.replace_all ("..\\src\\", "$(src)");
  text.replace_all ("../doc/", "$(doc)");
  text.replace_all ("..\\doc\\", "$(doc)");
  text.replace_all ("$(src)$(src)", "$(src)");
}

static void get_all_files (const cmt_string& full_name, 
                           CmtSystem::cmt_string_vector& files)
{
  static cmt_string suffix;
  static cmt_string name;

  suffix = "";
  name = "";

  files.clear ();

  CmtSystem::get_dot_suffix (full_name, suffix);

  if (full_name.find ('*') != cmt_string::npos)
    {
      CmtSystem::scan_dir (full_name, files);

      if (Cmt::debug)
        {
          cout << "CMT> full_name=" << full_name <<
	    " pwd=" << CmtSystem::pwd () << endl;
          cout << "CMT> files.size=" <<  files.size () << endl;
        }

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

          CmtSystem::get_dot_suffix (n, s);
          if (s != suffix) 
            {
              n = "";
            }
        }
    }
  else
    {
      cmt_string& n = files.add ();

      n = full_name;
    }
}

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

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

  obj = file;

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

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

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

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

  if (language == "java")
    {
      static Packager packager;
      
      obj  = "$(javabin)";
      
      packager.run (file);
      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 +=  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 (Cmt::debug)
    {
      cout << "MakefileGenerator::analyze_file> constituent=" << 
          constituent.name <<
          " obj=" << obj << endl;
    }

  SourceFile& source = source_files.add ();
  source.set (file, language, obj);
}

//--------------------------------------------------
void MakefileGenerator::analyze_document_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;

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

  filter_paths (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 = source_files.add ();
  source.set (file, Language::null (), obj);
}

//--------------------------------------------------
void MakefileGenerator::reset ()
{
  DOCPATH = "";
  PACKAGEPATH = "";
  PACKAGEPREFIX = "";
  PACKAGE = "";
  VERSION = "";
  MGRSTYLE = "";
  TITLE = "";
  GROUP = "";
  CONSTITUENT = "";
  CONSTITUENTSUFFIX = "";
  LIBRARYSUFFIX = "";
  USER = "";
  DATE = "";
  PROTOTARGET = "";
  OBJS = "";
  CLASSES = "";
  PROTOSTAMPS = "";
  NAME = "";
  FILEPATH = "";
  FILESUFFIX = "";
  SUFFIX = "";
  FILENAME = "";
  LINKMACRO = "";
  LINE = "";
  ADDINCLUDE = "";
  FULLNAME = "";
  OUTPUTNAME = "";
  ALLOS9SOURCES = "";
  NODEBUGUSELINKOPTS = "";
  DEBUGUSELINKOPTS = "";
  USEINCLUDES = "";

  PACKINCLUDES = "";
  PACKOS9      = false;
  GENERATOR    = "";

  is_library     = false;
  is_application = false;
  is_document    = false;
  srcdir       = "";
  docdir       = "";
  cmtdir       = "";
  incdir       = "";
  src          = "$(src)";
  doc          = "$(doc)";
  inc          = "$(inc)";
  mgr          = "$(mgr)";
  cmt          = "$(cmt)";
  protos       = "";
  protonames   = "";
  os9sources   = "";

  source_files.clear ();

  buildproto_fragment.reset ();
  dependencies_fragment.reset ();
  dependencies_and_triggers_fragment.reset ();

  make_header_fragment.reset ();
  library_header_fragment.reset ();
  application_header_fragment.reset ();
  document_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 ();
  cleanup_header_fragment.reset ();
  cleanup_fragment.reset ();
  cleanup_library_fragment.reset ();
  cleanup_application_fragment.reset ();
  cleanup_java_fragment.reset ();
  cleanup_objects_fragment.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_shared_library_header_fragment.reset ();
  dsp_application_header_fragment.reset ();
  dsp_windows_header_fragment.reset ();
  dsp_contents_fragment.reset ();
  dsp_trailer_fragment.reset ();

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

  constituents_header_fragment.reset ();
  constituent_fragment.reset ();

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

  check_application_fragment.reset ();
  check_java_fragment.reset ();
  check_application_header_fragment.reset ();

  Language::setup_all_fragments ();

  CmtSystem::cd (Cmt::current_dir);

  cmt_string branch = CmtSystem::current_branch ();

  if ((branch == "mgr") || (branch == "cmt"))
    {
      if (CmtSystem::test_directory ("../src"))
        {
          srcdir = "..";
	  srcdir += CmtSystem::file_separator ();
          srcdir += "src";
	  srcdir += CmtSystem::file_separator ();
        }
      else
        {
          srcdir = "";
        }

      if (CmtSystem::test_directory ("../doc"))
        {
          docdir = "..";
	  docdir += CmtSystem::file_separator ();
          docdir += "doc";
	  docdir += CmtSystem::file_separator ();
        }
      else
        {
          docdir = "";
        }

      if (CmtSystem::test_directory ("../cmt"))
        {
          cmtdir = "..";
	  cmtdir += CmtSystem::file_separator ();
          cmtdir += "cmt";
	  cmtdir += CmtSystem::file_separator ();
        }
      else if (CmtSystem::test_directory ("../mgr"))
        {
          cmtdir = "..";
	  cmtdir += CmtSystem::file_separator ();
          cmtdir += "mgr";
	  cmtdir += CmtSystem::file_separator ();
        }
      else
        {
          cmtdir = CmtSystem::pwd ();
          cmtdir += CmtSystem::file_separator ();
        }

      if (CmtSystem::test_directory ("../src"))
        {
          incdir = "..";
	  incdir += CmtSystem::file_separator ();
          incdir += "src";
	  incdir += CmtSystem::file_separator ();
        }
      else
        {
          incdir = "";
        }

      msdevdir = "..";
      msdevdir += CmtSystem::file_separator ();
      msdevdir += "Visual";

      if (!CmtSystem::test_directory (msdevdir))
        {
          CmtSystem::mkdir (msdevdir);
        }

      msdevdir += CmtSystem::file_separator ();
    }
  else
    {
      srcdir = ".";
      srcdir += CmtSystem::file_separator ();
      docdir = ".";
      docdir += CmtSystem::file_separator ();
      cmtdir = CmtSystem::pwd ();
      cmtdir += CmtSystem::file_separator ();
      incdir = ".";
      incdir += CmtSystem::file_separator ();
      msdevdir = ".";
      msdevdir += CmtSystem::file_separator ();
    }
}

//--------------------------------------------------
void MakefileGenerator::build_application_makefile (const cmt_string& package,
						    const Constituent& constituent)
{
  build_library_makefile (package, constituent);
}

//--------------------------------------------------
void MakefileGenerator::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";

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

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

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

  filter_paths (FILEPATH.value);

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

  CmtSystem::basename (FILENAME, suffix, NAME.value);

  buildproto_fragment.copy (output_file, constituent.variables, 3, &NAME, &FILEPATH, &FILENAME);
}

//--------------------------------------------------
void MakefileGenerator::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;

  FULLNAME = name;

  CmtSystem::get_dot_suffix (name, suffix);

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

  CmtSystem::dirname (name, prefix);
  CmtSystem::basename (name, 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"))
    {
      ADDINCLUDE = "";
    }
  else if (prefix != "")
    {
      ADDINCLUDE  = preproc;
      ADDINCLUDE += prefix;
    }

  if (!CmtSystem::test_file (name))
    {
      cout << "#CMT> Warning : Source file " << name << " not found" << endl;
    }

  FILEPATH = prefix;
  if (FILEPATH.value != "") FILEPATH.value += CmtSystem::file_separator ();
  filter_paths (FILEPATH.value);

  LINE = FULLNAME.value;
  LINE += " ";

  filter_paths (FULLNAME.value);
  filter_paths (LINE.value);

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

  if (fragment != 0)
    {
      fragment->copy (output_file, constituent.variables, 10,
                      &CONSTITUENT, &CONSTITUENTSUFFIX, &FILENAME, &NAME, &LINE,
                      &ADDINCLUDE, &FULLNAME, &FILEPATH, &FILESUFFIX, &PACKAGE);
    }

  if (PACKOS9)
    {
      os9sources += LINE;
      os9sources += " ";
    }
}

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

  FULLNAME = file.name ();
  OUTPUTNAME = file.output ();

  CmtSystem::get_dot_suffix (FULLNAME, suffix);
  
  CmtSystem::basename (FULLNAME, suffix, NAME.value);
  CmtSystem::basename (FULLNAME, FILENAME.value);
  
  if (CmtSystem::test_file (FULLNAME))
    {
      java_fragment.copy (output_file, constituent.variables, 5, &NAME,
                          &FULLNAME, &OUTPUTNAME,
                          &CONSTITUENT, &CONSTITUENTSUFFIX);
    }
  else
    {
      cout << "#CMT> Warning : file " << FULLNAME << " not found" << endl;
    }
}

//--------------------------------------------------
void MakefileGenerator::fill_outputs ()
{
  bool first = true;

  OBJS = "";

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

      if (output != "")
        {
          if (first)
            {
              first = false;
            }
          else
            {
              OBJS += " ";
            }

          OBJS += output;
        }

      if (Cmt::debug)
        {
          cout << "MakefileGenerator::fill_outputs> output=" << output << " OBJS=" << OBJS << endl;
        }

    }

  if (Cmt::debug)
    {
      cout << "MakefileGenerator::fill_outputs> OBJS=" << OBJS << endl;
    }

}

//--------------------------------------------------
void MakefileGenerator::build_library_makefile (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;

  source_files.clear ();

  need_prototypes = constituent.need_prototypes;

  cout << TITLE << " " << CONSTITUENT << endl;

  lib  = "$(";
  lib += 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];

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

  //
  // Scan the sources.
  //

  const CmtSystem::cmt_string_vector& sources = constituent.modules;

  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;

      get_all_files (full_name, files);

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

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

  fill_outputs ();

  prepare_use_context ();

  DATE = CmtSystem::now ();
  USER = CmtSystem::user ();

  make_header_fragment.copy (output_file, constituent.variables, 5, 
			     &TITLE, &CONSTITUENT, &CONSTITUENTSUFFIX,
			     &USER, &DATE);

  if (need_prototypes)
    {
      need_prototypes = false;

      for (i = 0; i < source_files.size (); i++)
        {
          const SourceFile& file = 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
  //
  //-------------------------------------------

  PROTOTARGET = "";

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

  if (LINKMACRO == "java")
    {
      if (is_library)
        {
          jar_header_fragment.copy (output_file, constituent.variables, 3, 
				    &CONSTITUENT, &CONSTITUENTSUFFIX, &OBJS);
        }
      else
        {
          java_header_fragment.copy (output_file, constituent.variables, 3, 
				     &CONSTITUENT, &CONSTITUENTSUFFIX, &OBJS);
        }
    }
  else
    {
      if (is_library)
        {
          library_header_fragment.copy (output_file, constituent.variables, 3,
                                        &CONSTITUENT,
                                        &CONSTITUENTSUFFIX,
                                        &PROTOTARGET);
        }
      else
        {
          application_header_fragment.copy (output_file, constituent.variables, 3,
                                            &CONSTITUENT, &CONSTITUENTSUFFIX, 
					    &PROTOTARGET);
        }
    }


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

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

      if (PROTOSTAMPS != "")
        {
          protos_header_fragment.copy (output_file, constituent.variables, 3, 
				       &CONSTITUENT, &CONSTITUENTSUFFIX, &PROTOSTAMPS);
        }

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

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

  if (OBJS != "")
    {
      if (LINKMACRO == "java")
        {
          if (is_library)
            {
	      cmt_string classes = OBJS.value;

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

	      CLASSES = classes;

              jar_fragment.copy (output_file, constituent.variables, 4, 
				 &CONSTITUENT, &CONSTITUENTSUFFIX, &OBJS, &CLASSES);
            }
        }
      else
        {
          if (is_library)
            {
              if (constituent.no_share)
                {
                  library_no_share_fragment.copy (output_file, constituent.variables, 3, 
						  &CONSTITUENT, &CONSTITUENTSUFFIX, &OBJS);
                }
              else
                {
                  library_fragment.copy (output_file, constituent.variables, 3, 
					 &CONSTITUENT, &CONSTITUENTSUFFIX, &OBJS);
                }
            }
          else
            {
              application_fragment.copy (output_file, constituent.variables, 4,
                                         &CONSTITUENT, &CONSTITUENTSUFFIX, 
					 &OBJS, &LINKMACRO);
            }
        }
    }

  LINE = "";
  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, files);

      int count = 0;

      for (int j = 0; j < files.size (); j++)
        {
          cmt_string& n = files[j];
          if (n != "") count++;
        }

      if (count > 0)
        {
          LINE += full_name;
          LINE += " ";
        }
    }

  filter_paths (LINE.value);

  if (constituent.build_triggers)
    {
      dependencies_and_triggers_fragment.copy (output_file, 
                                               constituent.variables, 3,
                                               &CONSTITUENT, 
                                               &CONSTITUENTSUFFIX, 
                                               &LINE);
    }
  else
    {
      dependencies_fragment.copy (output_file, 
                                  constituent.variables, 3,
                                  &CONSTITUENT, 
                                  &CONSTITUENTSUFFIX, 
                                  &LINE);
    }

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

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

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

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

          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 (output_file, constituent.variables, 2, 
				&CONSTITUENT, &CONSTITUENTSUFFIX);

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

  if (LINKMACRO == "java")
    {
      cleanup_java_fragment.copy (output_file, constituent.variables, 1, &OBJS);

      if (!is_library)
	{
          if (constituent.need_check)
            {
              check_java_fragment.copy (output_file, constituent.variables, 2, 
					&CONSTITUENT, &CONSTITUENTSUFFIX);
            }
	}
    }
  else
    {
      if (is_library)
        {
          cleanup_library_fragment.copy (output_file, constituent.variables, 2, 
					 &CONSTITUENT, &CONSTITUENTSUFFIX);
        }
      else
        {
          cleanup_application_fragment.copy (output_file, constituent.variables, 2, 
					     &CONSTITUENT, &CONSTITUENTSUFFIX);
          if (OBJS != "")
            {
              cleanup_objects_fragment.copy (output_file, constituent.variables, 3, 
					     &OBJS, &CONSTITUENT, &CONSTITUENTSUFFIX);
            }

          if (constituent.need_check)
            {
              check_application_fragment.copy (output_file, constituent.variables, 2, 
					       &CONSTITUENT, &CONSTITUENTSUFFIX);
            }
        }
    }
}

//--------------------------------------------------
void MakefileGenerator::build_document_makefile (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 suffix;
  static cmt_string output_suffix;
  static cmt_string fragment_suffix;
  int i;

  cout << TITLE << " " << 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];

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

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

  FragmentHandle fragment (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;

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

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

      static CmtSystem::cmt_string_vector files;

      get_all_files (full_name, files);

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

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

  fill_outputs ();

  prepare_use_context ();

  DATE = CmtSystem::now ();
  USER = CmtSystem::user ();

  make_header_fragment.copy (output_file, constituent.variables, 5,
			     &TITLE, &CONSTITUENT, &CONSTITUENTSUFFIX,
			     &USER, &DATE);

  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 (output_file, constituent.variables, 3, 
			    &CONSTITUENT, &CONSTITUENTSUFFIX, &OBJS);
    }
  else
    {
      document_header_fragment.copy (output_file, constituent.variables, 3, 
				     &CONSTITUENT, &CONSTITUENTSUFFIX, &OBJS);
    }

  if (fragment.need_dependencies ())
    {
      LINE = "";
      for (i = 0; i < sources.size (); i++)
        {
          cmt_string& file = sources[i];

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

          static CmtSystem::cmt_string_vector files;
          get_all_files (full_name, files);

          int count = 0;

          for (int j = 0; j < files.size (); j++)
            {
              cmt_string& n = files[j];
              if (n != "") count++;
            }

          if (count > 0)
            {
              LINE += full_name;
              LINE += " ";
            }
        }

      filter_paths (LINE.value);

      dependencies_fragment.copy (output_file, constituent.variables, 3, 
				  &CONSTITUENT, &CONSTITUENTSUFFIX, &LINE);
    }
  else
    {
      for (i = 0; i < sources.size (); i++)
        {
          cmt_string& file = sources[i];
          
          set_full_name (full_name, file);
	  if (full_name == "") continue;
          
          static CmtSystem::cmt_string_vector files;
          
          get_all_files (full_name, 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 (output_file, "%s_%s_dependencies = %s\n",
                           n.c_str (),
                           s.c_str (),
                           name.c_str ());
                }
            }
        }
    }
  
  SUFFIX = fragment_suffix;
  for (i = 0; i < source_files.size (); i++)
    {
      SourceFile& file = source_files[i];
      const cmt_string& file_name = file.name ();
      FULLNAME = file_name;
      CmtSystem::get_dot_suffix (file_name, suffix);
      CmtSystem::basename (file_name, suffix, NAME.value);
      CmtSystem::dirname (file_name, FILEPATH.value);
      if (FILEPATH.value != "") FILEPATH.value += CmtSystem::file_separator ();
      filter_paths (FILEPATH.value);
      CmtSystem::basename (file_name, FILENAME.value);
      CmtSystem::get_dot_suffix (FILENAME.value, FILESUFFIX.value);

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

      filter_paths (FULLNAME.value);

      fragment.copy (output_file, constituent.variables, 8,
                     &FILEPATH, &SUFFIX,
                     &CONSTITUENT, &CONSTITUENTSUFFIX, &FILENAME,
                     &NAME, &FULLNAME, &FILESUFFIX);
    }

  const cmt_string& trailer = fragment.trailer ();
  if (trailer != "")
    {
      FragmentHandle trailer_fragment (trailer);
      trailer_fragment.copy (output_file, constituent.variables, 3, 
			     &CONSTITUENT, &CONSTITUENTSUFFIX, &OBJS);
    }

  //
  //  Generate package cleanup operations.
  //

  cleanup_header_fragment.copy (output_file, constituent.variables, 2, 
				&CONSTITUENT, &CONSTITUENTSUFFIX);
}

//--------------------------------------------------
void MakefileGenerator::prepare_use_context ()
{
  cmt_string path;
  cmt_string substitution;

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

  deps_builder.clear ();

  if (use->include_path != "none")
    {
      if (use->include_path == "")
	{
	  deps_builder.add (incdir, "$(src)");
	}
      else
	{
	  substitution = use->include_path;
	  
	  path = substitution;
	  Symbol::expand (path);
	  
	  if (CmtSystem::file_separator () == '/')
	    {
	      path.replace_all ("\\", "/");
	      path.replace_all ("//", "/");
	    }
	  else
	    {
	      path.replace_all ("/", "\\");
	      path.replace_all ("\\\\", "\\");
	    }
	}
      
      deps_builder.add (path, substitution);
    }

  deps_builder.add_includes (*use);

  Use::UsePtrVector& uses = Use::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 == "")
		    {
		      path = use->real_path;
		      path += CmtSystem::file_separator ();
		      path += use->package;
		      path += CmtSystem::file_separator ();
		      path += use->version;
		      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);

		      if (CmtSystem::file_separator () == '/')
			{
			  path.replace_all ("\\", "/");
			  path.replace_all ("//", "/");
			}
		      else
			{
			  path.replace_all ("/", "\\");
			  path.replace_all ("\\\\", "\\");
			}
		    }

		  deps_builder.add (path, substitution);
		}

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

//--------------------------------------------------
void MakefileGenerator::set_full_name (cmt_string& full_name, cmt_string& file)
{
  full_name = "";

  Symbol::expand (file);

  if (file == "") return;
  
  if (!CmtSystem::absolute_path (file))
    {
      full_name = srcdir;
      if (full_name != "") full_name += CmtSystem::file_separator ();
    }
  
  full_name += file;

  char sep = CmtSystem::file_separator ();
  if (sep == '/') 
    {
      full_name.replace_all ("\\", sep);
      full_name.replace_all ("//", "/");
    }
  else
    {
      full_name.replace_all ("/", sep);
      full_name.replace_all ("\\\\", "\\");
    }
}

//--------------------------------------------------
void Generator::commit (const cmt_string& name)
{
  static cmt_string old;
  static cmt_string backup;

  old = name;

  int pos = old.find_last_of ("new");
  old.erase (pos);

  if (CmtSystem::test_file (old))
    {
      backup = old;
      backup += "sav";

      unlink (backup.c_str ());
      rename (old.c_str (), backup.c_str ());
    }

  rename (name.c_str (), old.c_str ());
}

//--------------------------------------------------
void Generator::check (const cmt_string& name)
{
  static cmt_string old;
  static cmt_string backup;

  old = name;

  int pos = old.find_last_of ("new");
  old.erase (pos);

  if (!CmtSystem::compare_files (old, name))
    {
      backup = old;
      backup += "sav";

      unlink (backup.c_str ());
      rename (old.c_str (), backup.c_str ());
      rename (name.c_str (), old.c_str ());
    }
  else
    {
      unlink (name);
    }
}

//--------------------------------------------------
int Generator::build_msdev_workspace (const Constituent::ConstituentVector& constituents)
{
  Context.reset ();

  const cmt_string& package = Cmt::current_package;

  cmt_string output = Context.msdevdir + package + ".dswnew";

  Context.output_file = fopen (output.c_str (), "wb");
  if (Context.output_file != NULL)
    {
      PACKAGE = package;
      dsw_header_fragment.wincopy (Context.output_file, 1, &PACKAGE);

      int i;

      dsw_all_project_header_fragment.wincopy (Context.output_file,
                                               1, &PACKAGE);

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

          if (constituent.type == Library)
            {
              CONSTITUENT = constituent.name;
              CONSTITUENTSUFFIX = constituent.suffix;
              dsw_all_project_dependency_fragment.wincopy (Context.output_file, constituent.variables, 3,
                                                           &PACKAGE,
                                                           &CONSTITUENT, 
                                                           &CONSTITUENTSUFFIX);
            }
	  else
	    {
	      CONSTITUENT = constituent.name;
	      CONSTITUENTSUFFIX = constituent.suffix;
	      dsw_all_project_dependency_fragment.wincopy (Context.output_file, constituent.variables, 3,
                                                           &PACKAGE,
							   &CONSTITUENT, 
                                                           &CONSTITUENTSUFFIX);
	    }

        }

      dsw_all_project_trailer_fragment.wincopy (Context.output_file,
                                                1, &PACKAGE);

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

          if (constituent.type == Library)
            {
              CONSTITUENT = constituent.name;
              CONSTITUENTSUFFIX = constituent.suffix;
              dsw_project_fragment.wincopy (Context.output_file,
                                            constituent.variables, 3,
                                            &PACKAGE,
                                            &CONSTITUENT, 
                                            &CONSTITUENTSUFFIX);
            }
          else
            {
              CONSTITUENT = constituent.name;
              CONSTITUENTSUFFIX = constituent.suffix;
              dsw_project_fragment.wincopy (Context.output_file, constituent.variables, 3, 
                                            &PACKAGE,
                                            &CONSTITUENT, 
                                            &CONSTITUENTSUFFIX);
            }
        }

      dsw_trailer_fragment.wincopy (Context.output_file, 1, &PACKAGE);

      fclose (Context.output_file);

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

      commit (output);
    }

  output = Context.msdevdir + "all.dspnew";

  Context.output_file = fopen (output.c_str (), "wb");
  if (Context.output_file != NULL)
    {
      dsp_all_fragment.wincopy (Context.output_file, 1, &PACKAGE);
      fclose (Context.output_file);

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

      commit (output);
    }

  return (0);
}

//--------------------------------------------------
int Generator::build_msdev (const Constituent& constituent)
{
  Context.reset ();

  const cmt_string& package = Cmt::current_package;
  static cmt_string file;
  static cmt_string full_name;
  static cmt_string suffix;

  int i;

  CONSTITUENT = constituent.name;
  CONSTITUENTSUFFIX = constituent.suffix;

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

  switch (constituent.type)
    {
    case Application:
      Context.is_application = true;
      TITLE = "Application";
      break;
    case Library:
      Context.is_library = true;
      TITLE = "Library";
      break;
    case Document:
      Context.is_document = true;
      Context.GENERATOR = constituent.generator;
      TITLE = "Document";
      break;
    }

  Context.PACKOS9 = constituent.need_OS9;

  const CmtSystem::cmt_string_vector& sources = constituent.modules;

  //--- Build the constituents fragment -----
  cmt_string output;
  cmt_string output_s;

  FILE* output_file = NULL;
  FILE* output_file_s = NULL;

  output = Context.msdevdir + CONSTITUENT + ".dspnew";
  output_file = fopen (output.c_str (), "wb");

  if ((output_file == NULL) && (output_file_s == NULL)) return (0);

  PACKAGE = package;

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

      dsp_library_header_fragment.wincopy (output_file, constituent.variables, 4,
                                           &PACKAGE,
                                           &CONSTITUENT, 
                                           &CONSTITUENTSUFFIX, 
                                           &LIBRARYSUFFIX);
    }
  else
    {
      if (constituent.windows)
        {
          dsp_windows_header_fragment.wincopy (output_file, constituent.variables, 3,
                                               &PACKAGE,
                                               &CONSTITUENT, 
                                               &CONSTITUENTSUFFIX);
        }
      else
        {
          dsp_application_header_fragment.wincopy (output_file, constituent.variables, 3,
                                                   &PACKAGE,
                                                   &CONSTITUENT, 
                                                   &CONSTITUENTSUFFIX);
        }
    }

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

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

      static CmtSystem::cmt_string_vector files;

      get_all_files (full_name, files);

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

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

              if (output_file != NULL)
                {
                  dsp_contents_fragment.wincopy (output_file, constituent.variables, 2, 
                                                 &PACKAGE, 
                                                 &FULLNAME);
                }
              if (output_file_s != NULL)
                {
                  dsp_contents_fragment.wincopy (output_file_s, constituent.variables, 2, 
                                                 &PACKAGE,
                                                 &FULLNAME);
                }
            }
        }

      /*
	CmtSystem::get_suffix (full_name, suffix);

	if (file.find ('*') != cmt_string::npos)
        {
	static CmtSystem::cmt_string_vector files;

	CmtSystem::scan_dir (full_name, files);

	if (Cmt::debug)
	{
	cout << "CMT> full_name=" << full_name <<
	" pwd=" << CmtSystem::pwd () << endl;
	cout << "CMT> files.size=" <<  files.size () << endl;
	}

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

	CmtSystem::get_suffix (nnn, sss);
	if (sss == suffix)
	{
	FULLNAME = nnn;
	if (output_file != NULL)
	{
	dsp_contents_fragment.wincopy (output_file,
	constituent.variables, 1, &FULLNAME);
	}
	if (output_file_s != NULL)
	{
	dsp_contents_fragment.wincopy (output_file_s,
	constituent.variables, 1, &FULLNAME);
	}
	}
	}
        }
	else
        {
	FULLNAME = full_name;
	if (output_file != NULL)
	{
	dsp_contents_fragment.wincopy (output_file, constituent.variables, 1, &FULLNAME);
	}
	if (output_file_s != NULL)
	{
	dsp_contents_fragment.wincopy (output_file_s, constituent.variables, 1, &FULLNAME);
	}
        }
      */
    }

  if (output_file != NULL)
    {
      dsp_trailer_fragment.wincopy (output_file, constituent.variables, 3,
                                    &PACKAGE,
				    &CONSTITUENT, 
                                    &CONSTITUENTSUFFIX);
      fclose (output_file);
      commit (output);
    }

  if (output_file_s != NULL)
    {
      dsp_trailer_fragment.wincopy (output_file_s, constituent.variables, 3,
                                    &PACKAGE,
				    &CONSTITUENT, 
                                    &CONSTITUENTSUFFIX);
      fclose (output_file_s);
      commit (output_s);
    }

  return (0);
}

//--------------------------------------------------
void Generator::build_make_setup (const cmt_string& package)
{
  Context.reset ();

  PACKAGE = package;

  FILE* output_file;

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

  output_file = fopen (new_file_name, "wb");

  if (output_file != NULL)
    {
      int number;
      const Use::UsePtrVector& uses = Use::uses ();
      const Constituent::ConstituentVector& constituents =
	Constituent::constituents ();
      cmt_string temp;

      make_setup_header_fragment.copy (output_file, 1, &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->real_path;
              temp += SLASH;
              temp += use->package;
              temp += SLASH;
              temp += use->version;

              fprintf (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 (output_file, "%s\n", temp.c_str());

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

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

      make_setup_fragment.copy (output_file, 1, &PACKAGE);

      fclose (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`

  */
}

//--------------------------------------------------
void Generator::build_constituents_makefile (const cmt_string& package)
{
  Context.reset ();
  cmt_string 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";

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

      GROUP = "all";

      constituents_header_fragment.copy (output_file, 1, &GROUP);

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

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

          GROUP = group.name ();

          constituents_header_fragment.copy (output_file, 1, &GROUP);
        }
      
      for (number = 0; number < constituents.size (); number++)
        {
          const Constituent& constituent = constituents[number];

          CONSTITUENT = constituent.name;
          CONSTITUENTSUFFIX = constituent.suffix;

          LINE = "";

          const CmtSystem::cmt_string_vector& sources = constituent.modules;

          constituent_fragment.copy (output_file, constituent.variables, 3, 
				     &CONSTITUENT, &CONSTITUENTSUFFIX, &LINE);

          if (constituent.need_check)
            {
              check_application_header_fragment.copy (output_file, 
						      constituent.variables, 2,
						      &CONSTITUENT, &CONSTITUENTSUFFIX);
            }
        }

      fclose (output_file);

      commit (new_file_name);
    }
}

//--------------------------------------------------
int Generator::build_constituent_makefile (const Constituent& constituent)
{
  Context.reset ();

  const cmt_string& package = Cmt::current_package;

  int i;

  PACKAGE = package;
  CONSTITUENT = constituent.name;
  CONSTITUENTSUFFIX = constituent.suffix;

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

  switch (constituent.type)
    {
    case Application:
      Context.is_library = false;
      Context.is_application = true;
      Context.is_document = false;
      TITLE = "Application";
      break;
    case Library:
      Context.is_library = true;
      Context.is_application = false;
      Context.is_document = false;
      TITLE = "Library";
      break;
    case Document:
      Context.is_library = false;
      Context.is_application = false;
      Context.is_document = true;
      Context.GENERATOR = constituent.generator;
      TITLE = "Document";
      break;
    }

  Context.PACKOS9 = constituent.need_OS9;

  cmt_string output = Context.cmtdir + CONSTITUENT + ".";

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


  Context.output_file = fopen (output.c_str (), "wb");
  if (Context.output_file != NULL)
    {
      if (Context.is_library)
        {
          Context.build_library_makefile (package, constituent);
        }
      else if (Context.is_application)
        {
          Context.build_application_makefile (package, constituent);
        }
      else if (Context.is_document)
        {
          Context.build_document_makefile (package, constituent);
        }

      fclose (Context.output_file);

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

      commit (output);
    }

  return (0);
}

//--------------------------------------------------
void Generator::build_constituent_makefile (const cmt_string& name)
{
  const Constituent* constituent = Constituent::find (name);
  if (constituent != 0) build_constituent_makefile (*constituent);
}

//--------------------------------------------------
void Generator::build_default_makefile ()
{
  cmt_string makefile;

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

#ifndef WIN32

  bool need_makefile = false;

  makefile = Context.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)
                {
                  cout << "# " << endl;
                  cout << "#CMT> Warning !!! " << endl;
                  cout << "# A Makefile already exists "
		    "but it does not provides " << endl;
                  cout << "# the recommended features "
		    "for a full benefit of CMT" << endl;
                  cout << "# " << endl;
                  cout << "# CMT is now building "
		    "a new 'Makefile.cmt' which you can use" << endl;
                  cout << "# to upgrade your current one." << endl;
                  cout << "# " << 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 = Context.cmtdir + "NMake";

  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

}

//--------------------------------------------------
cmt_string Generator::build_dependencies (const cmt_string& file_name)
{
  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 = Context.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 = Context.deps_builder.run (full_name);

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

  for (int j = 0; j < deps.size (); j++)
    {
      line += deps[j];
      line += " ";
    }

  filter_paths (line);

  return (line);
}

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

//--------------------------------------------------
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 Generator::build_dependencies (const cmt_string& name,
                                    int argc, char* argv[])
{
  Context.reset ();
  Context.prepare_use_context ();

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

  const Constituent& constituent = *constituent_ptr;

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

  static cmt_string output_name;

  cmt_string branch = CmtSystem::current_branch ();

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

      output_name = "../";
      if (current_use.package == "CMT")
        {
          output_name += CmtSystem::getenv ("CMTBIN");
        }
      else
        {
          output_name += Cmt::current_tag;
        }
      output_name += "/";

      Symbol::expand (output_name);
    }

  output_name += name;
  output_name += "_";
  output_name += "dependencies.";
  if (Cmt::build_nmake)
    {
      output_name += "nmake";
    }
  else
    {
      output_name += "make";
    }

  static DependencyFilter filter;

  dependencies.read (output_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;
  bool all_sources = false;

  int source_number = argc;
  int i;

  for (i = argc-1; i >= 0; i--)
    {
      file_name = argv[i];

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


  if (all_sources)
    {
      for (i = 0; i < sources.size (); i++)
        {
          file_name = sources[i];
          
          Context.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, files);

          for (int j = 0; j < files.size (); j++)
            {
              const cmt_string& name = files[j];
              
              if (name != "") 
                {
                  const cmt_string& line = build_dependencies (name);
                  
                    //cout << ">>> name1=" << name << endl;
                  
                  add_line_to_text (line, dependencies);
                }
            }
        }
    }
  else
    {
      for (i = 0; i < source_number; i++)
        {
          file_name = argv[i];
          
          Context.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_dependencies (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];
          
          Context.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, 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_dependencies (name);
                  
                        //cout << ">>> name3=" << name << endl;
                  
                      add_line_to_text (line, dependencies);
                    }
                }
            }
        }
    }

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

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

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

    Generator::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 Generator::build_prototype (const cmt_string& file_name)
{
  Prototyper prototyper;

  prototyper.run (file_name);
  /*
    static cmt_string pp;
    pp  = incdir;
    pp += name;
    pp += ".pp";
  */
}

//--------------------------------------------------
void Generator::build_readme (const CmtSystem::cmt_string_vector& arguments)
{
  Context.reset ();

  PACKAGE = Cmt::current_package;
  VERSION = Cmt::current_version;
  DATE = CmtSystem::now ();
  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);
        }
    }

  cmt_string output = Context.cmtdir + "README.html";

  Context.output_file = fopen (output.c_str (), "wb");
  if (Context.output_file != NULL)
    {
      readme_header_fragment.copy (Context.output_file, 2, &PACKAGE, &VERSION);

      if (doc != "")
        {
          DOCPATH = doc;
          readme_doc_fragment.copy (Context.output_file, 3, &PACKAGE, &VERSION, &DOCPATH);
        }

      readme_fragment.copy (Context.output_file, 2, &PACKAGE, &VERSION);

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

      for (number = 0; number < uses.size (); number++)
        {
          const Use* use = uses[number];
          if (use->discarded) continue;
          if ((use != 0) && (use->package != "CMT"))
            {
              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 ();
                    }
                }

              PACKAGEPATH = selected_path;
              PACKAGEPREFIX = use->specified_path;
              PACKAGE = use->package;
              VERSION = use->version;
              MGRSTYLE = (use->style == mgr_style) ? "mgr" : "cmt";
              readme_use_fragment.copy (Context.output_file, 5,
                                        &PACKAGEPATH,
                                        &PACKAGEPREFIX,
                                        &PACKAGE,
                                        &VERSION,
                                        &MGRSTYLE);
            }
        }
      PACKAGE = Cmt::current_package;
      VERSION = Cmt::current_version;
      readme_trailer_fragment.copy (Context.output_file, 4, 
                                    &PACKAGE, 
                                    &VERSION, 
                                    &DATE, 
                                    &USER);
    }
}

class WinDefAwk : public PAwk
{
public :
   WinDefAwk (const cmt_string& library_name)
    {
      m_name = library_name;
    }

  void begin ()
    {
      cout << "LIBRARY " << m_name << endl;
      cout << "EXPORTS" << endl;
    }

  void filter (const cmt_string& line)
    {
      if (line.find ("External") == cmt_string::npos) return;
      if (line.find ("??_") != cmt_string::npos) return;

      CmtSystem::cmt_string_vector words;
      CmtSystem::split (line, " \t", words);
      if (words.size () >= 8)
        {
          int pos = 7;

          cmt_string& fifth_word = words[4];
          if (fifth_word == "()") pos = 7;
          else if (fifth_word == "External") pos = 6;
          else return;

          cmt_string& symbol = words[pos];
          if (symbol[0] == '_') symbol.erase (0, 1);
          symbol.replace_all ("\r", "");
          symbol.replace_all ("\n", "");
          cout << " " << symbol << (pos == 6 ? "\tDATA" : " ") << endl;
        }
    }

  void end ()
    {
    }

private:
  cmt_string m_name;
};

//--------------------------------------------------
void Generator::build_windefs (const cmt_string& library_name)
{
	cmt_string bin;
	cmt_string name;
	cmt_string suffix;

	CmtSystem::dirname (library_name, bin);
	CmtSystem::get_dot_suffix (library_name, suffix);
	CmtSystem::basename (library_name, suffix, name);

	if (!CmtSystem::cd (bin)) return;
	
	cmt_string text;
	cmt_string command;
	
	command = "dumpbin /symbols ";
	command += library_name;
	
	WinDefAwk filter (name);
	
	filter.run (command, "SECT");
}

//--------------------------------------------------
void Packager::begin ()
{
  m_package_name = "";
}

void Packager::filter (const cmt_string& line)
{
  CmtSystem::cmt_string_vector words;

  CmtSystem::split (line, " ", words);
  if (words.size () > 1)
    {
      cmt_string& w = words[0];

      if (w == "package")
        {
          m_package_name = words[1];

	  int pos = m_package_name.find (";");
          if (pos != cmt_string::npos) m_package_name.erase (pos);
          m_package_name.replace_all (".", CmtSystem::file_separator ());
        }
    }
}

cmt_string& Packager::package_name ()
{
  return (m_package_name);
}

