From 1f55680332c133fddce4a0b85cfb7ee1a20cff75 Mon Sep 17 00:00:00 2001
From: Brad King <brad.king@kitware.com>
Date: Fri, 14 Feb 2003 10:53:37 -0500
Subject: ENH: Added cmDocumentation class to generate various forms of
 documentation.  Each executable will be able to generate its own
 documentation.

---
 Source/CMakeLists.txt          |   1 +
 Source/CursesDialog/ccmake.cxx |  35 +++
 Source/Makefile.in             |   1 +
 Source/cmDocumentation.cxx     | 478 +++++++++++++++++++++++++++++++++++++++++
 Source/cmDocumentation.h       |  65 ++++++
 Source/cmStandardIncludes.h    |   8 +
 Source/cmSystemTools.cxx       |   9 +
 Source/cmSystemTools.h         |   2 +
 Source/cmake.cxx               |  17 ++
 Source/cmake.h                 |   2 +
 Source/cmakemain.cxx           |  54 ++++-
 11 files changed, 663 insertions(+), 9 deletions(-)
 create mode 100644 Source/cmDocumentation.cxx
 create mode 100644 Source/cmDocumentation.h

diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index 0c83d53..fd9d006 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -9,6 +9,7 @@ cmRegularExpression.cxx
 cmSourceFile.cxx
 cmSystemTools.cxx
 cmDirectory.cxx
+cmDocumentation.cxx
 cmDynamicLoader.cxx
 cmCommands.cxx
 cmTarget.cxx
diff --git a/Source/CursesDialog/ccmake.cxx b/Source/CursesDialog/ccmake.cxx
index 8cd2ccb..47ae7ee 100644
--- a/Source/CursesDialog/ccmake.cxx
+++ b/Source/CursesDialog/ccmake.cxx
@@ -17,6 +17,7 @@
 #include "../cmCacheManager.h"
 #include "../cmSystemTools.h"
 #include "../cmake.h"
+#include "../cmDocumentation.h"
 
 #include <signal.h>
 #include <sys/ioctl.h>
@@ -26,6 +27,30 @@
 #include <curses.h>
 #include <form.h>
 
+//----------------------------------------------------------------------------
+static const cmDocumentationEntry cmDocumentationName[] =
+{
+  {"ccmake",
+   "- Curses Interface for CMake.", 0},
+  {0,0,0}
+};
+
+//----------------------------------------------------------------------------
+static const cmDocumentationEntry cmDocumentationUsage[] =
+{
+  {0,
+   "ccmake <path-to-source>", 0},
+  {0,0,0}
+};
+
+//----------------------------------------------------------------------------
+static const cmDocumentationEntry cmDocumentationDescription[] =
+{
+  {0,
+   "CMake reads ... ", 0},
+  {0,0,0}
+};
+
 cmCursesForm* cmCursesForm::CurrentForm=0;
 
 extern "C"
