[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