commit 9b74e57: [Feature] Libucl: Allow to sort keys in ucl objects

Vsevolod Stakhov vsevolod at highsecure.ru
Mon Jul 8 13:28:05 UTC 2019


Author: Vsevolod Stakhov
Date: 2019-07-08 13:01:08 +0100
URL: https://github.com/rspamd/rspamd/commit/9b74e57ad3fb694741fdcf5e27a046fbe99a40f7

[Feature] Libucl: Allow to sort keys in ucl objects

---
 contrib/libucl/lua_ucl.c  | 13 +++++++++++++
 contrib/libucl/ucl.h      | 13 +++++++++++++
 contrib/libucl/ucl_hash.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++
 contrib/libucl/ucl_hash.h |  7 +++++++
 contrib/libucl/ucl_util.c |  8 ++++++++
 5 files changed, 90 insertions(+)

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


More information about the Commits mailing list