/* Chrysalide - Outil d'analyse de fichiers binaires * configuration.c - prototypes pour l'équivalent Python du fichier "glibext/configuration.c" * * Copyright (C) 2018-2019 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 "configuration.h" #include #include #include #include "constants.h" #include "../access.h" #include "../helpers.h" /* ---------------------------- ELEMENT DE CONFIGURATION ---------------------------- */ /* Crée un nouvel objet Python de type 'ConfigParam'. */ static PyObject *py_config_param_new(PyTypeObject *, PyObject *, PyObject *); /* Initialise une instance sur la base du dérivé de GObject. */ static int py_config_param_init(PyObject *, PyObject *, PyObject *); /* Efface toute valeur courante d'un paramètre de configuration. */ static PyObject *py_config_param_make_empty(PyObject *, PyObject *); /* Réinitialise la valeur d'un paramètre de configuration. */ static PyObject *py_config_param_reset(PyObject *, PyObject *); /* Indique le chemin d'accès utilisé pour un paramètre. */ static PyObject *py_config_param_get_path(PyObject *, void *); /* Indique le type de valeur utilisée par un paramètre. */ static PyObject *py_config_param_get_type(PyObject *, void *); /* Indique le statut d'une valeur utilisée par un paramètre. */ static PyObject *py_config_param_get_state(PyObject *, void *); /* Indique la valeur courante d'un paramètre de configuration. */ static PyObject *py_config_param_get_value(PyObject *, void *); /* Modifie la valeur courante d'un paramètre de configuration. */ static int py_config_param_set_value(PyObject *, PyObject *, void *); /* ----------------------------- PARCOURS DE PARAMETRES ----------------------------- */ /* Parcours des éléments de configuration */ typedef struct _pyConfigParamIterator { PyObject_HEAD /* A laisser en premier */ GGenConfig *config; /* Configuration à parcourir */ GList *params; /* Liste de paramètres */ GList *last; /* Dernier élément retourné */ } pyConfigParamIterator; /* Prend acte d'un compteur de référence à 0. */ static void py_config_param_iterator_dealloc(PyObject *); /* Fournit un itérateur pour paramètres de configuration. */ static PyObject *py_config_param_iterator_next(PyObject *); /* Initialise un objet Python de type 'ConfigParamIterator'. */ static int py_config_param_iterator_init(PyObject *, PyObject *, PyObject *); /* ----------------------- GESTION GENERIQUE DE CONFIGURATION ----------------------- */ /* Accompagne la création d'une instance dérivée en Python. */ static PyObject *py_generic_config_new(PyTypeObject *, PyObject *, PyObject *); /* Initialise une instance sur la base du dérivé de GObject. */ static int py_generic_config_init(PyObject *, PyObject *, PyObject *); /* Met à disposition un encadrement des accès aux paramètres. */ static PyObject *py_generic_config_lock_unlock(PyObject *, PyObject *); /* Lit la configuration depuis un fichier. */ static PyObject *py_generic_config_read(PyObject *, PyObject *); /* Ecrit la configuration dans un fichier. */ static PyObject *py_generic_config_write(PyObject *, PyObject *); /* Retrouve un élément de configuration par son chemin. */ static PyObject *py_generic_config_search(PyObject *, PyObject *); /* Ajoute un paramètre à une configuration. */ static PyObject *py_generic_config_add(PyObject *, PyObject *); /* Retire un paramètre d'une configuration. */ static PyObject *py_generic_config_delete(PyObject *, PyObject *); /* Indique le fichier utilisé pour l'enregistrement XML. */ static PyObject *py_generic_config_get_filename(PyObject *, void *); /* Renvoie la liste des paramètres de configuration. */ static PyObject *py_generic_config_get_params(PyObject *, void *); /* ---------------------------------------------------------------------------------- */ /* ELEMENT DE CONFIGURATION */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : type = type du nouvel objet à mettre en place. * * args = éventuelle liste d'arguments. * * kwds = éventuel dictionnaire de valeurs mises à disposition. * * * * Description : Accompagne la création d'une instance dérivée en Python. * * * * Retour : Nouvel objet Python mis en place ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ static PyObject *py_config_param_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { PyObject *result; /* Objet à retourner */ PyTypeObject *base; /* Type de base à dériver */ bool first_time; /* Evite les multiples passages*/ GType gtype; /* Nouveau type de processeur */ bool status; /* Bilan d'un enregistrement */ /* Validations diverses */ base = get_python_config_param_type(); if (type == base) goto simple_way; /* Mise en place d'un type dédié */ first_time = (g_type_from_name(type->tp_name) == 0); gtype = build_dynamic_type(G_TYPE_CFG_PARAM, type->tp_name, NULL, NULL, NULL); if (first_time) { status = register_class_for_dynamic_pygobject(gtype, type, base); if (!status) { result = NULL; goto exit; } } /* On crée, et on laisse ensuite la main à PyGObject_Type.tp_init() */ simple_way: result = PyType_GenericNew(type, args, kwds); exit: return result; } /****************************************************************************** * * * Paramètres : self = objet à initialiser (théoriquement). * * args = arguments fournis à l'appel. * * kwds = arguments de type key=val fournis. * * * * Description : Initialise une instance sur la base du dérivé de GObject. * * * * Retour : 0. * * * * Remarques : - * * * ******************************************************************************/ static int py_config_param_init(PyObject *self, PyObject *args, PyObject *kwds) { const char *path; /* Accès au paramètre */ ConfigParamType ptype; /* Type de paramètre */ PyObject *py_value; /* Valeur par défaut éventuelle*/ int ret; /* Bilan de lecture des args. */ bool valid; /* Validité des transmissions */ param_value value; /* Valeur de paramètre */ GCfgParam *param; /* Paramètre mis en place */ #define CONFIG_PARAM_DOC \ "ConfigParam holds a configuration parameter with its default and current" \ " values.\n" \ "\n" \ "Parameters are aimed to join a pychrysalide.glibext.GenConfig instance.\n" \ "\n" \ "Instances can be created using the following constructor:\n" \ "\n" \ " ConfigParam(path, type, value=None)" \ "\n" \ "Where *path* is dot separated string items serving as a parameter key," \ " *type* is a pychrysalide.glibext.ConfigParam.ConfigParamType value and" \ " *value* is an optional default value if the parameter initial value" \ " has not to be empty." /* Récupération des paramètres */ py_value = NULL; ret = PyArg_ParseTuple(args, "sO&|O", &path, convert_to_config_param_type, &ptype, &py_value); if (!ret) return -1; if (py_value != NULL && py_value != Py_None) { switch (ptype) { case CPT_BOOLEAN: valid = PyBool_Check(py_value); if (valid) value.boolean = (bool)(py_value == Py_True); break; case CPT_INTEGER: valid = PyLong_Check(py_value); if (valid) value.integer = (int)PyLong_AsLong(py_value); break; case CPT_ULONG: valid = PyLong_Check(py_value); if (valid) value.ulong = (unsigned long)PyLong_AsUnsignedLong(py_value); break; case CPT_STRING: valid = PyUnicode_Check(py_value); if (valid) value.string = PyUnicode_DATA(py_value); break; case CPT_COLOR: valid = (convert_to_gdk_rgba(py_value, &value.color) == 1); break; default: assert(false); valid = false; break; } if (!valid) { PyErr_SetString(PyExc_TypeError, "invalid value for the specified parameter type"); return -1; } } /* Initialisation d'un objet GLib */ ret = forward_pygobjet_init(self); if (ret == -1) return -1; /* Eléments de base */ param = G_CFG_PARAM(pygobject_get(self)); if (py_value == NULL || py_value == Py_None) g_config_param_build_empty(param, path, ptype); else g_config_param_build(param, path, ptype, &value); return 0; } /****************************************************************************** * * * Paramètres : self = paramètre de configuration à manipuler. * * args = non utilisé ici. * * * * Description : Efface toute valeur courante d'un paramètre de configuration.* * * * Retour : None. * * * * Remarques : - * * * ******************************************************************************/ static PyObject *py_config_param_make_empty(PyObject *self, PyObject *args) { GCfgParam *param; /* Paramètre visé par l'opérat°*/ #define CONFIG_PARAM_MAKE_EMPTY_METHOD PYTHON_METHOD_DEF \ ( \ make_empty, "$self, /", \ METH_NOARGS, py_config_param, \ "Unset the value of the current parameter." \ ) param = G_CFG_PARAM(pygobject_get(self)); g_config_param_make_empty(param); Py_RETURN_NONE; } /****************************************************************************** * * * Paramètres : self = paramètre de configuration à manipuler. * * args = non utilisé ici. * * * * Description : Réinitialise la valeur d'un paramètre de configuration. * * * * Retour : None. * * * * Remarques : - * * * ******************************************************************************/ static PyObject *py_config_param_reset(PyObject *self, PyObject *args) { GCfgParam *param; /* Paramètre visé par l'opérat°*/ #define CONFIG_PARAM_RESET_METHOD PYTHON_METHOD_DEF \ ( \ reset, "$self, /", \ METH_NOARGS, py_config_param, \ "Reset the content of the current parameter." \ ) param = G_CFG_PARAM(pygobject_get(self)); g_config_param_reset(param); Py_RETURN_NONE; } /****************************************************************************** * * * Paramètres : self = paramètre de configuration à manipuler. * * closure = non utilisé ici. * * * * Description : Indique le chemin d'accès utilisé pour un paramètre. * * * * Retour : Chemin d'accès en Python. * * * * Remarques : - * * * ******************************************************************************/ static PyObject *py_config_param_get_path(PyObject *self, void *closure) { GCfgParam *param; /* Paramètre visé par l'opérat°*/ const char *path; /* Chemin d'accès à diffuser */ #define CONFIG_PARAM_PATH_ATTRIB PYTHON_GET_DEF_FULL \ ( \ path, py_config_param, \ "Dot separated string items used as key for a" \ " configuration parameter." \ ) param = G_CFG_PARAM(pygobject_get(self)); path = g_config_param_get_path(param); return PyUnicode_FromString(path); } /****************************************************************************** * * * Paramètres : self = paramètre de configuration à manipuler. * * closure = non utilisé ici. * * * * Description : Indique le type de valeur utilisée par un paramètre. * * * * Retour : Type en Python. * * * * Remarques : - * * * ******************************************************************************/ static PyObject *py_config_param_get_type(PyObject *self, void *closure) { PyObject *result; /* Type de paramètre à renvoyer*/ GCfgParam *param; /* Paramètre visé par l'opérat°*/ ConfigParamType type; /* Type de paramètre */ #define CONFIG_PARAM_TYPE_ATTRIB PYTHON_GET_DEF_FULL \ ( \ type, py_config_param, \ "Type of value provided by a configuration parameter.\n" \ "\n" \ "The attribute carries a" \ " pychrysalide.glibext.ConfigParam.ConfigParamType value." \ ) param = G_CFG_PARAM(pygobject_get(self)); type = g_config_param_get_ptype(param); result = cast_with_constants_group_from_type(get_python_config_param_type(), "ConfigParamType", type); return result; } /****************************************************************************** * * * Paramètres : self = paramètre de configuration à manipuler. * * closure = non utilisé ici. * * * * Description : Indique le statut d'une valeur utilisée par un paramètre. * * * * Retour : Etat en Python. * * * * Remarques : - * * * ******************************************************************************/ static PyObject *py_config_param_get_state(PyObject *self, void *closure) { PyObject *result; /* Etat à retourner */ GCfgParam *param; /* Paramètre visé par l'opérat°*/ ConfigParamState state; /* Statut de paramètre */ #define CONFIG_PARAM_STATE_ATTRIB PYTHON_GET_DEF_FULL \ ( \ state, py_config_param, \ "State of a configuration parameter.\n" \ "\n" \ "The attribute carries a" \ " pychrysalide.glibext.ConfigParam.ConfigParamState value." \ ) param = G_CFG_PARAM(pygobject_get(self)); state = g_config_param_get_state(param); result = cast_with_constants_group_from_type(get_python_config_param_type(), "ConfigParamState", state); return result; } /****************************************************************************** * * * Paramètres : self = paramètre de configuration à manipuler. * * closure = non utilisé ici. * * * * Description : Indique la valeur courante d'un paramètre de configuration. * * * * Retour : Etat en Python. * * * * Remarques : - * * * ******************************************************************************/ static PyObject *py_config_param_get_value(PyObject *self, void *closure) { PyObject *result; /* Valeur à retourner */ GCfgParam *param; /* Paramètre visé par l'opérat°*/ ConfigParamType type; /* Type de paramètre manipulé */ param_value value; /* Valeur de paramètre */ #define CONFIG_PARAM_VALUE_ATTRIB PYTHON_GETSET_DEF_FULL \ ( \ value, py_config_param, \ "Value of a configuration parameter.\n" \ "\n" \ "The type of the value carried by the attribute depends on" \ " pychrysalide.glibext.ConfigParam.type value." \ ) param = G_CFG_PARAM(pygobject_get(self)); type = g_config_param_get_ptype(param); g_config_param_get_value(param, &value); switch (type) { case CPT_BOOLEAN: result = (value.boolean ? Py_True : Py_False); Py_INCREF(result); break; case CPT_INTEGER: result = PyLong_FromLong(value.integer); break; case CPT_ULONG: result = PyLong_FromUnsignedLong(value.ulong); break; case CPT_STRING: if (value.string != NULL) result = PyUnicode_FromString(value.string); else { result = Py_None; Py_INCREF(result); } break; case CPT_COLOR: result = create_gdk_rgba(&value.color); break; default: result = NULL; break; } return result; } /****************************************************************************** * * * Paramètres : self = paramètre de configuration à manipuler. * * value = nouvelle valeur à convertir et définir. * * closure = non utilisé ici. * * * * Description : Modifie la valeur courante d'un paramètre de configuration. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ static int py_config_param_set_value(PyObject *self, PyObject *value, void *closure) { int result; /* Conclusion à remonter */ GCfgParam *param; /* Paramètre visé par l'opérat°*/ ConfigParamType type; /* Type de paramètre manipulé */ param_value pvalue; /* Valeur de paramètre */ result = -1; param = G_CFG_PARAM(pygobject_get(self)); if (value == Py_None) { g_config_param_make_empty(param); result = 0; } else { type = g_config_param_get_ptype(param); switch (type) { case CPT_BOOLEAN: if (PyBool_Check(value)) { pvalue.integer = (value == Py_True); g_config_param_set_value(param, pvalue.integer); result = 0; } break; case CPT_INTEGER: if (PyLong_Check(value)) { pvalue.integer = PyLong_AsLong(value); g_config_param_set_value(param, pvalue.integer); result = 0; } break; case CPT_ULONG: if (PyLong_Check(value)) { pvalue.ulong = PyLong_AsUnsignedLong(value); g_config_param_set_value(param, pvalue.ulong); result = 0; } break; case CPT_STRING: if (PyUnicode_Check(value)) { pvalue.string = PyUnicode_DATA(value); g_config_param_set_value(param, pvalue.string); result = 0; } break; case CPT_COLOR: if (convert_to_gdk_rgba(value, &pvalue.color) == 1) { g_config_param_set_value(param, &pvalue.color); result = 0; } break; default: assert(false); break; } } return result; } /****************************************************************************** * * * Paramètres : - * * * * Description : Fournit un accès à une définition de type à diffuser. * * * * Retour : Définition d'objet pour Python. * * * * Remarques : - * * * ******************************************************************************/ PyTypeObject *get_python_config_param_type(void) { static PyMethodDef py_config_param_methods[] = { CONFIG_PARAM_MAKE_EMPTY_METHOD, CONFIG_PARAM_RESET_METHOD, { NULL } }; static PyGetSetDef py_config_param_getseters[] = { CONFIG_PARAM_PATH_ATTRIB, CONFIG_PARAM_TYPE_ATTRIB, CONFIG_PARAM_STATE_ATTRIB, CONFIG_PARAM_VALUE_ATTRIB, CONFIG_PARAM_VALUE_ATTRIB, { NULL } }; static PyTypeObject py_config_param_type = { PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "pychrysalide.glibext.ConfigParam", .tp_basicsize = sizeof(PyGObject), .tp_flags = Py_TPFLAGS_DEFAULT, .tp_doc = CONFIG_PARAM_DOC, .tp_methods = py_config_param_methods, .tp_getset = py_config_param_getseters, .tp_init = py_config_param_init, .tp_new = py_config_param_new }; return &py_config_param_type; } /****************************************************************************** * * * Paramètres : module = module dont la définition est à compléter. * * * * Description : Prend en charge l'objet 'pychrysalide.glibext.ConfigParam'. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool ensure_python_config_param_is_registered(void) { PyTypeObject *type; /* Type Python 'ConfigParam' */ PyObject *module; /* Module à recompléter */ PyObject *dict; /* Dictionnaire du module */ type = get_python_config_param_type(); if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) { module = get_access_to_python_module("pychrysalide.glibext"); dict = PyModule_GetDict(module); if (!register_class_for_pygobject(dict, G_TYPE_CFG_PARAM, type, &PyGObject_Type)) return false; if (!define_config_param_constants(type)) return false; } 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 paramètre de configuration. * * * * Retour : Bilan de l'opération, voire indications supplémentaires. * * * * Remarques : - * * * ******************************************************************************/ int convert_to_config_param(PyObject *arg, void *dst) { int result; /* Bilan à retourner */ result = PyObject_IsInstance(arg, (PyObject *)get_python_config_param_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 configuration parameter"); break; case 1: *((GCfgParam **)dst) = G_CFG_PARAM(pygobject_get(arg)); break; default: assert(false); break; } return result; } /* ---------------------------------------------------------------------------------- */ /* PARCOURS DE PARAMETRES */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : self = instance Python à libérer de la mémoire. * * * * Description : Prend acte d'un compteur de référence à 0. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void py_config_param_iterator_dealloc(PyObject *self) { pyConfigParamIterator *iterator; /* Références pour le parcours */ /** * Il aurait été sans doute mieux de reposer ici sur .tp_finalize, * mais cela semble impliquer de mettre en place tous les mécanismes de GC... * * cf. https://docs.python.org/3/extending/newtypes.html#finalization-and-de-allocation */ iterator = (pyConfigParamIterator *)self; g_generic_config_runlock(iterator->config); g_object_unref(G_OBJECT(iterator->config)); Py_TYPE(self)->tp_free((PyObject *)self); } /****************************************************************************** * * * Paramètres : self = itérateur à manipuler. * * * * Description : Fournit un itérateur pour paramètres de configuration. * * * * Retour : Instance Python prête à emploi. * * * * Remarques : - * * * ******************************************************************************/ static PyObject *py_config_param_iterator_next(PyObject *self) { PyObject *result; /* Instance à retourner */ pyConfigParamIterator *iterator; /* Références pour le parcours */ GList *item; /* Nouvel élément courant */ iterator = (pyConfigParamIterator *)self; if (iterator->last == NULL) item = iterator->params; else item = g_list_next(iterator->last); iterator->last = item; if (item != NULL) result = pygobject_new(G_OBJECT(item->data)); else { PyErr_SetNone(PyExc_StopIteration); result = NULL; } return result; } /****************************************************************************** * * * Paramètres : self = objet instancié à initialiser. * * args = arguments fournis à l'appel. * * kwds = arguments de type key=val fournis. * * * * Description : Initialise un objet Python de type 'ConfigParamIterator'. * * * * Retour : Instance Python mise en place. * * * * Remarques : - * * * ******************************************************************************/ static int py_config_param_iterator_init(PyObject *self, PyObject *args, PyObject *kwds) { GGenConfig *config; /* Configuration format natif */ int ret; /* Bilan de lecture des args. */ pyConfigParamIterator *iterator; /* Références pour le parcours */ #define CONFIG_PARAM_ITERATOR_DOC \ "ConfigParamIterator is an iterator for configuration parameters.\n" \ "\n" \ "This kind of iterator is provided by the" \ " pychrysalide.glibext.GenConfig.params attribute." ret = PyArg_ParseTuple(args, "O&", convert_to_generic_config, &config); if (!ret) return -1; iterator = (pyConfigParamIterator *)self; iterator->config = config; g_object_ref(G_OBJECT(iterator->config)); g_generic_config_rlock(iterator->config); iterator->params = g_generic_config_list_params(iterator->config); iterator->last = NULL; return 0; } /****************************************************************************** * * * Paramètres : - * * * * Description : Fournit un accès à une définition de type à diffuser. * * * * Retour : Définition d'objet pour Python. * * * * Remarques : - * * * ******************************************************************************/ PyTypeObject *get_python_config_param_iterator_type(void) { static PyTypeObject py_config_param_iterator_type = { PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "pychrysalide.glibext.ConfigParamIterator", .tp_basicsize = sizeof(pyConfigParamIterator), .tp_dealloc = py_config_param_iterator_dealloc, .tp_flags = Py_TPFLAGS_DEFAULT, .tp_doc = CONFIG_PARAM_ITERATOR_DOC, .tp_iter = PyObject_SelfIter, .tp_iternext = py_config_param_iterator_next, .tp_init = py_config_param_iterator_init, .tp_new = PyType_GenericNew, }; return &py_config_param_iterator_type; } /****************************************************************************** * * * Paramètres : module = module dont la définition est à compléter. * * * * Description : Prend en charge l'objet 'pychrysalide...ConfigParamIterator'.* * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool ensure_python_config_param_iterator_is_registered(void) { PyTypeObject *type; /* Type Python 'Cnf...Iter' */ PyObject *module; /* Module à recompléter */ type = get_python_config_param_iterator_type(); type->tp_base = &PyBaseObject_Type; if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) { module = get_access_to_python_module("pychrysalide.glibext"); if (PyType_Ready(type) != 0) return false; if (!register_python_module_object(module, type)) return false; } return true; } /* ---------------------------------------------------------------------------------- */ /* GESTION GENERIQUE DE CONFIGURATION */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : type = type du nouvel objet à mettre en place. * * args = éventuelle liste d'arguments. * * kwds = éventuel dictionnaire de valeurs mises à disposition. * * * * Description : Accompagne la création d'une instance dérivée en Python. * * * * Retour : Nouvel objet Python mis en place ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ static PyObject *py_generic_config_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { PyObject *result; /* Objet à retourner */ PyTypeObject *base; /* Type de base à dériver */ bool first_time; /* Evite les multiples passages*/ GType gtype; /* Nouveau type de processeur */ bool status; /* Bilan d'un enregistrement */ /* Validations diverses */ base = get_python_generic_config_type(); if (type == base) goto simple_way; /* Mise en place d'un type dédié */ first_time = (g_type_from_name(type->tp_name) == 0); gtype = build_dynamic_type(G_TYPE_GEN_CONFIG, type->tp_name, NULL, NULL, NULL); if (first_time) { status = register_class_for_dynamic_pygobject(gtype, type, base); if (!status) { result = NULL; goto exit; } } /* On crée, et on laisse ensuite la main à PyGObject_Type.tp_init() */ simple_way: result = PyType_GenericNew(type, args, kwds); exit: return result; } /****************************************************************************** * * * Paramètres : self = objet à initialiser (théoriquement). * * args = arguments fournis à l'appel. * * kwds = arguments de type key=val fournis. * * * * Description : Initialise une instance sur la base du dérivé de GObject. * * * * Retour : 0. * * * * Remarques : - * * * ******************************************************************************/ static int py_generic_config_init(PyObject *self, PyObject *args, PyObject *kwds) { const char *name; /* Désignation de configuration*/ int ret; /* Bilan de lecture des args. */ GGenConfig *config; /* Configuration en place */ #define GENERIC_CONFIG_DOC \ "The GenConfig class defines a generic way to load, provide and store" \ " configuration items. Each of these items is handled with a" \ " pychrysalide.glibext.ConfigParam object.\n" \ "\n" \ "Instances can be created using the following constructor:\n" \ "\n" \ " GenConfig(name=None)" \ "\n" \ "Where *name* is a suitable storage filename for the configuration. If" \ " no *name* is defined, the configuration is expected to be" \ " memory-only resident." /* Récupération des paramètres */ name = NULL; ret = PyArg_ParseTuple(args, "|s", &name); if (!ret) return -1; /* Initialisation d'un objet GLib */ ret = forward_pygobjet_init(self); if (ret == -1) return -1; /* Eléments de base */ config = G_GEN_CONFIG(pygobject_get(self)); if (name != NULL) g_generic_config_build(config, name); return 0; } /****************************************************************************** * * * Paramètres : self = configuration à manipuler. * * args = paramètres liés à l'appel. * * * * Description : Met à disposition un encadrement des accès aux paramètres. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static PyObject *py_generic_config_lock_unlock(PyObject *self, PyObject *args) { PyObject *result; /* Instance à retourner */ bool write; /* Accès en lecture / écriture */ bool lock; /* Pose ou retrait du verrou ? */ int ret; /* Bilan de lecture des args. */ GGenConfig *config; /* Version GLib de la config. */ #define GENERIC_CONFIG_LOCK_UNLOCK_METHOD PYTHON_METHOD_DEF \ ( \ lock_unlock, "$self, write, lock", \ METH_VARARGS, py_generic_config, \ "Lock or unlock access to the configuration internals.\n" \ "\n" \ "The *write* argument states if the operation targets read" \ " or write accesses, and the *lock* value defines the" \ " state to achieve.\n" \ "\n" \ "Both arguments are boolean values." \ ) ret = PyArg_ParseTuple(args, "pp", &write, &lock); if (!ret) return NULL; config = G_GEN_CONFIG(pygobject_get(self)); g_generic_config_lock_unlock(config, write, lock); result = Py_None; Py_INCREF(result); return result; } /****************************************************************************** * * * Paramètres : self = configuration à manipuler. * * args = non utilisé ici. * * * * Description : Lit la configuration depuis un fichier. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ static PyObject *py_generic_config_read(PyObject *self, PyObject *args) { PyObject *result; /* Instance à retourner */ GGenConfig *config; /* Version GLib de la config. */ bool status; /* Bilan de l'opération */ #define GENERIC_CONFIG_READ_METHOD PYTHON_METHOD_DEF \ ( \ read, "$self, /", \ METH_NOARGS, py_generic_config, \ "Read the configuration from its relative XML file.\n" \ "\n" \ "The returned value is True if the operation terminated" \ " with success, or False in case of failure." \ ) config = G_GEN_CONFIG(pygobject_get(self)); status = g_generic_config_read(config); result = status ? Py_True : Py_False; Py_INCREF(result); return result; } /****************************************************************************** * * * Paramètres : self = configuration à manipuler. * * args = non utilisé ici. * * * * Description : Ecrit la configuration dans un fichier. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ static PyObject *py_generic_config_write(PyObject *self, PyObject *args) { PyObject *result; /* Instance à retourner */ GGenConfig *config; /* Version GLib de la config. */ bool status; /* Bilan de l'opération */ #define GENERIC_CONFIG_WRITE_METHOD PYTHON_METHOD_DEF \ ( \ write, "$self, /", \ METH_NOARGS, py_generic_config, \ "Write the configuration to its relative XML file.\n" \ "\n" \ "The returned value is True if the operation terminated" \ " with success, or False in case of failure." \ ) config = G_GEN_CONFIG(pygobject_get(self)); status = g_generic_config_write(config); result = status ? Py_True : Py_False; Py_INCREF(result); return result; } /****************************************************************************** * * * Paramètres : self = configuration à manipuler. * * args = indication sur l'élément à retrouver. * * * * Description : Retrouve un élément de configuration par son chemin. * * * * Retour : Elément trouvé ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ static PyObject *py_generic_config_search(PyObject *self, PyObject *args) { PyObject *result; /* Instance à retourner */ int lock; /* Ordre de pose de verrou */ const char *path; /* Chemin d'accès du paramètre */ int ret; /* Bilan de lecture des args. */ GGenConfig *config; /* Version GLib de la config. */ GCfgParam *param; /* Paramètre trouvé ou NULL */ #define GENERIC_CONFIG_SEARCH_METHOD PYTHON_METHOD_DEF \ ( \ search, "$self, path, /, lock=True", \ METH_VARARGS, py_generic_config, \ "Look for a given configuration parameter.\n" \ "\n" \ "The *path* argument is a string used as key pointing to a parameter." \ " The *lock* boolean value is an optional order handling the way" \ " configuration parameters are accessed.\n" \ "\n" \ "The configuration has to be locked while accessing its content. This" \ " lock can be managed with the *lock* argument of this function or" \ " thanks to the pychrysalide.glibext.GenConfig.lock_unlock method().\n" \ "\n" \ "The returned value is a pychrysalide.glibext.ConfigParam instance in" \ " case of success or None if the parameter is not found." \ ) lock = 1; ret = PyArg_ParseTuple(args, "s|p", &path, &lock); if (!ret) return NULL; config = G_GEN_CONFIG(pygobject_get(self)); param = _g_generic_config_search(config, path, lock); if (param == NULL) { result = Py_None; Py_INCREF(result); } else { result = pygobject_new(G_OBJECT(param)); g_object_unref(G_OBJECT(param)); } return result; } /****************************************************************************** * * * Paramètres : self = configuration à manipuler. * * args = indication sur l'élément à retrouver. * * * * Description : Ajoute un paramètre à une configuration. * * * * Retour : Elément ajouté ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ static PyObject *py_generic_config_add(PyObject *self, PyObject *args) { PyObject *result; /* Instance à retourner */ int lock; /* Ordre de pose de verrou */ GCfgParam *param; /* Paramètre GLib transmis */ int ret; /* Bilan de lecture des args. */ GGenConfig *config; /* Version GLib de la config. */ bool status; /* Bilan de l'opération */ #define GENERIC_CONFIG_ADD_METHOD PYTHON_METHOD_DEF \ ( \ add, "$self, param, /, lock=True", \ METH_VARARGS, py_generic_config, \ "Add an existing parameter to a configuration.\n" \ "\n" \ "The *param* argument has to be a pychrysalide.glibext.ConfigParam" \ " instance. The *lock* boolean value is an optional order handling" \ " the way configuration parameters are accessed.\n" \ "\n" \ "The configuration has to be locked while accessing its content. This" \ " lock can be managed with the *lock* argument of this function or" \ " thanks to the pychrysalide.glibext.GenConfig.lock_unlock method().\n" \ "\n" \ "The returned value is a pychrysalide.glibext.ConfigParam instance in" \ " case of success or None if the parameter already exists in the" \ " configuration." \ ) lock = 1; ret = PyArg_ParseTuple(args, "O&|p", convert_to_config_param, ¶m, &lock); if (!ret) return NULL; config = G_GEN_CONFIG(pygobject_get(self)); status = _g_generic_config_add_param(config, param, lock); result = status ? Py_True : Py_False; Py_INCREF(result); return result; } /****************************************************************************** * * * Paramètres : self = configuration à manipuler. * * args = indication sur l'élément à retrouver. * * * * Description : Retire un paramètre d'une configuration. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static PyObject *py_generic_config_delete(PyObject *self, PyObject *args) { const char *path; /* Chemin d'accès du paramètre */ int ret; /* Bilan de lecture des args. */ GGenConfig *config; /* Version GLib de la config. */ #define GENERIC_CONFIG_DELETE_METHOD PYTHON_METHOD_DEF \ ( \ delete, "$self, path", \ METH_VARARGS, py_generic_config, \ "Delete an existing parameter from a configuration.\n" \ "\n" \ "The *path* argument is a string used as key pointing to the parameter" \ " to process." \ ) ret = PyArg_ParseTuple(args, "s", &path); if (!ret) return NULL; config = G_GEN_CONFIG(pygobject_get(self)); g_generic_config_delete_param(config, path); Py_RETURN_NONE; } /****************************************************************************** * * * Paramètres : self = NULL car méthode statique. * * closure = non utilisé ici. * * * * Description : Indique le fichier utilisé pour l'enregistrement XML. * * * * Retour : Chemin d'accès, potentiellement non existant. * * * * Remarques : - * * * ******************************************************************************/ static PyObject *py_generic_config_get_filename(PyObject *self, void *closure) { PyObject *result; /* Chemin à retourner */ GGenConfig *config; /* Version GLib de la config. */ const char *filename; /* Chemin d'accès au fichier */ #define GENERIC_CONFIG_FILENAME_ATTRIB PYTHON_GET_DEF_FULL \ ( \ filename, py_generic_config, \ "Path to the file used as storage backend for the" \ " configuration.\n" \ "\n" \ "The result is a string pointing to a file which may not" \ " (yet) exist or None if not defined." \ ) config = G_GEN_CONFIG(pygobject_get(self)); filename = g_generic_config_get_filename(config); if (filename == NULL) { result = Py_None; Py_INCREF(result); } else result = PyUnicode_FromString(filename); return result; } /****************************************************************************** * * * Paramètres : self = NULL car méthode statique. * * closure = non utilisé ici. * * * * Description : Renvoie la liste des paramètres de configuration. * * * * Retour : Liste d'éléments à parcourir. * * * * Remarques : - * * * ******************************************************************************/ static PyObject *py_generic_config_get_params(PyObject *self, void *closure) { PyObject *result; /* Instance à retourner */ PyTypeObject *iterator_type; /* Type Python de l'itérateur */ PyObject *args_list; /* Arguments de mise en place */ #define GENERIC_CONFIG_PARAMS_ATTRIB PYTHON_GET_DEF_FULL \ ( \ params, py_generic_config, \ "List of all registered configuration parameters.\n" \ "\n" \ "The result is a pychrysalide.glibext.ConfigParamIterator" \ " over pychrysalide.glibext.ConfigParam instances." \ ) iterator_type = get_python_config_param_iterator_type(); Py_INCREF(self); args_list = Py_BuildValue("(O)", self); result = PyObject_CallObject((PyObject *)iterator_type, args_list); Py_DECREF(args_list); return result; } /****************************************************************************** * * * Paramètres : - * * * * Description : Fournit un accès à une définition de type à diffuser. * * * * Retour : Définition d'objet pour Python. * * * * Remarques : - * * * ******************************************************************************/ PyTypeObject *get_python_generic_config_type(void) { static PyMethodDef py_generic_config_methods[] = { GENERIC_CONFIG_LOCK_UNLOCK_METHOD, GENERIC_CONFIG_READ_METHOD, GENERIC_CONFIG_WRITE_METHOD, GENERIC_CONFIG_SEARCH_METHOD, GENERIC_CONFIG_ADD_METHOD, GENERIC_CONFIG_DELETE_METHOD, { NULL } }; static PyGetSetDef py_generic_config_getseters[] = { GENERIC_CONFIG_FILENAME_ATTRIB, GENERIC_CONFIG_PARAMS_ATTRIB, { NULL } }; static PyTypeObject py_generic_config_type = { PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "pychrysalide.glibext.GenConfig", .tp_basicsize = sizeof(PyGObject), .tp_flags = Py_TPFLAGS_DEFAULT, .tp_doc = GENERIC_CONFIG_DOC, .tp_methods = py_generic_config_methods, .tp_getset = py_generic_config_getseters, .tp_init = py_generic_config_init, .tp_new = py_generic_config_new }; return &py_generic_config_type; } /****************************************************************************** * * * Paramètres : module = module dont la définition est à compléter. * * * * Description : Prend en charge l'objet 'pychrysalide.glibext.GenConfig'. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool ensure_python_generic_config_is_registered(void) { PyTypeObject *type; /* Type Python 'GenConfig' */ PyObject *module; /* Module à recompléter */ PyObject *dict; /* Dictionnaire du module */ type = get_python_generic_config_type(); if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) { module = get_access_to_python_module("pychrysalide.glibext"); dict = PyModule_GetDict(module); if (!register_class_for_pygobject(dict, G_TYPE_GEN_CONFIG, type, &PyGObject_Type)) return false; } 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 configuration générique. * * * * Retour : Bilan de l'opération, voire indications supplémentaires. * * * * Remarques : - * * * ******************************************************************************/ int convert_to_generic_config(PyObject *arg, void *dst) { int result; /* Bilan à retourner */ result = PyObject_IsInstance(arg, (PyObject *)get_python_generic_config_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 generic configuration"); break; case 1: *((GGenConfig **)dst) = G_GEN_CONFIG(pygobject_get(arg)); break; default: assert(false); break; } return result; }