NumeRe v1.1.4
NumeRe: Framework für Numerische Rechnungen
doc_helper.cpp
Go to the documentation of this file.
1/*****************************************************************************
2 NumeRe: Framework fuer Numerische Rechnungen
3 Copyright (C) 2016 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#include <fstream>
19
20#include "doc_helper.hpp"
21#include "docfile.hpp"
22#include "../version.h"
23#include "../utils/tools.hpp"
24#include "../../kernel.hpp"
25#include <algorithm>
26
27using namespace std;
28
29
39static void stripComments(std::string& sLine, std::ifstream& fDocument)
40{
41 while (sLine.find("<!--") != std::string::npos)
42 {
43 if (sLine.find("-->", sLine.find("<!--")+4) != std::string::npos)
44 sLine.erase(sLine.find("<!--"), sLine.find("-->", sLine.find("<!--")+4)+3 - sLine.find("<!--"));
45 else
46 {
47 sLine.erase(sLine.find("<!--"));
48 std::string sLineTemp = "";
49
50 while (!fDocument.eof())
51 {
52 std::getline(fDocument, sLineTemp);
53 StripSpaces(sLineTemp);
54
55 if (!sLineTemp.length())
56 continue;
57
58 if (sLineTemp.find("-->") != std::string::npos)
59 {
60 sLine += sLineTemp.substr(sLineTemp.find("-->")+3);
61 break;
62 }
63 }
64 }
65 }
66}
67
68
79static void findArticleById(std::string& sLine, const std::string& sArticleID, std::ifstream& fDocument)
80{
81 while (sLine.find("<article ") != std::string::npos && !fDocument.eof())
82 {
83 // Does the article contain the necessary ID?
84 if (Documentation::getArgAtPos(sLine, sLine.find("id=")+3) != sArticleID)
85 {
86 while (!fDocument.eof())
87 {
88 std::getline(fDocument, sLine);
89 StripSpaces(sLine);
90
91 // Remove comments
92 if (sLine.find("<!--") != std::string::npos)
93 stripComments(sLine, fDocument);
94
95 if (!sLine.length())
96 continue;
97
98 // The next article starts
99 if (sLine.find("<article") != std::string::npos)
100 break;
101 }
102 }
103 else
104 {
105 sLine.erase(0, sLine.find('>', sLine.find("<article "))+1);
106 StripSpaces(sLine);
107 return;
108 }
109 }
110}
111
112
122static std::vector<std::string> loadDocumentationArticle(const std::string& sFileName, const std::string& sArticleID)
123{
124 std::ifstream fDocument;
125 fDocument.open(sFileName.c_str(), std::ios_base::in);
126
127 if (fDocument.fail())
128 {
129 fDocument.close();
131 }
132
133 std::string sLine;
134 std::vector<std::string> vReturn;
135
136 while (!fDocument.eof())
137 {
138 std::getline(fDocument, sLine);
139 StripSpaces(sLine);
140
141 // Remove comments
142 if (sLine.find("<!--") != std::string::npos)
143 stripComments(sLine, fDocument);
144
145 if (!sLine.length())
146 continue;
147
148 // Find the selected article
149 if (sLine.find("<article ") != std::string::npos)
150 {
151 findArticleById(sLine, sArticleID, fDocument);
152
153 if (fDocument.eof())
154 {
155 vReturn.push_back("NO_ENTRY_FOUND");
156 return vReturn;
157 }
158
159 if (!sLine.length())
160 continue;
161 }
162
163 // Extract the title
164 if (sLine.find("<title ") != std::string::npos)
165 {
166 vReturn.push_back(getArgAtPos(sLine, sLine.find("string=", sLine.find("<title "))+7));
167 sLine.erase(0, sLine.find("/>", sLine.find("<title "))+2);
168 StripSpaces(sLine);
169
170 if (!sLine.length())
171 continue;
172 }
173
174 // Extract the contents
175 if (sLine.find("<contents>") != std::string::npos)
176 {
177 sLine.erase(0, sLine.find("<contents>")+10);
178
179 if (sLine.length())
180 vReturn.push_back(sLine);
181
182 while (!fDocument.eof())
183 {
184 std::getline(fDocument, sLine);
185 StripSpaces(sLine);
186
187 if (!sLine.length())
188 continue;
189
190 if (sLine.find("<!--") != std::string::npos)
191 stripComments(sLine, fDocument);
192
193 if (sLine.find("</contents>") != std::string::npos)
194 {
195 sLine.erase(sLine.find("</contents>"));
196
197 if (sLine.length())
198 vReturn.push_back(sLine);
199
200 return vReturn;
201 }
202
203 vReturn.push_back(sLine);
204 }
205 }
206 }
207
208 fDocument.close();
209
210 if (!vReturn.size())
211 vReturn.push_back("NO_ENTRY_FOUND");
212
213 return vReturn;
214}
215
216
217
218
219
220
221
226{
227 vDocIndexTable.reserve(128);
228}
229
230
236{
237}
238
239
251void Documentation::addEntry(const DocumentationEntry& entry, const std::vector<std::string>& keyWords)
252{
254 int nIndex = findPositionUsingIdxKeys(entry.sIdxKeys);
255
256 // No entry found?
257 if (nIndex == -1)
258 {
259 nIndex = vDocIndexTable.size();
260 vDocIndexTable.push_back(entry);
261
262 // Insert all keys
263 for (const std::string& key : keys)
264 mDocumentationIndex[key] = nIndex;
265 }
266 else
267 {
268 vDocIndexTable[nIndex] = entry;
269
270 // synchronize all keys
271 for (const std::string& key : keys)
272 mDocumentationIndex[key] = nIndex;
273 }
274
275 // Insert the keywords to the map and use the
276 // identified index as reference
277 for (const std::string& kw : keyWords)
278 mDocumentationIndex[kw] = nIndex;
279}
280
281
291int Documentation::findPositionInDocumentationIndex(const std::string& sTopic) const
292{
293 int nIndex = -1;
294 auto iter = mDocumentationIndex.begin();
295 auto firstIndex = mDocumentationIndex.end();
296 auto secondIndex = mDocumentationIndex.end();
297
298 for (int i = sTopic.length(); i > 0; i--)
299 {
300 if (firstIndex != mDocumentationIndex.end())
301 iter = firstIndex;
302 else
303 iter = mDocumentationIndex.begin();
304
305 for (; iter != secondIndex; ++iter)
306 {
307 if (iter->first[0] < sTopic[0])
308 continue;
309
310 if (iter->first[0] == sTopic[0] && firstIndex == mDocumentationIndex.end())
311 firstIndex = iter;
312
313 if (iter->first[0] > sTopic[0])
314 {
315 secondIndex = iter;
316 break;
317 }
318
319 if (iter->first == sTopic.substr(0,i))
320 {
321 nIndex = iter->second;
322 break;
323 }
324 }
325
326 if (nIndex != -1)
327 break;
328 }
329
330 return nIndex;
331}
332
333
346int Documentation::findPositionUsingIdxKeys(const std::string& sIdxKeys) const
347{
349 int nIndex = -1;
350
351 // is this item already known? (user lang file)
352 std::map<int,size_t> keyCount;
353 for (const std::string& key : keys)
354 {
355 if (mDocumentationIndex.find(key) != mDocumentationIndex.end())
356 {
357 keyCount[mDocumentationIndex.at(key)]++;
358 }
359 }
360
361 // Find the entry with most key matches
362 if (keyCount.size())
363 {
364 auto el = std::max_element(keyCount.begin(), keyCount.end(),
365 [](const pair<int,size_t>& p1, const pair<int,size_t>& p2) { return p1.second < p2.second; });
366 nIndex = el->first;
367 }
368
369 return nIndex;
370}
371
372
382std::string Documentation::getArgAtPos(const std::string& sCmd, unsigned int nPos)
383{
384 std::string sArgument = "";
385
386 // If the position is greater than the string length
387 // return an empty string
388 if (nPos >= sCmd.length())
389 return "";
390
391 // Jump over whitespaces
392 while (nPos < sCmd.length() && sCmd[nPos] == ' ')
393 nPos++;
394
395 // Ensure that the position is smaller than the length of the string
396 if (nPos >= sCmd.length())
397 return "";
398
399 // Extract the option value
400 // Determine the delimiter first
401 if (sCmd[nPos] == '"')
402 {
403 // This option value is surrounded with quotation marks
404 // Go through the string and find the next quotation
405 // mark, which is not escaped by a backslash
406 for (unsigned int i = nPos + 1; i < sCmd.length(); i++)
407 {
408 if (sCmd[i] == '"' && sCmd[i - 1] != '\\')
409 {
410 sArgument = sCmd.substr(nPos+1, i - nPos - 1);
411 break;
412 }
413 }
414 }
415 else
416 {
417 // This option value is not surrounded with quotation marks
418 // Go through the string and find the next whitespace
419 for (unsigned int i = nPos; i < sCmd.length(); i++)
420 {
421 // Jump over parentheses, if you find one
422 if (sCmd[i] == '(' || sCmd[i] == '[' || sCmd[i] == '{')
423 i += getMatchingParenthesis(sCmd.substr(i));
424
425 // Whitespace. Stop the loop here
426 if (sCmd[i] == ' ')
427 {
428 sArgument = sCmd.substr(nPos, i - nPos);
429 StripSpaces(sArgument);
430 break;
431 }
432 }
433
434 // Special case: obviously there's no whitespace any more
435 // simply use the remaining string completely
436 if (!sArgument.length())
437 {
438 sArgument = sCmd.substr(nPos);
439 StripSpaces(sArgument);
440 }
441 }
442
443 // return the found option value
444 return sArgument;
445}
446
447
456void Documentation::createDocumentationIndex(bool bLoadUserLangFiles)
457{
459
460 // Add standard documentation files
461 std::vector<std::string> vFiles = getFileList(ValidFolderName("<>") + "docs/*.nhlp", _option, 1);
462
463 for (const std::string& file : vFiles)
464 {
466 }
467
468 // Add plugin documentation files
469 vFiles = getFileList(ValidFolderName("<>") + "docs/plugins/*.nhlp", _option, 1);
470
471 for (const std::string& file : vFiles)
472 {
474 }
475
476 if (!bLoadUserLangFiles)
477 return;
478
479 // Add user documentation files
480 vFiles = getFileList(ValidFolderName("<>") + "user/docs/*.nhlp", _option, 1);
481
482 for (const std::string& file : vFiles)
483 {
485 }
486}
487
488
498void Documentation::addFileToDocumentationIndex(const std::string& sFileName)
499{
500 if (!sFileName.length())
501 return;
502
503 try
504 {
505 DocumentationFile docFile(sFileName);
506
507 // Parse the file and add it to the documentation
508 // index
509 for (DocumentationArticle& article : docFile.getArticles())
510 {
511 if (article.m_keywords.size())
512 addEntry(article.m_docEntry, article.m_keywords);
513 }
514 }
515 catch (...)
516 {
517 // Catch all to avoid issues during start-up
518 }
519}
520
521
531void Documentation::removeFromDocIndex(const string& _sID)
532{
533 if (!vDocIndexTable.size())
535
536 if (_sID == "<<NO_HLP_ENTRY>>")
537 return;
538
539 // Search the documentation ID in the documentation
540 // index table
541 for (size_t i = 0; i < vDocIndexTable.size(); i++)
542 {
543 if (vDocIndexTable[i].sArticleId == _sID)
544 {
545 // Search the keywords corresponding to the
546 // position in the documentation index table
547 for (auto iter = mDocumentationIndex.begin(); iter != mDocumentationIndex.end(); ++iter)
548 {
549 if (iter->second == (int)i)
550 {
551 auto curiter = iter;
552 --iter;
553 mDocumentationIndex.erase(curiter);
554 }
555 else if (iter->second > (int)i)
556 {
557 // Reassign the correct postion in the
558 // table to the following entries
559 (iter->second)--;
560 }
561 }
562
563 remove(vDocIndexTable[i].sDocFilePath.c_str());
564 vDocIndexTable.erase(vDocIndexTable.begin()+i);
565 break;
566 }
567 }
568}
569
570
581std::vector<std::string> Documentation::getHelpArticle(const std::string& sTopic)
582{
583 std::vector<std::string> vReturn;
584
585 if (!vDocIndexTable.size())
587
588 // Return the documentation article or
589 // the whole index
590 if (sTopic != "idx" && sTopic != "index")
591 {
592 // Find the documentation article
593 int nIndex = findPositionInDocumentationIndex(sTopic);
594
595 if (nIndex != -1)
596 {
597 if (vDocIndexTable[nIndex].sDocFilePath.find("<>") != std::string::npos)
598 vDocIndexTable[nIndex].sDocFilePath = FileSystem::ValidFileName(vDocIndexTable[nIndex].sDocFilePath, ".nhlp");
599
600 return loadDocumentationArticle(vDocIndexTable[nIndex].sDocFilePath, vDocIndexTable[nIndex].sArticleId);
601 }
602 else
603 vReturn.push_back("NO_ENTRY_FOUND");
604 }
605 else
606 {
607 string sKeyList;
608 vReturn.push_back("Index");
609 std::map<std::string,std::string> mIdx;
610
611 for (size_t i = 0; i < vDocIndexTable.size(); i++)
612 {
614
615 for (const std::string& key : keylist)
616 {
617 mIdx[key] = vDocIndexTable[i].sTitle;
618 }
619 }
620
621 vReturn.push_back(_lang.get("DOCHELPER_KEYWORDS_AND_ARTICLES")+ ":");
622 vReturn.push_back("<list>");
623
624 for (auto iter = mIdx.begin(); iter != mIdx.end(); ++iter)
625 {
626 vReturn.push_back("<item node=\"" + iter->first + "\">" + iter->second + "</item>");
627 }
628
629 vReturn.push_back("</list>");
630 vReturn.push_back(_lang.get("DOCHELPER_KEYWORDS_AND_ARTICLES_NUMBERS", toString((int)vReturn.size()-4), toString((int)vDocIndexTable.size())));
631 }
632
633 return vReturn;
634}
635
636
646std::vector<std::string> Documentation::getDocIndex() const
647{
648 std::vector<std::string> vReturn;
649
650 // Go through the index table and extract the
651 // key list
652 for (size_t i = 0; i < vDocIndexTable.size(); i++)
653 {
654 std::string sKeyWords;
655
656 // Connect all keywords
657 for (const auto& iter : mDocumentationIndex)
658 {
659 if (iter.second == (int)i)
660 sKeyWords += " " + iter.first;
661 }
662
664
665 for (const std::string& key : keylist)
666 {
667 // Append the keywords to the key
668 if (std::find(vReturn.begin(), vReturn.end(), key+sKeyWords) == vReturn.end())
669 vReturn.push_back(key+sKeyWords);
670 }
671 }
672
673 std::sort(vReturn.begin(), vReturn.end());
674
675 return vReturn;
676}
677
678
687std::string Documentation::getHelpIdxKey(const std::string& sTopic)
688{
689 int nIndex = findPositionInDocumentationIndex(sTopic);
690 std::string sReturn = "";
691
692 if (nIndex == -1)
693 return "<<NONE>>";
694
695 sReturn = vDocIndexTable[nIndex].sIdxKeys;
696
697 if (sReturn.find(',') != std::string::npos)
698 sReturn.erase(sReturn.find(','));
699
700 return sReturn;
701}
702
703
712std::string Documentation::getHelpArticleID(const std::string& sTopic)
713{
714 int nIndex = findPositionInDocumentationIndex(sTopic);
715
716 if (nIndex != -1)
717 return vDocIndexTable[nIndex].sArticleId;
718
719 return "NO_ENTRY_FOUND";
720}
721
722
732std::string Documentation::getHelpArticleTitle(const std::string& _sIdxKey)
733{
734 int nIndex = findPositionInDocumentationIndex(_sIdxKey);
735
736 if (nIndex == -1)
737 return "<<NONE>>";
738
739 return vDocIndexTable[nIndex].sTitle;
740}
741
This class represents a whole documentation file with its contained documentation articles.
Definition: docfile.hpp:61
std::vector< DocumentationArticle > & getArticles()
Get all articles present in the current documentation file.
Definition: docfile.hpp:81
~Documentation()
The destructor closes the internal file stream, if it is still open.
Definition: doc_helper.cpp:235
void addFileToDocumentationIndex(const std::string &sFileName)
This member function is used to add documentation index entries to the index during a plugin or packa...
Definition: doc_helper.cpp:498
std::string getHelpArticleID(const std::string &sTopic)
This member function returns the article ID corresponding to the queried topic.
Definition: doc_helper.cpp:712
std::vector< DocumentationEntry > vDocIndexTable
Definition: doc_helper.hpp:42
std::string getHelpIdxKey(const std::string &sTopic)
This member function returns an index key, which corresponds to the queried topic.
Definition: doc_helper.cpp:687
void removeFromDocIndex(const std::string &_sID)
This member function removes the index entry passed to the function from the documentation index.
Definition: doc_helper.cpp:531
std::vector< std::string > getHelpArticle(const std::string &sTopic)
This member function returns the documentation article, which corresponds to the passed documentation...
Definition: doc_helper.cpp:581
void createDocumentationIndex(bool bLoadUserLangFiles=true)
This member function loads the index files to memory.
Definition: doc_helper.cpp:456
void addEntry(const DocumentationEntry &entry, const std::vector< std::string > &keyWords)
Add a new entry to the documentation index respecting already existing versions of the new entry....
Definition: doc_helper.cpp:251
std::vector< std::string > getDocIndex() const
This member function returns the key list for the documentation index prepared for the corresponding ...
Definition: doc_helper.cpp:646
int findPositionUsingIdxKeys(const std::string &sIdxKeys) const
Finds the best match of a documentation entry using a list of index keys. If multiple matches have be...
Definition: doc_helper.cpp:346
std::string getHelpArticleTitle(const std::string &_sIdxKey)
This member function returns the documentation article title corresponding to the queried index key.
Definition: doc_helper.cpp:732
Documentation()
The default constructor.
Definition: doc_helper.cpp:225
static std::string getArgAtPos(const std::string &sCmd, unsigned int pos)
This static member is a fallback for the XML-parsing logic-stuff.
Definition: doc_helper.cpp:382
std::map< std::string, int > mDocumentationIndex
Definition: doc_helper.hpp:41
int findPositionInDocumentationIndex(const std::string &sTopic) const
This private member function returns the position of the queried topic in the documentation index tab...
Definition: doc_helper.cpp:291
This class extends the std::vector for endlessness.
Definition: structures.hpp:838
This class implements the basic input/ output file system and provides functionalities to work with f...
Definition: filesystem.hpp:92
std::string ValidFolderName(std::string _sFileName, bool doCleanPath=true, bool appendTrailingSeparator=true) const
This member function evaluates, whether the passed foldername is a valid foldername.
Definition: filesystem.cpp:369
std::string ValidFileName(std::string _sFileName, const std::string sExtension=".dat", bool checkExtension=true, bool doCleanPath=true) const
This member function evaluates, whether the passed filename is a valid filename. One may supply a pre...
Definition: filesystem.cpp:280
std::string get(const std::string &sMessage, const std::vector< std::string > &vTokens) const
This member function returns the language string for the passed language identifier and replaces all ...
Definition: language.cpp:292
static NumeReKernel * getInstance()
This static member function returns a a pointer to the singleton instance of the kernel.
Definition: kernel.hpp:221
Settings & getSettings()
Definition: kernel.hpp:296
This class manages the setting values of the internal (kernel) settings of this application.
Definition: settings.hpp:663
Common exception class for all exceptions thrown in NumeRe.
Definition: error.hpp:32
@ INVALID_HLPIDX
Definition: error.hpp:128
@ HLP_FILE_MISSING
Definition: error.hpp:116
static size_t invalid_position
Definition: error.hpp:235
Language _lang
Definition: kernel.cpp:39
static void stripComments(std::string &sLine, std::ifstream &fDocument)
Strips comments from the documentation article file.
Definition: doc_helper.cpp:39
static std::vector< std::string > loadDocumentationArticle(const std::string &sFileName, const std::string &sArticleID)
This static function loads and prepares the selected documentation article.
Definition: doc_helper.cpp:122
static void findArticleById(std::string &sLine, const std::string &sArticleID, std::ifstream &fDocument)
Searches an article in a file by the selected ID.
Definition: doc_helper.cpp:79
unsigned int getMatchingParenthesis(const StringView &)
Returns the position of the closing parenthesis.
Definition: tools.cpp:414
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
This structure defines a single entry in the documentation index.
Definition: docfile.hpp:30
std::string sIdxKeys
Definition: docfile.hpp:34
std::string toString(int)
Converts an integer to a string without the Settings bloat.
vector< string > getFileList(const string &sDirectory, const Settings &_option, int nFlags)
This function returns a list of files (including their paths, if nFlags & 1).
Definition: tools.cpp:2853
string getArgAtPos(const string &sCmd, unsigned int nPos, int extraction)
Extracts a options value at the selected position and applies automatic parsing, if necessary.
Definition: tools.cpp:1598
EndlessVector< StringView > getAllArguments(StringView sArgList)
Splits up the complete argument list and returns them as an EndlessVector.
Definition: tools.cpp:2346