diff options
author | Kartik K. Agaram <vc@akkartik.com> | 2021-12-11 00:30:42 -0800 |
---|---|---|
committer | Kartik K. Agaram <vc@akkartik.com> | 2021-12-11 00:43:26 -0800 |
commit | 0b0a58da066ba1da2d74348af66e85a7f7a95bbf (patch) | |
tree | 81c4b7bb3b7dca41d1b83118c7457f0f780be18c /src/tlv.c | |
parent | 469ad4e5469b5cda4c61d39cc042852467691a82 (diff) | |
download | teliva-0b0a58da066ba1da2d74348af66e85a7f7a95bbf.tar.gz |
snapshot: start reading a new format
I really wanted to avoid getting into defining or parsing new file formats. However, using the entire power of Lua is not ideal, as described earlier in Konrad Hinsen's bug. In addition to everything else, it's a vector for arbitrary code execution when someone loads an untrusted image. I could use JSON, but it requires ugly string escaping. Seems cleaner to just use YAML. But YAML is complex and needs its own dependencies. If I'm going to do my own, might as well make the multi-line string format really clear. I can't yet write the new format.
Diffstat (limited to 'src/tlv.c')
-rw-r--r-- | src/tlv.c | 73 |
1 files changed, 73 insertions, 0 deletions
diff --git a/src/tlv.c b/src/tlv.c new file mode 100644 index 0000000..bf23da8 --- /dev/null +++ b/src/tlv.c @@ -0,0 +1,73 @@ +#include <assert.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> + +#include "lua.h" +#include "lauxlib.h" + +void teliva_load_multiline_string(lua_State* L, FILE* in) { + luaL_Buffer b; + luaL_buffinit(L, &b); + char line[1024] = {'\0'}; + int indent = -1; + while (!feof(in)) { + char c = fgetc(in); + ungetc(c, in); + if (c != ' ') break; + assert(fgets(line, 1024, in)); + assert(line[strlen(line)-1] == '\n'); + char* start = strchr(line, '>'); + if (indent == -1) + indent = start - line; + else + assert(indent == start - line); + ++start; /* skip '>' */ + luaL_addstring(&b, start); + } + luaL_pushresult(&b); +} + +/* leave a single table on stack containing the next top-level definition from the file */ +void teliva_load_definition(lua_State* L, FILE* in) { + lua_newtable(L); + int def_idx = lua_gettop(L); + char line[1024] = {'\0'}; + char key[512] = {'\0'}; + char value[1024] = {'\0'}; + while (!feof(in)) { + assert(fgets(line, 1024, in)); + assert(line[strlen(line)-1] == '\n'); + if (line[0] == '#') continue; /* comment */ + assert(line[0] == '-' || line[0] == ' '); + assert(line[1] == ' '); + memset(key, 0, 512); + memset(value, 0, 1024); + sscanf(line+2, "%s%s", key, value); + assert(key[strlen(key)-1] == ':'); + key[strlen(key)-1] = '\0'; + lua_pushstring(L, key); + if (value[0] != '\0') + lua_pushstring(L, value); /* value string on same line */ + else + teliva_load_multiline_string(L, in); /* load from later lines */ + lua_settable(L, def_idx); + /* done with this definition? */ + char c = fgetc(in); + ungetc(c, in); + if (c != ' ') break; + } +} + +void load_tlv(lua_State* L, char* filename) { + lua_newtable(L); + int history_array = lua_gettop(L); + FILE* in = fopen(filename, "r"); + for (int i = 1; !feof(in); ++i) { + teliva_load_definition(L, in); + if (lua_isnil(L, -1)) break; + lua_rawseti(L, history_array, i); + } + fclose(in); + lua_setglobal(L, "teliva_program"); +} |