From 2700e6892a0c0d78baf7228040aa07a1e21c6f53 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Fri, 29 May 2020 00:25:26 +0200
Subject: Adapted the API for renamed operands.

---
 plugins/pychrysalide/arch/operands/rename.c | 352 +++++++++++++++++++++++++++-
 plugins/pychrysalide/arch/operands/rename.h |   6 +
 plugins/pychrysalide/glibext/linegen.c      |   4 +-
 src/arch/operands/rename-int.h              |   2 +-
 src/arch/operands/rename.c                  |   4 +-
 src/arch/operands/rename.h                  |   2 +-
 6 files changed, 353 insertions(+), 17 deletions(-)

diff --git a/plugins/pychrysalide/arch/operands/rename.c b/plugins/pychrysalide/arch/operands/rename.c
index da1543b..7a5be98 100644
--- a/plugins/pychrysalide/arch/operands/rename.c
+++ b/plugins/pychrysalide/arch/operands/rename.c
@@ -28,7 +28,7 @@
 #include <pygobject.h>
 
 
-#include <arch/operands/rename.h>
+#include <arch/operands/rename-int.h>
 
 
 #include "../../access.h"
@@ -36,12 +36,18 @@
 
 
 
-/* ------------------------ INTERFACE POUR OPERANDE RENOMMEE ------------------------ */
+/* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */
+
+
+/* Procède à l'initialisation de l'interface de renom. */
+static void py_renamed_operand_init(GRenamedOperandIface *, gpointer *);
+
+/* Fournit un texte comme représentation alternative d'opérande. */
+static char *py_renamed_operand_get_text_wrapper(const GRenamedOperand *);
+
 
 
-#define RENAMED_OPERAND_DOC                                             \
-    "The RenamedOperand interface depicts operands renamed with an"     \
-    " alternative text."
+/* ------------------------ INTERFACE POUR OPERANDE RENOMMEE ------------------------ */
 
 
 /* Fournit un texte comme représentation alternative d'opérande. */
@@ -49,12 +55,18 @@ static PyObject *py_renamed_operand_get_text(PyObject *, void *);
 
 
 
-/* ----------------------- INTERFACE POUR OPERANDE RENOMMABLE ----------------------- */
+/* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */
+
 
+/* Procède à l'initialisation de l'interface de renommage. */
+static void py_renameable_operand_init(GRenameableOperandIface *, gpointer *);
+
+/* Construit un opérande de représentation alternative. */
+static GRenamedOperand *py_renameable_operand_build_wrapper(const GRenameableOperand *, const char *);
 
-#define RENAMEABLE_OPERAND_DOC                                          \
-    "The RenameableOperand interface depicts operands which can get"    \
-    " renamed with an alternative text."                                \
+
+
+/* ----------------------- INTERFACE POUR OPERANDE RENOMMABLE ----------------------- */
 
 
 /* Construit un opérande de représentation alternative. */
@@ -63,6 +75,107 @@ static PyObject *py_renameable_operand_build(PyObject *, PyObject *);
 
 
 /* ---------------------------------------------------------------------------------- */
