From 9e4480706b28abc41618bd598c00a194beb14c4f Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Sun, 7 May 2023 11:10:31 +0200
Subject: Aggregate YAML values from sequences when requested and possible.

---
 plugins/yaml/node.c             |   3 -
 plugins/yaml/pair-int.h         |   5 +-
 plugins/yaml/pair.c             | 176 +++++++++++++++++++++++++++++++++++++--
 plugins/yaml/pair.h             |  21 ++++-
 plugins/yaml/parser.c           |  60 +++++++++-----
 plugins/yaml/python/Makefile.am |   1 +
 plugins/yaml/python/constants.c | 127 ++++++++++++++++++++++++++++
 plugins/yaml/python/constants.h |  42 ++++++++++
 plugins/yaml/python/pair.c      | 179 ++++++++++++++++++++++++++++++++++++++--
 tests/plugins/yaml.py           |  27 ++++++
 10 files changed, 601 insertions(+), 40 deletions(-)
 create mode 100644 plugins/yaml/python/constants.c
 create mode 100644 plugins/yaml/python/constants.h

diff --git a/plugins/yaml/node.c b/plugins/yaml/node.c
index 97f845e..ff6fa7e 100644
--- a/plugins/yaml/node.c
+++ b/plugins/yaml/node.c
@@ -84,7 +84,6 @@ static void g_yaml_node_class_init(GYamlNodeClass *klass)
 
 static void g_yaml_node_init(GYamlNode *node)
 {
-    //node->line = NULL;
 
 }
 
@@ -103,8 +102,6 @@ static void g_yaml_node_init(GYamlNode *node)
 
 static void g_yaml_node_dispose(GYamlNode *node)
 {
-    //g_clear_object(&node->line);
-
     G_OBJECT_CLASS(g_yaml_node_parent_class)->dispose(G_OBJECT(node));
 
 }
diff --git a/plugins/yaml/pair-int.h b/plugins/yaml/pair-int.h
index 735a357..88b968d 100644
--- a/plugins/yaml/pair-int.h
+++ b/plugins/yaml/pair-int.h
@@ -41,7 +41,10 @@ struct _GYamlPair
     GYamlNode parent;                       /* A laisser en premier        */
 
     char *key;                              /* Clef présente dans le noeud */
+    YamlOriginalStyle key_style;            /* Forme d'origine associé     */
+
     char *value;                            /* Valeur associée             */
+    YamlOriginalStyle value_style;          /* Forme d'origine associé     */
 
     GYamlCollection *children;              /* Collection de noeuds        */
 
@@ -56,7 +59,7 @@ struct _GYamlPairClass
 
 
 /* Met en place une pair clef/valeur YAML. */
-bool g_yaml_pair_create(GYamlPair *, const char *, const char *);
+bool g_yaml_pair_create(GYamlPair *, const char *, YamlOriginalStyle, const char *, YamlOriginalStyle);
 
 
 
diff --git a/plugins/yaml/pair.c b/plugins/yaml/pair.c
index 1057a68..4faba88 100644
--- a/plugins/yaml/pair.c
+++ b/plugins/yaml/pair.c
@@ -29,6 +29,9 @@
 #include <string.h>
 
 
+#include <common/extstr.h>
+
+
 #include "pair-int.h"
 
 
