iu9-ca-web-chat/src/http_server/new_york_transit_line/templater.cpp

139 lines
5.9 KiB
C++

#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 = mv(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.empty() ? child_entry : 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.empty() ? no_postfix : 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(result.data() + oldN, buf, ret);
}
if (ret < 0) {
close(fd);
THROW("reading file");
}
return result;
}
void Templater::update() {
elements = {
{"jsinsert", Element{{json::JSON(true)}, true}},
{"jesc", Element{{json::JSON(true)}, true}},
{"jesccomp", Element{{json::JSON(true)}, true}},
/* str2text base element has a dedicated operator - WRITE */
{"str2text", Element{{json::JSON(true)}, true}},
/* str2code base element has a dedicated operator - ROUGHINSERT */
{"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, settings);
} else {
parse_bare_file(file.dot_name, content, elements);
}
}
}
/* Still can throw some stuff derived from std::exception (like bad alloc) */
std::string Templater::render(const std::string& element, const std::vector<const json::JSON*> &arguments) const {
ASSERT(is_uname_dotted_sequence(element), "Incorrect entry element name");
return rendering_core(element, arguments, elements, settings.escape);
}
}