summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristopher Davis <loafier@gmail.com>2006-06-25 05:47:20 +0000
committerChristopher Davis <loafier@gmail.com>2006-06-25 05:47:20 +0000
commit3b04cf6a1210f97d8144ee1ba646186aca4912ef (patch)
treed2d4081cd3043bd3b1d403f93f147e94a471aeac
parentd75ad2cebb61a3cb46570cecbc257693c528da0b (diff)
downloadirssi-python-3b04cf6a1210f97d8144ee1ba646186aca4912ef.tar.gz
irssi-python-3b04cf6a1210f97d8144ee1ba646186aca4912ef.tar.xz
irssi-python-3b04cf6a1210f97d8144ee1ba646186aca4912ef.zip
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
-rw-r--r--objects/base-objects.h9
-rw-r--r--objects/pyscript-object.c213
-rw-r--r--objects/pyscript-object.h2
-rw-r--r--pymodule.c59
-rw-r--r--pysigmap.h1
-rw-r--r--pysignals.c254
-rw-r--r--pysignals.h15
-rw-r--r--sig2code.py2
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 <Python.h>
#include <glib.h>
-//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)