Browse Source

ENH: Change to new CABLE command architecture. CABLE configuration code is now generated on the first pass, during the Invoke() calls.

Brad King 25 years ago
parent
commit
dc72655414

+ 55 - 0
Source/cmCableCloseNamespaceCommand.cxx

@@ -0,0 +1,55 @@
+/*=========================================================================
+
+  Program:   Insight Segmentation & Registration Toolkit
+  Module:    $RCSfile$
+  Language:  C++
+  Date:      $Date$
+  Version:   $Revision$
+
+
+  Copyright (c) 2000 National Library of Medicine
+  All rights reserved.
+
+  See COPYRIGHT.txt for copyright details.
+
+=========================================================================*/
+#include "cmCableCloseNamespaceCommand.h"
+#include "cmCacheManager.h"
+
+
+// cmCableCloseNamespaceCommand
+bool cmCableCloseNamespaceCommand::Invoke(std::vector<std::string>& args)
+{
+  if(args.size() != 1)
+    {
+    this->SetError("called with incorrect number of arguments");
+    return false;
+    }
+  
+  // This command needs to access the Cable data.
+  this->SetupCableData();
+  
+  // The argument is the namespace name.
+  m_NamespaceName = args[0];
+  
+  // Ask the cable data to close the namespace.
+  m_CableData->CloseNamespace(m_NamespaceName);
+
+  // Write the configuration for this command.
+  this->WriteNamespaceFooter();  
+  
+  return true;
+}
+
+
+/**
+ * Generate a CABLE Namespace close tag.
+ */
+void cmCableCloseNamespaceCommand::WriteNamespaceFooter() const
+{
+  m_CableData->Unindent();
+  std::ostream& os = m_CableData->GetOutputStream();
+  cmCableData::Indentation indent = m_CableData->GetIndentation();
+  os << indent << "</Namespace> <!-- \"" << m_NamespaceName.c_str()
+     << "\" -->" << std::endl;
+}

+ 89 - 0
Source/cmCableCloseNamespaceCommand.h

@@ -0,0 +1,89 @@
+/*=========================================================================
+
+  Program:   Insight Segmentation & Registration Toolkit
+  Module:    $RCSfile$
+  Language:  C++
+  Date:      $Date$
+  Version:   $Revision$
+
+
+  Copyright (c) 2000 National Library of Medicine
+  All rights reserved.
+
+  See COPYRIGHT.txt for copyright details.
+
+=========================================================================*/
+#ifndef cmCableCloseNamespaceCommand_h
+#define cmCableCloseNamespaceCommand_h
+
+#include "cmStandardIncludes.h"
+#include "cmCableCommand.h"
+
+/** \class cmCableCloseNamespaceCommand
+ * \brief Define a command that closes a CABLE Namespace.
+ *
+ * cmCableCloseNamespaceCommand is used to generate CABLE Namespace
+ * close tags in the configuration file.
+ */
+class cmCableCloseNamespaceCommand : public cmCableCommand
+{
+public:
+  /**
+   * This is a virtual constructor for the command.
+   */
+  virtual cmCommand* Clone()
+    {
+      return new cmCableCloseNamespaceCommand;
+    }
+
+  /**
+   * This is called when the command is first encountered in
+   * the CMakeLists.txt file.
+   */
+  virtual bool Invoke(std::vector<std::string>& args);
+  
+  /**
+   * This determines if the command gets propagated down
+   * to makefiles located in subdirectories.
+   */
+  virtual bool IsInherited() 
+    {return true;}
+
+  /**
+   * The name of the command as specified in CMakeList.txt.
+   */
+  virtual const char* GetName() { return "CABLE_CLOSE_NAMESPACE";}
+
+  /**
+   * Succinct documentation.
+   */
+  virtual const char* GetTerseDocumentation() 
+    {
+    return "Close a CABLE Namespace";
+    }
+  
+  /**
+   * More documentation.
+   */
+  virtual const char* GetFullDocumentation()
+    {
+    return
+      "CABLE_CLOSE_NAMESPACE(namespace_name)\n"
+      "Close the given namespace in the generated configuration file.\n"
+      "There must be a matching CABLE_OPEN_NAMESPACE(namespace_name)\n"
+      "called with the same name.";
+    }
+
+  cmTypeMacro(cmCableCloseNamespaceCommand, cmCableCommand);
+private:
+  void WriteNamespaceFooter() const;
+private:
+  /**
+   * The name of the namespace to setup.
+   */
+  std::string m_NamespaceName;
+};
+
+
+
+#endif

+ 0 - 19
Source/cmCableCommand.cxx

@@ -39,25 +39,6 @@ cmCableCommand::~cmCableCommand()
 }
 
 
-/**
- * Write a CABLE configuration file header.
- */
-void cmCableCommand::WriteConfigurationHeader(std::ostream& os) const
-{
-  os << "<?xml version=\"1.0\"?>" << std::endl
-     << "<CableConfiguration>" << std::endl;
-}
-
-
-/**
- * Write a CABLE configuration file footer.
- */
-void cmCableCommand::WriteConfigurationFooter(std::ostream& os) const
-{
-  os << "</CableConfiguration>" << std::endl;
-}
-
-
 /**
  * Ensure that this cmCableCommand has a valid m_CableData pointer.
  */

+ 0 - 3
Source/cmCableCommand.h

@@ -37,9 +37,6 @@ public:
   cmCableCommand();
   virtual ~cmCableCommand();
   
-  void WriteConfigurationHeader(std::ostream&) const;
-  void WriteConfigurationFooter(std::ostream&) const;
-  
   cmTypeMacro(cmCableCommand, cmCommand);
 protected:
   void SetupCableData();

+ 141 - 49
Source/cmCableData.cxx

@@ -16,104 +16,196 @@
 #include "cmCableData.h"
 #include "cmCacheManager.h"
 
