aboutsummaryrefslogtreecommitdiff
path: root/src/LuaEngine
diff options
context:
space:
mode:
Diffstat (limited to 'src/LuaEngine')
-rw-r--r--src/LuaEngine/LuaEngine.c124
-rw-r--r--src/LuaEngine/LuaEngine.h15
2 files changed, 137 insertions, 2 deletions
diff --git a/src/LuaEngine/LuaEngine.c b/src/LuaEngine/LuaEngine.c
index c34fd68..af30403 100644
--- a/src/LuaEngine/LuaEngine.c
+++ b/src/LuaEngine/LuaEngine.c
@@ -143,6 +143,121 @@ static char *make_chunk_name(const char *input_path, unsigned long line) {
return chunk_name;
}
+typedef struct {
+ htmlDocPtr source;
+ EmitList *emits;
+} EmitContext;
+
+static int grow_emit_list(EmitList *emits) {
+ size_t larger_capacity;
+ EmittedPage *larger_items;
+
+ if (emits->capacity > SIZE_MAX / (2 * sizeof(*emits->items))) {
+ return -1;
+ }
+
+ larger_capacity = emits->capacity == 0 ? 4 : emits->capacity * 2;
+ larger_items =
+ realloc(emits->items, larger_capacity * sizeof(*emits->items));
+ if (larger_items == NULL) {
+ return -1;
+ }
+
+ emits->items = larger_items;
+ emits->capacity = larger_capacity;
+ return 0;
+}
+
+static int append_emit(EmitList *emits, const char *path,
+ htmlDocPtr document) {
+ EmittedPage *emitted;
+
+ if (emits->length == emits->capacity && grow_emit_list(emits) != 0) {
+ return -1;
+ }
+
+ emitted = &emits->items[emits->length];
+ emitted->path = duplicate_string(path);
+ if (emitted->path == NULL) {
+ return -1;
+ }
+
+ emitted->document = document;
+ ++emits->length;
+ return 0;
+}
+
+void emit_list_free(EmitList *emits) {
+ size_t index;
+
+ for (index = 0; index < emits->length; ++index) {
+ free(emits->items[index].path);
+ xmlFreeDoc(emits->items[index].document);
+ }
+ free(emits->items);
+ emits->items = NULL;
+ emits->length = 0;
+ emits->capacity = 0;
+}
+
+static htmlDocPtr snapshot_document(htmlDocPtr source, lua_State *lua) {
+ htmlDocPtr copy;
+ xmlDtdPtr dtd;
+ xmlNodePtr root;
+
+ lua_getglobal(lua, "page");
+ root = lua_istable(lua, -1) ? dom_page_from_lua(lua, lua_gettop(lua)) : NULL;
+ lua_pop(lua, 1);
+ if (root == NULL) {
+ return NULL;
+ }
+
+ copy = xmlNewDoc(BAD_CAST "1.0");
+ if (copy == NULL) {
+ xmlFreeNode(root);
+ return NULL;
+ }
+ if (source->encoding != NULL) {
+ copy->encoding = xmlStrdup(source->encoding);
+ }
+
+ dtd = xmlGetIntSubset(source);
+ if (dtd != NULL) {
+ dtd = xmlCopyDtd(dtd);
+ if (dtd != NULL) {
+ xmlAddChild((xmlNodePtr)copy, (xmlNodePtr)dtd);
+ copy->intSubset = dtd;
+ }
+ }
+
+ xmlAddChild((xmlNodePtr)copy, root);
+ return copy;
+}
+
+static int page_emit(lua_State *lua) {
+ EmitContext *context;
+ const char *path;
+ htmlDocPtr document;
+
+ luaL_checktype(lua, 1, LUA_TTABLE);
+ path = luaL_checkstring(lua, 2);
+ if (path[0] == '\0') {
+ return luaL_error(lua, "emit path cannot be empty");
+ }
+ context = lua_touserdata(lua, lua_upvalueindex(1));
+
+ document = snapshot_document(context->source, lua);
+ if (document == NULL) {
+ return luaL_error(lua, "unable to snapshot the current page");
+ }
+
+ if (append_emit(context->emits, path, document) != 0) {
+ xmlFreeDoc(document);
+ return luaL_error(lua, "unable to record emitted page");
+ }
+ return 0;
+}
+
static int run_script(lua_State *lua, const LuaScript *script,
const char *input_path) {
char *source_path = NULL;
@@ -228,7 +343,9 @@ static int replace_document_root(lua_State *lua, htmlDocPtr document,
return 0;
}
-int process_html_document(htmlDocPtr document, const char *input_path) {
+int process_html_document(htmlDocPtr document, const char *input_path,
+ EmitList *emits) {
+ EmitContext context = {document, emits};
xmlNodePtr root = xmlDocGetRootElement(document);
ScriptList scripts = {0};
lua_State *lua;
@@ -262,6 +379,11 @@ int process_html_document(htmlDocPtr document, const char *input_path) {
directory_walker_register(lua, input_path);
dom_push_page(lua, root);
lua_setglobal(lua, "page");
+ lua_getglobal(lua, "page");
+ lua_pushlightuserdata(lua, &context);
+ lua_pushcclosure(lua, page_emit, 1);
+ lua_setfield(lua, -2, "emit");
+ lua_pop(lua, 1);
result = run_scripts(lua, &scripts, input_path);
if (result == 0) {
diff --git a/src/LuaEngine/LuaEngine.h b/src/LuaEngine/LuaEngine.h
index bd035b9..2a5eea4 100644
--- a/src/LuaEngine/LuaEngine.h
+++ b/src/LuaEngine/LuaEngine.h
@@ -3,6 +3,19 @@
#include <libxml/HTMLparser.h>
-int process_html_document(htmlDocPtr document, const char *input_path);
+typedef struct {
+ char *path;
+ htmlDocPtr document;
+} EmittedPage;
+
+typedef struct {
+ EmittedPage *items;
+ size_t length;
+ size_t capacity;
+} EmitList;
+
+int process_html_document(htmlDocPtr document, const char *input_path,
+ EmitList *emits);
+void emit_list_free(EmitList *emits);
#endif