From: Alexandru Ardelean Date: Wed, 16 Nov 2016 09:55:41 +0000 (+0200) Subject: json_pointer: add json_pointer_getf/setf() function variants X-Git-Tag: json-c-0.13-20171207~112^2~3 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=742e059da1f5bd3c458f38bfbeb6e46ea1145f7b;p=thirdparty%2Fjson-c.git json_pointer: add json_pointer_getf/setf() function variants These include support for printf() style args for path. Adds support for calling with 'json_pointer_getf(obj, &res, "/foo/%d/%s", 0, bar)' style args. Makes it easier for doing more dynamic stuff/magic, without needing to use vasprintf() externally. Signed-off-by: Alexandru Ardelean --- diff --git a/json_pointer.c b/json_pointer.c index a445e3bf..582ca28d 100644 --- a/json_pointer.c +++ b/json_pointer.c @@ -8,6 +8,7 @@ #include "config.h" +#include #include #include #include @@ -192,6 +193,37 @@ int json_pointer_get(struct json_object *obj, const char *path, struct json_obje return rc; } +int json_pointer_getf(struct json_object *obj, struct json_object **res, const char *path_fmt, ...) +{ + char *path_copy = NULL; + int rc = 0; + va_list args; + + if (!obj || !path_fmt) { + errno = EINVAL; + return -1; + } + + va_start(args, path_fmt); + rc = vasprintf(&path_copy, path_fmt, args); + va_end(args); + + if (rc < 0) + return rc; + + if (path_copy[0] == '\0') { + if (res) + *res = obj; + goto out; + } + + rc = json_pointer_get_recursive(obj, path_copy, res); +out: + free(path_copy); + + return rc; +} + int json_pointer_set(struct json_object **obj, const char *path, struct json_object *value) { const char *endp; @@ -237,3 +269,56 @@ int json_pointer_set(struct json_object **obj, const char *path, struct json_obj return json_pointer_set_single_path(set, endp, value); } +int json_pointer_setf(struct json_object **obj, struct json_object *value, const char *path_fmt, ...) +{ + char *endp; + char *path_copy = NULL; + struct json_object *set = NULL; + va_list args; + int rc = 0; + + if (!obj || !path_fmt) { + errno = EINVAL; + return -1; + } + + /* pass a working copy to the recursive call */ + va_start(args, path_fmt); + rc = vasprintf(&path_copy, path_fmt, args); + va_end(args); + + if (rc < 0) + return rc; + + if (path_copy[0] == '\0') { + json_object_put(*obj); + *obj = value; + goto out; + } + + if (path_copy[0] != '/') { + errno = EINVAL; + rc = -1; + goto out; + } + + /* If there's only 1 level to set, stop here */ + if ((endp = strrchr(path_copy, '/')) == path_copy) { + set = *obj; + goto set_single_path; + } + + *endp = '\0'; + rc = json_pointer_get_recursive(*obj, path_copy, &set); + + if (rc) + goto out; + +set_single_path: + endp++; + rc = json_pointer_set_single_path(set, endp, value); +out: + free(path_copy); + return rc; +} + diff --git a/json_pointer.h b/json_pointer.h index d661b7b6..49e9c298 100644 --- a/json_pointer.h +++ b/json_pointer.h @@ -27,6 +27,11 @@ extern "C" { * Internally, this is equivalent to doing a series of 'json_object_object_get()' * and 'json_object_array_get_idx()' along the given 'path'. * + * Note that the 'path' string supports 'printf()' type arguments, so, whatever + * is added after the 'res' param will be treated as an argument for 'path' + * Example: json_pointer_get(obj, "/foo/%d/%s", &res, 0, bar) + * This means, that you need to escape '%' with '%%' (just like in printf()) + * * @param obj the json_object instance/tree from where to retrieve sub-objects * @param path a (RFC6901) string notation for the sub-object to retrieve * @param res a pointer where to store a reference to the json_object @@ -36,6 +41,24 @@ extern "C" { */ int json_pointer_get(struct json_object *obj, const char *path, struct json_object **res); +/** + * This is a variant of 'json_pointer_get()' that supports printf() style arguments. + * + * Example: json_pointer_getf(obj, res, "/foo/%d/%s", 0, bak) + * This also means that you need to escape '%' with '%%' (just like in printf()) + * + * Please take into consideration all recommended 'printf()' format security + * aspects when using this function. + * + * @param obj the json_object instance/tree to which to add a sub-object + * @param res a pointer where to store a reference to the json_object + * associated with the given path + * @param path_fmt a printf() style format for the path + * + * @return negative if an error (or not found), or 0 if succeeded + */ +int json_pointer_getf(struct json_object *obj, struct json_object **res, const char *path_fmt, ...); + /** * Sets JSON object 'value' in the 'obj' tree at the location specified * by the 'path'. 'path' is JSON pointer notation as defined in RFC 6901 @@ -54,6 +77,11 @@ int json_pointer_get(struct json_object *obj, const char *path, struct json_obje * That also implies that 'json_pointer_set()' does not do any refcount incrementing. * (Just that single decrement that was mentioned above). * + * Note that the 'path' string supports 'printf()' type arguments, so, whatever + * is added after the 'value' param will be treated as an argument for 'path' + * Example: json_pointer_set(obj, "/foo/%d/%s", value, 0, bak) + * This means, that you need to escape '%' with '%%' (just like in printf()) + * * @param obj the json_object instance/tree to which to add a sub-object * @param path a (RFC6901) string notation for the sub-object to set in the tree * @param value object to set at path @@ -62,6 +90,24 @@ int json_pointer_get(struct json_object *obj, const char *path, struct json_obje */ int json_pointer_set(struct json_object **obj, const char *path, struct json_object *value); +/** + * This is a variant of 'json_pointer_set()' that supports printf() style arguments. + * + * Example: json_pointer_setf(obj, value, "/foo/%d/%s", 0, bak) + * This also means that you need to escape '%' with '%%' (just like in printf()) + * + * Please take into consideration all recommended 'printf()' format security + * aspects when using this function. + * + * @param obj the json_object instance/tree to which to add a sub-object + * @param value object to set at path + * @param path_fmt a printf() style format for the path + * + * @return negative if an error (or not found), or 0 if succeeded + */ +int json_pointer_setf(struct json_object **obj, struct json_object *value, const char *path_fmt, ...); + + #ifdef __cplusplus } #endif