annotate templates/templater.cpp @ 0:a4671277546c tip

created the repository for the thymian project
author ferencd
date Tue, 17 Aug 2021 11:19:54 +0200
parents
children
rev   line source
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