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

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

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

/*----------------------------------------------------------*/
/*                                                          */
/*  Operations on Variables                                 */
/*                                                          */
/*----------------------------------------------------------*/

//----------------------------------------------------------
Variable* Variable::find (VariableVector& vector, 
                          const cmt_string& name)
{
  for (int i = 0; i < vector.size (); i++)
    {
      Variable& v = vector[i];

      if (v.name == name) return (&v);
    }

  return (0);
}

//----------------------------------------------------------
Variable::Variable ()
{
}

//----------------------------------------------------------
Variable::Variable (const cmt_string& n) : name (n)
{
  m_macro_braces = "${";
  m_macro_braces += name;
  m_macro_braces += "}";

  m_macro_pars = "$(";
  m_macro_pars += name;
  m_macro_pars += ")";
}

//----------------------------------------------------------
const cmt_string& Variable::macro_braces () const
{
  return (m_macro_braces);
}

//----------------------------------------------------------
const cmt_string& Variable::macro_pars () const
{
  return (m_macro_pars);
}

//----------------------------------------------------------
void Variable::set (const cmt_string& new_name,
                    const cmt_string& new_value)
{
  name = new_name;
  value = new_value;

  m_macro_braces = "${";
  m_macro_braces += name;
  m_macro_braces += "}";

  m_macro_pars = "$(";
  m_macro_pars += name;
  m_macro_pars += ")";
}

//----------------------------------------------------------
Variable& Variable::operator = (const Variable& other)
{
  value = other.value;
  return (*this);
}

//----------------------------------------------------------
Variable& Variable::operator = (const cmt_string& v)
{
  value = v;
  return (*this);
}

//----------------------------------------------------------
void Variable::operator += (const cmt_string& v)
{
  value += v;
}

//----------------------------------------------------------
cmt_string Variable::operator + (const cmt_string& v) const
{
  return (value + v);
}

//----------------------------------------------------------
Variable::operator const cmt_string& () const
{
  return (value);
}

//----------------------------------------------------------
bool Variable::operator == (const cmt_string& v) const
{
  return ((value == v));
}

//----------------------------------------------------------
bool Variable::operator != (const cmt_string& v) const
{
  return ((value != v));
}

/*----------------------------------------------------------*/
/*                                                          */
/*  Operations on Fragments                                 */
/*                                                          */
/*----------------------------------------------------------*/

/*----------------------------------------------------------*/
void Fragment::show (const cmt_string& name)
{
  Fragment* fragment = Fragment::find (name);
  if (fragment == 0)
    {
      cout << "Fragment " << name << " not found" << endl;
    }
  else
    {
      fragment->print ();
    }
}

/*----------------------------------------------------------*/
void Fragment::show_all ()
{
  static FragmentVector& Fragments = fragments ();

  int number;

  for (number = 0; number < Fragments.size (); number++)
    {
      Fragment& fragment = Fragments[number];

      fragment.print ();
    }
}

class fragment_action_iterator
{
public:

  fragment_action_iterator (Use* use) :
    m_need_dependencies (false),
    m_state (need_name),
    m_use (use)
  {
  }

  void add_word (const cmt_string& w)
  {
    switch (m_state)
      {
      case need_name:
	m_name = w;
	m_state = need_options;
	break;
      case need_options:
	if (w.find ("-suffix=") != cmt_string::npos)
	  {
	    m_suffix = w;
	    m_suffix.replace ("-suffix=", "");
	  }
	else if (w.find ("-dependencies") != cmt_string::npos)
	  {
	    m_need_dependencies = true;
	  }
	else if (w.find ("-header=") != cmt_string::npos)
	  {
	    m_header = w;
	    m_header.replace ("-header=", "");

	    if (Fragment::find (m_header) == 0)
	      {
		Fragment::add (m_header, "", "", "", false, m_use);
	      }
	  }
	else if (w.find ("-trailer=") != cmt_string::npos)
	  {
	    m_trailer = w;
	    m_trailer.replace ("-trailer=", "");
	    
	    if (Fragment::find (m_trailer) == 0)
	      {
		Fragment::add (m_trailer, "", "", "", false, m_use);
	      }
	  }
	break;
      }
  }

