From cef46f9f06a7448db60116e8c0ccadee44d83692 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Sun, 17 Nov 2019 20:10:25 +0100
Subject: Extended the API to find an unique Yaml node.

---
 plugins/yaml/node.c        | 41 ++++++++++++++++++++++++++++++++
 plugins/yaml/node.h        |  3 +++
 plugins/yaml/python/node.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++
 tests/plugins/yamlrdr.py   | 12 +++++-----
 4 files changed, 109 insertions(+), 6 deletions(-)

diff --git a/plugins/yaml/node.c b/plugins/yaml/node.c
index 3dc6ec0..e2abeca 100644
--- a/plugins/yaml/node.c
+++ b/plugins/yaml/node.c
@@ -392,3 +392,44 @@ void g_yaml_node_find_by_path(GYamlNode *node, const char *path, GYamlNode ***no
     _g_yaml_node_find_by_path(node, path, nodes, count);
 
 }
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : node = noeud d'arborescence Yaml à consulter.                *
+*                path = chemin d'accès à parcourir.                           *
+*                                                                             *
+*  Description : Recherche l'unique noeud correspondant à un chemin.          *
+*                                                                             *
+*  Retour      : Noeud avec correspondance établie ou NULL.                   *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GYamlNode *g_yaml_node_find_one_by_path(GYamlNode *node, const char *path)
+{
+    GYamlNode *result;                      /* Trouvaille unique à renvoyer*/
+    GYamlNode **nodes;                      /* Liste de noeuds trouvés     */
+    size_t count;                           /* Taille de cette liste       */
+    size_t i;                               /* Boucle de parcours          */
+
+    g_yaml_node_find_by_path(node, path, &nodes, &count);
+
+    if (count == 1)
+    {
+        result = nodes[0];
+        g_object_ref(G_OBJECT(result));
+    }
+    else
+        result = NULL;
+
+    for (i = 0; i < count; i++)
+        g_object_unref(G_OBJECT(nodes[i]));
+
+    if (nodes != NULL)
+        free(nodes);
+
+    return result;
+
+}
diff --git a/plugins/yaml/node.h b/plugins/yaml/node.h
index f1bbb23..e1526d2 100644
--- a/plugins/yaml/node.h
+++ b/plugins/yaml/node.h
@@ -72,6 +72,9 @@ void _g_yaml_node_find_by_path(GYamlNode *, const char *, GYamlNode ***, size_t
 /* Recherche les noeuds correspondant à un chemin. */
 void g_yaml_node_find_by_path(GYamlNode *, const char *, GYamlNode ***, size_t *);
 
+/* Recherche l'unique noeud correspondant à un chemin. */
+GYamlNode *g_yaml_node_find_one_by_path(GYamlNode *, const char *);
+
 
 
 #endif  /* PLUGINS_YAML_NODE_H */
diff --git a/plugins/yaml/python/node.c b/plugins/yaml/python/node.c
index f2984d1..17aa065 100644
--- a/plugins/yaml/python/node.c
+++ b/plugins/yaml/python/node.c
@@ -43,6 +43,9 @@ static PyObject *py_yaml_node_new(PyTypeObject *, PyObject *, PyObject *);
 /* Recherche les noeuds correspondant à un chemin. */
 static PyObject *py_yaml_node_find_by_path(PyObject *, PyObject *);
 
+/* Recherche l'unique noeud correspondant à un chemin. */
+static PyObject *py_yaml_node_find_one_by_path(PyObject *, PyObject *);
+
 /* Fournit la ligne principale associée à un noeud. */
 static PyObject *py_yaml_node_get_yaml_line(PyObject *, void *);
 
@@ -162,6 +165,61 @@ static PyObject *py_yaml_node_find_by_path(PyObject *self, PyObject *args)
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : self = variable non utilisée ici.                            *
+*                args = arguments fournis à l'appel.                          *
+*                                                                             *
+*  Description : Recherche l'unique noeud correspondant à un chemin.          *
+*                                                                             *
+*  Retour      : Noeud avec correspondance établie ou None.                   *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_yaml_node_find_one_by_path(PyObject *self, PyObject *args)
+{
+    PyObject *result;                       /* Instance à retourner        */
+    const char *path;                       /* Chemin d'accès à traiter    */
+    int ret;                                /* Bilan de lecture des args.  */
+    GYamlNode *node;                        /* Version GLib du noeud       */
+    GYamlNode *found;                       /* Création GLib à transmettre */
+
+#define YAML_NODE_FIND_ONE_BY_PATH PYTHON_METHOD_DEF                        \
+(                                                                           \
+    find_one_by_path, "path",                                               \
+    METH_VARARGS, py_yaml_node,                                             \
+    "Find a given node from a Yaml node using a path.\n"                    \
+    "\n"                                                                    \
+    "Paths are node keys separated by '/', such as '/my/path/to/node'."     \
+    "\n"                                                                    \
+    "Only one node has to match the path for the function success."         \
+)
+
+    ret = PyArg_ParseTuple(args, "s", &path);
+    if (!ret) return NULL;
+
+    node = G_YAML_NODE(pygobject_get(self));
+
+    found = g_yaml_node_find_one_by_path(node, path);
+
+    if (found == NULL)
+    {
+        result = Py_None;
+        Py_INCREF(result);
+    }
+    else
+    {
+        result = pygobject_new(G_OBJECT(found));
+        g_object_unref(G_OBJECT(found));
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : self    = objet Python concerné par l'appel.                 *
 *                closure = non utilisé ici.                                   *
 *                                                                             *
@@ -316,6 +374,7 @@ PyTypeObject *get_python_yaml_node_type(void)
 {
     static PyMethodDef py_yaml_node_methods[] = {
         YAML_NODE_FIND_BY_PATH,
+        YAML_NODE_FIND_ONE_BY_PATH,
         { NULL }
     };
 
diff --git a/tests/plugins/yamlrdr.py b/tests/plugins/yamlrdr.py
index eeae032..2f2694b 100644
--- a/tests/plugins/yamlrdr.py
+++ b/tests/plugins/yamlrdr.py
@@ -242,10 +242,10 @@ root:
 
         if len(found) == 2:
 
-            sub = found[0].find_by_path('/a')
-            self.assertEqual(len(sub), 1)
-            self.assertEqual(sub[0].yaml_line.key, 'a')
+            sub = found[0].find_one_by_path('/a')
+            self.assertIsNotNone(sub)
+            self.assertEqual(sub.yaml_line.key, 'a')
 
-            sub = found[0].find_by_path('/aa')
-            self.assertEqual(len(sub), 1)
-            self.assertEqual(sub[0].yaml_line.key, 'aa')
+            sub = found[0].find_one_by_path('/aa')
+            self.assertIsNotNone(sub)
+            self.assertEqual(sub.yaml_line.key, 'aa')
-- 
cgit v0.11.2-87-g4458