CMake/Source/cmDocumentation.cxx
Alex Neundorf d62c51ddc2 -fix documentation from a module which has *only* documentation
This is #10466. It didn't crash for me, but also didn't work.
The issue was that a line ending with something else than a # was considered as the
end of the documentation block. If there was simply the end of the file we didn't
get into the correct branch.

Alex
2010-05-08 10:10:19 +02:00

1585 lines
51 KiB
C++

/*============================================================================
CMake - Cross Platform Makefile Generator
Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
Distributed under the OSI-approved BSD License (the "License");
see accompanying file Copyright.txt for details.
This software is distributed WITHOUT ANY WARRANTY; without even the
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the License for more information.
============================================================================*/
#include "cmDocumentation.h"
#include "cmSystemTools.h"
#include "cmVersion.h"
#include <cmsys/Directory.hxx>
//----------------------------------------------------------------------------
static const char *cmDocumentationStandardOptions[][3] =
{
{"--copyright [file]", "Print the CMake copyright and exit.",
"If a file is specified, the copyright is written into it."},
{"--help", "Print usage information and exit.",
"Usage describes the basic command line interface and its options."},
{"--help-full [file]", "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. If a file is "
"specified, the help is written into it."},
{"--help-html [file]", "Print full help in HTML format.",
"This option is used by CMake authors to help produce web pages. "
"If a file is specified, the help is written into it."},
{"--help-man [file]", "Print full help as a UNIX man page and exit.",
"This option is used by the cmake build to generate the UNIX man page. "
"If a file is specified, the help is written into it."},
{"--version [file]", "Show program name/version banner and exit.",
"If a file is specified, the version is written into it."},
{0,0,0}
};
//----------------------------------------------------------------------------
static const char *cmModulesDocumentationDescription[][3] =
{
{0,
" CMake Modules - Modules coming with CMake, the Cross-Platform Makefile "
"Generator.", 0},
// CMAKE_DOCUMENTATION_OVERVIEW,
{0,
"This is the documentation for the modules and scripts coming with CMake. "
"Using these modules you can check the computer system for "
"installed software packages, features of the compiler and the "
"existance of headers to name just a few.", 0},
{0,0,0}
};
//----------------------------------------------------------------------------
static const char *cmCustomModulesDocumentationDescription[][3] =
{
{0,
" Custom CMake Modules - Additional Modules for CMake.", 0},
// CMAKE_DOCUMENTATION_OVERVIEW,
{0,
"This is the documentation for additional modules and scripts for CMake. "
"Using these modules you can check the computer system for "
"installed software packages, features of the compiler and the "
"existance of headers to name just a few.", 0},
{0,0,0}
};
//----------------------------------------------------------------------------
static const char *cmPropertiesDocumentationDescription[][3] =
{
{0,
" CMake Properties - Properties supported by CMake, "
"the Cross-Platform Makefile Generator.", 0},
// CMAKE_DOCUMENTATION_OVERVIEW,
{0,
"This is the documentation for the properties supported by CMake. "
"Properties can have different scopes. They can either be assigned to a "
"source file, a directory, a target or globally to CMake. By modifying the "
"values of properties the behaviour of the build system can be customized.",
0},
{0,0,0}
};
//----------------------------------------------------------------------------
static const char *cmCompatCommandsDocumentationDescription[][3] =
{
{0,
" CMake Compatibility Listfile Commands - "
"Obsolete commands supported by CMake for compatibility.", 0},
// CMAKE_DOCUMENTATION_OVERVIEW,
{0,
"This is the documentation for now obsolete listfile commands from previous "
"CMake versions, which are still supported for compatibility reasons. You "
"should instead use the newer, faster and shinier new commands. ;-)", 0},
{0,0,0}
};
//----------------------------------------------------------------------------
static const char *cmDocumentationModulesHeader[][3] =
{
{0,
"The following modules are provided with CMake. "
"They can be used with INCLUDE(ModuleName).", 0},
{0,0,0}
};
//----------------------------------------------------------------------------
static const char *cmDocumentationCustomModulesHeader[][3] =
{
{0,
"The following modules are also available for CMake. "
"They can be used with INCLUDE(ModuleName).", 0},
{0,0,0}
};
//----------------------------------------------------------------------------
static const char *cmDocumentationGeneratorsHeader[][3] =
{
{0,
"The following generators are available on this platform:", 0},
{0,0,0}
};
//----------------------------------------------------------------------------
static const char *cmDocumentationStandardSeeAlso[][3] =
{
{0,
"The following resources are available to get help using CMake:", 0},
{"Home Page",
"http://www.cmake.org",
"The primary starting point for learning about CMake."},
{"Frequently Asked Questions",
"http://www.cmake.org/Wiki/CMake_FAQ",
"A Wiki is provided containing answers to frequently asked questions. "},
{"Online Documentation",
"http://www.cmake.org/HTML/Documentation.html",
"Links to available documentation may be found on this web page."},
{"Mailing List",
"http://www.cmake.org/HTML/MailingLists.html",
"For help and discussion about using cmake, a mailing list is provided at "
"cmake@cmake.org. "
"The list is member-post-only but one may sign up on the CMake web page. "
"Please first read the full documentation at "
"http://www.cmake.org before posting questions to the list."},
{0,
"Summary of helpful links:\n"
" Home: http://www.cmake.org\n"
" Docs: http://www.cmake.org/HTML/Documentation.html\n"
" Mail: http://www.cmake.org/HTML/MailingLists.html\n"
" FAQ: http://www.cmake.org/Wiki/CMake_FAQ\n"
, 0},
{0,0,0}
};
//----------------------------------------------------------------------------
static const char *cmDocumentationCopyright[][3] =
{
{0,
"Copyright 2000-2009 Kitware, Inc., Insight Software Consortium. "
"All rights reserved.", 0},
{0,
"Redistribution and use in source and binary forms, with or without "
"modification, are permitted provided that the following conditions are "
"met:", 0},
{"",
"Redistributions of source code must retain the above copyright notice, "
"this list of conditions and the following disclaimer.", 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.",
0},
{"",
"Neither the names of Kitware, Inc., the Insight Software Consortium, "
"nor the names of their contributors may be used to endorse or promote "
"products derived from this software without specific prior written "
"permission.", 0},
{0,
"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT "
"HOLDER 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.",
0},
{0, 0, 0}
};
//----------------------------------------------------------------------------
#define DOCUMENT_INTRO(type, default_name, desc) \
static char const *cmDocumentation##type##Intro[2] = { default_name, desc };
#define GET_DOCUMENT_INTRO(type) cmDocumentation##type##Intro
DOCUMENT_INTRO(Modules, "cmakemodules",
"Reference of available CMake modules.");
DOCUMENT_INTRO(CustomModules, "cmakecustommodules",
"Reference of available CMake custom modules.");
DOCUMENT_INTRO(Policies, "cmakepolicies",
"Reference of CMake policies.");
DOCUMENT_INTRO(Properties, "cmakeprops",
"Reference of CMake properties.");
DOCUMENT_INTRO(Variables, "cmakevars",
"Reference of CMake variables.");
DOCUMENT_INTRO(Commands, "cmakecommands",
"Reference of available CMake commands.");
DOCUMENT_INTRO(CompatCommands, "cmakecompat",
"Reference of CMake compatibility commands.");
//----------------------------------------------------------------------------
cmDocumentation::cmDocumentation()
:CurrentFormatter(0)
{
this->SetForm(TextForm);
cmDocumentationSection *sec;
sec = new cmDocumentationSection("Author","AUTHOR");
sec->Append(cmDocumentationEntry
(0,
"This manual page was generated by the \"--help-man\" option.",
0));
this->AllSections["Author"] = sec;
sec = new cmDocumentationSection("Copyright","COPYRIGHT");
sec->Append(cmDocumentationCopyright);
this->AllSections["Copyright"] = sec;
sec = new cmDocumentationSection("See Also","SEE ALSO");
sec->Append(cmDocumentationStandardSeeAlso);
this->AllSections["Standard See Also"] = sec;
sec = new cmDocumentationSection("Options","OPTIONS");
sec->Append(cmDocumentationStandardOptions);
this->AllSections["Options"] = sec;
sec = new cmDocumentationSection("Properties","PROPERTIES");
sec->Append(cmPropertiesDocumentationDescription);
this->AllSections["Properties Description"] = sec;
sec = new cmDocumentationSection("Generators","GENERATORS");
sec->Append(cmDocumentationGeneratorsHeader);
this->AllSections["Generators"] = sec;
sec = new cmDocumentationSection("Compatibility Commands",
"COMPATIBILITY COMMANDS");
sec->Append(cmCompatCommandsDocumentationDescription);
this->AllSections["Compatibility Commands"] = sec;
this->PropertySections.push_back("Properties of Global Scope");
this->PropertySections.push_back("Properties on Directories");
this->PropertySections.push_back("Properties on Targets");
this->PropertySections.push_back("Properties on Tests");
this->PropertySections.push_back("Properties on Source Files");
this->PropertySections.push_back("Properties on Cache Entries");
this->VariableSections.push_back("Variables that Provide Information");
this->VariableSections.push_back("Variables That Change Behavior");
this->VariableSections.push_back("Variables That Describe the System");
this->VariableSections.push_back("Variables that Control the Build");
this->VariableSections.push_back("Variables for Languages");
this->ShowGenerators = true;
}
//----------------------------------------------------------------------------
cmDocumentation::~cmDocumentation()
{
for(std::vector< char* >::iterator i = this->ModuleStrings.begin();
i != this->ModuleStrings.end(); ++i)
{
delete [] *i;
}
for(std::map<std::string,cmDocumentationSection *>::iterator i =
this->AllSections.begin();
i != this->AllSections.end(); ++i)
{
delete i->second;
}
}
//----------------------------------------------------------------------------
bool cmDocumentation::PrintCopyright(std::ostream& os)
{
cmDocumentationSection *sec = this->AllSections["Copyright"];
const std::vector<cmDocumentationEntry> &entries = sec->GetEntries();
for(std::vector<cmDocumentationEntry>::const_iterator op = entries.begin();
op != entries.end(); ++op)
{
if(op->Name.size())
{
os << " * ";
this->TextFormatter.SetIndent(" ");
this->TextFormatter.PrintColumn(os, op->Brief.c_str());
}
else
{
this->TextFormatter.SetIndent("");
this->TextFormatter.PrintColumn(os, op->Brief.c_str());
}
os << "\n";
}
return true;
}
//----------------------------------------------------------------------------
bool cmDocumentation::PrintVersion(std::ostream& os)
{
os << this->GetNameString() << " version "
<< cmVersion::GetCMakeVersion() << "\n";
return true;
}
//----------------------------------------------------------------------------
void cmDocumentation::AddSectionToPrint(const char *section)
{
if (this->AllSections.find(section) != this->AllSections.end())
{
this->PrintSections.push_back(this->AllSections[section]);
}
}
//----------------------------------------------------------------------------
void cmDocumentation::ClearSections()
{
this->PrintSections.erase(this->PrintSections.begin(),
this->PrintSections.end());
this->ModulesFound.clear();
}
//----------------------------------------------------------------------------
void cmDocumentation::AddDocumentIntroToPrint(const char* intro[2])
{
const char* docname = this->GetDocName(false);
if(intro && docname)
{
cmDocumentationSection* section;
std::string desc("");
desc += docname;
desc += " - ";
desc += intro[1];
section = new cmDocumentationSection("Introduction", "NAME");
section->Append(0, desc.c_str(), 0);
this->PrintSections.push_back(section);
}
}
//----------------------------------------------------------------------------
bool cmDocumentation::PrintDocumentation(Type ht, std::ostream& os,
const char* docname)
{
if ((this->CurrentFormatter->GetForm() != HTMLForm)
&& (this->CurrentFormatter->GetForm() != DocbookForm)
&& (this->CurrentFormatter->GetForm() != ManForm))
{
this->PrintVersion(os);
}
// Handle Document Name. docname==0 disables intro.
this->SetDocName("");
if (docname)
{
if (*docname)
this->SetDocName(docname);
else // empty string was given. select default if possible
this->SetDocName(this->GetDefaultDocName(ht));
}
switch (ht)
{
case cmDocumentation::Usage:
return this->PrintDocumentationUsage(os);
case cmDocumentation::Single:
return this->PrintDocumentationSingle(os);
case cmDocumentation::SingleModule:
return this->PrintDocumentationSingleModule(os);
case cmDocumentation::SinglePolicy:
return this->PrintDocumentationSinglePolicy(os);
case cmDocumentation::SingleProperty:
return this->PrintDocumentationSingleProperty(os);
case cmDocumentation::SingleVariable:
return this->PrintDocumentationSingleVariable(os);
case cmDocumentation::List:
this->PrintDocumentationList(os,"Commands");
this->PrintDocumentationList(os,"Compatibility Commands");
return true;
case cmDocumentation::ModuleList:
// find the modules first, print the custom module docs only if
// any custom modules have been found actually, Alex
this->CreateCustomModulesSection();
this->CreateModulesSection();
if (this->AllSections.find("Custom CMake Modules")
!= this->AllSections.end())
{
this->PrintDocumentationList(os,"Custom CMake Modules");
}
this->PrintDocumentationList(os,"Modules");
return true;
case cmDocumentation::PropertyList:
this->PrintDocumentationList(os,"Properties Description");
for (std::vector<std::string>::iterator i =
this->PropertySections.begin();
i != this->PropertySections.end(); ++i)
{
this->PrintDocumentationList(os,i->c_str());
}
return true;
case cmDocumentation::VariableList:
for (std::vector<std::string>::iterator i =
this->VariableSections.begin();
i != this->VariableSections.end(); ++i)
{
this->PrintDocumentationList(os,i->c_str());
}
return true;
case cmDocumentation::Full:
return this->PrintDocumentationFull(os);
case cmDocumentation::Modules:
return this->PrintDocumentationModules(os);
case cmDocumentation::CustomModules:
return this->PrintDocumentationCustomModules(os);
case cmDocumentation::Policies:
return this->PrintDocumentationPolicies(os);
case cmDocumentation::Properties:
return this->PrintDocumentationProperties(os);
case cmDocumentation::Variables:
return this->PrintDocumentationVariables(os);
case cmDocumentation::Commands:
return this->PrintDocumentationCurrentCommands(os);
case cmDocumentation::CompatCommands:
return this->PrintDocumentationCompatCommands(os);
case cmDocumentation::Copyright:
return this->PrintCopyright(os);
case cmDocumentation::Version:
return true;
default: return false;
}
}
//----------------------------------------------------------------------------
bool cmDocumentation::CreateModulesSection()
{
cmDocumentationSection *sec =
new cmDocumentationSection("Standard CMake Modules", "MODULES");
this->AllSections["Modules"] = sec;
std::string cmakeModules = this->CMakeRoot;
cmakeModules += "/Modules";
cmsys::Directory dir;
dir.Load(cmakeModules.c_str());
if (dir.GetNumberOfFiles() > 0)
{
sec->Append(cmDocumentationModulesHeader[0]);
sec->Append(cmModulesDocumentationDescription);
this->CreateModuleDocsForDir(dir, *this->AllSections["Modules"]);
}
return true;
}
//----------------------------------------------------------------------------
bool cmDocumentation::CreateCustomModulesSection()
{
bool sectionHasHeader = false;
std::vector<std::string> dirs;
cmSystemTools::ExpandListArgument(this->CMakeModulePath, dirs);
for(std::vector<std::string>::const_iterator dirIt = dirs.begin();
dirIt != dirs.end();
++dirIt)
{
cmsys::Directory dir;
dir.Load(dirIt->c_str());
if (dir.GetNumberOfFiles() > 0)
{
if (!sectionHasHeader)
{
cmDocumentationSection *sec =
new cmDocumentationSection("Custom CMake Modules","CUSTOM MODULES");
this->AllSections["Custom CMake Modules"] = sec;
sec->Append(cmDocumentationCustomModulesHeader[0]);
sec->Append(cmCustomModulesDocumentationDescription);
sectionHasHeader = true;
}
this->CreateModuleDocsForDir
(dir, *this->AllSections["Custom CMake Modules"]);
}
}
return true;
}
//----------------------------------------------------------------------------
void cmDocumentation
::CreateModuleDocsForDir(cmsys::Directory& dir,
cmDocumentationSection &moduleSection)
{
// sort the files alphabetically, so the docs for one module are easier
// to find than if they are in random order
std::vector<std::string> sortedFiles;
for(unsigned int i = 0; i < dir.GetNumberOfFiles(); ++i)
{
sortedFiles.push_back(dir.GetFile(i));
}
std::sort(sortedFiles.begin(), sortedFiles.end());
for(std::vector<std::string>::const_iterator fname = sortedFiles.begin();
fname!=sortedFiles.end(); ++fname)
{
if(fname->length() > 6)
{
if(fname->substr(fname->length()-6, 6) == ".cmake")
{
std::string moduleName = fname->substr(0, fname->length()-6);
// this check is to avoid creating documentation for the modules with
// the same name in multiple directories of CMAKE_MODULE_PATH
if (this->ModulesFound.find(moduleName) == this->ModulesFound.end())
{
this->ModulesFound.insert(moduleName);
std::string path = dir.GetPath();
path += "/";
path += (*fname);
this->CreateSingleModule(path.c_str(), moduleName.c_str(),
moduleSection);
}
}
}
}
}
//----------------------------------------------------------------------------
bool cmDocumentation::CreateSingleModule(const char* fname,
const char* moduleName,
cmDocumentationSection &moduleSection)
{
std::ifstream fin(fname);
if(!fin)
{
std::cerr << "Internal error: can not open module." << fname << std::endl;
return false;
}
std::string line;
std::string text;
std::string brief;
brief = " ";
bool newParagraph = true;
while ( fin && cmSystemTools::GetLineFromStream(fin, line) )
{
if(line.size() && line[0] == '#')
{
// blank line
if(line.size() <= 2)
{
text += "\n";
newParagraph = true;
}
else if(line[2] == '-')
{
brief = line.c_str()+4;
}
else
{
// two spaces
if(line[1] == ' ' && line[2] == ' ')
{
if(!newParagraph)
{
text += "\n";
newParagraph = true;
}
// Skip #, and leave space for preformatted
text += line.c_str()+1;
text += "\n";
}
else if(line[1] == ' ')
{
if(!newParagraph)
{
text += " ";
}
newParagraph = false;
// skip # and space
text += line.c_str()+2;
}
else
{
if(!newParagraph)
{
text += " ";
}
newParagraph = false;
// skip #
text += line.c_str()+1;
}
}
}
else
{
break;
}
}
if(text.length() < 2 && brief.length() == 1)
{
return false;
}
char* pname = strcpy(new char[strlen(moduleName)+1], moduleName);
char* ptext = strcpy(new char[text.length()+1], text.c_str());
this->ModuleStrings.push_back(pname);
this->ModuleStrings.push_back(ptext);
char* pbrief = strcpy(new char[brief.length()+1], brief.c_str());
this->ModuleStrings.push_back(pbrief);
moduleSection.Append(pname, pbrief, ptext);
return true;
}
//----------------------------------------------------------------------------
bool cmDocumentation::PrintRequestedDocumentation(std::ostream& os)
{
bool result = true;
// Loop over requested documentation types.
for(std::vector<RequestedHelpItem>::const_iterator
i = this->RequestedHelpItems.begin();
i != this->RequestedHelpItems.end();
++i)
{
this->SetForm(i->HelpForm);
this->CurrentArgument = i->Argument;
// If a file name was given, use it. Otherwise, default to the
// given stream.
std::ofstream* fout = 0;
std::ostream* s = &os;
std::string docname("");
if(i->Filename.length() > 0)
{
fout = new std::ofstream(i->Filename.c_str(), std::ios::out);
if(fout)
{
s = fout;
}
else
{
result = false;
}
if(i->Filename != "-")
{
docname = cmSystemTools::GetFilenameWithoutLastExtension(i->Filename);
}
}
// Print this documentation type to the stream.
if(!this->PrintDocumentation(i->HelpType, *s, docname.c_str()) || !*s)
{
result = false;
}
// Close the file if we wrote one.
if(fout)
{
delete fout;
}
}
return result;
}
#define GET_OPT_ARGUMENT(target) \
if((i+1 < argc) && !this->IsOption(argv[i+1])) \
{ \
target = argv[i+1]; \
i = i+1; \
};
cmDocumentation::Form cmDocumentation::GetFormFromFilename(
const std::string& filename)
{
std::string ext = cmSystemTools::GetFilenameLastExtension(filename);
ext = cmSystemTools::UpperCase(ext);
if ((ext == ".HTM") || (ext == ".HTML"))
{
return cmDocumentation::HTMLForm;
}
if (ext == ".DOCBOOK")
{
return cmDocumentation::DocbookForm;
}
// ".1" to ".9" should be manpages
if ((ext.length()==2) && (ext[1] >='1') && (ext[1]<='9'))
{
return cmDocumentation::ManForm;
}
return cmDocumentation::TextForm;
}
//----------------------------------------------------------------------------
bool cmDocumentation::CheckOptions(int argc, const char* const* argv,
const char* exitOpt)
{
// Providing zero arguments gives usage information.
if(argc == 1)
{
RequestedHelpItem help;
help.HelpType = cmDocumentation::Usage;
help.HelpForm = cmDocumentation::UsageForm;
this->RequestedHelpItems.push_back(help);
return true;
}
// Search for supported help options.
bool result = false;
for(int i=1; i < argc; ++i)
{
if(exitOpt && strcmp(argv[i], exitOpt) == 0)
{
return result;
}
RequestedHelpItem help;
// Check if this is a supported help option.
if((strcmp(argv[i], "-help") == 0) ||
(strcmp(argv[i], "--help") == 0) ||
(strcmp(argv[i], "/?") == 0) ||
(strcmp(argv[i], "-usage") == 0) ||
(strcmp(argv[i], "-h") == 0) ||
(strcmp(argv[i], "-H") == 0))
{
help.HelpType = cmDocumentation::Usage;
help.HelpForm = cmDocumentation::UsageForm;
GET_OPT_ARGUMENT(help.Argument);
help.Argument = cmSystemTools::LowerCase(help.Argument);
// special case for single command
if (!help.Argument.empty())
{
help.HelpType = cmDocumentation::Single;
}
}
else if(strcmp(argv[i], "--help-properties") == 0)
{
help.HelpType = cmDocumentation::Properties;
GET_OPT_ARGUMENT(help.Filename);
help.HelpForm = this->GetFormFromFilename(help.Filename);
}
else if(strcmp(argv[i], "--help-policies") == 0)
{
help.HelpType = cmDocumentation::Policies;
GET_OPT_ARGUMENT(help.Filename);
help.HelpForm = this->GetFormFromFilename(help.Filename);
}
else if(strcmp(argv[i], "--help-variables") == 0)
{
help.HelpType = cmDocumentation::Variables;
GET_OPT_ARGUMENT(help.Filename);
help.HelpForm = this->GetFormFromFilename(help.Filename);
}
else if(strcmp(argv[i], "--help-modules") == 0)
{
help.HelpType = cmDocumentation::Modules;
GET_OPT_ARGUMENT(help.Filename);
help.HelpForm = this->GetFormFromFilename(help.Filename);
}
else if(strcmp(argv[i], "--help-custom-modules") == 0)
{
help.HelpType = cmDocumentation::CustomModules;
GET_OPT_ARGUMENT(help.Filename);
help.HelpForm = this->GetFormFromFilename(help.Filename);
}
else if(strcmp(argv[i], "--help-commands") == 0)
{
help.HelpType = cmDocumentation::Commands;
GET_OPT_ARGUMENT(help.Filename);
help.HelpForm = this->GetFormFromFilename(help.Filename);
}
else if(strcmp(argv[i], "--help-compatcommands") == 0)
{
help.HelpType = cmDocumentation::CompatCommands;
GET_OPT_ARGUMENT(help.Filename);
help.HelpForm = this->GetFormFromFilename(help.Filename);
}
else if(strcmp(argv[i], "--help-full") == 0)
{
help.HelpType = cmDocumentation::Full;
GET_OPT_ARGUMENT(help.Filename);
help.HelpForm = this->GetFormFromFilename(help.Filename);
}
else if(strcmp(argv[i], "--help-html") == 0)
{
help.HelpType = cmDocumentation::Full;
GET_OPT_ARGUMENT(help.Filename);
help.HelpForm = cmDocumentation::HTMLForm;
}
else if(strcmp(argv[i], "--help-man") == 0)
{
help.HelpType = cmDocumentation::Full;
GET_OPT_ARGUMENT(help.Filename);
help.HelpForm = cmDocumentation::ManForm;
}
else if(strcmp(argv[i], "--help-command") == 0)
{
help.HelpType = cmDocumentation::Single;
GET_OPT_ARGUMENT(help.Argument);
GET_OPT_ARGUMENT(help.Filename);
help.Argument = cmSystemTools::LowerCase(help.Argument);
help.HelpForm = this->GetFormFromFilename(help.Filename);
}
else if(strcmp(argv[i], "--help-module") == 0)
{
help.HelpType = cmDocumentation::SingleModule;
GET_OPT_ARGUMENT(help.Argument);
GET_OPT_ARGUMENT(help.Filename);
help.HelpForm = this->GetFormFromFilename(help.Filename);
}
else if(strcmp(argv[i], "--help-property") == 0)
{
help.HelpType = cmDocumentation::SingleProperty;
GET_OPT_ARGUMENT(help.Argument);
GET_OPT_ARGUMENT(help.Filename);
help.HelpForm = this->GetFormFromFilename(help.Filename);
}
else if(strcmp(argv[i], "--help-policy") == 0)
{
help.HelpType = cmDocumentation::SinglePolicy;
GET_OPT_ARGUMENT(help.Argument);
GET_OPT_ARGUMENT(help.Filename);
help.HelpForm = this->GetFormFromFilename(help.Filename);
}
else if(strcmp(argv[i], "--help-variable") == 0)
{
help.HelpType = cmDocumentation::SingleVariable;
GET_OPT_ARGUMENT(help.Argument);
GET_OPT_ARGUMENT(help.Filename);
help.HelpForm = this->GetFormFromFilename(help.Filename);
}
else if(strcmp(argv[i], "--help-command-list") == 0)
{
help.HelpType = cmDocumentation::List;
GET_OPT_ARGUMENT(help.Filename);
help.HelpForm = cmDocumentation::TextForm;
}
else if(strcmp(argv[i], "--help-module-list") == 0)
{
help.HelpType = cmDocumentation::ModuleList;
GET_OPT_ARGUMENT(help.Filename);
help.HelpForm = cmDocumentation::TextForm;
}
else if(strcmp(argv[i], "--help-property-list") == 0)
{
help.HelpType = cmDocumentation::PropertyList;
GET_OPT_ARGUMENT(help.Filename);
help.HelpForm = cmDocumentation::TextForm;
}
else if(strcmp(argv[i], "--help-variable-list") == 0)
{
help.HelpType = cmDocumentation::VariableList;
GET_OPT_ARGUMENT(help.Filename);
help.HelpForm = cmDocumentation::TextForm;
}
else if(strcmp(argv[i], "--copyright") == 0)
{
help.HelpType = cmDocumentation::Copyright;
GET_OPT_ARGUMENT(help.Filename);
help.HelpForm = cmDocumentation::UsageForm;
}
else if((strcmp(argv[i], "--version") == 0) ||
(strcmp(argv[i], "-version") == 0) ||
(strcmp(argv[i], "/V") == 0))
{
help.HelpType = cmDocumentation::Version;
GET_OPT_ARGUMENT(help.Filename);
help.HelpForm = cmDocumentation::UsageForm;
}
if(help.HelpType != None)
{
// This is a help option. See if there is a file name given.
result = true;
this->RequestedHelpItems.push_back(help);
}
}
return result;
}
//----------------------------------------------------------------------------
void cmDocumentation::Print(Form f, std::ostream& os)
{
this->SetForm(f);
this->Print(os);
}
//----------------------------------------------------------------------------
void cmDocumentation::Print(std::ostream& os)
{
// if the formatter supports it, print a master index for
// all sections
this->CurrentFormatter->PrintIndex(os, this->PrintSections);
for(unsigned int i=0; i < this->PrintSections.size(); ++i)
{
std::string name = this->PrintSections[i]->
GetName((this->CurrentFormatter->GetForm()));
this->CurrentFormatter->PrintSection(os,*this->PrintSections[i],
name.c_str());
}
}
//----------------------------------------------------------------------------
void cmDocumentation::SetName(const char* name)
{
this->NameString = name?name:"";
}
//----------------------------------------------------------------------------
void cmDocumentation::SetDocName(const char *docname)
{
this->DocName = docname?docname:"";
}
//----------------------------------------------------------------------------
void cmDocumentation::SetSection(const char *name,
cmDocumentationSection *section)
{
if (this->AllSections.find(name) != this->AllSections.end())
{
delete this->AllSections[name];
}
this->AllSections[name] = section;
}
//----------------------------------------------------------------------------
void cmDocumentation::SetSection(const char *name,
std::vector<cmDocumentationEntry> &docs)
{
cmDocumentationSection *sec =
new cmDocumentationSection(name,
cmSystemTools::UpperCase(name).c_str());
sec->Append(docs);
this->SetSection(name,sec);
}
//----------------------------------------------------------------------------
void cmDocumentation::SetSection(const char *name,
const char *docs[][3])
{
cmDocumentationSection *sec =
new cmDocumentationSection(name,
cmSystemTools::UpperCase(name).c_str());
sec->Append(docs);
this->SetSection(name,sec);
}
//----------------------------------------------------------------------------
void cmDocumentation
::SetSections(std::map<std::string,cmDocumentationSection *> &sections)
{
for (std::map<std::string,cmDocumentationSection *>::const_iterator
it = sections.begin(); it != sections.end(); ++it)
{
this->SetSection(it->first.c_str(),it->second);
}
}
//----------------------------------------------------------------------------
void cmDocumentation::PrependSection(const char *name,
const char *docs[][3])
{
cmDocumentationSection *sec = 0;
if (this->AllSections.find(name) == this->AllSections.end())
{
sec = new cmDocumentationSection
(name, cmSystemTools::UpperCase(name).c_str());
this->SetSection(name,sec);
}
else
{
sec = this->AllSections[name];
}
sec->Prepend(docs);
}
//----------------------------------------------------------------------------
void cmDocumentation::PrependSection(const char *name,
std::vector<cmDocumentationEntry> &docs)
{
cmDocumentationSection *sec = 0;
if (this->AllSections.find(name) == this->AllSections.end())
{
sec = new cmDocumentationSection
(name, cmSystemTools::UpperCase(name).c_str());
this->SetSection(name,sec);
}
else
{
sec = this->AllSections[name];
}
sec->Prepend(docs);
}
//----------------------------------------------------------------------------
void cmDocumentation::AppendSection(const char *name,
const char *docs[][3])
{
cmDocumentationSection *sec = 0;
if (this->AllSections.find(name) == this->AllSections.end())
{
sec = new cmDocumentationSection
(name, cmSystemTools::UpperCase(name).c_str());
this->SetSection(name,sec);
}
else
{
sec = this->AllSections[name];
}
sec->Append(docs);
}
//----------------------------------------------------------------------------
void cmDocumentation::AppendSection(const char *name,
std::vector<cmDocumentationEntry> &docs)
{
cmDocumentationSection *sec = 0;
if (this->AllSections.find(name) == this->AllSections.end())
{
sec = new cmDocumentationSection
(name, cmSystemTools::UpperCase(name).c_str());
this->SetSection(name,sec);
}
else
{
sec = this->AllSections[name];
}
sec->Append(docs);
}
//----------------------------------------------------------------------------
void cmDocumentation::AppendSection(const char *name,
cmDocumentationEntry &docs)
{
std::vector<cmDocumentationEntry> docsVec;
docsVec.push_back(docs);
this->AppendSection(name,docsVec);
}
//----------------------------------------------------------------------------
void cmDocumentation::PrependSection(const char *name,
cmDocumentationEntry &docs)
{
std::vector<cmDocumentationEntry> docsVec;
docsVec.push_back(docs);
this->PrependSection(name,docsVec);
}
//----------------------------------------------------------------------------
void cmDocumentation::SetSeeAlsoList(const char *data[][3])
{
cmDocumentationSection *sec =
new cmDocumentationSection("See Also", "SEE ALSO");
this->AllSections["See Also"] = sec;
this->SeeAlsoString = ".B ";
int i = 0;
while(data[i][1])
{
this->SeeAlsoString += data[i][1];
this->SeeAlsoString += data[i+1][1]? "(1), ":"(1)";
++i;
}
sec->Append(0,this->SeeAlsoString.c_str(),0);
sec->Append(cmDocumentationStandardSeeAlso);
}
//----------------------------------------------------------------------------
bool cmDocumentation::PrintDocumentationGeneric(std::ostream& os,
const char *section)
{
if(this->AllSections.find(section) == this->AllSections.end())
{
os << "Internal error: " << section << " list is empty." << std::endl;
return false;
}
if(this->CurrentArgument.length() == 0)
{
os << "Required argument missing.\n";
return false;
}
const std::vector<cmDocumentationEntry> &entries =
this->AllSections[section]->GetEntries();
for(std::vector<cmDocumentationEntry>::const_iterator ei =
entries.begin();
ei != entries.end(); ++ei)
{
if(this->CurrentArgument == ei->Name)
{
this->PrintDocumentationCommand(os, *ei);
return true;
}
}
return false;
}
//----------------------------------------------------------------------------
bool cmDocumentation::PrintDocumentationSingle(std::ostream& os)
{
if (this->PrintDocumentationGeneric(os,"Commands"))
{
return true;
}
if (this->PrintDocumentationGeneric(os,"Compatibility Commands"))
{
return true;
}
// Argument was not a command. Complain.
os << "Argument \"" << this->CurrentArgument.c_str()
<< "\" to --help-command is not a CMake command. "
<< "Use --help-command-list to see all commands.\n";
return false;
}
//----------------------------------------------------------------------------
bool cmDocumentation::PrintDocumentationSingleModule(std::ostream& os)
{
if(this->CurrentArgument.length() == 0)
{
os << "Argument --help-module needs a module name.\n";
return false;
}
std::string moduleName;
// find the module
std::vector<std::string> dirs;
cmSystemTools::ExpandListArgument(this->CMakeModulePath, dirs);
for(std::vector<std::string>::const_iterator dirIt = dirs.begin();
dirIt != dirs.end();
++dirIt)
{
moduleName = *dirIt;
moduleName += "/";
moduleName += this->CurrentArgument;
moduleName += ".cmake";
if(cmSystemTools::FileExists(moduleName.c_str()))
{
break;
}
moduleName = "";
}
if (moduleName.empty())
{
moduleName = this->CMakeRoot;
moduleName += "/Modules/";
moduleName += this->CurrentArgument;
moduleName += ".cmake";
if(!cmSystemTools::FileExists(moduleName.c_str()))
{
moduleName = "";
}
}
if(!moduleName.empty())
{
cmDocumentationSection *sec =
new cmDocumentationSection("Standard CMake Modules", "MODULES");
this->AllSections["Modules"] = sec;
if (this->CreateSingleModule(moduleName.c_str(),
this->CurrentArgument.c_str(),
*this->AllSections["Modules"]))
{
if(this->AllSections["Modules"]->GetEntries().size())
{
this->PrintDocumentationCommand
(os, this->AllSections["Modules"]->GetEntries()[0]);
os << "\n Defined in: ";
os << moduleName << "\n";
return true;
}
else
{
return false;
}
}
}
// Argument was not a module. Complain.
os << "Argument \"" << this->CurrentArgument.c_str()
<< "\" to --help-module is not a CMake module.\n";
return false;
}
//----------------------------------------------------------------------------
bool cmDocumentation::PrintDocumentationSingleProperty(std::ostream& os)
{
bool done = false;
for (std::vector<std::string>::iterator i =
this->PropertySections.begin();
!done && i != this->PropertySections.end(); ++i)
{
done = this->PrintDocumentationGeneric(os,i->c_str());
}
if (done)
{
return true;
}
// Argument was not a command. Complain.
os << "Argument \"" << this->CurrentArgument.c_str()
<< "\" to --help-property is not a CMake property. "
<< "Use --help-property-list to see all properties.\n";
return false;
}
//----------------------------------------------------------------------------
bool cmDocumentation::PrintDocumentationSinglePolicy(std::ostream& os)
{
if (this->PrintDocumentationGeneric(os,"Policies"))
{
return true;
}
// Argument was not a command. Complain.
os << "Argument \"" << this->CurrentArgument.c_str()
<< "\" to --help-policy is not a CMake policy.\n";
return false;
}
//----------------------------------------------------------------------------
bool cmDocumentation::PrintDocumentationSingleVariable(std::ostream& os)
{
bool done = false;
for (std::vector<std::string>::iterator i =
this->VariableSections.begin();
!done && i != this->VariableSections.end(); ++i)
{
done = this->PrintDocumentationGeneric(os,i->c_str());
}
if (done)
{
return true;
}
// Argument was not a command. Complain.
os << "Argument \"" << this->CurrentArgument.c_str()
<< "\" to --help-variable is not a defined variable. "
<< "Use --help-variable-list to see all defined variables.\n";
return false;
}
//----------------------------------------------------------------------------
bool cmDocumentation::PrintDocumentationList(std::ostream& os,
const char *section)
{
if(this->AllSections.find(section) == this->AllSections.end())
{
os << "Internal error: " << section << " list is empty." << std::endl;
return false;
}
const std::vector<cmDocumentationEntry> &entries =
this->AllSections[section]->GetEntries();
for(std::vector<cmDocumentationEntry>::const_iterator ei =
entries.begin();
ei != entries.end(); ++ei)
{
if(ei->Name.size())
{
os << ei->Name << std::endl;
}
}
return true;
}
//----------------------------------------------------------------------------
bool cmDocumentation::PrintDocumentationUsage(std::ostream& os)
{
this->ClearSections();
this->AddSectionToPrint("Usage");
this->AddSectionToPrint("Options");
if(this->ShowGenerators)
{
this->AddSectionToPrint("Generators");
}
this->Print(os);
return true;
}
//----------------------------------------------------------------------------
bool cmDocumentation::PrintDocumentationFull(std::ostream& os)
{
this->CreateFullDocumentation();
this->CurrentFormatter->PrintHeader(GetNameString(), GetNameString(), os);
this->Print(os);
this->CurrentFormatter->PrintFooter(os);
return true;
}
//----------------------------------------------------------------------------
bool cmDocumentation::PrintDocumentationModules(std::ostream& os)
{
this->ClearSections();
this->CreateModulesSection();
this->AddDocumentIntroToPrint(GET_DOCUMENT_INTRO(Modules));
this->AddSectionToPrint("Description");
this->AddSectionToPrint("Modules");
this->AddSectionToPrint("Copyright");
this->AddSectionToPrint("See Also");
this->CurrentFormatter->PrintHeader(GetDocName(), GetNameString(), os);
this->Print(os);
this->CurrentFormatter->PrintFooter(os);
return true;
}
//----------------------------------------------------------------------------
bool cmDocumentation::PrintDocumentationCustomModules(std::ostream& os)
{
this->ClearSections();
this->CreateCustomModulesSection();
this->AddDocumentIntroToPrint(GET_DOCUMENT_INTRO(CustomModules));
this->AddSectionToPrint("Description");
this->AddSectionToPrint("Custom CMake Modules");
// the custom modules are most probably not under Kitware's copyright, Alex
// this->AddSectionToPrint("Copyright");
this->AddSectionToPrint("See Also");
this->CurrentFormatter->PrintHeader(GetDocName(), GetNameString(), os);
this->Print(os);
this->CurrentFormatter->PrintFooter(os);
return true;
}
//----------------------------------------------------------------------------
bool cmDocumentation::PrintDocumentationPolicies(std::ostream& os)
{
this->ClearSections();
this->AddDocumentIntroToPrint(GET_DOCUMENT_INTRO(Policies));
this->AddSectionToPrint("Description");
this->AddSectionToPrint("Policies");
this->AddSectionToPrint("Copyright");
this->AddSectionToPrint("See Also");
this->CurrentFormatter->PrintHeader(GetDocName(), GetNameString(), os);
this->Print(os);
this->CurrentFormatter->PrintFooter(os);
return true;
}
//----------------------------------------------------------------------------
bool cmDocumentation::PrintDocumentationProperties(std::ostream& os)
{
this->ClearSections();
this->AddDocumentIntroToPrint(GET_DOCUMENT_INTRO(Properties));
this->AddSectionToPrint("Properties Description");
for (std::vector<std::string>::iterator i =
this->PropertySections.begin();
i != this->PropertySections.end(); ++i)
{
this->AddSectionToPrint(i->c_str());
}
this->AddSectionToPrint("Copyright");
this->AddSectionToPrint("Standard See Also");
this->CurrentFormatter->PrintHeader(GetDocName(), GetNameString(), os);
this->Print(os);
this->CurrentFormatter->PrintFooter(os);
return true;
}
//----------------------------------------------------------------------------
bool cmDocumentation::PrintDocumentationVariables(std::ostream& os)
{
this->ClearSections();
this->AddDocumentIntroToPrint(GET_DOCUMENT_INTRO(Variables));
for (std::vector<std::string>::iterator i =
this->VariableSections.begin();
i != this->VariableSections.end(); ++i)
{
this->AddSectionToPrint(i->c_str());
}
this->AddSectionToPrint("Copyright");
this->AddSectionToPrint("Standard See Also");
this->CurrentFormatter->PrintHeader(GetDocName(), GetNameString(), os);
this->Print(os);
this->CurrentFormatter->PrintFooter(os);
return true;
}
//----------------------------------------------------------------------------
bool cmDocumentation::PrintDocumentationCurrentCommands(std::ostream& os)
{
this->ClearSections();
this->AddDocumentIntroToPrint(GET_DOCUMENT_INTRO(Commands));
this->AddSectionToPrint("Commands");
this->AddSectionToPrint("Copyright");
this->AddSectionToPrint("Standard See Also");
this->CurrentFormatter->PrintHeader(GetDocName(), GetNameString(), os);
this->Print(os);
this->CurrentFormatter->PrintFooter(os);
return true;
}
//----------------------------------------------------------------------------
bool cmDocumentation::PrintDocumentationCompatCommands(std::ostream& os)
{
this->ClearSections();
this->AddDocumentIntroToPrint(GET_DOCUMENT_INTRO(CompatCommands));
this->AddSectionToPrint("Compatibility Commands Description");
this->AddSectionToPrint("Compatibility Commands");
this->AddSectionToPrint("Copyright");
this->AddSectionToPrint("Standard See Also");
this->CurrentFormatter->PrintHeader(GetDocName(), GetNameString(), os);
this->Print(os);
this->CurrentFormatter->PrintFooter(os);
return true;
}
//----------------------------------------------------------------------------
void cmDocumentation
::PrintDocumentationCommand(std::ostream& os,
const cmDocumentationEntry &entry)
{
// the string "SingleItem" will be used in a few places to detect the case
// that only the documentation for a single item is printed
cmDocumentationSection *sec = new cmDocumentationSection("SingleItem","");
sec->Append(entry);
this->AllSections["temp"] = sec;
this->ClearSections();
this->AddSectionToPrint("temp");
this->Print(os);
this->AllSections.erase("temp");
delete sec;
}
//----------------------------------------------------------------------------
void cmDocumentation::CreateFullDocumentation()
{
this->ClearSections();
this->CreateCustomModulesSection();
this->CreateModulesSection();
std::set<std::string> emitted;
this->AddSectionToPrint("Name");
emitted.insert("Name");
this->AddSectionToPrint("Usage");
emitted.insert("Usage");
this->AddSectionToPrint("Description");
emitted.insert("Description");
this->AddSectionToPrint("Options");
emitted.insert("Options");
this->AddSectionToPrint("Generators");
emitted.insert("Generators");
this->AddSectionToPrint("Commands");
emitted.insert("Commands");
this->AddSectionToPrint("Properties Description");
emitted.insert("Properties Description");
for (std::vector<std::string>::iterator i =
this->PropertySections.begin();
i != this->PropertySections.end(); ++i)
{
this->AddSectionToPrint(i->c_str());
emitted.insert(i->c_str());
}
emitted.insert("Copyright");
emitted.insert("See Also");
emitted.insert("Standard See Also");
emitted.insert("Author");
// add any sections not yet written out, or to be written out
for (std::map<std::string, cmDocumentationSection*>::iterator i =
this->AllSections.begin();
i != this->AllSections.end(); ++i)
{
if (emitted.find(i->first) == emitted.end())
{
this->AddSectionToPrint(i->first.c_str());
}
}
this->AddSectionToPrint("Copyright");
if(this->CurrentFormatter->GetForm() == ManForm)
{
this->AddSectionToPrint("See Also");
this->AddSectionToPrint("Author");
}
else
{
this->AddSectionToPrint("Standard See Also");
}
}
//----------------------------------------------------------------------------
void cmDocumentation::SetForm(Form f)
{
switch(f)
{
case HTMLForm:
this->CurrentFormatter = &this->HTMLFormatter;
break;
case DocbookForm:
this->CurrentFormatter = &this->DocbookFormatter;
break;
case ManForm:
this->CurrentFormatter = &this->ManFormatter;
break;
case TextForm:
this->CurrentFormatter = &this->TextFormatter;
break;
case UsageForm:
this->CurrentFormatter = & this->UsageFormatter;
break;
}
}
//----------------------------------------------------------------------------
const char* cmDocumentation::GetNameString() const
{
if(this->NameString.length() > 0)
{
return this->NameString.c_str();
}
else
{
return "CMake";
}
}
//----------------------------------------------------------------------------
const char* cmDocumentation::GetDocName(bool fallbackToNameString) const
{
if (this->DocName.length() > 0)
{
return this->DocName.c_str();
}
else if (fallbackToNameString)
{
return this->GetNameString();
}
else
return 0;
}
//----------------------------------------------------------------------------
#define CASE_DEFAULT_DOCNAME(doctype) \
case cmDocumentation::doctype : \
return GET_DOCUMENT_INTRO(doctype)[0];
const char* cmDocumentation::GetDefaultDocName(Type ht) const
{
switch (ht)
{
CASE_DEFAULT_DOCNAME(Modules)
CASE_DEFAULT_DOCNAME(CustomModules)
CASE_DEFAULT_DOCNAME(Policies)
CASE_DEFAULT_DOCNAME(Properties)
CASE_DEFAULT_DOCNAME(Variables)
CASE_DEFAULT_DOCNAME(Commands)
CASE_DEFAULT_DOCNAME(CompatCommands)
default: break;
}
return 0;
}
//----------------------------------------------------------------------------
bool cmDocumentation::IsOption(const char* arg) const
{
return ((arg[0] == '-') || (strcmp(arg, "/V") == 0) ||
(strcmp(arg, "/?") == 0));
}