Wireless Daemon for Linux
 help / color / mirror / Atom feed
From: James Prestwood <prestwoj at gmail.com>
To: iwd at lists.01.org
Subject: [PATCH v2 2/9] json: add support for primitive types
Date: Thu, 06 Jan 2022 11:50:00 -0800	[thread overview]
Message-ID: <20220106195007.528618-2-prestwoj@gmail.com> (raw)
In-Reply-To: 20220106195007.528618-1-prestwoj@gmail.com

[-- Attachment #1: Type: text/plain, Size: 5576 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 | 120 +++++++++++++++++++++++++++++++++++++++++++++++++----
 src/json.h |  13 +++++-
 2 files changed, 125 insertions(+), 8 deletions(-)

diff --git a/src/json.c b/src/json.c
index a917fb89..6c88ed3a 100644
--- a/src/json.c
+++ b/src/json.c
@@ -81,14 +81,14 @@ static int count_tokens_in_container(struct json_iter *iter, jsmntok_t *containe
 	return contents - container;
 }
 
-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 = count_tokens_in_container(iter, object);
+	child->start = token - c->tokens;
+	child->count = count_tokens_in_container(iter, token);
 }
 
 struct json_contents *json_contents_new(const char *json, size_t json_len)
@@ -149,7 +149,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:
@@ -159,12 +159,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:
@@ -205,6 +206,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;
@@ -264,3 +266,107 @@ 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 (!iter_get_primitive_data(iter, &ptr, &len))
+		return false;
+
+	errno = 0;
+
+	t = r = strtol(ptr, &endp, 10);
+	if (endp != ptr + len)
+		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 (!iter_get_primitive_data(iter, &ptr, &len))
+		return false;
+
+	errno = 0;
+
+	t = r = strtoul(ptr, &endp, 10);
+	if (endp != ptr + len)
+		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

                 reply	other threads:[~2022-01-06 19:50 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220106195007.528618-2-prestwoj@gmail.com \
    --to=iwd@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox