diff --git a/Source/CursesDialog/ccmake.cxx b/Source/CursesDialog/ccmake.cxx index 47ae7ee55..a9386a2cb 100644 --- a/Source/CursesDialog/ccmake.cxx +++ b/Source/CursesDialog/ccmake.cxx @@ -30,8 +30,8 @@ //---------------------------------------------------------------------------- static const cmDocumentationEntry cmDocumentationName[] = { - {"ccmake", - "- Curses Interface for CMake.", 0}, + {0, + " ccmake - Curses Interface for CMake.", 0}, {0,0,0} }; @@ -39,7 +39,7 @@ static const cmDocumentationEntry cmDocumentationName[] = static const cmDocumentationEntry cmDocumentationUsage[] = { {0, - "ccmake ", 0}, + " ccmake ", 0}, {0,0,0} }; @@ -88,10 +88,15 @@ int main(int argc, char** argv) cmDocumentation doc; if(cmDocumentation::Type ht = doc.CheckOptions(argc, argv)) { - doc.SetName(cmDocumentationName); - doc.SetUsage(cmDocumentationUsage); - doc.SetDescription(cmDocumentationDescription); - doc.Print(ht, std::cout); + cmake hcm; + std::vector commands; + hcm.GetCommandDocumentation(commands); + doc.SetNameSection(cmDocumentationName); + doc.SetUsageSection(cmDocumentationUsage); + doc.SetDescriptionSection(cmDocumentationDescription); + doc.SetOptionsSection(0); + doc.SetCommandsSection(&commands[0]); + doc.PrintDocumentation(ht, std::cout); return 0; } diff --git a/Source/cmDocumentation.cxx b/Source/cmDocumentation.cxx index 8ea414e62..1e2e69573 100644 --- a/Source/cmDocumentation.cxx +++ b/Source/cmDocumentation.cxx @@ -49,37 +49,45 @@ 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 " + "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.\n" - "All rights reserved.\n", 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:\n", 0}, - {" * ", + "met:", 0}, + {"", "Redistributions of source code must retain the above copyright notice, " - "this list of conditions and the following disclaimer.\n", 0}, - {" * ", + "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.\n", + "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.\n", 0}, - {" * ", + "specific prior written permission.", 0}, + {"", "Modified source versions must be plainly marked as such, and must " - "not be misrepresented as being the original software.\n", 0}, + "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 " @@ -91,75 +99,522 @@ const cmDocumentationEntry cmDocumentationCopyright[] = "PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF " "LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING " "NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS " - "SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n", 0}, + "SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.", 0}, {0, 0, 0} }; //---------------------------------------------------------------------------- cmDocumentation::cmDocumentation() { - this->SetCommands(0); - this->Description = 0; - this->Name = 0; - this->UsageHelp = 0; - this->SetOptions(0); + this->CurrentForm = TextForm; + this->TextIndent = ""; + this->TextWidth = 77; } //---------------------------------------------------------------------------- -void cmDocumentation::PrintManSection(std::ostream& os, +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) +{ + 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(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"; + for(;op->name;++op) + { + os << "
  • \n"; + if(op->name[0]) + { + os << " "; + this->PrintHTMLEscapes(os, op->name); + os << ": "; + } + this->PrintHTMLEscapes(os, op->brief); + if(op->full) + { + os << "
    \n "; + this->PrintFormatted(os, op->full); + } + os << "\n"; + os << "
  • \n"; + } + 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; } - os << ".SH " << name << "\n"; for(const cmDocumentationEntry* op = section; op->brief; ++op) { if(op->name) { os << ".TP\n" - << ".B " << op->name << "\n" - << op->brief << "\n\n"; - if(op->full) - { - this->PrintFull(os, op->full, 0, 0); - } + << ".B " << (op->name[0]?op->name:"*") << "\n"; + this->PrintFormatted(os, op->brief); + this->PrintFormatted(os, op->full); } else { - os << ".PP\n" - << op->brief << "\n"; + os << ".PP\n"; + this->PrintFormatted(os, op->brief); } } } //---------------------------------------------------------------------------- -void cmDocumentation::PrintHelpSection(std::ostream& os, - const cmDocumentationEntry* section) +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 << "\n" - << " "; - this->PrintColumn(os, 70, " ", op->brief); - if(op->full) + 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 << "\n" - << "\n" - << " "; - this->PrintColumn(os, 70, " ", op->full); + os << " "; } + os << "= "; + this->PrintColumn(os, op->brief); os << "\n"; } else { - this->PrintColumn(os, 77, "", op->brief); + os << "\n"; + this->TextIndent = ""; + this->PrintFormatted(os, op->brief); os << "\n"; } - 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 - 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; } + } } //---------------------------------------------------------------------------- @@ -192,445 +647,141 @@ void cmDocumentation::PrintHTMLEscapes(std::ostream& os, const char* text) } //---------------------------------------------------------------------------- -void cmDocumentation::PrintHTMLPreformatted(std::ostream& os, const char* text) +void cmDocumentation::PrintDocumentationUsage(std::ostream& os) { - os << "