@@ -60,6 +85,16 @@ void CMakeErrorHandler(const char* message, const char* title, bool&, void* clie
 
 int main(int argc, char** argv)
 {
+  cmDocumentation doc;
+  if(cmDocumentation::Type ht = doc.CheckOptions(argc, argv))
+    {
+    doc.SetName(cmDocumentationName);
+    doc.SetUsage(cmDocumentationUsage);
+    doc.SetDescription(cmDocumentationDescription);
+    doc.Print(ht, std::cout);
+    return 0;
+    }  
+  
   bool debug = false;
   unsigned int i;
   int j;
diff --git a/Source/Makefile.in b/Source/Makefile.in
index 1d8bd9a..df42fc3 100644
--- a/Source/Makefile.in
+++ b/Source/Makefile.in
@@ -19,6 +19,7 @@ cmakewizard.o  \
 cmakemain.o \
 cmMakeDepend.o \
 cmMakefile.o \
+cmDocumentation.o \
 cmGlobalGenerator.o \
 cmLocalGenerator.o \
 cmRegularExpression.o \
diff --git a/Source/cmDocumentation.cxx b/Source/cmDocumentation.cxx
new file mode 100644
index 0000000..2532c16
--- /dev/null
+++ b/Source/cmDocumentation.cxx
@@ -0,0 +1,478 @@
+/*=========================================================================
+
+  Program:   CMake - Cross-Platform Makefile Generator
+  Module:    $RCSfile$
+  Language:  C++
+  Date:      $Date$
+  Version:   $Revision$
+
+  Copyright (c) 2002 Kitware, Inc., Insight Consortium.  All rights reserved.
+  See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
+
+     This software is distributed WITHOUT ANY WARRANTY; without even 
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+     PURPOSE.  See the above copyright notices for more information.
+
+=========================================================================*/
+#include "cmDocumentation.h"
+
+#include "cmSystemTools.h"
+
+//----------------------------------------------------------------------------
+static const cmDocumentationEntry cmDocumentationStandardOptions[] =
+{
+  {"--copyright", "Print the CMake copyright and exit.", 0},
+  {"--usage", "Print usage information and exit.",
+   "Usage describes the basic command line interface and its options."},
+  {"--help", "Print full help and exit.",
+   "Full help displays most of the documentation provided by the UNIX "
+   "man page.  It is provided for use on non-UNIX platforms, but is "
+   "also convenient if the man page is not installed."},
+  {"--help-html", "Print full help in HTML format.",
+   "This option is used by CMake authors to help produce web pages."},
+  {"--man", "Print a UNIX man page and exit.",
+   "This option is used by CMake authors to generate the UNIX man page."},
+  {"--version", "Show program name/version banner and exit.", 0},
+  {0,0,0}
+};
+
+//----------------------------------------------------------------------------
+const cmDocumentationEntry cmDocumentationCopyright[] =
+{
+  {0,
+   "Copyright (c) 2002 Kitware, Inc., Insight Consortium.\n"
+   "All rights reserved.\n", 0},
+  {0,
+   "Redistribution and use in source and binary forms, with or without "
+   "modification, are permitted provided that the following conditions are "
+   "met:\n", 0},
+  {" * ",
+   "Redistributions of source code must retain the above copyright notice, "
+   "this list of conditions and the following disclaimer.\n", 0},
+  {" * ",
+   "Redistributions in binary form must reproduce the above copyright "
+   "notice, this list of conditions and the following disclaimer in the "
+   "documentation and/or other materials provided with the distribution.\n",
+   0},
+  {" * ",
+   "The names of Kitware, Inc., the Insight Consortium, or the names of "
+   "any consortium members, or of any contributors, may not be used to "
+   "endorse or promote products derived from this software without "
+   "specific prior written permission.\n", 0},
+  {" * ",
+   "Modified source versions must be plainly marked as such, and must "
+   "not be misrepresented as being the original software.\n", 0},
+  {0,
+   "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "
+   "``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT "
+   "LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR "
+   "A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR "
+   "CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, "
+   "EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, "
+   "PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR "
+   "PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF "
+   "LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING "
+   "NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS "
+   "SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n", 0},
+  {0, 0, 0}
+};
+
+//----------------------------------------------------------------------------
+cmDocumentation::cmDocumentation()
+{
+  this->Commands = 0;
+  this->Description = 0;
+  this->Name = 0;
+  this->UsageHelp = 0;  
+  this->SetOptions(0);
+}
+
+//----------------------------------------------------------------------------
+void cmDocumentation::PrintManSection(std::ostream& os,
+                                      const cmDocumentationEntry* section,
+                                      const char* name)
+{
+  if(!section) { return; }
+  os << ".SH " << name << "\n";
+  for(const cmDocumentationEntry* op = section; op->brief; ++op)
+    {
+    if(op->name)
+      {
+      os << ".TP\n"
+         << ".B " << op->name << "\n"
+         << op->brief << "\n";
+      if(op->full) { os << op->full << "\n"; }
+      }
+    else
+      {
+      os << ".PP\n"
+         << op->brief << "\n";
+      }
+    }  
+}
+
+//----------------------------------------------------------------------------
+void cmDocumentation::PrintHelpSection(std::ostream& os,
+                                       const cmDocumentationEntry* section)
+{
+  if(!section) { return; }
+  for(const cmDocumentationEntry* op = section; op->brief; ++op)
+    {
+    if(op->name)
+      {
+      os << "  " << op->name << "\n"
+         << "       ";
+      this->PrintColumn(os, 70, "       ", op->brief);
+      if(op->full)
+        {
+        os << "\n"
+           << "       ";
+        this->PrintColumn(os, 70, "       ", op->full);
+        }
+      os << "\n";
+      }
+    else
+      {
+      this->PrintColumn(os, 77, "", op->brief);
+      os << "\n";
+      }
+    os << "\n";
+    }  
+}
+
+//----------------------------------------------------------------------------
+void cmDocumentation::PrintHTMLEscapes(std::ostream& os, const char* text)
+{
+  static cmDocumentationEntry escapes[] =
+  {
+    {"<", "&lt;", 0},
+    {">", "&gt;", 0},
+    {"&", "&amp;", 0},
+    {0,0,0}
+  };
+  for(const char* p = text; *p; ++p)
+    {
+    bool found = false;
+    for(const cmDocumentationEntry* op = escapes; !found && op->name; ++op)
+      {
+      if(op->name[0] == *p)
+        {
+        os << op->brief;
+        found = true;
+        }
+      }
+    if(!found)
+      {
+      os << *p;
+      }
+    }
+}
+
+//----------------------------------------------------------------------------
+void cmDocumentation::PrintHelpHTMLSection(std::ostream& os,
+                                           const cmDocumentationEntry* section,
+                                           const char* header)
+{
+  if(!section) { return; }
+  if(header)
+    {
+    os << "<h2>" << header << "</h2>\n";
+    }
+  for(const cmDocumentationEntry* op = section; op->brief;)
+    {
+    if(op->name)
+      {
+      os << "<ul>\n";
+      for(;op->name;++op)
+        {
+        os << "  <li>\n";
+        os << "    <b><code>";
+        this->PrintHTMLEscapes(os, op->name);
+        os << "</code></b>: ";
+        this->PrintHTMLEscapes(os, op->brief);
+        if(op->full)
+          {
+          os << "  ";
+          this->PrintHTMLEscapes(os, op->full);
+          }
+        os << "\n";
+        os << "  </li>\n";
+        }
+      os << "</ul>\n";
+      }
+    else
+      {
+      this->PrintHTMLEscapes(os, op->brief);
+      os << "\n";
+      ++op;
+      }
+    }
+}
+
+//----------------------------------------------------------------------------
+void cmDocumentation::PrintUsageSection(std::ostream& os,
+                                        const cmDocumentationEntry* section)
+{
+  if(!section) { return; }
+  std::ios::fmtflags flags = os.flags();
+  os.setf(flags | std::ios::left);
+  for(const cmDocumentationEntry* op = section; op->brief; ++op)
+    {
+    if(op->name)
+      {
+      os << "  ";
+      os.width(25);
+      os << op->name << "= " << op->brief << "\n";
+      }
+    else
+      {
+      os << "\n";
+      this->PrintColumn(os, 74, "", op->brief);
+      os << "\n";
+      }
+    }  
+  os.setf(flags);
+}
+
+//----------------------------------------------------------------------------
+void cmDocumentation::PrintUsage(std::ostream& os)
+{
+  os << "Usage:\n";
+  this->PrintUsageSection(os, this->UsageHelp);
+  this->PrintUsageSection(os, &this->Options[0]);
+}
+
+//----------------------------------------------------------------------------
+void cmDocumentation::PrintHelp(std::ostream& os)
+{
+  os << "Usage:\n";
+  os << "\n";
+  this->PrintHelpSection(os, this->UsageHelp);
+  this->PrintHelpSection(os, this->Description);
+  os << "--------------------------------------------------------------------------\n";
+  this->PrintHelpSection(os, &this->Options[0]);
+  os << "--------------------------------------------------------------------------\n";
+  this->PrintHelpSection(os, this->Commands);
+}
+
+//----------------------------------------------------------------------------
+void cmDocumentation::PrintHelpHTML(std::ostream& os)
+{
+  os << "<html>\n"
+     << "<body>\n";
+  os << "<h2>Using CMake</h2>\n";
+  if(this->UsageHelp)
+    {
+    os << "<blockquote><code>\n";
+    this->PrintHelpHTMLSection(os, this->UsageHelp, 0);
+    os << "</code></blockquote>\n";
+    }
+  this->PrintHelpHTMLSection(os, this->Description, 0);
+  this->PrintHelpHTMLSection(os, &this->Options[0], "Command-line Options");
+  this->PrintHelpHTMLSection(os, this->Commands, "CMakeLists.txt Commands");
+  os << "</body>\n"
+     << "</html>\n";
+}
+
+//----------------------------------------------------------------------------
+void cmDocumentation::PrintManPage(std::ostream& os)
+{
+  os << ".TH CMake 1 \""
+     << cmSystemTools::GetCurrentDateTime("%B %d, %Y").c_str()
+     << "\" \"CMake " CMake_VERSION_STRING "\"\n";
+  this->PrintManSection(os, this->Name, "NAME");
+  this->PrintManSection(os, this->UsageHelp, "SYNOPSIS");
+  this->PrintManSection(os, this->Description, "DESCRIPTION");
+  this->PrintManSection(os, &this->Options[0], "OPTIONS");
+  this->PrintManSection(os, this->Commands, "COMMANDS");
+  this->PrintManSection(os, cmDocumentationCopyright, "COPYRIGHT");
+  os << ".SH MAILING LIST\n";
+  os << "For help and discussion about using cmake, a mailing list is\n"
+     << "provided at\n"
+     << ".B cmake@www.cmake.org.\n"
+     << "Please first read the full documentation at\n"
+     << ".B http://www.cmake.org\n"
+     << "before posting questions to the list.\n";
+  os << ".SH AUTHOR\n"
+     << "This manual page was generated by \"cmake --man\".\n";
+}
+
+//----------------------------------------------------------------------------
+void cmDocumentation::PrintCopyright(std::ostream& os)
+{
+  os << "CMake version " CMake_VERSION_STRING "\n";
+  for(const cmDocumentationEntry* op = cmDocumentationCopyright;
+      op->brief; ++op)
+    {
+    if(op->name)
+      {
+      os << " * ";
+      this->PrintColumn(os, 74, "   ", op->brief);
+      }
+    else
+      {
+      this->PrintColumn(os, 77, "", op->brief);
+      }
+    os << "\n";
+    }
+}
+
+//----------------------------------------------------------------------------
+void cmDocumentation::PrintVersion(std::ostream& os)
+{
+  os << "CMake version " CMake_VERSION_STRING "\n";
+}
+
+//----------------------------------------------------------------------------
+void cmDocumentation::PrintColumn(std::ostream& os, int width,
+                                  const char* indent, const char* text)
+{
+  // Print text arranged in a column of fixed witdh indented by the
+  // "indent" text.
+  const char* l = text;
+  int column = 0;
+  bool newSentence = false;
+  bool first = true;
+  while(*l)
+    {
+    // Parse the next word.
+    const char* r = l;
+    while(*r && (*r != '\n') && (*r != ' ')) { ++r; }
+    
+    // Does it fit on this line?
+    if(r-l < (width-column-(newSentence?1:0)))
+      {
+      // Word fits on this line.
+      if(r > l)
+        {
+        if(column)
+          {
+          // Not first word on line.  Separate from the previous word
+          // by a space, or two if this is a new sentence.
+          if(newSentence)
+            {
+            os << "  ";
+            column += 2;
+            }
+          else
+            {
+            os << " ";
+            column += 1;
+            }
+          }
+        else
+          {
+          // First word on line.  Print indentation unless this is the
+          // first line.
+          os << (first?"":indent);
+          }
+        
+        // Print the word.
+        os.write(l, static_cast<long>(r-l));
+        newSentence = (*(r-1) == '.');
+        }
+      
+      if(*r == '\n')
+        {
+        // Text provided a newline.  Start a new line.
+        os << "\n";
+        ++r;
+        column = 0;
+        first = false;
+        }
+      else
+        {
+        // No provided newline.  Continue this line.
+        column += static_cast<long>(r-l);
+        }
+      }
+    else
+      {
+      // Word does not fit on this line.  Start a new line.
+      os << "\n";
+      first = false;
+      if(r > l)
+        {
+        os << indent;
+        os.write(l, static_cast<long>(r-l));
+        column = static_cast<long>(r-l);
+        newSentence = (*(r-1) == '.');
+        }
+      }
+    
+    // Move to beginning of next word.  Skip over whitespace.
+    l = r;
+    while(*l && (*l == ' ')) { ++l; }    
+    }
+}
+
+//----------------------------------------------------------------------------
+void cmDocumentation::Print(Type ht, std::ostream& os)
+{
+  switch (ht)
+    {
+    case cmDocumentation::Usage:     this->PrintUsage(os); break;
+    case cmDocumentation::Help:      this->PrintHelp(os); break;
+    case cmDocumentation::HelpHTML:  this->PrintHelpHTML(os); break;
+    case cmDocumentation::Man:       this->PrintManPage(os); break;
+    case cmDocumentation::Copyright: this->PrintCopyright(os); break;
+    case cmDocumentation::Version:   this->PrintVersion(os); break;
+    default: break;
+    }
+}
+
+//----------------------------------------------------------------------------
+cmDocumentation::Type cmDocumentation::CheckOptions(int argc, char** argv)
+{
+  for(int i=1; i < argc; ++i)
+    {
+    if((strcmp(argv[i], "/?") == 0) ||
+       (strcmp(argv[i], "-usage") == 0) ||
+       (strcmp(argv[i], "--usage") == 0))
+      {
+      return cmDocumentation::Usage;
+      }
+    if((strcmp(argv[i], "-help") == 0) ||
+       (strcmp(argv[i], "--help") == 0))
+      {
+      return cmDocumentation::Help;
+      }
+    if(strcmp(argv[i], "--help-html") == 0)
+      {
+      return cmDocumentation::HelpHTML;
+      }
+    if(strcmp(argv[i], "--man") == 0)
+      {
+      return cmDocumentation::Man;
+      }
+    if(strcmp(argv[i], "--copyright") == 0)
+      {
+      return cmDocumentation::Copyright;
+      }
+    if(strcmp(argv[i], "--version") == 0)
+      {
+      return cmDocumentation::Version;
+      }
+    }
+  return cmDocumentation::None;
+}
+
+//----------------------------------------------------------------------------
+void cmDocumentation::SetOptions(const cmDocumentationEntry* d)
+{
+  this->Options.erase(this->Options.begin(), this->Options.end());
+  if(d)
+    {
+    for(const cmDocumentationEntry* op = d; op->brief; ++op)
+      {
+      this->Options.push_back(*op);
+      }
+    }
+  for(const cmDocumentationEntry* op = cmDocumentationStandardOptions;
+      op->brief; ++op)
+    {
+    this->Options.push_back(*op);
+    }
+  cmDocumentationEntry empty = {0,0,0};
+  this->Options.push_back(empty);
+}
diff --git a/Source/cmDocumentation.h b/Source/cmDocumentation.h
new file mode 100644
index 0000000..1081b12
--- /dev/null
+++ b/Source/cmDocumentation.h
@@ -0,0 +1,65 @@
+/*=========================================================================
+
+  Program:   CMake - Cross-Platform Makefile Generator
+  Module:    $RCSfile$
+  Language:  C++
+  Date:      $Date$
+  Version:   $Revision$
+
+  Copyright (c) 2002 Kitware, Inc., Insight Consortium.  All rights reserved.
+  See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
+
+     This software is distributed WITHOUT ANY WARRANTY; without even 
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+     PURPOSE.  See the above copyright notices for more information.
+
+=========================================================================*/
+#ifndef _cmDocumentation_h
+#define _cmDocumentation_h
+
+#include "cmStandardIncludes.h"
+
+/** Class to generate documentation.  */
+class cmDocumentation
+{
+public:
+  cmDocumentation();
+  
+  enum Type { None, Usage, Help, HelpHTML, Man, Copyright, Version };
+  
+  void Print(Type ht, std::ostream& os);
+  void PrintUsage(std::ostream& os);
+  void PrintHelp(std::ostream& os);
+  void PrintHelpHTML(std::ostream& os);
+  void PrintManPage(std::ostream& os);
+  void PrintCopyright(std::ostream& os);
+  void PrintVersion(std::ostream& os);
+  
+  void SetCommands(const cmDocumentationEntry* d)    {this->Commands = d;}
+  void SetDescription(const cmDocumentationEntry* d) {this->Description = d;}
+  void SetName(const cmDocumentationEntry* d)        {this->Name = d;}
+  void SetOptions(const cmDocumentationEntry* d);
+  void SetUsage(const cmDocumentationEntry* d)       {this->UsageHelp = d;}
+  
+  Type CheckOptions(int argc, char** argv);
+private:
+  void PrintColumn(std::ostream& os, int width,
+                   const char* indent, const char* text);
+  void PrintManSection(std::ostream& os, const cmDocumentationEntry* section,
+                       const char* name);
+  void PrintHelpSection(std::ostream& os, const cmDocumentationEntry* section);
+  void PrintHTMLEscapes(std::ostream& os, const char* text);
+  void PrintHelpHTMLSection(std::ostream& os,
+                            const cmDocumentationEntry* section,
+                            const char* header);
+  void PrintUsageSection(std::ostream& os,
+                         const cmDocumentationEntry* section);
+  
+  const cmDocumentationEntry* Commands;
+  const cmDocumentationEntry* Description;
+  const cmDocumentationEntry* Name;
+  std::vector<cmDocumentationEntry> Options;
+  const cmDocumentationEntry* UsageHelp;
+};
+
+#endif
diff --git a/Source/cmStandardIncludes.h b/Source/cmStandardIncludes.h
index 937d9c2..4204b53 100644
--- a/Source/cmStandardIncludes.h
+++ b/Source/cmStandardIncludes.h
@@ -244,4 +244,12 @@ private:
 };
 #endif
 
+/** Standard documentation entry for cmDocumentation's formatting.  */
+struct cmDocumentationEntry
+{
+  const char* name;
+  const char* brief;
+  const char* full;
+};
+
 #endif
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx
index 4214132..49d6bd8 100644
--- a/Source/cmSystemTools.cxx
+++ b/Source/cmSystemTools.cxx
@@ -2363,6 +2363,15 @@ void cmSystemTools::SplitProgramFromArgs(const char* path,
   args = "";
 }
 
+std::string cmSystemTools::GetCurrentDateTime(const char* format)
+{
+  char buf[1024];
+  time_t t;
+  time(&t);
+  strftime(buf, sizeof(buf), format, localtime(&t));
+  return buf;
+}
+
 std::string cmSystemTools::MakeCindentifier(const char* s)
 {
   std::string str(s);
diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h
index db4c3b4..a66d792 100644
--- a/Source/cmSystemTools.h
+++ b/Source/cmSystemTools.h
@@ -352,6 +352,8 @@ public:
    */
   static FileFormat GetFileFormat(const char* ext);
 
+  static std::string GetCurrentDateTime(const char* format);
+
   /**
    * On Windows 9x we need a comspec (command.com) substitute to run
    * programs correctly. This string has to be constant available
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index aa5984b..0dad7cf 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -1120,3 +1120,20 @@ void cmake::UpdateProgress(const char *msg, float prog)
     return;
     }
 }
+
+void cmake::GetCommandDocumentation(std::vector<cmDocumentationEntry>& v) const
+{
+  for(RegisteredCommandsMap::const_iterator j = m_Commands.begin();
+      j != m_Commands.end(); ++j)
+    {
+    cmDocumentationEntry e =
+      {
+        (*j).second->GetName(),
+        (*j).second->GetTerseDocumentation(),
+        (*j).second->GetFullDocumentation()
+      };
+    v.push_back(e);
+    }
+  cmDocumentationEntry empty = {0,0,0};
+  v.push_back(empty);
+}
diff --git a/Source/cmake.h b/Source/cmake.h
index 143f1e1..9418061 100644
--- a/Source/cmake.h
+++ b/Source/cmake.h
@@ -232,6 +232,8 @@ class cmake
   ///! Get the variable watch object
   cmVariableWatch* GetVariableWatch() { return m_VariableWatch; }
 
+  void GetCommandDocumentation(std::vector<cmDocumentationEntry>&) const;
+  
 protected:
   typedef std::map<cmStdString, cmCommand*> RegisteredCommandsMap;
   RegisteredCommandsMap m_Commands;
diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx
index 289f82e..f6d8dfa 100644
--- a/Source/cmakemain.cxx
+++ b/Source/cmakemain.cxx
@@ -19,6 +19,31 @@
 #include "cmCacheManager.h"
 #include "cmDynamicLoader.h"
 #include "cmListFileCache.h"
+#include "cmDocumentation.h"
+
+//----------------------------------------------------------------------------
+static const cmDocumentationEntry cmDocumentationName[] =
+{
+  {"cmake",
+   "- Cross-Platform Makefile Generator.", 0},
+  {0,0,0}
+};
+
+//----------------------------------------------------------------------------
+static const cmDocumentationEntry cmDocumentationUsage[] =
+{
+  {0,
+   "cmake <path-to-source>", 0},
+  {0,0,0}
+};
+
+//----------------------------------------------------------------------------
+static const cmDocumentationEntry cmDocumentationDescription[] =
+{
+  {0,
+   "CMake reads ... ", 0},
+  {0,0,0}
+};
 
 int do_cmake(int ac, char** av);
 void updateProgress(const char *msg, float prog, void *cd);
@@ -36,6 +61,20 @@ int main(int ac, char** av)
 
 int do_cmake(int ac, char** av)
 {
+  cmDocumentation doc;
+  if(cmDocumentation::Type ht = doc.CheckOptions(ac, av))
+    {
+    cmake hcm;
+    std::vector<cmDocumentationEntry> commands;
+    hcm.GetCommandDocumentation(commands);
+    doc.SetName(cmDocumentationName);
+    doc.SetUsage(cmDocumentationUsage);
+    doc.SetDescription(cmDocumentationDescription);
+    doc.SetCommands(&commands[0]);
+    doc.Print(ht, std::cout);
+    return 0;
+    }
+  
   bool wiz = false;
   bool command = false;
   std::vector<std::string> args;
@@ -45,16 +84,13 @@ int do_cmake(int ac, char** av)
       {
       wiz = true;
       }
-    else
+    else if (strcmp(av[i], "-E") == 0)
+      {
+      command = true;
+      }
+    else 
       {
-      if (strcmp(av[i], "-E") == 0)
-        {
-        command = true;
-        }
-      else 
-        {
-        args.push_back(av[i]);
-        }
+      args.push_back(av[i]);
       }
     }
 
-- 
cgit v0.12