2026-06-12 19:55:35 +00:00

189 lines
3.6 KiB
C++

// WASM-PROPOSAL Phase 3 — dynamic-loader core scaffold.
//
// This core owns the UCE heap, Request, DValue/UCEB1, and output buffer. The
// Phase 3 loader dynamically links a PIC side module generated in the same
// shape as UCE preprocessor output, sets its Request* context, and invokes its
// __uce_render entry.
#include <cstdlib>
#include <cstring>
#include <functional>
#include "../../src/lib/types.h"
#include "../../src/lib/dvalue.cpp"
extern "C" {
size_t uce_host_ctx_read(char* buf, size_t cap);
void uce_host_log(int level, const char* buf, size_t len);
}
extern "C" void phase3_core_print(const char* data, size_t len)
{
if(context && context->ob)
context->ob->write(data, len);
}
extern "C" void phase3_core_invoke_callback(void (*cb)(int), int value)
{
cb(value);
}
extern "C" void phase3_core_invoke_function(std::function<int(int)>* f, int value)
{
String out = "<p>fn=" + std::to_string((*f)(value)) + "</p>\n";
phase3_core_print(out.data(), out.size());
}
extern "C" intptr_t core_table_index_of_phase3_core_print()
{
return(reinterpret_cast<intptr_t>(phase3_core_print));
}
static Request g_request;
static ByteStream g_ob;
static String g_output;
SharedUnit::~SharedUnit() {}
String html_escape(String s)
{
String result;
for(char c : s)
{
switch(c)
{
case '&': result += "&amp;"; break;
case '<': result += "&lt;"; break;
case '>': result += "&gt;"; break;
case '"': result += "&quot;"; break;
case '\'': result += "&#39;"; break;
default: result.push_back(c); break;
}
}
return(result);
}
String nibble(String div, String& haystack)
{
auto pos = haystack.find(div);
if(pos == String::npos)
{
auto result = haystack;
haystack.clear();
return(result);
}
auto result = haystack.substr(0, pos);
haystack.erase(0, pos + div.length());
return(result);
}
void Request::ob_start()
{
ob_stack.push_back(new ByteStream());
ob = ob_stack.back();
}
void Request::set_status(s32 code, String reason)
{
if(reason == "")
reason = code == 200 ? "OK" : "Status";
response_code = "HTTP/1.1 " + std::to_string(code) + " " + reason;
}
Request::~Request()
{
for(auto* stream : ob_stack)
delete stream;
ob_stack.clear();
}
static void phase3_clear_ob_stack()
{
for(auto* stream : g_request.ob_stack)
delete stream;
g_request.ob_stack.clear();
}
static void phase3_apply_context(DValue& root)
{
g_request.call = root;
g_request.params.clear();
DValue* params = root.key("params");
if(params)
{
params->each([&](const DValue& item, String key) {
g_request.params[key] = item.to_string();
});
}
}
extern "C" {
void* uce_alloc(size_t len)
{
return(malloc(len));
}
void uce_free(void* ptr)
{
free(ptr);
}
int uce_phase3_prepare()
{
context = &g_request;
phase3_clear_ob_stack();
g_ob.str("");
g_ob.clear();
g_request.ob = &g_ob;
g_request.out = "";
g_output = "";
size_t ctx_required = uce_host_ctx_read(0, 0);
if(ctx_required == 0)
return(10);
char* ctx_buf = (char*)malloc(ctx_required);
if(ctx_buf == 0)
return(11);
size_t ctx_len = uce_host_ctx_read(ctx_buf, ctx_required);
if(ctx_len != ctx_required)
{
free(ctx_buf);
return(12);
}
DValue decoded;
String error;
bool ok = ucb_decode(String(ctx_buf, ctx_len), decoded, &error);
free(ctx_buf);
if(!ok)
{
uce_host_log(3, error.data(), error.size());
return(20);
}
phase3_apply_context(decoded);
return(0);
}
Request* uce_phase3_request()
{
return(&g_request);
}
void uce_phase3_finish()
{
g_output = g_ob.str();
}
const char* uce_phase3_output_data()
{
return(g_output.data());
}
size_t uce_phase3_output_size()
{
return(g_output.size());
}
}