aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libucl
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@highsecure.ru>2019-07-08 13:01:08 +0100
committerVsevolod Stakhov <vsevolod@highsecure.ru>2019-07-08 13:01:08 +0100
commit9b74e57ad3fb694741fdcf5e27a046fbe99a40f7 (patch)
tree3080fb43edac872ca98c4fe3c5953e59d02ceef9 /contrib/libucl
parent3d8f5c5e7f4ee08aa033805313fe9b5585a2d4fa (diff)
downloadrspamd-9b74e57ad3fb694741fdcf5e27a046fbe99a40f7.tar.gz
rspamd-9b74e57ad3fb694741fdcf5e27a046fbe99a40f7.zip
[Feature] Libucl: Allow to sort keys in ucl objects
Diffstat (limited to 'contrib/libucl')
-rw-r--r--contrib/libucl/lua_ucl.c13
-rw-r--r--contrib/libucl/ucl.h13
-rw-r--r--contrib/libucl/ucl_hash.c49
-rw-r--r--contrib/libucl/ucl_hash.h7
-rw-r--r--contrib/libucl/ucl_util.c8
5 files changed, 90 insertions, 0 deletions
diff --git a/contrib/libucl/lua_ucl.c b/contrib/libucl/lua_ucl.c
index b97387d9e..049b1d08c 100644
--- a/contrib/libucl/lua_ucl.c
+++ b/contrib/libucl/lua_ucl.c
@@ -1368,6 +1368,7 @@ lua_ucl_to_format (lua_State *L)
{
ucl_object_t *obj;
int format = UCL_EMIT_JSON;
+ bool sort = false;
if (lua_gettop (L) > 1) {
if (lua_type (L, 2) == LUA_TNUMBER) {
@@ -1397,10 +1398,22 @@ lua_ucl_to_format (lua_State *L)
format = UCL_EMIT_MSGPACK;
}
}
+
+ if (lua_isboolean (L, 3)) {
+ sort = lua_toboolean (L, 3);
+ }
}
obj = ucl_object_lua_import (L, 1);
+
if (obj != NULL) {
+
+ if (sort) {
+ if (ucl_object_type (obj) == UCL_OBJECT) {
+ ucl_object_sort_keys (obj, UCL_SORT_KEYS_RECURSIVE);
+ }
+ }
+
lua_ucl_to_string (L, obj, format);
ucl_object_unref (obj);
}
diff --git a/contrib/libucl/ucl.h b/contrib/libucl/ucl.h
index 01542d3c7..b6b9f44c0 100644
--- a/contrib/libucl/ucl.h
+++ b/contrib/libucl/ucl.h
@@ -800,6 +800,19 @@ UCL_EXTERN int ucl_object_compare_qsort (const ucl_object_t **o1,
UCL_EXTERN void ucl_object_array_sort (ucl_object_t *ar,
int (*cmp)(const ucl_object_t **o1, const ucl_object_t **o2));
+enum ucl_object_keys_sort_flags {
+ UCL_SORT_KEYS_DEFAULT = 0,
+ UCL_SORT_KEYS_ICASE = (1u << 0u),
+ UCL_SORT_KEYS_RECURSIVE = (1u << 1u),
+};
+/***
+ * Sorts keys in object in place
+ * @param obj
+ * @param how
+ */
+UCL_EXTERN void ucl_object_sort_keys (ucl_object_t *obj,
+ enum ucl_object_keys_sort_flags how);
+
/**
* Get the priority for specific UCL object
* @param obj any ucl object
diff --git a/contrib/libucl/ucl_hash.c b/contrib/libucl/ucl_hash.c
index 6594b2557..a8e735d13 100644
--- a/contrib/libucl/ucl_hash.c
+++ b/contrib/libucl/ucl_hash.c
@@ -28,6 +28,7 @@
#include "cryptobox.h"
#include "libutil/str_util.h"
+#include "ucl.h"
#include <time.h>
#include <limits.h>
@@ -453,4 +454,52 @@ ucl_hash_reserve (ucl_hash_t *hashlin, size_t sz)
return true;
e0:
return false;
+}
+
+static int
+ucl_hash_cmp_icase (const void *a, const void *b)
+{
+ const ucl_object_t *oa = *(const ucl_object_t **)a,
+ *ob = *(const ucl_object_t **)b;
+
+ if (oa->keylen == ob->keylen) {
+ return rspamd_lc_cmp (oa->key, ob->key, oa->keylen);
+ }
+
+ return ((int)(oa->keylen)) - ob->keylen;
+}
+
+static int
+ucl_hash_cmp_case_sens (const void *a, const void *b)
+{
+ const ucl_object_t *oa = *(const ucl_object_t **)a,
+ *ob = *(const ucl_object_t **)b;
+
+ if (oa->keylen == ob->keylen) {
+ return memcmp (oa->key, ob->key, oa->keylen);
+ }
+
+ return ((int)(oa->keylen)) - ob->keylen;
+}
+
+void
+ucl_hash_sort (ucl_hash_t *hashlin, enum ucl_object_keys_sort_flags fl)
+{
+
+ if (fl & UCL_SORT_KEYS_ICASE) {
+ qsort (hashlin->ar.a, hashlin->ar.n, sizeof (ucl_object_t *),
+ ucl_hash_cmp_icase);
+ }
+ else {
+ qsort (hashlin->ar.a, hashlin->ar.n, sizeof (ucl_object_t *),
+ ucl_hash_cmp_case_sens);
+ }
+
+ if (fl & UCL_SORT_KEYS_RECURSIVE) {
+ for (size_t i = 0; i < hashlin->ar.n; i ++) {
+ if (ucl_object_type (hashlin->ar.a[i]) == UCL_OBJECT) {
+ ucl_hash_sort (hashlin->ar.a[i]->value.ov, fl);
+ }
+ }
+ }
} \ No newline at end of file
diff --git a/contrib/libucl/ucl_hash.h b/contrib/libucl/ucl_hash.h
index 805c8efb2..c2d5517bb 100644
--- a/contrib/libucl/ucl_hash.h
+++ b/contrib/libucl/ucl_hash.h
@@ -104,4 +104,11 @@ bool ucl_hash_iter_has_next (ucl_hash_t *hashlin, ucl_hash_iter_t iter);
*/
bool ucl_hash_reserve (ucl_hash_t *hashlin, size_t sz);
+/**
+ * Sorts keys in a hash
+ * @param hashlin
+ * @param fl
+ */
+void ucl_hash_sort (ucl_hash_t *hashlin, enum ucl_object_keys_sort_flags fl);
+
#endif
diff --git a/contrib/libucl/ucl_util.c b/contrib/libucl/ucl_util.c
index 0996caa77..5ef83e31b 100644
--- a/contrib/libucl/ucl_util.c
+++ b/contrib/libucl/ucl_util.c
@@ -3746,6 +3746,14 @@ ucl_object_array_sort (ucl_object_t *ar,
(int (*)(const void *, const void *))cmp);
}
+void ucl_object_sort_keys (ucl_object_t *obj,
+ enum ucl_object_keys_sort_flags how)
+{
+ if (obj != NULL && obj->type == UCL_OBJECT) {
+ ucl_hash_sort (obj->value.ov, how);
+ }
+}
+
#define PRIOBITS 4
unsigned int