Mercurial > thymian
view 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 |
line wrap: on
line source
#include "templater.h" #include "dictionary.h" #ifdef PYTHON_SCRIPTING #include "python_runner.h" #endif #include <algorithm> #include <filesystem> #include <log.h> #include <cwctype> void templater_base::resolve_all_includes(std::string& templatized, bool do_replace) { size_t inc_pos = templatized.find(INCLUDE_TAG); while(inc_pos != std::string::npos) { templatized = resolve_includes(templatized, inc_pos, do_replace); // see if we have pulled in some extra vars if(do_replace) { templatized = stringholder(templatized).templatize(kps).get(); } inc_pos = templatized.find(INCLUDE_TAG); } } std::string templater_base::get(const std::string &template_name) { // Getting the content std::string content = template_warehouse::instance().getTemplateContent(template_name); // Resolve the #define's. This will update the extra_kp's std::string content_without_vars = resolve_defines(content); // resolve the initializer scripts, since they may modify the kps std::string scripts_resolved = resolve_scripts(content_without_vars, INIT_SCRIPT_TAG); // resolve all the top level template arguments std::string templatized = stringholder(scripts_resolved).templatize(kps).get(); // then search for all the {#include 's and: templatize those with the given variable: Value pairs // and include them here bool done = false; while(!done) { // search for structure definitions, there can be more than one size_t struct_pos = templatized.find(STRUCT_TAG); while(struct_pos != std::string::npos) { templatized = resolve_structure_declaration(struct_pos, templatized); struct_pos = templatized.find(STRUCT_TAG); } // search for input data definition hints size_t parameters_pos = templatized.find(PARAMETERS_TAG); if(parameters_pos != std::string::npos) { templatized = resolve_parameters(parameters_pos, templatized); } // search for the "include"'s resolve_all_includes(templatized); // now search for the "if"'s. Remember, ifs cannot have ifs in their body size_t if_pos = templatized.find(IF_TAG); if(if_pos != std::string::npos) { while(if_pos != std::string::npos) { templatized = resolve_ifs(if_pos, templatized); if_pos = templatized.find(IF_TAG); } } else { done = true; } } return templatized; } std::string templater_base::extract_identifier_word(const std::string& input, size_t& i, std::vector<char> separators, std::set<char> extra_allowed_chars, char&& c) { skip_whitespace(input, i); std::string result = ""; while(i < input.length() && (input.at(i) == '_' || extra_allowed_chars.count(input.at(i)) || isalnum(input.at(i))) ) { if(separators.empty()) { result += input.at(i); i++; } else { if(find(separators.begin(), separators.end(), input.at(i)) == separators.end()) { result += input.at(i); i++; } else { if(c != 0) { c = input[i]; } i ++; // skip the actual separator break; } } } skip_whitespace(input, i); if(!separators.empty()) { if(find(separators.begin(), separators.end(), input.at(i)) != separators.end()) { if(c != 0) { c = input[i]; } i++; // this characater is a separator. Skip it. And the space after skip_whitespace(input, i); } } return result; } bool templater_base::check_opening_parenthesis(const std::string& input, size_t& i) { bool opening_parentheses = false; // skip the parenthesis if any if(i < input.length() && input.at(i) == '(') { i ++; skip_whitespace(input, i); opening_parentheses = true; } return opening_parentheses; } bool templater_base::check_closing_comment(const std::string& templatized, size_t& i, std::size_t& include_tag_end_position) { if(i + 3 < templatized.length()) { if(templatized[i+1] == '-' && templatized[i+2] == '-' && templatized[i + 3] == '>') { include_tag_end_position = i + 4; return true; } } return false; } std::string templater_base::get_error() const { return error; } std::vector<std::string> templater_base::variables(bool resolve_includes_too) { std::vector<std::string> result; std::string content = template_warehouse::instance().getTemplateContent(name()); std::string::size_type start_pos = 0; if(resolve_includes_too) { resolve_all_includes(content, false); } while((start_pos = content.find(TEMPLATE_VARIABLE_START_DELIMITER, start_pos)) != std::string::npos) { std::string current_varname = ""; start_pos += TEMPLATE_VARIABLE_START_DELIMITER.length(); while(start_pos < content.length() && content[start_pos] != '}') { current_varname += content[start_pos++]; } if(start_pos == content.length()) { set_error("Unterminated variable name"); return result; } result.push_back(current_varname); start_pos ++; // to skip the closing '}' } return result; } std::string templater_base::resolve_includes(std::string templatized, size_t inc_pos, bool do_variable_replacement) { std::map<std::string, std::string> local_pairs; std::size_t include_tag_end_position = std::string::npos; std::size_t include_tag_start_position = inc_pos; inc_pos += INCLUDE_TAG.length(); std::string inc_template = extract_identifier_word(templatized, inc_pos); bool opening_parentheses = check_opening_parenthesis(templatized, inc_pos); size_t i = inc_pos; bool closing_comment_found = false; while(i < templatized.length() && ! closing_comment_found) { std::string var_name = extract_identifier_word(templatized, i, {':','='}); if(i == templatized.length() || var_name.empty()) { if(templatized[i] == '#' && !closing_comment_found) // This should be the closing comment { check_closing_comment(templatized, i, include_tag_end_position); } break; } // now read the variable value std::string var_value = ""; bool var_value_read = false; while(!var_value_read && i < templatized.length()) { if(templatized[i] == '"') // string starts. Do not read the '"' { i++; // skip the '"' bool string_read = false; while(i < templatized.length() && !string_read) { if(templatized[i] == '\\') // Skip the backslash from the escape sequence { i++; } var_value += templatized[i++]; if(i == templatized.length()) { set_error("String literal is not finished"); break; } if(templatized[i] == '"' && templatized[i-1] != '\\') { string_read = true; } } if(i == templatized.length()) // invalid syntax { set_error("Invalid syntax, could not resolve an include"); break; } i++; // skip closing quote } else { // see if this is a closing parenthesis, but only if there was an opening one if(opening_parentheses && templatized[i] == ')') { var_value_read = true; // now see if there is a closing comment. Everything after it will be ignored while(i < templatized.length() && !closing_comment_found) { i ++; skip_whitespace(templatized, i); if(i < templatized.length() && templatized[i] == '#') // This should be the closing comment { closing_comment_found = check_closing_comment(templatized, i, include_tag_end_position); } } } if(templatized[i] == '#' && !closing_comment_found) // This should be the closing comment { closing_comment_found = var_value_read = check_closing_comment(templatized, i, include_tag_end_position); } if(templatized[i] == '{' && i<templatized.length() && templatized[i + 1] == '#') // The substitution of a variable with another one from this level { // Read in the entire variable and simply change the var_value to the one in our objects' map i+=2; // skip {# std::string upperlevel_var_name = extract_identifier_word(templatized, i, {'}'}); if(i == templatized.length() || upperlevel_var_name.empty()) { break; } if(kps.count(upperlevel_var_name) != 0) { var_value += kps[upperlevel_var_name]; } } // and comma (or space) separatin the variables? if(i < templatized.length() && (templatized[i] == ',' || iswspace(templatized[i])) ) { var_value_read = true; i++; skip_whitespace(templatized, i); } // still not read the value? if(i < templatized.length() && !var_value_read) { var_value += templatized[i++]; } } } skip_whitespace(templatized, i); // now insert into local_pairs the keys and values local_pairs.insert(make_pair(var_name, var_value)); } // and now read in the template from inc_template // and replace everything that is supposed to be replaced std::string inc_content = template_warehouse::instance().getTemplateContent( inc_template ); std::string inc_templatized = do_variable_replacement ? stringholder(inc_content).templatize(local_pairs).get() : inc_content; templatized.erase(include_tag_start_position, include_tag_end_position - include_tag_start_position); templatized.insert(include_tag_start_position, inc_templatized); return templatized; } std::string templater_base::resolve_structure_declaration(size_t struct_pos, std::string templatized) { std::size_t include_tag_start_position = struct_pos; struct_pos += STRUCT_TAG.length(); std::string struct_name = extract_identifier_word(templatized, struct_pos); bool opening_parentheses = check_opening_parenthesis(templatized, struct_pos); add_structure_decl(struct_name, struct_name); // and now read in the structure members' names size_t i = struct_pos; bool closing_comment_found = false; std::size_t include_tag_end_position = std::string::npos; while (i < templatized.length() && !closing_comment_found) { std::string member_name = ""; while(i < templatized.length() && (isalnum(templatized[i]) || templatized[i] == '_')) { member_name += templatized[i++]; } if(member_name.empty()) // syntax error, just give back what came out { set_error("Invalid syntax, could not resolve a structure declaration"); return templatized; } skip_whitespace(templatized, i); // var_name now is the name of the structure's member, make it // a default value get_structure(struct_name)[member_name] = ""; // now this should point either to a space or a "," i++; // se if we have a "," coming up if(templatized[i] == ',') { i ++; skip_whitespace(templatized, i); } // see if this is a closing parenthesis, but only if there was an opening one if(opening_parentheses && templatized[i] == ')') { // now see if there is a closing comment. Everything after it will be ignored while(i < templatized.length() && !closing_comment_found) { i ++; skip_whitespace(templatized, i); if(i < templatized.length() && templatized[i] == '#') // This should be the closing comment { closing_comment_found = check_closing_comment(templatized, i, include_tag_end_position); } } } if(templatized[i] == '#' && !closing_comment_found) // This should be the closing comment { closing_comment_found = check_closing_comment(templatized, i, include_tag_end_position); } } templatized.erase(include_tag_start_position, include_tag_end_position - include_tag_start_position); return templatized; } templater_base &templater_base::templatize(const template_struct &s) { precalculated = ""; std::string templatized = get(); // will initialize the parameters if(!m_parameters.empty()) { for(const auto &p : m_parameters) { if(p.first == s.name) { for(const auto &x : s.struct_members) { std::string fullname = s.name + "." + x.first; kps.insert(make_pair(fullname, unafrog::utils::to_string(x.second))); } } } } templatized = stringholder(templatized).templatize(kps).get(); templatized = resolve_ifeqs(templatized); templatized = resolve_scripts(templatized, SCRIPT_TAG); precalculated = templatized; return *this; } std::string templater_base::resolve_loops(std::string templatized, const template_vector_par &v) { size_t loop_pos = templatized.find(LOOP_TAG); while(loop_pos != std::string::npos) { // find the stuff between the iterate and end iterate tags std::size_t loop_tag_end_position = std::string::npos; std::size_t loop_tag_start_position = loop_pos; loop_pos += LOOP_TAG.length(); // see on what are we iterating through std::string loop_target = extract_identifier_word(templatized, loop_pos); // there should be nothing more after this if(!check_closing_comment(templatized, loop_pos, loop_tag_end_position)) { return templatized; } // now find the end iterate tag size_t end_loop_pos = templatized.find(ENDLOOP_TAG, loop_tag_end_position); size_t save_endpos = end_loop_pos; end_loop_pos += ENDLOOP_TAG.length(); size_t endloop_endpos = std::string::npos; size_t temp = end_loop_pos; while(temp != std::string::npos) { size_t unused = temp; std::string endloop_target = extract_identifier_word(templatized, unused); if(endloop_target == loop_target) { if(!check_closing_comment(templatized, unused, endloop_endpos)) { return templatized; } break; } temp = templatized.find(ENDLOOP_TAG, temp); save_endpos = temp; temp += ENDLOOP_TAG.length(); } // now between loop_tag_end_position and save_endpos there is the strign we need std::string loop_content = templatized.substr(loop_tag_end_position, save_endpos - loop_tag_end_position); std::string final_loop_content = ""; // and now insert a bunch of kps for the elements in v if(!m_parameters.empty()) { size_t c = 0; for(const auto &ts : v.value()) { c++; for(const auto& p : m_parameters) { if(p.first == v.name()) { stringholder sh(loop_content); for(const auto &x : ts.struct_members) { //if(x.first == loop_target) { std::string fullname = v.name() + "." + x.first; std::string fullname_to_replace_with = v.name() + "." + x.first + ":" + std::to_string(c); kps.insert(make_pair(fullname_to_replace_with, unafrog::utils::to_string(x.second))); sh.replace_all(TEMPLATE_VARIABLE_START_DELIMITER + fullname +TEMPLATE_VARIABLE_END_DELIMITER, TEMPLATE_VARIABLE_START_DELIMITER + fullname_to_replace_with + TEMPLATE_VARIABLE_END_DELIMITER); } } final_loop_content += sh.get(); } } } } // now fetch out the substring (loop_tag_end_position, save_endpos - loop_tag_end_position) from templatized // and replace with final_loop_content if(v.name() == loop_target) { std::string part1 = templatized.substr(0, loop_tag_end_position); part1.erase(loop_tag_start_position, loop_tag_end_position - loop_tag_start_position); part1 += final_loop_content; part1 += templatized.substr(endloop_endpos); templatized = part1; loop_pos = templatized.find(LOOP_TAG); } else { loop_pos = templatized.find(LOOP_TAG, endloop_endpos); } } templatized = stringholder(templatized).templatize(kps).get(); precalculated = templatized; return templatized; } std::string templater_base::resolve_ifeqs(std::string templatized) { bool done = false; while(!done) { size_t ifeq_pos = templatized.find(IFEQ_TAG); if(ifeq_pos != std::string::npos) { while(ifeq_pos != std::string::npos) { templatized = resolve_ifeq(ifeq_pos, templatized); ifeq_pos = templatized.find(IFEQ_TAG); } } else { done = true; } } return templatized; } 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) { bool done = false; while(!done) { size_t ifeq_pos = templatized.find(TRANSLATE_TAG); if(ifeq_pos != std::string::npos) { while(ifeq_pos != std::string::npos) { std::map<std::string, std::string> local_translations; std::string span_id; templatized = resolve_translation(ifeq_pos, templatized, target_language, generate_span, span_id, local_translations); translations[span_id] = local_translations; ifeq_pos = templatized.find(TRANSLATE_TAG); } } else { done = true; } } return templatized; } static std::string span_name(std::string str) { str.erase(std::remove_if(str.begin(), str.end(), isspace), str.end()); return "span_" + str; } 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) { size_t i = tr_pos; // skip the <!--#translate i += TRANSLATE_TAG.length(); // and any whitespace that might follow skip_whitespace(templatized, i); size_t translateable_start = i; // now extract the word to translate if(i < templatized.length()) { char c_sep = 32; std::string what_to = extract_identifier_word(templatized, i, {'#'}, {' ', ',', '.', '!', '?', ':', ':'}, std::move(c_sep)); skip_whitespace(templatized, i); std::string before_translate = templatized.substr(0, tr_pos); std::string between = templatized.substr(translateable_start, what_to.length()); std::string after_translate = templatized.substr(translateable_start + what_to.length() + 4); span_id = span_name(between); templatized = before_translate + (generate_span ? "<span id='" + span_id + "'>" : "") + dictionary::translate(between, target_language, true, translations) +(generate_span ? "</span>" : "") + after_translate; } return templatized; } templater_base &templater_base::templatize(const template_vector_par &v) { do_not_resolve_in_get(); std::string templatized = precalculated.empty() ? get() : precalculated; do_resolve_in_get(); templatized = resolve_loops(templatized, v); templatized = resolve_ifeqs(templatized); templatized = resolve_scripts(templatized, SCRIPT_TAG); precalculated = templatized; return *this; } void templater_base::skip_whitespace(const std::string& templatized, size_t& i) { while(i < templatized.length() && std::iswspace(templatized[i])) { i++; } } std::string templater_base::resolve_parameters(size_t parameters_pos, std::string templatized) { std::size_t include_tag_end_position = std::string::npos; std::size_t include_tag_start_position = parameters_pos; parameters_pos += PARAMETERS_TAG.length(); skip_whitespace(templatized, parameters_pos); size_t i = parameters_pos; bool closing_comment_found = false; while(i < templatized.length() && ! closing_comment_found) { // first: read in the variable name char c_sep = 32; std::string var_name = extract_identifier_word(templatized, i, {':', ' '}, {}, static_cast<char&&>(c_sep)); if(i == templatized.length() || var_name.empty()) { return templatized; } std::string var_type = ""; bool iterable = false; if(c_sep == ':') { // now read the variable type var_type = extract_identifier_word(templatized, i); if(i < templatized.length() && templatized[i] == '[') { i ++; skip_whitespace(templatized, i); if(i < templatized.length() && templatized[i] == ']') { i ++; } iterable = true; } } add_parameter(var_name, var_type, iterable); skip_whitespace(templatized, i); // se if we have a "," coming up if(templatized[i] == ',') { i ++; skip_whitespace(templatized, i); } if(templatized[i] == '#') // This should be the closing comment { closing_comment_found = check_closing_comment(templatized, i, include_tag_end_position); } } templatized.erase(include_tag_start_position, include_tag_end_position - include_tag_start_position); return templatized; } std::string templater_base::resolve_ifs(size_t if_pos, std::string templatized) { size_t i = if_pos; // skip the <!--#if i += IF_TAG.length(); // and any whitespace that might follow skip_whitespace(templatized, i); // now extract the variable if(i < templatized.length()) { char c_sep = 32; std::string var_name = extract_identifier_word(templatized, i, {' ', '#'}, {}, std::move(c_sep)); skip_whitespace(templatized, i); std::string var_value = ""; // now if var_name is empty remove the if and it's body. if(kps.count(var_name)) { var_value = kps[var_name]; } std::string closing_endif_tag = ENDIF_TAG + " " + var_name; std::string closing_else_tag = ELSE_TAG + " " + var_name; if(var_value.empty()) { // search for the first <!--#endif var_name size_t endif_pos = templatized.find(closing_endif_tag); if(endif_pos != std::string::npos) { // search for the first <!--#else before the endif tag size_t else_pos = templatized.find(closing_else_tag); if(else_pos < endif_pos) { // this is the else of this if, removing the content of the if till the else templatized = templatized.substr(0, if_pos) + templatized.substr(else_pos + closing_else_tag.length() + 4); // we still need to remove the endif size_t final_endif_pos = templatized.find(closing_endif_tag); if(final_endif_pos != std::string::npos) { templatized = templatized.substr(0, final_endif_pos) + templatized.substr(final_endif_pos + closing_endif_tag.length() + 4); } } else { // no else, just remove the if tag templatized = templatized.substr(0, if_pos) + templatized.substr(endif_pos + closing_endif_tag.length() + 4); } } else { // oops, user forgot the enclosing endif, just return what is here return templatized; } } else // remove the comments :) { size_t endif_pos = templatized.find(closing_endif_tag); if(endif_pos != std::string::npos) { size_t remove_start_pos = endif_pos; std::string remove_tag = closing_endif_tag; size_t additional_remove = 0; // count ofchars between else and endif // search for the first <!--#else before the endif tag size_t else_pos = templatized.find(closing_else_tag); if(else_pos < endif_pos) { remove_start_pos = else_pos; additional_remove = endif_pos - remove_start_pos; } std::string before_if = templatized.substr(0, if_pos); std::string between = templatized.substr(i + 3, remove_start_pos - i - 3); std::string after_endif = templatized.substr(remove_start_pos + additional_remove + closing_endif_tag.length() + 4); templatized = before_if + between + after_endif; } else { // oops, user forgot the enclosing endif, just return what is here return templatized; } } } return templatized; } std::string templater_base::resolve_ifeq(size_t if_pos, std::string templatized) { size_t i = if_pos; // skip the <!--#ifeq i += IFEQ_TAG.length(); // and any whitespace that might follow skip_whitespace(templatized, i); // now extract the variable if(i < templatized.length()) { char c_sep = 32; std::string what_to = extract_identifier_word(templatized, i, {' ', '#'}, {',','-'}, std::move(c_sep)); skip_whitespace(templatized, i); size_t comma_pos = what_to.find(','); bool are_eq = true; if(comma_pos == std::string::npos) { are_eq = false; } else { std::string before = what_to.substr(0, comma_pos); std::string after = what_to.substr(comma_pos + 1); are_eq = before == after; } if(!are_eq) { // search for the first <!--#endifeq size_t endif_pos = templatized.find(ENDEQ_TAG); if(endif_pos != std::string::npos) { templatized = templatized.substr(0, if_pos) + templatized.substr(endif_pos + ENDEQ_TAG.length() + 4); } } else // remove the comments :) { size_t endif_pos = templatized.find(ENDEQ_TAG); if(endif_pos != std::string::npos) { size_t remove_start_pos = endif_pos; std::string before_if = templatized.substr(0, if_pos); std::string between = templatized.substr(i + 3, remove_start_pos - i - 3); std::string after_endif = templatized.substr(remove_start_pos + ENDEQ_TAG.length() + 4); templatized = before_if + between + after_endif; } } } return templatized; } std::string templater_base::resolve_defines(std::string content) { size_t define_pos = content.find(DEFINE_TAG); std::vector<std::pair<size_t, size_t>> strings_to_remove; // we will remove the define tags from in here if(define_pos != std::string::npos) { while(define_pos != std::string::npos) { bool define_read = false; // skipping the tag size_t i = define_pos + DEFINE_TAG.length(); // skipping the whitespace after the tag skip_whitespace(content, i); while(!define_read) { std::string var_name = ""; std::string var_value = ""; // now comes a list of comma separated variable=value assignments or just simply variable while(i < content.length() && content[i] != '=' && content[i] != ',' && content[i] != '#' && (isalnum(content[i]) || content[i] == '_' )) { var_name += content[i]; i ++; } // now if content[i] == '=' we need to parse out the value from it if(content[i] == '=') { i ++; bool string_comes = false; if(content[i] == '"') // string comes after this? { i++; string_comes = true; } while( (i < content.length() && content[i] != ',' && content[i] != '#' && !string_comes) || (i < content.length() && string_comes && content[i] != '"')) { if(content[i] != '\\') // escaping a quote in the string { var_value += content[i]; } else { i++; var_value += content[i]; } i++; } } else { var_value = "true"; } kps.insert({var_name, var_value}); if(content[i] == '#') { i++; if(i + 2 < content.length() && content[i] == '-' && content[i+1] == '-' && content[i+2]=='>') { i += 3; // skip the closing comment define_read = true; } else { // this is a malformed entry, just give up return content; } } else { if(content[i] == ',') { i++; } } } strings_to_remove.insert(strings_to_remove.begin(), {define_pos, i}); define_pos = content.find(DEFINE_TAG, i); } } // now walk through the strings_to_remove and delete from the content everything from there for(const auto& beg_end_pos : strings_to_remove) { content.erase(beg_end_pos.first, beg_end_pos.second - beg_end_pos.first); } return content; } std::string templater_base::resolve_scripts(std::string templatized, const std::string& tag) { bool done = false; while(!done) { size_t script_tag_pos = templatized.find(tag); if(script_tag_pos != std::string::npos) { while(script_tag_pos != std::string::npos) { templatized = resolve_script(script_tag_pos, templatized, tag); script_tag_pos = templatized.find(tag); } } else { done = true; } } return templatized; } std::string templater_base::resolve_script(size_t pos, const std::string& content, const std::string &tag) { size_t endscript_start_pos = content.find(ENDSCRIPT_TAG); size_t old_pos = pos; // skip the tag pos += tag.length(); // skip the space(s) followwing the "script" while(isspace(content[pos])) pos += 1; std::string script_type = ""; while(pos < content.length() && content[pos] != '#' && content[pos] != ':') { script_type += content[pos++]; } if(pos == content.length()) { set_error("Script tag at", old_pos, "is not closed"); return content.substr(0, old_pos); } static const auto script_types = {"python"}; bool found = false; for(const auto& st : script_types) { if(st == script_type) found = true; } if(!found) { set_error("Unsupported scripting language", script_type); return content.substr(0, old_pos); } // pos points to the script closing tag std::string before_script = content.substr(0, old_pos); std::string between = std::string(content.begin() + pos + 4, // #--> is the 4 content.begin() + endscript_start_pos); std::string after_script = content.substr(endscript_start_pos + ENDSCRIPT_TAG.length() + 4); std::string result = python_runner().run(kps, between, variables(true)); return before_script + unafrog::utils::trim(result) + after_script; } void stringholder::replace_all(const std::string &from, const std::string &to) { if(from.empty()) { return; } size_t start_pos = 0; while((start_pos = str.find(from, start_pos)) != std::string::npos) { str.replace(start_pos, from.length(), to); start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx' } } stringholder &stringholder::templatize(const std::map<std::string, std::string> &m) { for(auto it = m.begin(); it != m.end(); ++ it) { replace_all(TEMPLATE_VARIABLE_START_DELIMITER + it->first + TEMPLATE_VARIABLE_END_DELIMITER, it->second ); } return *this; } template_warehouse &template_warehouse::instance() { static template_warehouse twh; return twh; } bool template_warehouse::checkTemplates() { for(auto it = templates.begin(); it != templates.end(); ++it) { if(!it->second->check()) { return false; } } debug() << "All templates OK"; return true; } std::string template_warehouse::getTemplateContent(const std::string &templateName) { if(templates.count(templateName)) { std::shared_ptr<template_base> tb = templates[templateName]; std::string c = tb->content(); return c; } else { return "Not found:" + templateName; } } bool template_warehouse::registerTemplate(const std::string &name, template_base *templateClass) { // although this code seems stupid, it is due to the fact that every inclusion of the // templater.h will cause a new object to be created, but we want only one if(templates.count(name)) { debug() << "Freeing existing template class:" << name; delete templateClass; return false; } debug() << "Registering template class:" << name; templates[name] = std::shared_ptr<template_base>(templateClass); return true; } std::string file_template::base_dir() const { namespace fs = std::filesystem; if(fs::is_regular_file(fileName())) { return ""; } else { return TEMPLATES_DIRECTORY; } } std::string file_template::content() const { std::string fn = base_dir() + fileName(); std::ifstream ifs(fn); std::string s( (std::istreambuf_iterator<char>(ifs) ), (std::istreambuf_iterator<char>()) ); return s; } bool file_template::check() const { struct stat buffer; bool res = (stat ( (base_dir() + fileName()).c_str(), &buffer) == 0); if(!res) { debug() << "Check for "<< fileName() << " failed"; } return res; }
