diff options
Diffstat (limited to 'Source/cmDocumentation.cxx')
-rw-r--r-- | Source/cmDocumentation.cxx | 471 |
1 files changed, 422 insertions, 49 deletions
diff --git a/Source/cmDocumentation.cxx b/Source/cmDocumentation.cxx index 07683d0..904a157 100644 --- a/Source/cmDocumentation.cxx +++ b/Source/cmDocumentation.cxx @@ -14,7 +14,9 @@ #include "cmSystemTools.h" #include "cmVersion.h" #include <cmsys/Directory.hxx> +#include <cmsys/Glob.hxx> +#include <algorithm> //---------------------------------------------------------------------------- static const char *cmDocumentationStandardOptions[][3] = @@ -220,55 +222,7 @@ cmDocumentation::cmDocumentation() :CurrentFormatter(0) { this->SetForm(TextForm); - - cmDocumentationSection *sec; - - sec = new cmDocumentationSection("Author","AUTHOR"); - sec->Append(cmDocumentationEntry - (0, - "This manual page was generated by the \"--help-man\" option.", - 0)); - this->AllSections["Author"] = sec; - - sec = new cmDocumentationSection("Copyright","COPYRIGHT"); - sec->Append(cmDocumentationCopyright); - this->AllSections["Copyright"] = sec; - - sec = new cmDocumentationSection("See Also","SEE ALSO"); - sec->Append(cmDocumentationStandardSeeAlso); - this->AllSections["Standard See Also"] = sec; - - sec = new cmDocumentationSection("Options","OPTIONS"); - sec->Append(cmDocumentationStandardOptions); - this->AllSections["Options"] = sec; - - sec = new cmDocumentationSection("Properties","PROPERTIES"); - sec->Append(cmPropertiesDocumentationDescription); - this->AllSections["Properties Description"] = sec; - - sec = new cmDocumentationSection("Generators","GENERATORS"); - sec->Append(cmDocumentationGeneratorsHeader); - this->AllSections["Generators"] = sec; - - sec = new cmDocumentationSection("Compatibility Commands", - "COMPATIBILITY COMMANDS"); - sec->Append(cmCompatCommandsDocumentationDescription); - this->AllSections["Compatibility Commands"] = sec; - - - this->PropertySections.push_back("Properties of Global Scope"); - this->PropertySections.push_back("Properties on Directories"); - this->PropertySections.push_back("Properties on Targets"); - this->PropertySections.push_back("Properties on Tests"); - this->PropertySections.push_back("Properties on Source Files"); - this->PropertySections.push_back("Properties on Cache Entries"); - - this->VariableSections.push_back("Variables that Provide Information"); - this->VariableSections.push_back("Variables That Change Behavior"); - this->VariableSections.push_back("Variables That Describe the System"); - this->VariableSections.push_back("Variables that Control the Build"); - this->VariableSections.push_back("Variables for Languages"); - + this->addCommonStandardDocSections(); this->ShowGenerators = true; } @@ -559,6 +513,8 @@ bool cmDocumentation::CreateSingleModule(const char* fname, { if(line.size() && line[0] == '#') { + /* line beginnings with ## are mark-up ignore them */ + if (line.size()>=2 && line[1] == '#') continue; // blank line if(line.size() <= 2) { @@ -710,6 +666,423 @@ cmDocumentation::Form cmDocumentation::GetFormFromFilename( } //---------------------------------------------------------------------------- +void cmDocumentation::addCommonStandardDocSections() +{ + cmDocumentationSection *sec; + + sec = new cmDocumentationSection("Author","AUTHOR"); + sec->Append(cmDocumentationEntry + (0, + "This manual page was generated by the \"--help-man\" option.", + 0)); + this->AllSections["Author"] = sec; + + sec = new cmDocumentationSection("Copyright","COPYRIGHT"); + sec->Append(cmDocumentationCopyright); + this->AllSections["Copyright"] = sec; + + sec = new cmDocumentationSection("See Also","SEE ALSO"); + sec->Append(cmDocumentationStandardSeeAlso); + this->AllSections["Standard See Also"] = sec; + + sec = new cmDocumentationSection("Options","OPTIONS"); + sec->Append(cmDocumentationStandardOptions); + this->AllSections["Options"] = sec; + + sec = new cmDocumentationSection("Compatibility Commands", + "COMPATIBILITY COMMANDS"); + sec->Append(cmCompatCommandsDocumentationDescription); + this->AllSections["Compatibility Commands"] = sec; +} + +//---------------------------------------------------------------------------- +void cmDocumentation::addCMakeStandardDocSections() +{ + cmDocumentationSection *sec; + + sec = new cmDocumentationSection("Properties","PROPERTIES"); + sec->Append(cmPropertiesDocumentationDescription); + this->AllSections["Properties Description"] = sec; + + sec = new cmDocumentationSection("Generators","GENERATORS"); + sec->Append(cmDocumentationGeneratorsHeader); + this->AllSections["Generators"] = sec; + + this->PropertySections.push_back("Properties of Global Scope"); + this->PropertySections.push_back("Properties on Directories"); + this->PropertySections.push_back("Properties on Targets"); + this->PropertySections.push_back("Properties on Tests"); + this->PropertySections.push_back("Properties on Source Files"); + this->PropertySections.push_back("Properties on Cache Entries"); + + this->VariableSections.push_back("Variables that Provide Information"); + this->VariableSections.push_back("Variables That Change Behavior"); + this->VariableSections.push_back("Variables That Describe the System"); + this->VariableSections.push_back("Variables that Control the Build"); + this->VariableSections.push_back("Variables for Languages"); + +} + +//---------------------------------------------------------------------------- +void cmDocumentation::addCTestStandardDocSections() +{ + // This is currently done for backward compatibility reason + // We may suppress some of these. + addCMakeStandardDocSections(); +} + +//---------------------------------------------------------------------------- +void cmDocumentation::addCPackStandardDocSections() +{ + cmDocumentationSection *sec; + + sec = new cmDocumentationSection("Generators","GENERATORS"); + sec->Append(cmDocumentationGeneratorsHeader); + this->AllSections["Generators"] = sec; + + this->VariableSections.push_back( + "Variables common to all CPack generators"); +} + +void cmDocumentation::addAutomaticVariableSections(const std::string& section) +{ + std::vector<std::string>::iterator it; + it = std::find(this->VariableSections.begin(), + this->VariableSections.end(), + section); + /* if the section does not exist then add it */ + if (it==this->VariableSections.end()) + { + this->VariableSections.push_back(section); + } +} +//---------------------------------------------------------------------------- +int cmDocumentation::getDocumentedModulesListInDir( + std::string path, + std::string globExpr, + documentedModulesList_t& docedModuleList) +{ + cmsys::Glob gl; + std::string findExpr; + std::vector<std::string> files; + std::string line; + documentedModuleSectionPair_t docPair; + int nbDocumentedModules = 0; + + findExpr = path + "/" + globExpr; + if (gl.FindFiles(findExpr)) + { + files = gl.GetFiles(); + for (std::vector<std::string>::iterator itf=files.begin(); + itf!=files.end();++itf) + { + std::ifstream fin((*itf).c_str()); + // file access trouble ignore it (ignore this kind of error) + if (!fin) continue; + /* read first line in order to get doc section */ + if (cmSystemTools::GetLineFromStream(fin, line)) + { + /* Doc section indicates that + * this file has structured doc in it. + */ + if (line.find("##section")!=std::string::npos) + { + // ok found one more documented module + ++nbDocumentedModules; + docPair.first = *itf; + // 10 is the size of '##section' + 1 + docPair.second = line.substr(10,std::string::npos); + docedModuleList.push_back(docPair); + } + // No else if no section is found (undocumented module) + } + // No else cannot read first line (ignore this kind of error) + line = ""; + } + } + if (nbDocumentedModules>0) + { + return 0; + } + else + { + return 1; + } +} + +//---------------------------------------------------------------------------- +static void trim(std::string& s) +{ + std::string::size_type pos = s.find_last_not_of(' '); + if(pos != std::string::npos) + { + s.erase(pos + 1); + pos = s.find_first_not_of(' '); + if(pos != std::string::npos) s.erase(0, pos); + } + else + { + s.erase(s.begin(), s.end()); + } +} + +int cmDocumentation::GetStructuredDocFromFile( + const char* fname, + std::vector<cmDocumentationEntry>& commands, + cmake* cm) +{ + typedef enum sdoce { + SDOC_NONE, SDOC_MODULE, SDOC_MACRO, SDOC_FUNCTION, SDOC_VARIABLE, + SDOC_SECTION, + SDOC_UNKNOWN} sdoc_t; + int nbDocItemFound = 0; + int docCtxIdx = 0; + std::vector<int> docContextStack(60); + docContextStack[docCtxIdx]=SDOC_NONE; + cmDocumentationEntry e; + std::ifstream fin(fname); + if(!fin) + { + return nbDocItemFound; + } + std::string section; + std::string name; + std::string full; + std::string brief; + std::string line; + bool newCtx = false; /* we've just entered ##<beginkey> context */ + bool inBrief = false; /* we are currently parsing brief desc. */ + bool inFullFirstParagraph = false; /* we are currently parsing full + desc. first paragraph */ + brief = ""; + full = ""; + bool newParagraph = true; + while ( fin && cmSystemTools::GetLineFromStream(fin, line) ) + { + if(line.size() && line[0] == '#') + { + /* handle structured doc context */ + if ((line.size()>=2) && line[1]=='#') + { + /* markup word is following '##' stopping at first space + * Some markup word like 'section' may have more characters + * following but we don't handle those here. + */ + std::string mkword = line.substr(2,line.find(' ',2)-2); + if (mkword=="macro") + { + docCtxIdx++; + docContextStack[docCtxIdx]=SDOC_MACRO; + newCtx = true; + } + else if (mkword=="variable") + { + docCtxIdx++; + docContextStack[docCtxIdx]=SDOC_VARIABLE; + newCtx = true; + } + else if (mkword=="function") + { + docCtxIdx++; + docContextStack[docCtxIdx]=SDOC_FUNCTION; + newCtx = true; + } + else if (mkword=="module") + { + docCtxIdx++; + docContextStack[docCtxIdx]=SDOC_MODULE; + newCtx = true; + } + else if (mkword=="section") + { + docCtxIdx++; + docContextStack[docCtxIdx]=SDOC_SECTION; + // 10 is the size of '##section' + 1 + section = line.substr(10,std::string::npos); + /* drop the rest of the line */ + line = ""; + newCtx = true; + } + else if (mkword.substr(0,3)=="end") + { + switch (docContextStack[docCtxIdx]) { + case SDOC_MACRO: + /* for now MACRO and FUNCTION are handled in the same way */ + case SDOC_FUNCTION: + commands.push_back(cmDocumentationEntry(name.c_str(), + brief.c_str(),full.c_str())); + break; + case SDOC_VARIABLE: + this->addAutomaticVariableSections(section); + cm->DefineProperty + (name.c_str(), cmProperty::VARIABLE, + brief.c_str(), + full.c_str(),false, + section.c_str()); + break; + case SDOC_MODULE: + /* not implemented */ + break; + case SDOC_SECTION: + /* not implemented */ + break; + default: + /* ignore other cases */ + break; + } + docCtxIdx--; + newCtx = false; + ++nbDocItemFound; + } + else + { + // error out unhandled context + return nbDocItemFound; + } + /* context is set go to next doc line */ + continue; + } + + // Now parse the text attached to the context + + // The first line after the context mark-up contains:: + // name - brief until. (brief is dot terminated or + // followed by a blank line) + if (newCtx) + { + // no brief (for easy variable definition) + if (line.find("-")==std::string::npos) + { + name = line.substr(1,std::string::npos); + trim(name); + brief = ""; + inBrief = false; + full = ""; + } + // here we have a name and brief beginning + else + { + name = line.substr(1,line.find("-")-1); + trim(name); + // we are parsing the brief context + brief = line.substr(line.find("-")+1,std::string::npos); + trim(brief); + // Brief may already be terminated on the first line + if (brief.find('.')!=std::string::npos) + { + inBrief = false; + full = brief.substr(brief.find('.')+1,std::string::npos); + trim(full); + inFullFirstParagraph = true; + brief = brief.substr(0,brief.find('.')); + } + // brief is continued on following lines + else + { + inBrief = true; + full = ""; + } + } + newCtx = false; + continue; + } + // blank line + if(line.size() <= 2) + { + if (inBrief) { + inBrief = false; + full = ""; + } else { + if (full.length()>0) + { + full += "\n"; + } + // the first paragraph of full has ended + inFullFirstParagraph = false; + } + newParagraph = true; + } + // brief is terminated by '.' + else if (inBrief && (line.find('.')!=std::string::npos)) + { + /* the brief just ended */ + inBrief = false; + std::string endBrief = line.substr(1,line.find('.')); + trim(endBrief); + trim(brief); + brief += " " + endBrief; + full += line.substr(line.find('.')+1,std::string::npos); + trim(full); + inFullFirstParagraph = true; + } + // we handle full text or multi-line brief. + else + { + std::string* text; + if (inBrief) + { + text = &brief; + } + else + { + text = &full; + } + // two spaces + if(line[1] == ' ' && line[2] == ' ') + { + // there is no "full first paragraph at all." + if (line[3] == ' ') + { + inFullFirstParagraph = false; + } + + if(!newParagraph && !inFullFirstParagraph) + { + *text += "\n"; + newParagraph = true; + } + // Skip #, and leave space for pre-formatted + if (inFullFirstParagraph) + { + std::string temp = line.c_str()+1; + trim(temp); + *text += " " + temp; + } + else + { + *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; + } + } + } + /* next line is not the first context line */ + newCtx = false; + } + return nbDocItemFound; +} + +//---------------------------------------------------------------------------- bool cmDocumentation::CheckOptions(int argc, const char* const* argv, const char* exitOpt) { |