|
ferencd@0
|
1 #include "templater.h"
|
|
ferencd@0
|
2 #include "dictionary.h"
|
|
ferencd@0
|
3
|
|
ferencd@0
|
4 #ifdef PYTHON_SCRIPTING
|
|
ferencd@0
|
5 #include "python_runner.h"
|
|
ferencd@0
|
6 #endif
|
|
ferencd@0
|
7
|
|
ferencd@0
|
8 #include <algorithm>
|
|
ferencd@0
|
9 #include <filesystem>
|
|
ferencd@0
|
10
|
|
ferencd@0
|
11 #include <log.h>
|
|
ferencd@0
|
12 #include <cwctype>
|
|
ferencd@0
|
13
|
|
ferencd@0
|
14
|
|
ferencd@0
|
15 void templater_base::resolve_all_includes(std::string& templatized, bool do_replace)
|
|
ferencd@0
|
16 {
|
|
ferencd@0
|
17 size_t inc_pos = templatized.find(INCLUDE_TAG);
|
|
ferencd@0
|
18 while(inc_pos != std::string::npos)
|
|
ferencd@0
|
19 {
|
|
ferencd@0
|
20 templatized = resolve_includes(templatized, inc_pos, do_replace);
|
|
ferencd@0
|
21
|
|
ferencd@0
|
22 // see if we have pulled in some extra vars
|
|
ferencd@0
|
23 if(do_replace)
|
|
ferencd@0
|
24 {
|
|
ferencd@0
|
25 templatized = stringholder(templatized).templatize(kps).get();
|
|
ferencd@0
|
26 }
|
|
ferencd@0
|
27
|
|
ferencd@0
|
28 inc_pos = templatized.find(INCLUDE_TAG);
|
|
ferencd@0
|
29 }
|
|
ferencd@0
|
30 }
|
|
ferencd@0
|
31
|
|
ferencd@0
|
32 std::string templater_base::get(const std::string &template_name)
|
|
ferencd@0
|
33 {
|
|
ferencd@0
|
34 // Getting the content
|
|
ferencd@0
|
35 std::string content = template_warehouse::instance().getTemplateContent(template_name);
|
|
ferencd@0
|
36
|
|
ferencd@0
|
37 // Resolve the #define's. This will update the extra_kp's
|
|
ferencd@0
|
38 std::string content_without_vars = resolve_defines(content);
|
|
ferencd@0
|
39
|
|
ferencd@0
|
40 // resolve the initializer scripts, since they may modify the kps
|
|
ferencd@0
|
41 std::string scripts_resolved = resolve_scripts(content_without_vars, INIT_SCRIPT_TAG);
|
|
ferencd@0
|
42
|
|
ferencd@0
|
43 // resolve all the top level template arguments
|
|
ferencd@0
|
44 std::string templatized = stringholder(scripts_resolved).templatize(kps).get();
|
|
ferencd@0
|
45
|
|
ferencd@0
|
46 // then search for all the {#include 's and: templatize those with the given variable: Value pairs
|
|
ferencd@0
|
47 // and include them here
|
|
ferencd@0
|
48 bool done = false;
|
|
ferencd@0
|
49 while(!done)
|
|
ferencd@0
|
50 {
|
|
ferencd@0
|
51 // search for structure definitions, there can be more than one
|
|
ferencd@0
|
52 size_t struct_pos = templatized.find(STRUCT_TAG);
|
|
ferencd@0
|
53 while(struct_pos != std::string::npos)
|
|
ferencd@0
|
54 {
|
|
ferencd@0
|
55 templatized = resolve_structure_declaration(struct_pos, templatized);
|
|
ferencd@0
|
56 struct_pos = templatized.find(STRUCT_TAG);
|
|
ferencd@0
|
57 }
|
|
ferencd@0
|
58
|
|
ferencd@0
|
59 // search for input data definition hints
|
|
ferencd@0
|
60 size_t parameters_pos = templatized.find(PARAMETERS_TAG);
|
|
ferencd@0
|
61 if(parameters_pos != std::string::npos)
|
|
ferencd@0
|
62 {
|
|
ferencd@0
|
63 templatized = resolve_parameters(parameters_pos, templatized);
|
|
ferencd@0
|
64 }
|
|
ferencd@0
|
65
|
|
ferencd@0
|
66 // search for the "include"'s
|
|
ferencd@0
|
67 resolve_all_includes(templatized);
|
|
ferencd@0
|
68
|
|
ferencd@0
|
69 // now search for the "if"'s. Remember, ifs cannot have ifs in their body
|
|
ferencd@0
|
70 size_t if_pos = templatized.find(IF_TAG);
|
|
ferencd@0
|
71 if(if_pos != std::string::npos)
|
|
ferencd@0
|
72 {
|
|
ferencd@0
|
73 while(if_pos != std::string::npos)
|
|
ferencd@0
|
74 {
|
|
ferencd@0
|
75 templatized = resolve_ifs(if_pos, templatized);
|
|
ferencd@0
|
76 if_pos = templatized.find(IF_TAG);
|
|
ferencd@0
|
77 }
|
|
ferencd@0
|
78 }
|
|
ferencd@0
|
79 else
|
|
ferencd@0
|
80 {
|
|
ferencd@0
|
81 done = true;
|
|
ferencd@0
|
82 }
|
|
ferencd@0
|
83 }
|
|
ferencd@0
|
84
|
|
ferencd@0
|
85 return templatized;
|
|
ferencd@0
|
86 }
|
|
ferencd@0
|
87
|
|
ferencd@0
|
88 std::string templater_base::extract_identifier_word(const std::string& input, size_t& i, std::vector<char> separators,
|
|
ferencd@0
|
89 std::set<char> extra_allowed_chars, char&& c)
|
|
ferencd@0
|
90 {
|
|
ferencd@0
|
91 skip_whitespace(input, i);
|
|
ferencd@0
|
92
|
|
ferencd@0
|
93 std::string result = "";
|
|
ferencd@0
|
94 while(i < input.length() && (input.at(i) == '_' ||
|
|
ferencd@0
|
95 extra_allowed_chars.count(input.at(i)) ||
|
|
ferencd@0
|
96 isalnum(input.at(i))) )
|
|
ferencd@0
|
97 {
|
|
ferencd@0
|
98 if(separators.empty())
|
|
ferencd@0
|
99 {
|
|
ferencd@0
|
100 result += input.at(i);
|
|
ferencd@0
|
101 i++;
|
|
ferencd@0
|
102 }
|
|
ferencd@0
|
103 else
|
|
ferencd@0
|
104 {
|
|
ferencd@0
|
105 if(find(separators.begin(), separators.end(), input.at(i)) == separators.end())
|
|
ferencd@0
|
106 {
|
|
ferencd@0
|
107 result += input.at(i);
|
|
ferencd@0
|
108 i++;
|
|
ferencd@0
|
109 }
|
|
ferencd@0
|
110 else
|
|
ferencd@0
|
111 {
|
|
ferencd@0
|
112 if(c != 0)
|
|
ferencd@0
|
113 {
|
|
ferencd@0
|
114 c = input[i];
|
|
ferencd@0
|
115 }
|
|
ferencd@0
|
116 i ++; // skip the actual separator
|
|
ferencd@0
|
117 break;
|
|
ferencd@0
|
118 }
|
|
ferencd@0
|
119 }
|
|
ferencd@0
|
120 }
|
|
ferencd@0
|
121
|
|
ferencd@0
|
122 skip_whitespace(input, i);
|
|
ferencd@0
|
123 if(!separators.empty())
|
|
ferencd@0
|
124 {
|
|
ferencd@0
|
125 if(find(separators.begin(), separators.end(), input.at(i)) != separators.end())
|
|
ferencd@0
|
126 {
|
|
ferencd@0
|
127 if(c != 0)
|
|
ferencd@0
|
128 {
|
|
ferencd@0
|
129 c = input[i];
|
|
ferencd@0
|
130 }
|
|
ferencd@0
|
131 i++; // this characater is a separator. Skip it. And the space after
|
|
ferencd@0
|
132 skip_whitespace(input, i);
|
|
ferencd@0
|
133 }
|
|
ferencd@0
|
134 }
|
|
ferencd@0
|
135
|
|
ferencd@0
|
136 return result;
|
|
ferencd@0
|
137 }
|
|
ferencd@0
|
138
|
|
ferencd@0
|
139 bool templater_base::check_opening_parenthesis(const std::string& input, size_t& i)
|
|
ferencd@0
|
140 {
|
|
ferencd@0
|
141 bool opening_parentheses = false;
|
|
ferencd@0
|
142 // skip the parenthesis if any
|
|
ferencd@0
|
143 if(i < input.length() && input.at(i) == '(')
|
|
ferencd@0
|
144 {
|
|
ferencd@0
|
145 i ++;
|
|
ferencd@0
|
146 skip_whitespace(input, i);
|
|
ferencd@0
|
147 opening_parentheses = true;
|
|
ferencd@0
|
148 }
|
|
ferencd@0
|
149
|
|
ferencd@0
|
150 return opening_parentheses;
|
|
ferencd@0
|
151 }
|
|
ferencd@0
|
152
|
|
ferencd@0
|
153 bool templater_base::check_closing_comment(const std::string& templatized, size_t& i, std::size_t& include_tag_end_position)
|
|
ferencd@0
|
154 {
|
|
ferencd@0
|
155 if(i + 3 < templatized.length())
|
|
ferencd@0
|
156 {
|
|
ferencd@0
|
157 if(templatized[i+1] == '-' && templatized[i+2] == '-' && templatized[i + 3] == '>')
|
|
ferencd@0
|
158 {
|
|
ferencd@0
|
159 include_tag_end_position = i + 4;
|
|
ferencd@0
|
160 return true;
|
|
ferencd@0
|
161 }
|
|
ferencd@0
|
162 }
|
|
ferencd@0
|
163 return false;
|
|
ferencd@0
|
164 }
|
|
ferencd@0
|
165
|
|
ferencd@0
|
166 std::string templater_base::get_error() const
|
|
ferencd@0
|
167 {
|
|
ferencd@0
|
168 return error;
|
|
ferencd@0
|
169 }
|
|
ferencd@0
|
170
|
|
ferencd@0
|
171 std::vector<std::string> templater_base::variables(bool resolve_includes_too)
|
|
ferencd@0
|
172 {
|
|
ferencd@0
|
173 std::vector<std::string> result;
|
|
ferencd@0
|
174
|
|
ferencd@0
|
175 std::string content = template_warehouse::instance().getTemplateContent(name());
|
|
ferencd@0
|
176 std::string::size_type start_pos = 0;
|
|
ferencd@0
|
177
|
|
ferencd@0
|
178 if(resolve_includes_too)
|
|
ferencd@0
|
179 {
|
|
ferencd@0
|
180 resolve_all_includes(content, false);
|
|
ferencd@0
|
181 }
|
|
ferencd@0
|
182
|
|
ferencd@0
|
183 while((start_pos = content.find(TEMPLATE_VARIABLE_START_DELIMITER, start_pos)) != std::string::npos)
|
|
ferencd@0
|
184 {
|
|
ferencd@0
|
185 std::string current_varname = "";
|
|
ferencd@0
|
186 start_pos += TEMPLATE_VARIABLE_START_DELIMITER.length();
|
|
ferencd@0
|
187 while(start_pos < content.length() && content[start_pos] != '}')
|
|
ferencd@0
|
188 {
|
|
ferencd@0
|
189 current_varname += content[start_pos++];
|
|
ferencd@0
|
190 }
|
|
ferencd@0
|
191 if(start_pos == content.length())
|
|
ferencd@0
|
192 {
|
|
ferencd@0
|
193 set_error("Unterminated variable name");
|
|
ferencd@0
|
194 return result;
|
|
ferencd@0
|
195 }
|
|
ferencd@0
|
196 result.push_back(current_varname);
|
|
ferencd@0
|
197 start_pos ++; // to skip the closing '}'
|
|
ferencd@0
|
198 }
|
|
ferencd@0
|
199
|
|
ferencd@0
|
200 return result;
|
|
ferencd@0
|
201 }
|
|
ferencd@0
|
202
|
|
ferencd@0
|
203 std::string templater_base::resolve_includes(std::string templatized, size_t inc_pos, bool do_variable_replacement)
|
|
ferencd@0
|
204 {
|
|
ferencd@0
|
205 std::map<std::string, std::string> local_pairs;
|
|
ferencd@0
|
206 std::size_t include_tag_end_position = std::string::npos;
|
|
ferencd@0
|
207 std::size_t include_tag_start_position = inc_pos;
|
|
ferencd@0
|
208
|
|
ferencd@0
|
209 inc_pos += INCLUDE_TAG.length();
|
|
ferencd@0
|
210
|
|
ferencd@0
|
211 std::string inc_template = extract_identifier_word(templatized, inc_pos);
|
|
ferencd@0
|
212 bool opening_parentheses = check_opening_parenthesis(templatized, inc_pos);
|
|
ferencd@0
|
213 size_t i = inc_pos;
|
|
ferencd@0
|
214 bool closing_comment_found = false;
|
|
ferencd@0
|
215
|
|
ferencd@0
|
216 while(i < templatized.length() && ! closing_comment_found)
|
|
ferencd@0
|
217 {
|
|
ferencd@0
|
218 std::string var_name = extract_identifier_word(templatized, i, {':','='});
|
|
ferencd@0
|
219 if(i == templatized.length() || var_name.empty())
|
|
ferencd@0
|
220 {
|
|
ferencd@0
|
221 if(templatized[i] == '#' && !closing_comment_found) // This should be the closing comment
|
|
ferencd@0
|
222 {
|
|
ferencd@0
|
223 check_closing_comment(templatized, i, include_tag_end_position);
|
|
ferencd@0
|
224 }
|
|
ferencd@0
|
225
|
|
ferencd@0
|
226 break;
|
|
ferencd@0
|
227 }
|
|
ferencd@0
|
228
|
|
ferencd@0
|
229 // now read the variable value
|
|
ferencd@0
|
230 std::string var_value = "";
|
|
ferencd@0
|
231 bool var_value_read = false;
|
|
ferencd@0
|
232 while(!var_value_read && i < templatized.length())
|
|
ferencd@0
|
233 {
|
|
ferencd@0
|
234 if(templatized[i] == '"') // string starts. Do not read the '"'
|
|
ferencd@0
|
235 {
|
|
ferencd@0
|
236 i++; // skip the '"'
|
|
ferencd@0
|
237
|
|
ferencd@0
|
238 bool string_read = false;
|
|
ferencd@0
|
239 while(i < templatized.length() && !string_read)
|
|
ferencd@0
|
240 {
|
|
ferencd@0
|
241 if(templatized[i] == '\\') // Skip the backslash from the escape sequence
|
|
ferencd@0
|
242 {
|
|
ferencd@0
|
243 i++;
|
|
ferencd@0
|
244 }
|
|
ferencd@0
|
245
|
|
ferencd@0
|
246 var_value += templatized[i++];
|
|
ferencd@0
|
247
|
|
ferencd@0
|
248 if(i == templatized.length())
|
|
ferencd@0
|
249 {
|
|
ferencd@0
|
250 set_error("String literal is not finished");
|
|
ferencd@0
|
251 break;
|
|
ferencd@0
|
252 }
|
|
ferencd@0
|
253
|
|
ferencd@0
|
254 if(templatized[i] == '"' && templatized[i-1] != '\\')
|
|
ferencd@0
|
255 {
|
|
ferencd@0
|
256 string_read = true;
|
|
ferencd@0
|
257 }
|
|
ferencd@0
|
258 }
|
|
ferencd@0
|
259
|
|
ferencd@0
|
260 if(i == templatized.length()) // invalid syntax
|
|
ferencd@0
|
261 {
|
|
ferencd@0
|
262 set_error("Invalid syntax, could not resolve an include");
|
|
ferencd@0
|
263 break;
|
|
ferencd@0
|
264 }
|
|
ferencd@0
|
265
|
|
ferencd@0
|
266 i++; // skip closing quote
|
|
ferencd@0
|
267 }
|
|
ferencd@0
|
268 else
|
|
ferencd@0
|
269 {
|
|
ferencd@0
|
270 // see if this is a closing parenthesis, but only if there was an opening one
|
|
ferencd@0
|
271 if(opening_parentheses && templatized[i] == ')')
|
|
ferencd@0
|
272 {
|
|
ferencd@0
|
273 var_value_read = true;
|
|
ferencd@0
|
274
|
|
ferencd@0
|
275 // now see if there is a closing comment. Everything after it will be ignored
|
|
ferencd@0
|
276 while(i < templatized.length() && !closing_comment_found)
|
|
ferencd@0
|
277 {
|
|
ferencd@0
|
278 i ++;
|
|
ferencd@0
|
279 skip_whitespace(templatized, i);
|
|
ferencd@0
|
280 if(i < templatized.length() && templatized[i] == '#') // This should be the closing comment
|
|
ferencd@0
|
281 {
|
|
ferencd@0
|
282 closing_comment_found = check_closing_comment(templatized, i, include_tag_end_position);
|
|
ferencd@0
|
283 }
|
|
ferencd@0
|
284 }
|
|
ferencd@0
|
285 }
|
|
ferencd@0
|
286
|
|
ferencd@0
|
287 if(templatized[i] == '#' && !closing_comment_found) // This should be the closing comment
|
|
ferencd@0
|
288 {
|
|
ferencd@0
|
289 closing_comment_found = var_value_read = check_closing_comment(templatized, i, include_tag_end_position);
|
|
ferencd@0
|
290 }
|
|
ferencd@0
|
291
|
|
ferencd@0
|
292 if(templatized[i] == '{' && i<templatized.length() && templatized[i + 1] == '#') // The substitution of a variable with another one from this level
|
|
ferencd@0
|
293 {
|
|
ferencd@0
|
294 // Read in the entire variable and simply change the var_value to the one in our objects' map
|
|
ferencd@0
|
295 i+=2; // skip {#
|
|
ferencd@0
|
296 std::string upperlevel_var_name = extract_identifier_word(templatized, i, {'}'});
|
|
ferencd@0
|
297
|
|
ferencd@0
|
298 if(i == templatized.length() || upperlevel_var_name.empty())
|
|
ferencd@0
|
299 {
|
|
ferencd@0
|
300 break;
|
|
ferencd@0
|
301 }
|
|
ferencd@0
|
302
|
|
ferencd@0
|
303 if(kps.count(upperlevel_var_name) != 0)
|
|
ferencd@0
|
304 {
|
|
ferencd@0
|
305 var_value += kps[upperlevel_var_name];
|
|
ferencd@0
|
306 }
|
|
ferencd@0
|
307 }
|
|
ferencd@0
|
308
|
|
ferencd@0
|
309 // and comma (or space) separatin the variables?
|
|
ferencd@0
|
310 if(i < templatized.length() && (templatized[i] == ',' || iswspace(templatized[i])) )
|
|
ferencd@0
|
311 {
|
|
ferencd@0
|
312 var_value_read = true;
|
|
ferencd@0
|
313 i++;
|
|
ferencd@0
|
314 skip_whitespace(templatized, i);
|
|
ferencd@0
|
315 }
|
|
ferencd@0
|
316
|
|
ferencd@0
|
317 // still not read the value?
|
|
ferencd@0
|
318 if(i < templatized.length() && !var_value_read)
|
|
ferencd@0
|
319 {
|
|
ferencd@0
|
320 var_value += templatized[i++];
|
|
ferencd@0
|
321 }
|
|
ferencd@0
|
322 }
|
|
ferencd@0
|
323 }
|
|
ferencd@0
|
324
|
|
ferencd@0
|
325 skip_whitespace(templatized, i);
|
|
ferencd@0
|
326
|
|
ferencd@0
|
327 // now insert into local_pairs the keys and values
|
|
ferencd@0
|
328 local_pairs.insert(make_pair(var_name, var_value));
|
|
ferencd@0
|
329 }
|
|
ferencd@0
|
330
|
|
ferencd@0
|
331 // and now read in the template from inc_template
|
|
ferencd@0
|
332 // and replace everything that is supposed to be replaced
|
|
ferencd@0
|
333 std::string inc_content = template_warehouse::instance().getTemplateContent( inc_template );
|
|
ferencd@0
|
334 std::string inc_templatized = do_variable_replacement ? stringholder(inc_content).templatize(local_pairs).get() : inc_content;
|
|
ferencd@0
|
335
|
|
ferencd@0
|
336 templatized.erase(include_tag_start_position, include_tag_end_position - include_tag_start_position);
|
|
ferencd@0
|
337 templatized.insert(include_tag_start_position, inc_templatized);
|
|
ferencd@0
|
338 return templatized;
|
|
ferencd@0
|
339 }
|
|
ferencd@0
|
340
|
|
ferencd@0
|
341 std::string templater_base::resolve_structure_declaration(size_t struct_pos, std::string templatized)
|
|
ferencd@0
|
342 {
|
|
ferencd@0
|
343 std::size_t include_tag_start_position = struct_pos;
|
|
ferencd@0
|
344
|
|
ferencd@0
|
345 struct_pos += STRUCT_TAG.length();
|
|
ferencd@0
|
346
|
|
ferencd@0
|
347 std::string struct_name = extract_identifier_word(templatized, struct_pos);
|
|
ferencd@0
|
348 bool opening_parentheses = check_opening_parenthesis(templatized, struct_pos);
|
|
ferencd@0
|
349
|
|
ferencd@0
|
350 add_structure_decl(struct_name, struct_name);
|
|
ferencd@0
|
351
|
|
ferencd@0
|
352 // and now read in the structure members' names
|
|
ferencd@0
|
353 size_t i = struct_pos;
|
|
ferencd@0
|
354 bool closing_comment_found = false;
|
|
ferencd@0
|
355 std::size_t include_tag_end_position = std::string::npos;
|
|
ferencd@0
|
356
|
|
ferencd@0
|
357 while (i < templatized.length() && !closing_comment_found)
|
|
ferencd@0
|
358 {
|
|
ferencd@0
|
359 std::string member_name = "";
|
|
ferencd@0
|
360 while(i < templatized.length() && (isalnum(templatized[i]) || templatized[i] == '_'))
|
|
ferencd@0
|
361 {
|
|
ferencd@0
|
362 member_name += templatized[i++];
|
|
ferencd@0
|
363 }
|
|
ferencd@0
|
364 if(member_name.empty()) // syntax error, just give back what came out
|
|
ferencd@0
|
365 {
|
|
ferencd@0
|
366 set_error("Invalid syntax, could not resolve a structure declaration");
|
|
ferencd@0
|
367 return templatized;
|
|
ferencd@0
|
368 }
|
|
ferencd@0
|
369
|
|
ferencd@0
|
370 skip_whitespace(templatized, i);
|
|
ferencd@0
|
371
|
|
ferencd@0
|
372 // var_name now is the name of the structure's member, make it
|
|
ferencd@0
|
373 // a default value
|
|
ferencd@0
|
374 get_structure(struct_name)[member_name] = "";
|
|
ferencd@0
|
375
|
|
ferencd@0
|
376 // now this should point either to a space or a ","
|
|
ferencd@0
|
377 i++;
|
|
ferencd@0
|
378
|
|
ferencd@0
|
379 // se if we have a "," coming up
|
|
ferencd@0
|
380 if(templatized[i] == ',')
|
|
ferencd@0
|
381 {
|
|
ferencd@0
|
382 i ++;
|
|
ferencd@0
|
383 skip_whitespace(templatized, i);
|
|
ferencd@0
|
384 }
|
|
ferencd@0
|
385
|
|
ferencd@0
|
386 // see if this is a closing parenthesis, but only if there was an opening one
|
|
ferencd@0
|
387 if(opening_parentheses && templatized[i] == ')')
|
|
ferencd@0
|
388 {
|
|
ferencd@0
|
389
|
|
ferencd@0
|
390 // now see if there is a closing comment. Everything after it will be ignored
|
|
ferencd@0
|
391 while(i < templatized.length() && !closing_comment_found)
|
|
ferencd@0
|
392 {
|
|
ferencd@0
|
393 i ++;
|
|
ferencd@0
|
394 skip_whitespace(templatized, i);
|
|
ferencd@0
|
395 if(i < templatized.length() && templatized[i] == '#') // This should be the closing comment
|
|
ferencd@0
|
396 {
|
|
ferencd@0
|
397 closing_comment_found = check_closing_comment(templatized, i, include_tag_end_position);
|
|
ferencd@0
|
398 }
|
|
ferencd@0
|
399 }
|
|
ferencd@0
|
400 }
|
|
ferencd@0
|
401
|
|
ferencd@0
|
402 if(templatized[i] == '#' && !closing_comment_found) // This should be the closing comment
|
|
ferencd@0
|
403 {
|
|
ferencd@0
|
404 closing_comment_found = check_closing_comment(templatized, i, include_tag_end_position);
|
|
ferencd@0
|
405 }
|
|
ferencd@0
|
406 }
|
|
ferencd@0
|
407
|
|
ferencd@0
|
408 templatized.erase(include_tag_start_position, include_tag_end_position - include_tag_start_position);
|
|
ferencd@0
|
409 return templatized;
|
|
ferencd@0
|
410 }
|
|
ferencd@0
|
411
|
|
ferencd@0
|
412 templater_base &templater_base::templatize(const template_struct &s)
|
|
ferencd@0
|
413 {
|
|
ferencd@0
|
414 precalculated = "";
|
|
ferencd@0
|
415 std::string templatized = get(); // will initialize the parameters
|
|
ferencd@0
|
416 if(!m_parameters.empty())
|
|
ferencd@0
|
417 {
|
|
ferencd@0
|
418 for(const auto &p : m_parameters)
|
|
ferencd@0
|
419 {
|
|
ferencd@0
|
420 if(p.first == s.name)
|
|
ferencd@0
|
421 {
|
|
ferencd@0
|
422 for(const auto &x : s.struct_members)
|
|
ferencd@0
|
423 {
|
|
ferencd@0
|
424 std::string fullname = s.name + "." + x.first;
|
|
ferencd@0
|
425 kps.insert(make_pair(fullname, unafrog::utils::to_string(x.second)));
|
|
ferencd@0
|
426 }
|
|
ferencd@0
|
427 }
|
|
ferencd@0
|
428 }
|
|
ferencd@0
|
429 }
|
|
ferencd@0
|
430 templatized = stringholder(templatized).templatize(kps).get();
|
|
ferencd@0
|
431 templatized = resolve_ifeqs(templatized);
|
|
ferencd@0
|
432 templatized = resolve_scripts(templatized, SCRIPT_TAG);
|
|
ferencd@0
|
433 precalculated = templatized;
|
|
ferencd@0
|
434
|
|
ferencd@0
|
435 return *this;
|
|
ferencd@0
|
436 }
|
|
ferencd@0
|
437
|
|
ferencd@0
|
438 std::string templater_base::resolve_loops(std::string templatized, const template_vector_par &v)
|
|
ferencd@0
|
439 {
|
|
ferencd@0
|
440 size_t loop_pos = templatized.find(LOOP_TAG);
|
|
ferencd@0
|
441 while(loop_pos != std::string::npos)
|
|
ferencd@0
|
442 {
|
|
ferencd@0
|
443 // find the stuff between the iterate and end iterate tags
|
|
ferencd@0
|
444 std::size_t loop_tag_end_position = std::string::npos;
|
|
ferencd@0
|
445 std::size_t loop_tag_start_position = loop_pos;
|
|
ferencd@0
|
446
|
|
ferencd@0
|
447 loop_pos += LOOP_TAG.length();
|
|
ferencd@0
|
448
|
|
ferencd@0
|
449 // see on what are we iterating through
|
|
ferencd@0
|
450 std::string loop_target = extract_identifier_word(templatized, loop_pos);
|
|
ferencd@0
|
451
|
|
ferencd@0
|
452 // there should be nothing more after this
|
|
ferencd@0
|
453 if(!check_closing_comment(templatized, loop_pos, loop_tag_end_position))
|
|
ferencd@0
|
454 {
|
|
ferencd@0
|
455 return templatized;
|
|
ferencd@0
|
456 }
|
|
ferencd@0
|
457
|
|
ferencd@0
|
458 // now find the end iterate tag
|
|
ferencd@0
|
459 size_t end_loop_pos = templatized.find(ENDLOOP_TAG, loop_tag_end_position);
|
|
ferencd@0
|
460 size_t save_endpos = end_loop_pos;
|
|
ferencd@0
|
461 end_loop_pos += ENDLOOP_TAG.length();
|
|
ferencd@0
|
462 size_t endloop_endpos = std::string::npos;
|
|
ferencd@0
|
463
|
|
ferencd@0
|
464 size_t temp = end_loop_pos;
|
|
ferencd@0
|
465
|
|
ferencd@0
|
466 while(temp != std::string::npos)
|
|
ferencd@0
|
467 {
|
|
ferencd@0
|
468 size_t unused = temp;
|
|
ferencd@0
|
469
|
|
ferencd@0
|
470 std::string endloop_target = extract_identifier_word(templatized, unused);
|
|
ferencd@0
|
471 if(endloop_target == loop_target)
|
|
ferencd@0
|
472 {
|
|
ferencd@0
|
473 if(!check_closing_comment(templatized, unused, endloop_endpos))
|
|
ferencd@0
|
474 {
|
|
ferencd@0
|
475 return templatized;
|
|
ferencd@0
|
476 }
|
|
ferencd@0
|
477
|
|
ferencd@0
|
478 break;
|
|
ferencd@0
|
479 }
|
|
ferencd@0
|
480
|
|
ferencd@0
|
481 temp = templatized.find(ENDLOOP_TAG, temp);
|
|
ferencd@0
|
482 save_endpos = temp;
|
|
ferencd@0
|
483 temp += ENDLOOP_TAG.length();
|
|
ferencd@0
|
484 }
|
|
ferencd@0
|
485
|
|
ferencd@0
|
486 // now between loop_tag_end_position and save_endpos there is the strign we need
|
|
ferencd@0
|
487 std::string loop_content = templatized.substr(loop_tag_end_position, save_endpos - loop_tag_end_position);
|
|
ferencd@0
|
488
|
|
ferencd@0
|
489 std::string final_loop_content = "";
|
|
ferencd@0
|
490
|
|
ferencd@0
|
491 // and now insert a bunch of kps for the elements in v
|
|
ferencd@0
|
492 if(!m_parameters.empty())
|
|
ferencd@0
|
493 {
|
|
ferencd@0
|
494 size_t c = 0;
|
|
ferencd@0
|
495 for(const auto &ts : v.value())
|
|
ferencd@0
|
496 {
|
|
ferencd@0
|
497 c++;
|
|
ferencd@0
|
498 for(const auto& p : m_parameters)
|
|
ferencd@0
|
499 {
|
|
ferencd@0
|
500 if(p.first == v.name())
|
|
ferencd@0
|
501 {
|
|
ferencd@0
|
502 stringholder sh(loop_content);
|
|
ferencd@0
|
503
|
|
ferencd@0
|
504 for(const auto &x : ts.struct_members)
|
|
ferencd@0
|
505 {
|
|
ferencd@0
|
506 //if(x.first == loop_target)
|
|
ferencd@0
|
507 {
|
|
ferencd@0
|
508 std::string fullname = v.name() + "." + x.first;
|
|
ferencd@0
|
509 std::string fullname_to_replace_with = v.name() + "." + x.first + ":" + std::to_string(c);
|
|
ferencd@0
|
510
|
|
ferencd@0
|
511 kps.insert(make_pair(fullname_to_replace_with, unafrog::utils::to_string(x.second)));
|
|
ferencd@0
|
512 sh.replace_all(TEMPLATE_VARIABLE_START_DELIMITER + fullname +TEMPLATE_VARIABLE_END_DELIMITER,
|
|
ferencd@0
|
513 TEMPLATE_VARIABLE_START_DELIMITER + fullname_to_replace_with + TEMPLATE_VARIABLE_END_DELIMITER);
|
|
ferencd@0
|
514 }
|
|
ferencd@0
|
515 }
|
|
ferencd@0
|
516
|
|
ferencd@0
|
517 final_loop_content += sh.get();
|
|
ferencd@0
|
518 }
|
|
ferencd@0
|
519 }
|
|
ferencd@0
|
520 }
|
|
ferencd@0
|
521 }
|
|
ferencd@0
|
522 // now fetch out the substring (loop_tag_end_position, save_endpos - loop_tag_end_position) from templatized
|
|
ferencd@0
|
523 // and replace with final_loop_content
|
|
ferencd@0
|
524
|
|
ferencd@0
|
525 if(v.name() == loop_target)
|
|
ferencd@0
|
526 {
|
|
ferencd@0
|
527 std::string part1 = templatized.substr(0, loop_tag_end_position);
|
|
ferencd@0
|
528
|
|
ferencd@0
|
529 part1.erase(loop_tag_start_position, loop_tag_end_position - loop_tag_start_position);
|
|
ferencd@0
|
530 part1 += final_loop_content;
|
|
ferencd@0
|
531 part1 += templatized.substr(endloop_endpos);
|
|
ferencd@0
|
532
|
|
ferencd@0
|
533 templatized = part1;
|
|
ferencd@0
|
534 loop_pos = templatized.find(LOOP_TAG);
|
|
ferencd@0
|
535 }
|
|
ferencd@0
|
536 else
|
|
ferencd@0
|
537 {
|
|
ferencd@0
|
538 loop_pos = templatized.find(LOOP_TAG, endloop_endpos);
|
|
ferencd@0
|
539 }
|
|
ferencd@0
|
540 }
|
|
ferencd@0
|
541
|
|
ferencd@0
|
542 templatized = stringholder(templatized).templatize(kps).get();
|
|
ferencd@0
|
543 precalculated = templatized;
|
|
ferencd@0
|
544 return templatized;
|
|
ferencd@0
|
545 }
|
|
ferencd@0
|
546
|
|
ferencd@0
|
547 std::string templater_base::resolve_ifeqs(std::string templatized)
|
|
ferencd@0
|
548 {
|
|
ferencd@0
|
549 bool done = false;
|
|
ferencd@0
|
550 while(!done)
|
|
ferencd@0
|
551 {
|
|
ferencd@0
|
552 size_t ifeq_pos = templatized.find(IFEQ_TAG);
|
|
ferencd@0
|
553 if(ifeq_pos != std::string::npos)
|
|
ferencd@0
|
554 {
|
|
ferencd@0
|
555 while(ifeq_pos != std::string::npos)
|
|
ferencd@0
|
556 {
|
|
ferencd@0
|
557 templatized = resolve_ifeq(ifeq_pos, templatized);
|
|
ferencd@0
|
558 ifeq_pos = templatized.find(IFEQ_TAG);
|
|
ferencd@0
|
559 }
|
|
ferencd@0
|
560 }
|
|
ferencd@0
|
561 else
|
|
ferencd@0
|
562 {
|
|
ferencd@0
|
563 done = true;
|
|
ferencd@0
|
564 }
|
|
ferencd@0
|
565 }
|
|
ferencd@0
|
566 return templatized;
|
|
ferencd@0
|
567 }
|
|
ferencd@0
|
568
|
|
ferencd@0
|
569 std::string templater_base::resolve_translations(std::string templatized, const std::string &target_language, bool generate_span, std::map<std::string, std::map<std::string, std::string> >& translations)
|
|
ferencd@0
|
570 {
|
|
ferencd@0
|
571 bool done = false;
|
|
ferencd@0
|
572 while(!done)
|
|
ferencd@0
|
573 {
|
|
ferencd@0
|
574 size_t ifeq_pos = templatized.find(TRANSLATE_TAG);
|
|
ferencd@0
|
575 if(ifeq_pos != std::string::npos)
|
|
ferencd@0
|
576 {
|
|
ferencd@0
|
577 while(ifeq_pos != std::string::npos)
|
|
ferencd@0
|
578 {
|
|
ferencd@0
|
579 std::map<std::string, std::string> local_translations;
|
|
ferencd@0
|
580 std::string span_id;
|
|
ferencd@0
|
581
|
|
ferencd@0
|
582 templatized = resolve_translation(ifeq_pos, templatized, target_language, generate_span, span_id, local_translations);
|
|
ferencd@0
|
583
|
|
ferencd@0
|
584 translations[span_id] = local_translations;
|
|
ferencd@0
|
585
|
|
ferencd@0
|
586 ifeq_pos = templatized.find(TRANSLATE_TAG);
|
|
ferencd@0
|
587 }
|
|
ferencd@0
|
588 }
|
|
ferencd@0
|
589 else
|
|
ferencd@0
|
590 {
|
|
ferencd@0
|
591 done = true;
|
|
ferencd@0
|
592 }
|
|
ferencd@0
|
593 }
|
|
ferencd@0
|
594 return templatized;
|
|
ferencd@0
|
595
|
|
ferencd@0
|
596 }
|
|
ferencd@0
|
597
|
|
ferencd@0
|
598 static std::string span_name(std::string str)
|
|
ferencd@0
|
599 {
|
|
ferencd@0
|
600 str.erase(std::remove_if(str.begin(), str.end(), isspace), str.end());
|
|
ferencd@0
|
601 return "span_" + str;
|
|
ferencd@0
|
602 }
|
|
ferencd@0
|
603
|
|
ferencd@0
|
604 std::string templater_base::resolve_translation(size_t tr_pos, std::string templatized, const std::string &target_language, bool generate_span, std::string& span_id, std::map<std::string, std::string> &translations)
|
|
ferencd@0
|
605 {
|
|
ferencd@0
|
606 size_t i = tr_pos;
|
|
ferencd@0
|
607
|
|
ferencd@0
|
608 // skip the <!--#translate
|
|
ferencd@0
|
609 i += TRANSLATE_TAG.length();
|
|
ferencd@0
|
610
|
|
ferencd@0
|
611 // and any whitespace that might follow
|
|
ferencd@0
|
612 skip_whitespace(templatized, i);
|
|
ferencd@0
|
613 size_t translateable_start = i;
|
|
ferencd@0
|
614
|
|
ferencd@0
|
615 // now extract the word to translate
|
|
ferencd@0
|
616 if(i < templatized.length())
|
|
ferencd@0
|
617 {
|
|
ferencd@0
|
618 char c_sep = 32;
|
|
ferencd@0
|
619 std::string what_to = extract_identifier_word(templatized, i, {'#'}, {' ', ',', '.', '!', '?', ':', ':'}, std::move(c_sep));
|
|
ferencd@0
|
620 skip_whitespace(templatized, i);
|
|
ferencd@0
|
621
|
|
ferencd@0
|
622 std::string before_translate = templatized.substr(0, tr_pos);
|
|
ferencd@0
|
623 std::string between = templatized.substr(translateable_start, what_to.length());
|
|
ferencd@0
|
624 std::string after_translate = templatized.substr(translateable_start + what_to.length() + 4);
|
|
ferencd@0
|
625
|
|
ferencd@0
|
626 span_id = span_name(between);
|
|
ferencd@0
|
627
|
|
ferencd@0
|
628 templatized = before_translate + (generate_span ? "<span id='" + span_id + "'>" : "") + dictionary::translate(between, target_language, true, translations) +(generate_span ? "</span>" : "") + after_translate;
|
|
ferencd@0
|
629 }
|
|
ferencd@0
|
630
|
|
ferencd@0
|
631
|
|
ferencd@0
|
632 return templatized;
|
|
ferencd@0
|
633
|
|
ferencd@0
|
634 }
|
|
ferencd@0
|
635
|
|
ferencd@0
|
636 templater_base &templater_base::templatize(const template_vector_par &v)
|
|
ferencd@0
|
637 {
|
|
ferencd@0
|
638 do_not_resolve_in_get();
|
|
ferencd@0
|
639 std::string templatized = precalculated.empty() ? get() : precalculated;
|
|
ferencd@0
|
640
|
|
ferencd@0
|
641 do_resolve_in_get();
|
|
ferencd@0
|
642
|
|
ferencd@0
|
643 templatized = resolve_loops(templatized, v);
|
|
ferencd@0
|
644 templatized = resolve_ifeqs(templatized);
|
|
ferencd@0
|
645 templatized = resolve_scripts(templatized, SCRIPT_TAG);
|
|
ferencd@0
|
646 precalculated = templatized;
|
|
ferencd@0
|
647
|
|
ferencd@0
|
648 return *this;
|
|
ferencd@0
|
649 }
|
|
ferencd@0
|
650
|
|
ferencd@0
|
651 void templater_base::skip_whitespace(const std::string& templatized, size_t& i)
|
|
ferencd@0
|
652 {
|
|
ferencd@0
|
653 while(i < templatized.length() && std::iswspace(templatized[i]))
|
|
ferencd@0
|
654 {
|
|
ferencd@0
|
655 i++;
|
|
ferencd@0
|
656 }
|
|
ferencd@0
|
657 }
|
|
ferencd@0
|
658
|
|
ferencd@0
|
659 std::string templater_base::resolve_parameters(size_t parameters_pos, std::string templatized)
|
|
ferencd@0
|
660 {
|
|
ferencd@0
|
661 std::size_t include_tag_end_position = std::string::npos;
|
|
ferencd@0
|
662 std::size_t include_tag_start_position = parameters_pos;
|
|
ferencd@0
|
663
|
|
ferencd@0
|
664 parameters_pos += PARAMETERS_TAG.length();
|
|
ferencd@0
|
665 skip_whitespace(templatized, parameters_pos);
|
|
ferencd@0
|
666
|
|
ferencd@0
|
667 size_t i = parameters_pos;
|
|
ferencd@0
|
668 bool closing_comment_found = false;
|
|
ferencd@0
|
669 while(i < templatized.length() && ! closing_comment_found)
|
|
ferencd@0
|
670 {
|
|
ferencd@0
|
671 // first: read in the variable name
|
|
ferencd@0
|
672 char c_sep = 32;
|
|
ferencd@0
|
673 std::string var_name = extract_identifier_word(templatized, i, {':', ' '}, {}, static_cast<char&&>(c_sep));
|
|
ferencd@0
|
674
|
|
ferencd@0
|
675 if(i == templatized.length() || var_name.empty())
|
|
ferencd@0
|
676 {
|
|
ferencd@0
|
677 return templatized;
|
|
ferencd@0
|
678 }
|
|
ferencd@0
|
679
|
|
ferencd@0
|
680 std::string var_type = "";
|
|
ferencd@0
|
681 bool iterable = false;
|
|
ferencd@0
|
682
|
|
ferencd@0
|
683 if(c_sep == ':')
|
|
ferencd@0
|
684 {
|
|
ferencd@0
|
685 // now read the variable type
|
|
ferencd@0
|
686 var_type = extract_identifier_word(templatized, i);
|
|
ferencd@0
|
687
|
|
ferencd@0
|
688 if(i < templatized.length() && templatized[i] == '[')
|
|
ferencd@0
|
689 {
|
|
ferencd@0
|
690 i ++;
|
|
ferencd@0
|
691 skip_whitespace(templatized, i);
|
|
ferencd@0
|
692 if(i < templatized.length() && templatized[i] == ']')
|
|
ferencd@0
|
693 {
|
|
ferencd@0
|
694 i ++;
|
|
ferencd@0
|
695 }
|
|
ferencd@0
|
696 iterable = true;
|
|
ferencd@0
|
697 }
|
|
ferencd@0
|
698 }
|
|
ferencd@0
|
699
|
|
ferencd@0
|
700 add_parameter(var_name, var_type, iterable);
|
|
ferencd@0
|
701
|
|
ferencd@0
|
702 skip_whitespace(templatized, i);
|
|
ferencd@0
|
703
|
|
ferencd@0
|
704 // se if we have a "," coming up
|
|
ferencd@0
|
705 if(templatized[i] == ',')
|
|
ferencd@0
|
706 {
|
|
ferencd@0
|
707 i ++;
|
|
ferencd@0
|
708 skip_whitespace(templatized, i);
|
|
ferencd@0
|
709 }
|
|
ferencd@0
|
710
|
|
ferencd@0
|
711 if(templatized[i] == '#') // This should be the closing comment
|
|
ferencd@0
|
712 {
|
|
ferencd@0
|
713 closing_comment_found = check_closing_comment(templatized, i, include_tag_end_position);
|
|
ferencd@0
|
714 }
|
|
ferencd@0
|
715 }
|
|
ferencd@0
|
716
|
|
ferencd@0
|
717 templatized.erase(include_tag_start_position, include_tag_end_position - include_tag_start_position);
|
|
ferencd@0
|
718 return templatized;
|
|
ferencd@0
|
719 }
|
|
ferencd@0
|
720
|
|
ferencd@0
|
721 std::string templater_base::resolve_ifs(size_t if_pos, std::string templatized)
|
|
ferencd@0
|
722 {
|
|
ferencd@0
|
723 size_t i = if_pos;
|
|
ferencd@0
|
724
|
|
ferencd@0
|
725 // skip the <!--#if
|
|
ferencd@0
|
726 i += IF_TAG.length();
|
|
ferencd@0
|
727
|
|
ferencd@0
|
728 // and any whitespace that might follow
|
|
ferencd@0
|
729 skip_whitespace(templatized, i);
|
|
ferencd@0
|
730
|
|
ferencd@0
|
731 // now extract the variable
|
|
ferencd@0
|
732 if(i < templatized.length())
|
|
ferencd@0
|
733 {
|
|
ferencd@0
|
734 char c_sep = 32;
|
|
ferencd@0
|
735 std::string var_name = extract_identifier_word(templatized, i, {' ', '#'}, {}, std::move(c_sep));
|
|
ferencd@0
|
736 skip_whitespace(templatized, i);
|
|
ferencd@0
|
737
|
|
ferencd@0
|
738 std::string var_value = "";
|
|
ferencd@0
|
739 // now if var_name is empty remove the if and it's body.
|
|
ferencd@0
|
740 if(kps.count(var_name))
|
|
ferencd@0
|
741 {
|
|
ferencd@0
|
742 var_value = kps[var_name];
|
|
ferencd@0
|
743 }
|
|
ferencd@0
|
744
|
|
ferencd@0
|
745 std::string closing_endif_tag = ENDIF_TAG + " " + var_name;
|
|
ferencd@0
|
746 std::string closing_else_tag = ELSE_TAG + " " + var_name;
|
|
ferencd@0
|
747
|
|
ferencd@0
|
748 if(var_value.empty())
|
|
ferencd@0
|
749 {
|
|
ferencd@0
|
750 // search for the first <!--#endif var_name
|
|
ferencd@0
|
751 size_t endif_pos = templatized.find(closing_endif_tag);
|
|
ferencd@0
|
752 if(endif_pos != std::string::npos)
|
|
ferencd@0
|
753 {
|
|
ferencd@0
|
754 // search for the first <!--#else before the endif tag
|
|
ferencd@0
|
755
|
|
ferencd@0
|
756 size_t else_pos = templatized.find(closing_else_tag);
|
|
ferencd@0
|
757 if(else_pos < endif_pos)
|
|
ferencd@0
|
758 {
|
|
ferencd@0
|
759 // this is the else of this if, removing the content of the if till the else
|
|
ferencd@0
|
760 templatized = templatized.substr(0, if_pos) + templatized.substr(else_pos + closing_else_tag.length() + 4);
|
|
ferencd@0
|
761 // we still need to remove the endif
|
|
ferencd@0
|
762 size_t final_endif_pos = templatized.find(closing_endif_tag);
|
|
ferencd@0
|
763 if(final_endif_pos != std::string::npos)
|
|
ferencd@0
|
764 {
|
|
ferencd@0
|
765 templatized = templatized.substr(0, final_endif_pos) + templatized.substr(final_endif_pos + closing_endif_tag.length() + 4);
|
|
ferencd@0
|
766 }
|
|
ferencd@0
|
767
|
|
ferencd@0
|
768 }
|
|
ferencd@0
|
769 else
|
|
ferencd@0
|
770 {
|
|
ferencd@0
|
771 // no else, just remove the if tag
|
|
ferencd@0
|
772 templatized = templatized.substr(0, if_pos) + templatized.substr(endif_pos + closing_endif_tag.length() + 4);
|
|
ferencd@0
|
773 }
|
|
ferencd@0
|
774 }
|
|
ferencd@0
|
775 else
|
|
ferencd@0
|
776 {
|
|
ferencd@0
|
777 // oops, user forgot the enclosing endif, just return what is here
|
|
ferencd@0
|
778 return templatized;
|
|
ferencd@0
|
779 }
|
|
ferencd@0
|
780 }
|
|
ferencd@0
|
781 else // remove the comments :)
|
|
ferencd@0
|
782 {
|
|
ferencd@0
|
783 size_t endif_pos = templatized.find(closing_endif_tag);
|
|
ferencd@0
|
784
|
|
ferencd@0
|
785 if(endif_pos != std::string::npos)
|
|
ferencd@0
|
786 {
|
|
ferencd@0
|
787 size_t remove_start_pos = endif_pos;
|
|
ferencd@0
|
788 std::string remove_tag = closing_endif_tag;
|
|
ferencd@0
|
789 size_t additional_remove = 0; // count ofchars between else and endif
|
|
ferencd@0
|
790 // search for the first <!--#else before the endif tag
|
|
ferencd@0
|
791 size_t else_pos = templatized.find(closing_else_tag);
|
|
ferencd@0
|
792 if(else_pos < endif_pos)
|
|
ferencd@0
|
793 {
|
|
ferencd@0
|
794 remove_start_pos = else_pos;
|
|
ferencd@0
|
795 additional_remove = endif_pos - remove_start_pos;
|
|
ferencd@0
|
796 }
|
|
ferencd@0
|
797
|
|
ferencd@0
|
798 std::string before_if = templatized.substr(0, if_pos);
|
|
ferencd@0
|
799 std::string between = templatized.substr(i + 3, remove_start_pos - i - 3);
|
|
ferencd@0
|
800 std::string after_endif = templatized.substr(remove_start_pos + additional_remove + closing_endif_tag.length() + 4);
|
|
ferencd@0
|
801
|
|
ferencd@0
|
802 templatized = before_if + between + after_endif;
|
|
ferencd@0
|
803 }
|
|
ferencd@0
|
804 else
|
|
ferencd@0
|
805 {
|
|
ferencd@0
|
806 // oops, user forgot the enclosing endif, just return what is here
|
|
ferencd@0
|
807 return templatized;
|
|
ferencd@0
|
808 }
|
|
ferencd@0
|
809 }
|
|
ferencd@0
|
810 }
|
|
ferencd@0
|
811
|
|
ferencd@0
|
812 return templatized;
|
|
ferencd@0
|
813 }
|
|
ferencd@0
|
814
|
|
ferencd@0
|
815 std::string templater_base::resolve_ifeq(size_t if_pos, std::string templatized)
|
|
ferencd@0
|
816 {
|
|
ferencd@0
|
817 size_t i = if_pos;
|
|
ferencd@0
|
818
|
|
ferencd@0
|
819 // skip the <!--#ifeq
|
|
ferencd@0
|
820 i += IFEQ_TAG.length();
|
|
ferencd@0
|
821
|
|
ferencd@0
|
822 // and any whitespace that might follow
|
|
ferencd@0
|
823 skip_whitespace(templatized, i);
|
|
ferencd@0
|
824
|
|
ferencd@0
|
825 // now extract the variable
|
|
ferencd@0
|
826 if(i < templatized.length())
|
|
ferencd@0
|
827 {
|
|
ferencd@0
|
828 char c_sep = 32;
|
|
ferencd@0
|
829 std::string what_to = extract_identifier_word(templatized, i, {' ', '#'}, {',','-'}, std::move(c_sep));
|
|
ferencd@0
|
830 skip_whitespace(templatized, i);
|
|
ferencd@0
|
831
|
|
ferencd@0
|
832 size_t comma_pos = what_to.find(',');
|
|
ferencd@0
|
833 bool are_eq = true;
|
|
ferencd@0
|
834 if(comma_pos == std::string::npos)
|
|
ferencd@0
|
835 {
|
|
ferencd@0
|
836 are_eq = false;
|
|
ferencd@0
|
837 }
|
|
ferencd@0
|
838 else
|
|
ferencd@0
|
839 {
|
|
ferencd@0
|
840 std::string before = what_to.substr(0, comma_pos);
|
|
ferencd@0
|
841 std::string after = what_to.substr(comma_pos + 1);
|
|
ferencd@0
|
842
|
|
ferencd@0
|
843 are_eq = before == after;
|
|
ferencd@0
|
844 }
|
|
ferencd@0
|
845
|
|
ferencd@0
|
846
|
|
ferencd@0
|
847 if(!are_eq)
|
|
ferencd@0
|
848 {
|
|
ferencd@0
|
849 // search for the first <!--#endifeq
|
|
ferencd@0
|
850 size_t endif_pos = templatized.find(ENDEQ_TAG);
|
|
ferencd@0
|
851 if(endif_pos != std::string::npos)
|
|
ferencd@0
|
852 {
|
|
ferencd@0
|
853 templatized = templatized.substr(0, if_pos) + templatized.substr(endif_pos + ENDEQ_TAG.length() + 4);
|
|
ferencd@0
|
854 }
|
|
ferencd@0
|
855 }
|
|
ferencd@0
|
856 else // remove the comments :)
|
|
ferencd@0
|
857 {
|
|
ferencd@0
|
858 size_t endif_pos = templatized.find(ENDEQ_TAG);
|
|
ferencd@0
|
859
|
|
ferencd@0
|
860 if(endif_pos != std::string::npos)
|
|
ferencd@0
|
861 {
|
|
ferencd@0
|
862 size_t remove_start_pos = endif_pos;
|
|
ferencd@0
|
863 std::string before_if = templatized.substr(0, if_pos);
|
|
ferencd@0
|
864 std::string between = templatized.substr(i + 3, remove_start_pos - i - 3);
|
|
ferencd@0
|
865 std::string after_endif = templatized.substr(remove_start_pos + ENDEQ_TAG.length() + 4);
|
|
ferencd@0
|
866
|
|
ferencd@0
|
867 templatized = before_if + between + after_endif;
|
|
ferencd@0
|
868 }
|
|
ferencd@0
|
869 }
|
|
ferencd@0
|
870 }
|
|
ferencd@0
|
871
|
|
ferencd@0
|
872 return templatized;
|
|
ferencd@0
|
873 }
|
|
ferencd@0
|
874
|
|
ferencd@0
|
875 std::string templater_base::resolve_defines(std::string content)
|
|
ferencd@0
|
876 {
|
|
ferencd@0
|
877 size_t define_pos = content.find(DEFINE_TAG);
|
|
ferencd@0
|
878
|
|
ferencd@0
|
879 std::vector<std::pair<size_t, size_t>> strings_to_remove; // we will remove the define tags from in here
|
|
ferencd@0
|
880 if(define_pos != std::string::npos)
|
|
ferencd@0
|
881 {
|
|
ferencd@0
|
882 while(define_pos != std::string::npos)
|
|
ferencd@0
|
883 {
|
|
ferencd@0
|
884 bool define_read = false;
|
|
ferencd@0
|
885 // skipping the tag
|
|
ferencd@0
|
886 size_t i = define_pos + DEFINE_TAG.length();
|
|
ferencd@0
|
887 // skipping the whitespace after the tag
|
|
ferencd@0
|
888 skip_whitespace(content, i);
|
|
ferencd@0
|
889 while(!define_read)
|
|
ferencd@0
|
890 {
|
|
ferencd@0
|
891
|
|
ferencd@0
|
892 std::string var_name = "";
|
|
ferencd@0
|
893 std::string var_value = "";
|
|
ferencd@0
|
894 // now comes a list of comma separated variable=value assignments or just simply variable
|
|
ferencd@0
|
895 while(i < content.length() && content[i] != '=' && content[i] != ',' && content[i] != '#'
|
|
ferencd@0
|
896 && (isalnum(content[i]) || content[i] == '_' ))
|
|
ferencd@0
|
897 {
|
|
ferencd@0
|
898 var_name += content[i];
|
|
ferencd@0
|
899 i ++;
|
|
ferencd@0
|
900 }
|
|
ferencd@0
|
901 // now if content[i] == '=' we need to parse out the value from it
|
|
ferencd@0
|
902 if(content[i] == '=')
|
|
ferencd@0
|
903 {
|
|
ferencd@0
|
904 i ++;
|
|
ferencd@0
|
905 bool string_comes = false;
|
|
ferencd@0
|
906 if(content[i] == '"') // string comes after this?
|
|
ferencd@0
|
907 {
|
|
ferencd@0
|
908 i++;
|
|
ferencd@0
|
909 string_comes = true;
|
|
ferencd@0
|
910 }
|
|
ferencd@0
|
911 while( (i < content.length() && content[i] != ',' && content[i] != '#' && !string_comes)
|
|
ferencd@0
|
912 || (i < content.length() && string_comes && content[i] != '"'))
|
|
ferencd@0
|
913 {
|
|
ferencd@0
|
914 if(content[i] != '\\') // escaping a quote in the string
|
|
ferencd@0
|
915 {
|
|
ferencd@0
|
916 var_value += content[i];
|
|
ferencd@0
|
917 }
|
|
ferencd@0
|
918 else
|
|
ferencd@0
|
919 {
|
|
ferencd@0
|
920 i++;
|
|
ferencd@0
|
921 var_value += content[i];
|
|
ferencd@0
|
922 }
|
|
ferencd@0
|
923 i++;
|
|
ferencd@0
|
924 }
|
|
ferencd@0
|
925 }
|
|
ferencd@0
|
926 else
|
|
ferencd@0
|
927 {
|
|
ferencd@0
|
928 var_value = "true";
|
|
ferencd@0
|
929 }
|
|
ferencd@0
|
930 kps.insert({var_name, var_value});
|
|
ferencd@0
|
931 if(content[i] == '#')
|
|
ferencd@0
|
932 {
|
|
ferencd@0
|
933 i++;
|
|
ferencd@0
|
934 if(i + 2 < content.length() && content[i] == '-' && content[i+1] == '-' && content[i+2]=='>')
|
|
ferencd@0
|
935 {
|
|
ferencd@0
|
936 i += 3; // skip the closing comment
|
|
ferencd@0
|
937 define_read = true;
|
|
ferencd@0
|
938 }
|
|
ferencd@0
|
939 else
|
|
ferencd@0
|
940 {
|
|
ferencd@0
|
941 // this is a malformed entry, just give up
|
|
ferencd@0
|
942 return content;
|
|
ferencd@0
|
943 }
|
|
ferencd@0
|
944 }
|
|
ferencd@0
|
945 else
|
|
ferencd@0
|
946 {
|
|
ferencd@0
|
947 if(content[i] == ',')
|
|
ferencd@0
|
948 {
|
|
ferencd@0
|
949 i++;
|
|
ferencd@0
|
950 }
|
|
ferencd@0
|
951 }
|
|
ferencd@0
|
952 }
|
|
ferencd@0
|
953
|
|
ferencd@0
|
954 strings_to_remove.insert(strings_to_remove.begin(), {define_pos, i});
|
|
ferencd@0
|
955 define_pos = content.find(DEFINE_TAG, i);
|
|
ferencd@0
|
956 }
|
|
ferencd@0
|
957 }
|
|
ferencd@0
|
958 // now walk through the strings_to_remove and delete from the content everything from there
|
|
ferencd@0
|
959 for(const auto& beg_end_pos : strings_to_remove)
|
|
ferencd@0
|
960 {
|
|
ferencd@0
|
961 content.erase(beg_end_pos.first, beg_end_pos.second - beg_end_pos.first);
|
|
ferencd@0
|
962 }
|
|
ferencd@0
|
963
|
|
ferencd@0
|
964 return content;
|
|
ferencd@0
|
965 }
|
|
ferencd@0
|
966
|
|
ferencd@0
|
967 std::string templater_base::resolve_scripts(std::string templatized, const std::string& tag)
|
|
ferencd@0
|
968 {
|
|
ferencd@0
|
969 bool done = false;
|
|
ferencd@0
|
970 while(!done)
|
|
ferencd@0
|
971 {
|
|
ferencd@0
|
972 size_t script_tag_pos = templatized.find(tag);
|
|
ferencd@0
|
973 if(script_tag_pos != std::string::npos)
|
|
ferencd@0
|
974 {
|
|
ferencd@0
|
975 while(script_tag_pos != std::string::npos)
|
|
ferencd@0
|
976 {
|
|
ferencd@0
|
977 templatized = resolve_script(script_tag_pos, templatized, tag);
|
|
ferencd@0
|
978 script_tag_pos = templatized.find(tag);
|
|
ferencd@0
|
979 }
|
|
ferencd@0
|
980 }
|
|
ferencd@0
|
981 else
|
|
ferencd@0
|
982 {
|
|
ferencd@0
|
983 done = true;
|
|
ferencd@0
|
984 }
|
|
ferencd@0
|
985 }
|
|
ferencd@0
|
986 return templatized;
|
|
ferencd@0
|
987 }
|
|
ferencd@0
|
988
|
|
ferencd@0
|
989 std::string templater_base::resolve_script(size_t pos, const std::string& content, const std::string &tag)
|
|
ferencd@0
|
990 {
|
|
ferencd@0
|
991 size_t endscript_start_pos = content.find(ENDSCRIPT_TAG);
|
|
ferencd@0
|
992 size_t old_pos = pos;
|
|
ferencd@0
|
993
|
|
ferencd@0
|
994 // skip the tag
|
|
ferencd@0
|
995 pos += tag.length();
|
|
ferencd@0
|
996 // skip the space(s) followwing the "script"
|
|
ferencd@0
|
997 while(isspace(content[pos])) pos += 1;
|
|
ferencd@0
|
998
|
|
ferencd@0
|
999 std::string script_type = "";
|
|
ferencd@0
|
1000 while(pos < content.length() && content[pos] != '#' && content[pos] != ':')
|
|
ferencd@0
|
1001 {
|
|
ferencd@0
|
1002 script_type += content[pos++];
|
|
ferencd@0
|
1003 }
|
|
ferencd@0
|
1004
|
|
ferencd@0
|
1005 if(pos == content.length())
|
|
ferencd@0
|
1006 {
|
|
ferencd@0
|
1007 set_error("Script tag at", old_pos, "is not closed");
|
|
ferencd@0
|
1008 return content.substr(0, old_pos);
|
|
ferencd@0
|
1009 }
|
|
ferencd@0
|
1010
|
|
ferencd@0
|
1011 static const auto script_types = {"python"};
|
|
ferencd@0
|
1012
|
|
ferencd@0
|
1013 bool found = false;
|
|
ferencd@0
|
1014 for(const auto& st : script_types)
|
|
ferencd@0
|
1015 {
|
|
ferencd@0
|
1016 if(st == script_type) found = true;
|
|
ferencd@0
|
1017 }
|
|
ferencd@0
|
1018
|
|
ferencd@0
|
1019 if(!found)
|
|
ferencd@0
|
1020 {
|
|
ferencd@0
|
1021 set_error("Unsupported scripting language", script_type);
|
|
ferencd@0
|
1022 return content.substr(0, old_pos);
|
|
ferencd@0
|
1023 }
|
|
ferencd@0
|
1024
|
|
ferencd@0
|
1025 // pos points to the script closing tag
|
|
ferencd@0
|
1026 std::string before_script = content.substr(0, old_pos);
|
|
ferencd@0
|
1027 std::string between = std::string(content.begin() + pos + 4, // #--> is the 4
|
|
ferencd@0
|
1028 content.begin() + endscript_start_pos);
|
|
ferencd@0
|
1029 std::string after_script = content.substr(endscript_start_pos + ENDSCRIPT_TAG.length() + 4);
|
|
ferencd@0
|
1030
|
|
ferencd@0
|
1031 std::string result = python_runner().run(kps, between, variables(true));
|
|
ferencd@0
|
1032
|
|
ferencd@0
|
1033
|
|
ferencd@0
|
1034 return before_script + unafrog::utils::trim(result) + after_script;
|
|
ferencd@0
|
1035 }
|
|
ferencd@0
|
1036
|
|
ferencd@0
|
1037 void stringholder::replace_all(const std::string &from, const std::string &to)
|
|
ferencd@0
|
1038 {
|
|
ferencd@0
|
1039 if(from.empty())
|
|
ferencd@0
|
1040 {
|
|
ferencd@0
|
1041 return;
|
|
ferencd@0
|
1042 }
|
|
ferencd@0
|
1043 size_t start_pos = 0;
|
|
ferencd@0
|
1044 while((start_pos = str.find(from, start_pos)) != std::string::npos)
|
|
ferencd@0
|
1045 {
|
|
ferencd@0
|
1046 str.replace(start_pos, from.length(), to);
|
|
ferencd@0
|
1047 start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx'
|
|
ferencd@0
|
1048 }
|
|
ferencd@0
|
1049 }
|
|
ferencd@0
|
1050
|
|
ferencd@0
|
1051 stringholder &stringholder::templatize(const std::map<std::string, std::string> &m)
|
|
ferencd@0
|
1052 {
|
|
ferencd@0
|
1053 for(auto it = m.begin(); it != m.end(); ++ it)
|
|
ferencd@0
|
1054 {
|
|
ferencd@0
|
1055 replace_all(TEMPLATE_VARIABLE_START_DELIMITER + it->first + TEMPLATE_VARIABLE_END_DELIMITER, it->second );
|
|
ferencd@0
|
1056 }
|
|
ferencd@0
|
1057 return *this;
|
|
ferencd@0
|
1058 }
|
|
ferencd@0
|
1059
|
|
ferencd@0
|
1060 template_warehouse &template_warehouse::instance()
|
|
ferencd@0
|
1061 {
|
|
ferencd@0
|
1062 static template_warehouse twh;
|
|
ferencd@0
|
1063 return twh;
|
|
ferencd@0
|
1064 }
|
|
ferencd@0
|
1065
|
|
ferencd@0
|
1066 bool template_warehouse::checkTemplates()
|
|
ferencd@0
|
1067 {
|
|
ferencd@0
|
1068 for(auto it = templates.begin(); it != templates.end(); ++it)
|
|
ferencd@0
|
1069 {
|
|
ferencd@0
|
1070 if(!it->second->check())
|
|
ferencd@0
|
1071 {
|
|
ferencd@0
|
1072 return false;
|
|
ferencd@0
|
1073 }
|
|
ferencd@0
|
1074 }
|
|
ferencd@0
|
1075 debug() << "All templates OK";
|
|
ferencd@0
|
1076 return true;
|
|
ferencd@0
|
1077 }
|
|
ferencd@0
|
1078
|
|
ferencd@0
|
1079 std::string template_warehouse::getTemplateContent(const std::string &templateName)
|
|
ferencd@0
|
1080 {
|
|
ferencd@0
|
1081 if(templates.count(templateName))
|
|
ferencd@0
|
1082 {
|
|
ferencd@0
|
1083 std::shared_ptr<template_base> tb = templates[templateName];
|
|
ferencd@0
|
1084 std::string c = tb->content();
|
|
ferencd@0
|
1085 return c;
|
|
ferencd@0
|
1086 }
|
|
ferencd@0
|
1087 else
|
|
ferencd@0
|
1088 {
|
|
ferencd@0
|
1089 return "Not found:" + templateName;
|
|
ferencd@0
|
1090 }
|
|
ferencd@0
|
1091 }
|
|
ferencd@0
|
1092
|
|
ferencd@0
|
1093 bool template_warehouse::registerTemplate(const std::string &name, template_base *templateClass)
|
|
ferencd@0
|
1094 {
|
|
ferencd@0
|
1095 // although this code seems stupid, it is due to the fact that every inclusion of the
|
|
ferencd@0
|
1096 // templater.h will cause a new object to be created, but we want only one
|
|
ferencd@0
|
1097 if(templates.count(name))
|
|
ferencd@0
|
1098 {
|
|
ferencd@0
|
1099 debug() << "Freeing existing template class:" << name;
|
|
ferencd@0
|
1100 delete templateClass;
|
|
ferencd@0
|
1101 return false;
|
|
ferencd@0
|
1102 }
|
|
ferencd@0
|
1103 debug() << "Registering template class:" << name;
|
|
ferencd@0
|
1104 templates[name] = std::shared_ptr<template_base>(templateClass);
|
|
ferencd@0
|
1105 return true;
|
|
ferencd@0
|
1106 }
|
|
ferencd@0
|
1107
|
|
ferencd@0
|
1108
|
|
ferencd@0
|
1109 std::string file_template::base_dir() const
|
|
ferencd@0
|
1110 {
|
|
ferencd@0
|
1111 namespace fs = std::filesystem;
|
|
ferencd@0
|
1112 if(fs::is_regular_file(fileName()))
|
|
ferencd@0
|
1113 {
|
|
ferencd@0
|
1114 return "";
|
|
ferencd@0
|
1115 }
|
|
ferencd@0
|
1116 else
|
|
ferencd@0
|
1117 {
|
|
ferencd@0
|
1118 return TEMPLATES_DIRECTORY;
|
|
ferencd@0
|
1119 }
|
|
ferencd@0
|
1120
|
|
ferencd@0
|
1121 }
|
|
ferencd@0
|
1122
|
|
ferencd@0
|
1123 std::string file_template::content() const
|
|
ferencd@0
|
1124 {
|
|
ferencd@0
|
1125 std::string fn = base_dir() + fileName();
|
|
ferencd@0
|
1126 std::ifstream ifs(fn);
|
|
ferencd@0
|
1127 std::string s( (std::istreambuf_iterator<char>(ifs) ),
|
|
ferencd@0
|
1128 (std::istreambuf_iterator<char>()) );
|
|
ferencd@0
|
1129 return s;
|
|
ferencd@0
|
1130 }
|
|
ferencd@0
|
1131
|
|
ferencd@0
|
1132 bool file_template::check() const
|
|
ferencd@0
|
1133 {
|
|
ferencd@0
|
1134 struct stat buffer;
|
|
ferencd@0
|
1135 bool res = (stat ( (base_dir() + fileName()).c_str(), &buffer) == 0);
|
|
ferencd@0
|
1136 if(!res)
|
|
ferencd@0
|
1137 {
|
|
ferencd@0
|
1138 debug() << "Check for "<< fileName() << " failed";
|
|
ferencd@0
|
1139 }
|
|
ferencd@0
|
1140 return res;
|
|
ferencd@0
|
1141 }
|
|
ferencd@0
|
1142
|
|
ferencd@0
|
1143
|
|
ferencd@0
|
1144
|