WebFramework v3.0.12
Web framework for C++.
Loading...
Searching...
No Matches
WebFrameworkDynamicPages.cpp
1#include "WebFrameworkDynamicPages.h"
2
3#include "Strings.h"
4#include "Log.h"
5
6#include "Exceptions/DynamicPagesSyntaxException.h"
7#include "StandardWebFrameworkDynamicPagesFunctions.h"
8
9#pragma warning(disable: 26800)
10
11using namespace std;
12
13static constexpr string_view argumentsDelimiter = "</arg>";
14
15namespace framework
16{
17 WebFrameworkDynamicPages::ExecutionUnit::ExecutionUnit(string&& functionName, vector<string>&& arguments) noexcept :
18 functionName(move(functionName)),
19 arguments(move(arguments))
20 {
21
22 }
23
24 void WebFrameworkDynamicPages::clear(string& code)
25 {
26 code.erase(remove_if(code.begin(), code.end(), [](const char& c) { return iscntrl(c) || isspace(c); }), code.end());
27 }
28
29 void WebFrameworkDynamicPages::separateArguments(string& code)
30 {
31 bool stringArgument = false;
32
33 for (size_t i = 0; i < code.size(); i++)
34 {
35 switch (code[i])
36 {
37 case '"':
38 stringArgument = !stringArgument;
39
40 break;
41
42 case ',':
43 if (stringArgument)
44 {
45 continue;
46 }
47
48 code.replace(i, 1, argumentsDelimiter);
49
50 break;
51
52 default:
53 break;
54 }
55 }
56 }
57
58 string WebFrameworkDynamicPages::insertVariables(const unordered_map<string, string>& variables, string code)
59 {
60 size_t changeVariableStart = code.find('$');
61
62 while (changeVariableStart != string::npos)
63 {
64 changeVariableStart++;
65
66 size_t changeVariableEnd = code.find('$', changeVariableStart);
67
68 if (changeVariableEnd == string::npos)
69 {
70 throw exceptions::DynamicPagesSyntaxException(::exceptions::variableDeclarationSyntaxError);
71 }
72
73 const string& variable = variables.at(string(code.data() + changeVariableStart, changeVariableEnd - changeVariableStart));
74
75 code.replace(code.begin() + changeVariableStart - 1, code.begin() + changeVariableEnd + 1, variable);
76
77 changeVariableStart = code.find('$');
78 }
79
80 return code;
81 }
82
83 vector<WebFrameworkDynamicPages::ExecutionUnit> WebFrameworkDynamicPages::preExecute(const string& code)
84 {
85 vector<ExecutionUnit> result;
86 size_t startLine = 0;
87 size_t endLine = code.find(';');
88
89 if (endLine == string::npos)
90 {
91 throw exceptions::DynamicPagesSyntaxException(::exceptions::missingSemicolonSyntaxError);
92 }
93
94 result.reserve(count(code.begin(), code.end(), ';'));
95
96 while (endLine != string::npos)
97 {
98 endLine++;
99
100 string_view line(code.data() + startLine, endLine - startLine);
101 size_t openBracket = line.find('(');
102 string functionName(line.substr(0, openBracket));
103
104 result.emplace_back
105 (
106 move(functionName),
107 utility::strings::split(string_view(line.data() + openBracket + 1, line.find(')') - openBracket - 1), argumentsDelimiter)
108 );
109
110 startLine = endLine;
111 endLine = code.find(';', endLine + 1);
112 }
113
114 return result;
115 }
116
117 string WebFrameworkDynamicPages::execute(const vector<ExecutionUnit>& codes)
118 {
119 string result;
120
121 for (const auto& [functionName, arguments] : codes)
122 {
123 try
124 {
125 result += dynamicPagesFunctions.at(functionName)(arguments);
126 }
127 catch (const exception& e)
128 {
129 if (Log::isValid())
130 {
131 Log::error("WebFrameworkDynamicPages execute exception: {}", "LogWebFrameworkDynamicPages", e.what());
132 }
133
134 throw;
135 }
136 }
137
138 return result;
139 }
140
141 WebFrameworkDynamicPages::WebFrameworkDynamicPages(const filesystem::path& pathToTemplates) :
142 pathToTemplates(pathToTemplates)
143 {
144 dynamicPagesFunctions.try_emplace("print", print);
145 dynamicPagesFunctions.try_emplace("include", bind(include, placeholders::_1, pathToTemplates.string()));
146 dynamicPagesFunctions.try_emplace("for", bind(forWFDP, placeholders::_1, ref(dynamicPagesFunctions)));
147 }
148
149 void WebFrameworkDynamicPages::run(const unordered_map<string, string>& variables, string& source)
150 {
151 size_t nextSectionStart = source.find("{%");
152
153 while (nextSectionStart != string::npos)
154 {
155 size_t nextSectionEnd = source.find("%}", nextSectionStart);
156
157 if (nextSectionEnd == string::npos)
158 {
159 throw exceptions::DynamicPagesSyntaxException(::exceptions::sectionDeclarationSyntaxError);
160 }
161
162 string code(source.begin() + nextSectionStart + 2, source.begin() + nextSectionEnd);
163
164 WebFrameworkDynamicPages::clear(code);
165
166 WebFrameworkDynamicPages::separateArguments(code);
167
168 if (variables.size())
169 {
170 code = WebFrameworkDynamicPages::insertVariables(variables, code);
171 }
172
173 source.replace(source.begin() + nextSectionStart, source.begin() + nextSectionEnd + 2, this->execute(WebFrameworkDynamicPages::preExecute(code)));
174
175 nextSectionStart = source.find("{%", nextSectionStart + 1);
176 }
177
178 if (source.find("{%") != string::npos)
179 {
180 this->run(variables, source);
181 }
182 }
183
184 void WebFrameworkDynamicPages::registerDynamicFunction(const string& functionName, function<string(const vector<string>&)>&& function)
185 {
186 dynamicPagesFunctions.try_emplace(functionName, move(function));
187 }
188
189 void WebFrameworkDynamicPages::unregisterDynamicFunction(const string& functionName)
190 {
191 dynamicPagesFunctions.erase(functionName);
192 }
193
194 bool WebFrameworkDynamicPages::isDynamicFunctionRegistered(const string& functionName)
195 {
196 return dynamicPagesFunctions.find(functionName) != dynamicPagesFunctions.end();
197 }
198
199 const filesystem::path& WebFrameworkDynamicPages::getPathToTemplates() const
200 {
201 return pathToTemplates;
202 }
203}