/*========================================================================= 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}, {"--help", "Print usage information and exit.", "Usage describes the basic command line interface and its options."}, {"--help-full", "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."}, {"--help-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} }; //---------------------------------------------------------------------------- static const cmDocumentationEntry cmDocumentationCommandsHeader[] = { {0, "The following commands are available in CMakeLists.txt code:", 0}, {0,0,0} }; //---------------------------------------------------------------------------- const cmDocumentationEntry cmDocumentationMailingList[] = { {0, "For help and discussion about using cmake, a mailing list is provided " "at cmake@www.cmake.org. Please first read the full documentation at " "http://www.cmake.org before posting questions to the list.", 0}, {0,0,0} }; //---------------------------------------------------------------------------- const cmDocumentationEntry cmDocumentationAuthor[] = { {0, "This manual page was generated by \"cmake --help-man\".", 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; } //---------------------------------------------------------------------------- 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->TextIndent = " "; this->PrintColumn(os, op->brief); } else { this->TextIndent = ""; this->PrintColumn(os, op->brief); } os << "\n"; } } //---------------------------------------------------------------------------- void cmDocumentation::PrintVersion(std::ostream& os) { os << "CMake version " CMake_VERSION_STRING "\n"; } //---------------------------------------------------------------------------- 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()); } //---------------------------------------------------------------------------- void cmDocumentation::PrintDocumentation(Type ht, std::ostream& os) { switch (ht) { case cmDocumentation::Usage: this->PrintDocumentationUsage(os); break; case cmDocumentation::Full: this->PrintDocumentationFull(os); break; case cmDocumentation::HTML: this->PrintDocumentationHTML(os); break; case cmDocumentation::Man: this->PrintDocumentationMan(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) { // Providing zero arguments gives usage information. if(argc == 1) { return cmDocumentation::Usage; } // Search for supported help options. for(int i=1; i < argc; ++i) { 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)) { return cmDocumentation::Usage; } if(strcmp(argv[i], "--help-full") == 0) { return cmDocumentation::Full; } if(strcmp(argv[i], "--help-html") == 0) { return cmDocumentation::HTML; } if(strcmp(argv[i], "--help-man") == 0) { return cmDocumentation::Man; } if(strcmp(argv[i], "--copyright") == 0) { return cmDocumentation::Copyright; } if((strcmp(argv[i], "--version") == 0) || (strcmp(argv[i], "-version") == 0) || (strcmp(argv[i], "-V") == 0) || (strcmp(argv[i], "/V") == 0)) { return cmDocumentation::Version; } } return cmDocumentation::None; } //---------------------------------------------------------------------------- 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::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::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 << 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 << " "; } 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) { os << text << "\n"; } //---------------------------------------------------------------------------- void cmDocumentation::PrintParagraphMan(std::ostream& os, const char* text) { os << 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) == '.'); } } // Move to beginning of next word. Skip over whitespace. l = r; while(*l && (*l == ' ')) { ++l; } } } //---------------------------------------------------------------------------- void cmDocumentation::PrintHTMLEscapes(std::ostream& os, const char* text) { static cmDocumentationEntry escapes[] = { {"<", "<", 0}, {">", ">", 0}, {"&", "&", 0}, {"\n", "
", 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::PrintDocumentationUsage(std::ostream& os) { this->CreateUsageDocumentation(); this->Print(UsageForm, os); } //---------------------------------------------------------------------------- void cmDocumentation::PrintDocumentationFull(std::ostream& os) { this->CreateFullDocumentation(); this->Print(TextForm, os); } //---------------------------------------------------------------------------- void cmDocumentation::PrintDocumentationHTML(std::ostream& os) { this->CreateFullDocumentation(); os << "\n"; this->Print(HTMLForm, os); os << "\n"; } //---------------------------------------------------------------------------- void cmDocumentation::PrintDocumentationMan(std::ostream& os) { this->CreateManDocumentation(); os << ".TH CMake 1 \"" << cmSystemTools::GetCurrentDateTime("%B %d, %Y").c_str() << "\" \"CMake " CMake_VERSION_STRING "\"\n"; this->Print(ManForm, os); } //---------------------------------------------------------------------------- void cmDocumentation::CreateUsageDocumentation() { this->ClearSections(); if(!this->NameSection.empty()) { this->AddSection("Name", &this->NameSection[0]); } if(!this->UsageSection.empty()) { this->AddSection("Usage", &this->UsageSection[0]); } if(!this->OptionsSection.empty()) { this->AddSection("Command-Line Options", &this->OptionsSection[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->CommandsSection.empty()) { this->AddSection("Listfile Commands", &this->CommandsSection[0]); } this->AddSection("Copyright", cmDocumentationCopyright); this->AddSection("Mailing List", cmDocumentationMailingList); } //---------------------------------------------------------------------------- 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->CommandsSection.empty()) { this->AddSection("COMMANDS", &this->CommandsSection[0]); } this->AddSection("COPYRIGHT", cmDocumentationCopyright); this->AddSection("MAILING LIST", cmDocumentationMailingList); 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); }