]> source.dussan.org Git - rspamd.git/commitdiff
Sync with libucl
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Sun, 27 Dec 2015 15:12:28 +0000 (15:12 +0000)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Sun, 27 Dec 2015 15:12:28 +0000 (15:12 +0000)
contrib/libucl/ucl.h
contrib/libucl/ucl_schema.c
contrib/libucl/ucl_util.c

index 82a1fd1880f390ccb3c4a26b9643d355ba8bb617..cfe62c081ecb970f11817d9804b742a00127302e 100644 (file)
@@ -305,6 +305,21 @@ UCL_EXTERN ucl_object_t * ucl_object_copy (const ucl_object_t *other)
  */
 UCL_EXTERN ucl_type_t ucl_object_type (const ucl_object_t *obj);
 
+/**
+ * Converts ucl object type to its string representation
+ * @param type type of object
+ * @return constant string describing type
+ */
+UCL_EXTERN const char * ucl_object_type_to_string (ucl_type_t type);
+
+/**
+ * Converts string that represents ucl type to real ucl type enum
+ * @param input C string with name of type
+ * @param res resulting target
+ * @return true if `input` is a name of type stored in `res`
+ */
+UCL_EXTERN bool ucl_object_string_to_type (const char *input, ucl_type_t *res);
+
 /**
  * Convert any string to an ucl object making the specified transformations
  * @param str fixed size or NULL terminated string
@@ -1280,6 +1295,9 @@ enum ucl_schema_error_code {
        UCL_SCHEMA_MISSING_PROPERTY,/**< one or more missing properties */
        UCL_SCHEMA_CONSTRAINT,      /**< constraint found */
        UCL_SCHEMA_MISSING_DEPENDENCY, /**< missing dependency */
+       UCL_SCHEMA_EXTERNAL_REF_MISSING, /**< cannot fetch external ref */
+       UCL_SCHEMA_EXTERNAL_REF_INVALID, /**< invalid external ref */
+       UCL_SCHEMA_INTERNAL_ERROR, /**< something bad happened */
        UCL_SCHEMA_UNKNOWN          /**< generic error */
 };
 
