summaryrefslogtreecommitdiff
path: root/plugins/yaml/tree.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/yaml/tree.c')
-rw-r--r--plugins/yaml/tree.c277
1 files changed, 140 insertions, 137 deletions
diff --git a/plugins/yaml/tree.c b/plugins/yaml/tree.c
index 98ee30c..0494aeb 100644
--- a/plugins/yaml/tree.c
+++ b/plugins/yaml/tree.c
@@ -24,20 +24,25 @@
#include "tree.h"
+#include <assert.h>
#include <malloc.h>
#include <string.h>
+#include <i18n.h>
+#include <core/logs.h>
+
+
+#include "collection.h"
+
+
/* Arborescence de lignes au format Yaml (instance) */
struct _GYamlTree
{
GObject parent; /* A laisser en premier */
- size_t indent; /* Niveau d'indentation */
-
- GYamlNode **nodes; /* Liste de noeuds à la racine */
- size_t count; /* Quantité de ces noeuds */
+ GYamlNode *root; /* Racine des noeuds */
};
@@ -61,8 +66,8 @@ static void g_yaml_tree_dispose(GYamlTree *);
/* Procède à la libération totale de la mémoire. */
static void g_yaml_tree_finalize(GYamlTree *);
-/* Construit un nouveau noeud dans une arborescence Yaml. */
-static GYamlNode *g_yaml_tree_build_node(GYamlLine **, size_t, size_t *);
+/* Construit une collection de noeuds avec une arborescence. */
+static bool g_yaml_tree_build_node(GYamlCollection *, GYamlLine **, size_t, size_t, size_t *);
@@ -108,10 +113,7 @@ static void g_yaml_tree_class_init(GYamlTreeClass *klass)
static void g_yaml_tree_init(GYamlTree *tree)
{
- tree->indent = 0;
-
- tree->nodes = NULL;
- tree->count = 0;
+ tree->root = NULL;
}
@@ -130,10 +132,7 @@ static void g_yaml_tree_init(GYamlTree *tree)
static void g_yaml_tree_dispose(GYamlTree *tree)
{
- size_t i; /* Boucle de parcours */
-
- for (i = 0; i < tree->count; i++)
- g_clear_object(&tree->nodes[i]);
+ g_clear_object(&tree->root);
G_OBJECT_CLASS(g_yaml_tree_parent_class)->dispose(G_OBJECT(tree));
@@ -154,9 +153,6 @@ static void g_yaml_tree_dispose(GYamlTree *tree)
static void g_yaml_tree_finalize(GYamlTree *tree)
{
- if (tree->nodes != NULL)
- free(tree->nodes);
-
G_OBJECT_CLASS(g_yaml_tree_parent_class)->finalize(G_OBJECT(tree));
}
@@ -164,8 +160,7 @@ static void g_yaml_tree_finalize(GYamlTree *tree)
/******************************************************************************
* *
-* Paramètres : indent = indentation nominale pour les lignes à traiter. *
-* lines = ensemble de lignes à constituer en arborescence. *
+* Paramètres : lines = ensemble de lignes à constituer en arborescence. *
* count = taille de cet ensemble de lignes. *
* *
* Description : Construit une arborescence à partir de lignes Yaml. *
@@ -176,34 +171,37 @@ static void g_yaml_tree_finalize(GYamlTree *tree)
* *
******************************************************************************/
-GYamlTree *g_yaml_tree_new(size_t indent, GYamlLine **lines, size_t count)
+GYamlTree *g_yaml_tree_new(GYamlLine **lines, size_t count)
{
GYamlTree *result; /* Structure à retourner */
- size_t cur; /* Boucle de parcours */
- GYamlNode *node; /* Nouveau noeud à intéger */
+ GYamlCollection *collec; /* Collection de noeuds */
+ size_t indent; /* Indentation initiale */
+ size_t processed; /* Quantité de noeuds traités */
+ bool status; /* Bilan de construction */
result = g_object_new(G_TYPE_YAML_TREE, NULL);
- result->indent = indent;
-
- for (cur = 0; cur < count; )
+ if (count > 0)
{
- node = g_yaml_tree_build_node(lines, count, &cur);
+ result->root = g_yaml_node_new(NULL);
- if (node == NULL)
- break;
+ collec = g_yaml_collection_new(g_yaml_line_is_list_item(lines[0]));
+ g_yaml_node_set_collection(result->root, collec);
- result->nodes = realloc(result->nodes, ++result->count * sizeof(GYamlNode *));
+ indent = g_yaml_line_count_indent(lines[0]);
+ processed = 0;
- g_object_ref_sink(G_OBJECT(node));
- result->nodes[result->count - 1] = node;
+ status = g_yaml_tree_build_node(collec, lines, count, indent, &processed);
- }
+ if (status)
+ assert(processed == count);
+
+ else
+ {
+ g_object_unref(G_OBJECT(result));
+ result = NULL;
+ }
- if (cur < count)
- {
- g_object_unref(G_OBJECT(result));
- result = NULL;
}
return result;
@@ -213,86 +211,129 @@ GYamlTree *g_yaml_tree_new(size_t indent, GYamlLine **lines, size_t count)
/******************************************************************************
* *
-* Paramètres : lines = ensemble de lignes à constituer en arborescence. *
-* count = taille de cet ensemble de lignes. *
-* cur = position courante dans les lignes. [OUT] *
+* Paramètres : lines = ensemble de lignes à constituer en arborescence. *
+* count = taille de cet ensemble de lignes. *
+* expected = niveau d'identation attendu. *
+* cur = position courante dans les lignes. [OUT] *
* *
-* Description : Construit un nouveau noeud dans une arborescence Yaml. *
+* Description : Construit une collection de noeuds avec une arborescence. *
* *
-* Retour : Noeud mis en place ou NULL en cas d'erreur. *
+* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
-static GYamlNode *g_yaml_tree_build_node(GYamlLine **lines, size_t count, size_t *cur)
+static bool g_yaml_tree_build_node(GYamlCollection *collec, GYamlLine **lines, size_t count, size_t expected, size_t *cur)
{
- GYamlNode *result; /* Structure à retourner */
+ bool result; /* Bilan à retourner */
+ bool first; /* Marque d'un premier élément */
+ GYamlNode *last; /* Mémorisation du dernier */
GYamlLine *line; /* Ligne de parcours courante */
- size_t cur_indent; /* Indentation courante */
- bool same_indent; /* Comparaison pour les enfants*/
- size_t next_indent; /* Indentation de la ligne */
- GYamlNode *child; /* Sous-noeud mis en place */
+ size_t indent; /* Indentation de ligne */
+ bool is_item; /* Elément d'une liste ? */
+ GYamlCollection *sub; /* Nouvelle sous-collection */
+ GYamlNode *glue; /* Noeud vide intermédiaire */
- line = lines[(*cur)++];
+ result = true;
- result = g_yaml_node_new(line);
+ first = true;
+ last = NULL;
- /* Détermination de l'indentation associée */
+ for (; *cur < count; )
+ {
+ line = lines[*cur];
- cur_indent = g_yaml_line_count_indent(line);
+ indent = g_yaml_line_count_indent(line);
+ is_item = g_yaml_line_is_list_item(line);
+
+ /**
+ * Si la première ligne traitée commence par un élément de liste,
+ * alors un appel parent a constitué une collection qui n'est pas une séquence.
+ *
+ * L'objectif est de créer une simple association de 'clefs: valeurs'.
+ *
+ * Si la collection n'est pas adapté, alors le parcours n'est pas encore
+ * arrivé à ce stade de construction.
+ */
+ if (first && is_item && !g_yaml_collection_is_sequence(collec))
+ {
+ indent += 2; /* 2 == strlen("- ") */
+ is_item = false;
+ }
- same_indent = g_yaml_line_is_list_item(line);
+ first = false;
- /* Parcours du reste des lignes */
+ /* Fin de l'ensemble courant */
+ if (indent < expected)
+ goto done;
- for (; *cur < count; )
- {
- line = lines[*cur];
+ /* Début d'un sous-ensemble */
+ else if (indent > expected)
+ {
+ assert(last != NULL);
- next_indent = g_yaml_line_count_indent(line);
+ sub = g_yaml_collection_new(is_item);
+ g_yaml_node_set_collection(last, sub);
- if ((same_indent && next_indent > cur_indent)
- || (!same_indent && next_indent <= cur_indent))
- break;
+ result = g_yaml_tree_build_node(sub, lines, count, indent, cur);
+ if (!result) goto done;
- child = g_yaml_tree_build_node(lines, count, cur);
+ }
- if (child == NULL)
- goto build_error;
+ /* Elément de même niveau */
+ else
+ {
+ if (is_item)
+ {
+ /* Vérification de cohérence */
+ if (!g_yaml_collection_is_sequence(collec))
+ {
+ log_variadic_message(LMT_BAD_BINARY, _("A mapping item was expected at line %zu"),
+ g_yaml_line_get_number(line));
- g_yaml_node_add_child(result, child);
+ result = false;
+ goto done;
- }
+ }
- return result;
+ glue = g_yaml_node_new(NULL);
+ g_yaml_collection_add_node(collec, glue);
- build_error:
+ sub = g_yaml_collection_new(false);
+ g_yaml_node_set_collection(glue, sub);
- g_object_unref(G_OBJECT(result));
+ result = g_yaml_tree_build_node(sub, lines, count, expected + 2 /* 2 == strlen("- ") */, cur);
+ if (!result) goto done;
- return NULL;
+ }
-}
+ else
+ {
+ /* Vérification de cohérence */
+ if (g_yaml_collection_is_sequence(collec))
+ {
+ log_variadic_message(LMT_BAD_BINARY, _("A list item was expected at line %zu"),
+ g_yaml_line_get_number(line));
-/******************************************************************************
-* *
-* Paramètres : tree = ligne au format Yaml à consulter. *
-* *
-* Description : Fournit la taille de l'indentation nomilae d'un arbre Yaml. *
-* *
-* Retour : Taille de l'indentation associée. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
+ result = false;
+ goto done;
-size_t g_yaml_tree_get_indent(const GYamlTree *tree)
-{
- size_t result; /* Quantité à retourner */
+ }
+
+ last = g_yaml_node_new(line);
+ g_yaml_collection_add_node(collec, last);
+
+ (*cur)++;
+
+ }
+
+ }
+
+ }
- result = tree->indent;
+ done:
return result;
@@ -302,30 +343,21 @@ size_t g_yaml_tree_get_indent(const GYamlTree *tree)
/******************************************************************************
* *
* Paramètres : tree = ligne au format Yaml à consulter. *
-* count = taille de la liste constituée. [OUT] *
* *
-* Description : Fournit la liste des premiers noeuds de l'arborescence Yaml. *
+* Description : Fournit le noeud constituant la racine d'arborescence Yaml. *
* *
-* Retour : Noeuds constituant les racines de l'arborescence. *
+* Retour : Noeud constituant la racine de l'arborescence. *
* *
* Remarques : - *
* *
******************************************************************************/
-GYamlNode **g_yaml_tree_get_root_nodes(const GYamlTree *tree, size_t *count)
+GYamlNode *g_yaml_tree_get_root(const GYamlTree *tree)
{
- GYamlNode **result; /* Liste à retourner */
- size_t i; /* Boucle de parcours */
-
- *count = tree->count;
+ GYamlNode *result; /* Liste à retourner */
- result = malloc(*count * sizeof(GYamlNode *));
-
- for (i = 0; i < *count; i++)
- {
- result[i] = tree->nodes[i];
- g_object_ref(G_OBJECT(result[i]));
- }
+ result = tree->root;
+ g_object_ref(G_OBJECT(result));
return result;
@@ -334,50 +366,21 @@ GYamlNode **g_yaml_tree_get_root_nodes(const GYamlTree *tree, size_t *count)
/******************************************************************************
* *
-* Paramètres : tree = ligne au format Yaml à consulter. *
-* path = chemin d'accès à parcourir. *
+* Paramètres : tree = ligne au format Yaml à consulter. *
+* path = chemin d'accès à parcourir. *
+* nodes = liste de noeuds avec correspondance établie. [OUT] *
+* count = quantité de ces noeuds. [OUT] *
* *
-* Description : Recherche le noeud correspondant à un chemin. *
+* Description : Recherche les noeuds correspondant à un chemin. *
* *
-* Retour : Eventuel noeud trouvé ou NULL si aucun. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-GYamlNode *g_yaml_tree_find_node_by_path(const GYamlTree *tree, const char *path)
+void g_yaml_tree_find_by_path(const GYamlTree *tree, const char *path, GYamlNode ***nodes, size_t *count)
{
- GYamlNode *result; /* Trouvaille à retourner */
- char *next; /* Prochaine partie du chemin */
- size_t cmplen; /* Etendue de la comparaison */
- size_t i; /* Boucle de parcours */
- GYamlLine *line; /* Ligne Yaml d'un enfant */
- const char *key; /* Clef d'un noeud */
- int ret; /* Bilan d'une comparaison */
-
- result = NULL;
-
- if (path[0] == '/' && path[0] != '\0')
- {
- next = strchr(path + 1, '/');
-
- cmplen = (next == NULL ? strlen(path + 1) : next - path - 1);
-
- for (i = 0; i < tree->count && result == NULL; i++)
- {
- line = g_yaml_node_get_yaml_line(tree->nodes[i]);
-
- key = g_yaml_line_get_key(line);
-
- ret = strncmp(path + 1, key, cmplen);
-
- if (ret == 0)
- result = g_yaml_node_find_node_by_path(tree->nodes[i], next);
-
- }
-
- }
-
- return result;
+ g_yaml_node_find_by_path(tree->root, path, nodes, count);
}