/*========================================================================= 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" #include "cmVersion.h" #include //---------------------------------------------------------------------------- static const cmDocumentationEntry cmDocumentationStandardOptions[] = { {"--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 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 cmDocumentationEntry cmDocumentationCommandsHeader[] = { {0, "The following commands are available in CMakeLists.txt code:", 0}, {0,0,0} }; //---------------------------------------------------------------------------- static const cmDocumentationEntry cmDocumentationPropertiesHeader[] = { {0, "The following properties are available in CMakeLists.txt code:", 0}, {0,0,0} }; //---------------------------------------------------------------------------- static const cmDocumentationEntry cmDocumentationModulesHeader[] = { {0, "The following modules are provided with CMake. " "They can be used with INCLUDE(ModuleName).", 0}, {0,0,0} }; //---------------------------------------------------------------------------- static const cmDocumentationEntry cmDocumentationGeneratorsHeader[] = { {0, "The following generators are available on this platform:", 0}, {0,0,0} }; //---------------------------------------------------------------------------- static const cmDocumentationEntry cmDocumentationStandardSeeAlso[] = { {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} }; //---------------------------------------------------------------------------- const cmDocumentationEntry cmDocumentationAuthor[] = { {0, "This manual page was generated by the \"--help-man\" option.", 0}, {0,0,0} }; //---------------------------------------------------------------------------- const cmDocumentationEntry cmDocumentationCopyright[] = { {0, "Copyright (c) 2002 Kitware, Inc., Insight 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}, {"", "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.", 0}, {"", "Modified source versions must be plainly marked as such, and must " "not be misrepresented as being the original software.", 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.", 0}, {0, 0, 0} }; //---------------------------------------------------------------------------- cmDocumentation::cmDocumentation() { this->CurrentForm = TextForm; this->TextIndent = ""; this->TextWidth = 77; } //---------------------------------------------------------------------------- cmDocumentation::~cmDocumentation() { for(std::vector< char* >::iterator i = this->ModuleStrings.begin(); i != this->ModuleStrings.end(); ++i) { delete [] *i; } } //---------------------------------------------------------------------------- bool cmDocumentation::PrintCopyright(std::ostream& os) { for(const cmDocumentationEntry* op = cmDocumentationCopyright; op->brief; ++op) { if(op->name) { os << " * "; this->TextIndent = " "; this->PrintColumn(os, op->brief); } else { this->TextIndent = ""; this->PrintColumn(os, op->brief); } os << "\n"; } return true; } //---------------------------------------------------------------------------- bool cmDocumentation::PrintVersion(std::ostream& os) { os << this->GetNameString() << " version " << cmVersion::GetCMakeVersion() << "\n"; return true; } //---------------------------------------------------------------------------- void cmDocumentation::AddSection(const char* name, const cmDocumentationEntry* d) { this->Names.push_back(name); this->Sections.push_back(d); } //---------------------------------------------------------------------------- void cmDocumentation::ClearSections() { this->Names.erase(this->Names.begin(), this->Names.end()); this->Sections.erase(this->Sections.begin(), this->Sections.end()); } //---------------------------------------------------------------------------- bool cmDocumentation::PrintDocumentation(Type ht, std::ostream& os) { if ( ht != cmDocumentation::HTML && ht != cmDocumentation::Man ) { this->PrintVersion(os); } 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::SingleProperty: return this->PrintDocumentationSingleProperty(os); case cmDocumentation::List: return this->PrintDocumentationList(os); case cmDocumentation::ModuleList: return this->PrintModuleList(os); case cmDocumentation::PropertyList: return this->PrintPropertyList(os); case cmDocumentation::Full: return this->PrintDocumentationFull(os); case cmDocumentation::HTML: return this->PrintDocumentationHTML(os); case cmDocumentation::Man: return this->PrintDocumentationMan(os); case cmDocumentation::Copyright: return this->PrintCopyright(os); case cmDocumentation::Version: return true; default: return false; } } //---------------------------------------------------------------------------- bool cmDocumentation::CreateModulesSection() { this->ModulesSection.push_back(cmDocumentationModulesHeader[0]); std::string cmakeModules = this->CMakeRoot; cmakeModules += "/Modules"; cmsys::Directory dir; dir.Load(cmakeModules.c_str()); for(unsigned int i = 0; i < dir.GetNumberOfFiles(); ++i) { std::string fname = dir.GetFile(i); if(fname.length() > 6) { if(fname.substr(fname.length()-6, 6) == ".cmake") { std::string moduleName = fname.substr(0, fname.length()-6); std::string path = cmakeModules; path += "/"; path += fname; this->CreateSingleModule(path.c_str(), moduleName.c_str()); } } } cmDocumentationEntry e = { 0, 0, 0 }; this->ModulesSection.push_back(e); return true; } //---------------------------------------------------------------------------- bool cmDocumentation::CreateSingleModule(const char* fname, const char* moduleName) { 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 { 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); cmDocumentationEntry e = { pname, pbrief, ptext }; this->ModulesSection.push_back(e); return true; } } return true; } //---------------------------------------------------------------------------- bool cmDocumentation::PrintRequestedDocumentation(std::ostream& os) { bool result = true; // Loop over requested documentation types. for(RequestedMapType::const_iterator i = this->RequestedMap.begin(); i != this->RequestedMap.end(); ++i) { // Special case for printing help for a single command. if(i->first == cmDocumentation::Usage && i->second.length() > 0 && !this->CommandsSection.empty()) { // Check if the argument to the usage request was a command. for(cmDocumentationEntry* entry = &this->CommandsSection[0]; entry->brief; ++entry) { if(entry->name && (strcmp(entry->name, i->second.c_str()) == 0)) { this->PrintDocumentationCommand(os, entry); return true; } } // Argument was not a command. Complain. os << "Help argument \"" << i->second.c_str() << "\" is not a CMake command. " << "Use --help-command-list to see all commands.\n"; return false; } // If a file name was given, use it. Otherwise, default to the // given stream. std::ofstream* fout = 0; std::ostream* s = &os; if(i->second.length() > 0) { fout = new std::ofstream(i->second.c_str(), std::ios::out); if(fout) { s = fout; } else { result = false; } } // Print this documentation type to the stream. if(!this->PrintDocumentation(i->first, *s) || !*s) { result = false; } // Close the file if we wrote one. if(fout) { delete fout; } } return result; } //---------------------------------------------------------------------------- bool cmDocumentation::CheckOptions(int argc, const char* const* argv) { // Providing zero arguments gives usage information. if(argc == 1) { this->RequestedMap[cmDocumentation::Usage] = ""; return true; } // Search for supported help options. bool result = false; for(int i=1; i < argc; ++i) { // Check if this is a supported help option. Type type = cmDocumentation::None; 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)) { type = cmDocumentation::Usage; } else if(strcmp(argv[i], "--help-full") == 0) { type = cmDocumentation::Full; } else if(strcmp(argv[i], "--help-html") == 0) { type = cmDocumentation::HTML; } else if(strcmp(argv[i], "--help-man") == 0) { type = cmDocumentation::Man; } else if(strcmp(argv[i], "--help-command") == 0) { type = cmDocumentation::Single; if((i+1 < argc) && !this->IsOption(argv[i+1])) { this->SingleCommand = argv[i+1]; this->SingleCommand = cmSystemTools::UpperCase(this->SingleCommand); i = i+1; } } else if(strcmp(argv[i], "--help-module") == 0) { type = cmDocumentation::SingleModule; if((i+1 < argc) && !this->IsOption(argv[i+1])) { this->SingleModuleName = argv[i+1]; i = i+1; } } else if(strcmp(argv[i], "--help-property") == 0) { type = cmDocumentation::SingleProperty; if((i+1 < argc) && !this->IsOption(argv[i+1])) { this->SinglePropertyName = argv[i+1]; i = i+1; } } else if(strcmp(argv[i], "--help-command-list") == 0) { type = cmDocumentation::List; } else if(strcmp(argv[i], "--help-module-list") == 0) { type = cmDocumentation::ModuleList; } else if(strcmp(argv[i], "--help-property-list") == 0) { type = cmDocumentation::PropertyList; } else if(strcmp(argv[i], "--copyright") == 0) { type = cmDocumentation::Copyright; } else if((strcmp(argv[i], "--version") == 0) || (strcmp(argv[i], "-version") == 0) || (strcmp(argv[i], "/V") == 0)) { type = cmDocumentation::Version; } if(type) { // This is a help option. See if there is a file name given. result = true; if((i+1 < argc) && !this->IsOption(argv[i+1])) { this->RequestedMap[type] = argv[i+1]; i = i+1; } else { this->RequestedMap[type] = ""; } } } return result; } //---------------------------------------------------------------------------- void cmDocumentation::Print(Form f, std::ostream& os) { this->CurrentForm = f; for(unsigned int i=0; i < this->Sections.size(); ++i) { this->PrintSection(os, this->Sections[i], this->Names[i]); } } //---------------------------------------------------------------------------- void cmDocumentation::SetName(const char* name) { this->NameString = name?name:""; } //---------------------------------------------------------------------------- void cmDocumentation::SetNameSection(const cmDocumentationEntry* section) { this->SetSection(0, section, 0, this->NameSection); } //---------------------------------------------------------------------------- void cmDocumentation::SetUsageSection(const cmDocumentationEntry* section) { this->SetSection(0, section, 0, this->UsageSection); } //---------------------------------------------------------------------------- void cmDocumentation ::SetDescriptionSection(const cmDocumentationEntry* section) { this->SetSection(0, section, 0, this->DescriptionSection); } //---------------------------------------------------------------------------- void cmDocumentation::SetOptionsSection(const cmDocumentationEntry* section) { this->SetSection(0, section, cmDocumentationStandardOptions, this->OptionsSection); } //---------------------------------------------------------------------------- void cmDocumentation::SetCommandsSection(const cmDocumentationEntry* section) { this->SetSection(cmDocumentationCommandsHeader, section, 0, this->CommandsSection); } //---------------------------------------------------------------------------- void cmDocumentation ::SetPropertiesSection(const cmDocumentationEntry* section) { this->SetSection(cmDocumentationPropertiesHeader, section, 0, this->PropertiesSection); } //---------------------------------------------------------------------------- void cmDocumentation ::SetGeneratorsSection(const cmDocumentationEntry* section) { this->SetSection(cmDocumentationGeneratorsHeader, section, 0, this->GeneratorsSection); } //---------------------------------------------------------------------------- void cmDocumentation::SetSeeAlsoList(const cmDocumentationEntry* also) { this->SeeAlsoSection.clear(); this->SeeAlsoString = ".B "; for(const cmDocumentationEntry* i = also; i->brief; ++i) { this->SeeAlsoString += i->brief; this->SeeAlsoString += (i+1)->brief? "(1), ":"(1)"; } cmDocumentationEntry e = {0, 0, 0}; e.brief = this->SeeAlsoString.c_str(); this->SeeAlsoSection.push_back(e); for(const cmDocumentationEntry* i = cmDocumentationStandardSeeAlso; i->brief; ++i) { this->SeeAlsoSection.push_back(*i); } e.brief = 0; this->SeeAlsoSection.push_back(e); } //---------------------------------------------------------------------------- void cmDocumentation::PrintSection(std::ostream& os, const cmDocumentationEntry* section, const char* name) { switch (this->CurrentForm) { case TextForm: this->PrintSectionText(os, section, name); break; case HTMLForm: this->PrintSectionHTML(os, section, name); break; case ManForm: this->PrintSectionMan(os, section, name); break; case UsageForm: this->PrintSectionUsage(os, section, name); break; } } //---------------------------------------------------------------------------- void cmDocumentation::PrintSectionText(std::ostream& os, const cmDocumentationEntry* section, const char* name) { if(name) { os << "---------------------------------------" "---------------------------------------\n"; os << name << "\n\n"; } if(!section) { return; } for(const cmDocumentationEntry* op = section; op->brief; ++op) { if(op->name) { if(op->name[0]) { os << " " << op->name << "\n"; } this->TextIndent = " "; this->PrintFormatted(os, op->brief); if(op->full) { os << "\n"; this->PrintFormatted(os, op->full); } } else { this->TextIndent = ""; this->PrintFormatted(os, op->brief); } os << "\n"; } } //---------------------------------------------------------------------------- void cmDocumentation::PrintSectionHTML(std::ostream& os, const cmDocumentationEntry* section, const char* name) { if(name) { os << "

" << name << "

\n"; } if(!section) { return; } for(const cmDocumentationEntry* op = section; op->brief;) { if(op->name) { os << "\n"; } else { this->PrintFormatted(os, op->brief); os << "\n"; ++op; } } } //---------------------------------------------------------------------------- void cmDocumentation::PrintSectionMan(std::ostream& os, const cmDocumentationEntry* section, const char* name) { if(name) { os << ".SH " << name << "\n"; } if(!section) { return; } for(const cmDocumentationEntry* op = section; op->brief; ++op) { if(op->name) { os << ".TP\n" << ".B " << (op->name[0]?op->name:"*") << "\n"; this->PrintFormatted(os, op->brief); this->PrintFormatted(os, op->full); } else { os << ".PP\n"; this->PrintFormatted(os, op->brief); } } } //---------------------------------------------------------------------------- void cmDocumentation::PrintSectionUsage(std::ostream& os, const cmDocumentationEntry* section, const char* name) { if(name) { os << name << "\n"; } if(!section) { return; } for(const cmDocumentationEntry* op = section; op->brief; ++op) { if(op->name) { os << " " << op->name; this->TextIndent = " "; int align = static_cast(strlen(this->TextIndent))-4; for(int i = static_cast(strlen(op->name)); i < align; ++i) { os << " "; } if ( strlen(op->name) > strlen(this->TextIndent)-4 ) { os << "\n"; os.write(this->TextIndent, strlen(this->TextIndent)-2); } os << "= "; this->PrintColumn(os, op->brief); os << "\n"; } else { os << "\n"; this->TextIndent = ""; this->PrintFormatted(os, op->brief); } } os << "\n"; } //---------------------------------------------------------------------------- void cmDocumentation::PrintFormatted(std::ostream& os, const char* text) { if(!text) { return; } const char* ptr = text; while(*ptr) { // Any ptrs starting in a space are treated as preformatted text. std::string preformatted; while(*ptr == ' ') { for(char ch = *ptr; ch && ch != '\n'; ++ptr, ch = *ptr) { preformatted.append(1, ch); } if(*ptr) { ++ptr; preformatted.append(1, '\n'); } } if(preformatted.length()) { this->PrintPreformatted(os, preformatted.c_str()); } // Other ptrs are treated as paragraphs. std::string paragraph; for(char ch = *ptr; ch && ch != '\n'; ++ptr, ch = *ptr) { paragraph.append(1, ch); } if(*ptr) { ++ptr; paragraph.append(1, '\n'); } if(paragraph.length()) { this->PrintParagraph(os, paragraph.c_str()); } } } //---------------------------------------------------------------------------- void cmDocumentation::PrintPreformatted(std::ostream& os, const char* text) { switch (this->CurrentForm) { case TextForm: this->PrintPreformattedText(os, text); break; case HTMLForm: this->PrintPreformattedHTML(os, text); break; case ManForm: this->PrintPreformattedMan(os, text); break; case UsageForm: this->PrintPreformattedText(os, text); break; } } //---------------------------------------------------------------------------- void cmDocumentation::PrintParagraph(std::ostream& os, const char* text) { switch (this->CurrentForm) { case TextForm: this->PrintParagraphText(os, text); break; case HTMLForm: this->PrintParagraphHTML(os, text); break; case ManForm: this->PrintParagraphMan(os, text); break; case UsageForm: this->PrintParagraphText(os, text); break; } } //---------------------------------------------------------------------------- void cmDocumentation ::PrintPreformattedText(std::ostream& os, const char* text) { bool newline = true; for(const char* ptr = text; *ptr; ++ptr) { if(newline) { os << this->TextIndent; newline = false; } os << *ptr; if(*ptr == '\n') { newline = true; } } os << "\n"; } //---------------------------------------------------------------------------- void cmDocumentation::PrintParagraphText(std::ostream& os, const char* text) { os << this->TextIndent; this->PrintColumn(os, text); os << "\n"; } //---------------------------------------------------------------------------- void cmDocumentation ::PrintPreformattedHTML(std::ostream& os, const char* text) { os << "
";
  this->PrintHTMLEscapes(os, text);
  os << "
\n "; } //---------------------------------------------------------------------------- void cmDocumentation::PrintParagraphHTML(std::ostream& os, const char* text) { os << "

"; this->PrintHTMLEscapes(os, text); } //---------------------------------------------------------------------------- void cmDocumentation::PrintPreformattedMan(std::ostream& os, const char* text) { std::string man_text = text; cmSystemTools::ReplaceString(man_text, "\\", "\\\\"); os << man_text << "\n"; } //---------------------------------------------------------------------------- void cmDocumentation::PrintParagraphMan(std::ostream& os, const char* text) { std::string man_text = text; cmSystemTools::ReplaceString(man_text, "\\", "\\\\"); os << man_text << "\n\n"; } //---------------------------------------------------------------------------- void cmDocumentation::PrintColumn(std::ostream& os, const char* text) { // Print text arranged in an indented column of fixed witdh. const char* l = text; int column = 0; bool newSentence = false; bool firstLine = true; int width = this->TextWidth - static_cast(strlen(this->TextIndent)); // Loop until the end of the text. 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 << (firstLine?"":this->TextIndent); } // Print the word. os.write(l, static_cast(r-l)); newSentence = (*(r-1) == '.'); } if(*r == '\n') { // Text provided a newline. Start a new line. os << "\n"; ++r; column = 0; firstLine = false; } else { // No provided newline. Continue this line. column += static_cast(r-l); } } else { // Word does not fit on this line. Start a new line. os << "\n"; firstLine = false; if(r > l) { os << this->TextIndent; os.write(l, static_cast(r-l)); column = static_cast(r-l); newSentence = (*(r-1) == '.'); } else { column = 0; } } // Move to beginning of next word. Skip over whitespace. l = r; while(*l && (*l == ' ')) { ++l; } } } //---------------------------------------------------------------------------- static bool cmDocumentationIsHyperlinkChar(char c) { // This is not a complete list but works for CMake documentation. return ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '-' || c == '.' || c == '/' || c == '~' || c == '@' || c == ':' || c == '_' || c == '&' || c == '?' || c == '='); } //---------------------------------------------------------------------------- static void cmDocumentationPrintHTMLChar(std::ostream& os, char c) { // Use an escape sequence if necessary. static cmDocumentationEntry escapes[] = { {"<", "<", 0}, {">", ">", 0}, {"&", "&", 0}, {"\n", "
", 0}, {0,0,0} }; for(const cmDocumentationEntry* op = escapes; op->name; ++op) { if(op->name[0] == c) { os << op->brief; return; } } // No escape sequence is needed. os << c; } //---------------------------------------------------------------------------- const char* cmDocumentationPrintHTMLLink(std::ostream& os, const char* begin) { // Look for the end of the link. const char* end = begin; while(cmDocumentationIsHyperlinkChar(*end)) { ++end; } // Print the hyperlink itself. os << ""; // The name of the hyperlink is the text itself. for(const char* c = begin; c != end; ++c) { cmDocumentationPrintHTMLChar(os, *c); } os << ""; // Return the position at which to continue scanning the input // string. return end; } //---------------------------------------------------------------------------- void cmDocumentation::PrintHTMLEscapes(std::ostream& os, const char* text) { // Hyperlink prefixes. static const char* hyperlinks[] = {"http://", "ftp://", "mailto:", 0}; // Print each character. for(const char* p = text; *p;) { // Handle hyperlinks specially to make them active. bool found_hyperlink = false; for(const char** h = hyperlinks; !found_hyperlink && *h; ++h) { if(strncmp(p, *h, strlen(*h)) == 0) { p = cmDocumentationPrintHTMLLink(os, p); found_hyperlink = true; } } // Print other characters normally. if(!found_hyperlink) { cmDocumentationPrintHTMLChar(os, *p++); } } } //---------------------------------------------------------------------------- bool cmDocumentation::PrintDocumentationSingle(std::ostream& os) { if(this->CommandsSection.empty()) { os << "Internal error: commands list is empty." << std::endl; return false; } if(this->SingleCommand.length() == 0) { os << "Argument --help-command needs a command name.\n"; return false; } for(cmDocumentationEntry* entry = &this->CommandsSection[0]; entry->brief; ++entry) { if(entry->name && this->SingleCommand == entry->name) { this->PrintDocumentationCommand(os, entry); return true; } } // Argument was not a command. Complain. os << "Argument \"" << this->SingleCommand.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->SingleModuleName.length() == 0) { os << "Argument --help-module needs a module name.\n"; return false; } std::string cmakeModules = this->CMakeRoot; cmakeModules += "/Modules/"; cmakeModules += this->SingleModuleName; cmakeModules += ".cmake"; if(cmSystemTools::FileExists(cmakeModules.c_str()) && this->CreateSingleModule(cmakeModules.c_str(), this->SingleModuleName.c_str())) { this->PrintDocumentationCommand(os, &this->ModulesSection[0]); os << "\n Defined in: "; os << cmakeModules << "\n"; return true; } // Argument was not a module. Complain. os << "Argument \"" << this->SingleModuleName.c_str() << "\" to --help-module is not a CMake module."; return false; } //---------------------------------------------------------------------------- bool cmDocumentation::PrintDocumentationSingleProperty(std::ostream& os) { if(this->PropertiesSection.empty()) { os << "Internal error: properties list is empty." << std::endl; return false; } if(this->SinglePropertyName.length() == 0) { os << "Argument --help-property needs a property name.\n"; return false; } for(cmDocumentationEntry* entry = &this->PropertiesSection[0]; entry->brief; ++entry) { if(entry->name && this->SinglePropertyName == entry->name) { this->PrintDocumentationCommand(os, entry); return true; } } // Argument was not a command. Complain. os << "Argument \"" << this->SinglePropertyName.c_str() << "\" to --help-property is not a CMake property. " << "Use --help-property-list to see all properties.\n"; return false; } //---------------------------------------------------------------------------- bool cmDocumentation::PrintDocumentationList(std::ostream& os) { if(this->CommandsSection.empty()) { os << "Internal error: commands list is empty." << std::endl; return false; } for(cmDocumentationEntry* entry = &this->CommandsSection[0]; entry->brief; ++entry) { if(entry->name) { os << entry->name << std::endl; } } return true; } //---------------------------------------------------------------------------- bool cmDocumentation::PrintPropertyList(std::ostream& os) { if(this->PropertiesSection.empty()) { os << "Internal error: properties list is empty." << std::endl; return false; } for(cmDocumentationEntry* entry = &this->PropertiesSection[0]; entry->brief; ++entry) { if(entry->name) { os << entry->name << std::endl; } } return true; } //---------------------------------------------------------------------------- bool cmDocumentation::PrintModuleList(std::ostream& os) { this->CreateModulesSection(); if(this->ModulesSection.empty()) { os << "Internal error: modules list is empty." << std::endl; return false; } for(cmDocumentationEntry* entry = &this->ModulesSection[0]; entry->brief; ++entry) { if(entry->name) { os << entry->name << std::endl; } } return true; } //---------------------------------------------------------------------------- bool cmDocumentation::PrintDocumentationUsage(std::ostream& os) { this->CreateUsageDocumentation(); this->Print(UsageForm, os); return true; } //---------------------------------------------------------------------------- bool cmDocumentation::PrintDocumentationFull(std::ostream& os) { this->CreateFullDocumentation(); this->Print(TextForm, os); return true; } //---------------------------------------------------------------------------- bool cmDocumentation::PrintDocumentationHTML(std::ostream& os) { this->CreateFullDocumentation(); os << "\n"; this->Print(HTMLForm, os); os << "\n"; return true; } //---------------------------------------------------------------------------- bool cmDocumentation::PrintDocumentationMan(std::ostream& os) { this->CreateManDocumentation(); os << ".TH " << this->GetNameString() << " 1 \"" << cmSystemTools::GetCurrentDateTime("%B %d, %Y").c_str() << "\" \"" << this->GetNameString() << " " << cmVersion::GetCMakeVersion() << "\"\n"; this->Print(ManForm, os); return true; } //---------------------------------------------------------------------------- void cmDocumentation::PrintDocumentationCommand(std::ostream& os, cmDocumentationEntry* entry) { cmDocumentationEntry singleCommandSection[3] = { {entry->name, entry->brief, entry->full}, {0,0,0} }; this->ClearSections(); this->AddSection(0, &singleCommandSection[0]); this->Print(TextForm, os); } //---------------------------------------------------------------------------- void cmDocumentation::CreateUsageDocumentation() { this->ClearSections(); if(!this->UsageSection.empty()) { this->AddSection("Usage", &this->UsageSection[0]); } if(!this->OptionsSection.empty()) { this->AddSection("Command-Line Options", &this->OptionsSection[0]); } if(!this->GeneratorsSection.empty()) { this->AddSection("Generators", &this->GeneratorsSection[0]); } } //---------------------------------------------------------------------------- void cmDocumentation::CreateFullDocumentation() { this->ClearSections(); if(!this->NameSection.empty()) { this->AddSection("Name", &this->NameSection[0]); } if(!this->UsageSection.empty()) { this->AddSection("Usage", &this->UsageSection[0]); } if(!this->DescriptionSection.empty()) { this->AddSection(0, &this->DescriptionSection[0]); } if(!this->OptionsSection.empty()) { this->AddSection("Command-Line Options", &this->OptionsSection[0]); } if(!this->GeneratorsSection.empty()) { this->AddSection("Generators", &this->GeneratorsSection[0]); } if(!this->CommandsSection.empty()) { this->AddSection("Listfile Commands", &this->CommandsSection[0]); } this->CreateModulesSection(); if(!this->ModulesSection.empty()) { this->AddSection("Standard CMake Modules", &this->ModulesSection[0]); } if(!this->PropertiesSection.empty()) { this->AddSection("Standard Properties", &this->PropertiesSection[0]); } this->AddSection("Copyright", cmDocumentationCopyright); this->AddSection("See Also", cmDocumentationStandardSeeAlso); } //---------------------------------------------------------------------------- void cmDocumentation::CreateManDocumentation() { this->ClearSections(); if(!this->NameSection.empty()) { this->AddSection("NAME", &this->NameSection[0]); } if(!this->UsageSection.empty()) { this->AddSection("SYNOPSIS", &this->UsageSection[0]); } if(!this->DescriptionSection.empty()) { this->AddSection("DESCRIPTION", &this->DescriptionSection[0]); } if(!this->OptionsSection.empty()) { this->AddSection("OPTIONS", &this->OptionsSection[0]); } if(!this->GeneratorsSection.empty()) { this->AddSection("GENERATORS", &this->GeneratorsSection[0]); } if(!this->CommandsSection.empty()) { this->AddSection("COMMANDS", &this->CommandsSection[0]); } this->CreateModulesSection(); if(!this->ModulesSection.empty()) { this->AddSection("MODULES", &this->ModulesSection[0]); } this->AddSection("COPYRIGHT", cmDocumentationCopyright); if(!this->SeeAlsoSection.empty()) { this->AddSection("SEE ALSO", &this->SeeAlsoSection[0]); } this->AddSection("AUTHOR", cmDocumentationAuthor); } //---------------------------------------------------------------------------- void cmDocumentation::SetSection(const cmDocumentationEntry* header, const cmDocumentationEntry* section, const cmDocumentationEntry* footer, std::vector& vec) { vec.erase(vec.begin(), vec.end()); if(header) { for(const cmDocumentationEntry* op = header; op->brief; ++op) { vec.push_back(*op); } } if(section) { for(const cmDocumentationEntry* op = section; op->brief; ++op) { vec.push_back(*op); } } if(footer) { for(const cmDocumentationEntry* op = footer; op->brief; ++op) { vec.push_back(*op); } } cmDocumentationEntry empty = {0,0,0}; vec.push_back(empty); } //---------------------------------------------------------------------------- const char* cmDocumentation::GetNameString() { if(this->NameString.length() > 0) { return this->NameString.c_str(); } else { return "CMake"; } } //---------------------------------------------------------------------------- bool cmDocumentation::IsOption(const char* arg) { return ((arg[0] == '-') || (strcmp(arg, "/V") == 0) || (strcmp(arg, "/?") == 0)); }