From 581a4620de476d4291dbaf73e249468f3c9fc4b8 Mon Sep 17 00:00:00 2001 From: Andreev Gregory Date: Sat, 10 Aug 2024 23:56:07 +0300 Subject: [PATCH] Daily saving of progress --- building/main.cpp | 33 +++- .../engine_engine_number_9/baza.cpp | 12 +- src/http_server/engine_engine_number_9/baza.h | 4 - .../static_asset_manager.cpp | 4 +- .../engine_engine_number_9/os_utils.cpp | 2 +- .../new_york_transit_line/alotalot.cpp | 58 +++++++ .../new_york_transit_line/alotalot.h | 43 +++++ src/http_server/new_york_transit_line/core.h | 28 ++++ .../execute_expression.cpp | 44 ++++++ .../new_york_transit_line/html_case.cpp | 30 ++++ .../new_york_transit_line/html_case.h | 10 ++ .../new_york_transit_line/parser.cpp | 88 +++++++++++ .../new_york_transit_line/rendering.cpp | 98 ++++++++++++ .../new_york_transit_line/templater.cpp | 149 ++++++++++++++++++ .../new_york_transit_line/templater.h | 86 ++++++++++ 15 files changed, 671 insertions(+), 18 deletions(-) create mode 100644 src/http_server/new_york_transit_line/alotalot.cpp create mode 100644 src/http_server/new_york_transit_line/alotalot.h create mode 100644 src/http_server/new_york_transit_line/core.h create mode 100644 src/http_server/new_york_transit_line/execute_expression.cpp create mode 100644 src/http_server/new_york_transit_line/html_case.cpp create mode 100644 src/http_server/new_york_transit_line/html_case.h create mode 100644 src/http_server/new_york_transit_line/parser.cpp create mode 100644 src/http_server/new_york_transit_line/rendering.cpp create mode 100644 src/http_server/new_york_transit_line/templater.cpp create mode 100644 src/http_server/new_york_transit_line/templater.h diff --git a/building/main.cpp b/building/main.cpp index 241d527..f591287 100644 --- a/building/main.cpp +++ b/building/main.cpp @@ -108,10 +108,39 @@ struct CAWebChat { T.installation_dir = ""; my_targets.push_back(T); } + { CTarget T{"new_york_transit_line", "shared_library"}; + T.additional_compilation_flags = getSomeRadFlags(); + T.external_deps = { + CTargetDependenceOnExternalLibrary{"libjsonincpp", {true, true}}, + }; + T.units = { + "alotalot.cpp", + "execute_expression.cpp", + "html_case.cpp", + "parser.cpp", + "rendering.cpp", + "templater.cpp", + }; + for (std::string& u: T.units) + u = "http_server/new_york_transit_line/" + u; + T.include_pr = "http_server"; + T.exported_headers = { + "templater.h", + "html_case.h", + }; + for (std::string& u: T.exported_headers) + u = "new_york_transit_line/" + u; + my_targets.push_back(T); + } { CTarget T{"iu9-ca-web-chat", "executable"}; T.additional_compilation_flags = getSomeRadFlags(); - T.proj_deps = {CTargetDependenceOnProjectsLibrary{"engine_engine_number_9"}}; - T.external_deps = {CTargetDependenceOnExternalLibrary{"sqlite3"}}; + T.proj_deps = { + CTargetDependenceOnProjectsLibrary{"engine_engine_number_9"}, + CTargetDependenceOnProjectsLibrary{"new_york_transit_line"}, + }; + T.external_deps = { + CTargetDependenceOnExternalLibrary{"sqlite3"} + }; T.units = {"main.cpp"}; for (std::string& u: T.units) u = "web_chat/" + u; diff --git a/src/http_server/engine_engine_number_9/baza.cpp b/src/http_server/engine_engine_number_9/baza.cpp index 8116cc7..dec371c 100644 --- a/src/http_server/engine_engine_number_9/baza.cpp +++ b/src/http_server/engine_engine_number_9/baza.cpp @@ -5,15 +5,9 @@ #include namespace een9 { - ServerError::ServerError(const std::string &err, const std::string &file, const std::string &func, int line): err(err), - FILE(file), - func(func), - LINE(line) { - char buf[4096]; - snprintf(buf, 4096, "Error occured in function %s (line %d of %s)\n" - "Error: %s", - func.c_str(), LINE, FILE.c_str(), err.c_str()); - WHAT = buf; + ServerError::ServerError(const std::string &err, const std::string &file, const std::string &func, int line){ + WHAT = "Error occured in function " + func + " (line " + std::to_string(line) + " of " + + file + ")\nError: " + err; } const char * ServerError::what() const noexcept { diff --git a/src/http_server/engine_engine_number_9/baza.h b/src/http_server/engine_engine_number_9/baza.h index eb0d1c0..ef6b868 100644 --- a/src/http_server/engine_engine_number_9/baza.h +++ b/src/http_server/engine_engine_number_9/baza.h @@ -6,10 +6,6 @@ namespace een9 { class ServerError : public std::exception{ - std::string err; - std::string FILE; - std::string func; - int LINE; std::string WHAT; public: diff --git a/src/http_server/engine_engine_number_9/connecting_assets/static_asset_manager.cpp b/src/http_server/engine_engine_number_9/connecting_assets/static_asset_manager.cpp index 4688b3e..12bbea6 100644 --- a/src/http_server/engine_engine_number_9/connecting_assets/static_asset_manager.cpp +++ b/src/http_server/engine_engine_number_9/connecting_assets/static_asset_manager.cpp @@ -23,9 +23,9 @@ namespace een9 { ASSERT_on_iret(ret, "stat(\"" + cur + "\")"); if (S_ISDIR(info.st_mode)) { DIR* D = opendir(path_to_cur_ent.c_str()); - cur += "/"; - ASSERT(D != NULL, prettyprint_errno("opendir(\"" + cur +"\")")); struct Guard1{ DIR*& D; ~Guard1(){ closedir(D); } } g1{D}; + ASSERT(D != NULL, prettyprint_errno("opendir(\"" + cur +"\")")); + cur += "/"; while (true) { errno = 0; struct dirent* Dent = readdir(D); diff --git a/src/http_server/engine_engine_number_9/os_utils.cpp b/src/http_server/engine_engine_number_9/os_utils.cpp index d6111dc..cc14d30 100644 --- a/src/http_server/engine_engine_number_9/os_utils.cpp +++ b/src/http_server/engine_engine_number_9/os_utils.cpp @@ -55,7 +55,7 @@ namespace een9 { while ((ret = (int)read(fd, buf, 2048)) > 0) { size_t oldN = result.size(); result.resize(oldN + ret); - memcpy(&result[oldN], buf, ret); + memcpy((void*)&result.c_str()[oldN], buf, ret); } ASSERT_on_iret(ret, "Reading from " + description); } diff --git a/src/http_server/new_york_transit_line/alotalot.cpp b/src/http_server/new_york_transit_line/alotalot.cpp new file mode 100644 index 0000000..ad6b8c8 --- /dev/null +++ b/src/http_server/new_york_transit_line/alotalot.cpp @@ -0,0 +1,58 @@ +#include "alotalot.h" + +#include +#include +#include + +namespace nytl { + FUp::FUp(const std::string &err, const std::string &file, const std::string &func, int line){ + WHAT = "Error occured in function " + func + " (line " + std::to_string(line) + " of " + + file + ")\nError: " + err; + } + + const char * FUp::what() const noexcept { + return WHAT.c_str(); + } + + std::string prettyprint_errno(const std::string &pref) { + const char* d = strerrorname_np(errno); + return pref.empty() ? std::string(d) : std::string(pref) + ": " + d; + } + + bool endsIn(const std::string &a, const std::string &b) { + if (b.size() > a.size()) + return false; + return std::equal(a.end() - (ssize_t)b.size(), a.end(), b.begin()); + } + + std::string throwout_postfix(const std::string &a, size_t bsz) { + return a.substr(0, a.size() >= bsz ? a.size() - bsz : 0); + } + + bool isALPHA(char ch) { + return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z'); + } + + bool isNUM(char ch) { + return '0' <= ch && ch <= '9'; + } + + bool isUNCHAR(char ch) { + return isALPHA(ch) || isNUM(ch) || ch == '-' || ch == '_'; + } + + bool isSPACE(char ch) { + return ch == ' ' || ch == '\r' || ch == '\t' || ch == '\r'; + } + + bool isUname(const std::string &str) noexcept { + if (str.empty() || str == "_") + return false; + if (isNUM(str[0])) + return false; + for (char ch: str) + if (!isUNCHAR(ch)) + return false; + return true; + } +} diff --git a/src/http_server/new_york_transit_line/alotalot.h b/src/http_server/new_york_transit_line/alotalot.h new file mode 100644 index 0000000..36ea1dc --- /dev/null +++ b/src/http_server/new_york_transit_line/alotalot.h @@ -0,0 +1,43 @@ +#ifndef NEW_YORK_TRANSIT_LINE_ALOTALOT_H +#define NEW_YORK_TRANSIT_LINE_ALOTALOT_H + +/* A little of this, a little of that + * DO NOT EXPORT THIS FILE */ + +#include +#include + +namespace nytl { + template + using uptr = std::unique_ptr; + + class FUp : public std::exception{ + std::string WHAT; + public: + FUp(const std::string &err, const std::string &file, const std::string &func, int line); + + const char *what() const noexcept override; + }; + + std::string prettyprint_errno(const std::string& pref); +#define THROW(err) throw FUp(err, __FILE__, __func__, __LINE__) +#define THROW_on_errno(err) THROW(prettyprint_errno(err)) +#define THROW_on_errno_pl() THROW(prettyprint_errno("")) +#define ASSERT(cond, err) do { if (!(cond)) { THROW(err); } } while (0); +#define ASSERT_pl(cond) ASSERT(cond, "Failed assertion `" #cond "`") +#define ASSERT_on_iret(iret, err) ASSERT((iret) >= 0, prettyprint_errno(err)); +#define ASSERT_on_iret_pl(iret) ASSERT(iret >= 0, prettyprint_errno("")); + + bool endsIn(const std::string& a, const std::string& b); + + std::string throwout_postfix(const std::string& a, size_t bsz); + + bool isALPHA(char ch); + bool isNUM(char ch); + bool isUNCHAR(char ch); + bool isSPACE(char ch); + + bool isUname(const std::string& str) noexcept; +} + +#endif diff --git a/src/http_server/new_york_transit_line/core.h b/src/http_server/new_york_transit_line/core.h new file mode 100644 index 0000000..ff2f157 --- /dev/null +++ b/src/http_server/new_york_transit_line/core.h @@ -0,0 +1,28 @@ +#ifndef NEW_YORK_TRANSIT_LINE_CORE_H +#define NEW_YORK_TRANSIT_LINE_CORE_H + +#include "templater.h" +#include + +namespace nytl { + void parse_bare_file(const std::string& filename, const std::string& content, + global_elem_set_t& result); + void parse_special_file(const std::string& filename, const std::string& content, + global_elem_set_t& result); + + struct LocalVarValue { + bool is_json = false; + std::string EL_name; + const json::JSON* JSON_subval = NULL; + }; + + /* No new JSON object will ever be created, I have one root json argument, + * all the other json variables are subtrees of it */ + LocalVarValue rendering_core_execute_expression(global_elem_set_t& global_elems, + const std::vector& local_vars, json::JSON& expr); + + std::string rendering_core(const std::string& entry_func, const std::vector& entry_arguments, + std::map& elem_ns, const std::function& escape); +} + +#endif diff --git a/src/http_server/new_york_transit_line/execute_expression.cpp b/src/http_server/new_york_transit_line/execute_expression.cpp new file mode 100644 index 0000000..9d4f538 --- /dev/null +++ b/src/http_server/new_york_transit_line/execute_expression.cpp @@ -0,0 +1,44 @@ +#include "core.h" +#include "alotalot.h" +#include + +namespace nytl { + struct Frame { + json::JSON& expr; + LocalVarValue& result; + LocalVarValue temp_ret; + size_t chain_el = 0; + + Frame(json::JSON &expr, LocalVarValue &result) + : expr(expr), + result(result) { + } + + uptr toMe(bool returned_from_bottom, global_elem_set_t& global_elems, + const std::vector& local_vars) { + if (returned_from_bottom) { + ASSERT(temp_ret.is_json, "Expression \"[ element ]\" is not allowed"); + assert(temp_ret.JSON_subval); + // json::JSON + // todo: make usable const JSON + } else { + assert(expr.isDictionary()); + if ((*expr["V"]).isInteger()) { + size_t lv_ind = (*expr["V"]).asInteger().get_int(); + assert(lv_ind < local_vars.size()); + result = local_vars[lv_ind]; + } else if ((*expr["V"]).isString()) { + std::string cur_el_name_str = (*expr["V"]).asString(); + result = LocalVarValue{false, cur_el_name_str, NULL}; + } else + assert(false); + } + if (chain_el == (*expr["C"]).) + } + }; + + LocalVarValue rendering_core_execute_expression(global_elem_set_t& global_elems, + const std::vector& local_vars, json::JSON& expr) { + + } +} diff --git a/src/http_server/new_york_transit_line/html_case.cpp b/src/http_server/new_york_transit_line/html_case.cpp new file mode 100644 index 0000000..5e356fd --- /dev/null +++ b/src/http_server/new_york_transit_line/html_case.cpp @@ -0,0 +1,30 @@ +#include "html_case.h" + +namespace nytl { + std::string html_case_espace_string(const std::string &inp) { + std::string res; + res.reserve(inp.size()); + for (char ch: inp) { + switch (ch) { + case '&': + res += "&"; + break; + case '<': + res += "<"; + break; + case '>': + res += ">"; + break; + case '"': + res += """; + break; + case '\'': + res += "'"; + break; + default: + res += ch; + } + } + return res; + } +} \ No newline at end of file diff --git a/src/http_server/new_york_transit_line/html_case.h b/src/http_server/new_york_transit_line/html_case.h new file mode 100644 index 0000000..7070c39 --- /dev/null +++ b/src/http_server/new_york_transit_line/html_case.h @@ -0,0 +1,10 @@ +#ifndef NEW_YORK_TRANSIT_LINE_HTML_CASE_H +#define NEW_YORK_TRANSIT_LINE_HTML_CASE_H + +#include + +namespace nytl { + std::string html_case_espace_string(const std::string &inp); +} + +#endif diff --git a/src/http_server/new_york_transit_line/parser.cpp b/src/http_server/new_york_transit_line/parser.cpp new file mode 100644 index 0000000..303c9d8 --- /dev/null +++ b/src/http_server/new_york_transit_line/parser.cpp @@ -0,0 +1,88 @@ +#include "core.h" +#include "alotalot.h" +#include +#include + +namespace nytl { + size_t first_nw_char(const std::string& str) { + size_t i = 0; + for (; i < str.size(); i++) + if (!isSPACE(str[i])) + break; + return i; + } + + bool is_space_only(const std::string& str) { + return first_nw_char(str) == str.size(); + } + + void rstrip(std::string& str) { + while (!str.empty() && isSPACE(str.back())) + str.resize(str.size() - 1); + } + + void parse_bare_file(const std::string& filename, const std::string& content, + std::map& result) + { + ASSERT(result.count(filename) == 0, "Repeated element " + filename); + std::vector lines; + bool had_nw_line = false; + size_t smallest_tab; + std::string current_line; + auto finish = [&]() { + size_t tab_sz = first_nw_char(current_line); + if (tab_sz == current_line.size()) { + if (had_nw_line) + lines.emplace_back(); + } else { + if (had_nw_line) { + if (smallest_tab > tab_sz) + smallest_tab = tab_sz; + } else { + smallest_tab = tab_sz; + had_nw_line = true; + } + rstrip(current_line); + lines.push_back(current_line); + } + current_line.clear(); + }; + for (char ch: content) { + if (ch == '\n') { + finish(); + } else { + current_line += ch; + } + } + finish(); + while (!lines.empty() && lines.back().empty()) + lines.pop_back(); + + for (std::string& line: lines) { + if (!line.empty()) { + assert(line.size() > smallest_tab); + line = line.substr(smallest_tab); + } + } + Element& el = result[filename]; + el.parts = {ElementPart{element_part_types::code}}; + // std::string concatenated = ""; + // el.parts[0].when_code.lines = std::move(lines); + std::string lines_cat; + // todo: concatenate lines + size_t n = lines.size(); + for (size_t i = 0; i < n; i++) { + lines_cat += lines[i]; + if (i + 1 < n) + lines_cat += '\n'; + } + json::JSON a; + json::JSON b; + } + + void parse_special_file(const std::string& filename, const std::string& content, + std::map& result) + { + // todo + } +} diff --git a/src/http_server/new_york_transit_line/rendering.cpp b/src/http_server/new_york_transit_line/rendering.cpp new file mode 100644 index 0000000..f591fa9 --- /dev/null +++ b/src/http_server/new_york_transit_line/rendering.cpp @@ -0,0 +1,98 @@ +#include "core.h" +#include "alotalot.h" +#include +#include +#include + +namespace nytl { + std::string rendering_core(const std::string& entry_func, const std::vector& entry_arguments, + std::map& elem_ns, const std::function& escape) + { + size_t cur_line_width = 0; + std::string result; + + struct Frame { + const Element* el = NULL; + /* Use by base elements to distinguish them */ + std::string base_name; + size_t part_to_do = 0; + std::vector passed_args; + /* This parameter incapsulates `cur_line_width` at some point for multiline `put-parts` */ + size_t multiline_put_start = 0; + }; + std::vector> stack; + + auto make_frame = [&](const std::string& name, std::vector passed_args){ + const Element* el = &elem_ns[name]; + Frame* us = new Frame{el, el->base ? name : "", 0, std::move(passed_args), cur_line_width}; + stack.push_back(uptr(us)); + }; + + ASSERT(elem_ns.count(entry_func) == 1, "No such element " + entry_func); + const Element& el = elem_ns[entry_func]; + ASSERT(el.arguments.size() == entry_arguments.size(), "Signature mismatch " + entry_func); + for (const json::JSON& sigtbj: el.arguments) { + ASSERT(sigtbj.type == json::true_symbol, "Signature mismatch. Entry element can take only JSON arguments"); + } + { + size_t AN = entry_arguments.size(); + std::vector entry_arguments_conv(AN); + for (size_t i = 0; i < AN; i++) + entry_arguments_conv[i] = {"", &entry_arguments[i]}; + make_frame(entry_func, entry_arguments_conv); + } + auto append2res = [&](const std::string& text) { + size_t n = result.size(); + result.resize(n + text.size()); + memcpy((void*)&result.c_str()[n], text.c_str(), text.size()); + for (char ch: text) { + if (ch == '\n') + cur_line_width = 0; + else + cur_line_width++; + } + }; + auto linefeed2res = [&]() { + result += "\n"; + cur_line_width = 0; + }; + while (!stack.empty()) { + Frame& cur = *stack.back(); + if (cur.el->base) { + assert(cur.passed_args.size() == 1); + const json::JSON* X = cur.passed_args[0].JSON_subval; + assert(X); + if (cur.base_name == "jesc") { + append2res(escape(json::generate_str(*X, json::print_pretty))); + } else if (cur.base_name == "str2text") { + ASSERT(X->isString(), "str2text takes json string"); + append2res(escape(X->asString())); + } else if (cur.base_name == "str2code") { + ASSERT(X->isString(), "str2code takes json string"); + append2res(X->asString()); + } + stack.pop_back(); + continue; + } + if (cur.part_to_do == cur.el->parts.size()) { + stack.pop_back(); + continue; + } + const ElementPart& cur_part = cur.el->parts[cur.part_to_do++]; + if (cur_part.type == element_part_types::code) { + const ElementPart::when_code_S& pt = cur_part.when_code; + append2res(pt.lines); + } else if (cur_part.type == element_part_types::put) { + const ElementPart::when_put_S& pt = cur_part.when_put; + // todo + } else if (cur_part.type == element_part_types::for_put) { + const ElementPart::when_for_put_S& pt = cur_part.when_for_put; + // todo + } else if (cur_part.type == element_part_types::ref_put) { + const ElementPart::when_ref_put_S& pt = cur_part.when_ref_put; + // todo + } + } + return result; + } +} diff --git a/src/http_server/new_york_transit_line/templater.cpp b/src/http_server/new_york_transit_line/templater.cpp new file mode 100644 index 0000000..afe157f --- /dev/null +++ b/src/http_server/new_york_transit_line/templater.cpp @@ -0,0 +1,149 @@ +#include "templater.h" +#include +#include +#include "alotalot.h" +#include +#include +#include +#include "core.h" + +namespace nytl { + /* Throws std::runtime_exception on incorrect settings */ + void check_settings(const TemplaterSettings& settings) { +#define lmao_serving_kid_with_identity_issues throw std::runtime_error("What was wrong with {% %} ????") + if (settings.magic_block_start.empty() || settings.magic_block_end.empty()) + lmao_serving_kid_with_identity_issues; + char incode = settings.magic_block_start[0]; + if (isSPACE(incode) || isALPHA(incode) || isNUM(incode)) + lmao_serving_kid_with_identity_issues; + char ender = settings.magic_block_end[0]; + if (isUNCHAR(ender) || ender == ':' || isSPACE(ender) || ender == '[' || ender == ']' || ender == '.') + lmao_serving_kid_with_identity_issues; + } + + Templater::Templater(TemplaterSettings settings): settings(std::move(settings)) { + check_settings(this->settings); + } + + struct InterestingFile { + std::string path; + std::string dot_name; + bool special_syntax_applied; + }; + + std::vector indexing_detour(const TemplaterDetourRules& rules) { + std::vector result; + int ret; + + std::vector todo; + todo.emplace_back(); + while (!todo.empty()) { + std::string cur = std::move(todo.back()); + todo.pop_back(); + std::string path_to_cur_dir = rules.root_dir_path + "/" + cur; + DIR* D = opendir(path_to_cur_dir.c_str()); + struct Guard1{ DIR*& D; ~Guard1(){ closedir(D); } } g1{D}; + ASSERT(D != NULL, prettyprint_errno("opendir(\"" + cur +"\")")); + while (true) { + errno = 0; + struct dirent* Dent = readdir(D); + if (Dent == NULL) { + if (errno == 0) + break; + THROW_on_errno("dirent in \"" + cur + "\""); + } + std::string child_entry = Dent->d_name; + if (child_entry == "." || child_entry == "..") + continue; + std::string path_to_cur_child = path_to_cur_dir + "/" + child_entry; + struct stat info; + ret = stat(path_to_cur_child.c_str(), &info); + ASSERT_on_iret(ret, "stat(" + path_to_cur_child + ")"); + if (S_ISDIR(info.st_mode)) { + if (isUname(child_entry)) + todo.push_back(cur + "/" + child_entry); + } else if (S_ISREG(info.st_mode)) { + auto replace_sep = [](const std::string& slashed) -> std::string { + std::string dotted; + dotted.reserve(slashed.size()); + for (char ch: slashed) { + if (ch == '/') + dotted += '.'; + else + dotted += ch; + } + return dotted; + }; + auto np_reg_categ_result = [&](const std::string& no_postfix, bool applied) { + if (isUname(no_postfix)) + result.push_back({path_to_cur_child, replace_sep(cur + "/" + no_postfix), applied}); + }; + if (endsIn(child_entry, rules.postfix_rule_for_element_cont)) { + np_reg_categ_result(throwout_postfix(child_entry, rules.postfix_rule_for_element_cont.size()), true); + } else if (endsIn(child_entry, rules.postfix_rule_for_static_files)) { + np_reg_categ_result(throwout_postfix(child_entry, rules.postfix_rule_for_static_files.size()), false); + } + } else { + THROW("unknown fs entry type \"" + cur + "\""); + } + } + } + return result; + } + + std::string readFile(const std::string& path) { + std::string result; + int ret; + int fd = open(path.c_str(), O_RDONLY); + ASSERT_on_iret(fd, "Opening \"" + path + "\""); + char buf[2048]; + while ((ret = (int)read(fd, buf, 2048)) > 0) { + size_t oldN = result.size(); + result.resize(oldN + ret); + memcpy((void*)&result.c_str()[oldN], buf, ret); + } + if (ret < 0) { + close(fd); + THROW("reading file"); + } + return result; + } + + void Templater::update() { + elements = { + {"jesc", Element{{json::JSON(true)}, true}}, + {"str2text", Element{{json::JSON(true)}, true}}, + {"str2code", Element{{json::JSON(true)}, true}}, + }; + std::vector intersting_files = indexing_detour(settings.det); + for (const InterestingFile& file: intersting_files) { + std::string content = readFile(file.path); + if (file.special_syntax_applied) { + parse_special_file(file.dot_name, content, elements); + } else { + parse_bare_file(file.dot_name, content, elements); + } + } + } + + void check_uinp_element(const std::string& uinp) { + if (uinp.empty()) + THROW("empty???"); + std::vector r = {""}; + for (char ch: uinp) { + if (ch == '.') { + r.emplace_back(); + } else { + r.back() += ch; + } + } + for (const std::string& c: r) + ASSERT(isUname(c), "Incorrect name component"); + } + + /* Still can throw some stuff derived from std::exception (like bad alloc) */ + std::string Templater::render(const std::string& element, const std::vector &arguments) const { + check_uinp_element(element); + return rendering_core(element, arguments, elements); + } +} diff --git a/src/http_server/new_york_transit_line/templater.h b/src/http_server/new_york_transit_line/templater.h new file mode 100644 index 0000000..d0ebda3 --- /dev/null +++ b/src/http_server/new_york_transit_line/templater.h @@ -0,0 +1,86 @@ +#ifndef NEW_YORK_TRANSIT_LINE_TEMPLATER_H +#define NEW_YORK_TRANSIT_LINE_TEMPLATER_H + +#include +#include +#include +#include +#include "html_case.h" + +namespace nytl { + typedef json::JSON expression_t; + + namespace element_part_types { + enum element_part_type_E { + code, + /* write statements really mean PUT str2text X */ + put, + for_put, + ref_put + }; + } + + typedef element_part_types::element_part_type_E element_part_type_t; + + struct ElementPart { + /* Used with all types */ + element_part_type_t type = element_part_types::code; + struct when_code_S { + std::string lines; + } when_code; + struct when_put_S { + expression_t called_element; + std::vector passed_arguments; + } when_put; + struct when_for_put_S { + expression_t ref_over; + bool have_av_key = false; + bool have_av_value = false; + expression_t internal_element; + bool line_feed = true; + } when_for_put; + struct when_ref_put_S { + expression_t ref_over; + expression_t internal_element; + } when_ref_put; + }; + + struct Element { + /* Stores signature of element */ + std::vector arguments; + /* `base` is true for builtin elements (jesc str2code str2text). Parts for such ' are empty */ + bool base = false; + std::vector parts; + }; + + struct TemplaterDetourRules { + std::string root_dir_path; + std::string postfix_rule_for_element_cont = ".nytl.html"; + std::string postfix_rule_for_static_files = ".html"; + }; + + struct TemplaterSettings { + TemplaterDetourRules det; + std::string magic_block_start = "{%"; + std::string magic_block_end = "%}"; + std::function escape = html_case_espace_string; + }; + + typedef std::map global_elem_set_t; + + struct Templater { + TemplaterSettings settings; + + global_elem_set_t elements; + + explicit Templater(TemplaterSettings settings); + + /* Throws exception, derived from std::exception */ + void update(); + + /* Throws exception, derived from std::exception */ + std::string render(const std::string& element, const std::vector& arguments) const; + }; +} + +#endif