  void commit ()
  {
    Fragment::add (m_name, m_suffix, m_header, m_trailer, m_need_dependencies, m_use);
  }

private:

  enum
    {
      need_name,
      need_options
    } m_state;

  cmt_string m_name;
  cmt_string m_suffix;
  cmt_string m_header;
  cmt_string m_trailer;
  bool m_need_dependencies;
  Use* m_use;
};


/*----------------------------------------------------------*/
void Fragment::action (const CmtSystem::cmt_string_vector& words,
                       Use* use)
{
  if ((Cmt::get_current_access () == UserMode) &&
      (use->get_current_scope () == ScopePrivate)) return;

  if (words.size () <= 1) return;

  fragment_action_iterator it (use);

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

      Symbol::expand (ew);
      if (ew != w)
        {
          CmtSystem::cmt_string_vector ws;

          CmtSystem::split (ew, " ", ws);

          for (int j = 0; j < ws.size (); ++j)
            {
              const cmt_string& ww = ws[j];
              it.add_word (ww);
            }
        }
      else
        {
          it.add_word (ew);
        }
    }

  it.commit ();
}

/*----------------------------------------------------------*/
Fragment* Fragment::find (const cmt_string& name)
{
  static FragmentVector& Fragments = fragments ();

  int fragment_index;

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

  for (fragment_index = 0;
       fragment_index < Fragments.size ();
       fragment_index++)
    {
      Fragment& fragment = Fragments[fragment_index];

      if (fragment.name == name)
        {
          return (&fragment);
        }
    }

  return (0);
}

/*----------------------------------------------------------*/
void Fragment::add (const cmt_string& name,
                    const cmt_string& suffix,
                    const cmt_string& header,
                    const cmt_string& trailer,
                    bool need_dependencies,
                    Use* use)
{
  static FragmentVector& Fragments = fragments ();

  {
    Fragment* fragment;

    if (name == "") return;

    fragment = find (name);
    if (fragment != 0)
      {
        if (suffix != "")
          {
            fragment->suffix = suffix;
          }

        if (header != "")
          {
            fragment->header = header;
          }

        if (trailer != "")
          {
            fragment->trailer = trailer;
          }

        fragment->need_dependencies = need_dependencies;

        fragment->use = use;
        return;
      }
  }

  Fragment& fragment = Fragments.add ();

  fragment.name              = name;
  fragment.suffix            = suffix;
  fragment.header            = header;
  fragment.trailer           = trailer;
  fragment.need_dependencies = need_dependencies;
  fragment.use               = use;
}

/*----------------------------------------------------------*/
void Fragment::clear_all ()
{
  static FragmentVector& Fragments = fragments ();

  for (int i = 0; i < Fragments.size (); i++)
    {
      Fragment& f = Fragments[i];
      f.clear ();
    }

  Fragments.clear ();
}

/*----------------------------------------------------------*/
Fragment::FragmentVector& Fragment::fragments ()
{
  static Database& db = Database::instance ();
  static FragmentVector& Fragments = db.fragments ();

  return (Fragments);
}

/*----------------------------------------------------------*/
Fragment::Fragment ()
{
  use = 0;
}

/*----------------------------------------------------------*/
Fragment::Fragment (const cmt_string& fragment_name)
{
  name = fragment_name;
  use = 0;
  path = "";
}

/*----------------------------------------------------------*/
Fragment::~Fragment ()
{
  use = 0;
}

/*----------------------------------------------------------*/
void Fragment::clear ()
{
  name    = "";
  suffix  = "";
  header  = "";
  trailer = "";
  need_dependencies = false;
  path = "";
  use  = 0;
}

/*----------------------------------------------------------*/
int Fragment::print ()
{
  int result = 1;

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

  if (use == 0)
    {
      Use& u = Use::current();
      use = &u;
    }
  
  cmt_string the_path = path;

  use->reduce_path (the_path);

  cout << the_path;

  if (suffix != "")
    {
      cout << "->" << suffix;
    }

  cout << endl;

  return (result);
}

