diff options
Diffstat (limited to 'plugins/yaml/tree.c')
-rw-r--r-- | plugins/yaml/tree.c | 277 |
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); } |