diff options
author | Vsevolod Stakhov <vsevolod@rspamd.com> | 2024-08-16 13:21:28 +0100 |
---|---|---|
committer | Vsevolod Stakhov <vsevolod@rspamd.com> | 2024-08-16 13:21:28 +0100 |
commit | 05ea03c3b2cd36a35996e8dc0c59a6b1d0659df4 (patch) | |
tree | 99a8458d1c1587977f95e4a4493bdfd9ae85f8a3 /contrib | |
parent | e88ab8ee93e49b9f2ebc7d2026f5c5ad642ff808 (diff) | |
download | rspamd-05ea03c3b2cd36a35996e8dc0c59a6b1d0659df4.tar.gz rspamd-05ea03c3b2cd36a35996e8dc0c59a6b1d0659df4.zip |
[Minor] Add some hacks to convert lua table into either object or an array
Diffstat (limited to 'contrib')
-rw-r--r-- | contrib/libucl/lua_ucl.c | 161 |
1 files changed, 118 insertions, 43 deletions
diff --git a/contrib/libucl/lua_ucl.c b/contrib/libucl/lua_ucl.c index c2b37b14c..19ac9cb12 100644 --- a/contrib/libucl/lua_ucl.c +++ b/contrib/libucl/lua_ucl.c @@ -44,6 +44,7 @@ #include "ucl.h" #include "ucl_internal.h" #include "lua_ucl.h" +#include "kvec.h" #include <strings.h> /*** @@ -1423,67 +1424,141 @@ lua_ucl_newindex(lua_State *L) obj = lua_ucl_object_get(L, 1); int key_type = lua_type(L, 2); - if (ucl_object_type(obj) == UCL_OBJECT && (key_type == LUA_TSTRING)) { - lua_Integer keylen; - const char *key = lua_tolstring(L, 2, &keylen); + if (ucl_object_type(obj) == UCL_OBJECT) { + if (key_type == LUA_TSTRING) { + lua_Integer keylen; + const char *key = lua_tolstring(L, 2, &keylen); - ucl_object_t *value_obj = lua_ucl_object_get(L, 3); - if (value_obj) { - value_obj = ucl_object_ref(value_obj); - } - else { - value_obj = ucl_object_lua_import(L, 3); + ucl_object_t *value_obj = lua_ucl_object_get(L, 3); + if (value_obj) { + value_obj = ucl_object_ref(value_obj); + } + else { + value_obj = ucl_object_lua_import(L, 3); + } + + if (ucl_object_lookup_len(obj, key, keylen) != NULL) { + if (value_obj != NULL) { + ucl_object_replace_key(obj, value_obj, key, keylen, true); + } + else { + /* Delete key */ + ucl_object_delete_keyl(obj, key, keylen); + } + } + else { + if (value_obj != NULL) { + ucl_object_insert_key(obj, value_obj, key, keylen, true); + } + /* Do nothing if value_obj is null, like Lua does */ + } } + else if (key_type == LUA_TNUMBER) { + /* + * We have some object but wanted it to be an array + * In Lua, this is allowed but UCL has distinction between array and object + * Here, we allow one thing: if an object is empty, and we want a numeric index, we convert it to an array + */ + lua_Integer idx = lua_tointeger(L, 2); + if (idx == 1 && obj->len == 0 && obj->value.ov == NULL) { + /* UCL preallocate arrays, but it is not a requirement once av is NULL */ + obj->type = UCL_ARRAY; + ucl_object_t *value_obj = lua_ucl_object_get(L, 3); + if (value_obj) { + value_obj = ucl_object_ref(value_obj); + } + else { + value_obj = ucl_object_lua_import(L, 3); + } - if (ucl_object_lookup_len(obj, key, keylen) != NULL) { - if (value_obj != NULL) { - ucl_object_replace_key(obj, value_obj, key, keylen, true); + if (value_obj == NULL) { + return luaL_error(L, "invalid value type: %s", lua_typename(L, lua_type(L, 3))); + } + ucl_array_append(obj, value_obj); } else { - /* Delete key */ - ucl_object_delete_keyl(obj, key, keylen); + return luaL_error(L, "invalid index type for an object: %s", lua_typename(L, key_type)); } } else { - if (value_obj != NULL) { - ucl_object_insert_key(obj, value_obj, key, keylen, true); - } - /* Do nothing if value_obj is null, like Lua does */ + return luaL_error(L, "invalid index type for an object: %s", lua_typename(L, key_type)); } return 0; } - else if (ucl_object_type(obj) == UCL_ARRAY && (key_type == LUA_TNUMBER)) { - lua_Integer idx = lua_tointeger(L, 2); + else if (ucl_object_type(obj) == UCL_ARRAY) { + if (key_type == LUA_TNUMBER) { + lua_Integer idx = lua_tointeger(L, 2); - ucl_object_t *value_obj = lua_ucl_object_get(L, 3); - if (value_obj) { - value_obj = ucl_object_ref(value_obj); - } - else { - value_obj = ucl_object_lua_import(L, 3); - } + ucl_object_t *value_obj = lua_ucl_object_get(L, 3); + if (value_obj) { + value_obj = ucl_object_ref(value_obj); + } + else { + value_obj = ucl_object_lua_import(L, 3); + } - if (value_obj == NULL) { - return luaL_error(L, "invalid value type: %s", lua_typename(L, lua_type(L, 3))); - } + if (value_obj == NULL) { + return luaL_error(L, "invalid value type: %s", lua_typename(L, lua_type(L, 3))); + } - /* Lua allows sparse arrays and ucl does not - * So we have 3 options: - * 1) Idx is some existing index, so we need to replace it - * 3) Idx is #len, so we append it - * Everything else is an error - */ - if (idx == ucl_array_size(obj) + 1) { - ucl_array_append(obj, value_obj); + /* Lua allows sparse arrays and ucl does not + * So we have 2 options: + * 1) Idx is some existing index, so we need to replace it + * 3) Idx is #len, so we append it + * Everything else is an error + */ + if (idx == ucl_array_size(obj) + 1) { + ucl_array_append(obj, value_obj); + } + else if (idx >= 1 && idx <= ucl_array_size(obj)) { + ucl_array_replace_index(obj, value_obj, idx - 1); + } + else { + ucl_object_unref(value_obj); + + return luaL_error(L, "invalid index for array: %d", (int) idx); + } } - else if (idx >= 1 && idx <= ucl_array_size(obj)) { - ucl_array_replace_index(obj, value_obj, idx - 1); + else if (key_type == LUA_TSTRING) { + /* + * We have some array but wanted it to be an object + * In Lua, this is allowed but UCL has distinction between array and object + * Here, we allow one thing: if an array is empty, and we want a string index, we convert it to an object + * The biggest issue is that ucl array is preallocated in general, so we need to free it somehow + */ + /* + * Dirty hacks are here + */ + kvec_t(ucl_object_t *) *real_ar = obj->value.av; + + if (real_ar) { + kv_destroy(*real_ar); + } + UCL_FREE(sizeof(*real_ar), real_ar); + obj->value.av = NULL; + obj->type = UCL_OBJECT; + + lua_Integer keylen; + const char *key = lua_tolstring(L, 2, &keylen); + + ucl_object_t *value_obj = lua_ucl_object_get(L, 3); + if (value_obj) { + value_obj = ucl_object_ref(value_obj); + } + else { + value_obj = ucl_object_lua_import(L, 3); + } + + if (value_obj) { + ucl_object_insert_key(obj, value_obj, key, keylen, true); + } + else { + return luaL_error(L, "invalid value type: %s", lua_typename(L, lua_type(L, 3))); + } } else { - ucl_object_unref(value_obj); - - return luaL_error(L, "invalid index for array: %d", (int) idx); + return luaL_error(L, "invalid index type for an array: %s", lua_typename(L, key_type)); } return 0; |