/*----------------------------------------------------------*/
bool Fragment::locate ()
{
  cmt_string root_path;

  if (use == 0)
    {
      // Assume CMT
      use = Use::find ("CMT");
    }

  use->get_full_path (root_path);

  if (path != "") return (true);

  // First try <root>/fragments/<name> or <root>/fragments/nmake/<name>

  path = root_path;
  path += CmtSystem::file_separator ();
  path += "fragments";
  path += CmtSystem::file_separator ();
  
  if (Cmt::build_nmake ())
    {
      path += "nmake";
      path += CmtSystem::file_separator ();
    }
  
  path += name;

  if (CmtSystem::test_file (path)) return (true);

  // Then try <root>/fragments/<name> for both Win and Unix

  path = root_path;
  path += CmtSystem::file_separator ();
  path += "fragments";
  path += CmtSystem::file_separator ();
  path += name;

  if (CmtSystem::test_file (path)) return (true);

  // Then try <root>/cmt/fragments/<name> or <root>/cmt/fragments/nmake/<name>

  root_path += CmtSystem::file_separator ();

  if (use->style == mgr_style) root_path += "mgr";
  else root_path += "cmt";
  
  root_path += CmtSystem::file_separator ();
  root_path += "fragments";
  root_path += CmtSystem::file_separator ();
  
  path = root_path;
  
  if (Cmt::build_nmake ())
    {
      path += "nmake";
      path += CmtSystem::file_separator ();
    }
  
  path += name;
  
  if (CmtSystem::test_file (path)) return (true);

  // Then try <root>/cmt/fragments/<name> for both Win and Unix

  path = root_path;
  
  path += name;

  if (CmtSystem::test_file (path)) return (true);

  return (false);
}

//--------------------------------------------------
bool Fragment::copy (FILE* out,
                     const cmt_string& name,
                     int variables, ...)
{
  va_list ids;

  Fragment* fragment = Fragment::find (name);
  if (fragment == 0) return (false);

  va_start (ids, variables);
  bool result = fragment->copy (out, variables, ids);
  va_end (ids);

  return (result);
}

//--------------------------------------------------
bool Fragment::copy (cmt_string& out,
                     const cmt_string& name,
                     int variables, ...)
{
  va_list ids;

  Fragment* fragment = Fragment::find (name);
  if (fragment == 0) return (false);

  va_start (ids, variables);
  bool result = fragment->copy (out, variables, ids);
  va_end (ids);

  return (result);
}

//--------------------------------------------------
bool Fragment::copy (FILE* out, int variables, ...)
{
  va_list ids;

  va_start (ids, variables);
  bool result = copy (out, variables, ids);
  va_end (ids);

  return (result);
}

//--------------------------------------------------
bool Fragment::copy (cmt_string& out, int variables, ...)
{
  va_list ids;

  va_start (ids, variables);
  bool result = copy (out, variables, ids);
  va_end (ids);

  return (result);
}

//--------------------------------------------------
bool Fragment::copy (FILE* out, int variables, va_list ids)
{
  static cmt_string cline;

  bool result = copy (cline, variables, ids);
  if (result)
    {
      cline.write (out);
      return (true);
    }
  else
    {
      return (false);
    }
}

//--------------------------------------------------
bool Fragment::copy (cmt_string& out, int variables, va_list ids)
{
  int i;

  if (!locate ()) return (false);

  out.read (path);

  Variable* var = 0;
  for (i = 0; i < variables; i++)
    {
      var = va_arg (ids, Variable*);
      out.replace_all (var->macro_braces (), var->value);
      out.replace_all (var->macro_pars (), var->value);
    }

  return (true);
}

//--------------------------------------------------
bool Fragment::wincopy (FILE* out, int variables, va_list ids)
{
  static cmt_string cline;

  bool result = wincopy (cline, variables, ids);

  if (result)
    {
      cline.write (out);
      return (true);
    }
  else
    {
      return (false);
    }
}

