Implement traversing of linestack.
authorJelmer Vernooij <jelmer@samba.org>
Sat, 13 Jun 2009 16:32:54 +0000 (18:32 +0200)
committerJelmer Vernooij <jelmer@samba.org>
Sat, 13 Jun 2009 16:32:54 +0000 (18:32 +0200)
libirc/line.c
libirc/line.h
libirc/linestack.h
libirc/python/irc.c
libirc/python/irc.h
libirc/python/linestack.c
libirc/python/tests/test_irc.py

index 1839b8a42b74bba4b461966b309934f90b2a53d5..5a69fcc03fa4225b4c42acc59857867468cec657 100644 (file)
@@ -478,3 +478,29 @@ G_MODULE_EXPORT struct irc_line *line_prefix_time(const struct irc_line *l, time
        return nl;
 }
 
+int irc_line_cmp(const struct irc_line *a, const struct irc_line *b)
+{
+       int i;
+       int ret;
+
+       if (a->origin != NULL && b->origin == NULL)
+               return 1;
+
+       if (a->origin == NULL && b->origin != NULL)
+               return -1;
+
+       if (a->origin == NULL && b->origin == NULL)
+               ret = 0;
+       else
+               ret = strcmp(a->origin, b->origin);
+       if (ret != 0)
+               return ret;
+
+       for (i = 0; i < MIN(a->argc, b->argc); i++) {
+               ret = strcmp(a->args[i], b->args[i]);
+               if (ret != 0)
+                       return ret;
+       }
+
+       return a->argc - b->argc;
+}
index 2ba5efe5a9215bdad3401594be7c3504ff4471dd..ad6aa0eb6bc926e418ed139d7f44b33ff2bfbbb7 100644 (file)
@@ -91,4 +91,6 @@ G_MODULE_EXPORT gboolean line_add_arg(struct irc_line *l, const char *arg);
 G_MODULE_EXPORT struct irc_line *line_prefix_time(const struct irc_line *l, time_t t);
 #define irc_line_respcode(l) (((l)->argc == 0)?0:atoi((l)->args[0]))
 
+G_MODULE_EXPORT int irc_line_cmp(const struct irc_line *a, const struct irc_line *b);
+
 #endif /* __CTRLPROXY_LINE_H__ */
index bd40907ce13424e40942281aa613673eacdb61a0..80e50ee62ca615dc00c6b6f2e97cf902fafadfe4 100644 (file)
@@ -107,4 +107,11 @@ G_MODULE_EXPORT linestack_marker linestack_get_marker(struct linestack_context *
 G_MODULE_EXPORT struct linestack_context *create_linestack(const char *name, gboolean truncate, const char *basedir, const struct irc_network_state *);
 G_MODULE_EXPORT void free_linestack_context(struct linestack_context *);
 
+G_MODULE_EXPORT gboolean linestack_read_entry(struct linestack_context *nd, 
+                                                         guint64 i,
+                                                         struct irc_line **line,
+                                                         time_t *time
+                                                        );
+
+
 #endif /* __CTRLPROXY_LINESTACK_H__ */
index 3d3df3bec2129f7bbbc388a7ae0cb0e584218823..6f20edd3f077614fffc7e823932f698b30b8cc29 100644 (file)
@@ -134,6 +134,11 @@ static PyGetSetDef py_line_getsetters[] = {
     { NULL }
 };
 
+static int py_line_cmp(PyLineObject *a, PyLineObject *b)
+{
+    return irc_line_cmp(a->line, b->line);
+}
+
 PyTypeObject PyLineType = {
     .tp_name = "Line",
     .tp_new = py_line_new,
@@ -146,6 +151,7 @@ PyTypeObject PyLineType = {
     .tp_doc = "A RFC2459-compatible line.",
     .tp_getset = py_line_getsetters,
     .tp_as_sequence = &py_line_sequence,
+    .tp_compare = (cmpfunc)py_line_cmp,
 };
 
 struct irc_line *PyObject_AsLine(PyObject *obj)
@@ -1142,6 +1148,9 @@ void initirc(void)
     if (PyType_Ready(&PyLinestackType) < 0)
         return;
 
+    if (PyType_Ready(&PyLinestackIterType) < 0)
+        return;
+
     if (PyType_Ready(&PyChannelModeDictType) < 0)
         return;
 
@@ -1173,6 +1182,7 @@ void initirc(void)
     PyModule_AddObject(m, "Transport", (PyObject *)&PyTransportType);
     Py_INCREF(&PyLinestackType);
     PyModule_AddObject(m, "Linestack", (PyObject *)&PyLinestackType);
+    Py_INCREF(&PyLinestackIterType);
     PyModule_AddIntConstant(m, "TO_SERVER", TO_SERVER);
     PyModule_AddIntConstant(m, "FROM_SERVER", FROM_SERVER);
 }
index 770a1b8908548b347a8687e51c2b51e40e53577a..ffa34349d22ee21d8c4eebf12d5aae48efa70391 100644 (file)
@@ -63,6 +63,7 @@ typedef struct {
     PyObject *parent;
 } PyLinestackObject;
 PyTypeObject PyLinestackType;
+PyTypeObject PyLinestackIterType;
 
 /* GList iterator */
 PyObject *py_g_list_iter(GList *list, PyObject *parent, PyObject *(*converter) (PyObject *parent, void *));
index 0f013e075a07b13dfb199965d67f47923de04b38..8e89ea7c4ccf83d61df24cae5259f9417f56a50e 100644 (file)
@@ -161,6 +161,76 @@ static PyObject *py_linestack_send(PyLinestackObject *self, PyObject *args)
     Py_RETURN_NONE;
 }
 
