From fcc78751e1e733b8662fde7d5e8ac6023cb34582 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Sat, 12 Aug 2017 17:08:53 +0200
Subject: Fixed many mistakes in the Python bindings.

---
 ChangeLog                                |  11 +++
 plugins/pychrysa/glibext/configuration.c |   3 -
 plugins/pychrysa/gtkext/blockdisplay.c   |  19 ++--
 plugins/pychrysa/gtkext/bufferdisplay.c  |  19 ++--
 plugins/pychrysa/gtkext/displaypanel.c   |  14 +--
 plugins/pychrysa/helpers.c               | 152 ++++++++++++++++++++++++++++++-
 plugins/pychrysa/helpers.h               |  10 ++
 plugins/pychrysa/pychrysa.c              |  35 ++-----
 8 files changed, 200 insertions(+), 63 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 4981236..9cc2a11 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+17-08-12  Cyrille Bagard <nocbos@gmail.com>
+
+	* plugins/pychrysa/glibext/configuration.c:
+	* plugins/pychrysa/gtkext/blockdisplay.c:
+	* plugins/pychrysa/gtkext/bufferdisplay.c:
+	* plugins/pychrysa/gtkext/displaypanel.c:
+	* plugins/pychrysa/helpers.c:
+	* plugins/pychrysa/helpers.h:
+	* plugins/pychrysa/pychrysa.c:
+	Fix many mistakes in the Python bindings.
+
 17-08-07  Cyrille Bagard <nocbos@gmail.com>
 
 	* plugins/pychrysa/arch/processor.c:
diff --git a/plugins/pychrysa/glibext/configuration.c b/plugins/pychrysa/glibext/configuration.c
index 58eafb3..3ced957 100644
--- a/plugins/pychrysa/glibext/configuration.c
+++ b/plugins/pychrysa/glibext/configuration.c
@@ -1155,9 +1155,6 @@ bool register_python_generic_config(PyObject *module)
 
     py_generic_config_type = get_python_generic_config_type();
 
-    if (PyType_Ready(py_generic_config_type) != 0)
-        return false;
-
     dict = PyModule_GetDict(module);
 
     if (!register_class_for_pygobject(dict, G_TYPE_GEN_CONFIG, py_generic_config_type, &PyGObject_Type))
diff --git a/plugins/pychrysa/gtkext/blockdisplay.c b/plugins/pychrysa/gtkext/blockdisplay.c
index a329daf..c2ccfbb 100644
--- a/plugins/pychrysa/gtkext/blockdisplay.c
+++ b/plugins/pychrysa/gtkext/blockdisplay.c
@@ -66,7 +66,7 @@ PyTypeObject *get_python_block_display_type(void)
         .tp_name        = "pychrysalide.gtkext.BlockDisplay",
         .tp_basicsize   = sizeof(PyGObject),
 
-        .tp_flags       = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE,
+        .tp_flags       = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
 
         .tp_doc         = "PyChrysalide block display.",
 
@@ -78,12 +78,7 @@ PyTypeObject *get_python_block_display_type(void)
     static PyTypeObject *result = NULL;
 
     if (result == NULL)
-    {
-        result = calloc(1, sizeof(PyTypeObject));
-
-        memcpy(result, &py_block_display_type, sizeof(PyTypeObject));
-
-    }
+        result = define_python_dynamic_type(&py_block_display_type);
 
     return result;
 
@@ -104,17 +99,17 @@ PyTypeObject *get_python_block_display_type(void)
 
 bool register_python_block_display(PyObject *module)
 {
-    PyTypeObject *py_block_display_type;    /* Type Python 'BlockDisplay'     */
+    bool result;                            /* Bilan à retourner           */
+    PyTypeObject *py_block_display_type;    /* Type Python 'BlockDisplay'  */
     PyObject *dict;                         /* Dictionnaire du module      */
 
     py_block_display_type = get_python_block_display_type();
 
     dict = PyModule_GetDict(module);
 
-    if (!register_class_for_pygobject(dict, GTK_TYPE_BLOCK_DISPLAY,
-                                      py_block_display_type, get_python_buffer_display_type()))
-        return false;
+    result = register_class_for_pygobject(dict, GTK_TYPE_BLOCK_DISPLAY,
+                                          py_block_display_type, get_python_buffer_display_type());
 
-    return true;
+    return result;
 
 }
