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);  } | 
