1 // =================================
   2 // Copyright (c) 2020 Seppo Laakko
   3 // Distributed under the MIT license
   4 // =================================
   5 
   6 #include <gendoc/html/Html.hpp>
   7 #include <gendoc/html/HtmlSourceCodeGenerator.hpp>
   8 #include <gendoc/html/HtmlSourceCodeWriter.hpp>
   9 #include <gendoc/html/HtmlLexerFileSourceGenerator.hpp>
  10 #include <gendoc/html/HtmlParserFileSourceGenerator.hpp>
  11 #include <gendoc/html/ClassInheritanceDiagramCode.hpp>
  12 #include <sngxml/dom/Document.hpp>
  13 #include <sngxml/dom/Element.hpp>
  14 #include <sngxml/dom/CharacterData.hpp>
  15 #include <sngxml/xpath/XPathEvaluate.hpp>
  16 #include <sngcpp/symbols/Symbol.hpp>
  17 #include <soulng/lexer/XmlParsingLog.hpp>
  18 #include <soulng/util/TextUtils.hpp>
  19 #include <soulng/util/Path.hpp>
  20 #include <soulng/util/Unicode.hpp>
  21 #include <soulng/util/Util.hpp>
  22 #include <boost/filesystem.hpp>
  23 #include <algorithm>
  24 #include <stdexcept>
  25 #include <unordered_set>
  26 #include <fstream>
  27 #include <iostream>
  28 
  29 namespace gendoc { namespace html {
  30 
  31 using namespace soulng::util;
  32 using namespace soulng::unicode;
  33 using namespace sngcpp::symbols;
  34 
  35 void MakeDirectories(const std::string& targetDirstd::string& htmlDirstd::string& contentDirstd::string& fileDirstd::string& styleDir)
  36 {
  37     htmlDir = GetFullPath(Path::Combine(targetDir"html"));
  38     boost::filesystem::create_directories(htmlDir);
  39     contentDir = GetFullPath(Path::Combine(htmlDir"content"));
  40     boost::filesystem::create_directories(contentDir);
  41     fileDir = GetFullPath(Path::Combine(contentDir"file"));
  42     boost::filesystem::create_directories(fileDir);
  43     styleDir = GetFullPath(Path::Combine(htmlDir"style"));
  44     boost::filesystem::create_directories(styleDir);
  45 }
  46 
  47 void GenerateStyleSheet(const std::string& styleDirstd::string& styleDirNamestd::string& styleFileName)
  48 {
  49     styleDirName = "style";
  50     styleFileName = "style.css";
  51     std::string styleFilePath = GetFullPath(Path::Combine(styleDirstyleFileName));
  52     std::ofstream styleSheetFile(styleFilePath);
  53     CodeFormatter formatter(styleSheetFile);
  54     formatter.WriteLine(".diagram");
  55     formatter.WriteLine("{");
  56     formatter.IncIndent();
  57     formatter.WriteLine("text-align: center;");
  58     formatter.DecIndent();
  59     formatter.WriteLine("}");
  60     formatter.WriteLine(".tree");
  61     formatter.WriteLine("{");
  62     formatter.IncIndent();
  63     formatter.WriteLine("margin: 20px;");
  64     formatter.DecIndent();
  65     formatter.WriteLine("}");
  66     formatter.WriteLine(".indent");
  67     formatter.WriteLine("{");
  68     formatter.IncIndent();
  69     formatter.WriteLine("margin: 20px;");
  70     formatter.WriteLine("max-width: 800px;");
  71     formatter.DecIndent();
  72     formatter.WriteLine("}");
  73     formatter.WriteLine(".description");
  74     formatter.WriteLine("{");
  75     formatter.IncIndent();
  76     formatter.WriteLine("margin: 20px;");
  77     formatter.WriteLine("max-width: 800px;");
  78     formatter.DecIndent();
  79     formatter.WriteLine("}");
  80     formatter.WriteLine("h1, h2, h3, h4, h5, h6");
  81     formatter.WriteLine("{");
  82     formatter.IncIndent();
  83     formatter.WriteLine("color: #005ab4;");
  84     formatter.WriteLine("font-family: sans-serif;");
  85     formatter.DecIndent();
  86     formatter.WriteLine("}");
  87     formatter.WriteLine("table");
  88     formatter.WriteLine("{");
  89     formatter.IncIndent();
  90     formatter.WriteLine("font-family: sans-serif;");
  91     formatter.WriteLine("border-collapse: collapse;");
  92     formatter.DecIndent();
  93     formatter.WriteLine("}");
  94     formatter.WriteLine("table, th, td");
  95     formatter.WriteLine("{");
  96     formatter.IncIndent();
  97     formatter.WriteLine("text-align: left;");
  98     formatter.WriteLine("border: 1px solid #dddddd;");
  99     formatter.WriteLine("margin: 20px;");
 100     formatter.WriteLine("padding: 8px;");
 101     formatter.DecIndent();
 102     formatter.WriteLine("}");
 103     formatter.WriteLine("table.functionTable");
 104     formatter.WriteLine("{");
 105     formatter.IncIndent();
 106     formatter.WriteLine("font-family: sans-serif;");
 107     formatter.WriteLine("border-collapse: collapse;");
 108     formatter.DecIndent();
 109     formatter.WriteLine("}");
 110     formatter.WriteLine("table.functionTable, td.functionTableSecondCol");
 111     formatter.WriteLine("{");
 112     formatter.IncIndent();
 113     formatter.WriteLine("text-align: left;");
 114     formatter.WriteLine("border: 1px solid #dddddd;");
 115     formatter.WriteLine("margin: 20px;");
 116     formatter.WriteLine("padding: 8px;");
 117     formatter.DecIndent();
 118     formatter.WriteLine("}");
 119     formatter.WriteLine("td.functionTableFirstCol");
 120     formatter.WriteLine("{");
 121     formatter.IncIndent();
 122     formatter.WriteLine("text-align: right;");
 123     formatter.WriteLine("border: 1px solid #dddddd;");
 124     formatter.WriteLine("padding: 8px;");
 125     formatter.DecIndent();
 126     formatter.WriteLine("}");
 127     //  grammars:
 128     formatter.WriteLine("table.grammar");
 129     formatter.WriteLine("{");
 130     formatter.IncIndent();
 131     formatter.WriteLine("background-color: FloralWhite;");
 132     formatter.WriteLine("margin: 20px;");
 133     formatter.WriteLine("padding: 20px;");
 134     formatter.WriteLine("max-width: 800px;");
 135     formatter.DecIndent();
 136     formatter.WriteLine("}");
 137     formatter.WriteLine("table.grammar, td.grammarThirdCol");
 138     formatter.WriteLine("{");
 139     formatter.IncIndent();
 140     formatter.WriteLine("vertical-align: top;");
 141     formatter.WriteLine("text-align: left;");
 142     formatter.WriteLine("padding: 8px;");
 143     formatter.DecIndent();
 144     formatter.WriteLine("}");
 145     formatter.WriteLine("td.grammarFirstCol");
 146     formatter.WriteLine("{");
 147     formatter.IncIndent();
 148     formatter.WriteLine("vertical-align: top;");
 149     formatter.WriteLine("text-align: right;");
 150     formatter.WriteLine("padding: 8px;");
 151     formatter.DecIndent();
 152     formatter.WriteLine("}");
 153     formatter.WriteLine("td.grammarSecondCol");
 154     formatter.WriteLine("{");
 155     formatter.IncIndent();
 156     formatter.WriteLine("vertical-align: top;");
 157     formatter.WriteLine("text-align: left;");
 158     formatter.WriteLine("font-family: serif;");
 159     formatter.WriteLine("padding: 8px;");
 160     formatter.DecIndent();
 161     formatter.WriteLine("}");
 162     formatter.WriteLine(".rule");
 163     formatter.WriteLine("{");
 164     formatter.IncIndent();
 165     formatter.WriteLine("font-family: serif;");
 166     formatter.WriteLine("font-style: italic;");
 167     formatter.DecIndent();
 168     formatter.WriteLine("}");
 169     formatter.WriteLine(".ruleChar");
 170     formatter.WriteLine("{");
 171     formatter.IncIndent();
 172     formatter.WriteLine("font-family: Consolas;");
 173     formatter.WriteLine("color: #0000cc;");
 174     formatter.WriteLine("font-weight: bold");
 175     formatter.DecIndent();
 176     formatter.WriteLine("}");
 177     formatter.WriteLine(".ruleString");
 178     formatter.WriteLine("{");
 179     formatter.IncIndent();
 180     formatter.WriteLine("font-family: Consolas;");
 181     formatter.WriteLine("color: #0000cc;");
 182     formatter.WriteLine("font-weight: bold");
 183     formatter.DecIndent();
 184     formatter.WriteLine("}");
 185     formatter.WriteLine(".ruleCharSet");
 186     formatter.WriteLine("{");
 187     formatter.IncIndent();
 188     formatter.WriteLine("font-family: Consolas;");
 189     formatter.WriteLine("color: #0000cc;");
 190     formatter.WriteLine("font-weight: bold");
 191     formatter.DecIndent();
 192     formatter.WriteLine("}");
 193     formatter.WriteLine(".ruleKeyword");
 194     formatter.WriteLine("{");
 195     formatter.IncIndent();
 196     formatter.WriteLine("color: #0000cc;");
 197     formatter.WriteLine("font-weight: bold;");
 198     formatter.DecIndent();
 199     formatter.WriteLine("}");
 200     formatter.WriteLine(".ruleParams");
 201     formatter.WriteLine("{");
 202     formatter.IncIndent();
 203     formatter.WriteLine("color: black;");
 204     formatter.DecIndent();
 205     formatter.WriteLine("}");
 206     formatter.WriteLine(".ruleOp");
 207     formatter.WriteLine("{");
 208     formatter.IncIndent();
 209     formatter.WriteLine("padding-left: 0pt;");
 210     formatter.WriteLine("padding-right: 0pt;");
 211     formatter.WriteLine("font-family: serif;");
 212     formatter.WriteLine("color: black;");
 213     formatter.DecIndent();
 214     formatter.WriteLine("}");
 215     formatter.WriteLine(".ruleLink");
 216     formatter.WriteLine("{");
 217     formatter.IncIndent();
 218     formatter.WriteLine("font-family: serif;");
 219     formatter.WriteLine("font-style: italic;");
 220     formatter.DecIndent();
 221     formatter.WriteLine("}");
 222     formatter.WriteLine(".lexerRule");
 223     formatter.WriteLine("{");
 224     formatter.IncIndent();
 225     formatter.WriteLine("font-family: serif;");
 226     formatter.WriteLine("font-style: italic;");
 227     formatter.DecIndent();
 228     formatter.WriteLine("}");
 229     //  code:
 230     formatter.WriteLine(".code");
 231     formatter.WriteLine("{");
 232     formatter.IncIndent();
 233     formatter.WriteLine("font-family: Consolas;");
 234     formatter.WriteLine("font-size: small;");
 235     formatter.DecIndent();
 236     formatter.WriteLine("}");
 237     formatter.WriteLine(".lineNumber");
 238     formatter.WriteLine("{");
 239     formatter.IncIndent();
 240     formatter.WriteLine("color: #2b91af;");
 241     formatter.DecIndent();
 242     formatter.WriteLine("}");
 243     formatter.WriteLine(".type");
 244     formatter.WriteLine("{");
 245     formatter.IncIndent();
 246     formatter.WriteLine("color: #2b91af;");
 247     formatter.DecIndent();
 248     formatter.WriteLine("}");
 249     formatter.WriteLine(".pp");
 250     formatter.WriteLine("{");
 251     formatter.IncIndent();
 252     formatter.WriteLine("color: #808080;");
 253     formatter.DecIndent();
 254     formatter.WriteLine("}");
 255     formatter.WriteLine(".kw");
 256     formatter.WriteLine("{");
 257     formatter.IncIndent();
 258     formatter.WriteLine("color: #0000cc;");
 259     formatter.WriteLine("font-weight: bold;");
 260     formatter.DecIndent();
 261     formatter.WriteLine("}");
 262     formatter.WriteLine(".string");
 263     formatter.WriteLine("{");
 264     formatter.IncIndent();
 265     formatter.WriteLine("color: #a31515;");
 266     formatter.DecIndent();
 267     formatter.WriteLine("}");
 268     formatter.WriteLine(".char");
 269     formatter.WriteLine("{");
 270     formatter.IncIndent();
 271     formatter.WriteLine("color: #a31515;");
 272     formatter.DecIndent();
 273     formatter.WriteLine("}");
 274     formatter.WriteLine(".comment");
 275     formatter.WriteLine("{");
 276     formatter.IncIndent();
 277     formatter.WriteLine("color: green;");
 278     formatter.DecIndent();
 279     formatter.WriteLine("}");
 280     formatter.WriteLine(".identifier");
 281     formatter.WriteLine("{");
 282     formatter.IncIndent();
 283     formatter.WriteLine("color: black;");
 284     formatter.DecIndent();
 285     formatter.WriteLine("}");
 286     formatter.WriteLine(".number");
 287     formatter.WriteLine("{");
 288     formatter.IncIndent();
 289     formatter.WriteLine("color: black;");
 290     formatter.DecIndent();
 291     formatter.WriteLine("}");
 292     formatter.WriteLine(".other");
 293     formatter.WriteLine("{");
 294     formatter.IncIndent();
 295     formatter.WriteLine("color: black;");
 296     formatter.DecIndent();
 297     formatter.WriteLine("}");
 298 }
 299 
 300 std::u32string GetPrefix(sngxml::dom::Element* element)
 301 {
 302     std::u32string prefix;
 303     sngxml::dom::ParentNode* parent = element->Parent();
 304     while (parent && parent->GetNodeType() == sngxml::dom::NodeType::elementNode)
 305     {
 306         sngxml::dom::Element* parentElement = static_cast<sngxml::dom::Element*>(parent);
 307         if (parentElement->Name() == U"namespace" || parentElement->Name() == U"class")
 308         {
 309             std::u32string nsOrClassName = parentElement->GetAttribute(U"name");
 310             if (!nsOrClassName.empty())
 311             {
 312                 if (!prefix.empty())
 313                 {
 314                     prefix = nsOrClassName + U"::" + prefix;
 315                 }
 316                 else
 317                 {
 318                     prefix = nsOrClassName;
 319                 }
 320             }
 321         }
 322         parent = parent->Parent();
 323     }
 324     return prefix;
 325 }
 326 
 327 std::u32string MakeTitle(const std::u32string& name)
 328 {
 329     if (!name.empty())
 330     {
 331         return std::u32string(1ToUpper(name[0])) + name.substr(1);
 332     }
 333     else
 334     {
 335         return name;
 336     }
 337 }
 338 
 339 enum class Navigation
 340 {
 341     headerfooter
 342 };
 343 
 344 void GenerateNavigation(sngxml::dom::Element* pageElementNavigation navigation
 345     const std::u32string& topLinkconst std::u32string& parentLinkconst std::u32string& prevLinkconst std::u32string& nextLink)
 346 {
 347     if (!topLink.empty())
 348     {
 349         std::unique_ptr<sngxml::dom::Element> top(new sngxml::dom::Element(U"a"));
 350         top->SetAttribute(U"href"topLink);
 351         top->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U"top")));
 352         pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(top.release()));
 353     }
 354     else
 355     {
 356         pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U"top")));
 357     }
 358     pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U" | ")));
 359     if (!parentLink.empty())
 360     {
 361         std::unique_ptr<sngxml::dom::Element> parent(new sngxml::dom::Element(U"a"));
 362         parent->SetAttribute(U"href"parentLink);
 363         parent->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U"up")));
 364         pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(parent.release()));
 365     }
 366     else
 367     {
 368         pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U"up")));
 369     }
 370     pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U" | ")));
 371     if (!prevLink.empty())
 372     {
 373         std::unique_ptr<sngxml::dom::Element> prev(new sngxml::dom::Element(U"a"));
 374         prev->SetAttribute(U"href"prevLink);
 375         prev->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U"prev")));
 376         pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(prev.release()));
 377     }
 378     else
 379     {
 380         pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U"prev")));
 381     }
 382     pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U" | ")));
 383     if (!nextLink.empty())
 384     {
 385         std::unique_ptr<sngxml::dom::Element> next(new sngxml::dom::Element(U"a"));
 386         next->SetAttribute(U"href"nextLink);
 387         next->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U"next")));
 388         pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(next.release()));
 389     }
 390     else
 391     {
 392         pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U"next")));
 393     }
 394     if (navigation == Navigation::header)
 395     {
 396         std::unique_ptr<sngxml::dom::Element> hr(new sngxml::dom::Element(U"hr"));
 397         pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(hr.release()));
 398     }
 399 }
 400 
 401 std::u32string GetProject(sngxml::dom::Element* element);
 402 
 403 enum class DocFlags : uint8_t 
 404 {
 405     none=  0
 406     full=  1 << 0
 407     paragraph=  1 << 1
 408     moduleDoc=  1 << 2
 409 };
 410 
 411 inline DocFlags operator&(DocFlags leftDocFlags right)
 412 {
 413     return DocFlags(uint8_t(left) & uint8_t(right));
 414 }
 415 
 416 inline DocFlags operator|(DocFlags leftDocFlags right)
 417 {
 418     return DocFlags(uint8_t(left) | uint8_t(right));
 419 }
 420 
 421 inline DocFlags operator~(DocFlags flags)
 422 {
 423     return DocFlags(~uint8_t(flags));
 424 }
 425 
 426 std::set<std::u32string> headerElementNames;
 427 
 428 void InitHeaderElementNames()
 429 {
 430     headerElementNames.insert(U"h1");
 431     headerElementNames.insert(U"h2");
 432     headerElementNames.insert(U"h3");
 433     headerElementNames.insert(U"h4");
 434     headerElementNames.insert(U"h5");
 435 }
 436 
 437 bool IsHeaderElement(sngxml::dom::Node* node)
 438 {
 439     if (!node) return false;
 440     if (node->GetNodeType() != sngxml::dom::NodeType::elementNode) return false;
 441     sngxml::dom::Element* element = static_cast<sngxml::dom::Element*>(node);
 442     if (headerElementNames.find(element->Name()) != headerElementNames.cend())
 443     {
 444         return true;
 445     }
 446     return false;
 447 }
 448 
 449 sngxml::dom::Element* GetContainerElement(sngxml::dom::Element* element)
 450 {
 451     if (element->Name() == U"class" || element->Name() == U"namespace" || element->Name() == U"enumType")
 452     {
 453         return element;
 454     }
 455     else if (element->Parent())
 456     {
 457         if (element->Parent()->GetNodeType() == sngxml::dom::NodeType::elementNode)
 458         {
 459             sngxml::dom::Element* parentElement = static_cast<sngxml::dom::Element*>(element->Parent());
 460             return GetContainerElement(parentElement);
 461         }
 462     }
 463     return element;
 464 }
 465 
 466 void GenerateDocContent(const std::u32string& projectNamesngxml::dom::Element* elementconst std::string& documentationXmlFileNamesngxml::dom::Document* documentationXml
 467     sngxml::dom::Element* parentElementconst std::u32string& idsngxml::dom::Document* contentXmlHtmlContentFilePathResolver* contentFilePathResolverDocFlags flags)
 468 {
 469     sngxml::dom::Element * paragraphElement;
 470     if ((flags & DocFlags::paragraph) != DocFlags::none)
 471     {
 472         if (!IsHeaderElement(element->FirstChild()))
 473         {
 474             paragraphElement = new sngxml::dom::Element(U"p");
 475             parentElement->AppendChild(std::unique_ptr<sngxml::dom::Element>(paragraphElement));
 476             parentElement = paragraphElement;
 477         }
 478     }
 479     sngxml::dom::Node* child = element->FirstChild();
 480     while (child != nullptr)
 481     {
 482         switch (child->GetNodeType())
 483         {
 484             case sngxml::dom::NodeType::elementNode:
 485             {
 486                 sngxml::dom::Element* childElement = static_cast<sngxml::dom::Element*>(child);
 487                 if (childElement->Name() == U"link")
 488                 {
 489                     std::u32string refId = childElement->GetAttribute(U"ref");
 490                     sngxml::dom::Element* refElement = contentXml->GetElementById(refId);
 491                     if (refElement)
 492                     {
 493                         std::u32string project = GetProject(refElement);
 494                         if (!project.empty())
 495                         {
 496                             std::string dirPath = ".";
 497                             if ((flags & DocFlags::moduleDoc) != DocFlags::none)
 498                             {
 499                                 dirPath = "html/content";
 500                             }
 501                             sngxml::dom::Element* containerElement = GetContainerElement(refElement);
 502                             std::u32string link = ToUtf32(contentFilePathResolver->ResolveContentFilePath(projectNameprojectdirPathcontainerElement->GetAttribute(U"id")));
 503                             if (!link.empty())
 504                             {
 505                                 if (refElement != containerElement)
 506                                 {
 507                                     link.append(1'#').append(refId);
 508                                 }
 509                                 std::unique_ptr<sngxml::dom::Element> a(new sngxml::dom::Element(U"a"));
 510                                 a->SetAttribute(U"href"link);
 511                                 a->AppendChild(childElement->FirstChild()->CloneNode(true));
 512                                 parentElement->AppendChild(std::move(a));
 513                             }
 514                             else
 515                             {
 516                                 std::cerr << "warning: " << documentationXmlFileName << ":" << ToUtf8(id) + ": content file path for link element '" + ToUtf8(refId) + "' not found" << std::endl;
 517                             }
 518                         }
 519                         else
 520                         {
 521                             std::cerr << "warning: " << documentationXmlFileName << ":" << ToUtf8(id) + ": project for link element '" + ToUtf8(refId) + "' not found" << std::endl;
 522                         }
 523                     }
 524                     else
 525                     {
 526                         std::cerr << "warning: " << documentationXmlFileName << ":" << ToUtf8(id) + ": referenced element '" + ToUtf8(refId) + "' not found" << std::endl;
 527                     }
 528                 }
 529                 else
 530                 {
 531                     std::unique_ptr<sngxml::dom::Node> c(childElement->CloneNode(false));
 532                     GenerateDocContent(projectNamechildElementdocumentationXmlFileNamedocumentationXmlstatic_cast<sngxml::dom::Element*>(c.get())idcontentXmlcontentFilePathResolver
 533                         flags & ~DocFlags::paragraph);
 534                     parentElement->AppendChild(std::move(c));
 535                 }
 536                 break;
 537             }
 538             default:
 539             {
 540                 parentElement->AppendChild(child->CloneNode(true));
 541                 break;
 542             }
 543         }
 544         child = child->NextSibling();
 545     }
 546 }
 547 
 548 void GenerateDocumentation(const std::u32string& projectNameconst std::string& documentationXmlFileNamesngxml::dom::Document* documentationXmlsngxml::dom::Element* parentElement
 549     const std::u32string& idsngxml::dom::Document* contentXmlHtmlContentFilePathResolver* contentFilePathResolverDocFlags flags)
 550 {
 551     if (!documentationXml) return;
 552     sngxml::dom::Element* documentationElement = documentationXml->GetElementById(id);
 553     if (!documentationElement) return;
 554     std::unique_ptr<sngxml::xpath::XPathObject> description = sngxml::xpath::Evaluate(U"description"documentationElement);
 555     if (description)
 556     {
 557         if (description->Type() == sngxml::xpath::XPathObjectType::nodeSet)
 558         {
 559             sngxml::xpath::XPathNodeSet* nodeSet = static_cast<sngxml::xpath::XPathNodeSet*>(description.get());
 560             int n = nodeSet->Length();
 561             if (n > 0)
 562             {
 563                 for (int i = 0; i < n; ++i)
 564                 {
 565                     sngxml::dom::Node* node = (*nodeSet)[i];
 566                     if (node->GetNodeType() == sngxml::dom::NodeType::elementNode)
 567                     {
 568                         sngxml::dom::Element* descriptionElement = static_cast<sngxml::dom::Element*>(node);
 569                         GenerateDocContent(projectNamedescriptionElementdocumentationXmlFileNamedocumentationXmlparentElementidcontentXmlcontentFilePathResolverflags);
 570                     }
 571                     else
 572                     {
 573                         std::cerr << "warning: " << documentationXmlFileName << ":" << ToUtf8(id) + ": description not an element node" << std::endl;
 574                     }
 575                 }
 576             }
 577             else
 578             {
 579                 std::cerr << "warning: " << documentationXmlFileName << ":" << ToUtf8(id) + ": no description element" << std::endl;
 580             }
 581         }
 582         else
 583         {
 584             std::cerr << "warning: " << documentationXmlFileName << ":" << ToUtf8(id) + ": no description element" << std::endl;
 585         }
 586     }
 587     else
 588     {
 589         std::cerr << "warning: " << documentationXmlFileName << ":" << ToUtf8(id) + ": no description element" << std::endl;
 590     }
 591     if ((flags & DocFlags::full) == DocFlags::none) return;
 592     std::unique_ptr<sngxml::xpath::XPathObject> body = sngxml::xpath::Evaluate(U"body"documentationElement);
 593     if (body)
 594     {
 595         if (body->Type() == sngxml::xpath::XPathObjectType::nodeSet)
 596         {
 597             sngxml::xpath::XPathNodeSet* nodeSet = static_cast<sngxml::xpath::XPathNodeSet*>(body.get());
 598             int n = nodeSet->Length();
 599             for (int i = 0; i < n; ++i)
 600             {
 601                 sngxml::dom::Node* node = (*nodeSet)[i];
 602                 if (node->GetNodeType() == sngxml::dom::NodeType::elementNode)
 603                 {
 604                     sngxml::dom::Element* bodyElement = static_cast<sngxml::dom::Element*>(node);
 605                     GenerateDocContent(projectNamebodyElementdocumentationXmlFileNamedocumentationXmlparentElementidcontentXmlcontentFilePathResolver
 606                         flags | DocFlags::paragraph);
 607                 }
 608             }
 609         }
 610     }
 611 }
 612 
 613 bool GenerateNamespaceNames(const std::u32string& mainProjectNameint levelsngxml::dom::Element* namespaceTableElementsngxml::dom::Element* namespaceParentElement
 614     const std::u32string& moduleNamebool globalHtmlContentFilePathResolver* contentFilePathResolver);
 615 
 616 bool GenerateNamespaceNames(const std::u32string& mainProjectNameint levelsngxml::dom::Element* namespaceTableElementsngxml::dom::Element* namespaceParentElement
 617     const std::u32string& moduleNameHtmlContentFilePathResolver* contentFilePathResolver)
 618 {
 619     return GenerateNamespaceNames(mainProjectNamelevelnamespaceTableElementnamespaceParentElementmoduleNamefalsecontentFilePathResolver);
 620 }
 621 
 622 bool GenerateNamespaceNames(const std::u32string& mainProjectNameint levelsngxml::dom::Element* namespaceTableElementsngxml::dom::Element* namespaceParentElement
 623     const std::u32string& moduleNamebool globalHtmlContentFilePathResolver* contentFilePathResolver)
 624 {
 625     bool rowAdded = false;
 626     std::unique_ptr<sngxml::xpath::XPathObject> namespaces = sngxml::xpath::Evaluate(U"namespaces/namespace"namespaceParentElement);
 627     if (namespaces->Type() == sngxml::xpath::XPathObjectType::nodeSet || global)
 628     {
 629         sngxml::xpath::XPathNodeSet* namespacesNodeSet = static_cast<sngxml::xpath::XPathNodeSet*>(namespaces.get());
 630         int n = namespacesNodeSet->Length();
 631         if (global)
 632         {
 633             n = 1;
 634         }
 635         for (int i = 0; i < n; ++i)
 636         {
 637             std::u32string projectName;
 638             sngxml::dom::Node* nsNode = nullptr;
 639             if (global)
 640             {
 641                 nsNode = namespaceParentElement;
 642             }
 643             else
 644             {
 645                 nsNode = (*namespacesNodeSet)[i];
 646             }
 647             if (nsNode->GetNodeType() == sngxml::dom::NodeType::elementNode)
 648             {
 649                 sngxml::dom::Element* nsElement = static_cast<sngxml::dom::Element*>(nsNode);
 650                 bool addRow = false;
 651                 std::unique_ptr<sngxml::xpath::XPathObject> project = sngxml::xpath::Evaluate(U"projects/project"nsElement);
 652                 if (project->Type() == sngxml::xpath::XPathObjectType::nodeSet)
 653                 {
 654                     sngxml::xpath::XPathNodeSet* projectNodeSet = static_cast<sngxml::xpath::XPathNodeSet*>(project.get());
 655                     int m = projectNodeSet->Length();
 656                     for (int k = 0; k < m; ++k)
 657                     {
 658                         sngxml::dom::Node* projectNode = (*projectNodeSet)[k];
 659                         if (projectNode->GetNodeType() == sngxml::dom::NodeType::elementNode)
 660                         {
 661                             sngxml::dom::Element* projectElement = static_cast<sngxml::dom::Element*>(projectNode);
 662                             std::u32string projName = projectElement->GetAttribute(U"name");
 663                             if (projName == mainProjectName)
 664                             {
 665                                 projectName = projName;
 666                                 addRow = true;
 667                                 break;
 668                             }
 669                         }
 670                     }
 671                 }
 672                 if (addRow)
 673                 {
 674                     rowAdded = true;
 675                     std::unique_ptr<sngxml::dom::Element> trElement(new sngxml::dom::Element(U"tr"));
 676                     for (int l = 0; l < level; ++l)
 677                     {
 678                         std::unique_ptr<sngxml::dom::Element> tdElement(new sngxml::dom::Element(U"td"));
 679                         trElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(tdElement.release()));
 680                     }
 681                     std::unique_ptr<sngxml::dom::Element> tdElement(new sngxml::dom::Element(U"td"));
 682                     std::u32string nsName = nsElement->GetAttribute(U"name");
 683                     if (nsName.empty())
 684                     {
 685                         nsName = U"Global Namespace";
 686                     }
 687                     std::u32string nsId = nsElement->GetAttribute(U"id");
 688                     std::unique_ptr<sngxml::dom::Element> linkElement(new sngxml::dom::Element(U"a"));
 689                     std::u32string link;
 690                     if (!moduleName.empty())
 691                     {
 692                         link.append(U"html/content/");
 693                     }
 694                     link.append(ToUtf32(contentFilePathResolver->ResolveContentFilePath(mainProjectNameprojectName"."nsId)));
 695                     linkElement->SetAttribute(U"href"link);
 696                     linkElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(nsName)));
 697                     tdElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(linkElement.release()));
 698                     trElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(tdElement.release()));
 699                     namespaceTableElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(trElement.release()));
 700                     bool subRowAdded = GenerateNamespaceNames(mainProjectNamelevel + 1namespaceTableElementnsElementmoduleNamecontentFilePathResolver);
 701                     if (subRowAdded)
 702                     {
 703                         rowAdded = true;
 704                     }
 705                 }
 706             }
 707         }
 708     }
 709     return rowAdded;
 710 }
 711 
 712 std::u32string GetProject(sngxml::dom::Element* element)
 713 {
 714     if (!element) return std::u32string();
 715     std::u32string elementProjectName = element->GetAttribute(U"project");
 716     if (!elementProjectName.empty())
 717     {
 718         return elementProjectName;
 719     }
 720     else
 721     {
 722         sngxml::dom::ParentNode* parent = element->Parent();
 723         if (parent->GetNodeType() == sngxml::dom::NodeType::elementNode)
 724         {
 725             return GetProject(static_cast<sngxml::dom::Element*>(parent));
 726         }
 727         else
 728         {
 729             return std::u32string();
 730         }
 731     }
 732 }
 733 
 734 bool ProjectNameMatches(sngxml::dom::Element* elementconst std::u32string& projectName)
 735 {
 736     if (!element) return false;
 737     std::u32string elementProjectName = element->GetAttribute(U"project");
 738     if (!elementProjectName.empty())
 739     {
 740         return elementProjectName == projectName;
 741     }
 742     else
 743     {
 744         sngxml::dom::ParentNode* parent = element->Parent();
 745         if (parent->GetNodeType() == sngxml::dom::NodeType::elementNode)
 746         {
 747             return ProjectNameMatches(static_cast<sngxml::dom::Element*>(parent)projectName);
 748         }
 749         else
 750         {
 751             return false;
 752         }
 753     }
 754 }
 755 
 756 bool GenerateNamespaceSection(const std::u32string& mainProjectNamesngxml::dom::Element* parentNsElementsngxml::dom::Element* pageElementsngxml::dom::Document* contentXml
 757     const std::u32string& moduleNamebool globalHtmlContentFilePathResolver* contentFilePathResolverconst std::string& documentationXmlFileNamesngxml::dom::Document* documentationXml);
 758 
 759 void GenerateNamespaceSection(const std::u32string& mainProjectNamesngxml::dom::Element* parentNsElementsngxml::dom::Element* pageElementsngxml::dom::Document* contentXml
 760     const std::u32string& moduleNameHtmlContentFilePathResolver* contentFilePathResolverconst std::string& documentationXmlFileNamesngxml::dom::Document* documentationXml)
 761 {
 762     GenerateNamespaceSection(mainProjectNameparentNsElementpageElementcontentXmlmoduleNamefalsecontentFilePathResolverdocumentationXmlFileNamedocumentationXml);
 763 }
 764 
 765 bool GenerateNamespaceSection(const std::u32string& mainProjectNamesngxml::dom::Element* parentNsElementsngxml::dom::Element* pageElementsngxml::dom::Document* contentXml
 766     const std::u32string& moduleNamebool globalHtmlContentFilePathResolver* contentFilePathResolverconst std::string& documentationXmlFileNamesngxml::dom::Document* documentationXml)
 767 {
 768     std::unique_ptr<sngxml::dom::Element> namespaceTableElement(new sngxml::dom::Element(U"table"));
 769     if (GenerateNamespaceNames(mainProjectName0namespaceTableElement.get()parentNsElementmoduleNameglobalcontentFilePathResolver))
 770     {
 771         std::unique_ptr<sngxml::dom::Element> h2Element(new sngxml::dom::Element(U"h2"));
 772         h2Element->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U"Namespaces")));
 773         pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(h2Element.release()));
 774         pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(namespaceTableElement.release()));
 775         return true;
 776     }
 777     else
 778     {
 779         return false;
 780     }
 781 }
 782 
 783 sngxml::dom::Element* GetGlobalNsElement(sngxml::dom::Document* contentXml)
 784 {
 785     std::unique_ptr<sngxml::xpath::XPathObject> globalNs = sngxml::xpath::Evaluate(U"/symbolTable/namespace"contentXml);
 786     if (globalNs->Type() == sngxml::xpath::XPathObjectType::nodeSet)
 787     {
 788         sngxml::xpath::XPathNodeSet* globalNsNodeSet = static_cast<sngxml::xpath::XPathNodeSet*>(globalNs.get());
 789         if (globalNsNodeSet->Length() == 1)
 790         {
 791             sngxml::dom::Node* globalNsNode = (*globalNsNodeSet)[0];
 792             if (globalNsNode->GetNodeType() == sngxml::dom::NodeType::elementNode)
 793             {
 794                 sngxml::dom::Element* globalNsElement = static_cast<sngxml::dom::Element*>(globalNsNode);
 795                 return globalNsElement;
 796             }
 797         }
 798     }
 799     return nullptr;
 800 }
 801 
 802 void GenerateModuleNamespaceSection(const std::u32string& mainProjectNamesngxml::dom::Element* pageElementsngxml::dom::Document* contentXmlconst std::u32string& moduleName
 803     HtmlContentFilePathResolver* contentFilePathResolverconst std::string& documentationXmlFileNamesngxml::dom::Document* documentationXml)
 804 {
 805     sngxml::dom::Element* globalNsElement = GetGlobalNsElement(contentXml);
 806     if (globalNsElement)
 807     {
 808         if (!GenerateNamespaceSection(mainProjectNameglobalNsElementpageElementcontentXmlmoduleNametruecontentFilePathResolverdocumentationXmlFileNamedocumentationXml))
 809         {
 810             GenerateNamespaceSection(mainProjectNameglobalNsElementpageElementcontentXmlmoduleNamefalsecontentFilePathResolverdocumentationXmlFileNamedocumentationXml);
 811         }
 812     }
 813 }
 814 
 815 void GenerateModuleGrammarSection(sngxml::dom::Element* pageElementconst std::std::vector<gendoc::html::Grammar>&grammars)
 816 {
 817     if (grammars.empty()) return;
 818     std::unique_ptr<sngxml::dom::Element> h2Element(new sngxml::dom::Element(U"h2"));
 819     h2Element->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U"Grammars")));
 820     pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(h2Element.release()));
 821     std::unique_ptr<sngxml::dom::Element> grammarTableElement(new sngxml::dom::Element(U"table"));
 822     for (const auto& grammar : grammars)
 823     {
 824         std::unique_ptr<sngxml::dom::Element> trElement(new sngxml::dom::Element(U"tr"));
 825         std::unique_ptr<sngxml::dom::Element> tdElement(new sngxml::dom::Element(U"td"));
 826         std::unique_ptr<sngxml::dom::Element> linkElement(new sngxml::dom::Element(U"a"));
 827         linkElement->SetAttribute(U"href"grammar.fileName);
 828         linkElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(grammar.title)));
 829         tdElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(linkElement.release()));
 830         trElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(tdElement.release()));
 831         grammarTableElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(trElement.release()));
 832     }
 833     pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(grammarTableElement.release()));
 834 }
 835 
 836 struct ByRelativeFilePath 
 837 {
 838     bool operator()(SourceFileNode* leftSourceFileNode* right) const
 839     {
 840         return left->RelativeSourceFilePath() < right->RelativeSourceFilePath();
 841     }
 842 };
 843 
 844 void GenerateModuleFileSection(const std::std::vector<sngcpp::ast::SourceFileNode*>&sourceFilessngxml::dom::Element*pageElementconststd::u32string&moduleName)
 845 {
 846     std::vector<SourceFileNode*> moduleSourceFiles;
 847     int n = sourceFiles.size();
 848     for (int i = 0; i < n; ++i)
 849     {
 850         SourceFileNode* sourceFileNode = sourceFiles[i];
 851         if (sourceFileNode->ProjectName() == moduleName)
 852         {
 853             moduleSourceFiles.push_back(sourceFileNode);
 854         }
 855     }
 856     int m = moduleSourceFiles.size();
 857     if (m > 0)
 858     {
 859         std::unique_ptr<sngxml::dom::Element> fileTableElement(new sngxml::dom::Element(U"table"));
 860         std::unique_ptr<sngxml::dom::Element> h2Element(new sngxml::dom::Element(U"h2"));
 861         h2Element->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U"Files")));
 862         pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(h2Element.release()));
 863         std::sort(moduleSourceFiles.begin()moduleSourceFiles.end()ByRelativeFilePath());
 864         for (int i = 0; i < m; ++i)
 865         {
 866             SourceFileNode* sourceFile = moduleSourceFiles[i];
 867             std::u32string sourceFileName = ToUtf32(sourceFile->RelativeSourceFilePath());
 868             std::u32string sourceFileId = U"html/content/" + sourceFile->Id();
 869             std::unique_ptr<sngxml::dom::Element> trElement(new sngxml::dom::Element(U"tr"));
 870             std::unique_ptr<sngxml::dom::Element> tdElement(new sngxml::dom::Element(U"td"));
 871             std::unique_ptr<sngxml::dom::Element> linkElement(new sngxml::dom::Element(U"a"));
 872             linkElement->SetAttribute(U"href"sourceFileId);
 873             linkElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(sourceFileName)));
 874             tdElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(linkElement.release()));
 875             trElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(tdElement.release()));
 876             fileTableElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(trElement.release()));
 877         }
 878         pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(fileTableElement.release()));
 879     }
 880 }
 881 
 882 void GenerateConstructorSection(const std::u32string& projectNamesngxml::dom::Element* pageElementsngxml::dom::Element* parentElementconst std::string& contentDir
 883     const std::string& styleDirNameconst std::string& styleFileNamesngxml::dom::Document* contentXmlstd::std::vector<sngxml::dom::Element*>&constructorElements
 884     HtmlContentFilePathResolver* contentFilePathResolverconst std::string& documentationXmlFileNamesngxml::dom::Document* documentationXml);
 885 
 886 void GenerateFunctionSection(const std::u32string& projectNameconst std::u32string& titlesngxml::dom::Element* pageElementsngxml::dom::Element* parentElementconst std::string& contentDir
 887     const std::string& styleDirNameconst std::string& styleFileNamesngxml::dom::Document* contentXmlstd::std::vector<sngxml::dom::Element*>&functionElements
 888     HtmlContentFilePathResolver* contentFilePathResolverconst std::string& documentationXmlFileNamesngxml::dom::Document* documentationXml);
 889 
 890 void GenerateClassSection(const std::u32string& projectNamesngxml::dom::Element* pageElementsngxml::dom::Element* parentElementsngxml::dom::Document* contentXml
 891     const std::string& contentDirconst std::string& styleDirNameconst std::string& styleFileName
 892     std::std::unordered_map<std::u32stringstd::std::unique_ptr<sngxml::dom::Element>>&inlineCodeMapconststd::string&contentXmlFilePathboolverboseboolrebuild
 893     HtmlContentFilePathResolver* contentFilePathResolverconst std::u32string& topLinkconst std::string& documentationXmlFileNamesngxml::dom::Document* documentationXml);
 894 
 895 void GenerateEnumSection(const std::u32string& projectNamesngxml::dom::Element* pageElementsngxml::dom::Element* parentElementsngxml::dom::Document* contentXml
 896     const std::string& contentDirconst std::string& styleDirNameconst std::string& styleFileNameconst std::string& contentXmlFilePathbool verbosebool rebuild
 897     const std::u32string& topLinkHtmlContentFilePathResolver* contentFilePathResolverconst std::string& documentationXmlFileNamesngxml::dom::Document* documentationXml);
 898 
 899 void GenerateVariableSection(const std::u32string& projectNameconst std::u32string& titlesngxml::dom::Element* pageElementsngxml::dom::Element* parentElementsngxml::dom::Document* contentXml
 900     const std::string& contentDirconst std::string& styleDirNameconst std::string& styleFileName
 901     HtmlContentFilePathResolver* contentFilePathResolverconst std::u32string& topLinkconst std::string& documentationXmlFileNamesngxml::dom::Document* documentationXml);
 902 
 903 void GenerateTypedefSection(const std::u32string& projectNamesngxml::dom::Element* pageElementsngxml::dom::Element* parentElementsngxml::dom::Document* contentXml
 904     const std::string& contentDirconst std::string& styleDirNameconst std::string& styleFileName
 905     HtmlContentFilePathResolver* contentFilePathResolverconst std::u32string& topLinkconst std::string& documentationXmlFileNamesngxml::dom::Document* documentationXml);
 906 
 907 void GenerateFunctionDetailSection(const std::u32string& projectNameconst std::u32string& titleconst std::u32string& functionTitlesngxml::dom::Element* pageElementsngxml::dom::Element* parentElement
 908     std::std::vector<sngxml::dom::Element*>&functionElementssngxml::dom::Document*contentXmlstd::std::unordered_map<std::u32stringstd::std::unique_ptr<sngxml::dom::Element>>&inlineCodeMap
 909     HtmlContentFilePathResolver* contentFilePathResolverconst std::string& documentationXmlFileNamesngxml::dom::Document* documentationXml);
 910 
 911 std::u32string MakeClassName(sngxml::dom::Element* classElement)
 912 {
 913     std::u32string className = classElement->GetAttribute(U"name");
 914     std::unique_ptr<sngxml::xpath::XPathObject> templateParameters = sngxml::xpath::Evaluate(U"templateParameters/templateParameter"classElement);
 915     if (templateParameters->Type() == sngxml::xpath::XPathObjectType::nodeSet)
 916     {
 917         sngxml::xpath::XPathNodeSet* templateParameterNodeSet = static_cast<sngxml::xpath::XPathNodeSet*>(templateParameters.get());
 918         int n = templateParameterNodeSet->Length();
 919         if (n > 0)
 920         {
 921             className.append(1'<');
 922             for (int i = 0; i < n; ++i)
 923             {
 924                 if (i > 0)
 925                 {
 926                     className.append(U", ");
 927                 }
 928                 sngxml::dom::Node* templateParameterNode = (*templateParameterNodeSet)[i];
 929                 if (templateParameterNode->GetNodeType() == sngxml::dom::NodeType::elementNode)
 930                 {
 931                     sngxml::dom::Element* templateParameterElement = static_cast<sngxml::dom::Element*>(templateParameterNode);
 932                     className.append(templateParameterElement->GetAttribute(U"name"));
 933                 }
 934             }
 935             className.append(1'>');
 936         }
 937     }
 938     return className;
 939 }
 940 
 941 std::u32string MakeFullClassName(sngxml::dom::Element* classElement)
 942 {
 943     std::u32string className = MakeClassName(classElement);
 944     std::u32string prefix = GetPrefix(classElement);
 945     if (!prefix.empty())
 946     {
 947         return prefix + U"::" + className;
 948     }
 949     else
 950     {
 951         return className;
 952     }
 953 }
 954 
 955 struct Class 
 956 {
 957     Class(const std::u32string& name_int index_int level_bool subject_bool hasDerivedClasses_const std::u32string& link_);
 958     void Write(CodeFormatter& formatter);
 959     std::u32string name;
 960     int index;
 961     int level;
 962     bool subject;
 963     bool hasDerivedClasses;
 964     std::u32string link;
 965 };
 966 
 967 Class::Class(const std::u32string& name_int index_int level_bool subject_bool hasDerivedClasses_const std::u32string& link_) :
 968     name(name_)index(index_)level(level_)subject(subject_)hasDerivedClasses(hasDerivedClasses_)link(link_)
 969 {
 970 }
 971 
 972 void Class::Write(CodeFormatter& formatter)
 973 {
 974     formatter.Write("{ ");
 975     formatter.Write("name: \"");
 976     formatter.Write(ToUtf8(soulng::lexer::XmlEscape(name)));
 977     formatter.Write("\", ");
 978     formatter.Write("id: \"");
 979     formatter.Write("class_" + std::to_string(index));
 980     formatter.Write("\", ");
 981     formatter.Write("level: ");
 982     formatter.Write(std::to_string(level));
 983     formatter.Write(", ");
 984     formatter.Write("subject: ");
 985     formatter.Write(subject ? "true" : "false");
 986     formatter.Write(", ");
 987     formatter.Write("hasDerivedClasses: ");
 988     formatter.Write(hasDerivedClasses ? "true" : "false");
 989     formatter.Write(", ");
 990     formatter.Write("link: \"");
 991     formatter.Write(ToUtf8(link));
 992     formatter.Write("\"");
 993     formatter.Write(" }");
 994 }
 995 
 996 void GenerateClassData(const std::u32string& projectNamestd::std::vector<Class>&classessngxml::dom::Element*classElementsngxml::dom::Document*contentXmlint&depthint&level
 997     HtmlContentFilePathResolver* contentFilePathResolver)
 998 {
 999     int numBaseClasses = 0;
1000     std::unique_ptr<sngxml::xpath::XPathObject> baseClasses = sngxml::xpath::Evaluate(U"baseClasses/baseClass"classElement);
1001     if (baseClasses->Type() == sngxml::xpath::XPathObjectType::nodeSet)
1002     {
1003         sngxml::xpath::XPathNodeSet* baseClassNodeSet = static_cast<sngxml::xpath::XPathNodeSet*>(baseClasses.get());
1004         int n = baseClassNodeSet->Length();
1005         if (n > 0)
1006         {
1007             ++depth;
1008             --level;
1009             for (int i = 0; i < n; ++i)
1010             {
1011                 sngxml::dom::Node* baseClassNode = (*baseClassNodeSet)[i];
1012                 if (baseClassNode->GetNodeType() == sngxml::dom::NodeType::elementNode)
1013                 {
1014                     sngxml::dom::Element* baseClassIdElement = static_cast<sngxml::dom::Element*>(baseClassNode);
1015                     std::u32string baseClassId = baseClassIdElement->GetAttribute(U"baseClassId");
1016                     sngxml::dom::Element* baseClassElement = contentXml->GetElementById(baseClassId);
1017                     if (baseClassElement)
1018                     {
1019                         if (baseClassElement->Name() == U"specialization")
1020                         {
1021                             std::u32string primaryTypeId = baseClassElement->GetAttribute(U"primaryTypeId");
1022                             baseClassElement = contentXml->GetElementById(primaryTypeId);
1023                         }
1024                         if (baseClassElement)
1025                         {
1026                             if (baseClassElement->Name() == U"class")
1027                             {
1028                                 GenerateClassData(projectNameclassesbaseClassElementcontentXmldepthlevelcontentFilePathResolver);
1029                                 ++numBaseClasses;
1030                             }
1031                         }
1032                     }
1033                 }
1034             }
1035             ++level;
1036         }
1037     }
1038     std::unique_ptr<sngxml::xpath::XPathObject> derivedClasses = sngxml::xpath::Evaluate(U"derivedClasses/derivedClass"classElement);
1039     if (derivedClasses->Type() == sngxml::xpath::XPathObjectType::nodeSet)
1040     {
1041         sngxml::xpath::XPathNodeSet* derivedClassNodeSet = static_cast<sngxml::xpath::XPathNodeSet*>(derivedClasses.get());
1042         int numDerivedClasses = derivedClassNodeSet->Length();
1043         if (level == 0)
1044         {
1045             if (numBaseClasses > 0 || numDerivedClasses > 0)
1046             {
1047                 std::u32string link = ToUtf32(contentFilePathResolver->ResolveContentFilePath(projectNameGetProject(classElement)"."classElement->GetAttribute(U"id")));
1048                 classes.push_back(Class(MakeFullClassName(classElement)classes.size()leveltruenumDerivedClasses > 0link));
1049                 if (numDerivedClasses > 0)
1050                 {
1051                     ++level;
1052                     for (int i = 0; i < numDerivedClasses; ++i)
1053                     {
1054                         sngxml::dom::Node* derivedClassNode = (*derivedClassNodeSet)[i];
1055                         if (derivedClassNode->GetNodeType() == sngxml::dom::NodeType::elementNode)
1056                         {
1057                             sngxml::dom::Element* derivedClassIdElement = static_cast<sngxml::dom::Element*>(derivedClassNode);
1058                             std::u32string derivedClassId = derivedClassIdElement->GetAttribute(U"derivedClassId");
1059                             sngxml::dom::Element* derivedClassElement = contentXml->GetElementById(derivedClassId);
1060                             if (derivedClassElement)
1061                             {
1062                                 if (derivedClassElement->Name() == U"specialization")
1063                                 {
1064                                     std::u32string primaryTypeId = derivedClassElement->GetAttribute(U"primaryTypeId");
1065                                     derivedClassElement = contentXml->GetElementById(primaryTypeId);
1066                                 }
1067                                 if (derivedClassElement)
1068                                 {
1069                                     if (derivedClassElement->Name() == U"class")
1070                                     {
1071                                         std::u32string link = ToUtf32(contentFilePathResolver->ResolveContentFilePath(projectNameGetProject(derivedClassElement)"."derivedClassElement->GetAttribute(U"id")));
1072                                         bool hasDerivedClasses = false;
1073                                         std::unique_ptr<sngxml::xpath::XPathObject> descendantClasses = sngxml::xpath::Evaluate(U"derivedClasses/derivedClass"derivedClassElement);
1074                                         if (descendantClasses->Type() == sngxml::xpath::XPathObjectType::nodeSet)
1075                                         {
1076                                             sngxml::xpath::XPathNodeSet* descendantClassNodeSet = static_cast<sngxml::xpath::XPathNodeSet*>(descendantClasses.get());
1077                                             int numDescendantClasses = descendantClassNodeSet->Length();
1078                                             if (numDescendantClasses > 0)
1079                                             {
1080                                                 hasDerivedClasses = true;
1081                                             }
1082                                         }
1083                                         classes.push_back(Class(MakeFullClassName(derivedClassElement)classes.size()levelfalsehasDerivedClasseslink));
1084                                     }
1085                                 }
1086                             }
1087                         }
1088                     }
1089                 }
1090             }
1091         }
1092         else
1093         {
1094             std::u32string link = ToUtf32(contentFilePathResolver->ResolveContentFilePath(projectNameGetProject(classElement)"."classElement->GetAttribute(U"id")));
1095             classes.push_back(Class(MakeFullClassName(classElement)classes.size()levelfalsenumDerivedClasses > 0link));
1096         }
1097     }
1098 }
1099 
1100 struct ByLevelAndIndex 
1101 {
1102     bool operator()(const Class& leftconst Class& right) const
1103     {
1104         if (left.level < right.level) return true;
1105         if (left.level > right.level) return false;
1106         return left.index < right.index;
1107     }
1108 };
1109 
1110 bool GenerateClassInheritanceDiagramFile(const std::u32string& projectNameconst std::string& contentDirsngxml::dom::Element* classElementsngxml::dom::Document* contentXml
1111     std::string& inheritanceDiagramFileNameHtmlContentFilePathResolver* contentFilePathResolver)
1112 {
1113     int depth = 0;
1114     int level = 0;
1115     std::vector<Class> classes;
1116     GenerateClassData(projectNameclassesclassElementcontentXmldepthlevelcontentFilePathResolver);
1117     if (!classes.empty())
1118     {
1119         for (Class& cls : classes)
1120         {
1121             cls.level += depth;
1122         }
1123         std::sort(classes.begin()classes.end()ByLevelAndIndex());
1124         inheritanceDiagramFileName = ToUtf8(classElement->GetAttribute(U"id")) + "_inheritance.js";
1125         std::string inheritanceDiagramFilePath = Path::Combine(contentDirinheritanceDiagramFileName);
1126         std::ofstream inheritanceDiagramFile(inheritanceDiagramFilePath);
1127         CodeFormatter formatter(inheritanceDiagramFile);
1128         GenerateClassInheritanceDiagramCode(formatter);
1129         formatter.WriteLine("function drawClassInheritanceDiagram() {");
1130         formatter.IncIndent();
1131         formatter.WriteLine("var classes = [");
1132         formatter.IncIndent();
1133         bool first = true;
1134         for (Class& cls : classes)
1135         {
1136             if (first)
1137             {
1138                 first = false;
1139             }
1140             else
1141             {
1142                 formatter.WriteLine(",");
1143             }
1144             cls.Write(formatter);
1145         }
1146         formatter.WriteLine("];");
1147         formatter.DecIndent();
1148         formatter.WriteLine("drawDiagram(classes);");
1149         formatter.DecIndent();
1150         formatter.WriteLine("}");
1151         formatter.WriteLine();
1152         return true;
1153     }
1154     else
1155     {
1156         return false;
1157     }
1158 }
1159 
1160 void GenerateClassContent(const std::u32string& projectNamesngxml::dom::Element* classElementsngxml::dom::Document* contentXmlconst std::string& contentDirconst std::string& styleDirNameconst std::string& styleFileName
1161     const std::u32string& topLinkconst std::u32string& parentLinkconst std::u32string& prevLinkstd::u32string& nextLink
1162     std::std::unordered_map<std::u32stringstd::std::unique_ptr<sngxml::dom::Element>>&inlineCodeMapconststd::string&contentXmlFilePathboolverboseboolrebuild
1163     HtmlContentFilePathResolver* contentFilePathResolverconst std::string& documentationXmlFileNamesngxml::dom::Document* documentationXml)
1164 {
1165     std::vector<sngxml::dom::Element*> constructorElements;
1166     std::vector<sngxml::dom::Element*> functionElements;
1167     std::u32string className = MakeClassName(classElement);
1168     std::u32string classId = classElement->GetAttribute(U"id");
1169     std::u32string classKey = classElement->GetAttribute(U"key");
1170     std::string classFileName = ToUtf8(classId) + ".html";
1171     std::string classFilePath = Path::Combine(contentDirclassFileName);
1172     if (!rebuild)
1173     {
1174         if (boost::filesystem::exists(classFilePath) && boost::filesystem::exists(contentXmlFilePath) && boost::filesystem::last_write_time(contentXmlFilePath) < boost::filesystem::last_write_time(classFilePath))
1175         {
1176             return;
1177         }
1178     }
1179     std::ofstream classFile(classFilePath);
1180     CodeFormatter formatter(classFile);
1181     sngxml::dom::Document classDocument;
1182     std::unique_ptr<sngxml::dom::Element> htmlElement(new sngxml::dom::Element(U"html"));
1183     std::unique_ptr<sngxml::dom::Element> headElement(new sngxml::dom::Element(U"head"));
1184     std::unique_ptr<sngxml::dom::Element> metaElement(new sngxml::dom::Element(U"meta"));
1185     metaElement->SetAttribute(U"charset"U"utf-8");
1186     headElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(metaElement.release()));
1187     std::unique_ptr<sngxml::dom::Element> titleElement(new sngxml::dom::Element(U"title"));
1188     std::u32string abstract_;
1189     if (classElement->GetAttribute(U"abstract") == U"true")
1190     {
1191         abstract_ = U"Abstract ";
1192     }
1193     std::u32string title = className + U" " + abstract_ + MakeTitle(classKey);
1194     titleElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(title)));
1195     headElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(titleElement.release()));
1196     std::unique_ptr<sngxml::dom::Element> linkElement(new sngxml::dom::Element(U"link"));
1197     linkElement->SetAttribute(U"rel"U"stylesheet");
1198     linkElement->SetAttribute(U"type"U"text/css");
1199     std::u32string relativeStyleFilePath = ToUtf32(Path::Combine(Path::Combine(".."styleDirName)styleFileName));
1200     linkElement->SetAttribute(U"href"relativeStyleFilePath);
1201     headElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(linkElement.release()));
1202     std::string inheritanceDiagramFileName;
1203     bool classInheritanceDiagramGenerated = GenerateClassInheritanceDiagramFile(projectNamecontentDirclassElementcontentXmlinheritanceDiagramFileNamecontentFilePathResolver);
1204     if (classInheritanceDiagramGenerated)
1205     {
1206         std::unique_ptr<sngxml::dom::Element> scriptElement(new sngxml::dom::Element(U"script"));
1207         scriptElement->SetAttribute(U"type"U"text/javascript");
1208         scriptElement->SetAttribute(U"src"ToUtf32(inheritanceDiagramFileName));
1209         scriptElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U" ")));
1210         headElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(scriptElement.release()));
1211     }
1212     htmlElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(headElement.release()));
1213     std::unique_ptr<sngxml::dom::Element> bodyElement(new sngxml::dom::Element(U"body"));
1214     GenerateNavigation(bodyElement.get()Navigation::headertopLinkparentLinkprevLinknextLink);
1215     std::unique_ptr<sngxml::dom::Element> h1Element(new sngxml::dom::Element(U"h1"));
1216     h1Element->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(title)));
1217     bodyElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(h1Element.release()));
1218     GenerateDocumentation(projectNamedocumentationXmlFileNamedocumentationXmlbodyElement.get()classIdcontentXmlcontentFilePathResolverDocFlags::full | DocFlags::paragraph);
1219     if (classInheritanceDiagramGenerated)
1220     {
1221         bodyElement->SetAttribute(U"onload"U"drawClassInheritanceDiagram()");
1222         std::unique_ptr<sngxml::dom::Element> divElement(new sngxml::dom::Element(U"div"));
1223         divElement->SetAttribute(U"class"U"diagram");
1224         std::unique_ptr<sngxml::dom::Element> svgElement(new sngxml::dom::Element(U"svg"));
1225         svgElement->SetAttribute(U"width"U"0");
1226         svgElement->SetAttribute(U"height"U"0");
1227         svgElement->SetAttribute(U"id"U"classInheritanceDiagram");
1228         svgElement->SetAttribute(U"xmlns"U"http://www.w3.org/2000/svg");
1229         svgElement->SetAttribute(U"version"U"2.0");
1230         divElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(svgElement.release()));
1231         bodyElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(divElement.release()));
1232     }
1233     std::u32string definitionFileId = classElement->GetAttribute(U"definitionFileId");
1234     if (!definitionFileId.empty())
1235     {
1236         std::unique_ptr<sngxml::dom::Element> span(new sngxml::dom::Element(U"span"));
1237         span->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U"Definition at line ")));
1238         std::unique_ptr<sngxml::dom::Element> lineLink(new sngxml::dom::Element(U"a"));
1239         std::u32string line = classElement->GetAttribute(U"definitionLine");
1240         lineLink->SetAttribute(U"href"definitionFileId + U"#" + line);
1241         lineLink->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(line)));
1242         span->AppendChild(std::unique_ptr<sngxml::dom::Node>(lineLink.release()));
1243         span->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U" of ")));
1244         std::unique_ptr<sngxml::dom::Element> fileLink(new sngxml::dom::Element(U"a"));
1245         fileLink->SetAttribute(U"href"definitionFileId);
1246         fileLink->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(classElement->GetAttribute(U"definitionFile"))));
1247         span->AppendChild(std::unique_ptr<sngxml::dom::Node>(fileLink.release()));
1248         bodyElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(span.release()));
1249         bodyElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Element(U"br")));
1250     }
1251     GenerateClassSection(projectNamebodyElement.get()classElementcontentXmlcontentDirstyleDirNamestyleFileNameinlineCodeMapcontentXmlFilePathverboserebuild
1252         contentFilePathResolvertopLinkdocumentationXmlFileNamedocumentationXml);
1253     GenerateConstructorSection(projectNamebodyElement.get()classElementcontentDirstyleDirNamestyleFileNamecontentXmlconstructorElementscontentFilePathResolver
1254         documentationXmlFileNamedocumentationXml);
1255     GenerateFunctionSection(projectNameU"Member Functions"bodyElement.get()classElementcontentDirstyleDirNamestyleFileNamecontentXmlfunctionElementscontentFilePathResolver
1256         documentationXmlFileNamedocumentationXml);
1257     GenerateEnumSection(projectNamebodyElement.get()classElementcontentXmlcontentDirstyleDirNamestyleFileNamecontentXmlFilePathverboserebuildtopLink
1258         contentFilePathResolverdocumentationXmlFileNamedocumentationXml);
1259     GenerateTypedefSection(projectNamebodyElement.get()classElementcontentXmlcontentDirstyleDirNamestyleFileNamecontentFilePathResolvertopLink
1260         documentationXmlFileNamedocumentationXml);
1261     GenerateVariableSection(projectNameU"Member Variables"bodyElement.get()classElementcontentXmlcontentDirstyleDirNamestyleFileNamecontentFilePathResolvertopLink
1262         documentationXmlFileNamedocumentationXml);
1263     bodyElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Element(U"hr")));
1264     GenerateFunctionDetailSection(projectNameU"Constructor Details"U"Constructor"bodyElement.get()classElementconstructorElementscontentXmlinlineCodeMapcontentFilePathResolver
1265         documentationXmlFileNamedocumentationXml);
1266     GenerateFunctionDetailSection(projectNameU"Member Function Details"U"Member Function"bodyElement.get()classElementfunctionElementscontentXmlinlineCodeMapcontentFilePathResolver
1267         documentationXmlFileNamedocumentationXml);
1268     GenerateNavigation(bodyElement.get()Navigation::footertopLinkparentLinkprevLinknextLink);
1269     htmlElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(bodyElement.release()));
1270     classDocument.AppendChild(std::unique_ptr<sngxml::dom::Node>(htmlElement.release()));
1271     classDocument.Write(formatter);
1272     if (verbose)
1273     {
1274         std::cout << ToUtf8(projectName) << "==> " << classFilePath << std::endl;
1275     }
1276 }
1277 
1278 void GenerateClassSection(const std::u32string& projectNamesngxml::dom::Element* pageElementsngxml::dom::Element* parentElementsngxml::dom::Document* contentXml
1279     const std::string& contentDirconst std::string& styleDirNameconst std::string& styleFileName
1280     std::std::unordered_map<std::u32stringstd::std::unique_ptr<sngxml::dom::Element>>&inlineCodeMapconststd::string&contentXmlFilePathboolverboseboolrebuild
1281     HtmlContentFilePathResolver* contentFilePathResolverconst std::u32string& topLinkconst std::string& documentationXmlFileNamesngxml::dom::Document* documentationXml)
1282 {
1283     std::unique_ptr<sngxml::dom::Element> classTableElement(new sngxml::dom::Element(U"table"));
1284     std::unique_ptr<sngxml::xpath::XPathObject> classes = sngxml::xpath::Evaluate(U"classes/class"parentElement);
1285     if (classes->Type() == sngxml::xpath::XPathObjectType::nodeSet)
1286     {
1287         std::u32string parentLink = parentElement->GetAttribute(U"id") + U".html";
1288         std::u32string prevLink;
1289         std::u32string nextLink;
1290         sngxml::xpath::XPathNodeSet* classNodeSet = static_cast<sngxml::xpath::XPathNodeSet*>(classes.get());
1291         int n = classNodeSet->Length();
1292         std::vector<sngxml::dom::Element*> matchedClasses;
1293         for (int i = 0; i < n; ++i)
1294         {
1295             sngxml::dom::Node* classNode = (*classNodeSet)[i];
1296             sngxml::dom::Element* classElement = static_cast<sngxml::dom::Element*>(classNode);
1297             if (!ProjectNameMatches(classElementprojectName)) continue;
1298             matchedClasses.push_back(classElement);
1299         }
1300         if (!matchedClasses.empty())
1301         {
1302             std::unique_ptr<sngxml::dom::Element> h2Element(new sngxml::dom::Element(U"h2"));
1303             h2Element->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U"Classes")));
1304             pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(h2Element.release()));
1305         }
1306         for (int i = 0; i < matchedClasses.size(); ++i)
1307         {
1308             nextLink.clear();
1309             if (i < matchedClasses.size() - 1)
1310             {
1311                 sngxml::dom::Element* nextClassElement = matchedClasses[i + 1];
1312                 nextLink = nextClassElement->GetAttribute(U"id") + U".html";
1313             }
1314             sngxml::dom::Element* classElement = matchedClasses[i];
1315             std::unique_ptr<sngxml::dom::Element> trElement(new sngxml::dom::Element(U"tr"));
1316             std::unique_ptr<sngxml::dom::Element> tdElement(new sngxml::dom::Element(U"td"));
1317             std::u32string classKey = classElement->GetAttribute(U"key");
1318             std::u32string classId = classElement->GetAttribute(U"id");
1319             std::u32string className = classElement->GetAttribute(U"name");
1320             tdElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(classKey + U" ")));
1321             std::unique_ptr<sngxml::dom::Element> linkElement(new sngxml::dom::Element(U"a"));
1322             std::u32string classLink = classId + U".html";
1323             linkElement->SetAttribute(U"href"classLink);
1324             linkElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(className)));
1325             tdElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(linkElement.release()));
1326             trElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(tdElement.release()));
1327             if (documentationXml && documentationXml->GetElementById(classId) != nullptr)
1328             {
1329                 std::unique_ptr<sngxml::dom::Element> documentationTdElement(new sngxml::dom::Element(U"td"));
1330                 GenerateDocumentation(projectNamedocumentationXmlFileNamedocumentationXmldocumentationTdElement.get()classIdcontentXmlcontentFilePathResolverDocFlags::none);
1331                 trElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(documentationTdElement.release()));
1332             }
1333             classTableElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(trElement.release()));
1334             GenerateClassContent(projectNameclassElementcontentXmlcontentDirstyleDirNamestyleFileNametopLinkparentLinkprevLinknextLinkinlineCodeMap
1335                 contentXmlFilePathverboserebuildcontentFilePathResolverdocumentationXmlFileNamedocumentationXml);
1336             prevLink = classLink;
1337         }
1338         if (!matchedClasses.empty())
1339         {
1340             pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(classTableElement.release()));
1341         }
1342     }
1343 }
1344 
1345 void GenerateEnumContent(const std::u32string& projectNamesngxml::dom::Element* enumTypeElementsngxml::dom::Document* contentXmlconst std::string& contentDirconst std::string& styleDirNameconst std::string& styleFileName
1346     const std::u32string& topLinkconst std::u32string& parentLinkconst std::u32string& prevLinkstd::u32string& nextLinkconst std::string& contentXmlFilePathbool verbosebool rebuild
1347     HtmlContentFilePathResolver* contentFilePathResolverconst std::string& documentationXmlFileNamesngxml::dom::Document* documentationXml)
1348 {
1349     std::u32string enumTypeName = enumTypeElement->GetAttribute(U"name");
1350     std::u32string enumTypeId = enumTypeElement->GetAttribute(U"id");
1351     std::u32string enumKey = enumTypeElement->GetAttribute(U"key");
1352     std::string enumFileName = ToUtf8(enumTypeId) + ".html";
1353     std::string enumFilePath = Path::Combine(contentDirenumFileName);
1354     std::ofstream enumFile(enumFilePath);
1355     if (!rebuild)
1356     {
1357         if (boost::filesystem::exists(enumFilePath) && boost::filesystem::exists(contentXmlFilePath) && boost::filesystem::last_write_time(contentXmlFilePath) < boost::filesystem::last_write_time(enumFilePath))
1358         {
1359             return;
1360         }
1361     }
1362     CodeFormatter formatter(enumFile);
1363     sngxml::dom::Document enumDocument;
1364     std::unique_ptr<sngxml::dom::Element> htmlElement(new sngxml::dom::Element(U"html"));
1365     std::unique_ptr<sngxml::dom::Element> headElement(new sngxml::dom::Element(U"head"));
1366     std::unique_ptr<sngxml::dom::Element> metaElement(new sngxml::dom::Element(U"meta"));
1367     metaElement->SetAttribute(U"charset"U"utf-8");
1368     headElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(metaElement.release()));
1369     std::unique_ptr<sngxml::dom::Element> titleElement(new sngxml::dom::Element(U"title"));
1370     std::u32string title = enumTypeName + U" Enumeration";
1371     titleElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(title)));
1372     headElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(titleElement.release()));
1373     std::unique_ptr<sngxml::dom::Element> linkElement(new sngxml::dom::Element(U"link"));
1374     linkElement->SetAttribute(U"rel"U"stylesheet");
1375     linkElement->SetAttribute(U"type"U"text/css");
1376     std::u32string relativeStyleFilePath = ToUtf32(Path::Combine(Path::Combine(".."styleDirName)styleFileName));
1377     linkElement->SetAttribute(U"href"relativeStyleFilePath);
1378     headElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(linkElement.release()));
1379     htmlElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(headElement.release()));
1380     std::unique_ptr<sngxml::dom::Element> bodyElement(new sngxml::dom::Element(U"body"));
1381     GenerateNavigation(bodyElement.get()Navigation::headertopLinkparentLinkprevLinknextLink);
1382     std::unique_ptr<sngxml::dom::Element> h1Element(new sngxml::dom::Element(U"h1"));
1383     h1Element->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(title)));
1384     bodyElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(h1Element.release()));
1385     GenerateDocumentation(projectNamedocumentationXmlFileNamedocumentationXmlbodyElement.get()enumTypeIdcontentXmlcontentFilePathResolverDocFlags::full | DocFlags::paragraph);
1386     std::u32string definitionFileId = enumTypeElement->GetAttribute(U"definitionFileId");
1387     if (!definitionFileId.empty())
1388     {
1389         std::unique_ptr<sngxml::dom::Element> span(new sngxml::dom::Element(U"span"));
1390         span->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U"Definition at line ")));
1391         std::unique_ptr<sngxml::dom::Element> lineLink(new sngxml::dom::Element(U"a"));
1392         std::u32string line = enumTypeElement->GetAttribute(U"definitionLine");
1393         lineLink->SetAttribute(U"href"definitionFileId + U"#" + line);
1394         lineLink->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(line)));
1395         span->AppendChild(std::unique_ptr<sngxml::dom::Node>(lineLink.release()));
1396         span->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U" of ")));
1397         std::unique_ptr<sngxml::dom::Element> fileLink(new sngxml::dom::Element(U"a"));
1398         fileLink->SetAttribute(U"href"definitionFileId);
1399         fileLink->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(enumTypeElement->GetAttribute(U"definitionFile"))));
1400         span->AppendChild(std::unique_ptr<sngxml::dom::Node>(fileLink.release()));
1401         bodyElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(span.release()));
1402         bodyElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Element(U"br")));
1403     }
1404     std::unique_ptr<sngxml::xpath::XPathObject> enumerators = sngxml::xpath::Evaluate(U"enumerators/enumerator"enumTypeElement);
1405     if (enumerators->Type() == sngxml::xpath::XPathObjectType::nodeSet)
1406     {
1407         sngxml::xpath::XPathNodeSet* enumeratorNodeSet = static_cast<sngxml::xpath::XPathNodeSet*>(enumerators.get());
1408         int n = enumeratorNodeSet->Length();
1409         if (n > 0)
1410         {
1411             std::unique_ptr<sngxml::dom::Element> h2Element(new sngxml::dom::Element(U"h2"));
1412             h2Element->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U"Enumerators")));
1413             bodyElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(h2Element.release()));
1414             std::unique_ptr<sngxml::dom::Element> enumeratorTableElement(new sngxml::dom::Element(U"table"));
1415             std::unique_ptr<sngxml::dom::Element> trElement(new sngxml::dom::Element(U"tr"));
1416             std::unique_ptr<sngxml::dom::Element> nameThElement(new sngxml::dom::Element(U"th"));
1417             nameThElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U"Name")));
1418             trElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(nameThElement.release()));
1419             std::unique_ptr<sngxml::dom::Element> valueThElement(new sngxml::dom::Element(U"th"));
1420             valueThElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U"Value")));
1421             trElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(valueThElement.release()));
1422             enumeratorTableElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(trElement.release()));
1423             for (int i = 0; i < n; ++i)
1424             {
1425                 sngxml::dom::Node* node = (*enumeratorNodeSet)[i];
1426                 if (node->GetNodeType() == sngxml::dom::NodeType::elementNode)
1427                 {
1428                     sngxml::dom::Element* enumeratorElement = static_cast<sngxml::dom::Element*>(node);
1429                     std::u32string enumeratorName = enumeratorElement->GetAttribute(U"name");
1430                     std::u32string enumeratorValue = enumeratorElement->GetAttribute(U"value");
1431                     std::u32string enumeratorId = enumeratorElement->GetAttribute(U"id");
1432                     std::unique_ptr<sngxml::dom::Element> trElement(new sngxml::dom::Element(U"tr"));
1433                     trElement->SetAttribute(U"id"enumeratorId);
1434                     std::unique_ptr<sngxml::dom::Element> nameTdElement(new sngxml::dom::Element(U"td"));
1435                     nameTdElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(enumeratorName)));
1436                     trElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(nameTdElement.release()));
1437                     std::unique_ptr<sngxml::dom::Element> valueTdElement(new sngxml::dom::Element(U"td"));
1438                     valueTdElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(enumeratorValue)));
1439                     trElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(valueTdElement.release()));
1440                     enumeratorTableElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(trElement.release()));
1441                 }
1442             }
1443             bodyElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(enumeratorTableElement.release()));
1444         }
1445     }
1446     bodyElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Element(U"hr")));
1447     GenerateNavigation(bodyElement.get()Navigation::footertopLinkparentLinkprevLinknextLink);
1448     htmlElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(bodyElement.release()));
1449     enumDocument.AppendChild(std::unique_ptr<sngxml::dom::Node>(htmlElement.release()));
1450     enumDocument.Write(formatter);
1451     if (verbose)
1452     {
1453         std::cout << ToUtf8(projectName) << "==> " << enumFilePath << std::endl;
1454     }
1455 }
1456 
1457 void GenerateEnumSection(const std::u32string& projectNamesngxml::dom::Element* pageElementsngxml::dom::Element* parentElementsngxml::dom::Document* contentXml
1458     const std::string& contentDirconst std::string& styleDirNameconst std::string& styleFileNameconst std::string& contentXmlFilePathbool verbosebool rebuild
1459     const std::u32string& topLinkHtmlContentFilePathResolver* contentFilePathResolverconst std::string& documentationXmlFileNamesngxml::dom::Document* documentationXml)
1460 {
1461     std::unique_ptr<sngxml::dom::Element> enumTableElement(new sngxml::dom::Element(U"table"));
1462     std::unique_ptr<sngxml::xpath::XPathObject> enumTypes = sngxml::xpath::Evaluate(U"enumTypes/enumType"parentElement);
1463     if (enumTypes->Type() == sngxml::xpath::XPathObjectType::nodeSet)
1464     {
1465         std::u32string parentLink = parentElement->GetAttribute(U"id") + U".html";
1466         std::u32string prevLink;
1467         std::u32string nextLink;
1468         sngxml::xpath::XPathNodeSet* enumTypeNodeSet = static_cast<sngxml::xpath::XPathNodeSet*>(enumTypes.get());
1469         int n = enumTypeNodeSet->Length();
1470         std::vector<sngxml::dom::Element*> matchedEnums;
1471         for (int i = 0; i < n; ++i)
1472         {
1473             sngxml::dom::Node* enumNode = (*enumTypeNodeSet)[i];
1474             sngxml::dom::Element* enumElement = static_cast<sngxml::dom::Element*>(enumNode);
1475             if (!ProjectNameMatches(enumElementprojectName)) continue;
1476             matchedEnums.push_back(enumElement);
1477         }
1478         if (!matchedEnums.empty())
1479         {
1480             std::unique_ptr<sngxml::dom::Element> h2Element(new sngxml::dom::Element(U"h2"));
1481             h2Element->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U"Enumerations")));
1482             pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(h2Element.release()));
1483         }
1484         for (int i = 0; i < matchedEnums.size(); ++i)
1485         {
1486             nextLink.clear();
1487             if (i < matchedEnums.size() - 1)
1488             {
1489                 sngxml::dom::Element* nextEnumTypeElement = static_cast<sngxml::dom::Element*>(matchedEnums[i + 1]);
1490                 nextLink = nextEnumTypeElement->GetAttribute(U"id") + U".html";
1491             }
1492             sngxml::dom::Element* enumTypeElement = static_cast<sngxml::dom::Element*>(matchedEnums[i]);
1493             std::unique_ptr<sngxml::dom::Element> trElement(new sngxml::dom::Element(U"tr"));
1494             std::unique_ptr<sngxml::dom::Element> tdElement(new sngxml::dom::Element(U"td"));
1495             std::u32string enumKey = enumTypeElement->GetAttribute(U"key");
1496             std::u32string enumId = enumTypeElement->GetAttribute(U"id");
1497             std::u32string enumTypeName = enumTypeElement->GetAttribute(U"name");
1498             tdElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(enumKey + U" ")));
1499             std::unique_ptr<sngxml::dom::Element> linkElement(new sngxml::dom::Element(U"a"));
1500             std::u32string enumTypeLink = enumId + U".html";
1501             linkElement->SetAttribute(U"href"enumTypeLink);
1502             linkElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(enumTypeName)));
1503             tdElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(linkElement.release()));
1504             trElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(tdElement.release()));
1505             if (documentationXml && documentationXml->GetElementById(enumId) != nullptr)
1506             {
1507                 std::unique_ptr<sngxml::dom::Element> documentationTdElement(new sngxml::dom::Element(U"td"));
1508                 GenerateDocumentation(projectNamedocumentationXmlFileNamedocumentationXmldocumentationTdElement.get()enumIdcontentXmlcontentFilePathResolverDocFlags::none);
1509                 trElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(documentationTdElement.release()));
1510             }
1511             enumTableElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(trElement.release()));
1512             GenerateEnumContent(projectNameenumTypeElementcontentXmlcontentDirstyleDirNamestyleFileNametopLinkparentLinkprevLinknextLinkcontentXmlFilePathverboserebuild
1513                 contentFilePathResolverdocumentationXmlFileNamedocumentationXml);
1514             prevLink = enumTypeLink;
1515         }
1516         if (!matchedEnums.empty())
1517         {
1518             pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(enumTableElement.release()));
1519         }
1520     }
1521 }
1522 
1523 void AppendTypeName(const std::u32string& projectNamesngxml::dom::Element* pageElementsngxml::dom::Element* parentElementconst std::u32string& typeIdsngxml::dom::Document* contentXml
1524     HtmlContentFilePathResolver* contentFilePathResolver)
1525 {
1526     sngxml::dom::Element* typeElement = contentXml->GetElementById(typeId);
1527     if (typeElement)
1528     {
1529         std::u32string typeProject = GetProject(typeElement);
1530         std::u32string typeElementName = typeElement->Name();
1531         if (typeElementName == U"simpleType")
1532         {
1533             std::unique_ptr<sngxml::dom::Element> span(new sngxml::dom::Element(U"span"));
1534             span->SetAttribute(U"class"U"kw");
1535             span->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(typeElement->GetAttribute(U"name"))));
1536             pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(span.release()));
1537         }
1538         else if (typeElementName == U"externalType")
1539         {
1540             pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(typeElement->GetAttribute(U"name"))));
1541         }
1542         else if (typeElementName == U"integerLiteralType")
1543         {
1544             pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(typeElement->GetAttribute(U"name"))));
1545         }
1546         else if (typeElementName == U"derivedType")
1547         {
1548             std::unique_ptr<sngxml::xpath::XPathObject> derivations = sngxml::xpath::Evaluate(U"derivations/derivation"typeElement);
1549             if (derivations->Type() == sngxml::xpath::XPathObjectType::nodeSet)
1550             {
1551                 sngxml::xpath::XPathNodeSet* derivationNodeSet = static_cast<sngxml::xpath::XPathNodeSet*>(derivations.get());
1552                 int n = derivationNodeSet->Length();
1553                 for (int i = 0; i < n; ++i)
1554                 {
1555                     sngxml::dom::Node* derivationNode = (*derivationNodeSet)[i];
1556                     if (derivationNode->GetNodeType() == sngxml::dom::NodeType::elementNode)
1557                     {
1558                         sngxml::dom::Element* derivationElement = static_cast<sngxml::dom::Element*>(derivationNode);
1559                         std::u32string derivationKind = derivationElement->GetAttribute(U"kind");
1560                         if (derivationKind == U"base")
1561                         {
1562                             std::u32string typeId = derivationElement->GetAttribute(U"typeId");
1563                             AppendTypeName(projectNamepageElementparentElementtypeIdcontentXmlcontentFilePathResolver);
1564                         }
1565                         else
1566                         {
1567                             std::u32string derivationStr = derivationElement->GetAttribute(U"str");
1568                             if (derivationKind == U"specifier")
1569                             {
1570                                 std::unique_ptr<sngxml::dom::Element> span(new sngxml::dom::Element(U"span"));
1571                                 span->SetAttribute(U"class"U"kw");
1572                                 span->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(derivationStr)));
1573                                 pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(span.release()));
1574                             }
1575                             else
1576                             {
1577                                 pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(derivationStr)));
1578                             }
1579                         }
1580                     }
1581                 }
1582             }
1583         }
1584         else if (typeElementName == U"specialization")
1585         {
1586             std::u32string primaryTypeId = typeElement->GetAttribute(U"primaryTypeId");
1587             AppendTypeName(projectNamepageElementparentElementprimaryTypeIdcontentXmlcontentFilePathResolver);
1588             pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U"<")));
1589             std::unique_ptr<sngxml::xpath::XPathObject> templateArguments = sngxml::xpath::Evaluate(U"templateArguments/templateArgument"typeElement);
1590             if (templateArguments->Type() == sngxml::xpath::XPathObjectType::nodeSet)
1591             {
1592                 sngxml::xpath::XPathNodeSet* templateArgumentNodeSet = static_cast<sngxml::xpath::XPathNodeSet*>(templateArguments.get());
1593                 int n = templateArgumentNodeSet->Length();
1594                 for (int i = 0; i < n; ++i)
1595                 {
1596                     if (i > 0)
1597                     {
1598                         pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U", ")));
1599                     }
1600                     sngxml::dom::Node* templateArgumentNode = (*templateArgumentNodeSet)[i];
1601                     if (templateArgumentNode->GetNodeType() == sngxml::dom::NodeType::elementNode)
1602                     {
1603                         sngxml::dom::Element* templateArgumentElement = static_cast<sngxml::dom::Element*>(templateArgumentNode);
1604                         std::u32string templateArgumentTypeId = templateArgumentElement->GetAttribute(U"typeId");
1605                         AppendTypeName(projectNamepageElementparentElementtemplateArgumentTypeIdcontentXmlcontentFilePathResolver);
1606                     }
1607                 }
1608             }
1609             pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U">")));
1610         }
1611         else if (typeElementName == U"typedef")
1612         {
1613             std::u32string parentProject;
1614             std::u32string parentId;
1615             sngxml::dom::ParentNode* parent = typeElement->Parent();
1616             while (parent)
1617             {
1618                 if (parent->Name() == U"class" || parent->Name() == U"namespace")
1619                 {
1620                     if (parent->GetNodeType() == sngxml::dom::NodeType::elementNode)
1621                     {
1622                         sngxml::dom::Element* parentElement = static_cast<sngxml::dom::Element*>(parent);
1623                         parentProject = GetProject(parentElement);
1624                         parentId = parentElement->GetAttribute(U"id");
1625                         break;
1626                     }
1627                 }
1628                 parent = parent->Parent();
1629             }
1630             std::u32string link = ToUtf32(contentFilePathResolver->ResolveContentFilePath(projectNameparentProject"."parentId)) + U"#" + typeId;
1631             std::unique_ptr<sngxml::dom::Element> linkElement(new sngxml::dom::Element(U"a"));
1632             linkElement->SetAttribute(U"href"link);
1633             linkElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(typeElement->GetAttribute(U"name"))));
1634             pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(linkElement.release()));
1635         }
1636         else
1637         {
1638             std::u32string link = ToUtf32(contentFilePathResolver->ResolveContentFilePath(projectNametypeProject"."typeId));
1639             std::unique_ptr<sngxml::dom::Element> linkElement(new sngxml::dom::Element(U"a"));
1640             linkElement->SetAttribute(U"href"link);
1641             linkElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(typeElement->GetAttribute(U"name"))));
1642             pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(linkElement.release()));
1643         }
1644     }
1645     else
1646     {
1647         pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U"@TYPE_NOT_FOUND")));
1648     }
1649 }
1650 
1651 void AppendParameter(const std::u32string& projectNamesngxml::dom::Element* pageElementsngxml::dom::Element* parentElementsngxml::dom::Element* parameterElement
1652     sngxml::dom::Document* contentXmlHtmlContentFilePathResolver* contentFilePathResolver)
1653 {
1654     std::u32string typeId = parameterElement->GetAttribute(U"type");
1655     AppendTypeName(projectNamepageElementparentElementtypeIdcontentXmlcontentFilePathResolver);
1656     std::u32string name = parameterElement->GetAttribute(U"name");
1657     if (!name.empty())
1658     {
1659         pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U" " + name)));
1660     }
1661 }
1662 
1663 std::u32string MakeConstructorName(sngxml::dom::Element* constructorElementbool fullName);
1664 
1665 std::u32string MakeConstructorName(sngxml::dom::Element* constructorElement)
1666 {
1667     return MakeConstructorName(constructorElementfalse);
1668 }
1669 
1670 std::u32string MakeConstructorName(sngxml::dom::Element* constructorElementbool fullName)
1671 {
1672     std::u32string contructorName = constructorElement->GetAttribute(U"name");
1673     if (fullName)
1674     {
1675         std::u32string prefix = GetPrefix(constructorElement);
1676         if (!prefix.empty())
1677         {
1678             return prefix + U"::" + contructorName;
1679         }
1680         else
1681         {
1682             return contructorName;
1683         }
1684     }
1685     else
1686     {
1687         return contructorName;
1688     }
1689 }
1690 
1691 std::u32string MakeFunctionName(sngxml::dom::Element* functionElementbool fullName);
1692 
1693 std::u32string MakeFunctionName(sngxml::dom::Element* functionElement)
1694 {
1695     return MakeFunctionName(functionElementfalse);
1696 }
1697 
1698 std::u32string MakeFunctionName(sngxml::dom::Element* functionElementbool fullName)
1699 {
1700     std::u32string functionName = functionElement->GetAttribute(U"name");
1701     if (fullName)
1702     {
1703         std::u32string prefix = GetPrefix(functionElement);
1704         if (!prefix.empty())
1705         {
1706             functionName = prefix + U"::" + functionName;
1707         }
1708     }
1709     std::unique_ptr<sngxml::xpath::XPathObject> templateParameters = sngxml::xpath::Evaluate(U"templateParameters/templateParameter"functionElement);
1710     if (templateParameters->Type() == sngxml::xpath::XPathObjectType::nodeSet)
1711     {
1712         sngxml::xpath::XPathNodeSet* templateParameterNodeSet = static_cast<sngxml::xpath::XPathNodeSet*>(templateParameters.get());
1713         int n = templateParameterNodeSet->Length();
1714         if (n > 0)
1715         {
1716             functionName.append(1'<');
1717             for (int i = 0; i < n; ++i)
1718             {
1719                 if (i > 0)
1720                 {
1721                     functionName.append(U", ");
1722                 }
1723                 sngxml::dom::Node* templateParameterNode = (*templateParameterNodeSet)[i];
1724                 if (templateParameterNode->GetNodeType() == sngxml::dom::NodeType::elementNode)
1725                 {
1726                     sngxml::dom::Element* templateParameterElement = static_cast<sngxml::dom::Element*>(templateParameterNode);
1727                     functionName.append(templateParameterElement->GetAttribute(U"name"));
1728                 }
1729             }
1730             functionName.append(1'>');
1731         }
1732     }
1733     return functionName;
1734 }
1735 
1736 void AppendParameterList(const std::u32string& projectNamesngxml::dom::Element* pageElementsngxml::dom::Element* parentElementsngxml::dom::Element* functionElement
1737     sngxml::dom::Document* contentXmlHtmlContentFilePathResolver* contentFilePathResolver)
1738 {
1739     std::unique_ptr<sngxml::xpath::XPathObject> parameters = sngxml::xpath::Evaluate(U"parameters/parameter"functionElement);
1740     if (parameters->Type() == sngxml::xpath::XPathObjectType::nodeSet)
1741     {
1742         pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U"(")));
1743         sngxml::xpath::XPathNodeSet* parameterNodeSet = static_cast<sngxml::xpath::XPathNodeSet*>(parameters.get());
1744         int n = parameterNodeSet->Length();
1745         for (int i = 0; i < n; ++i)
1746         {
1747             if (i > 0)
1748             {
1749                 pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U", ")));
1750             }
1751             sngxml::dom::Node* parameterNode = (*parameterNodeSet)[i];
1752             if (parameterNode->GetNodeType() == sngxml::dom::NodeType::elementNode)
1753             {
1754                 sngxml::dom::Element* parameterElement = static_cast<sngxml::dom::Element*>(parameterNode);
1755                 AppendParameter(projectNamepageElementparentElementparameterElementcontentXmlcontentFilePathResolver);
1756             }
1757         }
1758         pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U")")));
1759     }
1760 }
1761 
1762 void GenerateVariableSection(const std::u32string& projectNameconst std::u32string& titlesngxml::dom::Element* pageElementsngxml::dom::Element* parentElementsngxml::dom::Document* contentXml
1763     const std::string& contentDirconst std::string& styleDirNameconst std::string& styleFileNameHtmlContentFilePathResolver* contentFilePathResolverconst std::u32string& topLink
1764     const std::string& documentationFileNamesngxml::dom::Document* documentationXml)
1765 {
1766     std::unique_ptr<sngxml::dom::Element> variableTableElement(new sngxml::dom::Element(U"table"));
1767     std::unique_ptr<sngxml::xpath::XPathObject> variables = sngxml::xpath::Evaluate(U"variables/variable"parentElement);
1768     if (variables->Type() == sngxml::xpath::XPathObjectType::nodeSet)
1769     {
1770         std::u32string parentLink = parentElement->GetAttribute(U"id") + U".html";
1771         std::u32string prevLink;
1772         std::u32string nextLink;
1773         sngxml::xpath::XPathNodeSet* variableNodeSet = static_cast<sngxml::xpath::XPathNodeSet*>(variables.get());
1774         int n = variableNodeSet->Length();
1775         std::vector<sngxml::dom::Element*> matchedVariables;
1776         for (int i = 0; i < n; ++i)
1777         {
1778             sngxml::dom::Node* variableNode = (*variableNodeSet)[i];
1779             sngxml::dom::Element* variableElement = static_cast<sngxml::dom::Element*>(variableNode);
1780             if (!ProjectNameMatches(variableElementprojectName)) continue;
1781             matchedVariables.push_back(variableElement);
1782         }
1783         if (!matchedVariables.empty())
1784         {
1785             std::unique_ptr<sngxml::dom::Element> h2Element(new sngxml::dom::Element(U"h2"));
1786             h2Element->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(title)));
1787             pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(h2Element.release()));
1788         }
1789         for (int i = 0; i < matchedVariables.size(); ++i)
1790         {
1791             sngxml::dom::Element* variableElement = matchedVariables[i];
1792             std::u32string variableTypeId = variableElement->GetAttribute(U"type");
1793             std::u32string variableName = variableElement->GetAttribute(U"name");
1794             std::u32string specifiers = variableElement->GetAttribute(U"specifiers");
1795             std::u32string variableId = variableElement->GetAttribute(U"id");
1796             std::unique_ptr<sngxml::dom::Element> trElement(new sngxml::dom::Element(U"tr"));
1797             trElement->SetAttribute(U"id"variableId);
1798             std::unique_ptr<sngxml::dom::Element> typeTdElement(new sngxml::dom::Element(U"td"));
1799             AppendTypeName(projectNametypeTdElement.get()parentElementvariableTypeIdcontentXmlcontentFilePathResolver);
1800             typeTdElement->SetAttribute(U"class"U"functionTableFirstCol");
1801             typeTdElement->SetAttribute(U"xml:space"U"preserve");
1802             trElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(typeTdElement.release()));
1803             std::unique_ptr<sngxml::dom::Element> nameTdElement(new sngxml::dom::Element(U"td"));
1804             nameTdElement->SetAttribute(U"class"U"functionTableSecondCol");
1805             nameTdElement->SetAttribute(U"xml:space"U"preserve");
1806             nameTdElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(variableName)));
1807             if (!specifiers.empty())
1808             {
1809                 nameTdElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U" ")));
1810                 std::unique_ptr<sngxml::dom::Element> span(new sngxml::dom::Element(U"span"));
1811                 span->SetAttribute(U"class"U"kw");
1812                 span->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(specifiers)));
1813                 nameTdElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(span.release()));
1814             }
1815             trElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(nameTdElement.release()));
1816             if (documentationXml && documentationXml->GetElementById(variableId) != nullptr)
1817             {
1818                 std::unique_ptr<sngxml::dom::Element> documentationTdElement(new sngxml::dom::Element(U"td"));
1819                 GenerateDocumentation(projectNamedocumentationFileNamedocumentationXmldocumentationTdElement.get()variableIdcontentXmlcontentFilePathResolverDocFlags::none);
1820                 trElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(documentationTdElement.release()));
1821             }
1822             variableTableElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(trElement.release()));
1823         }
1824         if (!matchedVariables.empty())
1825         {
1826             pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(variableTableElement.release()));
1827         }
1828     }
1829 }
1830 
1831 void GenerateTypedefSection(const std::u32string& projectNamesngxml::dom::Element* pageElementsngxml::dom::Element* parentElementsngxml::dom::Document* contentXml
1832     const std::string& contentDirconst std::string& styleDirNameconst std::string& styleFileNameHtmlContentFilePathResolver* contentFilePathResolverconst std::u32string& topLink
1833     const std::string& documentationXmlFileNamesngxml::dom::Document* documentationXml)
1834 {
1835     std::unique_ptr<sngxml::dom::Element> typedefTableElement(new sngxml::dom::Element(U"table"));
1836     std::unique_ptr<sngxml::xpath::XPathObject> typedefs = sngxml::xpath::Evaluate(U"typedefs/typedef"parentElement);
1837     if (typedefs->Type() == sngxml::xpath::XPathObjectType::nodeSet)
1838     {
1839         std::u32string parentLink = parentElement->GetAttribute(U"id") + U".html";
1840         std::u32string prevLink;
1841         std::u32string nextLink;
1842         sngxml::xpath::XPathNodeSet* typedefNodeSet = static_cast<sngxml::xpath::XPathNodeSet*>(typedefs.get());
1843         int n = typedefNodeSet->Length();
1844         std::vector<sngxml::dom::Element*> matchedTypedefs;
1845         for (int i = 0; i < n; ++i)
1846         {
1847             sngxml::dom::Node* typedefNode = (*typedefNodeSet)[i];
1848             sngxml::dom::Element* typedefElement = static_cast<sngxml::dom::Element*>(typedefNode);
1849             if (!ProjectNameMatches(typedefElementprojectName)) continue;
1850             matchedTypedefs.push_back(typedefElement);
1851         }
1852         if (!matchedTypedefs.empty())
1853         {
1854             std::unique_ptr<sngxml::dom::Element> h2Element(new sngxml::dom::Element(U"h2"));
1855             h2Element->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U"Typedefs")));
1856             pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(h2Element.release()));
1857         }
1858         for (int i = 0; i < matchedTypedefs.size(); ++i)
1859         {
1860             sngxml::dom::Element* typedefElement = matchedTypedefs[i];
1861             std::u32string typedefTypeId = typedefElement->GetAttribute(U"type");
1862             std::u32string typedefName = typedefElement->GetAttribute(U"name");
1863             std::u32string typedefId = typedefElement->GetAttribute(U"id");
1864             std::unique_ptr<sngxml::dom::Element> trElement(new sngxml::dom::Element(U"tr"));
1865             trElement->SetAttribute(U"id"typedefId);
1866             std::unique_ptr<sngxml::dom::Element> typeTdElement(new sngxml::dom::Element(U"td"));
1867             AppendTypeName(projectNametypeTdElement.get()parentElementtypedefTypeIdcontentXmlcontentFilePathResolver);
1868             typeTdElement->SetAttribute(U"class"U"functionTableFirstCol");
1869             typeTdElement->SetAttribute(U"xml:space"U"preserve");
1870             trElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(typeTdElement.release()));
1871             std::unique_ptr<sngxml::dom::Element> nameTdElement(new sngxml::dom::Element(U"td"));
1872             nameTdElement->SetAttribute(U"class"U"functionTableSecondCol");
1873             nameTdElement->SetAttribute(U"xml:space"U"preserve");
1874             nameTdElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(typedefName)));
1875             trElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(nameTdElement.release()));
1876             if (documentationXml && documentationXml->GetElementById(typedefId) != nullptr)
1877             {
1878                 std::unique_ptr<sngxml::dom::Element> documentationTdElement(new sngxml::dom::Element(U"td"));
1879                 GenerateDocumentation(projectNamedocumentationXmlFileNamedocumentationXmldocumentationTdElement.get()typedefIdcontentXmlcontentFilePathResolverDocFlags::none);
1880                 trElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(documentationTdElement.release()));
1881             }
1882             typedefTableElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(trElement.release()));
1883         }
1884         if (!matchedTypedefs.empty())
1885         {
1886             pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(typedefTableElement.release()));
1887         }
1888     }
1889 }
1890 
1891 void GenerateConstructorSection(const std::u32string& projectNamesngxml::dom::Element* pageElementsngxml::dom::Element* parentElementconst std::string& contentDir
1892     const std::string& styleDirNameconst std::string& styleFileNamesngxml::dom::Document* contentXmlstd::std::vector<sngxml::dom::Element*>&constructorElements
1893     HtmlContentFilePathResolver* contentFilePathResolverconst std::string& documentationXmlFileNamesngxml::dom::Document* documentationXml)
1894 {
1895     std::unique_ptr<sngxml::dom::Element> constructorTableElement(new sngxml::dom::Element(U"table"));
1896     constructorTableElement->SetAttribute(U"class"U"constructorTable");
1897     std::unique_ptr<sngxml::xpath::XPathObject> constructors = sngxml::xpath::Evaluate(U"constructors/constructor"parentElement);
1898     if (constructors->Type() == sngxml::xpath::XPathObjectType::nodeSet)
1899     {
1900         sngxml::xpath::XPathNodeSet* constructorNodeSet = static_cast<sngxml::xpath::XPathNodeSet*>(constructors.get());
1901         int n = constructorNodeSet->Length();
1902         std::vector<sngxml::dom::Element*> matchedConstructors;
1903         for (int i = 0; i < n; ++i)
1904         {
1905             sngxml::dom::Node* constructorNode = (*constructorNodeSet)[i];
1906             sngxml::dom::Element* constructorElement = static_cast<sngxml::dom::Element*>(constructorNode);
1907             if (!ProjectNameMatches(constructorElementprojectName)) continue;
1908             matchedConstructors.push_back(constructorElement);
1909         }
1910         if (!matchedConstructors.empty())
1911         {
1912             std::unique_ptr<sngxml::dom::Element> h2Element(new sngxml::dom::Element(U"h2"));
1913             h2Element->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U"Constructors")));
1914             pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(h2Element.release()));
1915         }
1916         for (int i = 0; i < matchedConstructors.size(); ++i)
1917         {
1918             sngxml::dom::Element* constructorElement = matchedConstructors[i];
1919             constructorElements.push_back(constructorElement);
1920             std::unique_ptr<sngxml::dom::Element> trElement(new sngxml::dom::Element(U"tr"));
1921             std::unique_ptr<sngxml::dom::Element> tdElement(new sngxml::dom::Element(U"td"));
1922             tdElement->SetAttribute(U"class"U"constructorTableFirstCol");
1923             tdElement->SetAttribute(U"xml:space"U"preserve");
1924             std::u32string constuctorName = MakeConstructorName(constructorElement);
1925             std::u32string constructorId = constructorElement->GetAttribute(U"id");
1926             std::unique_ptr<sngxml::dom::Element> linkElement(new sngxml::dom::Element(U"a"));
1927             std::u32string constructorLink = parentElement->GetAttribute(U"id");
1928             constructorLink.append(U".html#").append(constructorId);
1929             linkElement->SetAttribute(U"href"constructorLink);
1930             linkElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(constuctorName)));
1931             tdElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(linkElement.release()));
1932             AppendParameterList(projectNametdElement.get()parentElementconstructorElementcontentXmlcontentFilePathResolver);
1933             std::u32string specifiers = constructorElement->GetAttribute(U"specifiers");
1934             if (!specifiers.empty())
1935             {
1936                 tdElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U" ")));
1937                 std::unique_ptr<sngxml::dom::Element> span(new sngxml::dom::Element(U"span"));
1938                 span->SetAttribute(U"class"U"kw");
1939                 span->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(specifiers)));
1940                 tdElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(span.release()));
1941             }
1942             trElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(tdElement.release()));
1943             if (documentationXml && documentationXml->GetElementById(constructorId) != nullptr)
1944             {
1945                 std::unique_ptr<sngxml::dom::Element> documentationTdElement(new sngxml::dom::Element(U"td"));
1946                 GenerateDocumentation(projectNamedocumentationXmlFileNamedocumentationXmldocumentationTdElement.get()constructorIdcontentXmlcontentFilePathResolverDocFlags::none);
1947                 trElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(documentationTdElement.release()));
1948             }
1949             constructorTableElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(trElement.release()));
1950         }
1951         if (!matchedConstructors.empty())
1952         {
1953             pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(constructorTableElement.release()));
1954         }
1955     }
1956 }
1957 
1958 void GenerateFunctionSection(const std::u32string& projectNameconst std::u32string& titlesngxml::dom::Element* pageElementsngxml::dom::Element* parentElementconst std::string& contentDir
1959     const std::string& styleDirNameconst std::string& styleFileNamesngxml::dom::Document* contentXmlstd::std::vector<sngxml::dom::Element*>&functionElements
1960     HtmlContentFilePathResolver* contentFilePathResolverconst std::string& documentationXmlFileNamesngxml::dom::Document* documentationXml)
1961 {
1962     std::unique_ptr<sngxml::dom::Element> functionTableElement(new sngxml::dom::Element(U"table"));
1963     functionTableElement->SetAttribute(U"class"U"functionTable");
1964     std::unique_ptr<sngxml::xpath::XPathObject> functions = sngxml::xpath::Evaluate(U"functions/function"parentElement);
1965     if (functions->Type() == sngxml::xpath::XPathObjectType::nodeSet)
1966     {
1967         sngxml::xpath::XPathNodeSet* functionNodeSet = static_cast<sngxml::xpath::XPathNodeSet*>(functions.get());
1968         int n = functionNodeSet->Length();
1969         std::vector<sngxml::dom::Element*> matchedFunctions;
1970         for (int i = 0; i < n; ++i)
1971         {
1972             sngxml::dom::Node* functionNode = (*functionNodeSet)[i];
1973             sngxml::dom::Element* functionElement = static_cast<sngxml::dom::Element*>(functionNode);
1974             if (!ProjectNameMatches(functionElementprojectName)) continue;
1975             matchedFunctions.push_back(functionElement);
1976         }
1977         if (!matchedFunctions.empty())
1978         {
1979             std::unique_ptr<sngxml::dom::Element> h2Element(new sngxml::dom::Element(U"h2"));
1980             h2Element->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(title)));
1981             pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(h2Element.release()));
1982         }
1983         for (int i = 0; i < matchedFunctions.size(); ++i)
1984         {
1985             sngxml::dom::Element* functionElement = static_cast<sngxml::dom::Element*>(matchedFunctions[i]);
1986             functionElements.push_back(functionElement);
1987             std::unique_ptr<sngxml::dom::Element> trElement(new sngxml::dom::Element(U"tr"));
1988             std::u32string returnTypeId = functionElement->GetAttribute(U"returnType");
1989             if (returnTypeId.empty())
1990             {
1991                 std::unique_ptr<sngxml::dom::Element> tdElement(new sngxml::dom::Element(U"td"));
1992                 tdElement->SetAttribute(U"class"U"functionTableFirstCol");
1993                 tdElement->SetAttribute(U"xml:space"U"preserve");
1994                 trElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(tdElement.release()));
1995             }
1996             else
1997             {
1998                 std::unique_ptr<sngxml::dom::Element> tdElement(new sngxml::dom::Element(U"td"));
1999                 tdElement->SetAttribute(U"class"U"functionTableFirstCol");
2000                 tdElement->SetAttribute(U"xml:space"U"preserve");
2001                 AppendTypeName(projectNametdElement.get()parentElementreturnTypeIdcontentXmlcontentFilePathResolver);
2002                 trElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(tdElement.release()));
2003             }
2004             std::unique_ptr<sngxml::dom::Element> tdElement(new sngxml::dom::Element(U"td"));
2005             tdElement->SetAttribute(U"class"U"functionTableSecondCol");
2006             tdElement->SetAttribute(U"xml:space"U"preserve");
2007             std::u32string functionName = MakeFunctionName(functionElement);
2008             std::u32string functionId = functionElement->GetAttribute(U"id");
2009             std::unique_ptr<sngxml::dom::Element> linkElement(new sngxml::dom::Element(U"a"));
2010             std::u32string functionLink = parentElement->GetAttribute(U"id");
2011             functionLink.append(U".html#").append(functionId);
2012             linkElement->SetAttribute(U"href"functionLink);
2013             linkElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(functionName)));
2014             tdElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(linkElement.release()));
2015             AppendParameterList(projectNametdElement.get()parentElementfunctionElementcontentXmlcontentFilePathResolver);
2016             std::u32string specifiers = functionElement->GetAttribute(U"specifiers");
2017             if (!specifiers.empty())
2018             {
2019                 tdElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U" ")));
2020                 std::unique_ptr<sngxml::dom::Element> span(new sngxml::dom::Element(U"span"));
2021                 span->SetAttribute(U"class"U"kw");
2022                 span->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(specifiers)));
2023                 tdElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(span.release()));
2024             }
2025             trElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(tdElement.release()));
2026             if (documentationXml && documentationXml->GetElementById(functionId) != nullptr)
2027             {
2028                 std::unique_ptr<sngxml::dom::Element> documentationTdElement(new sngxml::dom::Element(U"td"));
2029                 GenerateDocumentation(projectNamedocumentationXmlFileNamedocumentationXmldocumentationTdElement.get()functionIdcontentXmlcontentFilePathResolverDocFlags::none);
2030                 trElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(documentationTdElement.release()));
2031             }
2032             functionTableElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(trElement.release()));
2033         }
2034         if (!functionElements.empty())
2035         {
2036             pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(functionTableElement.release()));
2037         }
2038     }
2039 }
2040 
2041 struct ByFunctionName 
2042 {
2043     bool operator()(const std::std::pair<std::u32stringstd::std::unique_ptr<sngxml::dom::Element>>&leftconststd::std::pair<std::u32stringstd::std::unique_ptr<sngxml::dom::Element>>&right) const
2044     {
2045         return left.first < right.first;
2046     }
2047 };
2048 
2049 void GenerateFunctionDetailSection(const std::u32string& projectNameconst std::u32string& titleconst std::u32string& functionTitlesngxml::dom::Element* pageElement
2050     sngxml::dom::Element* parentElementstd::std::vector<sngxml::dom::Element*>&functionElementssngxml::dom::Document*contentXml
2051     std::std::unordered_map<std::u32stringstd::std::unique_ptr<sngxml::dom::Element>>&inlineCodeMapHtmlContentFilePathResolver*contentFilePathResolverconststd::string&documentationXmlFileNamesngxml::dom::Document*documentationXml)
2052 {
2053     if (functionElements.empty()) return;
2054     std::unique_ptr<sngxml::dom::Element> h2Element(new sngxml::dom::Element(U"h2"));
2055     h2Element->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(title)));
2056     pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(h2Element.release()));
2057     int n = functionElements.size();
2058     for (int i = 0; i < n; ++i)
2059     {
2060         sngxml::dom::Element* functionElement = functionElements[i];
2061         std::u32string functionId = functionElement->GetAttribute(U"id");
2062         std::unique_ptr<sngxml::dom::Element> h3Element(new sngxml::dom::Element(U"h3"));
2063         h3Element->SetAttribute(U"id"functionId);
2064         std::u32string functionText = functionElement->GetAttribute(U"name");
2065         functionText.append(1' ').append(functionTitle);
2066         h3Element->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(functionText)));
2067         pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(h3Element.release()));
2068         std::unique_ptr<sngxml::dom::Element> h4Element(new sngxml::dom::Element(U"h4"));
2069         std::u32string returnTypeId = functionElement->GetAttribute(U"returnType");
2070         if (!returnTypeId.empty())
2071         {
2072             AppendTypeName(projectNameh4Element.get()parentElementreturnTypeIdcontentXmlcontentFilePathResolver);
2073             h4Element->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U" ")));
2074         }
2075         std::u32string functionName;
2076         if (functionElement->Name() == U"function")
2077         {
2078             functionName = MakeFunctionName(functionElementtrue);
2079         }
2080         else if (functionElement->Name() == U"constructor")
2081         {
2082             functionName = MakeConstructorName(functionElementtrue);
2083         }
2084         h4Element->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(functionName)));
2085         AppendParameterList(projectNameh4Element.get()parentElementfunctionElementcontentXmlcontentFilePathResolver);
2086         std::u32string specifiers = functionElement->GetAttribute(U"specifiers");
2087         if (!specifiers.empty())
2088         {
2089             h4Element->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U" ")));
2090             std::unique_ptr<sngxml::dom::Element> span(new sngxml::dom::Element(U"span"));
2091             span->SetAttribute(U"class"U"kw");
2092             span->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(specifiers)));
2093             h4Element->AppendChild(std::unique_ptr<sngxml::dom::Node>(span.release()));
2094         }
2095         pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(h4Element.release()));
2096         GenerateDocumentation(projectNamedocumentationXmlFileNamedocumentationXmlpageElementfunctionIdcontentXmlcontentFilePathResolverDocFlags::full | DocFlags::paragraph);
2097         bool codeAdded = false;
2098         std::u32string definitionFileId = functionElement->GetAttribute(U"definitionFileId");
2099         if (!definitionFileId.empty())
2100         {
2101             std::unique_ptr<sngxml::dom::Element> span(new sngxml::dom::Element(U"span"));
2102             span->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U"Definition at line ")));
2103             std::unique_ptr<sngxml::dom::Element> lineLink(new sngxml::dom::Element(U"a"));
2104             std::u32string line = functionElement->GetAttribute(U"definitionLine");
2105             lineLink->SetAttribute(U"href"definitionFileId + U"#" + line);
2106             lineLink->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(line)));
2107             span->AppendChild(std::unique_ptr<sngxml::dom::Node>(lineLink.release()));
2108             span->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U" of ")));
2109             std::unique_ptr<sngxml::dom::Element> fileLink(new sngxml::dom::Element(U"a"));
2110             fileLink->SetAttribute(U"href"definitionFileId);
2111             fileLink->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(functionElement->GetAttribute(U"definitionFile"))));
2112             span->AppendChild(std::unique_ptr<sngxml::dom::Node>(fileLink.release()));
2113             auto it = inlineCodeMap.find(functionElement->GetAttribute(U"id"));
2114             if (it != inlineCodeMap.cend())
2115             {
2116                 sngxml::dom::Element* inlineCode = it->second.get();
2117                 if (inlineCode)
2118                 {
2119                     span->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U":")));
2120                     span->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Element(U"br")));
2121                     std::unique_ptr<sngxml::dom::Element> inlineCode = std::move(it->second);
2122                     span->AppendChild(std::unique_ptr<sngxml::dom::Node>(inlineCode->CloneNode(true)));
2123                     span->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Element(U"br")));
2124                     codeAdded = true;
2125                 }
2126             }
2127             pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(span.release()));
2128             if (!codeAdded)
2129             {
2130                 pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Element(U"br")));
2131             }
2132         }
2133         std::u32string declarationFileId = functionElement->GetAttribute(U"declarationFileId");
2134         if (!declarationFileId.empty())
2135         {
2136             if (codeAdded)
2137             {
2138                 pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Element(U"br")));
2139             }
2140             std::unique_ptr<sngxml::dom::Element> span(new sngxml::dom::Element(U"span"));
2141             span->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U"Declaration at line ")));
2142             std::unique_ptr<sngxml::dom::Element> lineLink(new sngxml::dom::Element(U"a"));
2143             std::u32string line = functionElement->GetAttribute(U"declarationLine");
2144             lineLink->SetAttribute(U"href"declarationFileId + U"#" + line);
2145             lineLink->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(line)));
2146             span->AppendChild(std::unique_ptr<sngxml::dom::Node>(lineLink.release()));
2147             span->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U" of ")));
2148             std::unique_ptr<sngxml::dom::Element> fileLink(new sngxml::dom::Element(U"a"));
2149             fileLink->SetAttribute(U"href"declarationFileId);
2150             fileLink->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(functionElement->GetAttribute(U"declarationFile"))));
2151             span->AppendChild(std::unique_ptr<sngxml::dom::Node>(fileLink.release()));
2152             pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(span.release()));
2153             pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Element(U"br")));
2154         }
2155         bool hasOverriddenFunctions = false;
2156         std::unique_ptr<sngxml::xpath::XPathObject> overriddenFunctions = sngxml::xpath::Evaluate(U"overriddenFunctions/overriddenFunction"functionElement);
2157         if (overriddenFunctions->Type() == sngxml::xpath::XPathObjectType::nodeSet)
2158         {
2159             sngxml::xpath::XPathNodeSet* overriddenNodeSet = static_cast<sngxml::xpath::XPathNodeSet*>(overriddenFunctions.get());
2160             int n = overriddenNodeSet->Length();
2161             if (n > 0)
2162             {
2163                 pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Element(U"br")));
2164                 hasOverriddenFunctions = true;
2165                 std::unique_ptr<sngxml::dom::Element> span(new sngxml::dom::Element(U"span"));
2166                 span->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U"Base class overridden functions: ")));
2167                 std::vector<std::std::pair<std::u32stringstd::std::unique_ptr<sngxml::dom::Element>>>overriddenFunctionsVec;
2168                 for (int i = 0; i < n; ++i)
2169                 {
2170                     sngxml::dom::Node* overriddenNode = (*overriddenNodeSet)[i];
2171                     if (overriddenNode->GetNodeType() == sngxml::dom::NodeType::elementNode)
2172                     {
2173                         sngxml::dom::Element* overriddenIdElement = static_cast<sngxml::dom::Element*>(overriddenNode);
2174                         std::u32string overriddenId = overriddenIdElement->GetAttribute(U"functionId");
2175                         if (!overriddenId.empty())
2176                         {
2177                             sngxml::dom::Element* overriddenElement = contentXml->GetElementById(overriddenId);
2178                             sngxml::dom::ParentNode* overriddenParent = overriddenElement->Parent();
2179                             if (overriddenParent->GetNodeType() == sngxml::dom::NodeType::elementNode)
2180                             {
2181                                 sngxml::dom::Element* overriddenParentElement = static_cast<sngxml::dom::Element*>(overriddenParent);
2182                                 if (overriddenParentElement->Name() == U"functions")
2183                                 {
2184                                     sngxml::dom::ParentNode* functionsParent = overriddenParentElement->Parent();
2185                                     if (functionsParent->GetNodeType() == sngxml::dom::NodeType::elementNode)
2186                                     {
2187                                         sngxml::dom::Element* classElement = static_cast<sngxml::dom::Element*>(functionsParent);
2188                                         if (classElement->Name() == U"class")
2189                                         {
2190                                             std::u32string classId = classElement->GetAttribute(U"id");
2191                                             if (!classId.empty())
2192                                             {
2193                                                 std::u32string proj = GetProject(classElement);
2194                                                 if (!proj.empty())
2195                                                 {
2196                                                     std::u32string classLink = ToUtf32(contentFilePathResolver->ResolveContentFilePath(projectNameproj"."classId));
2197                                                     std::u32string overriddenLink = classLink + U"#" + overriddenId;
2198                                                     std::u32string overriddenFunctionName = MakeFunctionName(overriddenElementtrue);
2199                                                     std::unique_ptr<sngxml::dom::Element> linkElement(new sngxml::dom::Element(U"a"));
2200                                                     linkElement->SetAttribute(U"href"overriddenLink);
2201                                                     linkElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(overriddenFunctionName)));
2202                                                     overriddenFunctionsVec.push_back(std::make_pair(overriddenFunctionNamestd::move(linkElement)));
2203                                                 }
2204                                             }
2205                                         }
2206                                     }
2207                                 }
2208                             }
2209                         }
2210                     }
2211                 }
2212                 std::sort(overriddenFunctionsVec.begin()overriddenFunctionsVec.end()ByFunctionName());
2213                 int n = overriddenFunctionsVec.size();
2214                 for (int i = 0; i < n; ++i)
2215                 {
2216                     if (i > 0)
2217                     {
2218                         span->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U", ")));
2219                     }
2220                     std::std::pair<std::u32stringstd::std::unique_ptr<sngxml::dom::Element>>&p=overriddenFunctionsVec[i];
2221                     std::unique_ptr<sngxml::dom::Element> linkElement = std::move(p.second);
2222                     span->AppendChild(std::unique_ptr<sngxml::dom::Node>(linkElement.release()));
2223                 }
2224                 pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(span.release()));
2225                 pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Element(U"br")));
2226             }
2227         }
2228         bool hasOverrides = false;
2229         std::unique_ptr<sngxml::xpath::XPathObject> overrides = sngxml::xpath::Evaluate(U"overrides/override"functionElement);
2230         if (overrides->Type() == sngxml::xpath::XPathObjectType::nodeSet)
2231         {
2232             sngxml::xpath::XPathNodeSet* overrideNodeSet = static_cast<sngxml::xpath::XPathNodeSet*>(overrides.get());
2233             int n = overrideNodeSet->Length();
2234             if (n > 0)
2235             {
2236                 pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Element(U"br")));
2237                 hasOverrides = true;
2238                 std::unique_ptr<sngxml::dom::Element> span(new sngxml::dom::Element(U"span"));
2239                 span->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U"Derived class overrides: ")));
2240                 std::vector<std::std::pair<std::u32stringstd::std::unique_ptr<sngxml::dom::Element>>>overrideVec;
2241                 for (int i = 0; i < n; ++i)
2242                 {
2243                     sngxml::dom::Node* overrideNode = (*overrideNodeSet)[i];
2244                     if (overrideNode->GetNodeType() == sngxml::dom::NodeType::elementNode)
2245                     {
2246                         sngxml::dom::Element* overrideIdElement = static_cast<sngxml::dom::Element*>(overrideNode);
2247                         std::u32string overrideId = overrideIdElement->GetAttribute(U"functionId");
2248                         if (!overrideId.empty())
2249                         {
2250                             sngxml::dom::Element* overrideElement = contentXml->GetElementById(overrideId);
2251                             sngxml::dom::ParentNode* overrideParent = overrideElement->Parent();
2252                             if (overrideParent->GetNodeType() == sngxml::dom::NodeType::elementNode)
2253                             {
2254                                 sngxml::dom::Element* overrideParentElement = static_cast<sngxml::dom::Element*>(overrideParent);
2255                                 if (overrideParentElement->Name() == U"functions")
2256                                 {
2257                                     sngxml::dom::ParentNode* functionsParent = overrideParentElement->Parent();
2258                                     if (functionsParent->GetNodeType() == sngxml::dom::NodeType::elementNode)
2259                                     {
2260                                         sngxml::dom::Element* classElement = static_cast<sngxml::dom::Element*>(functionsParent);
2261                                         if (classElement->Name() == U"class")
2262                                         {
2263                                             std::u32string classId = classElement->GetAttribute(U"id");
2264                                             if (!classId.empty())
2265                                             {
2266                                                 std::u32string proj = GetProject(classElement);
2267                                                 if (!proj.empty())
2268                                                 {
2269                                                     std::u32string classLink = ToUtf32(contentFilePathResolver->ResolveContentFilePath(projectNameproj"."classId));
2270                                                     std::u32string overrideLink = classLink + U"#" + overrideId;
2271                                                     std::u32string overrideFunctionName = MakeFunctionName(overrideElementtrue);
2272                                                     std::unique_ptr<sngxml::dom::Element> linkElement(new sngxml::dom::Element(U"a"));
2273                                                     linkElement->SetAttribute(U"href"overrideLink);
2274                                                     linkElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(overrideFunctionName)));
2275                                                     overrideVec.push_back(std::make_pair(overrideFunctionNamestd::move(linkElement)));
2276                                                 }
2277                                             }
2278                                         }
2279                                     }
2280                                 }
2281                             }
2282                         }
2283                     }
2284                 }
2285                 std::sort(overrideVec.begin()overrideVec.end()ByFunctionName());
2286                 int n = overrideVec.size();
2287                 for (int i = 0; i < n; ++i)
2288                 {
2289                     if (i > 0)
2290                     {
2291                         span->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U", ")));
2292                     }
2293                     std::std::pair<std::u32stringstd::std::unique_ptr<sngxml::dom::Element>>&p=overrideVec[i];
2294                     std::unique_ptr<sngxml::dom::Element> linkElement = std::move(p.second);
2295                     span->AppendChild(std::unique_ptr<sngxml::dom::Node>(linkElement.release()));
2296                 }
2297                 pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(span.release()));
2298                 pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Element(U"br")));
2299             }
2300         }
2301         bool hasCalls = false;
2302         std::unique_ptr<sngxml::xpath::XPathObject> calls = sngxml::xpath::Evaluate(U"calls/call"functionElement);
2303         if (calls->Type() == sngxml::xpath::XPathObjectType::nodeSet)
2304         {
2305             sngxml::xpath::XPathNodeSet* callNodeSet = static_cast<sngxml::xpath::XPathNodeSet*>(calls.get());
2306             int n = callNodeSet->Length();
2307             if (n > 0)
2308             {
2309                 hasCalls = true;
2310                 std::unique_ptr<sngxml::dom::Element> span(new sngxml::dom::Element(U"span"));
2311                 span->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U"Calls: ")));
2312                 std::vector<std::std::pair<std::u32stringstd::std::unique_ptr<sngxml::dom::Element>>>callVec;
2313                 for (int i = 0; i < n; ++i)
2314                 {
2315                     sngxml::dom::Node* callNode = (*callNodeSet)[i];
2316                     if (callNode->GetNodeType() == sngxml::dom::NodeType::elementNode)
2317                     {
2318                         sngxml::dom::Element* callIdElement = static_cast<sngxml::dom::Element*>(callNode);
2319                         std::u32string callId = callIdElement->GetAttribute(U"functionId");
2320                         if (!callId.empty())
2321                         {
2322                             sngxml::dom::Element* callElement = contentXml->GetElementById(callId);
2323                             sngxml::dom::ParentNode* callParent = callElement->Parent();
2324                             if (callParent->GetNodeType() == sngxml::dom::NodeType::elementNode)
2325                             {
2326                                 sngxml::dom::Element* callParentElement = static_cast<sngxml::dom::Element*>(callParent);
2327                                 if (callParentElement->Name() == U"functions")
2328                                 {
2329                                     sngxml::dom::ParentNode* functionsParent = callParentElement->Parent();
2330                                     if (functionsParent->GetNodeType() == sngxml::dom::NodeType::elementNode)
2331                                     {
2332                                         sngxml::dom::Element* parentElement = static_cast<sngxml::dom::Element*>(functionsParent);
2333                                         if (parentElement->Name() == U"class" || parentElement->Name() == U"namespace")
2334                                         {
2335                                             std::u32string parentId = parentElement->GetAttribute(U"id");
2336                                             if (!parentId.empty())
2337                                             {
2338                                                 std::u32string proj = GetProject(parentElement);
2339                                                 if (!proj.empty())
2340                                                 {
2341                                                     std::u32string parentLink = ToUtf32(contentFilePathResolver->ResolveContentFilePath(projectNameproj"."parentId));
2342                                                     std::u32string callLink = parentLink + U"#" + callId;
2343                                                     std::u32string callFunctionName = MakeFunctionName(callElementtrue);
2344                                                     std::unique_ptr<sngxml::dom::Element> linkElement(new sngxml::dom::Element(U"a"));
2345                                                     linkElement->SetAttribute(U"href"callLink);
2346                                                     linkElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(callFunctionName)));
2347                                                     callVec.push_back(std::make_pair(callFunctionNamestd::move(linkElement)));
2348                                                 }
2349                                             }
2350                                         }
2351                                     }
2352                                 }
2353                             }
2354                         }
2355                     }
2356                 }
2357                 std::sort(callVec.begin()callVec.end()ByFunctionName());
2358                 int n = callVec.size();
2359                 for (int i = 0; i < n; ++i)
2360                 {
2361                     if (i > 0)
2362                     {
2363                         span->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U", ")));
2364                     }
2365                     std::std::pair<std::u32stringstd::std::unique_ptr<sngxml::dom::Element>>&p=callVec[i];
2366                     std::unique_ptr<sngxml::dom::Element> linkElement = std::move(p.second);
2367                     span->AppendChild(std::unique_ptr<sngxml::dom::Node>(linkElement.release()));
2368                 }
2369                 if (n > 0)
2370                 {
2371                     pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Element(U"br")));
2372                     pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(span.release()));
2373                     pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Element(U"br")));
2374                 }
2375                 else
2376                 {
2377                     hasCalls = false;
2378                 }
2379             }
2380         }
2381         bool hasCalledBy = false;
2382         std::unique_ptr<sngxml::xpath::XPathObject> calledBy = sngxml::xpath::Evaluate(U"calledByFunctions/calledByFunction"functionElement);
2383         if (calledBy->Type() == sngxml::xpath::XPathObjectType::nodeSet)
2384         {
2385             sngxml::xpath::XPathNodeSet* calledByNodeSet = static_cast<sngxml::xpath::XPathNodeSet*>(calledBy.get());
2386             int n = calledByNodeSet->Length();
2387             if (n > 0)
2388             {
2389                 hasCalledBy = true;
2390                 std::unique_ptr<sngxml::dom::Element> span(new sngxml::dom::Element(U"span"));
2391                 span->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U"Called by: ")));
2392                 std::vector<std::std::pair<std::u32stringstd::std::unique_ptr<sngxml::dom::Element>>>calledByVec;
2393                 for (int i = 0; i < n; ++i)
2394                 {
2395                     sngxml::dom::Node* calledByNode = (*calledByNodeSet)[i];
2396                     if (calledByNode->GetNodeType() == sngxml::dom::NodeType::elementNode)
2397                     {
2398                         sngxml::dom::Element* calledByIdElement = static_cast<sngxml::dom::Element*>(calledByNode);
2399                         std::u32string calledById = calledByIdElement->GetAttribute(U"functionId");
2400                         if (!calledById.empty())
2401                         {
2402                             sngxml::dom::Element* calledByElement = contentXml->GetElementById(calledById);
2403                             sngxml::dom::ParentNode* calledByParent = calledByElement->Parent();
2404                             if (calledByParent->GetNodeType() == sngxml::dom::NodeType::elementNode)
2405                             {
2406                                 sngxml::dom::Element* calledByParentElement = static_cast<sngxml::dom::Element*>(calledByParent);
2407                                 if (calledByParentElement->Name() == U"functions")
2408                                 {
2409                                     sngxml::dom::ParentNode* functionsParent = calledByParentElement->Parent();
2410                                     if (functionsParent->GetNodeType() == sngxml::dom::NodeType::elementNode)
2411                                     {
2412                                         sngxml::dom::Element* parentElement = static_cast<sngxml::dom::Element*>(functionsParent);
2413                                         if (parentElement->Name() == U"class" || parentElement->Name() == U"namespace")
2414                                         {
2415                                             std::u32string parentId = parentElement->GetAttribute(U"id");
2416                                             if (!parentId.empty())
2417                                             {
2418                                                 std::u32string proj = GetProject(parentElement);
2419                                                 if (!proj.empty())
2420                                                 {
2421                                                     std::u32string parentLink = ToUtf32(contentFilePathResolver->ResolveContentFilePath(projectNameproj"."parentId));
2422                                                     std::u32string calledByLink = parentLink + U"#" + calledById;
2423                                                     std::u32string calledByFunctionName = MakeFunctionName(calledByElementtrue);
2424                                                     std::unique_ptr<sngxml::dom::Element> linkElement(new sngxml::dom::Element(U"a"));
2425                                                     linkElement->SetAttribute(U"href"calledByLink);
2426                                                     linkElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(calledByFunctionName)));
2427                                                     calledByVec.push_back(std::make_pair(calledByFunctionNamestd::move(linkElement)));
2428                                                 }
2429                                             }
2430                                         }
2431                                     }
2432                                 }
2433                             }
2434                         }
2435                     }
2436                 }
2437                 std::sort(calledByVec.begin()calledByVec.end()ByFunctionName());
2438                 int n = calledByVec.size();
2439                 for (int i = 0; i < n; ++i)
2440                 {
2441                     if (i > 0)
2442                     {
2443                         span->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U", ")));
2444                     }
2445                     std::std::pair<std::u32stringstd::std::unique_ptr<sngxml::dom::Element>>&p=calledByVec[i];
2446                     std::unique_ptr<sngxml::dom::Element> linkElement = std::move(p.second);
2447                     span->AppendChild(std::unique_ptr<sngxml::dom::Node>(linkElement.release()));
2448                 }
2449                 if (n > 0)
2450                 {
2451                     pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Element(U"br")));
2452                     pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(span.release()));
2453                     pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Element(U"br")));
2454                 }
2455                 else
2456                 {
2457                     hasCalledBy = false;
2458                 }
2459             }
2460         }
2461         if (!definitionFileId.empty() || !declarationFileId.empty() || hasOverrides || hasOverriddenFunctions || hasCalls || hasCalledBy)
2462         {
2463             pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Element(U"br")));
2464         }
2465         pageElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Element(U"hr")));
2466     }
2467 }
2468 
2469 void GenerateContent(const std::u32string& projectNamesngxml::dom::Document* contentXmlconst std::string& contentDirconst std::string& styleDirNameconst std::string& styleFileName
2470     std::std::unordered_map<std::u32stringstd::std::unique_ptr<sngxml::dom::Element>>&inlineCodeMapconststd::string&contentXmlFilePathboolverboseboolrebuildbool&upToDate
2471     HtmlContentFilePathResolver* contentFilePathResolverconst std::u32string& topLinkconst std::string& documentationXmlFileNamesngxml::dom::Document* documentationXml)
2472 {
2473     upToDate = true;
2474     std::unique_ptr<sngxml::xpath::XPathObject> namespaces = sngxml::xpath::Evaluate(U"//namespace"contentXml);
2475     if (namespaces->Type() == sngxml::xpath::XPathObjectType::nodeSet)
2476     {
2477         sngxml::xpath::XPathNodeSet* namespaceNodeSet = static_cast<sngxml::xpath::XPathNodeSet*>(namespaces.get());
2478         std::u32string parentLink = U"../../" + projectName + U".html";
2479         std::u32string prevLink;
2480         std::u32string nextLink;
2481         int n = namespaceNodeSet->Length();
2482         for (int i = 0; i < n; ++i)
2483         {
2484             nextLink.clear();
2485             sngxml::dom::Node* nsNode = (*namespaceNodeSet)[i];
2486             if (nsNode->GetNodeType() == sngxml::dom::NodeType::elementNode)
2487             {
2488                 sngxml::dom::Element* nsElement = static_cast<sngxml::dom::Element*>(nsNode);
2489                 if (i < n - 1)
2490                 {
2491                     sngxml::dom::Node* nextNsNode = (*namespaceNodeSet)[i + 1];
2492                     if (nextNsNode->GetNodeType() == sngxml::dom::NodeType::elementNode)
2493                     {
2494                         sngxml::dom::Element* nextNsElement = static_cast<sngxml::dom::Element*>(nextNsNode);
2495                         std::u32string nextNsId = nextNsElement->GetAttribute(U"id");
2496                         std::string nextNsFileName = ToUtf8(nextNsId) + ".html";
2497                         nextLink = ToUtf32(nextNsFileName);
2498                     }
2499                 }
2500                 std::vector<sngxml::dom::Element*> functionElements;
2501                 std::u32string nsName = nsElement->GetAttribute(U"name");
2502                 std::u32string nsId = nsElement->GetAttribute(U"id");
2503                 std::string nsFileName = ToUtf8(nsId) + ".html";
2504                 std::string nsFilePath = Path::Combine(contentDirnsFileName);
2505                 if (!rebuild)
2506                 {
2507                     if (boost::filesystem::exists(nsFilePath) && boost::filesystem::exists(contentXmlFilePath) && boost::filesystem::last_write_time(contentXmlFilePath) < boost::filesystem::last_write_time(nsFilePath))
2508                     {
2509                         continue;
2510                     }
2511                 }
2512                 std::ofstream nsFile(nsFilePath);
2513                 CodeFormatter formatter(nsFile);
2514                 sngxml::dom::Document nsDocument;
2515                 std::unique_ptr<sngxml::dom::Element> htmlElement(new sngxml::dom::Element(U"html"));
2516                 std::unique_ptr<sngxml::dom::Element> headElement(new sngxml::dom::Element(U"head"));
2517                 std::unique_ptr<sngxml::dom::Element> metaElement(new sngxml::dom::Element(U"meta"));
2518                 metaElement->SetAttribute(U"charset"U"utf-8");
2519                 headElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(metaElement.release()));
2520                 std::unique_ptr<sngxml::dom::Element> titleElement(new sngxml::dom::Element(U"title"));
2521                 std::u32string title;
2522                 if (nsName.empty())
2523                 {
2524                     title = U"Global Namespace";
2525                 }
2526                 else
2527                 {
2528                     title = nsName + U" Namespace";
2529                 }
2530                 titleElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(title)));
2531                 headElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(titleElement.release()));
2532                 std::unique_ptr<sngxml::dom::Element> linkElement(new sngxml::dom::Element(U"link"));
2533                 linkElement->SetAttribute(U"rel"U"stylesheet");
2534                 linkElement->SetAttribute(U"type"U"text/css");
2535                 std::u32string relativeStyleFilePath = ToUtf32(Path::Combine(Path::Combine(".."styleDirName)styleFileName));
2536                 linkElement->SetAttribute(U"href"relativeStyleFilePath);
2537                 headElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(linkElement.release()));
2538                 htmlElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(headElement.release()));
2539                 std::unique_ptr<sngxml::dom::Element> bodyElement(new sngxml::dom::Element(U"body"));
2540                 GenerateNavigation(bodyElement.get()Navigation::headertopLinkparentLinkprevLinknextLink);
2541                 std::unique_ptr<sngxml::dom::Element> h1Element(new sngxml::dom::Element(U"h1"));
2542                 h1Element->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(title)));
2543                 bodyElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(h1Element.release()));
2544                 GenerateNamespaceSection(projectNamensElementbodyElement.get()contentXmlstd::u32string()contentFilePathResolverdocumentationXmlFileNamedocumentationXml);
2545                 GenerateClassSection(projectNamebodyElement.get()nsElementcontentXmlcontentDirstyleDirNamestyleFileNameinlineCodeMapcontentXmlFilePathverboserebuild
2546                     contentFilePathResolvertopLinkdocumentationXmlFileNamedocumentationXml);
2547                 GenerateFunctionSection(projectNameU"Functions"bodyElement.get()nsElementcontentDirstyleDirNamestyleFileNamecontentXmlfunctionElements
2548                     contentFilePathResolverdocumentationXmlFileNamedocumentationXml);
2549                 GenerateEnumSection(projectNamebodyElement.get()nsElementcontentXmlcontentDirstyleDirNamestyleFileNamecontentXmlFilePathverboserebuildtopLink
2550                     contentFilePathResolverdocumentationXmlFileNamedocumentationXml);
2551                 GenerateTypedefSection(projectNamebodyElement.get()nsElementcontentXmlcontentDirstyleDirNamestyleFileNamecontentFilePathResolvertopLink
2552                     documentationXmlFileNamedocumentationXml);
2553                 GenerateVariableSection(projectNameU"Variables"bodyElement.get()nsElementcontentXmlcontentDirstyleDirNamestyleFileNamecontentFilePathResolvertopLink
2554                     documentationXmlFileNamedocumentationXml);
2555                 bodyElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Element(U"hr")));
2556                 GenerateFunctionDetailSection(projectNameU"Function Details"U"Function"bodyElement.get()nsElementfunctionElementscontentXmlinlineCodeMapcontentFilePathResolver
2557                     documentationXmlFileNamedocumentationXml);
2558                 GenerateNavigation(bodyElement.get()Navigation::footertopLinkparentLinkprevLinknextLink);
2559                 htmlElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(bodyElement.release()));
2560                 nsDocument.AppendChild(std::unique_ptr<sngxml::dom::Node>(htmlElement.release()));
2561                 nsDocument.Write(formatter);
2562                 upToDate = false;
2563                 if (verbose)
2564                 {
2565                     std::cout << ToUtf8(projectName) << "==> " << nsFilePath << std::endl;
2566                 }
2567                 prevLink = ToUtf32(nsFileName);
2568             }
2569         }
2570     }
2571 }
2572 
2573 void GenerateModuleHtml(const std::u32string& projectNameconst std::u32string& parentProjectNameconst std::u32string& prevProjectconst std::u32string& nextProject
2574     const std::std::vector<std::u32string>&childProjectsconststd::std::vector<std::u32string>&childProjectNames
2575     sngxml::dom::Document* contentXmlconst std::string& contentDirconst std::string& styleDirName
2576     const std::string& styleFileNameconst std::std::vector<sngcpp::ast::SourceFileNode*>&sourceFilesconststd::string&contentXmlFilePathboolverboseboolrebuildbool& upToDate
2577     HtmlContentFilePathResolver* contentFilePathResolverconst std::u32string& topLinkconst std::string& documentationXmlFileNamesngxml::dom::Document* documentationXml
2578     const std::std::vector<Grammar>&grammars)
2579 {
2580     upToDate = true;
2581     std::string moduleFilePath = GetFullPath(Path::Combine(Path::Combine(contentDir"../..")ToUtf8(projectName) + ".html"));
2582     if (rebuild || !childProjects.empty())
2583     {
2584         upToDate = false;
2585     }
2586     else
2587     {
2588         if (boost::filesystem::exists(moduleFilePath))
2589         {
2590             if (boost::filesystem::exists(contentXmlFilePath) && boost::filesystem::last_write_time(contentXmlFilePath) < boost::filesystem::last_write_time(moduleFilePath))
2591             {
2592                 return;
2593             }
2594         }
2595         else
2596         {
2597             upToDate = false;
2598         }
2599     }
2600     std::u32string parentLink;
2601     if (!parentProjectName.empty())
2602     {
2603         parentLink = U"../" + parentProjectName + U".html";
2604     }
2605     std::u32string prevLink = prevProject;
2606     std::u32string nextLink = nextProject;
2607     std::ofstream moduleFile(moduleFilePath);
2608     CodeFormatter formatter(moduleFile);
2609     sngxml::dom::Document moduleDocument;
2610     std::unique_ptr<sngxml::dom::Element> htmlElement(new sngxml::dom::Element(U"html"));
2611     std::unique_ptr<sngxml::dom::Element> headElement(new sngxml::dom::Element(U"head"));
2612     std::unique_ptr<sngxml::dom::Element> metaElement(new sngxml::dom::Element(U"meta"));
2613     metaElement->SetAttribute(U"charset"U"utf-8");
2614     headElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(metaElement.release()));
2615     std::unique_ptr<sngxml::dom::Element> titleElement(new sngxml::dom::Element(U"title"));
2616     std::u32string title = projectName + U" Module";
2617     titleElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(title)));
2618     headElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(titleElement.release()));
2619     std::unique_ptr<sngxml::dom::Element> linkElement(new sngxml::dom::Element(U"link"));
2620     linkElement->SetAttribute(U"rel"U"stylesheet");
2621     linkElement->SetAttribute(U"type"U"text/css");
2622     std::u32string relativeStyleFilePath = ToUtf32(Path::Combine(Path::Combine("html"styleDirName)styleFileName));
2623     linkElement->SetAttribute(U"href"relativeStyleFilePath);
2624     headElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(linkElement.release()));
2625     htmlElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(headElement.release()));
2626     std::unique_ptr<sngxml::dom::Element> bodyElement(new sngxml::dom::Element(U"body"));
2627     std::unique_ptr<sngxml::dom::Element> h1Element(new sngxml::dom::Element(U"h1"));
2628     std::u32string documentTitle = projectName;
2629     documentTitle.append(U" Module");
2630     h1Element->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(documentTitle)));
2631     bodyElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(h1Element.release()));
2632     GenerateNavigation(bodyElement.get()Navigation::headertopLinkparentLinkprevLinknextLink);
2633     GenerateDocumentation(projectNamedocumentationXmlFileNamedocumentationXmlbodyElement.get()projectNamecontentXmlcontentFilePathResolver
2634         DocFlags::full | DocFlags::paragraph | DocFlags::moduleDoc);
2635     int n = childProjects.size();
2636     if (n > 0)
2637     {
2638         std::unique_ptr<sngxml::dom::Element> modulesElement(new sngxml::dom::Element(U"h2"));
2639         modulesElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U"Modules")));
2640         bodyElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(modulesElement.release()));
2641         std::unique_ptr<sngxml::dom::Element> moduleTableElement(new sngxml::dom::Element(U"table"));
2642         std::unique_ptr<sngxml::dom::Element> headerRowElement(new sngxml::dom::Element(U"tr"));
2643         std::unique_ptr<sngxml::dom::Element> nameElement(new sngxml::dom::Element(U"th"));
2644         nameElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U"Module")));
2645         headerRowElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(nameElement.release()));
2646         if (n == childProjectNames.size())
2647         {
2648             for (int i = 0; i < n; ++i)
2649             {
2650                 const std::u32string& childProjectLink = childProjects[i];
2651                 const std::u32string& childProjectName = childProjectNames[i];
2652                 std::unique_ptr<sngxml::dom::Element> moduleRowElement(new sngxml::dom::Element(U"tr"));
2653                 std::unique_ptr<sngxml::dom::Element> nameElement(new sngxml::dom::Element(U"td"));
2654                 std::unique_ptr<sngxml::dom::Element> moduleLinkElement(new sngxml::dom::Element(U"a"));
2655                 moduleLinkElement->SetAttribute(U"href"childProjectLink);
2656                 moduleLinkElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(childProjectName)));
2657                 nameElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(moduleLinkElement.release()));
2658                 moduleRowElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(nameElement.release()));
2659                 if (documentationXml && documentationXml->GetElementById(childProjectName) != nullptr)
2660                 {
2661                     std::unique_ptr<sngxml::dom::Element> descriptionElement(new sngxml::dom::Element(U"td"));
2662                     GenerateDocumentation(projectNamedocumentationXmlFileNamedocumentationXmldescriptionElement.get()childProjectNamecontentXmlcontentFilePathResolverDocFlags::none);
2663                     moduleRowElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(descriptionElement.release()));
2664                 }
2665                 moduleTableElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(moduleRowElement.release()));
2666             }
2667         }
2668         bodyElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(moduleTableElement.release()));
2669     }
2670     if (contentXml)
2671     {
2672         GenerateModuleNamespaceSection(projectNamebodyElement.get()contentXmlprojectNamecontentFilePathResolverdocumentationXmlFileNamedocumentationXml);
2673         GenerateModuleGrammarSection(bodyElement.get()grammars);
2674         GenerateModuleFileSection(sourceFilesbodyElement.get()projectName);
2675     }
2676     bodyElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Element(U"br")));
2677     bodyElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Element(U"hr")));
2678     GenerateNavigation(bodyElement.get()Navigation::footertopLinkparentLinkprevLinknextLink);
2679     htmlElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(bodyElement.release()));
2680     moduleDocument.AppendChild(std::unique_ptr<sngxml::dom::Node>(htmlElement.release()));
2681     moduleDocument.Write(formatter);
2682     if (verbose)
2683     {
2684         std::cout << ToUtf8(projectName) << "==> " << moduleFilePath << std::endl;
2685     }
2686 }
2687 
2688 int Log10(int n)
2689 {
2690     int log10 = 1;
2691     int m = n / 10;
2692     while (m > 0)
2693     {
2694         ++log10;
2695         m = m / 10;
2696     }
2697     return log10;
2698 }
2699 
2700 std::std::vector<std::u32string>GetLines(conststd::u32string&text)
2701 {
2702     std::vector<std::u32string> lines;
2703     std::u32string line;
2704     int state = 0;
2705     for (char32_t c : text)
2706     {
2707         switch (state)
2708         {
2709             case 0:
2710             {
2711                 if (c == '\n')
2712                 {
2713                     lines.push_back(std::move(line));
2714                     line.clear();
2715                     state = 1;
2716                 }
2717                 else if (c != '\r')
2718                 {
2719                     line.append(1c);
2720                 }
2721                 break;
2722             }
2723             case 1:
2724             {
2725                 if (c == '\n')
2726                 {
2727                     lines.push_back(std::move(line));
2728                     line.clear();
2729                 }
2730                 else if (c != '\r')
2731                 {
2732                     line.append(1c);
2733                     state = 0;
2734                 }
2735                 break;
2736             }
2737         }
2738     }
2739     if (state == 0)
2740     {
2741         lines.push_back(std::move(line));
2742     }
2743     return lines;
2744 }
2745 
2746 void GenerateHtmlCodeFiles(const std::u32string& projectNameconst std::std::vector<sngcpp::ast::SourceFileNode*>&sourceFilesconststd::string&styleDirNameconststd::string&styleFileName
2747     sngcpp::symbols::SymbolTable& symbolTableint inlineCodeLimitstd::std::unordered_map<std::u32stringstd::std::unique_ptr<sngxml::dom::Element>>&inlineCodeMapboolverboseboolrebuild
2748     bool& upToDate
2749     HtmlContentFilePathResolver* contentFilePathResolver)
2750 {
2751     upToDate = true;
2752     for (sngcpp::ast::SourceFileNode* sourceFile : sourceFiles)
2753     {
2754         if (!rebuild)
2755         {
2756             if (boost::filesystem::exists(sourceFile->HtmlSourceFilePath()))
2757             {
2758                 if (boost::filesystem::last_write_time(sourceFile->SourceFilePath()) < boost::filesystem::last_write_time(sourceFile->HtmlSourceFilePath()))
2759                 {
2760                     continue;
2761                 }
2762             }
2763         }
2764         std::vector<std::u32string> inputLines = GetLines(sourceFile->Text());
2765         int n = inputLines.size();
2766         int numDigits = Log10(n);
2767         if (Path::GetExtension(sourceFile->SourceFilePath()) == ".lexer")
2768         {
2769             HtmlLexerFileSourceGenerator generator(projectNameinputLinesnumDigitsstyleDirNamestyleFileName);
2770             sourceFile->Accept(generator);
2771         }
2772         else if (Path::GetExtension(sourceFile->SourceFilePath()) == ".parser")
2773         {
2774             HtmlParserFileSourceGenerator generator(projectNameinputLinesnumDigitsstyleDirNamestyleFileName);
2775             sourceFile->Accept(generator);
2776         }
2777         else
2778         {
2779             HtmlSourceCodeGenerator generator(projectNameinputLinesnumDigitsstyleDirNamestyleFileNamesymbolTableinlineCodeLimitinlineCodeMapcontentFilePathResolver);
2780             sourceFile->Accept(generator);
2781             generator.WriteDocument();
2782         }
2783         upToDate = false;
2784         if (verbose)
2785         {
2786             std::cout << ToUtf8(projectName) << "==> " << sourceFile->HtmlSourceFilePath() << std::endl;
2787         }
2788     }
2789 }
2790 
2791 } } // namespace gendoc::html