curl_json plugin: support arrays
authorJim Radford <radford@galvanix.com>
Sat, 10 Aug 2013 17:25:02 +0000 (10:25 -0700)
committerJim Radford <radford@galvanix.com>
Sat, 10 Aug 2013 17:33:28 +0000 (10:33 -0700)
Allow access to data in JSON arrays.  For example

    { workers: [ { requests: 10 }, { requests: 10 } ] }

can all be accessed with

    workers/*/requests

or just one by using the index.

    workers/1/requests

src/curl_json.c

index deee460..5bc3e41 100644 (file)
@@ -82,6 +82,8 @@ struct cj_s /* {{{ */
       c_avl_tree_t *tree;
       cj_key_t *key;
     };
+    _Bool in_array;
+    int index;
     char name[DATA_MAX_NAME_LEN];
   } state[YAJL_MAX_DEPTH];
 };
@@ -167,10 +169,41 @@ static int cj_get_type (cj_key_t *key)
   return ds->ds[0].type;
 }
 
+static int cj_cb_map_key (void *ctx, const unsigned char *val,
+    yajl_len_t len);
+
+static void cj_cb_inc_array_index (void * ctx, _Bool ignore)
+{
+  cj_t *db = (cj_t *)ctx;
+
+  if (db->state[db->depth].in_array) {
+    if (ignore)
+      db->state[db->depth].index++;
+    else {
+      char name[DATA_MAX_NAME_LEN];
+      cj_cb_map_key (ctx, (unsigned char *)name,
+                     ssnprintf (name, sizeof (name),
+                                "%d", db->state[db->depth].index++));
+    }
+  }
+}
+
 /* yajl callbacks */
 #define CJ_CB_ABORT    0
 #define CJ_CB_CONTINUE 1
 
+static int cj_cb_boolean (void * ctx, int boolVal)
+{
+  cj_cb_inc_array_index (ctx, 1);
+  return (CJ_CB_CONTINUE);
+}
+
+static int cj_cb_null (void * ctx)
+{
+  cj_cb_inc_array_index (ctx, 1);
+  return (CJ_CB_CONTINUE);
+}
+
 /* "number" may not be null terminated, so copy it into a buffer before
  * parsing. */
 static int cj_cb_number (void *ctx,
@@ -184,8 +217,11 @@ static int cj_cb_number (void *ctx,
   int type;
   int status;
 
-  if ((key == NULL) || !CJ_IS_KEY (key))
+  if ((key == NULL) || !CJ_IS_KEY (key)) {
+    cj_cb_inc_array_index (ctx, 1);
     return (CJ_CB_CONTINUE);
+  } else
+    cj_cb_inc_array_index (ctx, 0);
 
   memcpy (buffer, number, number_len);
   buffer[sizeof (buffer) - 1] = 0;
@@ -236,6 +272,9 @@ static int cj_cb_string (void *ctx, const unsigned char *val,
   cj_t *db = (cj_t *)ctx;
   char str[len + 1];
 
+  cj_cb_inc_array_index (ctx, 1);
+  return (CJ_CB_CONTINUE);
+
   /* Create a null-terminated version of the string. */
   memcpy (str, val, len);
   str[len] = 0;
@@ -276,6 +315,7 @@ static int cj_cb_end (void *ctx)
 
 static int cj_cb_start_map (void *ctx)
 {
+  cj_cb_inc_array_index (ctx, 0);
   return cj_cb_start (ctx);
 }
 
@@ -286,17 +326,25 @@ static int cj_cb_end_map (void *ctx)
 
 static int cj_cb_start_array (void * ctx)
 {
+  cj_t *db = (cj_t *)ctx;
+  cj_cb_inc_array_index (ctx, 0);
+  if (db->depth+1 < YAJL_MAX_DEPTH) {
+    db->state[db->depth+1].in_array = 1;
+    db->state[db->depth+1].index = 0;
+  }
   return cj_cb_start (ctx);
 }
 
 static int cj_cb_end_array (void * ctx)
 {
+  cj_t *db = (cj_t *)ctx;
+  db->state[db->depth].in_array = 0;
   return cj_cb_end (ctx);
 }
 
 static yajl_callbacks ycallbacks = {
-  NULL, /* null */
-  NULL, /* boolean */
+  cj_cb_null, /* null */
+  cj_cb_boolean, /* boolean */
   NULL, /* integer */
   NULL, /* double */
   cj_cb_number,