+/*                          GLUE POUR CREATION DEPUIS PYTHON                          */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : iface  = interface GLib à initialiser.                       *
+*                unused = adresse non utilisée ici.                           *
+*                                                                             *
+*  Description : Procède à l'initialisation de l'interface de renom.          *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void py_renamed_operand_init(GRenamedOperandIface *iface, gpointer *unused)
+{
+
+#define RENAMED_OPERAND_DOC                                                 \
+    "The RenamedOperand interface depicts operands renamed with an"         \
+    " alternative text."                                                    \
+    "\n"                                                                    \
+    "A typical class declaration for a new implementation looks like:\n"    \
+    "\n"                                                                    \
+    "    class NewImplem(GObject.Object, RenamedOperand):\n"                \
+    "        ...\n"                                                         \
+    "\n"                                                                    \
+    "The following method has to be defined for new implementations:\n"     \
+    "* pychrysalide.arch.operands.RenamedOperand._get_text();\n"            \
+
+    iface->get_text = py_renamed_operand_get_text_wrapper;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : operand = operande à consulter.                              *
+*                                                                             *
+*  Description : Fournit un texte comme représentation alternative d'opérande.*
+*                                                                             *
+*  Retour      : Chaîne de caractère de représentation alternative.           *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static char *py_renamed_operand_get_text_wrapper(const GRenamedOperand *operand)
+{
+    char *result;                           /* Texte à retourner           */
+    PyGILState_STATE gstate;                /* Sauvegarde d'environnement  */
+    PyObject *pyobj;                        /* Objet Python concerné       */
+    PyObject *pyret;                        /* Bilan de consultation       */
+    int ret;                                /* Bilan d'une conversion      */
+
+#define RENAMED_OPERAND_GET_TEXT_WRAPPER PYTHON_WRAPPER_DEF     \
+(                                                               \
+    _get_text, "$self",                                         \
+    METH_NOARGS,                                                \
+    "Abstract method used to provide the alternative text for"  \
+    " rendering."                                               \
+    "\n"                                                        \
+    "The result of the call has to be a string."                \
+)
+
+    result = NULL;
+
+    gstate = PyGILState_Ensure();
+
+    pyobj = pygobject_new(G_OBJECT(operand));
+
+    if (has_python_method(pyobj, "_get_text"))
+    {
+        pyret = run_python_method(pyobj, "_get_text", NULL);
+
+        if (pyret != NULL)
+        {
+            ret = PyUnicode_Check(pyret);
+
+            if (ret)
+                result = strdup(PyUnicode_AsUTF8(pyret));
+
+            Py_DECREF(pyret);
+
+        }
+
+    }
+
+    Py_DECREF(pyobj);
+
+    PyGILState_Release(gstate);
+
+    return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
 /*                          INTERFACE POUR OPERANDE RENOMMEE                          */
 /* ---------------------------------------------------------------------------------- */
 
@@ -117,6 +230,7 @@ static PyObject *py_renamed_operand_get_text(PyObject *self, void *closure)
 PyTypeObject *get_python_renamed_operand_type(void)
 {
     static PyMethodDef py_renamed_operand_methods[] = {
+        RENAMED_OPERAND_GET_TEXT_WRAPPER,
         { NULL }
     };
 
@@ -164,6 +278,14 @@ bool ensure_python_renamed_operand_is_registered(void)
     PyObject *module;                       /* Module à recompléter        */
     PyObject *dict;                         /* Dictionnaire du module      */
 
+    static GInterfaceInfo info = {          /* Paramètres d'inscription    */
+
+        .interface_init = (GInterfaceInitFunc)py_renamed_operand_init,
+        .interface_finalize = NULL,
+        .interface_data = NULL,
+
+    };
+
     type = get_python_renamed_operand_type();
 
     if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
@@ -172,7 +294,7 @@ bool ensure_python_renamed_operand_is_registered(void)
 
         dict = PyModule_GetDict(module);
 
-        if (!register_interface_for_pygobject(dict, G_TYPE_RENAMED_OPERAND, type))
+        if (!register_interface_for_pygobject_2(dict, G_TYPE_RENAMED_OPERAND, type, &info))
             return false;
 
     }
@@ -182,6 +304,160 @@ bool ensure_python_renamed_operand_is_registered(void)
 }
 
 
+/******************************************************************************
+*                                                                             *
+*  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 opérande renommé.                      *
+*                                                                             *
+*  Retour      : Bilan de l'opération, voire indications supplémentaires.     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+int convert_to_renamed_operand(PyObject *arg, void *dst)
+{
+    int result;                             /* Bilan à retourner           */
+
+    result = PyObject_IsInstance(arg, (PyObject *)get_python_renamed_operand_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 renamed operand");
+            break;
+
+        case 1:
+            *((GRenamedOperand **)dst) = G_RENAMED_OPERAND(pygobject_get(arg));
+            break;
+
+        default:
+            assert(false);
+            break;
+
+    }
+
+    return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                          GLUE POUR CREATION DEPUIS PYTHON                          */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : iface  = interface GLib à initialiser.                       *
+*                unused = adresse non utilisée ici.                           *
+*                                                                             *
+*  Description : Procède à l'initialisation de l'interface de renommage.      *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void py_renameable_operand_init(GRenameableOperandIface *iface, gpointer *unused)
+{
+
+#define RENAMEABLE_OPERAND_DOC                                              \
+    "The RenameableOperand interface depicts operands which can get"        \
+    " renamed with an alternative text."                                    \
+    "\n"                                                                    \
+    "A typical class declaration for a new implementation looks like:\n"    \
+    "\n"                                                                    \
+    "    class NewImplem(GObject.Object, RenameableOperand):\n"             \
+    "        ...\n"                                                         \
+    "\n"                                                                    \
+    "The following method has to be defined for new implementations:\n"     \
+    "* pychrysalide.arch.operands.RenameableOperand._build();\n"            \
+
+    iface->build = py_renameable_operand_build_wrapper;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : operand = operande à consulter.                              *
+*                text    = texte alternatif de représentation.                *
+*                                                                             *
+*  Description : Construit un opérande de représentation alternative.         *
+*                                                                             *
+*  Retour      : Nouvel opérande, en version renommée.                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static GRenamedOperand *py_renameable_operand_build_wrapper(const GRenameableOperand *operand, const char *text)
+{
+    GRenamedOperand *result;                /* Instance à retourner        */
+    PyGILState_STATE gstate;                /* Sauvegarde d'environnement  */
+    PyObject *pyobj;                        /* Objet Python concerné       */
+    PyObject *args;                         /* Arguments pour l'appel      */
+    PyObject *pyret;                        /* Bilan de consultation       */
+    int ret;                                /* Bilan d'une conversion      */
+
+#define RENAMEABLE_OPERAND_BUILD_WRAPPER PYTHON_WRAPPER_DEF         \
+(                                                                   \
+    _build, "$self, text",                                          \
+    METH_VARARGS,                                                   \
+    "Abstract method used to build a new operand with an"           \
+    " alternative text as rendering."                               \
+    "\n"                                                            \
+    "The result of the call has to be an object implementing the"   \
+    " pychrysalide.arch.operands.RenamedOperand interface."         \
+)
+
+    result = NULL;
+
+    gstate = PyGILState_Ensure();
+
+    pyobj = pygobject_new(G_OBJECT(operand));
+
+    if (has_python_method(pyobj, "_build"))
+    {
+        args = PyTuple_New(1);
+        PyTuple_SetItem(args, 0, PyUnicode_FromString(text));
+
+        pyret = run_python_method(pyobj, "_build", args);
+
+        if (pyret != NULL)
+        {
+            ret = convert_to_renamed_operand(pyret, &result);
+
+            if (ret == 1)
+                g_object_ref(G_OBJECT(result));
+
+            Py_DECREF(pyret);
+
+            Py_DECREF(args);
+
+        }
+
+    }
+
+    Py_DECREF(pyobj);
+
+    PyGILState_Release(gstate);
+
+    return result;
+
+}
+
+
 
 /* ---------------------------------------------------------------------------------- */
 /*                         INTERFACE POUR OPERANDE RENOMMABLE                         */
@@ -249,6 +525,7 @@ static PyObject *py_renameable_operand_build(PyObject *self, PyObject *args)
 PyTypeObject *get_python_renameable_operand_type(void)
 {
     static PyMethodDef py_renameable_operand_methods[] = {
+        RENAMEABLE_OPERAND_BUILD_WRAPPER,
         RENAMEABLE_OPERAND_BUILD_METHOD,
         { NULL }
     };
@@ -296,6 +573,14 @@ bool ensure_python_renameable_operand_is_registered(void)
     PyObject *module;                       /* Module à recompléter        */
     PyObject *dict;                         /* Dictionnaire du module      */
 
+    static GInterfaceInfo info = {          /* Paramètres d'inscription    */
+
+        .interface_init = (GInterfaceInitFunc)py_renameable_operand_init,
+        .interface_finalize = NULL,
+        .interface_data = NULL,
+
+    };
+
     type = get_python_renameable_operand_type();
 
     if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
@@ -304,7 +589,7 @@ bool ensure_python_renameable_operand_is_registered(void)
 
         dict = PyModule_GetDict(module);
 
-        if (!register_interface_for_pygobject(dict, G_TYPE_RENAMEABLE_OPERAND, type))
+        if (!register_interface_for_pygobject_2(dict, G_TYPE_RENAMEABLE_OPERAND, type, &info))
             return false;
 
     }
@@ -312,3 +597,48 @@ bool ensure_python_renameable_operand_is_registered(void)
     return true;
 
 }
+
+
+/******************************************************************************
+*                                                                             *
+*  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 opérande renommable.                   *
+*                                                                             *
+*  Retour      : Bilan de l'opération, voire indications supplémentaires.     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+int convert_to_renameable_operand(PyObject *arg, void *dst)
+{
+    int result;                             /* Bilan à retourner           */
+
+    result = PyObject_IsInstance(arg, (PyObject *)get_python_renameable_operand_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 renameable operand");
+            break;
+
+        case 1:
+            *((GRenameableOperand **)dst) = G_RENAMEABLE_OPERAND(pygobject_get(arg));
+            break;
+
+        default:
+            assert(false);
+            break;
+
+    }
+
+    return result;
+
+}
diff --git a/plugins/pychrysalide/arch/operands/rename.h b/plugins/pychrysalide/arch/operands/rename.h
index a7f9233..6e81436 100644
--- a/plugins/pychrysalide/arch/operands/rename.h
+++ b/plugins/pychrysalide/arch/operands/rename.h
@@ -40,6 +40,9 @@ PyTypeObject *get_python_renamed_operand_type(void);
 /* Prend en charge l'objet 'pychrysalide.arch.RenamedOperand'. */
 bool ensure_python_renamed_operand_is_registered(void);
 
