From 452107a39698856f1165185d5065d7d3555b86b6 Mon Sep 17 00:00:00 2001
From: Simon McVittie <smcv@collabora.com>
Date: Mon, 9 Nov 2020 17:53:18 +0000
Subject: [PATCH] json-utils: Add a helper to get an array of lines as a single
 string

We'll use this for the uevent blob in input devices, because that's much
easier to read than a single string with escaped newlines.

Signed-off-by: Simon McVittie <smcv@collabora.com>
---
 steam-runtime-tools/json-utils-internal.h |  3 ++
 steam-runtime-tools/json-utils.c          | 53 +++++++++++++++++++++++
 tests/json-utils.c                        | 35 +++++++++++++++
 3 files changed, 91 insertions(+)

diff --git a/steam-runtime-tools/json-utils-internal.h b/steam-runtime-tools/json-utils-internal.h
index c7e0a6793..318290e1b 100644
--- a/steam-runtime-tools/json-utils-internal.h
+++ b/steam-runtime-tools/json-utils-internal.h
@@ -43,3 +43,6 @@ guint srt_get_flags_from_json_array (GType flags_type,
 gchar ** _srt_json_object_dup_strv_member (JsonObject *json_obj,
                                            const gchar *array_member,
                                            const gchar *placeholder);
+
+gchar *_srt_json_object_dup_array_of_lines_member (JsonObject *json_obj,
+                                                   const gchar *array_member);
diff --git a/steam-runtime-tools/json-utils.c b/steam-runtime-tools/json-utils.c
index 1761d59c0..10dfbc7f0 100644
--- a/steam-runtime-tools/json-utils.c
+++ b/steam-runtime-tools/json-utils.c
@@ -139,3 +139,56 @@ _srt_json_object_dup_strv_member (JsonObject *json_obj,
 
   return ret;
 }
+
+/**
+ * _srt_json_object_dup_array_of_lines_member:
+ * @json_obj: (not nullable): A JSON Object used to search for
+ *  @array_member property
+ * @array_member: (not nullable): The JSON member to look up
+ *
+ * If @json_obj has a member named @array_member and it is an array
+ * of strings, concatenate the strings (adding a trailing newline to
+ * each one if not already present) and return them. Otherwise,
+ * return %NULL.
+ *
+ * Returns: (transfer full) (element-type utf8) (nullable):
+ *  A string, or %NULL if not found. Free with g_free().
+ */
+gchar *
+_srt_json_object_dup_array_of_lines_member (JsonObject *json_obj,
+                                            const gchar *array_member)
+{
+  JsonArray *array;
+  JsonNode *arr_node;
+  guint length;
+  g_autoptr(GString) ret = g_string_new ("");
+
+  g_return_val_if_fail (json_obj != NULL, NULL);
+  g_return_val_if_fail (array_member != NULL, NULL);
+
+  arr_node = json_object_get_member (json_obj, array_member);
+
+  if (arr_node == NULL || !JSON_NODE_HOLDS_ARRAY (arr_node))
+    return NULL;
+
+  array = json_node_get_array (arr_node);
+
+  if (array == NULL)
+    return NULL;
+
+  length = json_array_get_length (array);
+
+  for (guint i = 0; i < length; i++)
+    {
+      JsonNode *node = json_array_get_element (array, i);
+      const gchar *element = json_node_get_string (node);
+
+      if (element != NULL)
+        g_string_append (ret, element);
+
+      if (element == NULL || element[strlen (element) - 1] != '\n')
+        g_string_append_c (ret, '\n');
+    }
+
+  return g_string_free (g_steal_pointer (&ret), FALSE);
+}
diff --git a/tests/json-utils.c b/tests/json-utils.c
index 3bc22c9c4..6044a425e 100644
--- a/tests/json-utils.c
+++ b/tests/json-utils.c
@@ -57,6 +57,39 @@ teardown (Fixture *f,
   G_GNUC_UNUSED const Config *config = context;
 }
 
+static void
+test_dup_array_of_lines_member (Fixture *f,
+                                gconstpointer context)
+{
+  g_autoptr(JsonArray) arr = json_array_new ();
+  g_autoptr(JsonNode) arr_node = json_node_alloc ();
+  g_autoptr(JsonObject) obj = json_object_new ();
+  g_autofree gchar *missing = NULL;
+  g_autofree gchar *not_array = NULL;
+  g_autofree gchar *text = NULL;
+
+  json_array_add_string_element (arr, "one");
+  json_array_add_string_element (arr, "two\n");
+  json_array_add_object_element (arr, json_object_new ());
+  json_array_add_string_element (arr, "four");
+  json_node_init_array (arr_node, arr);
+  json_object_set_member (obj, "arr", g_steal_pointer (&arr_node));
+  json_object_set_double_member (obj, "not-array", 42.0);
+
+  missing = _srt_json_object_dup_array_of_lines_member (obj, "missing");
+  g_assert_null (missing);
+
+  not_array = _srt_json_object_dup_array_of_lines_member (obj, "not-array");
+  g_assert_null (not_array);
+
+  text = _srt_json_object_dup_array_of_lines_member (obj, "arr");
+  g_assert_cmpstr (text, ==,
+                   "one\n"
+                   "two\n"
+                   "\n"
+                   "four\n");
+}
+
 static void
 test_dup_strv_member (Fixture *f,
                       gconstpointer context)
@@ -105,6 +138,8 @@ main (int argc,
       char **argv)
 {
   g_test_init (&argc, &argv, NULL);
+  g_test_add ("/json-utils/dup-array-of-lines-member", Fixture, NULL,
+              setup, test_dup_array_of_lines_member, teardown);
   g_test_add ("/json-utils/dup-strv-member", Fixture, NULL,
               setup, test_dup_strv_member, teardown);
 
-- 
GitLab