+#include "cmCablePackageCommand.h"
 
 /**
- * Free all data that was stored here.
+ * The cmCableData instance is owned by one cmCableCommand, which is given
+ * to this constructor.
+ */
+cmCableData::cmCableData(const cmCableCommand* owner):
+  m_Owner(owner),
+  m_Indentation(0),
+  m_Package(NULL),
+  m_PackageNamespaceDepth(0)
+{
+  this->OpenOutputFile("cable_config.xml");
+}
+
+
+/**
+ * Free all data that was stored here.  Also close the output file.
  */
 cmCableData::~cmCableData()
 {
-  for(OutputFiles::iterator i = m_OutputFiles.begin();
-      i != m_OutputFiles.end(); ++i)
+  // End last package, if any.
+  this->EndPackage();
+  
+  // Finish up the output file.
+  this->CloseOutputFile();
+}
+
+
+/**
+ * Open the configuration output file with the given name.  This
+ * writes the configuration header.
+ */
+void cmCableData::OpenOutputFile(const std::string& name)
+{
+  m_OutputFile.open(name.c_str());
+  
+  if(m_OutputFile)
     {
-    delete i->second;
+    this->WriteConfigurationHeader();
     }
 }
 
 
 /**
- * The constructor attempts to open the file for writing.
+ * Close the configuration output file.  This writes the configuration
+ * footer.
  */
-cmCableData::OutputFile
-::OutputFile(std::string file, const cmCableCommand* command):
-  m_FileStream(file.c_str()),
-  m_FirstReferencingCommand(command),
-  m_LastReferencingCommand(command)
+void cmCableData::CloseOutputFile()
 {
-  if(!m_FileStream)
+  if(m_OutputFile)
     {
-    cmSystemTools::Error("Error can not open for write: ", file.c_str());
+    this->WriteConfigurationFooter();
+    m_OutputFile.close();
     }
 }
 
 
 /**
- * Destructor closes the file, if it was open.
+ * Write a CABLE configuration file header.
  */
-cmCableData::OutputFile
-::~OutputFile()
+void cmCableData::WriteConfigurationHeader()
 {
-  if(m_FileStream)
-    m_FileStream.close();
+  m_OutputFile << m_Indentation << "<?xml version=\"1.0\"?>" << std::endl
+               << m_Indentation << "<CableConfiguration>" << std::endl;  
+  this->Indent();
 }
 
 
 /**
- * Get the output stream associated with this OutputFile.
+ * Write a CABLE configuration file footer.
  */
-std::ostream&
-cmCableData::OutputFile
-::GetStream()
+void cmCableData::WriteConfigurationFooter()
 {
-  return m_FileStream;
+  this->Unindent();
+  m_OutputFile << m_Indentation << "</CableConfiguration>" << std::endl;
 }
 
 
+/**
+ * Print indentation spaces.
+ */
 void
-cmCableData::OutputFile
-::SetLastReferencingCommand(const cmCableCommand* command)
+cmCableData::Indentation
+::Print(std::ostream& os) const
+{
+  if(m_Indent <= 0)
+    { return; }
+  
+  // Use blocks of 8 spaces to speed up big indents.
+  unsigned int blockCount = m_Indent >> 3;
+  unsigned int singleCount = m_Indent & 7;
+  while(blockCount-- > 0)
+    {
+    os << "        ";
+    }
+  while(singleCount-- > 0)
+    {
+    os << " ";
+    }
+}
+
+
+/**
+ * Open a namespace with the given name.
+ */
+void cmCableData::OpenNamespace(const std::string& name)
 {
-  m_LastReferencingCommand = command;
+  m_NamespaceStack.push_back(name);
 }
 
 
-bool
-cmCableData::OutputFile
-::FirstReferencingCommandIs(const cmCableCommand* command) const
+/**
+ * Close the current namespace, checking whether it has the given name.
+ */
+void cmCableData::CloseNamespace(const std::string& name)
 {
-  return (m_FirstReferencingCommand == command);
+  if(m_NamespaceStack.empty())
+    {
+    cmSystemTools::Error("Unbalanced close-namespace = ", name.c_str());
+    return;
+    }
+  if(m_NamespaceStack.back() != name)
+    {
+    cmSystemTools::Error("Wrong name on close-namespace = ", name.c_str());
+    }
+  
+  // If this closes the namespace where the current package was opened,
+  // the package must end as well.
+  if(m_Package && (m_PackageNamespaceDepth == m_NamespaceStack.size()))
+    {
+    this->EndPackage();
+    }
+  
+  m_NamespaceStack.pop_back();
 }
 
 
-bool
-cmCableData::OutputFile
-::LastReferencingCommandIs(const cmCableCommand* command) const
+/**
+ * Begin a new package definition.  If there is a current one, it
+ * will be ended.
+ */
+void cmCableData::BeginPackage(cmCablePackageCommand* command)
 {
-  return (m_LastReferencingCommand == command);
+  // Close the current package, if any.
+  this->EndPackage();
+  
+  // Open this package.
+  m_Package = command;
+  
+  // Save the package's opening namespace depth for later verification
+  // on the end of the package.
+  m_PackageNamespaceDepth = m_NamespaceStack.size();
 }
 
 
 /**
- * Get the OutputFile for the file with the given name.  Automatically
- * maintains first and last referencing commands.
+ * End a package definition.
  */
-cmCableData::OutputFile*
-cmCableData::GetOutputFile(const std::string& name,
-                           const cmCableCommand* command)
+void cmCableData::EndPackage()
 {
-  OutputFiles::iterator f = m_OutputFiles.find(name);
-  // If the file hasn't yet been opened, create an entry for it.
-  if(f == m_OutputFiles.end())
+  // Make sure we have an open package.
+  if(!m_Package)
     {
-    OutputFile* outputFile = new OutputFile(name, command);
-    m_OutputFiles[name] = outputFile;
-    
-    return outputFile;
+    return;
     }
   
-  // The file has already been opened.  Set the command as the last
-  // referencing command.
-  f->second->SetLastReferencingCommand(command);
+  // Make sure the namespace nesting depth matches the opening depth
+  // of the package.
+  if(m_PackageNamespaceDepth != m_NamespaceStack.size())
+    {
+    cmSystemTools::Error("Package ended at different namespace depth than"
+                         "it was created!", "");
+    }
+  // Write out the package's footer.
+  m_Package->WritePackageFooter();
   
-  return f->second;
+  // Done with the package.
+  m_Package = NULL;
+}
+
+
+/**
+ * Simplify indentation printing by allowing Indentation objects to be added
+ * to streams.
+ */
+std::ostream& operator<<(std::ostream& os,
+                         const cmCableData::Indentation& indent)
+{  
+  indent.Print(os);
+  return os;
 }
 

