[LTP] [PATCH 2/2] metaparse: Map arrays with designated initializers to JSON objects

Cyril Hrubis chrubis@suse.cz
Fri Jun 20 17:43:46 CEST 2025


The parser now scans array declarations and if it finds out that
complete initialization is using designated initializers the result is
mapped into a JSON object instead of an arrray.

A diff snippet looks like:

--------------------------
    "filesystems": [
-    [
-     ".type=btrfs"
-    ],
-    [
-     ".type=bcachefs"
-    ],
-    [
-     ".type=xfs",
-     ".min_kver=4.16",
-     ".mkfs_ver=mkfs.xfs >= 1.5.0",
-     [
+    {
+     "type": "btrfs"
+    },
+    {
+     "type": "bcachefs"
+    },
+    {
+     "type": "xfs",
+     "min_kver": "4.16",
+     "mkfs_ver": "mkfs.xfs >= 1.5.0",
+     "mkfs_opts": [
       "-m",
       "reflink=1"
-     ],
-     ".mkfs_opts=(constchar*const[])"
-    ]
+     ]
+    }
    ],
--------------------------

Signed-off-by: Cyril Hrubis <chrubis@suse.cz>
---
 metadata/data_storage.h |  20 ++++++
 metadata/metaparse.c    | 134 +++++++++++++++++++++++++++++++++-------
 2 files changed, 131 insertions(+), 23 deletions(-)

diff --git a/metadata/data_storage.h b/metadata/data_storage.h
index f837feec8..6ca5d7d90 100644
--- a/metadata/data_storage.h
+++ b/metadata/data_storage.h
@@ -10,6 +10,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
+#include <stdbool.h>
 
 enum data_type {
 	DATA_ARRAY,
@@ -228,6 +229,13 @@ static inline struct data_node *data_node_hash_get(struct data_node *self, const
 	return hash->elems[i].node;
 }
 
+static inline unsigned int data_node_hash_len(struct data_node *self)
+{
+	struct data_node_hash *hash = &self->hash;
+
+	return hash->elems_used;
+}
+
 static inline int data_node_array_add(struct data_node *self, struct data_node *payload)
 {
 	if (self->type != DATA_ARRAY)
@@ -285,6 +293,18 @@ static inline void data_print_padd(unsigned int i)
 		putchar(' ');
 }
 
+static inline bool data_node_is_empty(struct data_node *self)
+{
+	switch (self->type) {
+	case DATA_ARRAY:
+		return data_node_array_len(self) == 0;
+	case DATA_HASH:
+		return data_node_hash_len(self) == 0;
+	default:
+		return false;
+	}
+}
+
 static inline void data_node_print_(struct data_node *self, unsigned int padd)
 {
 	unsigned int i;
diff --git a/metadata/metaparse.c b/metadata/metaparse.c
index 9723a92c2..e9e9aee10 100644
--- a/metadata/metaparse.c
+++ b/metadata/metaparse.c
@@ -337,15 +337,20 @@ static void try_apply_macro(char **res)
 	*res = ret->data;
 }
 
-static void finalize_array_entry(char **entry, struct data_node *node)
+static void finalize_array_entry(char **val, char **id, struct data_node *node)
 {
-	if (!*entry)
+	if (!*val)
 		return;
 
-	data_node_array_add(node, data_node_string(*entry));
+	if (*id)
+		data_node_hash_add(node, *id+1, data_node_string(*val));
+	else
+		data_node_array_add(node, data_node_string(*val));
 
-	free(*entry);
-	*entry = NULL;
+	free(*id);
+	free(*val);
+	*id = NULL;
+	*val = NULL;
 }
 
 static void str_append(char **res, char *append)
@@ -369,24 +374,98 @@ err:
 	exit(1);
 }
 