";
-  cmDocumentation::PrintHTMLEscapes(os, text);
-  os << "
"; + this->CreateUsageDocumentation(); + this->Print(UsageForm, os); } //---------------------------------------------------------------------------- -void cmDocumentation::PrintHelpHTMLSection(std::ostream& os, - const cmDocumentationEntry* section, - const char* header) +void cmDocumentation::PrintDocumentationFull(std::ostream& os) { - if(!section) { return; } - if(header) - { - os << "

" << header << "

\n"; - } - for(const cmDocumentationEntry* op = section; op->brief;) - { - if(op->name) - { - os << "
    \n"; - for(;op->name;++op) - { - os << "
  • \n"; - os << " "; - this->PrintHTMLEscapes(os, op->name); - os << ": "; - this->PrintHTMLEscapes(os, op->brief); - if(op->full) - { - os << "
    "; - this->PrintFull(os, op->full, - &cmDocumentation::PrintHTMLPreformatted, - &cmDocumentation::PrintHTMLEscapes); - } - os << "\n"; - os << "
  • \n"; - } - os << "
\n"; - } - else - { - this->PrintHTMLEscapes(os, op->brief); - os << "\n"; - ++op; - } - } + this->CreateFullDocumentation(); + this->Print(TextForm, os); } //---------------------------------------------------------------------------- -void cmDocumentation::PrintUsageSection(std::ostream& os, - const cmDocumentationEntry* section) +void cmDocumentation::PrintDocumentationHTML(std::ostream& os) { - if(!section) { return; } - for(const cmDocumentationEntry* op = section; op->brief; ++op) - { - if(op->name) - { - os << " " << op->name; - for(int i = static_cast(strlen(op->name)); i < 25; ++i) - { - os << " "; - } - os << "= " << op->brief << "\n"; - } - else - { - os << "\n"; - this->PrintColumn(os, 74, "", op->brief); - os << "\n"; - } - } + this->CreateFullDocumentation(); + os << "\n"; + this->Print(HTMLForm, os); + os << "\n"; } //---------------------------------------------------------------------------- -void cmDocumentation::PrintUsage(std::ostream& os) -{ - os << "Usage:\n"; - this->PrintUsageSection(os, this->UsageHelp); - this->PrintUsageSection(os, &this->Options[0]); -} - -//---------------------------------------------------------------------------- -void cmDocumentation::PrintHelp(std::ostream& os) -{ - os << "Usage:\n"; - os << "\n"; - this->PrintHelpSection(os, this->UsageHelp); - this->PrintHelpSection(os, this->Description); - os << "--------------------------------------------------------------------------\n"; - this->PrintHelpSection(os, &this->Options[0]); - os << "--------------------------------------------------------------------------\n"; - this->PrintHelpSection(os, &this->Commands[0]); -} - -//---------------------------------------------------------------------------- -void cmDocumentation::PrintHelpHTML(std::ostream& os) -{ - os << "\n" - << "\n"; - os << "

Using CMake

