Wireless Daemon for Linux
 help / color / mirror / Atom feed
* [PATCH 1/8] json: add support for primitive types
@ 2022-01-05 18:46 James Prestwood
  0 siblings, 0 replies; only message in thread
From: James Prestwood @ 2022-01-05 18:46 UTC (permalink / raw)
  To: iwd 

[-- Attachment #1: Type: text/plain, Size: 6138 bytes --]

This adds support for boolean, (unsigned) integers, and
null types. JSON_PRIMITIVE should be used as the type when
parsing and the value should be struct json_iter.

Once parsed the actual value can be obtained using one of
the primitive getters. If the type does not match they will
return false.

If using JSON_OPTIONAL with JSON_PRIMITIVE the resulting
iterator can be checked with json_iter_is_valid. If false
the key/value was not found or the type was not matching.
---
 src/json.c | 138 ++++++++++++++++++++++++++++++++++++++++++++++++++---
 src/json.h |  13 ++++-
 2 files changed, 143 insertions(+), 8 deletions(-)

diff --git a/src/json.c b/src/json.c
index 39570e7e..a83ba464 100644
--- a/src/json.c
+++ b/src/json.c
@@ -85,14 +85,26 @@ static int find_object_tokens(struct json_iter *iter, jsmntok_t *object)
 	return next - object - 1;
 }
 
-static void iter_recurse(struct json_iter *iter, jsmntok_t *object,
+static void iter_recurse(struct json_iter *iter, jsmntok_t *token,
 				struct json_iter *child)
 {
 	struct json_contents *c = iter->contents;
 
 	child->contents = c;
-	child->start = object - c->tokens;
-	child->count = find_object_tokens(iter, object);
+	child->start = token - c->tokens;
+
+	/*
+	* For objects iterating all tokens with the object as the parent
+	* parent should give the total number of tokens for this object.
+	*
+	* For strings/primitives the value is always going to one token which
+	* will not be iteratable. Because of this the count is set to zero to
+	* disallow any iteration on this child iterator.
+	*/
+	if (token->type == JSMN_OBJECT)
+		child->count = find_object_tokens(iter, token);
+	else
+		child->count = 0;
 }
 
 struct json_contents *json_contents_new(const char *json, size_t json_len)
@@ -153,7 +165,7 @@ static void assign_arg(void *data, void *user_data)
 	struct json_arg *arg = data;
 	struct json_contents *c = iter->contents;
 	char **sval;
-	struct json_iter *oval;
+	struct json_iter *iter_val;
 
 	switch (arg->type) {
 	case JSON_STRING:
@@ -163,12 +175,13 @@ static void assign_arg(void *data, void *user_data)
 
 		break;
 	case JSON_OBJECT:
-		oval = arg->value;
+	case JSON_PRIMITIVE:
+		iter_val = arg->value;
 
 		if (!arg->v)
-			oval->start = -1;
+			iter_val->start = -1;
 		else
-			iter_recurse(iter, arg->v, oval);
+			iter_recurse(iter, arg->v, iter_val);
 
 		break;
 	default:
@@ -209,6 +222,7 @@ bool json_iter_parse(struct json_iter *iter, enum json_type type, ...)
 			goto done;
 		case JSON_STRING:
 		case JSON_OBJECT:
+		case JSON_PRIMITIVE:
 			break;
 		default:
 			goto error;
@@ -268,3 +282,113 @@ error:
 	l_queue_destroy(args, l_free);
 	return false;
 }
+
+static bool iter_get_primitive_data(struct json_iter *iter, void **ptr,
+					size_t *len)
+{
+	struct json_contents *c = iter->contents;
+	jsmntok_t *t = c->tokens + iter->start;
+
+	if (t->type != JSMN_PRIMITIVE)
+		return false;
+
+	*ptr = TOK_PTR(c->json, t);
+	*len = TOK_LEN(t);
+
+	return true;
+}
+
+bool json_iter_get_int(struct json_iter *iter, int *i)
+{
+	void *ptr;
+	size_t len;
+	long int r;
+	int t;
+	char *endp;
+
+	if (json_iter_get_null(iter) || json_iter_get_boolean(iter, NULL))
+		return false;
+
+	if (!iter_get_primitive_data(iter, &ptr, &len))
+		return false;
+
+	errno = 0;
+
+	t = r = strtol(ptr, &endp, 0);
+	if (endp == ptr)
+		return false;
+
+	if (errno == ERANGE || r != t)
+		return false;
+
+	if (i)
+		*i = r;
+
+	return true;
+}
+
+bool json_iter_get_uint(struct json_iter *iter, unsigned int *i)
+{
+	void *ptr;
+	size_t len;
+	unsigned long int r;
+	unsigned int t;
+	char *endp;
+
+	if (json_iter_get_null(iter) || json_iter_get_boolean(iter, NULL))
+		return false;
+
+	if (!iter_get_primitive_data(iter, &ptr, &len))
+		return false;
+
+	errno = 0;
+
+	t = r = strtoul(ptr, &endp, 0);
+	if (endp == ptr)
+		return false;
+
+	if (errno == ERANGE || r != t)
+		return false;
+
+	if (i)
+		*i = r;
+
+	return true;
+}
+
+bool json_iter_get_boolean(struct json_iter *iter, bool *b)
+{
+	void *ptr;
+	size_t len;
+
+	if (!iter_get_primitive_data(iter, &ptr, &len))
+		return false;
+
+	if (len == 4 && !memcmp(ptr, "true", 4)) {
+		if (b)
+			*b = true;
+
+		return true;
+	} else if (len == 5 && !memcmp(ptr, "false", 5)) {
+		if (b)
+			*b = false;
+
+		return true;
+	}
+
+	return false;
+}
+
+bool json_iter_get_null(struct json_iter *iter)
+{
+	void *ptr;
+	size_t len;
+
+	if (!iter_get_primitive_data(iter, &ptr, &len))
+		return false;
+
+	if (len == 4 && !memcmp(ptr, "null", 4))
+		return true;
+
+	return false;
+}
diff --git a/src/json.h b/src/json.h
index 915b675b..9f00a9d5 100644
--- a/src/json.h
+++ b/src/json.h
@@ -73,11 +73,22 @@ void json_iter_init(struct json_iter *iter, struct json_contents *c);
  *
  * String values should be of type char ** and must be freed
  * Object values should be of type struct json_iter *
+ * Primitive types (numbers, booleans, null) should be of type
+ * 		struct json_iter *. This is to allow the caller to distinguish
+ * 		between the actual value type after parsing using a getter for
+ * 		the expected type (get_uint/get_int/get_boolean etc.). In
+ * 		addition this lets the caller use JSON_OPTIONAL and check post
+ * 		json_iter_parse if the iterator is valid (json_iter_is_valid).
  *
  * No other types are supported at this time, and json_iter_parse will fail if
  * other types are encountered.
  *
  * JSON_OPTIONAL string values will point to NULL if not found
- * JSON_OPTIONAL objects can be checked with json_object_not_found.
+ * JSON_OPTIONAL objects/primitives can be checked with json_object_is_valid.
  */
 bool json_iter_parse(struct json_iter *iter, enum json_type type, ...);
+
+bool json_iter_get_int(struct json_iter *iter, int *i);
+bool json_iter_get_uint(struct json_iter *iter, unsigned int *i);
+bool json_iter_get_boolean(struct json_iter *iter, bool *b);
+bool json_iter_get_null(struct json_iter *iter);
-- 
2.31.1

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2022-01-05 18:46 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-01-05 18:46 [PATCH 1/8] json: add support for primitive types James Prestwood

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox