trying to port web app starter from PHP
This commit is contained in:
+324
-53
@@ -12,25 +12,36 @@ String process_text_literal(Request* context, SharedUnit* su, String content)
|
||||
bool inside_quote = false;
|
||||
String code_buffer = "";
|
||||
bool is_field = false;
|
||||
bool escape_field = false;
|
||||
|
||||
for(u32 i = 0; i < content.length(); i++)
|
||||
{
|
||||
char c = content[i];
|
||||
char c1 = (i + 1 < content.length()) ? content[i + 1] : '\0';
|
||||
char c2 = (i + 2 < content.length()) ? content[i + 2] : '\0';
|
||||
|
||||
switch(mode)
|
||||
{
|
||||
case(0):
|
||||
if(c == '<' && content[i+1] == '?')
|
||||
if(c == '<' && c1 == '?')
|
||||
{
|
||||
code_buffer = "";
|
||||
if(content[i+2] == '=')
|
||||
if(c2 == '=')
|
||||
{
|
||||
is_field = true;
|
||||
escape_field = true;
|
||||
i += 2;
|
||||
}
|
||||
else if(c2 == ':')
|
||||
{
|
||||
is_field = true;
|
||||
escape_field = false;
|
||||
i += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
is_field = false;
|
||||
escape_field = false;
|
||||
i += 1;
|
||||
}
|
||||
mode = 1; // code-parsing mode
|
||||
@@ -43,7 +54,7 @@ String process_text_literal(Request* context, SharedUnit* su, String content)
|
||||
case(1):
|
||||
if(inside_quote)
|
||||
{
|
||||
if(quote_char == c && content[i-1] != '\\')
|
||||
if(quote_char == c && (i == 0 || content[i-1] != '\\'))
|
||||
inside_quote = false;
|
||||
code_buffer.append(1, c);
|
||||
}
|
||||
@@ -55,19 +66,32 @@ String process_text_literal(Request* context, SharedUnit* su, String content)
|
||||
quote_char = c;
|
||||
code_buffer.append(1, c);
|
||||
}
|
||||
else if(c == '?' && content[i+1] == '>')
|
||||
else if(c == '?' && c1 == '>')
|
||||
{
|
||||
mode = 0;
|
||||
i += 1;
|
||||
if(is_field)
|
||||
{
|
||||
pc.append(
|
||||
HT_END +
|
||||
"print(html_escape( " +
|
||||
code_buffer +
|
||||
" )); " +
|
||||
HT_START
|
||||
);
|
||||
if(escape_field)
|
||||
{
|
||||
pc.append(
|
||||
HT_END +
|
||||
"print(html_escape( " +
|
||||
code_buffer +
|
||||
" )); " +
|
||||
HT_START
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
pc.append(
|
||||
HT_END +
|
||||
"print( " +
|
||||
code_buffer +
|
||||
" ); " +
|
||||
HT_START
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -87,6 +111,57 @@ String process_text_literal(Request* context, SharedUnit* su, String content)
|
||||
return(HT_START + pc + HT_END);
|
||||
}
|
||||
|
||||
String preprocess_named_render_syntax(String content)
|
||||
{
|
||||
String result = "";
|
||||
String current_line = "";
|
||||
|
||||
auto flush_line = [&]() {
|
||||
if(current_line.length() == 0)
|
||||
return;
|
||||
|
||||
String line = current_line;
|
||||
String line_break = "";
|
||||
if(line.length() > 0 && line.back() == '\n')
|
||||
{
|
||||
line_break = "\n";
|
||||
line.pop_back();
|
||||
}
|
||||
|
||||
u32 indent_length = 0;
|
||||
while(indent_length < line.length() && isspace(line[indent_length]))
|
||||
indent_length += 1;
|
||||
|
||||
String indent = line.substr(0, indent_length);
|
||||
String trimmed = trim(line);
|
||||
if(trimmed.rfind("RENDER:", 0) == 0)
|
||||
{
|
||||
String signature = trimmed.substr(7);
|
||||
auto open_paren_pos = signature.find("(");
|
||||
if(open_paren_pos != String::npos)
|
||||
{
|
||||
String render_name = trim(signature.substr(0, open_paren_pos));
|
||||
String render_signature = signature.substr(open_paren_pos);
|
||||
if(render_name != "")
|
||||
line = indent + "EXPORT void render_" + safe_name(render_name) + render_signature;
|
||||
}
|
||||
}
|
||||
|
||||
result += line + line_break;
|
||||
current_line = "";
|
||||
};
|
||||
|
||||
for(auto c : content)
|
||||
{
|
||||
current_line.append(1, c);
|
||||
if(c == '\n')
|
||||
flush_line();
|
||||
}
|
||||
flush_line();
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
String preprocess_shared_unit_char_wise(Request* context, SharedUnit* su, String content)
|
||||
{
|
||||
String pc =
|
||||
@@ -104,10 +179,12 @@ String preprocess_shared_unit_char_wise(Request* context, SharedUnit* su, String
|
||||
for(u32 i = 0; i < source_length; i++)
|
||||
{
|
||||
char c = content[i];
|
||||
char c1 = (i + 1 < source_length) ? content[i + 1] : '\0';
|
||||
char c2 = (i + 2 < source_length) ? content[i + 2] : '\0';
|
||||
current_line.append(1, c);
|
||||
if(mode == 1)
|
||||
{
|
||||
if(c == '<' && (content[i+1] == '/') && (content[i+2] == '>'))
|
||||
if(c == '<' && c1 == '/' && c2 == '>')
|
||||
{
|
||||
i += 2;
|
||||
pc.append(process_text_literal(context, su, html_buffer));
|
||||
@@ -119,7 +196,7 @@ String preprocess_shared_unit_char_wise(Request* context, SharedUnit* su, String
|
||||
html_buffer.append(1, c);
|
||||
}
|
||||
}
|
||||
else if(!inside_quote && c == '<' && (content[i+1] == '>'))
|
||||
else if(!inside_quote && c == '<' && c1 == '>')
|
||||
{
|
||||
mode = 1;
|
||||
token = "";
|
||||
@@ -147,16 +224,20 @@ String preprocess_shared_unit_char_wise(Request* context, SharedUnit* su, String
|
||||
pc.append("#include \"" + sub_su->bin_path + "/" + sub_su->pre_file_name + "\"\n");
|
||||
}
|
||||
}
|
||||
else if(current_line.substr(0, 6) == "EXPORT" && isspace(current_line[6]))
|
||||
else
|
||||
{
|
||||
current_line = "";
|
||||
auto end_declaration_pos = content.find("{", i);
|
||||
if(end_declaration_pos != std::string::npos)
|
||||
String trimmed_line = trim(current_line);
|
||||
if(c == 10 && trimmed_line.length() > 7 && trimmed_line.substr(0, 6) == "EXPORT" && isspace(trimmed_line[6]))
|
||||
{
|
||||
pc.append(1, '\n');
|
||||
String declaration = trim(content.substr(i, end_declaration_pos - i));
|
||||
su->api_declarations.push_back(declaration+";\n");
|
||||
//printf("declaration found: %s\n", declaration.c_str());
|
||||
current_line = "";
|
||||
auto end_declaration_pos = content.find("{", i);
|
||||
if(end_declaration_pos != std::string::npos)
|
||||
{
|
||||
pc.append(1, '\n');
|
||||
String declaration = trim(content.substr(i, end_declaration_pos - i));
|
||||
su->api_declarations.push_back(declaration+";\n");
|
||||
//printf("declaration found: %s\n", declaration.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -168,11 +249,13 @@ String preprocess_shared_unit_char_wise(Request* context, SharedUnit* su, String
|
||||
|
||||
String preprocess_shared_unit(Request* context, SharedUnit* su)
|
||||
{
|
||||
String content = file_get_contents(su->file_name);
|
||||
content = preprocess_named_render_syntax(content);
|
||||
return(
|
||||
preprocess_shared_unit_char_wise(
|
||||
context,
|
||||
su,
|
||||
file_get_contents(su->file_name)
|
||||
content
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -223,9 +306,9 @@ void load_shared_unit(Request* context, SharedUnit* su, String file_name)
|
||||
su->on_setup = (request_handler)dlsym(su->so_handle, "set_current_request");
|
||||
if ((error = dlerror()) != NULL)
|
||||
printf("Error - %s in %s\n", error, su->file_name.c_str());
|
||||
su->on_render = (call_handler)dlsym(su->so_handle, "render");
|
||||
su->on_render = (request_ref_handler)dlsym(su->so_handle, "render");
|
||||
dlerror();
|
||||
su->on_websocket = (call_handler)dlsym(su->so_handle, "websocket");
|
||||
su->on_websocket = (request_ref_handler)dlsym(su->so_handle, "websocket");
|
||||
dlerror();
|
||||
su->api_declarations = split(file_get_contents(su->api_file_name), "\n");
|
||||
//else
|
||||
@@ -291,6 +374,11 @@ SharedUnit* get_shared_unit(Request* context, String file_name, bool opt_so_opti
|
||||
{
|
||||
SharedUnit* su = context->server->units[file_name];
|
||||
auto mod_time = file_mtime(file_name);
|
||||
auto setup_template_time = file_mtime(
|
||||
context->server->config["COMPILER_SYS_PATH"] + "/" +
|
||||
context->server->config["SETUP_TEMPLATE"]);
|
||||
if(setup_template_time > mod_time)
|
||||
mod_time = setup_template_time;
|
||||
auto compiled_time = su ? file_mtime(su->so_name) : 0;
|
||||
bool do_recompile = false;
|
||||
if(su && (compiled_time < mod_time || mod_time == 0))
|
||||
@@ -378,36 +466,141 @@ SharedUnit* compiler_load_shared_unit(Request* context, String file_name, String
|
||||
|
||||
}
|
||||
|
||||
void compiler_invoke(Request* context, String file_name, DTree& call_param)
|
||||
String component_normalize_path(String name)
|
||||
{
|
||||
name = trim(name);
|
||||
if(name.length() >= 4 && name.substr(name.length() - 4) == ".uce")
|
||||
return(name);
|
||||
return(name + ".uce");
|
||||
}
|
||||
|
||||
void component_parse_target(String target, String& file_name, String& render_name)
|
||||
{
|
||||
target = trim(target);
|
||||
render_name = "render";
|
||||
auto render_split_pos = target.find(":");
|
||||
if(render_split_pos != String::npos)
|
||||
{
|
||||
render_name = trim(target.substr(render_split_pos + 1));
|
||||
target = trim(target.substr(0, render_split_pos));
|
||||
if(render_name == "")
|
||||
render_name = "render";
|
||||
}
|
||||
file_name = target;
|
||||
}
|
||||
|
||||
String component_resolve_path(String name)
|
||||
{
|
||||
String file_name;
|
||||
String render_name;
|
||||
component_parse_target(name, file_name, render_name);
|
||||
|
||||
if(file_name == "")
|
||||
return("");
|
||||
|
||||
StringList candidates;
|
||||
auto push_candidate = [&] (String candidate) {
|
||||
if(candidate == "")
|
||||
return;
|
||||
candidates.push_back(candidate);
|
||||
};
|
||||
|
||||
push_candidate(file_name);
|
||||
push_candidate(component_normalize_path(file_name));
|
||||
|
||||
if(file_name.rfind("components/", 0) != 0)
|
||||
{
|
||||
push_candidate("components/" + file_name);
|
||||
push_candidate(component_normalize_path("components/" + file_name));
|
||||
}
|
||||
|
||||
std::map<String, bool> seen;
|
||||
for(auto& candidate : candidates)
|
||||
{
|
||||
if(seen[candidate])
|
||||
continue;
|
||||
seen[candidate] = true;
|
||||
String resolved = candidate;
|
||||
if(resolved[0] != '/')
|
||||
resolved = expand_path(resolved, get_cwd());
|
||||
if(file_exists(resolved))
|
||||
return(resolved);
|
||||
}
|
||||
|
||||
return("");
|
||||
}
|
||||
|
||||
String render_handler_symbol(String render_name)
|
||||
{
|
||||
render_name = trim(render_name);
|
||||
if(render_name == "" || render_name == "render")
|
||||
return("render");
|
||||
return("render_" + safe_name(render_name));
|
||||
}
|
||||
|
||||
request_ref_handler get_render_handler(SharedUnit* su, String render_name)
|
||||
{
|
||||
String symbol = render_handler_symbol(render_name);
|
||||
if(symbol == "render")
|
||||
return(su->on_render);
|
||||
|
||||
auto it = su->api_functions.find(symbol);
|
||||
if(it != su->api_functions.end())
|
||||
return((request_ref_handler)it->second);
|
||||
|
||||
auto handler = (request_ref_handler)dlsym(su->so_handle, symbol.c_str());
|
||||
dlerror();
|
||||
su->api_functions[symbol] = (void*)handler;
|
||||
return(handler);
|
||||
}
|
||||
|
||||
bool compiler_invoke_render(Request* context, String file_name, String render_name, String* error_out = 0)
|
||||
{
|
||||
auto su = compiler_load_shared_unit(context, file_name, "", false);
|
||||
if(!su)
|
||||
return(false);
|
||||
|
||||
if(!su->on_setup)
|
||||
{
|
||||
if(error_out)
|
||||
*error_out = "internal error: set_current_request() not defined in " + file_name;
|
||||
return(false);
|
||||
}
|
||||
|
||||
auto handler = get_render_handler(su, render_name);
|
||||
if(!handler)
|
||||
{
|
||||
if(error_out)
|
||||
{
|
||||
if(trim(render_name) == "" || trim(render_name) == "render")
|
||||
*error_out = "no RENDER() entry point";
|
||||
else
|
||||
*error_out = "no RENDER:" + render_name + "() entry point";
|
||||
}
|
||||
return(false);
|
||||
}
|
||||
|
||||
String prev_wd = get_cwd();
|
||||
set_cwd(su->src_path);
|
||||
su->on_setup(context);
|
||||
handler(*context);
|
||||
set_cwd(prev_wd);
|
||||
return(true);
|
||||
}
|
||||
|
||||
void compiler_invoke(Request* context, String file_name)
|
||||
{
|
||||
printf("(i) compiler_invoke file %s\n", file_name.c_str());
|
||||
auto su = compiler_load_shared_unit(context, file_name, "", false);
|
||||
if(su)
|
||||
String error_message = "";
|
||||
if(!compiler_invoke_render(context, file_name, "render", &error_message) && error_message != "")
|
||||
{
|
||||
if(!su->on_setup)
|
||||
{
|
||||
if(context->stats.invoke_count == 1)
|
||||
context->header["Content-Type"] = "text/plain";
|
||||
print("internal error: set_current_request() not defined in", file_name, "\n");
|
||||
}
|
||||
else if(!su->on_render)
|
||||
{
|
||||
if(context->stats.invoke_count == 1)
|
||||
context->header["Content-Type"] = "text/plain";
|
||||
print("no RENDER() entry point");
|
||||
}
|
||||
else
|
||||
{
|
||||
String prev_wd = get_cwd();
|
||||
set_cwd(su->src_path);
|
||||
su->on_setup(context);
|
||||
su->on_render(call_param);
|
||||
set_cwd(prev_wd);
|
||||
}
|
||||
if(context->stats.invoke_count == 1)
|
||||
context->header["Content-Type"] = "text/plain";
|
||||
print(error_message);
|
||||
}
|
||||
}
|
||||
|
||||
void compiler_invoke_websocket(Request* context, String file_name, DTree& call_param)
|
||||
void compiler_invoke_websocket(Request* context, String file_name)
|
||||
{
|
||||
auto su = compiler_load_shared_unit(context, file_name, "", false);
|
||||
if(!su)
|
||||
@@ -428,20 +621,98 @@ void compiler_invoke_websocket(Request* context, String file_name, DTree& call_p
|
||||
String prev_wd = get_cwd();
|
||||
set_cwd(su->src_path);
|
||||
su->on_setup(context);
|
||||
su->on_websocket(call_param);
|
||||
su->on_websocket(*context);
|
||||
set_cwd(prev_wd);
|
||||
}
|
||||
|
||||
void render_file(String file_name)
|
||||
{
|
||||
//printf("(i) render_file(%s)\n", file_name.c_str());
|
||||
DTree call_param;
|
||||
compiler_invoke(context, file_name, call_param);
|
||||
compiler_invoke(context, file_name);
|
||||
}
|
||||
|
||||
void render_file(String file_name, DTree& call_param)
|
||||
void render_file(String file_name, Request& context)
|
||||
{
|
||||
compiler_invoke(context, file_name, call_param);
|
||||
compiler_invoke(&context, file_name);
|
||||
}
|
||||
|
||||
String component_resolve(String name)
|
||||
{
|
||||
return(component_resolve_path(name));
|
||||
}
|
||||
|
||||
bool component_exists(String name)
|
||||
{
|
||||
return(component_resolve(name) != "");
|
||||
}
|
||||
|
||||
String component_error_banner(String message)
|
||||
{
|
||||
return("<div class=\"banner\">" + html_escape(message) + "</div>");
|
||||
}
|
||||
|
||||
void render_component(String name)
|
||||
{
|
||||
DTree props;
|
||||
render_component(name, props, *context);
|
||||
}
|
||||
|
||||
void render_component(String name, Request& context)
|
||||
{
|
||||
DTree props;
|
||||
render_component(name, props, context);
|
||||
}
|
||||
|
||||
void render_component(String name, DTree props)
|
||||
{
|
||||
render_component(name, props, *context);
|
||||
}
|
||||
|
||||
void render_component(String name, DTree props, Request& context)
|
||||
{
|
||||
String file_name;
|
||||
String render_name;
|
||||
component_parse_target(name, file_name, render_name);
|
||||
|
||||
String resolved_name = component_resolve_path(file_name);
|
||||
if(resolved_name == "")
|
||||
{
|
||||
print(component_error_banner("component not found: " + file_name));
|
||||
return;
|
||||
}
|
||||
|
||||
DTree previous_call = context.call;
|
||||
context.call = props;
|
||||
|
||||
String error_message = "";
|
||||
if(!compiler_invoke_render(&context, resolved_name, render_name, &error_message) && error_message != "")
|
||||
print(component_error_banner(error_message));
|
||||
|
||||
context.call = previous_call;
|
||||
}
|
||||
|
||||
String component(String name)
|
||||
{
|
||||
DTree props;
|
||||
return(component(name, props, *context));
|
||||
}
|
||||
|
||||
String component(String name, Request& context)
|
||||
{
|
||||
DTree props;
|
||||
return(component(name, props, context));
|
||||
}
|
||||
|
||||
String component(String name, DTree props)
|
||||
{
|
||||
return(component(name, props, *context));
|
||||
}
|
||||
|
||||
String component(String name, DTree props, Request& context)
|
||||
{
|
||||
ob_start();
|
||||
render_component(name, props, context);
|
||||
return(ob_get_close());
|
||||
}
|
||||
|
||||
SharedUnit* load_file(String file_name)
|
||||
|
||||
+17
-5
@@ -1,5 +1,7 @@
|
||||
#define RENDER() extern "C" void render(DTree& call)
|
||||
#define WS() extern "C" void websocket(DTree& call)
|
||||
#pragma once
|
||||
|
||||
#define RENDER(X) extern "C" void render(Request& context)
|
||||
#define WS(X) extern "C" void websocket(Request& context)
|
||||
#define EXPORT extern "C"
|
||||
|
||||
String process_html_literal(Request* context, SharedUnit* su, String content);
|
||||
@@ -8,13 +10,23 @@ void setup_unit_paths(Request* context, SharedUnit* su, String file_name);
|
||||
void load_shared_unit(Request* context, SharedUnit* su, String file_name);
|
||||
void compile_shared_unit(Request* context, SharedUnit* su, String file_name);
|
||||
SharedUnit* get_shared_unit(Request* context, String file_name, bool opt_so_optional = false);
|
||||
void compiler_invoke(Request* context, String file_name, DTree& call_param);
|
||||
void compiler_invoke_websocket(Request* context, String file_name, DTree& call_param);
|
||||
void compiler_invoke(Request* context, String file_name);
|
||||
void compiler_invoke_websocket(Request* context, String file_name);
|
||||
SharedUnit* compiler_load_shared_unit(Request* context, String file_name, String current_path = "", bool opt_so_optional = false);
|
||||
|
||||
SharedUnit* load_file(String file_name);
|
||||
void render_file(String file_name);
|
||||
void render_file(String file_name, DTree& call_param);
|
||||
void render_file(String file_name, Request& context);
|
||||
DTree* call_file(String file_name, String function_name, DTree* call_param = 0);
|
||||
String component_resolve(String name);
|
||||
bool component_exists(String name);
|
||||
void render_component(String name);
|
||||
void render_component(String name, Request& context);
|
||||
void render_component(String name, DTree props);
|
||||
void render_component(String name, DTree props, Request& context);
|
||||
String component(String name);
|
||||
String component(String name, Request& context);
|
||||
String component(String name, DTree props);
|
||||
String component(String name, DTree props, Request& context);
|
||||
|
||||
StringList precompile_jobs;
|
||||
|
||||
+167
-13
@@ -1,10 +1,30 @@
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename TreePtr>
|
||||
TreePtr dtree_resolve_reference(TreePtr tree)
|
||||
{
|
||||
u32 depth = 0;
|
||||
while(tree && tree->type == 'R' && depth < 16)
|
||||
{
|
||||
TreePtr target = reinterpret_cast<TreePtr>(tree->_ptr);
|
||||
if(target == 0 || target == tree)
|
||||
break;
|
||||
tree = target;
|
||||
depth += 1;
|
||||
}
|
||||
return(tree);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void DTree::each(std::function <void (DTree t, String key)> f)
|
||||
{
|
||||
switch(type)
|
||||
const DTree& target = deref();
|
||||
switch(target.type)
|
||||
{
|
||||
case('M'):
|
||||
for (auto it = _map.begin(); it != _map.end(); ++it)
|
||||
for (auto it = target._map.begin(); it != target._map.end(); ++it)
|
||||
{
|
||||
f(it->second, it->first);
|
||||
}
|
||||
@@ -17,43 +37,49 @@ void DTree::each(std::function <void (DTree t, String key)> f)
|
||||
|
||||
bool DTree::is_array()
|
||||
{
|
||||
return(type == 'M');
|
||||
return(deref().type == 'M');
|
||||
}
|
||||
|
||||
String DTree::to_string()
|
||||
{
|
||||
switch(type)
|
||||
const DTree& target = deref();
|
||||
switch(target.type)
|
||||
{
|
||||
case('S'):
|
||||
return(_String);
|
||||
return(target._String);
|
||||
break;
|
||||
case('F'):
|
||||
return(std::to_string(_float));
|
||||
return(std::to_string(target._float));
|
||||
break;
|
||||
case('B'):
|
||||
return(_bool ? "(true)" : "(false)");
|
||||
return(target._bool ? "(true)" : "(false)");
|
||||
break;
|
||||
case('M'):
|
||||
return("");
|
||||
break;
|
||||
case('P'):
|
||||
return(std::to_string((u64)_ptr));
|
||||
return(std::to_string((u64)target._ptr));
|
||||
break;
|
||||
case('R'):
|
||||
return("");
|
||||
break;
|
||||
}
|
||||
return("");
|
||||
}
|
||||
|
||||
String DTree::to_json()
|
||||
{
|
||||
switch(type)
|
||||
const DTree& target = deref();
|
||||
switch(target.type)
|
||||
{
|
||||
case('S'):
|
||||
return(json_escape(_String));
|
||||
return(json_escape(target._String));
|
||||
break;
|
||||
case('F'):
|
||||
return(std::to_string(_float));
|
||||
return(std::to_string(target._float));
|
||||
break;
|
||||
case('B'):
|
||||
return(_bool ? "true" : "false");
|
||||
return(target._bool ? "true" : "false");
|
||||
break;
|
||||
case('M'):
|
||||
return("\"(array)\"");
|
||||
@@ -61,12 +87,17 @@ String DTree::to_json()
|
||||
case('P'):
|
||||
return("\"(pointer)\"");
|
||||
break;
|
||||
case('R'):
|
||||
return("\"(reference)\"");
|
||||
break;
|
||||
}
|
||||
return("\"(unknown)\"");
|
||||
}
|
||||
|
||||
String DTree::get_type_name()
|
||||
{
|
||||
switch(type)
|
||||
const DTree& target = deref();
|
||||
switch(target.type)
|
||||
{
|
||||
case('S'):
|
||||
return("String");
|
||||
@@ -83,11 +114,62 @@ String DTree::get_type_name()
|
||||
case('P'):
|
||||
return("pointer");
|
||||
break;
|
||||
case('R'):
|
||||
return("reference");
|
||||
break;
|
||||
}
|
||||
return("unknown");
|
||||
}
|
||||
|
||||
bool DTree::is_reference()
|
||||
{
|
||||
return(type == 'R');
|
||||
}
|
||||
|
||||
DTree* DTree::reference_target()
|
||||
{
|
||||
if(type != 'R')
|
||||
return(0);
|
||||
DTree* target = dtree_resolve_reference(this);
|
||||
if(target == 0 || target == this || target->type == 'R')
|
||||
return(0);
|
||||
return(target);
|
||||
}
|
||||
|
||||
const DTree* DTree::reference_target() const
|
||||
{
|
||||
if(type != 'R')
|
||||
return(0);
|
||||
const DTree* target = dtree_resolve_reference(this);
|
||||
if(target == 0 || target == this || target->type == 'R')
|
||||
return(0);
|
||||
return(target);
|
||||
}
|
||||
|
||||
DTree& DTree::deref()
|
||||
{
|
||||
DTree* target = dtree_resolve_reference(this);
|
||||
if(target == 0)
|
||||
return(*this);
|
||||
return(*target);
|
||||
}
|
||||
|
||||
const DTree& DTree::deref() const
|
||||
{
|
||||
const DTree* target = dtree_resolve_reference(this);
|
||||
if(target == 0)
|
||||
return(*this);
|
||||
return(*target);
|
||||
}
|
||||
|
||||
void DTree::set_type(char t)
|
||||
{
|
||||
DTree* target = reference_target();
|
||||
if(target)
|
||||
{
|
||||
target->set_type(t);
|
||||
return;
|
||||
}
|
||||
if(type != t)
|
||||
{
|
||||
type = t;
|
||||
@@ -103,30 +185,60 @@ void DTree::set_type(char t)
|
||||
|
||||
void DTree::set(String s)
|
||||
{
|
||||
DTree* target = reference_target();
|
||||
if(target)
|
||||
{
|
||||
target->set(s);
|
||||
return;
|
||||
}
|
||||
set_type('S');
|
||||
_String = s;
|
||||
}
|
||||
|
||||
void DTree::set(void* p)
|
||||
{
|
||||
DTree* target = reference_target();
|
||||
if(target)
|
||||
{
|
||||
target->set(p);
|
||||
return;
|
||||
}
|
||||
set_type('P');
|
||||
_ptr = p;
|
||||
}
|
||||
|
||||
void DTree::set(f64 f)
|
||||
{
|
||||
DTree* target = reference_target();
|
||||
if(target)
|
||||
{
|
||||
target->set(f);
|
||||
return;
|
||||
}
|
||||
set_type('F');
|
||||
_float = f;
|
||||
}
|
||||
|
||||
void DTree::set_bool(bool b)
|
||||
{
|
||||
DTree* target = reference_target();
|
||||
if(target)
|
||||
{
|
||||
target->set_bool(b);
|
||||
return;
|
||||
}
|
||||
set_type('B');
|
||||
_bool = b;
|
||||
}
|
||||
|
||||
void DTree::set(DTree source)
|
||||
{
|
||||
DTree* target = reference_target();
|
||||
if(target)
|
||||
{
|
||||
target->set(source);
|
||||
return;
|
||||
}
|
||||
set_type(source.type);
|
||||
switch(type)
|
||||
{
|
||||
@@ -145,11 +257,20 @@ void DTree::set(DTree source)
|
||||
case('P'):
|
||||
_ptr = source._ptr;
|
||||
break;
|
||||
case('R'):
|
||||
_ptr = source._ptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void DTree::set(StringMap source)
|
||||
{
|
||||
DTree* target = reference_target();
|
||||
if(target)
|
||||
{
|
||||
target->set(source);
|
||||
return;
|
||||
}
|
||||
set_type('M');
|
||||
for (auto it = source.begin(); it != source.end(); ++it)
|
||||
{
|
||||
@@ -157,13 +278,25 @@ void DTree::set(StringMap source)
|
||||
}
|
||||
}
|
||||
|
||||
void DTree::set_reference(DTree* target)
|
||||
{
|
||||
type = 'R';
|
||||
_ptr = target;
|
||||
}
|
||||
|
||||
DTree* DTree::key(String s)
|
||||
{
|
||||
DTree* target = reference_target();
|
||||
if(target)
|
||||
return(target->key(s));
|
||||
set_type('M');
|
||||
return(&_map[s]);
|
||||
}
|
||||
|
||||
DTree& DTree::operator [] (String s) {
|
||||
DTree* target = reference_target();
|
||||
if(target)
|
||||
return((*target)[s]);
|
||||
set_type('M');
|
||||
return(_map[s]);
|
||||
}
|
||||
@@ -176,6 +309,12 @@ void DTree::operator = (StringMap v) { set(v); }
|
||||
|
||||
void DTree::push(DTree& child)
|
||||
{
|
||||
DTree* target = reference_target();
|
||||
if(target)
|
||||
{
|
||||
target->push(child);
|
||||
return;
|
||||
}
|
||||
set_type('M');
|
||||
_map[std::to_string(_array_index)] = child;
|
||||
_array_index += 1;
|
||||
@@ -183,6 +322,9 @@ void DTree::push(DTree& child)
|
||||
|
||||
DTree DTree::pop()
|
||||
{
|
||||
DTree* target = reference_target();
|
||||
if(target)
|
||||
return(target->pop());
|
||||
set_type('M');
|
||||
auto last = _map.rbegin();
|
||||
DTree result = last->second;
|
||||
@@ -192,12 +334,24 @@ DTree DTree::pop()
|
||||
|
||||
void DTree::remove(String s)
|
||||
{
|
||||
DTree* target = reference_target();
|
||||
if(target)
|
||||
{
|
||||
target->remove(s);
|
||||
return;
|
||||
}
|
||||
set_type('M');
|
||||
_map.erase(s);
|
||||
}
|
||||
|
||||
void DTree::clear()
|
||||
{
|
||||
DTree* target = reference_target();
|
||||
if(target)
|
||||
{
|
||||
target->clear();
|
||||
return;
|
||||
}
|
||||
set_type('M');
|
||||
_map.clear();
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
String json_escape(String s);
|
||||
|
||||
struct DTree {
|
||||
@@ -16,6 +18,11 @@ struct DTree {
|
||||
String to_string();
|
||||
String to_json();
|
||||
String get_type_name();
|
||||
bool is_reference();
|
||||
DTree* reference_target();
|
||||
const DTree* reference_target() const;
|
||||
DTree& deref();
|
||||
const DTree& deref() const;
|
||||
void set_type(char t);
|
||||
void set(String s);
|
||||
void set(void* p);
|
||||
@@ -23,6 +30,7 @@ struct DTree {
|
||||
void set_bool(bool b);
|
||||
void set(DTree source);
|
||||
void set(StringMap source);
|
||||
void set_reference(DTree* target);
|
||||
DTree* key(String s);
|
||||
DTree& operator [] (String s);
|
||||
void operator = (String v);
|
||||
|
||||
@@ -77,9 +77,9 @@ String replace(String s, String search, String replace_with)
|
||||
|
||||
String trim(String raw)
|
||||
{
|
||||
u32 len = raw.length();
|
||||
u32 start_pos = 0;
|
||||
u32 end_pos = len - 1;
|
||||
s64 len = raw.length();
|
||||
s64 start_pos = 0;
|
||||
s64 end_pos = len - 1;
|
||||
if(len == 0 || (len == 1 && isspace(raw[0])))
|
||||
return("");
|
||||
while(start_pos < len && isspace(raw[start_pos]))
|
||||
@@ -610,7 +610,13 @@ void ob_close()
|
||||
delete context->ob;
|
||||
context->ob_stack.pop_back();
|
||||
if(context->ob_stack.size() == 0)
|
||||
{
|
||||
ob_start();
|
||||
}
|
||||
else
|
||||
{
|
||||
context->ob = context->ob_stack.back();
|
||||
}
|
||||
}
|
||||
|
||||
String ob_get()
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
u8 char_to_u8(char input);
|
||||
u8 hex_to_u8(String src);
|
||||
u64 int_val(String s, u32 base = 10);
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
/* ================ sha1.h ================ */
|
||||
/*
|
||||
SHA-1 in C
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
DTree markdown_to_ast(String src);
|
||||
DTree markdown_to_ast(String src, DTree options);
|
||||
String markdown_to_html(String src);
|
||||
String markdown_to_html(String src, DTree options);
|
||||
@@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
struct MySQLFieldInfo {
|
||||
String name;
|
||||
String table;
|
||||
|
||||
+45
-9
@@ -10,6 +10,45 @@
|
||||
#include <sys/file.h>
|
||||
#include "sys.h"
|
||||
|
||||
String capture_backtrace_string(u32 max_frames, u32 skip_frames)
|
||||
{
|
||||
if(max_frames == 0)
|
||||
return("");
|
||||
|
||||
std::vector<void*> frames(max_frames);
|
||||
size_t size = backtrace(frames.data(), max_frames);
|
||||
if(size == 0)
|
||||
return("");
|
||||
|
||||
char** symbols = backtrace_symbols(frames.data(), size);
|
||||
if(!symbols)
|
||||
return("");
|
||||
|
||||
String trace;
|
||||
for(size_t i = skip_frames; i < size; i++)
|
||||
{
|
||||
trace += symbols[i];
|
||||
trace += "\n";
|
||||
}
|
||||
free(symbols);
|
||||
return(trace);
|
||||
}
|
||||
|
||||
String signal_name(int sig)
|
||||
{
|
||||
switch(sig)
|
||||
{
|
||||
case SIGABRT: return("SIGABRT");
|
||||
case SIGBUS: return("SIGBUS");
|
||||
case SIGFPE: return("SIGFPE");
|
||||
case SIGILL: return("SIGILL");
|
||||
case SIGINT: return("SIGINT");
|
||||
case SIGSEGV: return("SIGSEGV");
|
||||
case SIGTERM: return("SIGTERM");
|
||||
default: return("");
|
||||
}
|
||||
}
|
||||
|
||||
String shell_exec(String cmd)
|
||||
{
|
||||
//printf("(i) shell_exec(%s)\n", cmd.c_str());
|
||||
@@ -410,15 +449,12 @@ StringMap memcache_get_multiple(u64 connection, StringList keys)
|
||||
|
||||
void on_segfault(int sig)
|
||||
{
|
||||
void *array[10];
|
||||
size_t size;
|
||||
|
||||
// get void*'s for all entries on the stack
|
||||
size = backtrace(array, 10);
|
||||
|
||||
// print out all the frames to stderr
|
||||
fprintf(stderr, "SEG FAULT: %d:\n", sig);
|
||||
backtrace_symbols_fd(array, size, STDERR_FILENO);
|
||||
String trace = capture_backtrace_string(32, 1);
|
||||
String sig_label = signal_name(sig);
|
||||
if(sig_label != "")
|
||||
fprintf(stderr, "SEG FAULT: %d (%s):\n%s", sig, sig_label.c_str(), trace.c_str());
|
||||
else
|
||||
fprintf(stderr, "SEG FAULT: %d:\n%s", sig, trace.c_str());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
+7
-3
@@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
String shell_exec(String cmd);
|
||||
@@ -43,11 +45,13 @@ u8 ws_opcode();
|
||||
bool ws_is_binary();
|
||||
StringList ws_connections(String scope = "");
|
||||
u64 ws_connection_count(String scope = "");
|
||||
bool ws_send(String message, String scope = "");
|
||||
u64 ws_broadcast(String message, String scope = "");
|
||||
bool ws_send_to(String connection_id, String message);
|
||||
bool ws_send(String message, bool binary = false, String scope = "");
|
||||
bool ws_send_to(String connection_id, String message, bool binary = false);
|
||||
bool ws_close(String connection_id = "");
|
||||
|
||||
String capture_backtrace_string(u32 max_frames = 32, u32 skip_frames = 0);
|
||||
String signal_name(int sig);
|
||||
|
||||
String memcache_escape_key(String key);
|
||||
StringList memcache_escape_keys(StringList keys);
|
||||
u64 memcache_connect(String host = "127.0.0.1", short port = 11211);
|
||||
|
||||
+10
-5
@@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <list>
|
||||
@@ -52,7 +54,7 @@ typedef std::ostringstream ByteStream;
|
||||
struct Request;
|
||||
struct DTree;
|
||||
|
||||
typedef void (*call_handler)(DTree& call_param);
|
||||
typedef void (*request_ref_handler)(Request& request);
|
||||
typedef DTree* (*dtree_call_handler)(DTree* call_param);
|
||||
typedef void (*request_handler)(Request* request);
|
||||
|
||||
@@ -77,8 +79,8 @@ struct SharedUnit {
|
||||
void* so_handle;
|
||||
|
||||
request_handler on_setup;
|
||||
call_handler on_render;
|
||||
call_handler on_websocket;
|
||||
request_ref_handler on_render;
|
||||
request_ref_handler on_websocket;
|
||||
|
||||
String compiler_messages;
|
||||
time_t last_compiled;
|
||||
@@ -113,7 +115,7 @@ String nibble(String div, String& haystack);
|
||||
|
||||
#include "dtree.h"
|
||||
|
||||
void compiler_invoke(Request* context, String file_name, DTree& call_param);
|
||||
void compiler_invoke(Request* context, String file_name);
|
||||
|
||||
struct Request {
|
||||
|
||||
@@ -126,6 +128,8 @@ struct Request {
|
||||
StringMap session;
|
||||
|
||||
DTree var;
|
||||
DTree call;
|
||||
DTree connection;
|
||||
|
||||
String session_id = "";
|
||||
String session_name = "";
|
||||
@@ -148,7 +152,7 @@ struct Request {
|
||||
struct Flags {
|
||||
bool log_request = true;
|
||||
bool is_finished = false;
|
||||
int status;
|
||||
int status = 0;
|
||||
bool output_closed = false;
|
||||
bool params_closed = false;
|
||||
bool input_closed = false;
|
||||
@@ -173,6 +177,7 @@ struct Request {
|
||||
bool is_websocket = false;
|
||||
String websocket_connection_id = "";
|
||||
String websocket_scope = "";
|
||||
DTree* websocket_connection_state = 0;
|
||||
u8 websocket_opcode = 0;
|
||||
bool websocket_is_binary = false;
|
||||
bool websocket_is_text = false;
|
||||
|
||||
@@ -7,4 +7,5 @@
|
||||
#include "sys.cpp"
|
||||
#include "uri.cpp"
|
||||
#include "compiler.cpp"
|
||||
#include "markdown.cpp"
|
||||
#include "mysql-connector.cpp"
|
||||
|
||||
+3
-2
@@ -1,10 +1,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
#include "hash.h"
|
||||
#include "functionlib.h"
|
||||
#include "sys.h"
|
||||
#include "uri.h"
|
||||
#include "compiler.h"
|
||||
#include "markdown.h"
|
||||
#include "mysql-connector.h"
|
||||
|
||||
|
||||
|
||||
+2
-1
@@ -1,3 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
#include "uce_lib.h"
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
String var_dump(URI uri, String prefix = "", String postfix = "\n");
|
||||
String uri_decode(String q);
|
||||
|
||||
Reference in New Issue
Block a user