\n"; - if(this->UsageHelp) - { - os << "
\n"; - this->PrintHelpHTMLSection(os, this->UsageHelp, 0); - os << "
\n"; - } - this->PrintHelpHTMLSection(os, this->Description, 0); - this->PrintHelpHTMLSection(os, &this->Options[0], "Command-line Options"); - this->PrintHelpHTMLSection(os, &this->Commands[0], "Listfile Commands"); - //this->PrintHelpHTMLSection(os, cmDocumentationCopyright, "Copyright"); - //this->PrintHelpHTMLSection(os, cmDocumentationMailingList, "Mailing List"); - os << "\n" - << "\n"; -} - -//---------------------------------------------------------------------------- -void cmDocumentation::PrintManPage(std::ostream& os) +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->PrintManSection(os, this->Name, "NAME"); - this->PrintManSection(os, this->UsageHelp, "SYNOPSIS"); - this->PrintManSection(os, this->Description, "DESCRIPTION"); - this->PrintManSection(os, &this->Options[0], "OPTIONS"); - this->PrintManSection(os, &this->Commands[0], "COMMANDS"); - this->PrintManSection(os, cmDocumentationCopyright, "COPYRIGHT"); - os << ".SH MAILING LIST\n"; - os << "For help and discussion about using cmake, a mailing list is\n" - << "provided at\n" - << ".B cmake@www.cmake.org.\n" - << "Please first read the full documentation at\n" - << ".B http://www.cmake.org\n" - << "before posting questions to the list.\n"; - os << ".SH AUTHOR\n" - << "This manual page was generated by \"cmake --help-man\".\n"; + this->Print(ManForm, os); } //---------------------------------------------------------------------------- -void cmDocumentation::PrintCopyright(std::ostream& os) +void cmDocumentation::CreateUsageDocumentation() { - os << "CMake version " CMake_VERSION_STRING "\n"; - for(const cmDocumentationEntry* op = cmDocumentationCopyright; - op->brief; ++op) + this->ClearSections(); + if(!this->NameSection.empty()) { - if(op->name) - { - os << " * "; - this->PrintColumn(os, 74, " ", op->brief); - } - else - { - this->PrintColumn(os, 77, "", op->brief); - } - os << "\n"; + 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::PrintVersion(std::ostream& os) +void cmDocumentation::CreateFullDocumentation() { - os << "CMake version " CMake_VERSION_STRING "\n"; + 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::PrintColumn(std::ostream& os, int width, - const char* indent, const char* text) +void cmDocumentation::CreateManDocumentation() { - // Print text arranged in a column of fixed witdh indented by the - // "indent" text. - const char* l = text; - int column = 0; - bool newSentence = false; - bool firstLine = true; - bool lastHadBlanks = false; - - // Count leading blanks in the text. - int blanks = 0; - for(const char* b = l; *b == ' '; ++b) { ++blanks; } - - // Loop until the end of the text. - while(*l) + this->ClearSections(); + if(!this->NameSection.empty()) { - // 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 - { - // If we are switching from a line that has leading blanks - // to a line that does not, or vice versa, add an extra - // newline. - if(blanks) - { - if(!lastHadBlanks && !firstLine) - { - os << "\n"; - } - lastHadBlanks = true; - } - else - { - if(lastHadBlanks && !firstLine) - { - os << "\n"; - } - lastHadBlanks = false; - } - - // First word on line. Print indentation unless this is the - // first line. - os << (firstLine?"":indent); - - // Further indent by leading blanks from the text on this - // line. - for(int i = 0; i < blanks; ++i) - { - os << " "; - ++column; - } - blanks = 0; - } - - // 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; - - // Count leading blanks in the text. - for(const char* b = r; *b == ' '; ++b) { ++blanks; } - } - 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 << indent; - 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; } + 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::PrintFull(std::ostream& os, const char* text, - void (*pPreform)(std::ostream&, const char*), - void (*pNormal)(std::ostream&, const char*)) +void cmDocumentation::SetSection(const cmDocumentationEntry* header, + const cmDocumentationEntry* section, + const cmDocumentationEntry* footer, + std::vector& vec) { - const char* line = text; - while(*line) + vec.erase(vec.begin(), vec.end()); + if(header) { - // Any lines starting in a space are treated as preformatted text. - std::string preformatted; - while(*line == ' ') + for(const cmDocumentationEntry* op = header; op->brief; ++op) { - for(char ch = *line; ch && ch != '\n'; ++line, ch = *line) - { - preformatted.append(1, ch); - } - if(*line) - { - ++line; - preformatted.append(1, '\n'); - } - } - if(preformatted.length()) - { - if(pPreform) - { - pPreform(os, preformatted.c_str()); - } - else - { - os << preformatted << "\n"; - } - } - - // Other lines are treated as normal text. - std::string normal; - for(char ch = *line; ch && ch != '\n'; ++line, ch = *line) - { - normal.append(1, ch); - } - if(*line) - { - ++line; - normal.append(1, '\n'); - } - if(normal.length()) - { - if(pNormal) - { - pNormal(os, normal.c_str()); - } - else - { - os << normal << "\n"; - } + vec.push_back(*op); } } -} - -//---------------------------------------------------------------------------- -void cmDocumentation::Print(Type ht, std::ostream& os) -{ - switch (ht) + if(section) { - case cmDocumentation::Usage: this->PrintUsage(os); break; - case cmDocumentation::Help: this->PrintHelp(os); break; - case cmDocumentation::HelpHTML: this->PrintHelpHTML(os); break; - case cmDocumentation::Man: this->PrintManPage(os); break; - case cmDocumentation::Copyright: this->PrintCopyright(os); break; - case cmDocumentation::Version: this->PrintVersion(os); break; - default: break; - } -} - -//---------------------------------------------------------------------------- -cmDocumentation::Type cmDocumentation::CheckOptions(int argc, char** argv) -{ - for(int i=1; i < argc; ++i) - { - if((strcmp(argv[i], "-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)) + for(const cmDocumentationEntry* op = section; op->brief; ++op) { - return cmDocumentation::Usage; - } - if(strcmp(argv[i], "--help-full") == 0) - { - return cmDocumentation::Help; - } - if(strcmp(argv[i], "--help-html") == 0) - { - return cmDocumentation::HelpHTML; - } - 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; + vec.push_back(*op); } } - return cmDocumentation::None; -} - -//---------------------------------------------------------------------------- -void cmDocumentation::SetOptions(const cmDocumentationEntry* d) -{ - this->Options.erase(this->Options.begin(), this->Options.end()); - if(d) + if(footer) { - for(const cmDocumentationEntry* op = d; op->brief; ++op) + for(const cmDocumentationEntry* op = footer; op->brief; ++op) { - this->Options.push_back(*op); - } - } - for(const cmDocumentationEntry* op = cmDocumentationStandardOptions; - op->brief; ++op) - { - this->Options.push_back(*op); - } - cmDocumentationEntry empty = {0,0,0}; - this->Options.push_back(empty); -} - -//---------------------------------------------------------------------------- -void cmDocumentation::SetCommands(const cmDocumentationEntry* d) -{ - this->Commands.erase(this->Commands.begin(), this->Commands.end()); - for(const cmDocumentationEntry* op = cmDocumentationCommandsHeader; - op->brief; ++op) - { - this->Commands.push_back(*op); - } - if(d) - { - for(const cmDocumentationEntry* op = d; op->brief; ++op) - { - this->Commands.push_back(*op); + vec.push_back(*op); } } cmDocumentationEntry empty = {0,0,0}; - this->Commands.push_back(empty); + vec.push_back(empty); } diff --git a/Source/cmDocumentation.h b/Source/cmDocumentation.h index fc87ce0e5..5e507a0f4 100644 --- a/Source/cmDocumentation.h +++ b/Source/cmDocumentation.h @@ -25,45 +25,111 @@ class cmDocumentation public: cmDocumentation(); - enum Type { None, Usage, Help, HelpHTML, Man, Copyright, Version }; + // High-level interface for standard documents: - void Print(Type ht, std::ostream& os); - void PrintUsage(std::ostream& os); - void PrintHelp(std::ostream& os); - void PrintHelpHTML(std::ostream& os); - void PrintManPage(std::ostream& os); + /** Types of help provided. */ + enum Type { None, Usage, Full, HTML, Man, Copyright, Version }; + + /** + * Check command line arguments for documentation options. Returns + * the type of help to be provided. If non-zero, the result should + * be passed to PrintDocumentation to produce the desired + * documentation. + */ + Type CheckOptions(int argc, char** argv); + + /** Print help of the given type. */ + void PrintDocumentation(Type ht, std::ostream& os); + + /** Set the program name for standard document generation. */ + void SetNameSection(const cmDocumentationEntry*); + + /** Set the program usage for standard document generation. */ + void SetUsageSection(const cmDocumentationEntry*); + + /** Set the program description for standard document generation. */ + void SetDescriptionSection(const cmDocumentationEntry*); + + /** Set the program options for standard document generation. */ + void SetOptionsSection(const cmDocumentationEntry*); + + /** Set the listfile commands for standard document generation. */ + void SetCommandsSection(const cmDocumentationEntry*); + + // Low-level interface for custom documents: + + /** Forms of documentation output. */ + enum Form { TextForm, HTMLForm, ManForm, UsageForm }; + + /** + * Print documentation in the given form. All previously added + * sections will be generated. + */ + void Print(Form f, std::ostream& os); + + /** + * Add a section of documentation. The cmDocumentationEntry pointer + * should point at an array terminated by an all zero ({0,0,0}) + * entry. This can be used to generate custom help documents. + */ + void AddSection(const char* name, const cmDocumentationEntry* d); + + /** Clear all previously added sections of help. */ + void ClearSections(); +private: + void PrintSection(std::ostream& os, + const cmDocumentationEntry* section, + const char* name); + void PrintSectionText(std::ostream& os, + const cmDocumentationEntry* section, + const char* name); + void PrintSectionHTML(std::ostream& os, + const cmDocumentationEntry* section, + const char* name); + void PrintSectionMan(std::ostream& os, const cmDocumentationEntry* section, + const char* name); + void PrintSectionUsage(std::ostream& os, + const cmDocumentationEntry* section, + const char* name); + void PrintFormatted(std::ostream& os, const char* text); + void PrintPreformatted(std::ostream& os, const char* text); + void PrintPreformattedText(std::ostream& os, const char* text); + void PrintPreformattedHTML(std::ostream& os, const char* text); + void PrintPreformattedMan(std::ostream& os, const char* text); + void PrintParagraph(std::ostream& os, const char* text); + void PrintParagraphText(std::ostream& os, const char* text); + void PrintParagraphHTML(std::ostream& os, const char* text); + void PrintParagraphMan(std::ostream& os, const char* text); + void PrintColumn(std::ostream& os, const char* text); + void PrintHTMLEscapes(std::ostream& os, const char* text); + void PrintCopyright(std::ostream& os); void PrintVersion(std::ostream& os); + void PrintDocumentationUsage(std::ostream& os); + void PrintDocumentationFull(std::ostream& os); + void PrintDocumentationHTML(std::ostream& os); + void PrintDocumentationMan(std::ostream& os); - void SetCommands(const cmDocumentationEntry* d); - void SetDescription(const cmDocumentationEntry* d) {this->Description = d;} - void SetName(const cmDocumentationEntry* d) {this->Name = d;} - void SetOptions(const cmDocumentationEntry* d); - void SetUsage(const cmDocumentationEntry* d) {this->UsageHelp = d;} + void CreateUsageDocumentation(); + void CreateFullDocumentation(); + void CreateManDocumentation(); + + void SetSection(const cmDocumentationEntry* header, + const cmDocumentationEntry* section, + const cmDocumentationEntry* footer, + std::vector&); + + std::vector NameSection; + std::vector UsageSection; + std::vector DescriptionSection; + std::vector OptionsSection; + std::vector CommandsSection; - Type CheckOptions(int argc, char** argv); -private: - void PrintColumn(std::ostream& os, int width, - const char* indent, const char* text); - void PrintManSection(std::ostream& os, const cmDocumentationEntry* section, - const char* name); - void PrintHelpSection(std::ostream& os, const cmDocumentationEntry* section); - static void PrintHTMLEscapes(std::ostream& os, const char* text); - static void PrintHTMLPreformatted(std::ostream& os, const char* text); - void PrintFull(std::ostream& os, const char* text, - void (*pPreform)(std::ostream&, const char*), - void (*pNormal)(std::ostream&, const char*)); - void PrintHelpHTMLSection(std::ostream& os, - const cmDocumentationEntry* section, - const char* header); - void PrintUsageSection(std::ostream& os, - const cmDocumentationEntry* section); - - std::vector Commands; - const cmDocumentationEntry* Description; - const cmDocumentationEntry* Name; - std::vector Options; - const cmDocumentationEntry* UsageHelp; + std::vector< const char* > Names; + std::vector< const cmDocumentationEntry* > Sections; + Form CurrentForm; + const char* TextIndent; + int TextWidth; }; #endif diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx index b86dc0708..6a0dc1fb3 100644 --- a/Source/cmakemain.cxx +++ b/Source/cmakemain.cxx @@ -24,8 +24,8 @@ //---------------------------------------------------------------------------- static const cmDocumentationEntry cmDocumentationName[] = { - {"cmake", - "- Cross-Platform Makefile Generator.", 0}, + {0, + " cmake - Cross-Platform Makefile Generator.", 0}, {0,0,0} }; @@ -33,7 +33,7 @@ static const cmDocumentationEntry cmDocumentationName[] = static const cmDocumentationEntry cmDocumentationUsage[] = { {0, - "cmake [options] ", 0}, + " cmake [options] ", 0}, {0,0,0} }; @@ -74,12 +74,12 @@ int do_cmake(int ac, char** av) cmake hcm; std::vector commands; hcm.GetCommandDocumentation(commands); - doc.SetName(cmDocumentationName); - doc.SetUsage(cmDocumentationUsage); - doc.SetDescription(cmDocumentationDescription); - doc.SetOptions(cmDocumentationOptions); - doc.SetCommands(&commands[0]); - doc.Print(ht, std::cout); + doc.SetNameSection(cmDocumentationName); + doc.SetUsageSection(cmDocumentationUsage); + doc.SetDescriptionSection(cmDocumentationDescription); + doc.SetOptionsSection(cmDocumentationOptions); + doc.SetCommandsSection(&commands[0]); + doc.PrintDocumentation(ht, std::cout); return 0; }