+ 52 - 24
Source/cmCableData.h

@@ -20,6 +20,7 @@
 #include "cmCommand.h"
 
 class cmCableCommand;
+class cmCablePackageCommand;
 
 /** \class cmCableData
  * \brief Hold data in one location for all cmCableCommand subclasses.
@@ -27,12 +28,7 @@ class cmCableCommand;
 class cmCableData
 {
 public:
-  /**
-   * The cmCableData instance is owned by one cmCableCommand, which is given
-   * to this constructor.
-   */
-  cmCableData(const cmCableCommand* owner): m_Owner(owner) {}
-  
+  cmCableData(const cmCableCommand*);
   ~cmCableData();
   
   /**
@@ -41,41 +37,73 @@ public:
    */
   bool OwnerIs(const cmCableCommand* owner) const
     { return (owner == m_Owner); }  
+
+  std::ostream& GetOutputStream()
+    { return m_OutputFile; }
+
+  void OpenOutputFile(const std::string&);
+  void CloseOutputFile();
+  
+  void WriteConfigurationHeader();
+  void WriteConfigurationFooter();
   
   /**
-   * Hold an output stream for all commands that use it.  Maintain the
-   * first and last commands that reference it so that they can write the
-   * header/footer lines, if necessary.
+   * Class to simplify indentation printing.
    */
-  class OutputFile
+  class Indentation
   {
   public:
-    OutputFile(std::string, const cmCableCommand*);
-    ~OutputFile();
-    std::ostream& GetStream();
-    void SetLastReferencingCommand(const cmCableCommand*);
-    bool FirstReferencingCommandIs(const cmCableCommand*) const;
-    bool LastReferencingCommandIs(const cmCableCommand*) const;
+    Indentation(int indent): m_Indent(indent) {}
+    void Print(std::ostream& os) const;
+    Indentation Next() const { return Indentation(m_Indent+2); }
+    Indentation Previous() const { return Indentation(m_Indent-2); }
   private:
-    std::ofstream m_FileStream;
-    const cmCableCommand* m_FirstReferencingCommand;
-    const cmCableCommand* m_LastReferencingCommand;
+    int m_Indent;
   };
   
-  OutputFile* GetOutputFile(const std::string&, const cmCableCommand*);
+  void Indent() { m_Indentation = m_Indentation.Next(); }
+  void Unindent() { m_Indentation = m_Indentation.Previous(); }
+  const Indentation& GetIndentation() const { return m_Indentation; }
   
-private:
-  typedef std::map<std::string, OutputFile*>  OutputFiles;
+  void OpenNamespace(const std::string&);
+  void CloseNamespace(const std::string&);
+
+  void BeginPackage(cmCablePackageCommand*);
+  void EndPackage();
   
+private:
   /**
    * The cmCableCommand which created this instance of cmCableCommand.
    */
   const cmCableCommand* m_Owner;
   
   /**
-   * Hold all output streams by file name.
+   * Current indentation for output.
+   */
+  Indentation m_Indentation;
+  
+  /**
+   * The output file to which the configuration is written.
+   */
+  std::ofstream m_OutputFile;
+  
+  /**
+   * The stack of namespaces.
    */
-  OutputFiles m_OutputFiles;  
+  std::list<std::string>  m_NamespaceStack;
+  
+  /**
+   * The command that created the package currently being defined.
+   */
+  cmCablePackageCommand*  m_Package;
+  
+  /**
+   * The namespace level at which the current package was created.
+   * This must be the level when the package is ended.
+   */
+  unsigned int m_PackageNamespaceDepth;
 };
 
+std::ostream& operator<<(std::ostream&, const cmCableData::Indentation&);
+
 #endif

+ 15 - 4
Source/cmCableDefineSetCommand.cxx

@@ -28,6 +28,9 @@ bool cmCableDefineSetCommand::Invoke(std::vector<std::string>& args)
     return false;
     }
   
+  // This command needs access to the Cable data.
+  this->SetupCableData();
+  
   std::vector<std::string>::const_iterator arg = args.begin();
   
   // The first argument is the name of the set.
@@ -39,6 +42,9 @@ bool cmCableDefineSetCommand::Invoke(std::vector<std::string>& args)
     m_Elements.push_back(Element(this->GenerateTag(*arg), *arg));
     }
   
+  // Write this command's configuration output.
+  this->WriteConfiguration();
+  
   return true;
 }
 
@@ -46,15 +52,20 @@ bool cmCableDefineSetCommand::Invoke(std::vector<std::string>& args)
 /**
  * Write the CABLE configuration code to define this Set.
  */
-void cmCableDefineSetCommand::WriteConfiguration(std::ostream& os) const
+void cmCableDefineSetCommand::WriteConfiguration() const
 {
   cmRegularExpression needCdataBlock("[&<>]");
   
-  os << "  <Set name=\"" << m_SetName.c_str() << "\">" << std::endl;
+  // Get the ouptut information from the cmCableData.
+  std::ostream& os = m_CableData->GetOutputStream();
+  cmCableData::Indentation indent = m_CableData->GetIndentation();
+  
+  // Output the code.
+  os << indent << "<Set name=\"" << m_SetName.c_str() << "\">" << std::endl;
   for(Elements::const_iterator e = m_Elements.begin();
       e != m_Elements.end(); ++e)
     {
-    os << "    <Element";
+    os << indent << "  <Element";
     // Only output the tag if it is not the empty string.
     if(e->first.length() > 0)
       {
@@ -71,7 +82,7 @@ void cmCableDefineSetCommand::WriteConfiguration(std::ostream& os) const
       }
     os << "</Element>" << std::endl;
     }
-  os << "  </Set>" << std::endl;
+  os << indent << "</Set>" << std::endl;
 }
 
 

+ 2 - 4
Source/cmCableDefineSetCommand.h

@@ -48,7 +48,7 @@ public:
    * to makefiles located in subdirectories.
    */
   virtual bool IsInherited() 