@@ -111,7 +114,10 @@ static void g_yaml_pair_class_init(GYamlPairClass *klass)
 static void g_yaml_pair_init(GYamlPair *pair)
 {
     pair->key = NULL;
+    pair->key_style = YOS_PLAIN;
+
     pair->value = NULL;
+    pair->value_style = YOS_PLAIN;
 
     pair->children = NULL;
 
@@ -166,8 +172,10 @@ static void g_yaml_pair_finalize(GYamlPair *pair)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : key   = désignation pour le noeud YAML.                      *
-*                value = éventuelle valeur directe portée par le noeud.       *
+*  Paramètres  : key    = désignation pour le noeud YAML.                     *
+*                kstyle = format d'origine de la clef.                        *
+*                value  = éventuelle valeur directe portée par le noeud.      *
+*                vstyle = éventuel format d'origine de l'éventuelle valeur.   *
 *                                                                             *
 *  Description : Construit un noeud d'arborescence YAML.                      *
 *                                                                             *
@@ -177,13 +185,13 @@ static void g_yaml_pair_finalize(GYamlPair *pair)
 *                                                                             *
 ******************************************************************************/
 
-GYamlPair *g_yaml_pair_new(const char *key, const char *value)
+GYamlPair *g_yaml_pair_new(const char *key, YamlOriginalStyle kstyle, const char *value, YamlOriginalStyle vstyle)
 {
     GYamlPair *result;                      /* Structure à retourner       */
 
     result = g_object_new(G_TYPE_YAML_PAIR, NULL);
 
-    if (!g_yaml_pair_create(result, key, value))
+    if (!g_yaml_pair_create(result, key, kstyle, value, vstyle))
         g_clear_object(&result);
 
     return result;
@@ -193,9 +201,11 @@ GYamlPair *g_yaml_pair_new(const char *key, const char *value)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : pair  = paire YAML à initialiser pleinement.                 *
-*                key   = désignation pour le noeud YAML.                      *
-*                value = éventuelle valeur directe portée par le noeud.       *
+*  Paramètres  : pair   = paire YAML à initialiser pleinement.                *
+*                key    = désignation pour le noeud YAML.                     *
+*                kstyle = format d'origine de la clef.                        *
+*                value  = éventuelle valeur directe portée par le noeud.      *
+*                vstyle = éventuel format d'origine de l'éventuelle valeur.   *
 *                                                                             *
 *  Description : Met en place une pair clef/valeur YAML.                      *
 *                                                                             *
@@ -205,16 +215,20 @@ GYamlPair *g_yaml_pair_new(const char *key, const char *value)
 *                                                                             *
 ******************************************************************************/
 
-bool g_yaml_pair_create(GYamlPair *pair, const char *key, const char *value)
+bool g_yaml_pair_create(GYamlPair *pair, const char *key, YamlOriginalStyle kstyle, const char *value, YamlOriginalStyle vstyle)
 {
     bool result;                            /* Bilan à retourner           */
 
     result = true;
 
     pair->key = strdup(key);
+    pair->key_style = kstyle;
 
     if (value != NULL)
+    {
         pair->value = strdup(value);
+        pair->value_style = vstyle;
+    }
 
     return result;
 
@@ -248,6 +262,29 @@ const char *g_yaml_pair_get_key(const GYamlPair *pair)
 *                                                                             *
 *  Paramètres  : pair = noeud d'arborescence YAML à consulter.                *
 *                                                                             *
+*  Description : Indique le format d'origine YAML associé à la clef.          *
+*                                                                             *
+*  Retour      : Valeur renseignée lors du chargement du noeud.               *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+YamlOriginalStyle g_yaml_pair_get_key_style(const GYamlPair *pair)
+{
+    YamlOriginalStyle result;               /* Indication à retourner      */
+
+    result = pair->key_style;
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : pair = noeud d'arborescence YAML à consulter.                *
+*                                                                             *
 *  Description : Fournit l'éventuelle valeur d'une paire en YAML.             *
 *                                                                             *
 *  Retour      : Valeur sous forme de chaîne de caractères ou NULL.           *
@@ -269,6 +306,129 @@ const char *g_yaml_pair_get_value(const GYamlPair *pair)
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : pair = noeud d'arborescence YAML à consulter.                *
+*                                                                             *
+*  Description : Indique le format d'origine YAML associé à la valeur.        *
+*                                                                             *
+*  Retour      : Valeur renseignée lors du chargement du noeud.               *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+YamlOriginalStyle g_yaml_pair_get_value_style(const GYamlPair *pair)
+{
+    YamlOriginalStyle result;               /* Indication à retourner      */
+
+    result = pair->value_style;
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : pair = noeud d'arborescence YAML à consulter.                *
+*                                                                             *
+*  Description : Rassemble une éventuelle séquence de valeurs attachées.      *
+*                                                                             *
+*  Retour      : Valeur sous forme de chaîne de caractères ou NULL.           *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+char *g_yaml_pair_aggregate_value(const GYamlPair *pair)
+{
+    char *result;                           /* Valeur à retourner          */
+    GYamlNode **nodes;                      /* Eventuels noeuds trouvés    */
+    size_t count;                           /* Quantité de ces noeuds      */
+    size_t i;                               /* Boucle de parcours          */
+    GYamlPair *child;                       /* Couple clef/valeur enfant   */
+    bool failed;                            /* Détection d'un échec        */
+
+    result = NULL;
+
+    if (pair->value != NULL)
+        result = strdup(pair->value);
+
+    else if (pair->children != NULL)
+    {
+        if (!g_yaml_collection_is_sequence(pair->children))
+            goto exit;
+
+        nodes = g_yaml_collection_get_nodes(pair->children, &count);
+
+        if (count == 0)
+            result = strdup("[ ]");
+
+        else
+        {
+            result = strdup("[ ");
+
+            for (i = 0; i < count; i++)
+            {
+                if (!G_IS_YAML_PAIR(nodes[i]))
+                    break;
+
+                child = G_YAML_PAIR(nodes[i]);
+
+                if (child->value != NULL)
+                    break;
+
+                if (i > 0)
+                    result = stradd(result, ", ");
+
+                switch (child->key_style)
+                {
+                    case YOS_PLAIN:
+                        result = stradd(result, child->key);
+                        break;
+
+                    case YOS_SINGLE_QUOTED:
+                        result = straddfmt(result, "'%s'", child->key);
+                        break;
+
+                    case YOS_DOUBLE_QUOTED:
+                        result = straddfmt(result, "\"%s\"", child->key);
+                        break;
+
+                }
+
+                g_object_unref(G_OBJECT(nodes[i]));
+
+            }
+
+            failed = (i < count);
+
+            for (; i < count; i++)
+                g_object_unref(G_OBJECT(nodes[i]));
+
+            free(nodes);
+
+            if (failed)
+            {
+                free(result);
+                result = NULL;
+            }
+
+            else
+                result = stradd(result, " ]");
+
+        }
+
+    }
+
+ exit:
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : pair     = noeud d'arborescence YAML à compléter.            *
 *                children = collection de noeuds YAML.                        *
 *                                                                             *
diff --git a/plugins/yaml/pair.h b/plugins/yaml/pair.h
index cc470ed..5265392 100644
--- a/plugins/yaml/pair.h
+++ b/plugins/yaml/pair.h
@@ -48,18 +48,37 @@ typedef struct _GYamlPair GYamlPair;
 typedef struct _GYamlPairClass GYamlPairClass;
 
 
+/* Format d'origine des éléments du couple clef/valeur */
+typedef enum _YamlOriginalStyle
+{
+    YOS_PLAIN,                              /* Mode brut, par défaut       */
+    YOS_SINGLE_QUOTED,                      /* Encadré simplement          */
+    YOS_DOUBLE_QUOTED,                      /* ENcadré avec des guillemets */
+
+} YamlOriginalStyle;
+
+
 /* Indique le type défini pour un noeud d'arborescence Yaml. */
 GType g_yaml_pair_get_type(void);
 
 /* Construit un noeud d'arborescence Yaml. */
-GYamlPair *g_yaml_pair_new(const char *, const char *);
+GYamlPair *g_yaml_pair_new(const char *, YamlOriginalStyle, const char *, YamlOriginalStyle);
 
 /* Fournit la clef représentée dans une paire en Yaml. */
 const char *g_yaml_pair_get_key(const GYamlPair *);
 
+/* Indique le format d'origine YAML associé à la clef. */
+YamlOriginalStyle g_yaml_pair_get_key_style(const GYamlPair *);
+
 /* Fournit l'éventuelle valeur d'une paire en Yaml. */
 const char *g_yaml_pair_get_value(const GYamlPair *);
 
+/* Indique le format d'origine YAML associé à la valeur. */
+YamlOriginalStyle g_yaml_pair_get_value_style(const GYamlPair *);
+
+/* Rassemble une éventuelle séquence de valeurs attachées. */
+char *g_yaml_pair_aggregate_value(const GYamlPair *);
+
 /* Attache une collection de noeuds Yaml à un noeud. */
 void g_yaml_pair_set_children(GYamlPair *, GYamlCollection *);
 
diff --git a/plugins/yaml/parser.c b/plugins/yaml/parser.c
index 92e78be..8c06723 100644
--- a/plugins/yaml/parser.c
+++ b/plugins/yaml/parser.c
@@ -37,12 +37,24 @@
 #include "pair.h"
 
 
+#define SCALAR_STYLE_TO_ORIGINAL_STYLE(v)               \
+    ({                                                  \
+        YamlOriginalStyle __result;                     \
+        if (v == YAML_SINGLE_QUOTED_SCALAR_STYLE)       \
+            __result = YOS_SINGLE_QUOTED;               \
+        else if (v == YAML_DOUBLE_QUOTED_SCALAR_STYLE)  \
+            __result = YOS_DOUBLE_QUOTED;               \
+        else                                            \
+            __result = YOS_PLAIN;                       \
+        __result;                                       \
+    })
+
 
 /* Construit la version GLib d'un noeud YAML brut. */
 static GYamlPair *build_pair_from_yaml(yaml_document_t *, int, int);
 
 /* Transforme un noeud YAML brut en sa version Glib. */
-static GYamlCollection *translate_yaml_node(yaml_document_t *, yaml_node_t *);
+static GYamlNode *translate_yaml_node(yaml_document_t *, yaml_node_t *);
 
 
 
@@ -65,7 +77,7 @@ static GYamlPair *build_pair_from_yaml(yaml_document_t *document, int key, int v
     GYamlPair *result;                      /* Racine à retourner          */
     yaml_node_t *key_node;                  /* Noeud brut de la clef       */
     yaml_node_t *value_node;                /* Noeud brut de la valeur     */
-    GYamlCollection *children;              /* Collection de noeuds YAML   */
+    GYamlNode *children;                    /* Collection de noeuds YAML   */
 
     result = NULL;
 
@@ -79,7 +91,10 @@ static GYamlPair *build_pair_from_yaml(yaml_document_t *document, int key, int v
     assert(value_node != NULL);
 
     if (value_node->type == YAML_SCALAR_NODE)
-        result = g_yaml_pair_new((char *)key_node->data.scalar.value, (char *)value_node->data.scalar.value);
+        result = g_yaml_pair_new((char *)key_node->data.scalar.value,
+                                 SCALAR_STYLE_TO_ORIGINAL_STYLE(key_node->data.scalar.style),
+                                 (char *)value_node->data.scalar.value,
+                                 SCALAR_STYLE_TO_ORIGINAL_STYLE(value_node->data.scalar.style));
 
     else
     {
@@ -87,9 +102,11 @@ static GYamlPair *build_pair_from_yaml(yaml_document_t *document, int key, int v
 
         if (children != NULL)
         {
-            result = g_yaml_pair_new((char *)key_node->data.scalar.value, NULL);
+            result = g_yaml_pair_new((char *)key_node->data.scalar.value,
+                                     SCALAR_STYLE_TO_ORIGINAL_STYLE(key_node->data.scalar.style),
+                                     NULL, YOS_PLAIN);
 
-            g_yaml_pair_set_children(result, children);
+            g_yaml_pair_set_children(result, G_YAML_COLLEC(children));
 
         }
 
@@ -115,35 +132,41 @@ static GYamlPair *build_pair_from_yaml(yaml_document_t *document, int key, int v
 *                                                                             *
 ******************************************************************************/
 
-static GYamlCollection *translate_yaml_node(yaml_document_t *document, yaml_node_t *node)
+static GYamlNode *translate_yaml_node(yaml_document_t *document, yaml_node_t *node)
 {
-    GYamlCollection *result;                /* Racine à retourner          */
+    GYamlNode *result;                      /* Racine à retourner          */
     yaml_node_item_t *index;                /* Elément d'une série         */
     yaml_node_t *item;                      /* Elément d'une série         */
-    GYamlCollection *collec;                /* Version GLib de l'élément   */
+    GYamlNode *child;                       /* Version GLib de l'élément   */
     yaml_node_pair_t *pair;                 /* Combinaison clef/valeur     */
     GYamlPair *sub;                         /* Sous-noeud à intégrer       */
 
     switch (node->type)
     {
+        case YAML_SCALAR_NODE:
+            result = G_YAML_NODE(g_yaml_pair_new((char *)node->data.scalar.value,
+                                                 SCALAR_STYLE_TO_ORIGINAL_STYLE(node->data.scalar.style),
+                                                 NULL, YOS_PLAIN));
+            break;
+
         case YAML_SEQUENCE_NODE:
 
-            result = g_yaml_collection_new(true);
+            result = G_YAML_NODE(g_yaml_collection_new(true));
 
             for (index = node->data.sequence.items.start; index < node->data.sequence.items.top; index++)
             {
                 item = yaml_document_get_node(document, *index);
                 assert(item != NULL);
 
-                collec = translate_yaml_node(document, item);
+                child = translate_yaml_node(document, item);
 
-                if (collec == NULL)
+                if (child == NULL)
                 {
                     g_clear_object(&result);
                     break;
                 }
 
-                g_yaml_collection_add_node(result, G_YAML_NODE(collec));
+                g_yaml_collection_add_node(G_YAML_COLLEC(result), child);
 
             }
 
@@ -151,7 +174,7 @@ static GYamlCollection *translate_yaml_node(yaml_document_t *document, yaml_node
 
         case YAML_MAPPING_NODE:
 
-            result = g_yaml_collection_new(false);
+            result = G_YAML_NODE(g_yaml_collection_new(false));
 
             for (pair = node->data.mapping.pairs.start; pair < node->data.mapping.pairs.top; pair++)
             {
@@ -163,7 +186,7 @@ static GYamlCollection *translate_yaml_node(yaml_document_t *document, yaml_node
                     break;
                 }
 
-                g_yaml_collection_add_node(result, G_YAML_NODE(sub));
+                g_yaml_collection_add_node(G_YAML_COLLEC(result), G_YAML_NODE(sub));
 
             }
 
@@ -201,7 +224,6 @@ GYamlNode *parse_yaml_from_text(const char *text, size_t len)
     yaml_document_t document;               /* Document YAML constitué     */
     int ret;                                /* Bilan de la constitution    */
     yaml_node_t *root;                      /* Elément racine brut         */
-    GYamlCollection *collec;                /* Version Glib de la racine   */
 
     result = NULL;
 
@@ -215,13 +237,7 @@ GYamlNode *parse_yaml_from_text(const char *text, size_t len)
     root = yaml_document_get_root_node(&document);
 
     if (root != NULL)
-    {
-        collec = translate_yaml_node(&document, root);
-
-        if (collec != NULL)
-            result = G_YAML_NODE(collec);
-
-    }
+        result = translate_yaml_node(&document, root);
 
     yaml_document_delete(&document);
 
diff --git a/plugins/yaml/python/Makefile.am b/plugins/yaml/python/Makefile.am
index 89b319c..f3dc989 100644
--- a/plugins/yaml/python/Makefile.am
+++ b/plugins/yaml/python/Makefile.am
@@ -3,6 +3,7 @@ noinst_LTLIBRARIES = libyamlpython.la
 
 libyamlpython_la_SOURCES =					\
 	collection.h collection.c				\
+	constants.h constants.c					\
 	module.h module.c						\
 	node.h node.c							\
 	pair.h pair.c							\
diff --git a/plugins/yaml/python/constants.c b/plugins/yaml/python/constants.c
new file mode 100644
index 0000000..ff04584
--- /dev/null
+++ b/plugins/yaml/python/constants.c
@@ -0,0 +1,127 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * constants.c - prise en charge des constantes liées à YAML
+ *
+ * Copyright (C) 2023 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 this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#include "constants.h"
+
+
+#include <plugins/pychrysalide/helpers.h>
+
+
+#include "../pair.h"
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : type = type dont le dictionnaire est à compléter.            *
+*                                                                             *
+*  Description : Définit les constantes relatives au noeuds principaux.       *
+*                                                                             *
+*  Retour      : true en cas de succès de l'opération, false sinon.           *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool define_yaml_pair_constants(PyTypeObject *type)
+{
+    bool result;                            /* Bilan à retourner           */
+    PyObject *values;                       /* Groupe de valeurs à établir */
+
+    values = PyDict_New();
+
+    result = add_const_to_group(values, "PLAIN", YOS_PLAIN);
+    if (result) result = add_const_to_group(values, "SINGLE_QUOTED", YOS_SINGLE_QUOTED);
+    if (result) result = add_const_to_group(values, "DOUBLE_QUOTED", YOS_DOUBLE_QUOTED);
+
+    if (!result)
+    {
+        Py_DECREF(values);
+        goto exit;
+    }
+
+    result = attach_constants_group_to_type(type, false, "YamlOriginalStyle", values,
+                                            "Original style of scalar YAML nodes.");
+
+ exit:
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : arg = argument quelconque à tenter de convertir.             *
+*                dst = destination des valeurs récupérées en cas de succès.   *
+*                                                                             *
+*  Description : Tente de convertir en constante YamlOriginalStyle.           *
+*                                                                             *
+*  Retour      : Bilan de l'opération, voire indications supplémentaires.     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+int convert_to_yaml_pair_original_style(PyObject *arg, void *dst)
+{
+    int result;                             /* Bilan à retourner           */
+    unsigned long value;                    /* Valeur transcrite           */
+
+    result = PyObject_IsInstance(arg, (PyObject *)&PyLong_Type);
+
+    switch (result)
+    {
+        case -1:
+            /* L'exception est déjà fixée par Python */
+            result = 0;
+            break;
+
+        case 0:
+            PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to YamlOriginalStyle");
+            break;
+
+        case 1:
+            value = PyLong_AsUnsignedLong(arg);
+
+            if (value > YOS_DOUBLE_QUOTED)
+            {
+                PyErr_SetString(PyExc_TypeError, "invalid value for YamlOriginalStyle");
+                result = 0;
+            }
+
+            else
+                *((YamlOriginalStyle *)dst) = value;
+
+            break;
+
+        default:
+            assert(false);
+            break;
+
+    }
+
+    return result;
+
+}
diff --git a/plugins/yaml/python/constants.h b/plugins/yaml/python/constants.h
new file mode 100644
index 0000000..d31bb69
--- /dev/null
+++ b/plugins/yaml/python/constants.h
@@ -0,0 +1,42 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * constants.h - prototypes pour la prise en charge des constantes liées à YAML
+ *
+ * Copyright (C) 2023 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 this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#ifndef _PLUGINS_YAML_PYTHON_CONSTANTS_H
+#define _PLUGINS_YAML_PYTHON_CONSTANTS_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Définit les constantes relatives au noeuds principaux. */
+bool define_yaml_pair_constants(PyTypeObject *);
+
+/* Tente de convertir en constante YamlOriginalStyle. */
+int convert_to_yaml_pair_original_style(PyObject *, void *);
+
+
+
+#endif  /* _PLUGINS_YAML_PYTHON_CONSTANTS_H */
diff --git a/plugins/yaml/python/pair.c b/plugins/yaml/python/pair.c
index adaf04d..65132f6 100644
--- a/plugins/yaml/python/pair.c
+++ b/plugins/yaml/python/pair.c
@@ -26,6 +26,7 @@
 
 
 #include <assert.h>
+#include <malloc.h>
 #include <pygobject.h>
 
 
@@ -34,6 +35,7 @@
 
 
 #include "collection.h"
+#include "constants.h"
 #include "node.h"
 #include "../pair-int.h"
 
@@ -44,12 +46,21 @@ CREATE_DYN_CONSTRUCTOR(yaml_pair, G_TYPE_YAML_PAIR);
 /* Initialise une instance sur la base du dérivé de GObject. */
 static int py_yaml_pair_init(PyObject *, PyObject *, PyObject *);
 
+/* Rassemble une éventuelle séquence de valeurs attachées. */
+static PyObject *py_yaml_pair_aggregate_value(PyObject *, PyObject *);
+
 /* Fournit la clef représentée dans une paire en YAML. */
 static PyObject *py_yaml_pair_get_key(PyObject *, void *);
 
+/* Indique le format d'origine YAML associé à la clef. */
+static PyObject *py_yaml_pair_get_key_style(PyObject *, void *);
+
 /* Fournit l'éventuelle valeur d'une paire en YAML. */
 static PyObject *py_yaml_pair_get_value(PyObject *, void *);
 
+/* Indique le format d'origine YAML associé à la clef. */
+static PyObject *py_yaml_pair_get_value_style(PyObject *, void *);
+
 /* Attache une collection de noeuds YAML à un noeud. */
 static int py_yaml_pair_set_children(PyObject *, PyObject *, void *);
 
@@ -74,7 +85,9 @@ static PyObject *py_yaml_pair_get_children(PyObject *, void *);
 
 static int py_yaml_pair_init(PyObject *self, PyObject *args, PyObject *kwds)
 {
+    YamlOriginalStyle kstyle;               /* Format d'origine de la clef */
     const char *value;                      /* Eventuelle valeur associée  */
+    YamlOriginalStyle vstyle;               /* Format d'origine de la val. */
     const char *key;                        /* Clef associée au noeud      */
     int ret;                                /* Bilan de lecture des args.  */
     GYamlPair *pair;                        /* Création GLib à transmettre */
@@ -84,16 +97,35 @@ static int py_yaml_pair_init(PyObject *self, PyObject *args, PyObject *kwds)
     "\n"                                                                \
     "Instances can be created using the following constructor:\n"       \
     "\n"                                                                \
-    "    YamlPair(key, value=None)\n"                                   \
+    "    YamlPair(key, kstyle=PLAIN, value=None, vstyle=PLAIN)\n"       \
     "\n"                                                                \
     "Where *key* defines the name for the YAML node, and *value*"       \
-    " provides an optional direct value for the node."
+    " provides an optional direct value for the node. The *kstyle* and" \
+    " *vstyle* arguements are"                                          \
+    " pychrysalide.plugins.yaml.YamlPair.YamlOriginalStyle states"      \
+    " linking an original format to the provided relative strings.\n"   \
+    "\n"                                                                \
+    "The two style are mainly used to aggregate children values into"   \
+    " a raw array. The following declarations are indeed equivalent"    \
+    " and pychrysalide.plugins.yaml.YamlPair.aggregate_value()"         \
+    " build the latter version from the former one:\n"                  \
+    "\n"                                                                \
+    "a: [ 1, 2, 3 ]\n"                                                  \
+    "\n"                                                                \
+    "a:\n"                                                              \
+    "    - 1\n"                                                         \
+    "    - 2\n"                                                         \
+    "    - 3"                                                           \
 
     /* Récupération des paramètres */
 
+    kstyle = YOS_PLAIN;
     value = NULL;
+    vstyle = YOS_PLAIN;
 
-    ret = PyArg_ParseTuple(args, "s|s", &key, &value);
+    ret = PyArg_ParseTuple(args, "s|O&sO&",
+                           &key, convert_to_yaml_pair_original_style, &kstyle,
+                           &value, convert_to_yaml_pair_original_style, &vstyle);
     if (!ret) return -1;
 
     /* Initialisation d'un objet GLib */
@@ -105,7 +137,7 @@ static int py_yaml_pair_init(PyObject *self, PyObject *args, PyObject *kwds)
 
     pair = G_YAML_PAIR(pygobject_get(self));
 
-    if (!g_yaml_pair_create(pair, key, value))
+    if (!g_yaml_pair_create(pair, key, kstyle, value, vstyle))
     {
         PyErr_SetString(PyExc_ValueError, _("Unable to create YAML pair."));
         return -1;
@@ -119,6 +151,58 @@ static int py_yaml_pair_init(PyObject *self, PyObject *args, PyObject *kwds)
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : self = serveur à manipuler.                                  *
+*                args = arguments d'appel non utilisés ici.                   *
+*                                                                             *
+*  Description : Rassemble une éventuelle séquence de valeurs attachées.      *
+*                                                                             *
+*  Retour      : Valeur sous forme de chaîne de caractères ou None.           *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_yaml_pair_aggregate_value(PyObject *self, PyObject *args)
+{
+    PyObject *result;                       /* Bilan à retourner           */
+    GYamlPair *node;                        /* Version GLib du type        */
+    char *value;                            /* Chaîne à transmettre        */
+
+#define YAML_PAIR_AGGREGATE_VALUE_METHOD PYTHON_METHOD_DEF  \
+(                                                           \
+    aggregate_value, "$self, /",                            \
+    METH_NOARGS, py_yaml_pair,                              \
+    "Provide the value linked to the YAML node, rebuilding" \
+    " it from inner sequenced values if necessary and"      \
+    " possible."                                            \
+    "\n"                                                    \
+    "The result is a string value, or *None* if none"       \
+    " available."                                           \
+)
+
+    node = G_YAML_PAIR(pygobject_get(self));
+
+    value = g_yaml_pair_aggregate_value(node);
+
+    if (value == NULL)
+    {
+        result = Py_None;
+        Py_INCREF(result);
+    }
+
+    else
+    {
+        result = PyUnicode_FromString(value);
+        free(value);
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : self    = objet Python concerné par l'appel.                 *
 *                closure = non utilisé ici.                                   *
 *                                                                             *
@@ -160,6 +244,44 @@ static PyObject *py_yaml_pair_get_key(PyObject *self, void *closure)
 *  Paramètres  : self    = objet Python concerné par l'appel.                 *
 *                closure = non utilisé ici.                                   *
 *                                                                             *
+*  Description : Indique le format d'origine YAML associé à la clef.          *
+*                                                                             *
+*  Retour      : Valeur renseignée lors du chargement du noeud.               *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_yaml_pair_get_key_style(PyObject *self, void *closure)
+{
+    PyObject *result;                       /* Résultat à retourner        */
+    GYamlPair *node;                        /* Version GLib du noeud       */
+    YamlOriginalStyle style;                /* Format à transmettre        */
+
+#define YAML_PAIR_KEY_STYLE_ATTRIB PYTHON_GET_DEF_FULL      \
+(                                                           \
+    key_style, py_yaml_pair,                                \
+    "Original format for the YAML node Key, as a"           \
+    " pychrysalide.plugins.yaml.YamlPair.YamlOriginalStyle" \
+    " value."                                               \
+)
+
+    node = G_YAML_PAIR(pygobject_get(self));
+
+    style = g_yaml_pair_get_key_style(node);
+
+    result = cast_with_constants_group_from_type(get_python_yaml_pair_type(), "YamlOriginalStyle", style);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self    = objet Python concerné par l'appel.                 *
+*                closure = non utilisé ici.                                   *
+*                                                                             *
 *  Description : Fournit l'éventuelle valeur d'une paire en YAML.             *
 *                                                                             *
 *  Retour      : Valeur sous forme de chaîne de caractères ou None.           *
@@ -178,7 +300,7 @@ static PyObject *py_yaml_pair_get_value(PyObject *self, void *closure)
 (                                                           \
     value, py_yaml_pair,                                    \
     "Value linked to the YAML key/value pair node, as a"    \
-    " string value, or None if none defined."               \
+    " string value, or *None* if none defined."             \
 )
 
     node = G_YAML_PAIR(pygobject_get(self));
@@ -201,6 +323,47 @@ static PyObject *py_yaml_pair_get_value(PyObject *self, void *closure)
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : self    = objet Python concerné par l'appel.                 *
+*                closure = non utilisé ici.                                   *
+*                                                                             *
+*  Description : Indique le format d'origine YAML associé à la clef.          *
+*                                                                             *
+*  Retour      : Valeur renseignée lors du chargement du noeud.               *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_yaml_pair_get_value_style(PyObject *self, void *closure)
+{
+    PyObject *result;                       /* Résultat à retourner        */
+    GYamlPair *node;                        /* Version GLib du noeud       */
+    YamlOriginalStyle style;                /* Format à transmettre        */
+
+#define YAML_PAIR_VALUE_STYLE_ATTRIB PYTHON_GET_DEF_FULL    \
+(                                                           \
+    value_style, py_yaml_pair,                              \
+    "Original format for the YAML node Value, as a"         \
+    " pychrysalide.plugins.yaml.YamlPair.YamlOriginalStyle" \
+    " value.\n"                                             \
+    "\n"                                                    \
+    "Even if there is no value for the node, the default"   \
+    " style is returned: *PLAIN*."                          \
+)
+
+    node = G_YAML_PAIR(pygobject_get(self));
+
+    style = g_yaml_pair_get_value_style(node);
+
+    result = cast_with_constants_group_from_type(get_python_yaml_pair_type(), "YamlOriginalStyle", style);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : self    = contenu binaire à manipuler.                       *
 *                value   = collection de noeuds YAML.                         *
 *                closure = adresse non utilisée ici.                          *
@@ -308,12 +471,15 @@ static PyObject *py_yaml_pair_get_children(PyObject *self, void *closure)
 PyTypeObject *get_python_yaml_pair_type(void)
 {
     static PyMethodDef py_yaml_pair_methods[] = {
+        YAML_PAIR_AGGREGATE_VALUE_METHOD,
         { NULL }
     };
 
     static PyGetSetDef py_yaml_pair_getseters[] = {
         YAML_PAIR_KEY_ATTRIB,
+        YAML_PAIR_KEY_STYLE_ATTRIB,
         YAML_PAIR_VALUE_ATTRIB,
+        YAML_PAIR_VALUE_STYLE_ATTRIB,
         YAML_PAIR_CHILDREN_ATTRIB,
         { NULL }
     };
@@ -367,6 +533,9 @@ bool register_python_yaml_pair(PyObject *module)
     if (!register_class_for_pygobject(dict, G_TYPE_YAML_PAIR, type, get_python_yaml_node_type()))
         return false;
 
+    if (!define_yaml_pair_constants(type))
+        return false;
+
     return true;
 
 }
diff --git a/tests/plugins/yaml.py b/tests/plugins/yaml.py
index 2fbb0bd..4d2680c 100644
--- a/tests/plugins/yaml.py
+++ b/tests/plugins/yaml.py
@@ -146,3 +146,30 @@ root:
         found = root.find_first_by_path('/root/d')
 
         self.assertEqual(found.value, "'xx::xx'")
+
+
+    def testArrayAsSeq(self):
+        """Handle array as YAML block sequence."""
+
+        definitions = '''
+root:
+  a: [ a, 'b', 0xcc, "\td\n\\"'" ]
+'''
+
+        root = yaml.parse_from_text(definitions)
+
+        found = root.find_first_by_path('/root/a')
+
+        self.assertIsNone(found.value)
+
+        self.assertEqual(len(found.children.nodes), 4)
+
+        self.assertEqual(found.children.nodes[0].key, 'a')
+
+        self.assertEqual(found.children.nodes[1].key, 'b')
+
+        self.assertEqual(found.children.nodes[2].key, '0xcc')
+
+        self.assertEqual(found.children.nodes[3].key, "\td \"'")
+
+        self.assertEqual(found.aggregate_value(), '[ a, \'b\', 0xcc, "	d \"\'" ]')
-- 
cgit v0.11.2-87-g4458