NumeRe v1.1.4
NumeRe: Framework für Numerische Rechnungen
docfile.cpp
Go to the documentation of this file.
1/*****************************************************************************
2 NumeRe: Framework fuer Numerische Rechnungen
3 Copyright (C) 2021 Erik Haenel et al.
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17******************************************************************************/
18
19#include <fstream>
20
21#include "docfile.hpp"
22#include "../utils/tinyxml2.h"
23#include "../utils/tools.hpp" // for stripSpaces()
24
25
37static void parseHeader(const std::string& sCombinedArticle, DocumentationEntry& docEntry, std::vector<std::string>& keyWords)
38{
39 // Parse the whole string as XML
41 tinyxml2::XMLError e = doc.Parse(sCombinedArticle.c_str(), sCombinedArticle.length());
42
43 if (e != tinyxml2::XML_SUCCESS)
45
46 // Try to find the article section
47 // (has to be available at this location)
48 tinyxml2::XMLElement* article = doc.FirstChildElement("article");
49
50 // Get ID
51 if (article->Attribute("id"))
52 docEntry.sArticleId = article->Attribute("id");
53
54 tinyxml2::XMLElement* iter = article->FirstChildElement("title");
55
56 // Get title and IDX keys
57 if (iter && iter->Attribute("string"))
58 docEntry.sTitle = iter->Attribute("string");
59
60 if (iter && iter->Attribute("idxkey"))
61 docEntry.sIdxKeys = iter->Attribute("idxkey");
62
63 // Get the keywords sections
64 iter = article->FirstChildElement("keywords");
65
66 // Parse keywords
67 if (iter)
68 {
69 iter = iter->FirstChildElement("keyword");
70
71 while (iter)
72 {
73 keyWords.push_back(iter->GetText());
74 iter = iter->NextSiblingElement();
75 }
76 }
77}
78
79
90DocumentationArticle::DocumentationArticle(const std::vector<std::string>& vArticleContents, const std::string& sFileName)
91{
92 std::string sCombinedArticle;
93
94 for (const auto& text : vArticleContents)
95 {
96 sCombinedArticle += text;
97 }
98
99 // Only complete sets with both <article> and </article>
100 // will enter this function
101 sCombinedArticle.erase(0, sCombinedArticle.find("<article "));
102 sCombinedArticle.erase(sCombinedArticle.find("</article>")+10);
103
104 // Parse the documentation article header information
105 parseHeader(sCombinedArticle, m_docEntry, m_keywords);
106
107 m_docEntry.sDocFilePath = sFileName;
108
109 // Extract the contents section of the documentation article
110 // into the internal vector
111 for (size_t i = 0; i < vArticleContents.size(); i++)
112 {
113 if (vArticleContents[i].find("<contents>") != std::string::npos)
114 {
115 if (vArticleContents[i].substr(vArticleContents[i].find("<contents>")+10).length())
116 m_contents.push_back(vArticleContents[i].substr(vArticleContents[i].find("<contents>")+10));
117
118 for (size_t j = i+1; j < vArticleContents.size(); j++)
119 {
120 if (vArticleContents[j].find("</contents>") != std::string::npos)
121 {
122 if (vArticleContents[j].find("</contents>"))
123 m_contents.push_back(vArticleContents[j].substr(0, vArticleContents[j].find("</contents>")));
124
125 break;
126 }
127
128 m_contents.push_back(vArticleContents[j]);
129 }
130
131 break;
132 }
133 }
134
135}
136
137
146static int indentationLevelDiff(const std::string& sText)
147{
148 int diff = 0;
149 std::vector<std::string> vTagStack;
150
151 // Go through the line
152 for (size_t i = 0; i < sText.length(); i++)
153 {
154 // Examine all tags
155 if (sText[i] == '<')
156 {
157 std::string tag = sText.substr(i, sText.find('>', i) + 1 - i);
158 std::string tagVal = tag.substr(tag.find_first_not_of("</ "));
159 tagVal.erase(tagVal.find_first_of(" />"));
160
161 // Ignore self-terminating tags
162 if (tag.find("/>") != std::string::npos)
163 continue;
164
165 // Is it an opening or closing tag?
166 if (tag.substr(0, 2) == "</")
167 {
168 // Do only decrement matched pairs
169 if (vTagStack.size() && tagVal == vTagStack.back())
170 {
171 vTagStack.pop_back();
172 diff--;
173 }
174 else if (!vTagStack.size()) // may be matched against a previous line
175 diff--;
176 //do not decrement if unmatched
177 }
178 else
179 {
180 // Always increment
181 vTagStack.push_back(tagVal);
182 diff++;
183 }
184 }
185 }
186
187 return diff;
188}
189
190
200{
201 // Format the header
202 std::string sFormat = "<article id=\"" + m_docEntry.sArticleId + "\" >\n\t<title string=\"" + m_docEntry.sTitle + "\" idxkey=\"" + m_docEntry.sIdxKeys + "\" />\n\t<keywords>\n";
203
204 // Add the keywords
205 for (const auto& keyw : m_keywords)
206 {
207 sFormat += "\t\t<keyword>" + keyw + "</keyword>\n";
208 }
209
210 // Terminate the header and start the
211 // contents section
212 sFormat += "\t</keywords>\n\t<contents>\n";
213
214 int indentationLevel = 0;
215
216 // Add the contents
217 for (const auto& text : m_contents)
218 {
219 int indLevelDiff = indentationLevelDiff(text);
220
221 if (indLevelDiff < 0)
222 indentationLevel += indLevelDiff;
223
224 // Not below zero!
225 indentationLevel = std::max(0, indentationLevel);
226
227 sFormat.append(indentationLevel+2, '\t');
228 sFormat += text + "\n";
229
230 if (indLevelDiff > 0)
231 indentationLevel += indLevelDiff;
232 }
233
234 return sFormat + "\t</contents>\n</article>";
235}
236
237
238
239
240
248DocumentationFile::DocumentationFile(const std::string& sFileName)
249{
250 parse(loadFromFile(sFileName), sFileName);
251}
252
253
261DocumentationFile::DocumentationFile(const std::vector<std::string>& vFileContents)
262{
263 parse(vFileContents, "");
264}
265
266
275std::vector<std::string> DocumentationFile::loadFromFile(const std::string& sFileName)
276{
277 std::vector<std::string> vFileContents;
278 std::ifstream file(sFileName);
279
280 if (!file.good())
282
283 while (!file.eof())
284 {
285 vFileContents.push_back("");
286 std::getline(file, vFileContents.back());
287 StripSpaces(vFileContents.back());
288 }
289
290 return vFileContents;
291}
292
293
304void DocumentationFile::parse(const std::vector<std::string>& vFileContents, const std::string& sFileName)
305{
306 for (size_t i = 0; i < vFileContents.size(); i++)
307 {
308 // Start of an article section
309 if (vFileContents[i].find("<article ") != std::string::npos)
310 {
311 // Search for its end
312 for (size_t j = i; j < vFileContents.size(); j++)
313 {
314 if (vFileContents[j].find("</article>") != std::string::npos
315 && (j > i || vFileContents[i].find("<article ") < vFileContents[j].find("</article>")))
316 {
317 m_articles.push_back(DocumentationArticle(std::vector<std::string>(vFileContents.begin()+i, vFileContents.begin()+j+1), sFileName));
318
319 if (j > i)
320 i = j-1;
321 }
322 }
323 }
324 }
325}
326
327
336void DocumentationFile::print(const std::string& sFileName)
337{
338 std::ofstream file(sFileName, std::ios_base::out | std::ios_base::trunc);
339
340 if (!file.good())
342
343 for (auto& article : m_articles)
344 {
345 file << article.format() << std::endl;
346 }
347}
348
349
void parse(const std::vector< std::string > &vFileContents, const std::string &sFileName)
Parse the documentation file into single articles. Only complete <article>..</article> sections are p...
Definition: docfile.cpp:304
void print(const std::string &sFileName)
Print the documentation file to the specified file.
Definition: docfile.cpp:336
std::vector< DocumentationArticle > m_articles
Definition: docfile.hpp:63
std::vector< std::string > loadFromFile(const std::string &sFileName)
Load the documentation file contents from the specified file.
Definition: docfile.cpp:275
DocumentationFile(const std::string &sFileName)
Create a DocumentationFile from the an actual file.
Definition: docfile.cpp:248
Common exception class for all exceptions thrown in NumeRe.
Definition: error.hpp:32
@ CANNOT_READ_FILE
Definition: error.hpp:75
@ HLPIDX_ENTRY_IS_MISSING
INSERT HERE.
Definition: error.hpp:115
@ HLP_FILE_MISSING
Definition: error.hpp:116
static size_t invalid_position
Definition: error.hpp:235
const char * ErrorStr() const
Definition: tinyxml2.cpp:2501
XMLError Parse(const char *xml, size_t nBytes=static_cast< size_t >(-1))
Definition: tinyxml2.cpp:2415
const char * GetText() const
Definition: tinyxml2.cpp:1656
const char * Attribute(const char *name, const char *value=0) const
Definition: tinyxml2.cpp:1595
const XMLElement * NextSiblingElement(const char *name=0) const
Get the next (right) sibling element of this node, with an optionally supplied name.
Definition: tinyxml2.cpp:1018
const XMLElement * FirstChildElement(const char *name=0) const
Definition: tinyxml2.cpp:994
static int indentationLevelDiff(const std::string &sText)
Calculate the indentation level difference from the passed line.
Definition: docfile.cpp:146
static void parseHeader(const std::string &sCombinedArticle, DocumentationEntry &docEntry, std::vector< std::string > &keyWords)
Parse the documentation article header into the DocumentationEntry structure and the list of keywords...
Definition: docfile.cpp:37
CONSTCD11 std::enable_if<!std::chrono::treat_as_floating_point< T >::value, T >::type trunc(T t) NOEXCEPT
Definition: date.h:1113
@ XML_SUCCESS
Definition: tinyxml2.h:524
#define max(a, b)
Definition: resampler.cpp:30
void StripSpaces(std::string &)
Removes leading and trailing white spaces and tabulator characters.
This structure defines a single article in a documentation file.
Definition: docfile.hpp:44
DocumentationEntry m_docEntry
Definition: docfile.hpp:45
std::vector< std::string > m_keywords
Definition: docfile.hpp:46
std::string format()
Format the documentation article into a single string, which then can be printed to a file.
Definition: docfile.cpp:199
DocumentationArticle(const std::vector< std::string > &vArticleContents, const std::string &sFileName)
Create a DocumentationArticle structure from the selected part of the documentation file containing e...
Definition: docfile.cpp:90
std::vector< std::string > m_contents
Definition: docfile.hpp:47
This structure defines a single entry in the documentation index.
Definition: docfile.hpp:30
std::string sDocFilePath
Definition: docfile.hpp:32
std::string sArticleId
Definition: docfile.hpp:31
std::string sIdxKeys
Definition: docfile.hpp:34
std::string sTitle
Definition: docfile.hpp:33