diff --git a/plugins/pychrysa/gtkext/bufferdisplay.c b/plugins/pychrysa/gtkext/bufferdisplay.c
index a6e5327..9aa1bca 100644
--- a/plugins/pychrysa/gtkext/bufferdisplay.c
+++ b/plugins/pychrysa/gtkext/bufferdisplay.c
@@ -66,7 +66,7 @@ PyTypeObject *get_python_buffer_display_type(void)
         .tp_name        = "pychrysalide.gtkext.BufferDisplay",
         .tp_basicsize   = sizeof(PyGObject),
 
-        .tp_flags       = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE,
+        .tp_flags       = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
 
         .tp_doc         = "PyChrysalide buffer display.",
 
@@ -78,12 +78,7 @@ PyTypeObject *get_python_buffer_display_type(void)
     static PyTypeObject *result = NULL;
 
     if (result == NULL)
-    {
-        result = calloc(1, sizeof(PyTypeObject));
-
-        memcpy(result, &py_buffer_display_type, sizeof(PyTypeObject));
-
-    }
+        result = define_python_dynamic_type(&py_buffer_display_type);
 
     return result;
 
@@ -104,17 +99,17 @@ PyTypeObject *get_python_buffer_display_type(void)
 
 bool register_python_buffer_display(PyObject *module)
 {
-    PyTypeObject *py_buffer_display_type;   /* Type Python 'Bufferdisplay'    */
+    bool result;                            /* Bilan à retourner           */
+    PyTypeObject *py_buffer_display_type;   /* Type Python 'BufferDisplay' */
     PyObject *dict;                         /* Dictionnaire du module      */
 
     py_buffer_display_type = get_python_buffer_display_type();
 
     dict = PyModule_GetDict(module);
 
-    if (!register_class_for_pygobject(dict, GTK_TYPE_BUFFER_DISPLAY,
-                                      py_buffer_display_type, get_python_display_panel_type()))
-        return false;
+    result = register_class_for_pygobject(dict, GTK_TYPE_BUFFER_DISPLAY,
+                                          py_buffer_display_type, get_python_display_panel_type());
 
-    return true;
+    return result;
 
 }
diff --git a/plugins/pychrysa/gtkext/displaypanel.c b/plugins/pychrysa/gtkext/displaypanel.c
index e857475..aa166e5 100644
--- a/plugins/pychrysa/gtkext/displaypanel.c
+++ b/plugins/pychrysa/gtkext/displaypanel.c
@@ -197,7 +197,7 @@ PyTypeObject *get_python_display_panel_type(void)
         .tp_name        = "pychrysalide.gtkext.DisplayPanel",
         .tp_basicsize   = sizeof(PyGObject),
 
-        .tp_flags       = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE,
+        .tp_flags       = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
 
         .tp_doc         = "PyChrysalide view panel.",
 
@@ -211,12 +211,7 @@ PyTypeObject *get_python_display_panel_type(void)
     static PyTypeObject *result = NULL;
 
     if (result == NULL)
-    {
-        result = calloc(1, sizeof(PyTypeObject));
-
-        memcpy(result, &py_display_panel_type, sizeof(PyTypeObject));
-
-    }
+        result = define_python_dynamic_type(&py_display_panel_type);
 
     return result;
 
@@ -248,7 +243,9 @@ bool register_python_display_panel(PyObject *module)
     py_display_panel_type = get_python_display_panel_type();
 
     parent_mod = PyImport_ImportModule("gi.repository.Gtk");
-    if (parent_mod == NULL) return false;
+
+    if (parent_mod == NULL)
+        goto rpdp_exit;
 
     fixed = PyObject_GetAttrString(parent_mod, "Fixed");
 
@@ -258,7 +255,6 @@ bool register_python_display_panel(PyObject *module)
 
     result = register_class_for_pygobject(dict, GTK_TYPE_DISPLAY_PANEL,
                                           py_display_panel_type, (PyTypeObject *)fixed);
-
     Py_DECREF(fixed);
 
     if (!result)
diff --git a/plugins/pychrysa/helpers.c b/plugins/pychrysa/helpers.c
index a0a828f..17a396d 100644
--- a/plugins/pychrysa/helpers.c
+++ b/plugins/pychrysa/helpers.c
@@ -27,9 +27,15 @@
 #include <assert.h>
 #include <pygobject.h>
 #include <stdarg.h>