-static int parse_array(FILE *f, struct data_node *node)
+static int array_is_hash(FILE *f)
 {
+	long pos = ftell(f);
+	int has_ids = 1;
+	int elem_seen = 0;
+	int in_id = 1;
 	char *token;
-	char *entry = NULL;
+
+	while ((token = next_token(f, NULL))) {
+
+		if (!strcmp(token, "}"))
+			goto ret;
+
+		elem_seen = 1;
+
+		if (!strcmp(token, "{")) {
+			if (in_id) {
+				has_ids = 0;
+				goto ret;
+			}
+
+			int level = 1;
+
+			for (;;) {
+				token = next_token(f, NULL);
+
+				if (!token)
+					goto ret;
+
+				if (!strcmp(token, "{"))
+					level++;
+
+				if (!strcmp(token, "}"))
+					level--;
+
+				if (!level)
+					break;
+			}
+		} else if (!strcmp(token, ",")) {
+			if (in_id) {
+				has_ids = 0;
+				goto ret;
+			}
+
+			in_id = 1;
+		} else if (!strcmp(token, "=")) {
+			in_id = 0;
+		}
+	}
+
+ret:
+	fseek(f, pos, SEEK_SET);
+	return elem_seen && has_ids;
+}
+
+static int parse_array(FILE *f, const char *arr_id, struct data_node **ret)
+{
+	char *token;
+	char *val = NULL, *id = NULL;
 	int parent_cnt = 0;
+	int is_hash = array_is_hash(f);
+
+	if (verbose)
+		fprintf(stderr, "PARSING ARRAY (%s) is_hash = %i\n", arr_id, is_hash);
+
+	if (is_hash)
+		*ret = data_node_hash();
+	else
+		*ret = data_node_array();
 
 	for (;;) {
 		if (!(token = next_token(f, NULL)))
 			return 1;
 
 		if (!strcmp(token, "{")) {
-			struct data_node *ret = data_node_array();
-			parse_array(f, ret);
+			struct data_node *sub_ret;
 
-			if (data_node_array_len(ret))
-				data_node_array_add(node, ret);
-			else
-				data_node_free(ret);
+			parse_array(f, id, &sub_ret);
+
+			if (data_node_is_empty(sub_ret)) {
+				data_node_free(sub_ret);
+			} else {
+				if (is_hash)
+					data_node_hash_add(*ret, id+1, sub_ret);
+				else
+					data_node_array_add(*ret, sub_ret);
+			}
+
+			free(id);
+			id = NULL;
+			free(val);
+			val = NULL;
 
 			continue;
 		}
@@ -394,23 +473,33 @@ static int parse_array(FILE *f, struct data_node *node)
 		if (!strcmp(token, "}")) {
 			struct data_node *arr_last;
 
-			finalize_array_entry(&entry, node);
-
+			finalize_array_entry(&val, &id, *ret);
 			/* Remove NULL terminating entry, if present. */
-			arr_last = data_node_array_last(node);
-			if (arr_last && arr_last->type == DATA_NULL)
-				data_node_array_last_rem(node);
+			if (!is_hash) {
+				arr_last = data_node_array_last(*ret);
+				if (arr_last && arr_last->type == DATA_NULL)
+					data_node_array_last_rem(*ret);
+			}
 
 			return 0;
 		}
 
+		if (is_hash && !strcmp(token, "=") && !id) {
+			id = val;
+			val = NULL;
+			continue;
+		}
+
 		if (!strcmp(token, ",") && parent_cnt <= 0) {
-			finalize_array_entry(&entry, node);
+			finalize_array_entry(&val, &id, *ret);
 			continue;
 		}
 
 		if (!strcmp(token, "NULL")) {
-			data_node_array_add(node, data_node_null());
+			if (is_hash)
+				data_node_hash_add(*ret, id, data_node_null());
+			else
+				data_node_array_add(*ret, data_node_null());
 			continue;
 		}
 
@@ -421,7 +510,7 @@ static int parse_array(FILE *f, struct data_node *node)
 			parent_cnt--;
 
 		try_apply_macro(&token);
-		str_append(&entry, token);
+		str_append(&val, token);
 	}
 
 	return 0;
@@ -605,8 +694,7 @@ static int parse_test_struct(FILE *f, struct data_node *doc, struct data_node *n
 		}
 
 		if (!strcmp(token, "{")) {
-			ret = data_node_array();
-			parse_array(f, ret);
+			parse_array(f, id, &ret);
 		} else if (!strcmp(token, "ARRAY_SIZE")) {
 			if (parse_array_size(f, &ret))
 				return 1;
-- 
2.49.0



More information about the ltp mailing list