/* Chrysalide - Outil d'analyse de fichiers binaires * tree.c - ligne de contenu Yaml * * Copyright (C) 2019 Cyrille Bagard * * This file is part of Chrysalide. * * Chrysalide is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * Chrysalide is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Chrysalide. If not, see . */ #include "tree.h" #include #include /* 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 */ }; /* Arborescence de lignes au format Yaml (classe) */ struct _GYamlTreeClass { GObjectClass parent; /* A laisser en premier */ }; /* Initialise la classe des arborescence de lignes Yaml. */ static void g_yaml_tree_class_init(GYamlTreeClass *); /* Initialise une instance d'arborescence de lignes Yaml. */ static void g_yaml_tree_init(GYamlTree *); /* Supprime toutes les références externes. */ 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 *); /* Indique le type défini pour une arborescence de lignes au format Yaml. */ G_DEFINE_TYPE(GYamlTree, g_yaml_tree, G_TYPE_OBJECT); /****************************************************************************** * * * Paramètres : klass = classe à initialiser. * * * * Description : Initialise la classe des arborescence de lignes Yaml. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_yaml_tree_class_init(GYamlTreeClass *klass) { GObjectClass *object; /* Autre version de la classe */ object = G_OBJECT_CLASS(klass); object->dispose = (GObjectFinalizeFunc/* ! */)g_yaml_tree_dispose; object->finalize = (GObjectFinalizeFunc)g_yaml_tree_finalize; } /****************************************************************************** * * * Paramètres : tree = instance à initialiser. * * * * Description : Initialise une instance d'arborescence de lignes Yaml. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_yaml_tree_init(GYamlTree *tree) { tree->indent = 0; tree->nodes = NULL; tree->count = 0; } /****************************************************************************** * * * Paramètres : tree = instance d'objet GLib à traiter. * * * * Description : Supprime toutes les références externes. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ 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_OBJECT_CLASS(g_yaml_tree_parent_class)->dispose(G_OBJECT(tree)); } /****************************************************************************** * * * Paramètres : tree = instance d'objet GLib à traiter. * * * * Description : Procède à la libération totale de la mémoire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ 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)); } /****************************************************************************** * * * Paramètres : indent = indentation nominale pour les lignes à traiter. * * lines = ensemble de lignes à constituer en arborescence. * * count = taille de cet ensemble de lignes. * * * * Description : Construit une arborescence à partir de lignes Yaml. * * * * Retour : Instance mise en place ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ GYamlTree *g_yaml_tree_new(size_t indent, GYamlLine **lines, size_t count) { GYamlTree *result; /* Structure à retourner */ size_t cur; /* Boucle de parcours */ GYamlNode *node; /* Nouveau noeud à intéger */ result = g_object_new(G_TYPE_YAML_TREE, NULL); result->indent = indent; for (cur = 0; cur < count; ) { node = g_yaml_tree_build_node(lines, count, &cur); if (node == NULL) break; result->nodes = realloc(result->nodes, ++result->count * sizeof(GYamlNode *)); g_object_ref_sink(G_OBJECT(node)); result->nodes[result->count - 1] = node; } if (cur < count) { g_object_unref(G_OBJECT(result)); result = NULL; } return result; } /****************************************************************************** * * * Paramètres : lines = ensemble de lignes à constituer en arborescence. * * count = taille de cet ensemble de lignes. * * cur = position courante dans les lignes. [OUT] * * * * Description : Construit un nouveau noeud dans une arborescence Yaml. * * * * Retour : Noeud mis en place ou NULL en cas d'erreur. * * * * Remarques : - * * * ******************************************************************************/ static GYamlNode *g_yaml_tree_build_node(GYamlLine **lines, size_t count, size_t *cur) { GYamlNode *result; /* Structure à retourner */ 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 */ line = lines[(*cur)++]; result = g_yaml_node_new(line); /* Détermination de l'indentation associée */ cur_indent = g_yaml_line_count_indent(line); same_indent = g_yaml_line_is_list_item(line); /* Parcours du reste des lignes */ for (; *cur < count; ) { line = lines[*cur]; next_indent = g_yaml_line_count_indent(line); if ((same_indent && next_indent > cur_indent) || (!same_indent && next_indent <= cur_indent)) break; child = g_yaml_tree_build_node(lines, count, cur); if (child == NULL) goto build_error; g_yaml_node_add_child(result, child); } return result; build_error: g_object_unref(G_OBJECT(result)); return NULL; } /****************************************************************************** * * * 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 : - * * * ******************************************************************************/ size_t g_yaml_tree_get_indent(const GYamlTree *tree) { size_t result; /* Quantité à retourner */ result = tree->indent; return result; } /****************************************************************************** * * * 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. * * * * Retour : Noeuds constituant les racines de l'arborescence. * * * * Remarques : - * * * ******************************************************************************/ GYamlNode **g_yaml_tree_get_root_nodes(const GYamlTree *tree, size_t *count) { GYamlNode **result; /* Liste à retourner */ size_t i; /* Boucle de parcours */ *count = tree->count; result = malloc(*count * sizeof(GYamlNode *)); for (i = 0; i < *count; i++) { result[i] = tree->nodes[i]; g_object_ref(G_OBJECT(result[i])); } return result; } /****************************************************************************** * * * Paramètres : tree = ligne au format Yaml à consulter. * * path = chemin d'accès à parcourir. * * * * Description : Recherche le noeud correspondant à un chemin. * * * * Retour : Eventuel noeud trouvé ou NULL si aucun. * * * * Remarques : - * * * ******************************************************************************/ GYamlNode *g_yaml_tree_find_node_by_path(const GYamlTree *tree, const char *path) { 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; }