//--------------------------------------------------
bool Fragment::wincopy (cmt_string& out, int variables, va_list ids)
{
  int i;

  if (!locate ()) return (false);

  out.read (path);

  Variable* var = 0;
  for (i = 0; i < variables; i++)
    {
      var = va_arg (ids, Variable*);
      out.replace_all (var->macro_braces (), var->value);
      out.replace_all (var->macro_pars (), var->value);
    }

  cmt_string pattern;
  cmt_string macro_name;
  char end_pattern;

  int start = 0;

  for (;;)
    {
      //
      // Try and substitute all ${xxx} or $(xxx) patterns
      // using symbol values.
      //
      int par;
      int brace;
      int begin;

      par = out.find (start, "$(");
      brace = out.find (start, "${");

      if (par == cmt_string::npos)
        {
	  // No parentheses. Look for brace
          if (brace == cmt_string::npos)
            {
	      // No pattern, finish the scan.
              break;
            }

	  // Brace found
          end_pattern = '}';
          begin = brace;
        }
      else
        {
	  // Parenthese found. Look for closest from {par, brace}
          if ((brace == cmt_string::npos) ||
              (brace > par))
            {
              end_pattern = ')';
              begin = par;
            }
          else
            {
              end_pattern = '}';
              begin = brace;
            }
        }

      // Skip the pattern intro.
      start = begin + 2;

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

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

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

      // Then only the macro name
      out.substr (begin + 2, end - begin - 2, macro_name);

      if (macro_name == "CFG")
        {
	  // This is a Windows reserved keyword...
          start = end + 1;
        }
      else
        {
          Symbol* macro = Symbol::find (macro_name);
          if (macro != 0)
            {
	      // Macro found
              cmt_string value = macro->resolve_macro_value ();
	      //cout << "resolve_macro_value2> value=" << value << endl;
              out.replace_all (pattern, value);

	      // The substitution will restart from the same place
	      // allowing for recursive replacements
              start = begin;
            }
          else
            {
	      // Macro not found. Look for env. variable
              cmt_string value = CmtSystem::getenv (macro_name);
	      //cout << "resolve_macro_value3> " << macro_name << "=" << value << endl;
              out.replace_all (pattern, value);

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

  // Uniformly install CR-LF doublets.

  out.replace_all ("\r\n", "\n");
  out.replace_all ("\n", "\r\n");

  return (true);
}








//--------------------------------------------------
bool Fragment::copy (FILE* out,
                     const cmt_string& name,
                     const Variable::VariableVector& vector, 
                     int variables, ...)
{
  va_list ids;

  Fragment* fragment = Fragment::find (name);
  if (fragment == 0) return (false);

  va_start (ids, variables);
  bool result = fragment->copy (out, vector, variables, ids);
  va_end (ids);

  return (result);
}

//--------------------------------------------------
bool Fragment::copy (cmt_string& out,
                     const cmt_string& name,
                     const Variable::VariableVector& vector, 
                     int variables, ...)
{
  va_list ids;

  Fragment* fragment = Fragment::find (name);
  if (fragment == 0) return (false);

  va_start (ids, variables);
  bool result = fragment->copy (out, vector, variables, ids);
  va_end (ids);

  return (result);
}

//--------------------------------------------------
bool Fragment::copy (FILE* out, const Variable::VariableVector& vector, int variables, ...)
{
  va_list ids;

  va_start (ids, variables);
  bool result = copy (out, vector, variables, ids);
  va_end (ids);

  return (result);
}

//--------------------------------------------------
bool Fragment::copy (cmt_string& out, const Variable::VariableVector& vector, int variables, ...)
{
  va_list ids;

  va_start (ids, variables);
  bool result = copy (out, vector, variables, ids);
  va_end (ids);

  return (result);
}

//--------------------------------------------------
bool Fragment::copy (FILE* out, const Variable::VariableVector& vector, int variables, va_list ids)
{
  static cmt_string cline;

  bool result = copy (cline, vector, variables, ids);
  if (result)
    {
      cline.write (out);
      return (true);
    }
  else
    {
      return (false);
    }
}

//--------------------------------------------------
bool Fragment::copy (cmt_string& out, const Variable::VariableVector& vector, int variables, va_list ids)
{
  int i;

  if (!locate ()) return (false);

  out.read (path);

  Variable* var = 0;

  for (i = 0; i < vector.size (); i++)
    {
      var = &(vector[i]);
      out.replace_all (var->macro_braces (), var->value);
      out.replace_all (var->macro_pars (), var->value);
    }

  for (i = 0; i < variables; i++)
    {
      var = va_arg (ids, Variable*);
      out.replace_all (var->macro_braces (), var->value);
      out.replace_all (var->macro_pars (), var->value);
    }

  return (true);
}

//--------------------------------------------------
bool Fragment::wincopy (FILE* out, const Variable::VariableVector& vector, int variables, va_list ids)
{
  static cmt_string cline;

  bool result = wincopy (cline, vector, variables, ids);
  if (result)
    {
      cline.write (out);
      return (true);
    }
  else
    {
      return (false);
    }
}

//--------------------------------------------------
bool Fragment::wincopy (cmt_string& out, const Variable::VariableVector& vector, 
                        int variables, va_list ids)
{
  int i;

  if (!locate ()) return (false);

  out.read (path);

  Variable* var = 0;

  for (i = 0; i < vector.size (); i++)
    {
      var = &(vector[i]);
      out.replace_all (var->macro_braces (), var->value);
      out.replace_all (var->macro_pars (), var->value);
    }

  for (i = 0; i < variables; i++)
    {
      var = va_arg (ids, Variable*);
      out.replace_all (var->macro_braces (), var->value);
      out.replace_all (var->macro_pars (), var->value);
    }

  cmt_string pattern;
  cmt_string macro_name;
  char end_pattern;

  int start = 0;

  for (;;)
    {
      //
      // Try and substitute all ${xxx} or $(xxx) patterns
      // using symbol values.
      //
      int par;
      int brace;
      int begin;

      par = out.find (start, "$(");
      brace = out.find (start, "${");

      if (par == cmt_string::npos)
        {
	  // No parentheses. Look for brace
          if (brace == cmt_string::npos)
            {
	      // No pattern, finish the scan.
              break;
            }

	  // Brace found
          end_pattern = '}';
          begin = brace;
        }
      else
        {
	  // Parenthese found. Look for closest from {par, brace}
          if ((brace == cmt_string::npos) ||
              (brace > par))
            {
              end_pattern = ')';
              begin = par;
            }
          else
            {
              end_pattern = '}';
              begin = brace;
            }
        }

      // Skip the pattern intro.
      start = begin + 2;

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

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

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

      // Then only the macro name
      out.substr (begin + 2, end - begin - 2, macro_name);

      if (macro_name == "CFG")
        {
	  // This is a Windows reserved keyword...
          start = end + 1;
        }
      else
        {
          Symbol* macro = Symbol::find (macro_name);
          if (macro != 0)
            {
	      // Macro found
              cmt_string value = macro->resolve_macro_value ();
	      //cout << "resolve_macro_value2> value=" << value << endl;
              out.replace_all (pattern, value);

	      // The substitution will restart from the same place
	      // allowing for recursive replacements
              start = begin;
            }
          else
            {
	      // Macro not found. Look for env. variable
              cmt_string value = CmtSystem::getenv (macro_name);
	      //cout << "resolve_macro_value3> " << macro_name << "=" << value << endl;
              out.replace_all (pattern, value);

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

  // Uniformly install CR-LF doublets.

  out.replace_all ("\r\n", "\n");
  out.replace_all ("\n", "\r\n");

  return (true);
}

//--------------------------------------------------
FragmentHandle::FragmentHandle ()
{
  _fragment = 0;
  _initialized = false;
}

//--------------------------------------------------
FragmentHandle::FragmentHandle (const cmt_string name) : _name(name)
{
  _fragment = 0;
  _initialized = false;
}

//--------------------------------------------------
FragmentHandle& FragmentHandle::operator = (const FragmentHandle& other)
{
  _name = other._name;
  _fragment = 0;
  _initialized = false;

  return (*this);
}

//--------------------------------------------------
void FragmentHandle::reset ()
{
  _fragment = 0;
  _initialized = false;
}

//--------------------------------------------------
void FragmentHandle::set (const cmt_string name)
{
  _name = name;
  _fragment = 0;
  _initialized = false;
}

//--------------------------------------------------
cmt_string& FragmentHandle::name ()
{
  static cmt_string null_string;

  if (!setup ()) return (null_string);

  return (_fragment->name);
}

//--------------------------------------------------
cmt_string& FragmentHandle::suffix ()
{
  static cmt_string null_string;

  if (!setup ()) return (null_string);

  return (_fragment->suffix);
}

//--------------------------------------------------
cmt_string& FragmentHandle::header ()
{
  static cmt_string null_string;

  if (!setup ()) return (null_string);

  return (_fragment->header);
}

//--------------------------------------------------
cmt_string& FragmentHandle::trailer ()
{
  static cmt_string null_string;

  if (!setup ()) return (null_string);

  return (_fragment->trailer);
}

//--------------------------------------------------
bool FragmentHandle::need_dependencies ()
{
  if (!setup ()) return (false);

  return (_fragment->need_dependencies);
}

//--------------------------------------------------
bool FragmentHandle::copy (FILE* out, int variables, ...)
{
  if (!setup ()) return (false);

  va_list ids;

  va_start (ids, variables);
  bool result = _fragment->copy (out, variables, ids);
  va_end (ids);

  if (!result)
    {
      cerr << "#CMT> Fragment " << _name << " not found" << endl;
      _fragment = 0;
    }

  return (result);
}

//--------------------------------------------------
bool FragmentHandle::copy (cmt_string& out, int variables, ...)
{
  if (!setup ()) return (false);

  va_list ids;

  va_start (ids, variables);
  bool result = _fragment->copy (out, variables, ids);
  va_end (ids);

  if (!result)
    {
      cerr << "#CMT> Fragment " << _name << " not found" << endl;
      _fragment = 0;
    }

  return (result);
}

//--------------------------------------------------
bool FragmentHandle::wincopy (FILE* out, int variables, ...)
{
  if (!setup ()) return (false);

  va_list ids;

  va_start (ids, variables);
  bool result = _fragment->wincopy (out, variables, ids);
  va_end (ids);

  if (!result)
    {
      cerr << "#CMT> Fragment " << _name << " not found" << endl;
      _fragment = 0;
    }

  return (result);
}

//--------------------------------------------------
bool FragmentHandle::wincopy (cmt_string& out, int variables, ...)
{
  if (!setup ()) return (false);

  va_list ids;

  va_start (ids, variables);
  bool result = _fragment->wincopy (out, variables, ids);
  va_end (ids);

  if (!result)
    {
      cerr << "#CMT> Fragment " << _name << " not found" << endl;
      _fragment = 0;
    }

  return (result);
}




//--------------------------------------------------
bool FragmentHandle::copy (FILE* out, const Variable::VariableVector& vector, int variables, ...)
{
  if (!setup ()) return (false);

  va_list ids;

  va_start (ids, variables);
  bool result = _fragment->copy (out, vector, variables, ids);
  va_end (ids);

  if (!result)
    {
      cerr << "#CMT> Fragment " << _name << " not found" << endl;
      _fragment = 0;
    }

  return (result);
}

//--------------------------------------------------
bool FragmentHandle::copy (cmt_string& out, const Variable::VariableVector& vector, int variables, ...)
{
  if (!setup ()) return (false);

  va_list ids;

  va_start (ids, variables);
  bool result = _fragment->copy (out, vector, variables, ids);
  va_end (ids);

  if (!result)
    {
      cerr << "#CMT> Fragment " << _name << " not found" << endl;
      _fragment = 0;
    }

  return (result);
}

//--------------------------------------------------
bool FragmentHandle::wincopy (FILE* out, const Variable::VariableVector& vector, int variables, ...)
{
  if (!setup ()) return (false);

  va_list ids;

  va_start (ids, variables);
  bool result = _fragment->wincopy (out, vector, variables, ids);
  va_end (ids);

  if (!result)
    {
      cerr << "#CMT> Fragment " << _name << " not found" << endl;
      _fragment = 0;
    }

  return (result);
}

//--------------------------------------------------
bool FragmentHandle::wincopy (cmt_string& out, 
                              const Variable::VariableVector& vector, 
                              int variables, ...)
{
  if (!setup ()) return (false);

  va_list ids;

  va_start (ids, variables);
  bool result = _fragment->wincopy (out, vector, variables, ids);
  va_end (ids);

  if (!result)
    {
      cerr << "#CMT> Fragment " << _name << " not found" << endl;
      _fragment = 0;
    }

  return (result);
}

//--------------------------------------------------
bool FragmentHandle::setup ()
{
  if (!_initialized)
    {
      _initialized = true;

      _fragment = Fragment::find (_name);
      if (_fragment == 0)
        {
          cerr << "#CMT> Fragment " << _name << " not found" << endl;
        }
    }

  if (_fragment == 0)
    {
      return (false);
    }
  else
    {
      return (true);
    }
}
