From 3b04cf6a1210f97d8144ee1ba646186aca4912ef Mon Sep 17 00:00:00 2001 From: Christopher Davis Date: Sun, 25 Jun 2006 05:47:20 +0000 Subject: worked more on signals. added signal emit, signal register, unregister, cmd unbind, signal remove. Needs testing. Need to find a better way of dealing with constants, too. git-svn-id: http://svn.irssi.org/repos/irssi-python@4291 dbcabf3a-b0e7-0310-adc4-f8d773084564 --- objects/base-objects.h | 9 ++ objects/pyscript-object.c | 213 +++++++++++++++++++++++++++++++++----- objects/pyscript-object.h | 2 +- pymodule.c | 59 +++++++++++ pysigmap.h | 1 + pysignals.c | 254 +++++++++++++++++++++++++++++++++++++++++----- pysignals.h | 15 +++ sig2code.py | 2 +- 8 files changed, 499 insertions(+), 56 deletions(-) diff --git a/objects/base-objects.h b/objects/base-objects.h index d2f6acb..ed2edfc 100644 --- a/objects/base-objects.h +++ b/objects/base-objects.h @@ -20,6 +20,15 @@ type *data; \ int cleanup_installed; +/* to access data from any irssi object */ +typedef struct +{ + PyObject_HEAD + void *data; +} PyIrssiObject; + +#define DATA(obj) (((PyIrssiObject *)obj)->data) + /* base for classes with a type */ typedef struct { diff --git a/objects/pyscript-object.c b/objects/pyscript-object.c index d4ec5f1..665828c 100644 --- a/objects/pyscript-object.c +++ b/objects/pyscript-object.c @@ -65,9 +65,10 @@ static PyObject *PyScript_new(PyTypeObject *type, PyObject *args, PyObject *kwds return (PyObject *)self; } -//FIXME: add prioriety as arg PyDoc_STRVAR(PyScript_command_bind_doc, - "Bind a command" + "command_bind(command, func, catetory=None, priority=SIGNAL_PRIORITY_DEFAULT) -> None\n" + "\n" + "Add handler for a command\n" ); static PyObject *PyScript_command_bind(PyScript *self, PyObject *args, PyObject *kwds) { @@ -76,59 +77,193 @@ static PyObject *PyScript_command_bind(PyScript *self, PyObject *args, PyObject PyObject *func; char *category = NULL; int priority = SIGNAL_PRIORITY_DEFAULT; - PY_SIGNAL_REC *srec; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "sO|si", kwlist, + if (!PyArg_ParseTupleAndKeywords(args, kwds, "sO|zi", kwlist, &cmd, &func, &category, &priority)) return NULL; if (!PyCallable_Check(func)) return PyErr_Format(PyExc_TypeError, "func must be callable"); - srec = pysignals_command_bind(cmd, func, category, priority); - if (!srec) + if (!pysignals_command_bind_list(&self->signals, cmd, func, category, priority)) return PyErr_Format(PyExc_RuntimeError, "unable to bind command"); - /* add record to internal list*/ - self->signals = g_slist_append(self->signals, srec); - Py_RETURN_NONE; } PyDoc_STRVAR(PyScript_signal_add_doc, - "add signal" + "signal_add(signal, func, priority=SIGNAL_PRIORITY_DEFAULT) -> None\n" + "\n" + "Add handler for signal" ); static PyObject *PyScript_signal_add(PyScript *self, PyObject *args, PyObject *kwds) { - static char *kwlist[] = {"signal", "func", "category", "priority", NULL}; + static char *kwlist[] = {"signal", "func", "priority", NULL}; char *signal; PyObject *func; - char *category = NULL; int priority = SIGNAL_PRIORITY_DEFAULT; - PY_SIGNAL_REC *srec; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "sO|si", kwlist, - &signal, &func, &category, &priority)) + if (!PyArg_ParseTupleAndKeywords(args, kwds, "sO|i", kwlist, + &signal, &func, &priority)) return NULL; if (!PyCallable_Check(func)) return PyErr_Format(PyExc_TypeError, "func must be callable"); - srec = pysignals_signal_add(signal, func, priority); - if (!srec) + if (!pysignals_signal_add_list(&self->signals, signal, func, priority)) return PyErr_Format(PyExc_KeyError, "unable to find signal, '%s'", signal); - self->signals = g_slist_append(self->signals, srec); + Py_RETURN_NONE; +} + +PyDoc_STRVAR(PyScript_signal_remove_doc, + "signal_remove(signal, func=None) -> None\n" + "\n" + "Remove signal handler\n" +); +static PyObject *PyScript_signal_remove(PyScript *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"signal", "func", NULL}; + char *signal = ""; + PyObject *func = Py_None; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|O", kwlist, + &signal, &func)) + return NULL; + + if (!PyCallable_Check(func) && func != Py_None) + return PyErr_Format(PyExc_TypeError, "func must be callable or None"); + if (func == Py_None) + func = NULL; + + if (!pysignals_remove_search(&self->signals, signal, func, PSG_SIGNAL)) + return PyErr_Format(PyExc_KeyError, "can't find signal"); + Py_RETURN_NONE; } -static PyMemberDef PyScript_members[] = { - {"argv", T_OBJECT, offsetof(PyScript, argv), 0, "Script arguments"}, - {"module", T_OBJECT_EX, offsetof(PyScript, module), RO, "Script module"}, - {"modules", T_OBJECT_EX, offsetof(PyScript, modules), 0, "Imported modules"}, - {NULL} /* Sentinel */ -}; +PyDoc_STRVAR(PyScript_command_unbind_doc, + "command_unbind(command, func=None) -> None\n" + "\n" + "Remove command handler\n" +); +static PyObject *PyScript_command_unbind(PyScript *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"command", "func", NULL}; + char *command = ""; + PyObject *func = Py_None; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|O", kwlist, + &command, &func)) + return NULL; + + if (!PyCallable_Check(func) && func != Py_None) + return PyErr_Format(PyExc_TypeError, "func must be callable or None"); + + if (func == Py_None) + func = NULL; + + if (!pysignals_remove_search(&self->signals, command, func, PSG_COMMAND)) + return PyErr_Format(PyExc_KeyError, "can't find command"); + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(PyScript_signal_register_doc, + "signal_register(signal, arglist) -> None\n" + "\n" + "Register a new dynamic signal for use with irssi_python\n" + "arglist is a string of character codes representing the type of each argument\n" + "of the signal handler function.\n" + "\n" + " Scalars\n" + " s -> char *\n" + " i -> int\n" + "\n" + " Chat objects\n" + " c -> CHATNET_REC\n" + " S -> SERVER_REC\n" + " C -> CHANNEL_REC\n" + " q -> QUERY_REC\n" + " n -> NICK_REC\n" + " W -> WI_ITEM_REC\n" + "\n" + " Irssi objects\n" + " d -> DCC_REC\n" + "\n" + " Other objects\n" + " r -> RECONNECT_REC\n" + " o -> COMMAND_REC\n" + " l -> LOG_REC\n" + " a -> RAWLOG_REC\n" + " g -> IGNORE_REC\n" + " b -> BAN_REC\n" + " N -> NETSPLIT_REC\n" + " e -> NETSPLIT_SERVER_REC\n" + " O -> NOTIFYLIST_REC\n" + " p -> PROCESS_REC\n" + " t -> TEXT_DEST_REC\n" + " w -> WINDOW_REC\n" +); +static PyObject *PyScript_signal_register(PyScript *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"signal", "arglist", NULL}; + static const char *good_codes = "sicSCqnWdrolagbNeOptw"; + char *signal = ""; + char *arglist = ""; + int i; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "ss", kwlist, + &signal, &arglist)) + return NULL; + + for (i = 0; arglist[i]; i++) + if (!strchr(good_codes, arglist[i])) + return PyErr_Format(PyExc_TypeError, "invalid code, %c", arglist[i]); + + if (i >= SIGNAL_MAX_ARGUMENTS) + return PyErr_Format(PyExc_TypeError, + "arglist greater than SIGNAL_MAX_ARGUMENTS (%d)", + SIGNAL_MAX_ARGUMENTS); + + if (!pysignals_register(signal, arglist)) + return PyErr_Format(PyExc_TypeError, "signal present with different args"); + + self->registered_signals = g_slist_append(self->registered_signals, + g_strdup(signal)); + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(PyScript_signal_unregister_doc, + "signal_unregister(signal) -> None\n" + "\n" + "Unregister dynamic signal\n" +); +static PyObject *PyScript_signal_unregister(PyScript *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"signal", NULL}; + char *signal = ""; + GSList *search; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, + &signal)) + return NULL; + + search = g_slist_find_custom(self->registered_signals, signal, (GCompareFunc)strcmp); + if (!search) + return PyErr_Format(PyExc_KeyError, "script has not registered that signal"); + + g_free(search->data); + self->registered_signals = g_slist_delete_link(self->registered_signals, search); + + if (!pysignals_unregister(signal)) + return PyErr_Format(PyExc_SystemError, + "script registered signal, but signal does not exist"); + + Py_RETURN_NONE; +} /* Methods for object */ static PyMethodDef PyScript_methods[] = { @@ -136,6 +271,21 @@ static PyMethodDef PyScript_methods[] = { PyScript_command_bind_doc}, {"signal_add", (PyCFunction)PyScript_signal_add, METH_VARARGS | METH_KEYWORDS, PyScript_signal_add_doc}, + {"signal_remove", (PyCFunction)PyScript_signal_remove, METH_VARARGS | METH_KEYWORDS, + PyScript_signal_remove_doc}, + {"command_unbind", (PyCFunction)PyScript_command_unbind, METH_VARARGS | METH_KEYWORDS, + PyScript_command_unbind_doc}, + {"signal_register", (PyCFunction)PyScript_signal_register, METH_VARARGS | METH_KEYWORDS, + PyScript_signal_register_doc}, + {"signal_unregister", (PyCFunction)PyScript_signal_unregister, METH_VARARGS | METH_KEYWORDS, + PyScript_signal_unregister_doc}, + {NULL} /* Sentinel */ +}; + +static PyMemberDef PyScript_members[] = { + {"argv", T_OBJECT, offsetof(PyScript, argv), 0, "Script arguments"}, + {"module", T_OBJECT_EX, offsetof(PyScript, module), RO, "Script module"}, + {"modules", T_OBJECT_EX, offsetof(PyScript, modules), 0, "Imported modules"}, {NULL} /* Sentinel */ }; @@ -224,11 +374,20 @@ void pyscript_remove_signals(PyObject *script) self = (PyScript *) script; - for (node = self->signals; node != NULL; node = node->next) - pysignals_remove_generic((PY_SIGNAL_REC *)node->data); - + /* remove bound signals */ + pysignals_remove_list(self->signals); g_slist_free(self->signals); self->signals = NULL; + + /* remove registered signals */ + for (node = self->registered_signals; node; node = node->next) + { + pysignals_unregister(node->data); + g_free(node->data); + } + + g_slist_free(self->registered_signals); + self->registered_signals = NULL; } void pyscript_clear_modules(PyObject *script) diff --git a/objects/pyscript-object.h b/objects/pyscript-object.h index ee32d8c..8565053 100644 --- a/objects/pyscript-object.h +++ b/objects/pyscript-object.h @@ -3,13 +3,13 @@ #include #include -//FIXME: add list of registered dynamic signal names typedef struct { PyObject_HEAD PyObject *module; /* module object */ PyObject *argv; /* list of argument strings from the load command */ PyObject *modules; /* dict of imported modules for script */ GSList *signals; /* list of bound signals and commands */ + GSList *registered_signals; /* list of signal names registered */ } PyScript; extern PyTypeObject PyScriptType; diff --git a/pymodule.c b/pymodule.c index 713511f..0f6d97a 100644 --- a/pymodule.c +++ b/pymodule.c @@ -5,6 +5,7 @@ #include "pyscript-object.h" #include "factory.h" #include "pyutils.h" +#include "pysignals.h" /* * This module is some what different than the Perl's. @@ -842,6 +843,58 @@ static PyObject *py_combine_level(PyObject *self, PyObject *args, PyObject *kwds return PyLong_FromUnsignedLong(combine_level(level, str)); } +PyDoc_STRVAR(py_signal_emit_doc, + "signal_emit(signal, *args) -> None\n" + "\n" + "Emit an Irssi signal with up to 6 arguments\n" +); +static PyObject *py_signal_emit(PyObject *self, PyObject *args) +{ + PyObject *pysig; + + if (PyTuple_Size(args) < 1 || PyTuple_Size(args) > SIGNAL_MAX_ARGUMENTS) + return PyErr_Format(PyExc_TypeError, "need at least one argument for signal"); + + pysig = PyTuple_GET_ITEM(args, 0); + if (!PyString_Check(pysig)) + return PyErr_Format(PyExc_TypeError, "signal must be string"); + + if (!pysignals_emit(PyString_AS_STRING(pysig), args)) + return NULL; + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(py_signal_stop_doc, + "signal_stop() -> None\n" + "\n" + "Stop the signal that's currently being emitted.\n" +); +static PyObject *py_signal_stop(PyObject *self, PyObject *args) +{ + signal_stop(); + Py_RETURN_NONE; +} + +PyDoc_STRVAR(py_signal_stop_by_name_doc, + "signal_stop_by_name(signal) -> None\n" + "\n" + "Stop the signal, 'signal', thats currently being emitted by name\n" +); +static PyObject *py_signal_stop_by_name(PyObject *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"signal", NULL}; + char *signal = ""; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, + &signal)) + return NULL; + + signal_stop_by_name(signal); + + Py_RETURN_NONE; +} + static PyMethodDef ModuleMethods[] = { {"prnt", (PyCFunction)py_prnt, METH_VARARGS|METH_KEYWORDS, py_prnt_doc}, {"get_script", (PyCFunction)py_get_script, METH_NOARGS, py_get_script_doc}, @@ -945,6 +998,12 @@ static PyMethodDef ModuleMethods[] = { py_bits2level_doc}, {"combine_level", (PyCFunction)py_combine_level, METH_VARARGS | METH_KEYWORDS, py_combine_level_doc}, + {"signal_emit", (PyCFunction)py_signal_emit, METH_VARARGS, + py_signal_emit_doc}, + {"signal_stop", (PyCFunction)py_signal_stop, METH_NOARGS, + py_signal_stop_doc}, + {"signal_stop_by_name", (PyCFunction)py_signal_stop_by_name, METH_VARARGS | METH_KEYWORDS, + py_signal_stop_by_name_doc}, {NULL, NULL, 0, NULL} /* Sentinel */ }; diff --git a/pysigmap.h b/pysigmap.h index b6c3278..fcf8ce8 100644 --- a/pysigmap.h +++ b/pysigmap.h @@ -14,6 +14,7 @@ static PY_SIGNAL_SPEC_REC py_sigmap[] = { {"error command", "is", 0, 0, 0}, {"send command", "sSW", 0, 0, 0}, {"send text", "sSW", 0, 0, 0}, + {"command ", "sSW", 0, 0, 1}, {"default command", "sSW", 0, 0, 0}, {"ignore created", "g", 0, 0, 0}, {"ignore destroyed", "g", 0, 0, 0}, diff --git a/pysignals.c b/pysignals.c index 58cc6d4..518b3e0 100644 --- a/pysignals.c +++ b/pysignals.c @@ -11,7 +11,9 @@ * Binding to the signal also increments its reference count. Likewise, * unregistering or unbinding a dynamic signal will decrement its refcount. * When refcount hits 0, the dynamic signal is removed from the list, and - * scripts can no longer bind to it. + * scripts can no longer bind to it. Built-in signals in the sigmap are + * never removed; it is an error for the refcount of any such signal entry + * to drop to 0. */ typedef struct _PY_SIGNAL_SPEC_REC @@ -25,6 +27,8 @@ typedef struct _PY_SIGNAL_SPEC_REC #include "pysigmap.h" +#define SIGNAME(sig) (sig->command? sig->command : sig->signal->name) + /* hashtable for normal signals, tree for variable signal prefixes. */ static GHashTable *py_sighash = NULL; static GTree *py_sigtree = NULL; @@ -38,6 +42,7 @@ static PY_SIGNAL_REC *py_signal_rec_new(const char *signal, PyObject *func, cons static void py_signal_rec_destroy(PY_SIGNAL_REC *sig); static PyObject *py_mkstrlist(void *iobj); static PyObject *py_i2py(char code, void *iobj); +static void *py_py2i(char code, PyObject *pobj, int arg); static void py_getstrlist(GList **list, PyObject *pylist); static int precmp(const char *spec, const char *test); static PY_SIGNAL_SPEC_REC *py_signal_lookup(const char *name); @@ -55,22 +60,42 @@ PY_SIGNAL_REC *pysignals_command_bind(const char *cmd, PyObject *func, return rec; } +int pysignals_command_bind_list(GSList **list, const char *command, + PyObject *func, const char *category, int priority) +{ + PY_SIGNAL_REC *rec = pysignals_command_bind(command, func, category, priority); + if (!rec) + return 0; + + *list = g_slist_append(*list, rec); + return 1; +} + /* return NULL if signal is invalid */ PY_SIGNAL_REC *pysignals_signal_add(const char *signal, PyObject *func, int priority) { PY_SIGNAL_REC *rec = py_signal_rec_new(signal, func, NULL); - char *name; if (rec == NULL) return NULL; - name = rec->command? rec->command : rec->signal->name; - - signal_add_full(MODULE_NAME, priority, name, (SIGNAL_FUNC)py_sig_proxy, rec); + signal_add_full(MODULE_NAME, priority, SIGNAME(rec), + (SIGNAL_FUNC)py_sig_proxy, rec); return rec; } +int pysignals_signal_add_list(GSList **list, const char *signal, + PyObject *func, int priority) +{ + PY_SIGNAL_REC *rec = pysignals_signal_add(signal, func, priority); + if (!rec) + return 0; + + *list = g_slist_append(*list, rec); + return 1; +} + void pysignals_command_unbind(PY_SIGNAL_REC *rec) { g_return_if_fail(rec->is_signal == FALSE); @@ -82,13 +107,9 @@ void pysignals_command_unbind(PY_SIGNAL_REC *rec) void pysignals_signal_remove(PY_SIGNAL_REC *rec) { - char *name; - g_return_if_fail(rec->is_signal == TRUE); - name = rec->command? rec->command : rec->signal->name; - - signal_remove_full(name, (SIGNAL_FUNC)py_sig_proxy, rec); + signal_remove_full(SIGNAME(rec), (SIGNAL_FUNC)py_sig_proxy, rec); py_signal_rec_destroy(rec); } @@ -100,6 +121,42 @@ void pysignals_remove_generic(PY_SIGNAL_REC *rec) pysignals_command_unbind(rec); } +/* returns 1 when found and removed successfully */ +int pysignals_remove_search(GSList **siglist, const char *name, + PyObject *func, PSG_TYPE type) +{ + GSList *node; + + for (node = *siglist; node != NULL; node = node->next) + { + PY_SIGNAL_REC *sig = node->data; + + if ((sig->is_signal && type == PSG_COMMAND) || + (!sig->is_signal && type == PSG_SIGNAL)) + continue; + + if ((strcmp(SIGNAME(sig), name) == 0) && + (func == NULL || func == sig->handler)) + { + pysignals_remove_generic(sig); + *siglist = g_slist_delete_link(*siglist, node); + + /* deleting node won't harm iteration because it quits here */ + return 1; + } + } + + return 0; +} + +void pysignals_remove_list(GSList *siglist) +{ + GSList *node = siglist; + + for (node = siglist; node != NULL; node = node->next) + pysignals_remove_generic(node->data); +} + static PyObject *py_mkstrlist(void *iobj) { PyObject *list; @@ -199,6 +256,117 @@ static PyObject *py_i2py(char code, void *iobj) return PyErr_Format(PyExc_TypeError, "unknown code %c", code); } +/* PyObject -> irssi obj*/ +static void *py_py2i(char code, PyObject *pobj, int arg) +{ + char *type; + + if (pobj == Py_None) + return NULL; + + switch (code) + { + case 's': + type = "str"; + if (PyString_Check(pobj)) return PyString_AsString(pobj); + break; + case 'i': + type = "int"; + if (PyInt_Check(pobj)) return (void*)PyInt_AsLong(pobj); + break; + + case 'L': /* list of nicks */ + /*FIXME*/ + return NULL; + + case 'c': + type = "Chatnet"; + if (pychatnet_check(pobj)) return DATA(pobj); + break; + case 'S': + type = "Server"; + if (pyserver_check(pobj)) return DATA(pobj); + break; + case 'C': + type = "Channel"; + if (pychannel_check(pobj)) return DATA(pobj); + break; + case 'q': + type = "Query"; + if (pyquery_check(pobj)) return DATA(pobj); + break; + case 'n': + type = "Nick"; + if (pynick_check(pobj)) return DATA(pobj); + break; + case 'W': + type = "WindowItem"; + if (pywindow_item_check(pobj)) return DATA(pobj); + break; + + case 'd': + type = "DCC"; + if (pydcc_check(pobj)) return DATA(pobj); + break; + + case 'r': + type = "Reconnect"; + if (pyreconnect_check(pobj)) return DATA(pobj); + break; + case 'o': + type = "Command"; + if (pycommand_check(pobj)) return DATA(pobj); + break; + case 'l': + type = "Log"; + if (pylog_check(pobj)) return DATA(pobj); + break; + case 'a': + type = "Rawlog"; + if (pyrawlog_check(pobj)) return DATA(pobj); + break; + case 'g': + type = "Ignore"; + if (pyignore_check(pobj)) return DATA(pobj); + break; + case 'b': + type = "Ban"; + if (pyban_check(pobj)) return DATA(pobj); + break; + case 'N': + type = "Netsplit"; + if (pynetsplit_check(pobj)) return DATA(pobj); + break; + case 'e': + type = "NetsplitServer"; + if (pynetsplit_server_check(pobj)) return DATA(pobj); + break; + case 'O': + type = "Notifylist"; + if (pynotifylist_check(pobj)) return DATA(pobj); + break; + case 'p': + type = "Process"; + if (pyprocess_check(pobj)) return DATA(pobj); + break; + case 't': + type = "TextDest"; + if (pytextdest_check(pobj)) return DATA(pobj); + break; + case 'w': + type = "Window"; + if (pywindow_check(pobj)) return DATA(pobj); + break; + default: + PyErr_Format(PyExc_TypeError, "don't know type code %c", code); + return NULL; + } + + PyErr_Format(PyExc_TypeError, "expected type %s for arg %d, but got %s", + type, arg, pobj->ob_type->tp_name); + return NULL; +} + static void py_getstrlist(GList **list, PyObject *pylist) { GList *out = NULL; @@ -305,6 +473,40 @@ static void py_sig_proxy(void *p1, void *p2, void *p3, void *p4, void *p5, void py_run_handler(rec, args); } +int pysignals_emit(const char *signal, PyObject *argtup) +{ + PY_SIGNAL_SPEC_REC *spec; + void *args[6]; + char *arglist; + int i; + int maxargs; + + memset(args, 0, sizeof args); + + spec = py_signal_lookup(signal); + if (!spec) + { + PyErr_Format(PyExc_KeyError, "signal not found"); + return 0; + } + + arglist = spec->arglist; + maxargs = strlen(arglist); + + for (i = 0; i < maxargs && i+1 < PyTuple_Size(argtup); i++) + { + args[i] = py_py2i(arglist[i], PyTuple_GET_ITEM(argtup, i+1), i+1); + if (PyErr_Occurred()) /* XXX: any cleanup needed? */ + return 0; + } + + signal_emit(signal, maxargs, + args[0], args[1], args[2], + args[3], args[4], args[5]); + + return 1; +} + /* returns NULL if signal is invalid, incr reference to func */ static PY_SIGNAL_REC *py_signal_rec_new(const char *signal, PyObject *func, const char *command) { @@ -345,7 +547,6 @@ static PY_SIGNAL_REC *py_signal_rec_new(const char *signal, PyObject *func, cons static void py_signal_rec_destroy(PY_SIGNAL_REC *sig) { py_signal_unref(sig->signal); - Py_DECREF(sig->handler); g_free(sig->command); g_free(sig); @@ -374,8 +575,6 @@ static void py_signal_remove(PY_SIGNAL_SPEC_REC *sig) static int precmp(const char *spec, const char *test) { - //printf("precmp(spec,test) -> '%s', '%s'\n", spec, test); - while (*spec == *test++) if (*spec++ == '\0') return 0; @@ -410,23 +609,18 @@ static void py_signal_ref(PY_SIGNAL_SPEC_REC *sig) static int py_signal_unref(PY_SIGNAL_SPEC_REC *sig) { g_return_val_if_fail(sig->refcount >= 1, 0); - g_return_val_if_fail(sig->refcount > 1 || !sig->dynamic, 0); + g_return_val_if_fail(sig->refcount > 1 || sig->dynamic, 0); sig->refcount--; if (sig->refcount == 0) { - if (sig->dynamic) - { - py_signal_remove(sig); + py_signal_remove(sig); - /* freeing name also takes care of the key */ - g_free(sig->name); - g_free(sig->arglist); - g_free(sig); - } - - /* non-dynamic signals are not removed */ + /* freeing name also takes care of the key */ + g_free(sig->name); + g_free(sig->arglist); + g_free(sig); return 1; } @@ -434,16 +628,21 @@ static int py_signal_unref(PY_SIGNAL_SPEC_REC *sig) return 0; } -/* returns 0 when signal already exists, but with different args. */ +/* returns 0 when signal already exists, but with different args, or when + similar signal prefix is already present. */ int pysignals_register(const char *name, const char *arglist) { + int len; PY_SIGNAL_SPEC_REC *spec; + len = strlen(name); + g_return_val_if_fail(len > 0, 0); + spec = py_signal_lookup(name); if (!spec) { spec = g_new0(PY_SIGNAL_SPEC_REC, 1); - spec->is_var = name[strlen(name)-1] == ' '; /* trailing space means signal prefix */ + spec->is_var = name[len-1] == ' '; /* trailing space means signal prefix */ spec->dynamic = 1; spec->refcount = 0; spec->name = g_strdup(name); @@ -451,7 +650,7 @@ int pysignals_register(const char *name, const char *arglist) py_signal_add(spec); } - else if (strcmp(spec->arglist, arglist) != 0) + else if (strcmp(spec->arglist, arglist) || strcmp(spec->name, name)) return 0; spec->refcount++; @@ -501,6 +700,7 @@ static int py_check_sig(char *key, PY_SIGNAL_SPEC_REC *value, void *data) return FALSE; } +/* XXX: remember to remove all scripts before calling this deinit */ void pysignals_deinit(void) { g_return_if_fail(py_sighash != NULL); diff --git a/pysignals.h b/pysignals.h index a069482..7627d19 100644 --- a/pysignals.h +++ b/pysignals.h @@ -13,13 +13,28 @@ typedef struct _PY_SIGNAL_REC int is_signal; } PY_SIGNAL_REC; +typedef enum +{ + PSG_COMMAND, + PSG_SIGNAL, + PSG_ALL, +} PSG_TYPE; + PY_SIGNAL_REC *pysignals_command_bind(const char *cmd, PyObject *func, const char *category, int priority); PY_SIGNAL_REC *pysignals_signal_add(const char *signal, PyObject *func, int priority); +int pysignals_command_bind_list(GSList **list, const char *command, + PyObject *func, const char *category, int priority); +int pysignals_signal_add_list(GSList **list, const char *signal, + PyObject *func, int priority); void pysignals_command_unbind(PY_SIGNAL_REC *rec); void pysignals_signal_remove(PY_SIGNAL_REC *rec); void pysignals_remove_generic(PY_SIGNAL_REC *rec); +int pysignals_remove_search(GSList **siglist, const char *name, + PyObject *func, PSG_TYPE type); +void pysignals_remove_list(GSList *siglist); +int pysignals_emit(const char *signal, PyObject *argtup); int pysignals_register(const char *name, const char *arglist); int pysignals_unregister(const char *name); void pysignals_init(void); diff --git a/sig2code.py b/sig2code.py index 4798e87..c0f2353 100644 --- a/sig2code.py +++ b/sig2code.py @@ -108,7 +108,7 @@ def main(): signal, args = m.groups() if signal.startswith('script '): continue - if signal == 'command ': continue + #if signal == 'command ': continue argv = [transcode(a.strip()) for a in args.split(',')] argv = ''.join(argv) -- cgit