diff --git a/src/luaapi.c b/src/luaapi.c index b6f7518..e80714c 100644 --- a/src/luaapi.c +++ b/src/luaapi.c @@ -3285,26 +3285,99 @@ static const char *k3glslloader(const char *fn) { return data; } +#define KV_STORE_SIZE 128 +struct KVPair { + char *key; + char *value; +}; +typedef struct KVPair KVStore[KV_STORE_SIZE]; + +static intmax_t kvpair_compare(const void *a_, const void *b_) { + const struct KVPair *a = a_; + const struct KVPair *b = b_; + + if(!a->key) { + return 1; + } else if(!b->key) { + return -1; + } + + return strcmp(a->key, b->key); +} +static char *kvstore_tostring(KVStore store) { + ssort(store, KV_STORE_SIZE, sizeof(struct KVPair), kvpair_compare); + + const size_t sz = 2048; + char *ret = calloc(1, sz); + + for(size_t i = 0; i < KV_STORE_SIZE; i++) { + if(store[i].key == NULL) { + break; + } + + char def[256]; + snprintf(def, sizeof(def), "%s\x1F%s\x1E", store[i].key, store[i].value); + + strncat(ret, def, sz - strlen(ret) - 1); + } + + return ret; +} +static bool kvstore_add(KVStore store, char *key, char *value) { + for(size_t i = 0; i < KV_STORE_SIZE; i++) { + if(store[i].key == NULL) { + store[i].key = key; + store[i].value = value; + return true; + } + } + + return false; +} +static bool kvstore_add_fmt(KVStore store, char *key, const char *format, ...) { + va_list vl; + va_start(vl, format); + + va_list vl2; + va_copy(vl2, vl); + size_t len = vsnprintf(NULL, 0, format, vl2); + + char *def = malloc(len); + vsnprintf(def, len, format, vl); + + va_end(vl); + va_end(vl2); + + return kvstore_add(store, key, def); +} +static void kvstore_free(KVStore store) { + for(size_t i = 0; i < KV_STORE_SIZE; i++) { + free(store[i].key); + free(store[i].value); + } +} + // The glsl field of a material table is cached and stored // in the resource manager. This function generates its name. static char *glsl_table_fullname() { + KVStore store = {}; + lua_getfield(L, -1, "vs"); lua_geti(L, -1, 1); // Version size_t vsVer = lua_tointeger(L, -1); lua_geti(L, -2, 2); // Filename - char *vsFile = strdup(lua_tostring(L, -1)); + kvstore_add(store, strdup("vs"), strdup(lua_tostring(L, -1))); + kvstore_add_fmt(store, strdup("vsv"), "%lu", vsVer); lua_pop(L, 3); lua_getfield(L, -1, "fs"); lua_geti(L, -1, 1); // Version size_t fsVer = lua_tointeger(L, -1); lua_geti(L, -2, 2); // Filename - char *fsFile = strdup(lua_tostring(L, -1)); + kvstore_add(store, strdup("fs"), strdup(lua_tostring(L, -1))); + kvstore_add_fmt(store, strdup("fsv"), "%lu", fsVer); lua_pop(L, 3); - char ret[1024]; - snprintf(ret, sizeof(ret), "\x1E%u\x1E%s\x1E%u\x1E%s\x1E", vsVer, vsFile, fsVer, fsFile); - lua_getfield(L, -1, "defs"); lua_pushnil(L); while(lua_next(L, -2)) { @@ -3314,19 +3387,17 @@ static char *glsl_table_fullname() { continue; } - char def[128]; - snprintf(def, sizeof(def), "%s\x1F%s\x1E", lua_tostring(L, -2), lua_tostring(L, -1)); - - strncat(ret, def, sizeof(ret) - strlen(ret) - 1); + kvstore_add(store, strdup(lua_tostring(L, -2)), strdup(lua_tostring(L, -1))); lua_pop(L, 1); } lua_pop(L, 1); - free(vsFile); - free(fsFile); + char *fullname = kvstore_tostring(store); - return strdup(ret); + kvstore_free(store); + + return fullname; } static int parse_glsl_table(struct k3Mat *mat) {