+/* Tente de convertir en opérande renommé. */
+int convert_to_renamed_operand(PyObject *, void *);
+
 
 
 /* ----------------------- INTERFACE POUR OPERANDE RENOMMABLE ----------------------- */
@@ -51,6 +54,9 @@ PyTypeObject *get_python_renameable_operand_type(void);
 /* Prend en charge l'objet 'pychrysalide.arch.RenameableOperand'. */
 bool ensure_python_renameable_operand_is_registered(void);
 
+/* Tente de convertir en opérande renommable. */
+int convert_to_renameable_operand(PyObject *, void *);
+
 
 
 #endif  /* _PLUGINS_PYCHRYSALIDE_ARCH_OPERANDS_RENAME_H */
diff --git a/plugins/pychrysalide/glibext/linegen.c b/plugins/pychrysalide/glibext/linegen.c
index 4d6d60d..9001b71 100644
--- a/plugins/pychrysalide/glibext/linegen.c
+++ b/plugins/pychrysalide/glibext/linegen.c
@@ -465,10 +465,10 @@ static void py_line_generator_print_wrapper(GLineGenerator *generator, GBufferLi
 
         pyret = run_python_method(pyobj, "_print", args);
 
-        Py_DECREF(args);
-
         Py_XDECREF(pyret);
 
+        Py_DECREF(args);
+
     }
 
     PyGILState_Release(gstate);