@@ -1303,6 +1321,37 @@ struct ucl_schema_error {
 UCL_EXTERN bool ucl_object_validate (const ucl_object_t *schema,
                const ucl_object_t *obj, struct ucl_schema_error *err);
 
+/**
+ * Validate object `obj` using schema object `schema` and root schema at `root`.
+ * @param schema schema object
+ * @param obj object to validate
+ * @param root root schema object
+ * @param err error pointer, if this parameter is not NULL and error has been
+ * occured, then `err` is filled with the exact error definition.
+ * @return true if `obj` is valid using `schema`
+ */
+UCL_EXTERN bool ucl_object_validate_root (const ucl_object_t *schema,
+               const ucl_object_t *obj,
+               const ucl_object_t *root,
+               struct ucl_schema_error *err);
+
+/**
+ * Validate object `obj` using schema object `schema` and root schema at `root`
+ * using some external references provided.
+ * @param schema schema object
+ * @param obj object to validate
+ * @param root root schema object
+ * @param ext_refs external references (might be modified during validation)
+ * @param err error pointer, if this parameter is not NULL and error has been
+ * occured, then `err` is filled with the exact error definition.
+ * @return true if `obj` is valid using `schema`
+ */
+UCL_EXTERN bool ucl_object_validate_root_ext (const ucl_object_t *schema,
+               const ucl_object_t *obj,
+               const ucl_object_t *root,
+               ucl_object_t *ext_refs,
+               struct ucl_schema_error *err);
+
 /** @} */
 
 #ifdef  __cplusplus
index 834b62accb5f5ef3ea3254155bde2718d0a12f28..9b96da5efc6f809f6c5b4ed1bfd42f78f5e878d4 100644 (file)
 static bool ucl_schema_validate (const ucl_object_t *schema,
                const ucl_object_t *obj, bool try_array,
                struct ucl_schema_error *err,
-               const ucl_object_t *root);
-
-static bool
-ucl_string_to_type (const char *input, ucl_type_t *res)
-{
-       if (strcasecmp (input, "object") == 0) {
-               *res = UCL_OBJECT;
-       }
-       else if (strcasecmp (input, "array") == 0) {
-               *res = UCL_ARRAY;
-       }
-       else if (strcasecmp (input, "integer") == 0) {
-               *res = UCL_INT;
-       }
-       else if (strcasecmp (input, "number") == 0) {
-               *res = UCL_FLOAT;
-       }
-       else if (strcasecmp (input, "string") == 0) {
-               *res = UCL_STRING;
-       }
-       else if (strcasecmp (input, "boolean") == 0) {
-               *res = UCL_BOOLEAN;
-       }
-       else if (strcasecmp (input, "null") == 0) {
-               *res = UCL_NULL;
-       }
-       else {
-               return false;
-       }
-
-       return true;
-}
-
-static const char *
-ucl_object_type_to_string (ucl_type_t type)
-{
-       const char *res = "unknown";
-
-       switch (type) {
-       case UCL_OBJECT:
-               res = "object";
-               break;
-       case UCL_ARRAY:
-               res = "array";
-               break;
-       case UCL_INT:
-               res = "integer";
-               break;
-       case UCL_FLOAT:
-       case UCL_TIME:
-               res = "number";
-               break;
-       case UCL_STRING:
-               res = "string";
-               break;
-       case UCL_BOOLEAN:
-               res = "boolean";
-               break;
-       case UCL_NULL:
-       case UCL_USERDATA:
-               res = "null";
-               break;
-       }
-
-       return res;
-}
+               const ucl_object_t *root,
+               ucl_object_t *ext_ref);
 
 /*
  * Create validation error
@@ -160,7 +96,8 @@ ucl_schema_test_pattern (const ucl_object_t *obj, const char *pattern)
 static bool
 ucl_schema_validate_dependencies (const ucl_object_t *deps,
                const ucl_object_t *obj, struct ucl_schema_error *err,
-               const ucl_object_t *root)
+               const ucl_object_t *root,
+               ucl_object_t *ext_ref)
 {
        const ucl_object_t *elt, *cur, *cur_dep;
        ucl_object_iter_t iter = NULL, piter;
@@ -183,7 +120,7 @@ ucl_schema_validate_dependencies (const ucl_object_t *deps,
                                }
                        }
                        else if (cur->type == UCL_OBJECT) {
-                               ret = ucl_schema_validate (cur, obj, true, err, root);
+                               ret = ucl_schema_validate (cur, obj, true, err, root, ext_ref);
                        }
                }
        }
@@ -197,7 +134,8 @@ ucl_schema_validate_dependencies (const ucl_object_t *deps,
 static bool
 ucl_schema_validate_object (const ucl_object_t *schema,
                const ucl_object_t *obj, struct ucl_schema_error *err,
-               const ucl_object_t *root)
+               const ucl_object_t *root,
+               ucl_object_t *ext_ref)
 {
        const ucl_object_t *elt, *prop, *found, *additional_schema = NULL,
                        *required = NULL, *pat, *pelt;
@@ -212,7 +150,8 @@ ucl_schema_validate_object (const ucl_object_t *schema,
                        while (ret && (prop = ucl_iterate_object (elt, &piter, true)) != NULL) {
                                found = ucl_object_find_key (obj, ucl_object_key (prop));
                                if (found) {
-                                       ret = ucl_schema_validate (prop, found, true, err, root);
+                                       ret = ucl_schema_validate (prop, found, true, err, root,
+                                                       ext_ref);
                                }
                        }
                }
@@ -270,13 +209,15 @@ ucl_schema_validate_object (const ucl_object_t *schema,
                        while (ret && (prop = ucl_iterate_object (elt, &piter, true)) != NULL) {
                                found = ucl_schema_test_pattern (obj, ucl_object_key (prop));
                                if (found) {
-                                       ret = ucl_schema_validate (prop, found, true, err, root);
+                                       ret = ucl_schema_validate (prop, found, true, err, root,
+                                                       ext_ref);
                                }
                        }
                }
                else if (elt->type == UCL_OBJECT &&
                                strcmp (ucl_object_key (elt), "dependencies") == 0) {
-                       ret = ucl_schema_validate_dependencies (elt, obj, err, root);
+                       ret = ucl_schema_validate_dependencies (elt, obj, err, root,
+                                       ext_ref);
                }
        }
 
@@ -308,7 +249,8 @@ ucl_schema_validate_object (const ucl_object_t *schema,
                                                break;
                                        }
                                        else if (additional_schema != NULL) {
-                                               if (!ucl_schema_validate (additional_schema, elt, true, err, root)) {
+                                               if (!ucl_schema_validate (additional_schema, elt,
+                                                               true, err, root, ext_ref)) {
                                                        ret = false;
                                                        break;
                                                }
@@ -518,7 +460,8 @@ ucl_schema_array_is_unique (const ucl_object_t *obj, struct ucl_schema_error *er
 static bool
 ucl_schema_validate_array (const ucl_object_t *schema,
                const ucl_object_t *obj, struct ucl_schema_error *err,
-               const ucl_object_t *root)
+               const ucl_object_t *root,
+               ucl_object_t *ext_ref)
 {
        const ucl_object_t *elt, *it, *found, *additional_schema = NULL,
                        *first_unvalidated = NULL;
@@ -533,7 +476,8 @@ ucl_schema_validate_array (const ucl_object_t *schema,
                                found = ucl_array_head (obj);
                                while (ret && (it = ucl_iterate_object (elt, &piter, true)) != NULL) {
                                        if (found) {
-                                               ret = ucl_schema_validate (it, found, false, err, root);
+                                               ret = ucl_schema_validate (it, found, false, err,
+                                                               root, ext_ref);
                                                found = ucl_array_find_index (obj, ++idx);
                                        }
                                }
@@ -545,7 +489,8 @@ ucl_schema_validate_array (const ucl_object_t *schema,
                        else if (elt->type == UCL_OBJECT) {
                                /* Validate all items using the specified schema */
                                while (ret && (it = ucl_iterate_object (obj, &piter, true)) != NULL) {
-                                       ret = ucl_schema_validate (elt, it, false, err, root);
+                                       ret = ucl_schema_validate (elt, it, false, err, root,
+                                                       ext_ref);
                                }
                        }
                        else {
@@ -612,7 +557,7 @@ ucl_schema_validate_array (const ucl_object_t *schema,
                                        elt = ucl_array_find_index (obj, idx);
                                        while (elt) {
                                                if (!ucl_schema_validate (additional_schema, elt, false,
-                                                               err, root)) {
+                                                               err, root, ext_ref)) {
                                                        ret = false;
                                                        break;
                                                }
@@ -657,7 +602,7 @@ ucl_schema_type_is_allowed (const ucl_object_t *type, const ucl_object_t *obj,
        }
        else if (type->type == UCL_STRING) {
                type_str = ucl_object_tostring (type);
-               if (!ucl_string_to_type (type_str, &t)) {
+               if (!ucl_object_string_to_type (type_str, &t)) {
                        ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, type,
                                        "Type attribute is invalid in schema");
                        return false;
@@ -771,31 +716,109 @@ ucl_schema_resolve_ref_component (const ucl_object_t *cur,
  */
 static const ucl_object_t *
 ucl_schema_resolve_ref (const ucl_object_t *root, const char *ref,
-               struct ucl_schema_error *err)
+               struct ucl_schema_error *err, ucl_object_t *ext_ref,
+               ucl_object_t const ** nroot)
 {
-       const char *p, *c;
-       const ucl_object_t *res = NULL;
-
+       UT_string *url_err = NULL;
+       struct ucl_parser *parser;
+       const ucl_object_t *res = NULL, *ext_obj = NULL;
+       ucl_object_t *url_obj;
+       const char *p, *c, *hash_ptr = NULL;
+       char *url_copy = NULL;
+       unsigned char *url_buf;
+       size_t url_buflen;
 
        if (ref[0] != '#') {
-               ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, root,
-                               "reference %s is invalid, not started with #", ref);
-               return NULL;
+               hash_ptr = strrchr (ref, '#');
+
+               if (hash_ptr) {
+                       url_copy = malloc (hash_ptr - ref + 1);
+
+                       if (url_copy == NULL) {
+                               ucl_schema_create_error (err, UCL_SCHEMA_INTERNAL_ERROR, root,
+                                               "cannot allocate memory");
+                               return NULL;
+                       }
+
+                       ucl_strlcpy (url_copy, ref, hash_ptr - ref + 1);
+                       p = url_copy;
+               }
+               else {
+                       /* Full URL */
+                       p = ref;
+               }
+
+               ext_obj = ucl_object_find_key (ext_ref, p);
+
+               if (ext_obj == NULL) {
+                       if (ucl_strnstr (p, "://", strlen (p)) != NULL) {
+                               if (!ucl_fetch_url (p, &url_buf, &url_buflen, &url_err, true)) {
+                                       free (url_copy);
+                                       ucl_schema_create_error (err,
+                                                       UCL_SCHEMA_INVALID_SCHEMA,
+                                                       root,
+                                                       "cannot fetch reference %s: %s",
+                                                       p,
+                                                       url_err != NULL ? utstring_body (url_err)
+                                                                                       : "unknown");
+                                       return NULL;
+                               }
+                       }
+                       else {
+                               if (!ucl_fetch_file (p, &url_buf, &url_buflen, &url_err,
+                                               true)) {
+                                       free (url_copy);
+                                       ucl_schema_create_error (err,
+                                                       UCL_SCHEMA_INVALID_SCHEMA,
+                                                       root,
+                                                       "cannot fetch reference %s: %s",
+                                                       p,
+                                                       url_err != NULL ? utstring_body (url_err)
+                                                                                       : "unknown");
+                                       return NULL;
+                               }
+                       }
+
+                       parser = ucl_parser_new (0);
+
+                       if (!ucl_parser_add_chunk (parser, url_buf, url_buflen)) {
+                               free (url_copy);
+                               ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, root,
+                                               "cannot fetch reference %s: %s", p,
+                                               ucl_parser_get_error (parser));
+                               ucl_parser_free (parser);
+                               return NULL;
+                       }
+
+                       url_obj = ucl_parser_get_object (parser);
+                       ext_obj = url_obj;
+                       ucl_object_insert_key (ext_ref, url_obj, p, 0, true);
+                       free (url_buf);
+                       free (url_copy);
+               }
+
+               if (hash_ptr) {
+                       p = hash_ptr + 1;
+               }
+               else {
+                       p = "";
+               }
        }
-       if (ref[1] == '/') {
-               p = &ref[2];
+       else {
+               p = ref + 1;
        }
-       else if (ref[1] == '\0') {
-               return root;
+
+       res = ext_obj != NULL ? ext_obj : root;
+       *nroot = res;
+
+       if (*p == '/') {
+               p++;
        }
-       else {
-               ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, root,
-                               "reference %s is invalid, not started with #/", ref);
-               return NULL;
+       else if (*p == '\0') {
+               return res;
        }
 
        c = p;
-       res = root;
 
        while (*p != '\0') {
                if (*p == '/') {
@@ -878,15 +901,17 @@ static bool
 ucl_schema_validate (const ucl_object_t *schema,
                const ucl_object_t *obj, bool try_array,
                struct ucl_schema_error *err,
-               const ucl_object_t *root)
+               const ucl_object_t *root,
+               ucl_object_t *external_refs)
 {
-       const ucl_object_t *elt, *cur;
+       const ucl_object_t *elt, *cur, *ref_root;
        ucl_object_iter_t iter = NULL;
        bool ret;
 
        if (schema->type != UCL_OBJECT) {
                ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, schema,
-                               "schema is %s instead of object", ucl_object_type_to_string (schema->type));
+                               "schema is %s instead of object",
+                               ucl_object_type_to_string (schema->type));
                return false;
        }
 
@@ -898,7 +923,7 @@ ucl_schema_validate (const ucl_object_t *schema,
                        return false;
                }
                LL_FOREACH (obj, cur) {
-                       if (!ucl_schema_validate (schema, cur, false, err, root)) {
+                       if (!ucl_schema_validate (schema, cur, false, err, root, external_refs)) {
                                return false;
                        }
                }
@@ -916,7 +941,7 @@ ucl_schema_validate (const ucl_object_t *schema,
        if (elt != NULL && elt->type == UCL_ARRAY) {
                iter = NULL;
                while ((cur = ucl_iterate_object (elt, &iter, true)) != NULL) {
-                       ret = ucl_schema_validate (cur, obj, true, err, root);
+                       ret = ucl_schema_validate (cur, obj, true, err, root, external_refs);
                        if (!ret) {
                                return false;
                        }
@@ -927,7 +952,7 @@ ucl_schema_validate (const ucl_object_t *schema,
        if (elt != NULL && elt->type == UCL_ARRAY) {
                iter = NULL;
                while ((cur = ucl_iterate_object (elt, &iter, true)) != NULL) {
-                       ret = ucl_schema_validate (cur, obj, true, err, root);
+                       ret = ucl_schema_validate (cur, obj, true, err, root, external_refs);
                        if (ret) {
                                break;
                        }
@@ -947,9 +972,9 @@ ucl_schema_validate (const ucl_object_t *schema,
                ret = false;
                while ((cur = ucl_iterate_object (elt, &iter, true)) != NULL) {
                        if (!ret) {
-                               ret = ucl_schema_validate (cur, obj, true, err, root);
+                               ret = ucl_schema_validate (cur, obj, true, err, root, external_refs);
                        }
-                       else if (ucl_schema_validate (cur, obj, true, err, root)) {
+                       else if (ucl_schema_validate (cur, obj, true, err, root, external_refs)) {
                                ret = false;
                                break;
                        }
@@ -961,7 +986,7 @@ ucl_schema_validate (const ucl_object_t *schema,
 
        elt = ucl_object_find_key (schema, "not");
        if (elt != NULL && elt->type == UCL_OBJECT) {
-               if (ucl_schema_validate (elt, obj, true, err, root)) {
+               if (ucl_schema_validate (elt, obj, true, err, root, external_refs)) {
                        return false;
                }
                else {
@@ -972,11 +997,15 @@ ucl_schema_validate (const ucl_object_t *schema,
 
        elt = ucl_object_find_key (schema, "$ref");
        if (elt != NULL) {
-               cur = ucl_schema_resolve_ref (root, ucl_object_tostring (elt), err);
+               ref_root = root;
+               cur = ucl_schema_resolve_ref (root, ucl_object_tostring (elt),
+                               err, external_refs, &ref_root);
+
                if (cur == NULL) {
                        return false;
                }
-               if (!ucl_schema_validate (cur, obj, try_array, err, root)) {
+               if (!ucl_schema_validate (cur, obj, try_array, err, ref_root,
+                               external_refs)) {
                        return false;
                }
        }
@@ -988,10 +1017,10 @@ ucl_schema_validate (const ucl_object_t *schema,
 
        switch (obj->type) {
        case UCL_OBJECT:
-               return ucl_schema_validate_object (schema, obj, err, root);
+               return ucl_schema_validate_object (schema, obj, err, root, external_refs);
                break;
        case UCL_ARRAY:
-               return ucl_schema_validate_array (schema, obj, err, root);
+               return ucl_schema_validate_array (schema, obj, err, root, external_refs);
                break;
        case UCL_INT:
        case UCL_FLOAT:
@@ -1011,5 +1040,37 @@ bool
 ucl_object_validate (const ucl_object_t *schema,
                const ucl_object_t *obj, struct ucl_schema_error *err)
 {
-       return ucl_schema_validate (schema, obj, true, err, schema);
+       return ucl_object_validate_root_ext (schema, obj, schema, NULL, err);
+}
+
+bool
+ucl_object_validate_root (const ucl_object_t *schema,
+               const ucl_object_t *obj,
+               const ucl_object_t *root,
+               struct ucl_schema_error *err)
+{
+       return ucl_object_validate_root_ext (schema, obj, root, NULL, err);
+}
+
+bool
+ucl_object_validate_root_ext (const ucl_object_t *schema,
+               const ucl_object_t *obj,
+               const ucl_object_t *root,
+               ucl_object_t *ext_refs,
+               struct ucl_schema_error *err)
+{
+       bool ret, need_unref = false;
+
+       if (ext_refs == NULL) {
+               ext_refs = ucl_object_typed_new (UCL_OBJECT);
+               need_unref = true;
+       }
+
+       ret = ucl_schema_validate (schema, obj, true, err, root, ext_refs);
+
+       if (need_unref) {
+               ucl_object_unref (ext_refs);
+       }
+
+       return ret;
 }
index 730a5c4afd57d18c6ad26a9148d9278cf4cc2099..2bd0c2a3fe1197fc245313b5798cc770a9e7dcea 100644 (file)
@@ -437,7 +437,7 @@ ucl_copy_value_trash (const ucl_object_t *obj)
                }
                deconst->flags |= UCL_OBJECT_ALLOCATED_VALUE;
        }
-       
+
        return obj->trash_stack[UCL_TRASH_VALUE];
 }
 
@@ -628,7 +628,7 @@ ucl_curl_write_callback (void* contents, size_t size, size_t nmemb, void* ud)
  * @param buflen target length
  * @return
  */
-static bool
+bool
 ucl_fetch_url (const unsigned char *url, unsigned char **buf, size_t *buflen,
                UT_string **err, bool must_exist)
 {
@@ -690,8 +690,8 @@ ucl_fetch_url (const unsigned char *url, unsigned char **buf, size_t *buflen,
                return false;
        }
        curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, ucl_curl_write_callback);
-       cbdata.buf = *buf;
-       cbdata.buflen = *buflen;
+       cbdata.buf = NULL;
+       cbdata.buflen = 0;
        curl_easy_setopt (curl, CURLOPT_WRITEDATA, &cbdata);
 
        if ((r = curl_easy_perform (curl)) != CURLE_OK) {
@@ -723,7 +723,7 @@ ucl_fetch_url (const unsigned char *url, unsigned char **buf, size_t *buflen,
  * @param buflen target length
  * @return
  */
-static bool
+bool
 ucl_fetch_file (const unsigned char *filename, unsigned char **buf, size_t *buflen,
                UT_string **err, bool must_exist)
 {
@@ -739,7 +739,7 @@ ucl_fetch_file (const unsigned char *filename, unsigned char **buf, size_t *bufl
        }
        if (st.st_size == 0) {
                /* Do not map empty files */
-               *buf = "";
+               *buf = NULL;
                *buflen = 0;
        }
        else {
@@ -848,7 +848,7 @@ ucl_include_url (const unsigned char *data, size_t len,
        snprintf (urlbuf, sizeof (urlbuf), "%.*s", (int)len, data);
 
        if (!ucl_fetch_url (urlbuf, &buf, &buflen, &parser->err, params->must_exist)) {
-               return (!params->must_exist || false);
+               return !params->must_exist;
        }
 
        if (params->check_signature) {
@@ -1232,7 +1232,7 @@ ucl_include_file (const unsigned char *data, size_t len,
           treat allow_glob/need_glob as a NOOP and just return */
        return ucl_include_file_single (data, len, parser, params);
 #endif
-       
+
        return true;
 }
 
@@ -1252,7 +1252,7 @@ ucl_include_common (const unsigned char *data, size_t len,
                bool default_try,
                bool default_sign)
 {
-       bool allow_url, search;
+       bool allow_url = false, search = false;
        const char *duplicate;
        const ucl_object_t *param;
        ucl_object_iter_t it = NULL, ip = NULL;
@@ -1271,8 +1271,6 @@ ucl_include_common (const unsigned char *data, size_t len,
        params.strat = UCL_DUPLICATE_APPEND;
        params.must_exist = !default_try;
 
-       search = false;
-
        /* Process arguments */
        if (args != NULL && args->type == UCL_OBJECT) {
                while ((param = ucl_iterate_object (args, &it, true)) != NULL) {
@@ -3255,3 +3253,73 @@ ucl_object_set_priority (ucl_object_t *obj,
                obj->flags = priority;
        }
 }
+
+bool
+ucl_object_string_to_type (const char *input, ucl_type_t *res)
+{
+       if (strcasecmp (input, "object") == 0) {
+               *res = UCL_OBJECT;
+       }
+       else if (strcasecmp (input, "array") == 0) {
+               *res = UCL_ARRAY;
+       }
+       else if (strcasecmp (input, "integer") == 0) {
+               *res = UCL_INT;
+       }
+       else if (strcasecmp (input, "number") == 0) {
+               *res = UCL_FLOAT;
+       }
+       else if (strcasecmp (input, "string") == 0) {
+               *res = UCL_STRING;
+       }
+       else if (strcasecmp (input, "boolean") == 0) {
+               *res = UCL_BOOLEAN;
+       }
+       else if (strcasecmp (input, "null") == 0) {
+               *res = UCL_NULL;
+       }
+       else if (strcasecmp (input, "userdata") == 0) {
+               *res = UCL_USERDATA;
+       }
+       else {
+               return false;
+       }
+
+       return true;
+}
+
+const char *
+ucl_object_type_to_string (ucl_type_t type)
+{
+       const char *res = "unknown";
+
+       switch (type) {
+       case UCL_OBJECT:
+               res = "object";
+               break;
+       case UCL_ARRAY:
+               res = "array";
+               break;
+       case UCL_INT:
+               res = "integer";
+               break;
+       case UCL_FLOAT:
+       case UCL_TIME:
+               res = "number";
+               break;
+       case UCL_STRING:
+               res = "string";
+               break;
+       case UCL_BOOLEAN:
+               res = "boolean";
+               break;
+       case UCL_USERDATA:
+               res = "userdata";
+               break;
+       case UCL_NULL:
+               res = "null";
+               break;
+       }
+
+       return res;
+}