Daily saving of progress
This commit is contained in:
parent
3a8d1207b1
commit
c264e3802b
@ -108,10 +108,39 @@ struct CAWebChat {
|
|||||||
T.installation_dir = "";
|
T.installation_dir = "";
|
||||||
my_targets.push_back(T);
|
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"};
|
{ CTarget T{"iu9-ca-web-chat", "executable"};
|
||||||
T.additional_compilation_flags = getSomeRadFlags();
|
T.additional_compilation_flags = getSomeRadFlags();
|
||||||
T.proj_deps = {CTargetDependenceOnProjectsLibrary{"engine_engine_number_9"}};
|
T.proj_deps = {
|
||||||
T.external_deps = {CTargetDependenceOnExternalLibrary{"sqlite3"}};
|
CTargetDependenceOnProjectsLibrary{"engine_engine_number_9"},
|
||||||
|
CTargetDependenceOnProjectsLibrary{"new_york_transit_line"},
|
||||||
|
};
|
||||||
|
T.external_deps = {
|
||||||
|
CTargetDependenceOnExternalLibrary{"sqlite3"}
|
||||||
|
};
|
||||||
T.units = {"main.cpp"};
|
T.units = {"main.cpp"};
|
||||||
for (std::string& u: T.units)
|
for (std::string& u: T.units)
|
||||||
u = "web_chat/" + u;
|
u = "web_chat/" + u;
|
||||||
|
@ -5,15 +5,9 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
namespace een9 {
|
namespace een9 {
|
||||||
ServerError::ServerError(const std::string &err, const std::string &file, const std::string &func, int line): err(err),
|
ServerError::ServerError(const std::string &err, const std::string &file, const std::string &func, int line){
|
||||||
FILE(file),
|
WHAT = "Error occured in function " + func + " (line " + std::to_string(line) + " of " +
|
||||||
func(func),
|
file + ")\nError: " + err;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const char * ServerError::what() const noexcept {
|
const char * ServerError::what() const noexcept {
|
||||||
|
@ -6,10 +6,6 @@
|
|||||||
|
|
||||||
namespace een9 {
|
namespace een9 {
|
||||||
class ServerError : public std::exception{
|
class ServerError : public std::exception{
|
||||||
std::string err;
|
|
||||||
std::string FILE;
|
|
||||||
std::string func;
|
|
||||||
int LINE;
|
|
||||||
std::string WHAT;
|
std::string WHAT;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -23,9 +23,9 @@ namespace een9 {
|
|||||||
ASSERT_on_iret(ret, "stat(\"" + cur + "\")");
|
ASSERT_on_iret(ret, "stat(\"" + cur + "\")");
|
||||||
if (S_ISDIR(info.st_mode)) {
|
if (S_ISDIR(info.st_mode)) {
|
||||||
DIR* D = opendir(path_to_cur_ent.c_str());
|
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};
|
struct Guard1{ DIR*& D; ~Guard1(){ closedir(D); } } g1{D};
|
||||||
|
ASSERT(D != NULL, prettyprint_errno("opendir(\"" + cur +"\")"));
|
||||||
|
cur += "/";
|
||||||
while (true) {
|
while (true) {
|
||||||
errno = 0;
|
errno = 0;
|
||||||
struct dirent* Dent = readdir(D);
|
struct dirent* Dent = readdir(D);
|
||||||
|
@ -55,7 +55,7 @@ namespace een9 {
|
|||||||
while ((ret = (int)read(fd, buf, 2048)) > 0) {
|
while ((ret = (int)read(fd, buf, 2048)) > 0) {
|
||||||
size_t oldN = result.size();
|
size_t oldN = result.size();
|
||||||
result.resize(oldN + ret);
|
result.resize(oldN + ret);
|
||||||
memcpy(&result[oldN], buf, ret);
|
memcpy((void*)&result.c_str()[oldN], buf, ret);
|
||||||
}
|
}
|
||||||
ASSERT_on_iret(ret, "Reading from " + description);
|
ASSERT_on_iret(ret, "Reading from " + description);
|
||||||
}
|
}
|
||||||
|
58
src/http_server/new_york_transit_line/alotalot.cpp
Normal file
58
src/http_server/new_york_transit_line/alotalot.cpp
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
#include "alotalot.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
43
src/http_server/new_york_transit_line/alotalot.h
Normal file
43
src/http_server/new_york_transit_line/alotalot.h
Normal file
@ -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 <stdexcept>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace nytl {
|
||||||
|
template<typename T>
|
||||||
|
using uptr = std::unique_ptr<T>;
|
||||||
|
|
||||||
|
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
|
28
src/http_server/new_york_transit_line/core.h
Normal file
28
src/http_server/new_york_transit_line/core.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#ifndef NEW_YORK_TRANSIT_LINE_CORE_H
|
||||||
|
#define NEW_YORK_TRANSIT_LINE_CORE_H
|
||||||
|
|
||||||
|
#include "templater.h"
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
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<LocalVarValue>& local_vars, json::JSON& expr);
|
||||||
|
|
||||||
|
std::string rendering_core(const std::string& entry_func, const std::vector<json::JSON>& entry_arguments,
|
||||||
|
std::map<std::string, Element>& elem_ns, const std::function<std::string(std::string)>& escape);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
44
src/http_server/new_york_transit_line/execute_expression.cpp
Normal file
44
src/http_server/new_york_transit_line/execute_expression.cpp
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#include "core.h"
|
||||||
|
#include "alotalot.h"
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
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<Frame> toMe(bool returned_from_bottom, global_elem_set_t& global_elems,
|
||||||
|
const std::vector<LocalVarValue>& 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<LocalVarValue>& local_vars, json::JSON& expr) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
30
src/http_server/new_york_transit_line/html_case.cpp
Normal file
30
src/http_server/new_york_transit_line/html_case.cpp
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
10
src/http_server/new_york_transit_line/html_case.h
Normal file
10
src/http_server/new_york_transit_line/html_case.h
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#ifndef NEW_YORK_TRANSIT_LINE_HTML_CASE_H
|
||||||
|
#define NEW_YORK_TRANSIT_LINE_HTML_CASE_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace nytl {
|
||||||
|
std::string html_case_espace_string(const std::string &inp);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
88
src/http_server/new_york_transit_line/parser.cpp
Normal file
88
src/http_server/new_york_transit_line/parser.cpp
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
#include "core.h"
|
||||||
|
#include "alotalot.h"
|
||||||
|
#include <vector>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
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<std::string, Element>& result)
|
||||||
|
{
|
||||||
|
ASSERT(result.count(filename) == 0, "Repeated element " + filename);
|
||||||
|
std::vector<std::string> 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<std::string, Element>& result)
|
||||||
|
{
|
||||||
|
// todo
|
||||||
|
}
|
||||||
|
}
|
98
src/http_server/new_york_transit_line/rendering.cpp
Normal file
98
src/http_server/new_york_transit_line/rendering.cpp
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
#include "core.h"
|
||||||
|
#include "alotalot.h"
|
||||||
|
#include <string.h>
|
||||||
|
#include <libjsonincpp/string_representation.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
namespace nytl {
|
||||||
|
std::string rendering_core(const std::string& entry_func, const std::vector<json::JSON>& entry_arguments,
|
||||||
|
std::map<std::string, Element>& elem_ns, const std::function<std::string(std::string)>& 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<LocalVarValue> passed_args;
|
||||||
|
/* This parameter incapsulates `cur_line_width` at some point for multiline `put-parts` */
|
||||||
|
size_t multiline_put_start = 0;
|
||||||
|
};
|
||||||
|
std::vector<uptr<Frame>> stack;
|
||||||
|
|
||||||
|
auto make_frame = [&](const std::string& name, std::vector<LocalVarValue> 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<Frame>(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<LocalVarValue> 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;
|
||||||
|
}
|
||||||
|
}
|
149
src/http_server/new_york_transit_line/templater.cpp
Normal file
149
src/http_server/new_york_transit_line/templater.cpp
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
#include "templater.h"
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include "alotalot.h"
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#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<InterestingFile> indexing_detour(const TemplaterDetourRules& rules) {
|
||||||
|
std::vector<InterestingFile> result;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
std::vector<std::string> 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<InterestingFile> 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<std::string> 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<json::JSON> &arguments) const {
|
||||||
|
check_uinp_element(element);
|
||||||
|
return rendering_core(element, arguments, elements);
|
||||||
|
}
|
||||||
|
}
|
86
src/http_server/new_york_transit_line/templater.h
Normal file
86
src/http_server/new_york_transit_line/templater.h
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
#ifndef NEW_YORK_TRANSIT_LINE_TEMPLATER_H
|
||||||
|
#define NEW_YORK_TRANSIT_LINE_TEMPLATER_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <libjsonincpp/jsonobj.h>
|
||||||
|
#include <functional>
|
||||||
|
#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<expression_t> 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<json::JSON> arguments;
|
||||||
|
/* `base` is true for builtin elements (jesc str2code str2text). Parts for such ' are empty */
|
||||||
|
bool base = false;
|
||||||
|
std::vector<ElementPart> 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<std::string(std::string)> escape = html_case_espace_string;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::map<std::string, Element> 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<json::JSON>& arguments) const;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user