From 2700e6892a0c0d78baf7228040aa07a1e21c6f53 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard 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 -#include +#include #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