+#include <string.h>
 
 
 
+/* ---------------------------------------------------------------------------------- */
+/*                        ACCELERATEURS POUR PYTHON UNIQUEMENT                        */
+/* ---------------------------------------------------------------------------------- */
+
+
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : status = bilan de comparaison à traduire.                    *
@@ -242,6 +248,126 @@ bool PyDict_AddStringConstant(PyTypeObject *obj_type, const char *key, const cha
 }
 
 
+
+/* ---------------------------------------------------------------------------------- */
+/*                             CONFORTS CIBLANT PYGOBJECT                             */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : spec = définition à mettre en place dynamiquement.           *
+*                                                                             *
+*  Description : Définit dans le tas de Python un nouveau type.               *
+*                                                                             *
+*  Retour      : Nouveau type prêt à emploi.                                  *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+PyTypeObject *define_python_dynamic_type(const PyTypeObject *spec)
+{
+    PyTypeObject *result;                   /* Définition créée à renvoyer */
+    PyTypeObject *type;                     /* Type de tous les types      */
+    size_t size;                            /* Taille de la définition     */
+    char *s;                                /* Marqueur de début de chaîne */
+    PyHeapTypeObject *hobj;                 /* Version réelle du type créé */
+
+    /**
+     * Le cahier des charges est ici d'éviter les erreurs suivantes :
+     *
+     *    TypeError: type 'XXX' is not dynamically allocated but its base type 'YYY' is dynamically allocated
+     *    Fatal Python error: unexpected exception during garbage collection
+     *
+     * L'allocation dynamique est marquée par le fanion Py_TPFLAGS_HEAPTYPE.
+     *
+     * Une des rares fonctions qui appliquent ce fanion est PyType_FromSpecWithBases(),
+     * mais elle appelle ensuite PyType_Ready(), ce qui est incompatible avec des modifications
+     * utltérieures avant un appel à pygobject_register_class().
+     *
+     * Le code suivant s'inspire fortement des méthodes originales de Python,
+     * dont les mécanismes employés par PyType_GenericAlloc().
+     */
+
+    type = &PyType_Type;
+    size = _PyObject_SIZE(type);
+
+    if (PyType_IS_GC(type))
+        result = (PyTypeObject *)_PyObject_GC_Malloc(size);
+    else
+        result = (PyTypeObject *)PyObject_MALLOC(size);
+
+    if (type->tp_flags & Py_TPFLAGS_HEAPTYPE)
+        Py_INCREF(type);
+
+    /* Définitions sommaires */
+
+    memset(result, 0, sizeof(PyHeapTypeObject));
+
+    memcpy(result, spec, sizeof(PyTypeObject));
+
+    result->tp_flags |= Py_TPFLAGS_HEAPTYPE;
+
+    /* Définitions des noms */
+
+    /**
+     * Pour un type dynamique, les désignations ne s'appuient pas sur la partie réservée
+     * au type, mais sur les données suivantes (cf. type_name() et type_qualname()).
+     *
+     * Les deux fonctions désignées sont par ailleurs facilement accessibles :
+     *
+     *    #0  0x0000555555689bf0 in type_qualname (...) at Objects/typeobject.c:393
+     *    #1  0x000055555568b3b4 in type_repr (...) at Objects/typeobject.c:855
+     *    #2  0x0000555555693574 in object_str (...) at Objects/typeobject.c:3511
+     *    #3  0x0000555555670d02 in PyObject_Str (...) at Objects/object.c:535
+     *    ...
+     *
+     * On s'inspire donc du contenu de PyType_FromSpecWithBases() pour éviter tout
+     * plantage du fait de données non initialisées.
+     */
+
+    hobj = (PyHeapTypeObject *)result;
+
+    s = strrchr(spec->tp_name, '.');
+
+    if (s == NULL)
+        s = (char *)spec->tp_name;
+    else
+        s++;
+
+    hobj->ht_name = PyUnicode_FromString(s);
+    assert(hobj->ht_name != NULL);
+
+    hobj->ht_qualname = hobj->ht_name;
+    Py_INCREF(hobj->ht_qualname);
+
+    result->tp_as_async = &hobj->as_async;
+    result->tp_as_number = &hobj->as_number;
+    result->tp_as_sequence = &hobj->as_sequence;
+    result->tp_as_mapping = &hobj->as_mapping;
+    result->tp_as_buffer = &hobj->as_buffer;
+
+    hobj->ht_cached_keys = _PyDict_NewKeysForClass();
+
+
+
+
+#if 0
+    if (type->tp_itemsize == 0)
+        (void)PyObject_INIT(result, type);
+    else
+        (void) PyObject_INIT_VAR((PyVarObject *)result, type, 0);
+
+    if (PyType_IS_GC(type))
+        _PyObject_GC_TRACK(result);
+#endif
+
+    return result;
+
+}
+
+
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : module = module où conserver une référence au type créé.     *
@@ -259,6 +385,7 @@ bool PyDict_AddStringConstant(PyTypeObject *obj_type, const char *key, const cha
 
 bool _register_class_for_pygobject(PyObject *dict, GType gtype, PyTypeObject *type, PyTypeObject *base, ...)
 {
+    bool result;                            /* Bilan à retourner           */
     Py_ssize_t size;                        /* Taille de liste actuelle    */
     PyObject *static_bases;                 /* Base(s) de l'objet          */
     va_list ap;                             /* Parcours des arguments      */
@@ -314,10 +441,33 @@ bool _register_class_for_pygobject(PyObject *dict, GType gtype, PyTypeObject *ty
 
     va_end(ap);
 
+
+
+    /*
+#0  0x000055555565aad4 in insertdict (mp=0x7fffe7c2c8a8, key='GenConfig', hash=262970853803706525, value=<unknown at remote 0x7ffff6bd9ce0>) at ../Objects/dictobject.c:801
+#1  0x000055555565bf62 in PyDict_SetItem (op={'__doc__': 'Python module for Chrysalide.glibext', '__name__': 'pychrysalide.glibext', 'BufferLine': <type at remote 0x7ffff6bd9760>, '__spec__': None, 'ConfigParam': <type at remote 0x7ffff6bd9a00>, '__package__': None, 'Buffercache': <type at remote 0x7ffff6bd95c0>, 'ConfigParamIterator': <type at remote 0x7ffff6bd9fc0>, '__loader__': None}, key='GenConfig', value=<unknown at remote 0x7ffff6bd9ce0>) at ../Objects/dictobject.c:1227
+#2  0x00005555556610b0 in PyDict_SetItemString (v={'__doc__': 'Python module for Chrysalide.glibext', '__name__': 'pychrysalide.glibext', 'BufferLine': <type at remote 0x7ffff6bd9760>, '__spec__': None, 'ConfigParam': <type at remote 0x7ffff6bd9a00>, '__package__': None, 'Buffercache': <type at remote 0x7ffff6bd95c0>, 'ConfigParamIterator': <type at remote 0x7ffff6bd9fc0>, '__loader__': None}, key=0x7ffff69cd0bd "GenConfig", item=<unknown at remote 0x7ffff6bd9ce0>) at ../Objects/dictobject.c:2870
+#3  0x00007ffff69b3d12 in _register_class_for_pygobject (dict={'__doc__': 'Python module for Chrysalide.glibext', '__name__': 'pychrysalide.glibext', 'BufferLine': <type at remote 0x7ffff6bd9760>, '__spec__': None, 'ConfigParam': <type at remote 0x7ffff6bd9a00>, '__package__': None, 'Buffercache': <type at remote 0x7ffff6bd95c0>, 'ConfigParamIterator': <type at remote 0x7ffff6bd9fc0>, '__loader__': None}, gtype=93824998785328, type=0x7ffff6bd9ce0 <py_generic_config_type>, base=0x7fffe80e72a0 <PyGObject_Type>) at helpers.c:320
+    */
+
+
+
+    //type->tp_weaklistoffset = offsetof(PyGObject, weakreflist);
+    //type->tp_dictoffset = offsetof(PyGObject, inst_dict);
+
     pygobject_register_class(dict, NULL, gtype, type, static_bases);
 
+    if (PyErr_Occurred() == NULL)
+        result = true;
+
+    else
+    {
+        PyErr_Print();
+        result = false;
+    }
+
     assert(PyErr_Occurred() == NULL);
 
-    return true;
+    return result;
 
 }
diff --git a/plugins/pychrysa/helpers.h b/plugins/pychrysa/helpers.h
index 9fb83d0..3eee6a0 100644
--- a/plugins/pychrysa/helpers.h
+++ b/plugins/pychrysa/helpers.h
@@ -31,6 +31,9 @@
 
 
 
+/* ---------------------- ACCELERATEURS POUR PYTHON UNIQUEMENT ---------------------- */
+
+
 /* Traduit pour Python le bilan d'une comparaison riche. */
 PyObject *status_to_rich_cmp_state(int, int);
 
@@ -54,6 +57,10 @@ bool PyDict_AddStringConstant(PyTypeObject *, const char *, const char *);
 #define PyDict_AddStringMacro(tp, c) PyDict_AddStringConstant(tp, #c, c)
 
 
+
+/* --------------------------- CONFORTS CIBLANT PYGOBJECT --------------------------- */
+
+
 /**
  * Quelque chose est mal fait au niveau de l'abstraction GObject.
  * Du coup, Py_TPFLAGS_IS_ABSTRACT n'est pas pris en compte.
@@ -64,6 +71,9 @@ bool PyDict_AddStringConstant(PyTypeObject *, const char *, const char *);
 #define APPLY_ABSTRACT_FLAG(tp) tp->tp_new = PyBaseObject_Type.tp_new
 
 
+/* Définit dans le tas de Python un nouveau type. */
+PyTypeObject *define_python_dynamic_type(const PyTypeObject *);
+
 /* Enregistre correctement une surcouche de conversion GObject. */
 bool _register_class_for_pygobject(PyObject *, GType, PyTypeObject *, PyTypeObject *, ...);
 
diff --git a/plugins/pychrysa/pychrysa.c b/plugins/pychrysa/pychrysa.c
index f959671..bcd2284 100644
--- a/plugins/pychrysa/pychrysa.c
+++ b/plugins/pychrysa/pychrysa.c
@@ -332,7 +332,6 @@ static bool set_version_for_gtk_namespace(const char *version)
 PyMODINIT_FUNC PyInit_pychrysalide(void)
 {
     PyObject *result;                       /* Module Python à retourner   */
-    PyObject *pygobj_mod;                   /* Module Python-GObject       */
     bool status;                            /* Bilan des inclusions        */
 
     static PyMethodDef py_chrysalide_methods[] = {
@@ -370,8 +369,6 @@ PyMODINIT_FUNC PyInit_pychrysalide(void)
 
     };
 
-
-
 #if 0
     do
     {
@@ -425,20 +422,6 @@ PyMODINIT_FUNC PyInit_pychrysalide(void)
         return NULL;
     }
 
-    /* Préparatifs préalables aux chargements */
-
-    /**
-     * Pour une raison non identifiée, si le module n'est pas préchargé,
-     * le flot d'exécution plante dans la fonction insertdict() de Objects/dictobject.c:818.
-     */
-
-    pygobj_mod = PyImport_ImportModule("gi.repository.GObject");
-    if (pygobj_mod == NULL)
-    {
-        PyErr_SetString(PyExc_ImportError, "could not import gi.gobject");
-        return NULL;
-    }
-
     /* Mise en place des fonctionnalités offertes */
 
     result = PyModule_Create(&py_chrysalide_module);
@@ -446,15 +429,15 @@ PyMODINIT_FUNC PyInit_pychrysalide(void)
     /* Interface 'LineGenerator' en premier... */
     status = add_glibext_module_to_python_module(result);
 
-    status &= register_python_plugin_module(result);
-    status &= add_analysis_module_to_python_module(result);
-    status &= add_arch_module_to_python_module(result);
-    status &= add_common_module_to_python_module(result);
-    status &= add_core_module_to_python_module(result);
-    status &= add_debug_module_to_python_module(result);
-    status &= add_format_module_to_python_module(result);
-    status &= add_gtkext_module_to_python_module(result);
-    status &= add_gui_module_to_python_module(result);
+    if (status) status = register_python_plugin_module(result);
+    if (status) status = add_analysis_module_to_python_module(result);
+    if (status) status = add_arch_module_to_python_module(result);
+    if (status) status = add_common_module_to_python_module(result);
+    if (status) status = add_core_module_to_python_module(result);
+    if (status) status = add_debug_module_to_python_module(result);
+    if (status) status = add_format_module_to_python_module(result);
+    if (status) status = add_gtkext_module_to_python_module(result);
+    if (status) status = add_gui_module_to_python_module(result);
 
     if (!status)
     {
-- 
cgit v0.11.2-87-g4458