1
2
3
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& targetDir, std::string& htmlDir, std::string& contentDir, std::string& fileDir, std::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& styleDir, std::string& styleDirName, std::string& styleFileName)
48 {
49 styleDirName = "style";
50 styleFileName = "style.css";
51 std::string styleFilePath = GetFullPath(Path::Combine(styleDir, styleFileName));
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
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
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(1, ToUpper(name[0])) + name.substr(1);
332 }
333 else
334 {
335 return name;
336 }
337 }
338
339 enum class Navigation
340 {
341 header, footer
342 };
343
344 void GenerateNavigation(sngxml::dom::Element* pageElement, Navigation navigation,
345 const std::u32string& topLink, const std::u32string& parentLink, const std::u32string& prevLink, const 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 left, DocFlags right)
412 {
413 return DocFlags(uint8_t(left) & uint8_t(right));
414 }
415
416 inline DocFlags operator|(DocFlags left, DocFlags 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& projectName, sngxml::dom::Element* element, const std::string& documentationXmlFileName, sngxml::dom::Document* documentationXml,
467 sngxml::dom::Element* parentElement, const std::u32string& id, sngxml::dom::Document* contentXml, HtmlContentFilePathResolver* contentFilePathResolver, DocFlags 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(projectName, project, dirPath, containerElement->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(projectName, childElement, documentationXmlFileName, documentationXml, static_cast<sngxml::dom::Element*>(c.get()), id, contentXml, contentFilePathResolver,
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& projectName, const std::string& documentationXmlFileName, sngxml::dom::Document* documentationXml, sngxml::dom::Element* parentElement,
549 const std::u32string& id, sngxml::dom::Document* contentXml, HtmlContentFilePathResolver* contentFilePathResolver, DocFlags 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(projectName, descriptionElement, documentationXmlFileName, documentationXml, parentElement, id, contentXml, contentFilePathResolver, flags);
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(projectName, bodyElement, documentationXmlFileName, documentationXml, parentElement, id, contentXml, contentFilePathResolver,
606 flags | DocFlags::paragraph);
607 }
608 }
609 }
610 }
611 }
612
613 bool GenerateNamespaceNames(const std::u32string& mainProjectName, int level, sngxml::dom::Element* namespaceTableElement, sngxml::dom::Element* namespaceParentElement,
614 const std::u32string& moduleName, bool global, HtmlContentFilePathResolver* contentFilePathResolver);
615
616 bool GenerateNamespaceNames(const std::u32string& mainProjectName, int level, sngxml::dom::Element* namespaceTableElement, sngxml::dom::Element* namespaceParentElement,
617 const std::u32string& moduleName, HtmlContentFilePathResolver* contentFilePathResolver)
618 {
619 return GenerateNamespaceNames(mainProjectName, level, namespaceTableElement, namespaceParentElement, moduleName, false, contentFilePathResolver);
620 }
621
622 bool GenerateNamespaceNames(const std::u32string& mainProjectName, int level, sngxml::dom::Element* namespaceTableElement, sngxml::dom::Element* namespaceParentElement,
623 const std::u32string& moduleName, bool global, HtmlContentFilePathResolver* 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(mainProjectName, projectName, ".", 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(mainProjectName, level + 1, namespaceTableElement, nsElement, moduleName, contentFilePathResolver);
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* element, const 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& mainProjectName, sngxml::dom::Element* parentNsElement, sngxml::dom::Element* pageElement, sngxml::dom::Document* contentXml,
757 const std::u32string& moduleName, bool global, HtmlContentFilePathResolver* contentFilePathResolver, const std::string& documentationXmlFileName, sngxml::dom::Document* documentationXml);
758
759 void GenerateNamespaceSection(const std::u32string& mainProjectName, sngxml::dom::Element* parentNsElement, sngxml::dom::Element* pageElement, sngxml::dom::Document* contentXml,
760 const std::u32string& moduleName, HtmlContentFilePathResolver* contentFilePathResolver, const std::string& documentationXmlFileName, sngxml::dom::Document* documentationXml)
761 {
762 GenerateNamespaceSection(mainProjectName, parentNsElement, pageElement, contentXml, moduleName, false, contentFilePathResolver, documentationXmlFileName, documentationXml);
763 }
764
765 bool GenerateNamespaceSection(const std::u32string& mainProjectName, sngxml::dom::Element* parentNsElement, sngxml::dom::Element* pageElement, sngxml::dom::Document* contentXml,
766 const std::u32string& moduleName, bool global, HtmlContentFilePathResolver* contentFilePathResolver, const std::string& documentationXmlFileName, sngxml::dom::Document* documentationXml)
767 {
768 std::unique_ptr<sngxml::dom::Element> namespaceTableElement(new sngxml::dom::Element(U"table"));
769 if (GenerateNamespaceNames(mainProjectName, 0, namespaceTableElement.get(), parentNsElement, moduleName, global, contentFilePathResolver))
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& mainProjectName, sngxml::dom::Element* pageElement, sngxml::dom::Document* contentXml, const std::u32string& moduleName,
803 HtmlContentFilePathResolver* contentFilePathResolver, const std::string& documentationXmlFileName, sngxml::dom::Document* documentationXml)
804 {
805 sngxml::dom::Element* globalNsElement = GetGlobalNsElement(contentXml);
806 if (globalNsElement)
807 {
808 if (!GenerateNamespaceSection(mainProjectName, globalNsElement, pageElement, contentXml, moduleName, true, contentFilePathResolver, documentationXmlFileName, documentationXml))
809 {
810 GenerateNamespaceSection(mainProjectName, globalNsElement, pageElement, contentXml, moduleName, false, contentFilePathResolver, documentationXmlFileName, documentationXml);
811 }
812 }
813 }
814
815 void GenerateModuleGrammarSection(sngxml::dom::Element* pageElement, const 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* left, SourceFileNode* right) const
839 {
840 return left->RelativeSourceFilePath() < right->RelativeSourceFilePath();
841 }
842 };
843
844 void GenerateModuleFileSection(const std::std::vector<sngcpp::ast::SourceFileNode*>&sourceFiles, sngxml::dom::Element*pageElement, conststd::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& projectName, sngxml::dom::Element* pageElement, sngxml::dom::Element* parentElement, const std::string& contentDir,
883 const std::string& styleDirName, const std::string& styleFileName, sngxml::dom::Document* contentXml, std::std::vector<sngxml::dom::Element*>&constructorElements,
884 HtmlContentFilePathResolver* contentFilePathResolver, const std::string& documentationXmlFileName, sngxml::dom::Document* documentationXml);
885
886 void GenerateFunctionSection(const std::u32string& projectName, const std::u32string& title, sngxml::dom::Element* pageElement, sngxml::dom::Element* parentElement, const std::string& contentDir,
887 const std::string& styleDirName, const std::string& styleFileName, sngxml::dom::Document* contentXml, std::std::vector<sngxml::dom::Element*>&functionElements,
888 HtmlContentFilePathResolver* contentFilePathResolver, const std::string& documentationXmlFileName, sngxml::dom::Document* documentationXml);
889
890 void GenerateClassSection(const std::u32string& projectName, sngxml::dom::Element* pageElement, sngxml::dom::Element* parentElement, sngxml::dom::Document* contentXml,
891 const std::string& contentDir, const std::string& styleDirName, const std::string& styleFileName,
892 std::std::unordered_map<std::u32string, std::std::unique_ptr<sngxml::dom::Element>>&inlineCodeMap, conststd::string&contentXmlFilePath, boolverbose, boolrebuild,
893 HtmlContentFilePathResolver* contentFilePathResolver, const std::u32string& topLink, const std::string& documentationXmlFileName, sngxml::dom::Document* documentationXml);
894
895 void GenerateEnumSection(const std::u32string& projectName, sngxml::dom::Element* pageElement, sngxml::dom::Element* parentElement, sngxml::dom::Document* contentXml,
896 const std::string& contentDir, const std::string& styleDirName, const std::string& styleFileName, const std::string& contentXmlFilePath, bool verbose, bool rebuild,
897 const std::u32string& topLink, HtmlContentFilePathResolver* contentFilePathResolver, const std::string& documentationXmlFileName, sngxml::dom::Document* documentationXml);
898
899 void GenerateVariableSection(const std::u32string& projectName, const std::u32string& title, sngxml::dom::Element* pageElement, sngxml::dom::Element* parentElement, sngxml::dom::Document* contentXml,
900 const std::string& contentDir, const std::string& styleDirName, const std::string& styleFileName,
901 HtmlContentFilePathResolver* contentFilePathResolver, const std::u32string& topLink, const std::string& documentationXmlFileName, sngxml::dom::Document* documentationXml);
902
903 void GenerateTypedefSection(const std::u32string& projectName, sngxml::dom::Element* pageElement, sngxml::dom::Element* parentElement, sngxml::dom::Document* contentXml,
904 const std::string& contentDir, const std::string& styleDirName, const std::string& styleFileName,
905 HtmlContentFilePathResolver* contentFilePathResolver, const std::u32string& topLink, const std::string& documentationXmlFileName, sngxml::dom::Document* documentationXml);
906
907 void GenerateFunctionDetailSection(const std::u32string& projectName, const std::u32string& title, const std::u32string& functionTitle, sngxml::dom::Element* pageElement, sngxml::dom::Element* parentElement,
908 std::std::vector<sngxml::dom::Element*>&functionElements, sngxml::dom::Document*contentXml, std::std::unordered_map<std::u32string, std::std::unique_ptr<sngxml::dom::Element>>&inlineCodeMap,
909 HtmlContentFilePathResolver* contentFilePathResolver, const std::string& documentationXmlFileName, sngxml::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& projectName, std::std::vector<Class>&classes, sngxml::dom::Element*classElement, sngxml::dom::Document*contentXml, int&depth, int&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(projectName, classes, baseClassElement, contentXml, depth, level, contentFilePathResolver);
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(projectName, GetProject(classElement), ".", classElement->GetAttribute(U"id")));
1048 classes.push_back(Class(MakeFullClassName(classElement), classes.size(), level, true, numDerivedClasses > 0, link));
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(projectName, GetProject(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(), level, false, hasDerivedClasses, link));
1084 }
1085 }
1086 }
1087 }
1088 }
1089 }
1090 }
1091 }
1092 else
1093 {
1094 std::u32string link = ToUtf32(contentFilePathResolver->ResolveContentFilePath(projectName, GetProject(classElement), ".", classElement->GetAttribute(U"id")));
1095 classes.push_back(Class(MakeFullClassName(classElement), classes.size(), level, false, numDerivedClasses > 0, link));
1096 }
1097 }
1098 }
1099
1100 struct ByLevelAndIndex
1101 {
1102 bool operator()(const Class& left, const 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& projectName, const std::string& contentDir, sngxml::dom::Element* classElement, sngxml::dom::Document* contentXml,
1111 std::string& inheritanceDiagramFileName, HtmlContentFilePathResolver* contentFilePathResolver)
1112 {
1113 int depth = 0;
1114 int level = 0;
1115 std::vector<Class> classes;
1116 GenerateClassData(projectName, classes, classElement, contentXml, depth, level, contentFilePathResolver);
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(contentDir, inheritanceDiagramFileName);
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& projectName, sngxml::dom::Element* classElement, sngxml::dom::Document* contentXml, const std::string& contentDir, const std::string& styleDirName, const std::string& styleFileName,
1161 const std::u32string& topLink, const std::u32string& parentLink, const std::u32string& prevLink, std::u32string& nextLink,
1162 std::std::unordered_map<std::u32string, std::std::unique_ptr<sngxml::dom::Element>>&inlineCodeMap, conststd::string&contentXmlFilePath, boolverbose, boolrebuild,
1163 HtmlContentFilePathResolver* contentFilePathResolver, const std::string& documentationXmlFileName, sngxml::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(contentDir, classFileName);
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(projectName, contentDir, classElement, contentXml, inheritanceDiagramFileName, contentFilePathResolver);
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::header, topLink, parentLink, prevLink, nextLink);
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(projectName, documentationXmlFileName, documentationXml, bodyElement.get(), classId, contentXml, contentFilePathResolver, DocFlags::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(projectName, bodyElement.get(), classElement, contentXml, contentDir, styleDirName, styleFileName, inlineCodeMap, contentXmlFilePath, verbose, rebuild,
1252 contentFilePathResolver, topLink, documentationXmlFileName, documentationXml);
1253 GenerateConstructorSection(projectName, bodyElement.get(), classElement, contentDir, styleDirName, styleFileName, contentXml, constructorElements, contentFilePathResolver,
1254 documentationXmlFileName, documentationXml);
1255 GenerateFunctionSection(projectName, U"Member Functions", bodyElement.get(), classElement, contentDir, styleDirName, styleFileName, contentXml, functionElements, contentFilePathResolver,
1256 documentationXmlFileName, documentationXml);
1257 GenerateEnumSection(projectName, bodyElement.get(), classElement, contentXml, contentDir, styleDirName, styleFileName, contentXmlFilePath, verbose, rebuild, topLink,
1258 contentFilePathResolver, documentationXmlFileName, documentationXml);
1259 GenerateTypedefSection(projectName, bodyElement.get(), classElement, contentXml, contentDir, styleDirName, styleFileName, contentFilePathResolver, topLink,
1260 documentationXmlFileName, documentationXml);
1261 GenerateVariableSection(projectName, U"Member Variables", bodyElement.get(), classElement, contentXml, contentDir, styleDirName, styleFileName, contentFilePathResolver, topLink,
1262 documentationXmlFileName, documentationXml);
1263 bodyElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Element(U"hr")));
1264 GenerateFunctionDetailSection(projectName, U"Constructor Details", U"Constructor", bodyElement.get(), classElement, constructorElements, contentXml, inlineCodeMap, contentFilePathResolver,
1265 documentationXmlFileName, documentationXml);
1266 GenerateFunctionDetailSection(projectName, U"Member Function Details", U"Member Function", bodyElement.get(), classElement, functionElements, contentXml, inlineCodeMap, contentFilePathResolver,
1267 documentationXmlFileName, documentationXml);
1268 GenerateNavigation(bodyElement.get(), Navigation::footer, topLink, parentLink, prevLink, nextLink);
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& projectName, sngxml::dom::Element* pageElement, sngxml::dom::Element* parentElement, sngxml::dom::Document* contentXml,
1279 const std::string& contentDir, const std::string& styleDirName, const std::string& styleFileName,
1280 std::std::unordered_map<std::u32string, std::std::unique_ptr<sngxml::dom::Element>>&inlineCodeMap, conststd::string&contentXmlFilePath, boolverbose, boolrebuild,
1281 HtmlContentFilePathResolver* contentFilePathResolver, const std::u32string& topLink, const std::string& documentationXmlFileName, sngxml::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(classElement, projectName)) 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(projectName, documentationXmlFileName, documentationXml, documentationTdElement.get(), classId, contentXml, contentFilePathResolver, DocFlags::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(projectName, classElement, contentXml, contentDir, styleDirName, styleFileName, topLink, parentLink, prevLink, nextLink, inlineCodeMap,
1335 contentXmlFilePath, verbose, rebuild, contentFilePathResolver, documentationXmlFileName, documentationXml);
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& projectName, sngxml::dom::Element* enumTypeElement, sngxml::dom::Document* contentXml, const std::string& contentDir, const std::string& styleDirName, const std::string& styleFileName,
1346 const std::u32string& topLink, const std::u32string& parentLink, const std::u32string& prevLink, std::u32string& nextLink, const std::string& contentXmlFilePath, bool verbose, bool rebuild,
1347 HtmlContentFilePathResolver* contentFilePathResolver, const std::string& documentationXmlFileName, sngxml::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(contentDir, enumFileName);
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::header, topLink, parentLink, prevLink, nextLink);
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(projectName, documentationXmlFileName, documentationXml, bodyElement.get(), enumTypeId, contentXml, contentFilePathResolver, DocFlags::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::footer, topLink, parentLink, prevLink, nextLink);
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& projectName, sngxml::dom::Element* pageElement, sngxml::dom::Element* parentElement, sngxml::dom::Document* contentXml,
1458 const std::string& contentDir, const std::string& styleDirName, const std::string& styleFileName, const std::string& contentXmlFilePath, bool verbose, bool rebuild,
1459 const std::u32string& topLink, HtmlContentFilePathResolver* contentFilePathResolver, const std::string& documentationXmlFileName, sngxml::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(enumElement, projectName)) 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(projectName, documentationXmlFileName, documentationXml, documentationTdElement.get(), enumId, contentXml, contentFilePathResolver, DocFlags::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(projectName, enumTypeElement, contentXml, contentDir, styleDirName, styleFileName, topLink, parentLink, prevLink, nextLink, contentXmlFilePath, verbose, rebuild,
1513 contentFilePathResolver, documentationXmlFileName, documentationXml);
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& projectName, sngxml::dom::Element* pageElement, sngxml::dom::Element* parentElement, const std::u32string& typeId, sngxml::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(projectName, pageElement, parentElement, typeId, contentXml, contentFilePathResolver);
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(projectName, pageElement, parentElement, primaryTypeId, contentXml, contentFilePathResolver);
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(projectName, pageElement, parentElement, templateArgumentTypeId, contentXml, contentFilePathResolver);
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(projectName, parentProject, ".", 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(projectName, typeProject, ".", 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& projectName, sngxml::dom::Element* pageElement, sngxml::dom::Element* parentElement, sngxml::dom::Element* parameterElement,
1652 sngxml::dom::Document* contentXml, HtmlContentFilePathResolver* contentFilePathResolver)
1653 {
1654 std::u32string typeId = parameterElement->GetAttribute(U"type");
1655 AppendTypeName(projectName, pageElement, parentElement, typeId, contentXml, contentFilePathResolver);
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* constructorElement, bool fullName);
1664
1665 std::u32string MakeConstructorName(sngxml::dom::Element* constructorElement)
1666 {
1667 return MakeConstructorName(constructorElement, false);
1668 }
1669
1670 std::u32string MakeConstructorName(sngxml::dom::Element* constructorElement, bool 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* functionElement, bool fullName);
1692
1693 std::u32string MakeFunctionName(sngxml::dom::Element* functionElement)
1694 {
1695 return MakeFunctionName(functionElement, false);
1696 }
1697
1698 std::u32string MakeFunctionName(sngxml::dom::Element* functionElement, bool 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& projectName, sngxml::dom::Element* pageElement, sngxml::dom::Element* parentElement, sngxml::dom::Element* functionElement,
1737 sngxml::dom::Document* contentXml, HtmlContentFilePathResolver* 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(projectName, pageElement, parentElement, parameterElement, contentXml, contentFilePathResolver);
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& projectName, const std::u32string& title, sngxml::dom::Element* pageElement, sngxml::dom::Element* parentElement, sngxml::dom::Document* contentXml,
1763 const std::string& contentDir, const std::string& styleDirName, const std::string& styleFileName, HtmlContentFilePathResolver* contentFilePathResolver, const std::u32string& topLink,
1764 const std::string& documentationFileName, sngxml::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(variableElement, projectName)) 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(projectName, typeTdElement.get(), parentElement, variableTypeId, contentXml, contentFilePathResolver);
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(projectName, documentationFileName, documentationXml, documentationTdElement.get(), variableId, contentXml, contentFilePathResolver, DocFlags::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& projectName, sngxml::dom::Element* pageElement, sngxml::dom::Element* parentElement, sngxml::dom::Document* contentXml,
1832 const std::string& contentDir, const std::string& styleDirName, const std::string& styleFileName, HtmlContentFilePathResolver* contentFilePathResolver, const std::u32string& topLink,
1833 const std::string& documentationXmlFileName, sngxml::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(typedefElement, projectName)) 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(projectName, typeTdElement.get(), parentElement, typedefTypeId, contentXml, contentFilePathResolver);
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(projectName, documentationXmlFileName, documentationXml, documentationTdElement.get(), typedefId, contentXml, contentFilePathResolver, DocFlags::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& projectName, sngxml::dom::Element* pageElement, sngxml::dom::Element* parentElement, const std::string& contentDir,
1892 const std::string& styleDirName, const std::string& styleFileName, sngxml::dom::Document* contentXml, std::std::vector<sngxml::dom::Element*>&constructorElements,
1893 HtmlContentFilePathResolver* contentFilePathResolver, const std::string& documentationXmlFileName, sngxml::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(constructorElement, projectName)) 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(projectName, tdElement.get(), parentElement, constructorElement, contentXml, contentFilePathResolver);
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(projectName, documentationXmlFileName, documentationXml, documentationTdElement.get(), constructorId, contentXml, contentFilePathResolver, DocFlags::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& projectName, const std::u32string& title, sngxml::dom::Element* pageElement, sngxml::dom::Element* parentElement, const std::string& contentDir,
1959 const std::string& styleDirName, const std::string& styleFileName, sngxml::dom::Document* contentXml, std::std::vector<sngxml::dom::Element*>&functionElements,
1960 HtmlContentFilePathResolver* contentFilePathResolver, const std::string& documentationXmlFileName, sngxml::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(functionElement, projectName)) 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(projectName, tdElement.get(), parentElement, returnTypeId, contentXml, contentFilePathResolver);
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(projectName, tdElement.get(), parentElement, functionElement, contentXml, contentFilePathResolver);
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(projectName, documentationXmlFileName, documentationXml, documentationTdElement.get(), functionId, contentXml, contentFilePathResolver, DocFlags::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::u32string, std::std::unique_ptr<sngxml::dom::Element>>&left, conststd::std::pair<std::u32string, std::std::unique_ptr<sngxml::dom::Element>>&right) const
2044 {
2045 return left.first < right.first;
2046 }
2047 };
2048
2049 void GenerateFunctionDetailSection(const std::u32string& projectName, const std::u32string& title, const std::u32string& functionTitle, sngxml::dom::Element* pageElement,
2050 sngxml::dom::Element* parentElement, std::std::vector<sngxml::dom::Element*>&functionElements, sngxml::dom::Document*contentXml,
2051 std::std::unordered_map<std::u32string, std::std::unique_ptr<sngxml::dom::Element>>&inlineCodeMap, HtmlContentFilePathResolver*contentFilePathResolver, conststd::string&documentationXmlFileName, sngxml::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(projectName, h4Element.get(), parentElement, returnTypeId, contentXml, contentFilePathResolver);
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(functionElement, true);
2079 }
2080 else if (functionElement->Name() == U"constructor")
2081 {
2082 functionName = MakeConstructorName(functionElement, true);
2083 }
2084 h4Element->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(functionName)));
2085 AppendParameterList(projectName, h4Element.get(), parentElement, functionElement, contentXml, contentFilePathResolver);
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(projectName, documentationXmlFileName, documentationXml, pageElement, functionId, contentXml, contentFilePathResolver, DocFlags::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::u32string, std::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(projectName, proj, ".", classId));
2197 std::u32string overriddenLink = classLink + U"#" + overriddenId;
2198 std::u32string overriddenFunctionName = MakeFunctionName(overriddenElement, true);
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(overriddenFunctionName, std::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::u32string, std::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::u32string, std::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(projectName, proj, ".", classId));
2270 std::u32string overrideLink = classLink + U"#" + overrideId;
2271 std::u32string overrideFunctionName = MakeFunctionName(overrideElement, true);
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(overrideFunctionName, std::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::u32string, std::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::u32string, std::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(projectName, proj, ".", parentId));
2342 std::u32string callLink = parentLink + U"#" + callId;
2343 std::u32string callFunctionName = MakeFunctionName(callElement, true);
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(callFunctionName, std::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::u32string, std::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::u32string, std::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(projectName, proj, ".", parentId));
2422 std::u32string calledByLink = parentLink + U"#" + calledById;
2423 std::u32string calledByFunctionName = MakeFunctionName(calledByElement, true);
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(calledByFunctionName, std::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::u32string, std::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& projectName, sngxml::dom::Document* contentXml, const std::string& contentDir, const std::string& styleDirName, const std::string& styleFileName,
2470 std::std::unordered_map<std::u32string, std::std::unique_ptr<sngxml::dom::Element>>&inlineCodeMap, conststd::string&contentXmlFilePath, boolverbose, boolrebuild, bool&upToDate,
2471 HtmlContentFilePathResolver* contentFilePathResolver, const std::u32string& topLink, const std::string& documentationXmlFileName, sngxml::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(contentDir, nsFileName);
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::header, topLink, parentLink, prevLink, nextLink);
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(projectName, nsElement, bodyElement.get(), contentXml, std::u32string(), contentFilePathResolver, documentationXmlFileName, documentationXml);
2545 GenerateClassSection(projectName, bodyElement.get(), nsElement, contentXml, contentDir, styleDirName, styleFileName, inlineCodeMap, contentXmlFilePath, verbose, rebuild,
2546 contentFilePathResolver, topLink, documentationXmlFileName, documentationXml);
2547 GenerateFunctionSection(projectName, U"Functions", bodyElement.get(), nsElement, contentDir, styleDirName, styleFileName, contentXml, functionElements,
2548 contentFilePathResolver, documentationXmlFileName, documentationXml);
2549 GenerateEnumSection(projectName, bodyElement.get(), nsElement, contentXml, contentDir, styleDirName, styleFileName, contentXmlFilePath, verbose, rebuild, topLink,
2550 contentFilePathResolver, documentationXmlFileName, documentationXml);
2551 GenerateTypedefSection(projectName, bodyElement.get(), nsElement, contentXml, contentDir, styleDirName, styleFileName, contentFilePathResolver, topLink,
2552 documentationXmlFileName, documentationXml);
2553 GenerateVariableSection(projectName, U"Variables", bodyElement.get(), nsElement, contentXml, contentDir, styleDirName, styleFileName, contentFilePathResolver, topLink,
2554 documentationXmlFileName, documentationXml);
2555 bodyElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Element(U"hr")));
2556 GenerateFunctionDetailSection(projectName, U"Function Details", U"Function", bodyElement.get(), nsElement, functionElements, contentXml, inlineCodeMap, contentFilePathResolver,
2557 documentationXmlFileName, documentationXml);
2558 GenerateNavigation(bodyElement.get(), Navigation::footer, topLink, parentLink, prevLink, nextLink);
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& projectName, const std::u32string& parentProjectName, const std::u32string& prevProject, const std::u32string& nextProject,
2574 const std::std::vector<std::u32string>&childProjects, conststd::std::vector<std::u32string>&childProjectNames,
2575 sngxml::dom::Document* contentXml, const std::string& contentDir, const std::string& styleDirName,
2576 const std::string& styleFileName, const std::std::vector<sngcpp::ast::SourceFileNode*>&sourceFiles, conststd::string&contentXmlFilePath, boolverbose, boolrebuild, bool& upToDate,
2577 HtmlContentFilePathResolver* contentFilePathResolver, const std::u32string& topLink, const std::string& documentationXmlFileName, sngxml::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::header, topLink, parentLink, prevLink, nextLink);
2633 GenerateDocumentation(projectName, documentationXmlFileName, documentationXml, bodyElement.get(), projectName, contentXml, contentFilePathResolver,
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(projectName, documentationXmlFileName, documentationXml, descriptionElement.get(), childProjectName, contentXml, contentFilePathResolver, DocFlags::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(projectName, bodyElement.get(), contentXml, projectName, contentFilePathResolver, documentationXmlFileName, documentationXml);
2673 GenerateModuleGrammarSection(bodyElement.get(), grammars);
2674 GenerateModuleFileSection(sourceFiles, bodyElement.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::footer, topLink, parentLink, prevLink, nextLink);
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(1, c);
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(1, c);
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& projectName, const std::std::vector<sngcpp::ast::SourceFileNode*>&sourceFiles, conststd::string&styleDirName, conststd::string&styleFileName,
2747 sngcpp::symbols::SymbolTable& symbolTable, int inlineCodeLimit, std::std::unordered_map<std::u32string, std::std::unique_ptr<sngxml::dom::Element>>&inlineCodeMap, boolverbose, boolrebuild,
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(projectName, inputLines, numDigits, styleDirName, styleFileName);
2770 sourceFile->Accept(generator);
2771 }
2772 else if (Path::GetExtension(sourceFile->SourceFilePath()) == ".parser")
2773 {
2774 HtmlParserFileSourceGenerator generator(projectName, inputLines, numDigits, styleDirName, styleFileName);
2775 sourceFile->Accept(generator);
2776 }
2777 else
2778 {
2779 HtmlSourceCodeGenerator generator(projectName, inputLines, numDigits, styleDirName, styleFileName, symbolTable, inlineCodeLimit, inlineCodeMap, contentFilePathResolver);
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 } }