diff --git a/src/arch/operands/rename-int.h b/src/arch/operands/rename-int.h
index 28653b9..d0551d0 100644
--- a/src/arch/operands/rename-int.h
+++ b/src/arch/operands/rename-int.h
@@ -33,7 +33,7 @@
 
 
 /* Obtient l'adresse de la cible visée par un opérande. */
-typedef const char * (* get_renamed_text_fc) (const GRenamedOperand *);
+typedef char * (* get_renamed_text_fc) (const GRenamedOperand *);
 
 
 /* Opérande renommé avec un texte alternatif (interface) */
diff --git a/src/arch/operands/rename.c b/src/arch/operands/rename.c
index e865b63..f87c566 100644
--- a/src/arch/operands/rename.c
+++ b/src/arch/operands/rename.c
@@ -83,9 +83,9 @@ static void g_renamed_operand_default_init(GRenamedOperandInterface *iface)
 *                                                                             *
 ******************************************************************************/
 
-const char *g_renamed_operand_get_text(const GRenamedOperand *operand)
+char *g_renamed_operand_get_text(const GRenamedOperand *operand)
 {
-    const char *result;                     /* Texte à retourner           */
+    char *result;                           /* Texte à retourner           */
     GRenamedOperandIface *iface;            /* Interface utilisée          */
 
     iface = G_RENAMED_OPERAND_GET_IFACE(operand);
diff --git a/src/arch/operands/rename.h b/src/arch/operands/rename.h
index a6b99d7..31314ca 100644
--- a/src/arch/operands/rename.h
+++ b/src/arch/operands/rename.h
@@ -51,7 +51,7 @@ typedef struct _GRenamedOperandIface GRenamedOperandIface;
 GType g_renamed_operand_get_type(void) G_GNUC_CONST;
 
 /* Fournit un texte comme représentation alternative d'opérande. */
-const char *g_renamed_operand_get_text(const GRenamedOperand *);
+char *g_renamed_operand_get_text(const GRenamedOperand *);
 
 
 
-- 
cgit v0.11.2-87-g4458