-    {return true;}
+    { return true; }
 
   /**
    * The name of the command as specified in CMakeList.txt.
@@ -75,13 +75,11 @@ public:
       "commands by a '$' immediately followed by the set name (ex. $SetName).";
     }
 
-  virtual void WriteConfiguration(std::ostream&) const;
-  
   cmTypeMacro(cmCableDefineSetCommand, cmCableCommand);
   
 private:
+  void WriteConfiguration() const;
   std::string GenerateTag(const std::string&) const;
-
 private:  
   typedef std::pair<std::string, std::string>  Element;
   typedef std::vector<Element>  Elements;

+ 9 - 7
Source/cmCableInstantiateClassCommand.cxx

@@ -23,16 +23,18 @@
  * Write the CABLE configuration code to define this InstantiationSet.
  * This includes the "class" keyword to do class template instantiations.
  */
-void cmCableInstantiateClassCommand::WriteConfiguration(std::ostream& os) const
+void cmCableInstantiateClassCommand::WriteConfiguration() const
 {
+  std::ostream& os = m_CableData->GetOutputStream();
+  cmCableData::Indentation indent = m_CableData->GetIndentation();
+
   cmRegularExpression needCdataBlock("[&<>]");
   
-  os << std::endl
-     << "  <InstantiationSet>" << std::endl;
-  for(Elements::const_iterator e = m_Elements.begin();
-      e != m_Elements.end(); ++e)
+  os << indent << "<InstantiationSet>" << std::endl;
+  for(Entries::const_iterator e = m_Entries.begin();
+      e != m_Entries.end(); ++e)
     {
-    os << "    <Element>class ";
+    os << indent << "  <Element>class ";
     if(needCdataBlock.find(e->c_str()))
       {
       os << "<![CDATA[" << e->c_str() << "]]>";
@@ -43,5 +45,5 @@ void cmCableInstantiateClassCommand::WriteConfiguration(std::ostream& os) const
       }
     os << "</Element>" << std::endl;
     }
-  os << "  </InstantiationSet>" << std::endl;
+  os << indent << "</InstantiationSet>" << std::endl;
 }

+ 6 - 6
Source/cmCableInstantiateClassCommand.h

@@ -17,7 +17,7 @@
 #define cmCableInstantiateClassCommand_h
 
 #include "cmStandardIncludes.h"
-#include "cmCableInstantiateCommand.h"
+#include "cmCablePackageEntryCommand.h"
 
 /** \class cmCableInstantiateClassCommand
  * \brief Define a command that generates a rule for explicit template
@@ -27,7 +27,7 @@
  * configuration file to create explicit template instantiations of
  * classes.
  */
