@@ -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); | |||
} |
@@ -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 |
@@ -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); | |||
} | |||
} | |||
} | |||
} |
@@ -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 |
@@ -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 |