+typedef struct {
+    PyObject_HEAD
+    PyLinestackObject *parent;
+    guint64 from, to;
+} PyLinestackIterObject;
+
+static int py_linestack_iter_dealloc(PyLinestackIterObject *self)
+{
+    Py_DECREF(self->parent);
+    PyObject_Del(self);
+    return 0;
+}
+
+static PyObject *py_linestack_iter_next(PyLinestackIterObject *self)
+{
+    time_t time;
+    struct irc_line *line = NULL;
+    gboolean ret;
+    PyLineObject *py_line;
+    PyObject *py_ret;
+    if (self->from == self->to) {
+        PyErr_SetNone(PyExc_StopIteration);
+        return NULL;
+    }
+
+    ret = linestack_read_entry(self->parent->linestack, self->from, 
+                         &line, &time);
+    if (ret == FALSE) {
+        PyErr_SetNone(PyExc_RuntimeError);
+        return NULL;
+    }
+
+    py_line = PyObject_New(PyLineObject, &PyLineType);
+    py_line->line = line;
+
+    py_ret = Py_BuildValue("(Nl)", py_line, time);
+
+    self->from++;
+    return py_ret;
+}
+
+PyTypeObject PyLinestackIterType = {
+    .tp_name = "LinestackIter",
+    .tp_flags = Py_TPFLAGS_DEFAULT,
+    .tp_basicsize = sizeof(PyLinestackIterObject),
+    .tp_iter = PyObject_SelfIter,
+    .tp_iternext = (iternextfunc)py_linestack_iter_next,
+    .tp_dealloc = (destructor)py_linestack_iter_dealloc,
+};
+
+static PyObject *py_linestack_traverse(PyLinestackObject *self, PyObject *args)
+{
+    PyLinestackIterObject *ret;
+    ret = PyObject_New(PyLinestackIterObject, &PyLinestackIterType);
+    if (ret == NULL) {
+        PyErr_NoMemory();
+        return NULL;
+    }
+
+    Py_INCREF(self);
+    ret->parent = self;
+
+    if (!PyArg_ParseTuple(args, "LL", &ret->from, &ret->to)) {
+        Py_DECREF(ret);
+        return NULL;
+    }
+
+    return (PyObject *)ret;
+}
+
 static PyMethodDef py_linestack_methods[] = {
     { "insert_line", (PyCFunction)py_linestack_insert_line, 
         METH_VARARGS, "Insert line" },
@@ -170,6 +240,8 @@ static PyMethodDef py_linestack_methods[] = {
         METH_NOARGS, "Get marker" },
     { "send", (PyCFunction)py_linestack_send, METH_VARARGS, 
         "Send" },
+    { "traverse", (PyCFunction)py_linestack_traverse, METH_VARARGS,
+        "Traverse" },
     { NULL }
 };
 
index 97ba5e376017653fd86c0959d8f23b2956e9dd2b..a4e8575ab08308020a362bb50bf4f586a41a46df 100644 (file)
@@ -688,3 +688,13 @@ class LinestackTests(unittest.TestCase):
         state2 = self.get_state()
         ls.replay(state2, m, ls.get_marker())
         self.assertEquals(["#bla"], state2.channels.keys())
+
+    def test_traverse(self):
+        state = self.get_state()
+        ls = irc.Linestack("insert_line", True, self.get_basedir(), state)
+        m1 = ls.get_marker()
+        ls.insert_line(":somebody!some@host JOIN #bla", irc.FROM_SERVER, state)
+        ls.insert_line(":somebody!some@host PRIVMSG #bla :BAR!", 
+                       irc.FROM_SERVER, state)
+        m2 = ls.get_marker()
+        self.assertEquals([irc.Line(":somebody!some@host JOIN #bla"), irc.Line(":somebody!some@host PRIVMSG #bla :BAR!")], [l for (l, t) in ls.traverse(m1, m2)])