]> granicus.if.org Git - json-c/commitdiff
json_pointer: add json_pointer_getf/setf() function variants
authorAlexandru Ardelean <ardeleanalex@gmail.com>
Wed, 16 Nov 2016 09:55:41 +0000 (11:55 +0200)
committerAlexandru Ardelean <ardeleanalex@gmail.com>
Tue, 22 Nov 2016 14:33:49 +0000 (16:33 +0200)
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 <ardeleanalex@gmail.com>
json_pointer.c
json_pointer.h

index a445e3bf77c545520d33bdbba0331d4672ec2490..582ca28dd9cd3163192b575bb2849b6ba12c516a 100644 (file)
@@ -8,6 +8,7 @@
 
 #include "config.h"
 
+#include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <errno.h>
@@ -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;
+}
+
index d661b7b6b622be431c3eef5f4bed25bb2faf1b93..49e9c2985e86825d25f9b90992a4354f7bb26491 100644 (file)
@@ -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