-class cmCableInstantiateClassCommand : public cmCableInstantiateCommand
+class cmCableInstantiateClassCommand : public cmCablePackageEntryCommand
 {
 public:
   /**
@@ -48,7 +48,7 @@ public:
    */
   virtual const char* GetTerseDocumentation() 
     {
-    return "Define CABLE InstantiationSet of classes.";
+    return "Define CABLE InstantiationSet of classes in a package.";
     }
   
   /**
@@ -57,17 +57,17 @@ public:
   virtual const char* GetFullDocumentation()
     {
     return
-      "CABLE_INSTANTIATE_CLASS(cable_config_file member1 member2 ...)\n"
+      "CABLE_INSTANTIATE_CLASS(package_name member1 member2 ...)\n"
       "Generates an InstantiationSet in the CABLE configuration.  It is\n"
       "assumed that all members of the set are explicit instantiations of\n"
       "template classes (not functions, operators, etc).";
     }
 
-  virtual void WriteConfiguration(std::ostream&) const;  
+  virtual void WriteConfiguration() const;  
 
   cmTypeMacro(cmCableInstantiateClassCommand, cmCableInstantiateCommand);
 protected:
-  typedef cmCableInstantiateCommand::Elements  Elements;
+  typedef cmCablePackageEntryCommand::Entries  Entries;
 };
 
 

+ 9 - 81
Source/cmCableInstantiateCommand.cxx

@@ -16,96 +16,24 @@
 #include "cmCableInstantiateCommand.h"
 #include "cmCacheManager.h"
 
-#include "cmCableDefineSetCommand.h"
 #include "cmRegularExpression.h"
 
-// cmCableInstantiateCommand
-bool cmCableInstantiateCommand::Invoke(std::vector<std::string>& args)
-{
-  if(args.size() < 2)
-    {
-    this->SetError("called with incorrect number of arguments");
-    return false;
-    }
-  
-  // This command instance needs to use the cmCableData instance.
-  this->SetupCableData();
-  
-  // The output file must be opened in the output directory.
-  std::string file = m_Makefile->GetStartOutputDirectory();
-  
-  // The first argument is the file into which the configuration code is to be
-  // written.
-  std::vector<std::string>::const_iterator arg = args.begin();
-
-  // Concatenate the file name onto the path.
-  file += "/" + *arg++;
-  
-  // Get the OutputFile corresponding to this file name.
-  m_OutputFile = m_CableData->GetOutputFile(file, this);
-  
-  // The rest of the arguments are the elements to be placed in the set.
-  for(; arg != args.end(); ++arg)
-    {
-    m_Elements.push_back(*arg);
-    }  
-  
-  return true;
-}
-
-
-void cmCableInstantiateCommand::FinalPass()
-{
-  // If this command is the first to reference its output file, write the
-  // header information.
-  if(m_OutputFile->FirstReferencingCommandIs(this))
-    {
-    this->WriteConfigurationHeader(m_OutputFile->GetStream());
-    
-    // Need to write out the Set definitions.
-    // Look through the vector of commands from the makefile.
-    const std::vector<cmCommand*>& usedCommands =
-      m_Makefile->GetUsedCommands();  
-    for(std::vector<cmCommand*>::const_iterator commandIter =
-          usedCommands.begin();
-        commandIter != usedCommands.end(); ++commandIter)
-      {
-      // If this command is a cmCableDefineSetCommand, ask it to write its
-      // configuration code to the output file.
-      cmCableDefineSetCommand* command =
-        cmCableDefineSetCommand::SafeDownCast(*commandIter);
-      if(command)
-        {
-        command->WriteConfiguration(m_OutputFile->GetStream());
-        }
-      }
-    }  
-  
-  // Write the instantiation block's code.
-  this->WriteConfiguration(m_OutputFile->GetStream());
-  
-  // If this command is the last to reference its output file, write the
-  // footer information.
-  if(m_OutputFile->LastReferencingCommandIs(this))
-    {
-    this->WriteConfigurationFooter(m_OutputFile->GetStream());
-    }
-}
-
 
 /**
  * Write the CABLE configuration code to define this InstantiationSet.
  */
-void cmCableInstantiateCommand::WriteConfiguration(std::ostream& os) const
+void cmCableInstantiateCommand::WriteConfiguration() const
 {
+  std::ostream& os = m_CableData->GetOutputStream();
+  cmCableData::Indentation indent = m_CableData->GetIndentation();
+
   cmRegularExpression needCdataBlock("[&<>]");
   
-  os << std::endl
-     << "  <InstantiationSet>" << std::endl;
-  for(Elements::const_iterator e = m_Elements.begin();
-      e != m_Elements.end(); ++e)
+  os << indent << "<InstantiationSet>" << std::endl;
+  for(Entries::const_iterator e = m_Entries.begin();
+      e != m_Entries.end(); ++e)
     {
-    os << "    <Element>";
+    os << indent << "  <Element>";
     if(needCdataBlock.find(e->c_str()))
       {
       os << "<![CDATA[" << e->c_str() << "]]>";
@@ -116,5 +44,5 @@ void cmCableInstantiateCommand::WriteConfiguration(std::ostream& os) const
       }
     os << "</Element>" << std::endl;
     }
-  os << "  </InstantiationSet>" << std::endl;
+  os << indent << "</InstantiationSet>" << std::endl;
 }

+ 7 - 35
Source/cmCableInstantiateCommand.h

@@ -17,7 +17,7 @@
 #define cmCableInstantiateCommand_h
 
 #include "cmStandardIncludes.h"
-#include "cmCableCommand.h"
+#include "cmCablePackageEntryCommand.h"
 
 /** \class cmCableInstantiateCommand
  * \brief Define a command that generates a rule for explicit template
@@ -26,7 +26,7 @@
  * cmCableInstantiateCommand is used to generate a rule in a CABLE
  * configuration file to create explicit template instantiations.
  */
-class cmCableInstantiateCommand : public cmCableCommand
+class cmCableInstantiateCommand : public cmCablePackageEntryCommand
 {
 public:
   /**
@@ -37,24 +37,6 @@ public:
     return new cmCableInstantiateCommand;
     }
 
-  /**
-   * This is called when the command is first encountered in
-   * the CMakeLists.txt file.
-   */
-  virtual bool Invoke(std::vector<std::string>& args);
-  
-  /**
-   * This is called after all input commands have been processed.
-   */
-  virtual void FinalPass();
-
-  /**
-   * This determines if the command gets propagated down
-   * to makefiles located in subdirectories.
-   */
-  virtual bool IsInherited() 
-    {return true;}
-
   /**
    * The name of the command as specified in CMakeList.txt.
    */
@@ -65,7 +47,7 @@ public:
    */
   virtual const char* GetTerseDocumentation() 
     {
-    return "Define CABLE InstantiationSet.";
+    return "Define CABLE InstantiationSet in a package.";
     }
   
   /**
@@ -74,27 +56,17 @@ public:
   virtual const char* GetFullDocumentation()
     {
     return
-      "CABLE_INSTANTIATE(cable_config_file member1 member2 ...)\n"
+      "CABLE_INSTANTIATE(member1 member2 ...)\n"
       "Generates an InstantiationSet in the CABLE configuration.  It is\n"
       "assumed that all members of the set are explicit instantiations of\n"
       "template non-classes (functions, operators, etc).";
     }
 
-  virtual void WriteConfiguration(std::ostream&) const;  
+  virtual void WriteConfiguration() const;  
 
-  cmTypeMacro(cmCableInstantiateCommand, cmCableCommand);
+  cmTypeMacro(cmCableInstantiateCommand, cmCablePackageCommand);
 protected:
-  typedef std::vector<std::string>  Elements;
-  
-  /**
-   * The output file to which to write the configuration.
-   */
-  cmCableData::OutputFile* m_OutputFile;
-
-  /**
-   * The elements describing the set of instantiations.
-   */
-  Elements m_Elements;
+  typedef cmCablePackageEntryCommand::Entries  Entries;
 };
 
 

+ 55 - 0
Source/cmCableOpenNamespaceCommand.cxx

@@ -0,0 +1,55 @@
+/*=========================================================================
+
+  Program:   Insight Segmentation & Registration Toolkit
+  Module:    $RCSfile$
+  Language:  C++
+  Date:      $Date$
+  Version:   $Revision$
+
+
+  Copyright (c) 2000 National Library of Medicine
+  All rights reserved.
+
+  See COPYRIGHT.txt for copyright details.
+
+=========================================================================*/
+#include "cmCableOpenNamespaceCommand.h"
+#include "cmCacheManager.h"
+
+
+// cmCableOpenNamespaceCommand
+bool cmCableOpenNamespaceCommand::Invoke(std::vector<std::string>& args)
+{
+  if(args.size() != 1)
+    {
+    this->SetError("called with incorrect number of arguments");
+    return false;
+    }
+  
+  // This command needs to access the Cable data.
+  this->SetupCableData();
+  
+  // The argument is the namespace name.
+  m_NamespaceName = args[0];
+  
+  // Write the configuration for this command.
+  this->WriteNamespaceHeader();
+  
+  // Ask the cable data to open the namespace.
+  m_CableData->OpenNamespace(m_NamespaceName);
+  
+  return true;
+}
+
+
+/**
+ * Generate a CABLE Namespace open tag.
+ */
+void cmCableOpenNamespaceCommand::WriteNamespaceHeader() const
+{
+  std::ostream& os = m_CableData->GetOutputStream();
+  cmCableData::Indentation indent = m_CableData->GetIndentation();
+  os << indent << "<Namespace name=\"" << m_NamespaceName.c_str()
+     << "\">" << std::endl;
+  m_CableData->Indent();
+}

+ 89 - 0
Source/cmCableOpenNamespaceCommand.h

@@ -0,0 +1,89 @@
+/*=========================================================================
+
+  Program:   Insight Segmentation & Registration Toolkit
+  Module:    $RCSfile$
+  Language:  C++
+  Date:      $Date$
+  Version:   $Revision$
+
+
+  Copyright (c) 2000 National Library of Medicine
+  All rights reserved.
+
+  See COPYRIGHT.txt for copyright details.
+
+=========================================================================*/
+#ifndef cmCableOpenNamespaceCommand_h
+#define cmCableOpenNamespaceCommand_h
+
+#include "cmStandardIncludes.h"
+#include "cmCableCommand.h"
+
+/** \class cmCableOpenNamespaceCommand
+ * \brief Define a command that opens a CABLE Namespace.
+ *
+ * cmCableOpenNamespaceCommand is used to generate CABLE Namespace
+ * open tags in the configuration file.
+ */
+class cmCableOpenNamespaceCommand : public cmCableCommand
+{
+public:
+  /**
+   * This is a virtual constructor for the command.
+   */
+  virtual cmCommand* Clone()
+    {
+      return new cmCableOpenNamespaceCommand;
+    }
+
+  /**
+   * This is called when the command is first encountered in
+   * the CMakeLists.txt file.
+   */
+  virtual bool Invoke(std::vector<std::string>& args);
+  
+  /**
+   * This determines if the command gets propagated down
+   * to makefiles located in subdirectories.
+   */
+  virtual bool IsInherited() 
+    {return true;}
+
+  /**
+   * The name of the command as specified in CMakeList.txt.
+   */
+  virtual const char* GetName() { return "CABLE_OPEN_NAMESPACE";}
+
+  /**
+   * Succinct documentation.
+   */
+  virtual const char* GetTerseDocumentation() 
+    {
+    return "Open a CABLE Namespace";
+    }
+  
+  /**
+   * More documentation.
+   */
+  virtual const char* GetFullDocumentation()
+    {
+    return
+      "CABLE_OPEN_NAMESPACE(namespace_name)\n"
+      "Open the given namespace in the generated configuration file.\n"
+      "There must be a matching CABLE_CLOSE_NAMESPACE(namespace_name)\n"
+      "called with the same name.";
+    }
+
+  cmTypeMacro(cmCableOpenNamespaceCommand, cmCableCommand);
+private:
+  void WriteNamespaceHeader() const;
+private:
+  /**
+   * The name of the namespace to setup.
+   */
+  std::string m_NamespaceName;
+};
+
+
+
+#endif

+ 70 - 0
Source/cmCablePackageCommand.cxx

@@ -0,0 +1,70 @@
+/*=========================================================================
+
+  Program:   Insight Segmentation & Registration Toolkit
+  Module:    $RCSfile$
+  Language:  C++
+  Date:      $Date$
+  Version:   $Revision$
+
+
+  Copyright (c) 2000 National Library of Medicine
+  All rights reserved.
+
+  See COPYRIGHT.txt for copyright details.
+
+=========================================================================*/
+#include "cmCablePackageCommand.h"
+#include "cmCacheManager.h"
+
+// cmCablePackageCommand
+bool cmCablePackageCommand::Invoke(std::vector<std::string>& args)
+{
+  if(args.size() != 1)
+    {
+    this->SetError("called with incorrect number of arguments");
+    return false;
+    }
+  
+  // This command needs to access the Cable data.
+  this->SetupCableData();
+  
+  // The argument is the package name.
+  m_PackageName = args[0];
+  
+  // Ask the cable data to begin the package.  This may call another
+  // cmCablePackageCommand's WritePackageFooter().
+  m_CableData->BeginPackage(this);
+  
+  // Write the configuration for this command.
+  // The cmCableData::EndPackage() later on will call WritePackageFooter().
+  this->WritePackageHeader();
+  
+  return true;
+}
+
+
+/**
+ * Write a CABLE package header.
+ */
+void cmCablePackageCommand::WritePackageHeader() const
+{
+  std::ostream& os = m_CableData->GetOutputStream();
+  cmCableData::Indentation indent = m_CableData->GetIndentation();
+  os << indent << "<Package name=\"" << m_PackageName.c_str() << "\">"
+     << std::endl;
+  m_CableData->Indent();
+}
+
+
+/**
+ * Write a CABLE package footer.
+ */
+void cmCablePackageCommand::WritePackageFooter() const
+{
+  m_CableData->Unindent();
+  std::ostream& os = m_CableData->GetOutputStream();
+  cmCableData::Indentation indent = m_CableData->GetIndentation();
+  os << indent << "</Package> <!-- \"" << m_PackageName.c_str() << "\" -->"
+     << std::endl;
+}
+

+ 85 - 0
Source/cmCablePackageCommand.h

@@ -0,0 +1,85 @@
+/*=========================================================================
+
+  Program:   Insight Segmentation & Registration Toolkit
+  Module:    $RCSfile$
+  Language:  C++
+  Date:      $Date$
+  Version:   $Revision$
+
+
+  Copyright (c) 2000 National Library of Medicine
+  All rights reserved.
+
+  See COPYRIGHT.txt for copyright details.
+
+=========================================================================*/
+#ifndef cmCablePackageCommand_h
+#define cmCablePackageCommand_h
+
+#include "cmStandardIncludes.h"
+#include "cmCableCommand.h"
+
+/** \class cmCablePackageCommand
+ * \brief Define a command that begins a CABLE Package definition.
+ *
+ * cmCablePackageCommand is used to generate a new CABLE Package.
+ * All subsequent commands that require a package will refer to that
+ * setup by this command, until another package is started.
+ */
+class cmCablePackageCommand : public cmCableCommand
+{
+public:
+  cmCablePackageCommand() {}
+  virtual ~cmCablePackageCommand() {}
+
+  /**
+   * This is a virtual constructor for the command.
+   */
+  virtual cmCommand* Clone()
+    {
+      return new cmCablePackageCommand;
+    }
+
+  /**
+   * This is called when the command is first encountered in
+   * the CMakeLists.txt file.
+   */
+  virtual bool Invoke(std::vector<std::string>& args);  
+
+  /**
+   * The name of the command as specified in CMakeList.txt.
+   */
+  virtual const char* GetName() { return "CABLE_PACKAGE";}
+
+  /**
+   * Succinct documentation.
+   */
+  virtual const char* GetTerseDocumentation() 
+    {
+    return "Begin a package definition.";
+    }
+  
+  /**
+   * More documentation.
+   */
+  virtual const char* GetFullDocumentation()
+    {
+    return
+      "CABLE_PACKAGE(package_name)\n"
+      "Close current package (if any), and open a new package definition.";
+    }  
+
+  void WritePackageHeader() const;
+  void WritePackageFooter() const;  
+  
+  cmTypeMacro(cmCablePackageCommand, cmCableCommand);
+private:
+  /**
+   * The name of the package.
+   */
+  std::string m_PackageName;  
+};
+
+
+
+#endif

+ 42 - 0
Source/cmCablePackageEntryCommand.cxx

@@ -0,0 +1,42 @@
+/*=========================================================================
+
+  Program:   Insight Segmentation & Registration Toolkit
+  Module:    $RCSfile$
+  Language:  C++
+  Date:      $Date$
+  Version:   $Revision$
+
+
+  Copyright (c) 2000 National Library of Medicine
+  All rights reserved.
+
+  See COPYRIGHT.txt for copyright details.
+
+=========================================================================*/
+#include "cmCablePackageEntryCommand.h"
+#include "cmCacheManager.h"
+
+// cmCablePackageEntryCommand
+bool cmCablePackageEntryCommand::Invoke(std::vector<std::string>& args)
+{
+  if(args.size() < 1)
+    {
+    this->SetError("called with incorrect number of arguments");
+    return false;
+    }
+  
+  // This command instance needs to use the cmCableData instance.
+  this->SetupCableData();
+  
+  // The arguments are the entries to the Pacakge.
+  for(std::vector<std::string>::const_iterator arg = args.begin();
+      arg != args.end(); ++arg)
+    {
+    m_Entries.push_back(*arg);
+    }  
+  
+  // Write this command's configuration.
+  this->WriteConfiguration();
+  
+  return true;
+}

+ 57 - 0
Source/cmCablePackageEntryCommand.h

@@ -0,0 +1,57 @@
+/*=========================================================================
+
+  Program:   Insight Segmentation & Registration Toolkit
+  Module:    $RCSfile$
+  Language:  C++
+  Date:      $Date$
+  Version:   $Revision$
+
+
+  Copyright (c) 2000 National Library of Medicine
+  All rights reserved.
+
+  See COPYRIGHT.txt for copyright details.
+
+=========================================================================*/
+#ifndef cmCablePackageEntryCommand_h
+#define cmCablePackageEntryCommand_h
+
+#include "cmStandardIncludes.h"
+#include "cmCableCommand.h"
+
+/** \class cmCablePackageEntryCommand
+ * \brief Superclass to all CABLE Package entry generation commands.
+ *
+ * cmCablePackageEntryCommand implements the Invoke method of a cmCommand
+ * to save the arguments as a vector of entries to a CABLE Package.  The
+ * Invoke then calls the virtual WriteConfiguration() so that the subclass
+ * can generate the configuration code for its particular type of Package
+ * entry.
+ */
+class cmCablePackageEntryCommand : public cmCableCommand
+{
+public:
+  cmCablePackageEntryCommand() {}
+  virtual ~cmCablePackageEntryCommand() {}
+  
+  /**
+   * This is called when the command is first encountered in
+   * the CMakeLists.txt file.
+   */
+  virtual bool Invoke(std::vector<std::string>& args);  
+
+  cmTypeMacro(cmCablePackageEntryCommand, cmCableCommand);
+
+  virtual void WriteConfiguration() const =0;
+protected:
+  typedef std::vector<std::string>  Entries;
+  
+  /**
+   * The package entries.
+   */
+  Entries m_Entries;
+};
+
+
+
+#endif

+ 37 - 0
Source/cmCableSourceFilesCommand.cxx

@@ -0,0 +1,37 @@
+/*=========================================================================
+
+  Program:   Insight Segmentation & Registration Toolkit
+  Module:    $RCSfile$
+  Language:  C++
+  Date:      $Date$
+  Version:   $Revision$
+
+
+  Copyright (c) 2000 National Library of Medicine
+  All rights reserved.
+
+  See COPYRIGHT.txt for copyright details.
+
+=========================================================================*/
+#include "cmCableSourceFilesCommand.h"
+#include "cmCacheManager.h"
+
+/**
+ * Write the CABLE configuration code to indicate header dependencies for
+ * a package.
+ */
+void cmCableSourceFilesCommand::WriteConfiguration() const
+{
+  std::ostream& os = m_CableData->GetOutputStream();
+  cmCableData::Indentation indent = m_CableData->GetIndentation();
+  
+  cmRegularExpression needCdataBlock("[&<>]");
+  
+  os << indent << "<Headers>" << std::endl;
+  for(Entries::const_iterator f = m_Entries.begin();
+      f != m_Entries.end(); ++f)
+    {
+    os << indent << "  <File name=\"" << f->c_str() << ".h\"/>" << std::endl;
+    }
+  os << indent << "</Headers>" << std::endl;
+}

+ 71 - 0
Source/cmCableSourceFilesCommand.h

@@ -0,0 +1,71 @@
+/*=========================================================================
+
+  Program:   Insight Segmentation & Registration Toolkit
+  Module:    $RCSfile$
+  Language:  C++
+  Date:      $Date$
+  Version:   $Revision$
+
+
+  Copyright (c) 2000 National Library of Medicine
+  All rights reserved.
+
+  See COPYRIGHT.txt for copyright details.
+
+=========================================================================*/
+#ifndef cmCableSourceFilesCommand_h
+#define cmCableSourceFilesCommand_h
+
+#include "cmStandardIncludes.h"
+#include "cmCablePackageEntryCommand.h"
+
+/** \class cmCableSourceFilesCommand
+ * \brief Define a command that generates a rule for a CABLE Headers block.
+ *
+ * cmCableSourceFilesCommand is used to generate a rule in a CABLE
+ * configuration file to setup a Package's include files.
+ */
+class cmCableSourceFilesCommand : public cmCablePackageEntryCommand
+{
+public:
+  /**
+   * This is a virtual constructor for the command.
+   */
+  virtual cmCommand* Clone() 
+    {
+    return new cmCableSourceFilesCommand;
+    }
+
+  /**
+   * The name of the command as specified in CMakeList.txt.
+   */
+  virtual const char* GetName() { return "CABLE_SOURCE_FILES";}
+
+  /**
+   * Succinct documentation.
+   */
+  virtual const char* GetTerseDocumentation() 
+    {
+    return "Define CABLE header file dependencies in a package.";
+    }
+  
+  /**
+   * More documentation.
+   */
+  virtual const char* GetFullDocumentation()
+    {
+    return
+      "CABLE_SOURCE_FILES(file1 file2 ...)"
+      "Generates a Package's Headers block in the CABLE configuration.";
+    }
+
+  virtual void WriteConfiguration() const;
+
+  cmTypeMacro(cmCableSourceFilesCommand, cmCableCommand);
+protected:
+  typedef cmCablePackageEntryCommand::Entries  Entries;
+};
+
+
+
+#endif

+ 45 - 0
Source/cmCableWrapCommand.cxx

@@ -0,0 +1,45 @@
+/*=========================================================================
+
+  Program:   Insight Segmentation & Registration Toolkit
+  Module:    $RCSfile$
+  Language:  C++
+  Date:      $Date$
+  Version:   $Revision$
+
+
+  Copyright (c) 2000 National Library of Medicine
+  All rights reserved.
+
+  See COPYRIGHT.txt for copyright details.
+
+=========================================================================*/
+#include "cmCableWrapCommand.h"
+#include "cmCacheManager.h"
+
+/**
+ * Write the CABLE configuration code to define this WrapperSet.
+ */
+void cmCableWrapCommand::WriteConfiguration() const
+{
+  std::ostream& os = m_CableData->GetOutputStream();
+  cmCableData::Indentation indent = m_CableData->GetIndentation();
+  
+  cmRegularExpression needCdataBlock("[&<>]");
+  
+  os << indent << "<WrapperSet>" << std::endl;
+  for(Entries::const_iterator e = m_Entries.begin();
+      e != m_Entries.end(); ++e)
+    {
+    os << indent << "  <Element>";
+    if(needCdataBlock.find(e->c_str()))
+      {
+      os << "<![CDATA[" << e->c_str() << "]]>";
+      }
+    else
+      {
+      os << e->c_str();
+      }
+    os << "</Element>" << std::endl;
+    }
+  os << indent << "</WrapperSet>" << std::endl;
+}

+ 69 - 0
Source/cmCableWrapCommand.h

@@ -0,0 +1,69 @@
+/*=========================================================================
+
+  Program:   Insight Segmentation & Registration Toolkit
+  Module:    $RCSfile$
+  Language:  C++
+  Date:      $Date$
+  Version:   $Revision$
+
+
+  Copyright (c) 2000 National Library of Medicine
+  All rights reserved.
+
+  See COPYRIGHT.txt for copyright details.
+
+=========================================================================*/
+#ifndef cmCableWrapCommand_h
+#define cmCableWrapCommand_h
+
+#include "cmStandardIncludes.h"
+#include "cmCablePackageEntryCommand.h"
+
+/** \class cmCableWrapCommand
+ * \brief Define a command that generates a rule for CABLE-generated wrappers.
+ *
+ * cmCableWrapCommand is used to generate a rule in a CABLE
+ * configuration file to create type wrappers.
+ */
+class cmCableWrapCommand : public cmCablePackageEntryCommand
+{
+public:
+  /**
+   * This is a virtual constructor for the command.
+   */
+  virtual cmCommand* Clone() 
+    {
+    return new cmCableWrapCommand;
+    }
+
+  /**
+   * The name of the command as specified in CMakeList.txt.
+   */
+  virtual const char* GetName() { return "CABLE_WRAP";}
+
+  /**
+   * Succinct documentation.
+   */
+  virtual const char* GetTerseDocumentation() 
+    {
+    return "Define CABLE WrapSet in a package.";
+    }
+  
+  /**
+   * More documentation.
+   */
+  virtual const char* GetFullDocumentation()
+    {
+    return
+      "CABLE_WRAP(member1 member2 ...)\n"
+      "Generates a WrapSet in the CABLE configuration.";
+    }
+
+  virtual void WriteConfiguration() const;
+  
+  cmTypeMacro(cmCableWrapCommand, cmCablePackageCommand);
+};
+
+
+
+#endif

+ 11 - 0
Source/cmCommands.cxx

@@ -27,6 +27,12 @@
 #include "cmCableCommand.cxx"
 #include "cmCableData.cxx"
 #include "cmCableDefineSetCommand.cxx"
+#include "cmCableOpenNamespaceCommand.cxx"
+#include "cmCableCloseNamespaceCommand.cxx"
+#include "cmCablePackageCommand.cxx"
+#include "cmCablePackageEntryCommand.cxx"
+#include "cmCableSourceFilesCommand.cxx"
+#include "cmCableWrapCommand.cxx"
 #include "cmCableInstantiateCommand.cxx"
 #include "cmCableInstantiateClassCommand.cxx"
 #include "cmFindFileCommand.cxx"
@@ -58,6 +64,11 @@ void GetPredefinedCommands(std::list<cmCommand*>& commands)
   commands.push_back(new cmWin32LibrariesCommand);
   commands.push_back(new cmConfigureFileNoAutoconf);
   commands.push_back(new cmCableDefineSetCommand);
+  commands.push_back(new cmCableOpenNamespaceCommand);
+  commands.push_back(new cmCableCloseNamespaceCommand);
+  commands.push_back(new cmCablePackageCommand);
+  commands.push_back(new cmCableSourceFilesCommand);
+  commands.push_back(new cmCableWrapCommand);
   commands.push_back(new cmCableInstantiateCommand);
   commands.push_back(new cmCableInstantiateClassCommand);
   commands.push_back(new cmFindFileCommand);