1 /* -*- Mode: C; c-basic-offset: 4 -*- */
9 #include <structmember.h> /* for PyMemberDef */
12 #include "pyglib-private.h"
13 #include "pygsource.h"
15 #include "pygiochannel.h"
20 int softspace; /* to make print >> chan, "foo" ... work */
23 PYGLIB_DEFINE_TYPE("gi._glib.IOChannel", PyGIOChannel_Type, PyGIOChannel)
26 py_io_channel_next(PyGIOChannel *self)
28 PyObject* ret_obj = NULL;
29 gsize length = 0, terminator_pos;
30 gchar *str_return = NULL;
34 status = g_io_channel_read_line(self->channel, &str_return, &length,
35 &terminator_pos, &error);
36 if (pyglib_error_check(&error))
39 if (status == G_IO_STATUS_EOF) {
40 PyErr_SetString(PyExc_StopIteration, "EOF");
44 ret_obj = PYGLIB_PyUnicode_FromStringAndSize(str_return, length);
50 py_io_channel_richcompare(PyObject *self, PyObject *other, int op)
52 if (Py_TYPE(self) == Py_TYPE(other) &&
53 Py_TYPE(self) == &PyGIOChannel_Type) {
54 return _pyglib_generic_ptr_richcompare(((PyGIOChannel*)self)->channel,
55 ((PyGIOChannel*)other)->channel,
58 Py_INCREF(Py_NotImplemented);
59 return Py_NotImplemented;
64 py_io_channel_get_iter(PyObject *self)
71 py_io_channel_hash(PyGIOChannel *self)
73 return (long) self->channel;
77 py_io_channel_dealloc(PyGIOChannel *self)
80 g_io_channel_unref(self->channel);
85 py_io_channel_shutdown(PyGIOChannel* self, PyObject *args, PyObject *kwargs)
87 static char *kwlist[] = { "flush", NULL };
89 PyObject* flush = Py_True;
92 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O:gi._glib.IOChannel.shutdown", kwlist, &flush))
95 ret = g_io_channel_shutdown(self->channel, PyObject_IsTrue(flush), &error);
96 if (pyglib_error_check(&error))
99 return PYGLIB_PyLong_FromLong(ret);
102 /* character encoding conversion involved functions.
106 py_io_channel_set_buffer_size(PyGIOChannel* self, PyObject *args, PyObject *kwargs)
108 static char *kwlist[] = { "size", NULL };
111 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i:gi._glib.IOChannel.set_buffer_size", kwlist, &size))
114 g_io_channel_set_buffer_size(self->channel, size);
121 py_io_channel_get_buffer_size(PyGIOChannel* self)
123 return PYGLIB_PyLong_FromLong(g_io_channel_get_buffer_size(self->channel));
127 py_io_channel_set_buffered(PyGIOChannel* self, PyObject *args, PyObject *kwargs)
129 static char *kwlist[] = { "buffered", NULL };
132 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i:gi._glib.IOChannel.set_buffered", kwlist, &buffered))
135 g_io_channel_set_buffered(self->channel, buffered);
142 py_io_channel_get_buffered(PyGIOChannel* self)
144 return PYGLIB_PyLong_FromLong(g_io_channel_get_buffered(self->channel));
148 py_io_channel_set_encoding(PyGIOChannel* self, PyObject *args, PyObject *kwargs)
150 static char *kwlist[] = { "encoding", NULL };
151 const char* encoding;
152 GError* error = NULL;
154 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "z:gi._glib.IOChannel.set_encoding", kwlist, &encoding))
157 g_io_channel_set_encoding(self->channel, encoding, &error);
158 if (pyglib_error_check(&error))
166 py_io_channel_get_encoding(PyGIOChannel* self)
168 const char* encoding = g_io_channel_get_encoding(self->channel);
170 if (encoding == NULL) {
175 return PYGLIB_PyUnicode_FromString(encoding);
178 #define CHUNK_SIZE (8 * 1024)
181 py_io_channel_read_chars(PyGIOChannel* self, PyObject *args, PyObject *kwargs)
183 static char *kwlist[] = { "max_count", NULL };
185 PyObject* ret_obj = NULL;
186 gsize total_read = 0;
187 GError* error = NULL;
188 GIOStatus status = G_IO_STATUS_NORMAL;
190 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:gi._glib.IOChannel.read", kwlist, &max_count))
194 return PYGLIB_PyUnicode_FromString("");
196 while (status == G_IO_STATUS_NORMAL
197 && (max_count == -1 || total_read < max_count)) {
203 buf_size = CHUNK_SIZE;
205 buf_size = max_count - total_read;
206 if (buf_size > CHUNK_SIZE)
207 buf_size = CHUNK_SIZE;
210 if ( ret_obj == NULL ) {
211 ret_obj = PYGLIB_PyBytes_FromStringAndSize((char *)NULL, buf_size);
215 else if (buf_size + total_read > PYGLIB_PyBytes_Size(ret_obj)) {
216 if (PYGLIB_PyBytes_Resize(&ret_obj, buf_size + total_read) == -1)
220 buf = PYGLIB_PyBytes_AsString(ret_obj) + total_read;
222 pyglib_unblock_threads();
223 status = g_io_channel_read_chars(self->channel, buf, buf_size,
224 &single_read, &error);
225 pyglib_block_threads();
226 if (pyglib_error_check(&error))
229 total_read += single_read;
232 if ( total_read != PYGLIB_PyBytes_Size(ret_obj) ) {
233 if (PYGLIB_PyBytes_Resize(&ret_obj, total_read) == -1)
237 #if PY_VERSION_HEX >= 0x03000000
238 /* If this is not UTF8 encoded channel return the raw bytes */
239 if (g_io_channel_get_encoding(self->channel) != NULL)
242 /* convert to Unicode string */
244 PyObject *unicode_obj;
246 unicode_obj = PyUnicode_FromString(PyBytes_AS_STRING(ret_obj));
247 if (unicode_obj == NULL)
250 ret_obj = unicode_obj;
262 py_io_channel_write_chars(PyGIOChannel* self, PyObject *args, PyObject *kwargs)
264 static char *kwlist[] = { "buf", NULL };
268 GError* error = NULL;
271 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#:gi._glib.IOChannel.write",
272 kwlist, &buf, &buf_len))
275 pyglib_unblock_threads();
276 status = g_io_channel_write_chars(self->channel, buf, buf_len, &count, &error);
277 pyglib_block_threads();
278 if (pyglib_error_check(&error))
281 return PYGLIB_PyLong_FromLong(count);
285 py_io_channel_write_lines(PyGIOChannel* self, PyObject *args, PyObject *kwargs)
287 static char *kwlist[] = { "lines", NULL };
291 GError* error = NULL;
293 PyObject *iter, *value, *pylines;
295 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O:gi._glib.IOChannel.writelines",
299 iter = PyObject_GetIter(pylines);
302 value = PyIter_Next(iter);
303 if (PyErr_ExceptionMatches(PyExc_StopIteration)) {
307 if (!PYGLIB_PyUnicode_Check(value)) {
308 PyErr_SetString(PyExc_TypeError, "gi._glib.IOChannel.writelines must"
309 " be sequence/iterator of strings");
313 PYGLIB_PyUnicode_AsStringAndSize(value, &buf, &buf_len);
314 pyglib_unblock_threads();
315 status = g_io_channel_write_chars(self->channel, buf, buf_len, &count, &error);
316 pyglib_unblock_threads();
318 if (pyglib_error_check(&error)) {
330 py_io_channel_flush(PyGIOChannel* self)
332 GError* error = NULL;
335 pyglib_unblock_threads();
336 status = g_io_channel_flush(self->channel, &error);
337 pyglib_block_threads();
338 if (pyglib_error_check(&error))
341 return PYGLIB_PyLong_FromLong(status);
345 py_io_channel_set_flags(PyGIOChannel* self, PyObject *args, PyObject *kwargs)
347 static char *kwlist[] = { "flags", NULL };
350 GError* error = NULL;
352 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i:gi._glib.IOChannel.set_flags",
356 status = g_io_channel_set_flags(self->channel, flags, &error);
357 if (pyglib_error_check(&error))
360 return PYGLIB_PyLong_FromLong(status);
364 py_io_channel_get_flags(PyGIOChannel* self)
366 return PYGLIB_PyLong_FromLong(g_io_channel_get_flags(self->channel));
370 py_io_channel_get_buffer_condition(PyGIOChannel* self)
372 return PYGLIB_PyLong_FromLong(g_io_channel_get_buffer_condition(self->channel));
376 py_io_channel_set_close_on_unref(PyGIOChannel* self, PyObject *args, PyObject *kwargs)
378 static char *kwlist[] = { "do_close", NULL };
381 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O:gi._glib.IOChannel.set_close_on_unref",
385 g_io_channel_set_close_on_unref(self->channel, PyObject_IsTrue(do_close));
391 py_io_channel_get_close_on_unref(PyGIOChannel* self)
393 if (g_io_channel_get_close_on_unref(self->channel)) {
409 pyg_iowatch_data_free(PyGIOWatchData *data)
411 Py_DECREF(data->callback);
412 Py_XDECREF(data->user_data);
413 Py_DECREF(data->iochannel);
414 g_slice_free(PyGIOWatchData, data);
418 pyg_iowatch_marshal(GIOChannel *source,
419 GIOCondition condition,
424 PyGIOWatchData *data = (PyGIOWatchData *) user_data;
425 PyGILState_STATE state;
427 g_return_val_if_fail(user_data != NULL, FALSE);
428 g_return_val_if_fail(((PyGIOChannel *) data->iochannel)->channel == source,
431 state = pyglib_gil_state_ensure();
434 ret = PyObject_CallFunction(data->callback, "OiO", data->iochannel,
435 condition, data->user_data);
437 ret = PyObject_CallFunction(data->callback, "Oi", data->iochannel,
444 res = PyObject_IsTrue(ret);
447 pyglib_gil_state_release(state);
455 py_io_channel_add_watch(PyObject *self, PyObject *args, PyObject *kwargs)
457 static char *kwlist[] = { "condition", "callback", "user_data", "priority", NULL };
458 PyObject *callback, *user_data = NULL;
459 int priority = G_PRIORITY_DEFAULT, condition;
460 GIOChannel *iochannel = NULL;
462 PyGIOWatchData *data;
464 if (!PyArg_ParseTupleAndKeywords(args, kwargs,
465 "iO|Oi:gi._glib.IOChannel.add_watch",
466 kwlist, &condition, &callback,
467 &user_data, &priority))
470 iochannel = ((PyGIOChannel *) self)->channel;
472 if (!PyCallable_Check(callback)) {
473 PyErr_SetString(PyExc_TypeError, "second must be callable");
477 data = g_slice_new(PyGIOWatchData);
478 data->callback = callback; Py_INCREF(callback);
479 data->user_data = user_data; Py_XINCREF(user_data);
480 data->iochannel = self; Py_INCREF(self);
482 handler_id = g_io_add_watch_full(iochannel,
484 pyg_iowatch_marshal, data,
485 (GDestroyNotify) pyg_iowatch_data_free);
486 return PyLong_FromUnsignedLong(handler_id);
493 py_io_channel_win32_poll(PyObject *self, PyObject *args, PyObject *kwargs)
495 static char *kwlist[] = { "fds", "timeout", NULL };
497 PyObject *pyfds, *pyfd;
502 if (!PyArg_ParseTupleAndKeywords(args, kwargs,
503 "O!|i:gi._glib.IOChannel.win32_poll",
504 kwlist, &PyList_Type, &pyfds, &timeout))
507 len = PyList_Size(pyfds);
508 pollfd = g_newa(GPollFD, len);
509 for (i = 0; i < len; ++i) {
510 pyfd = PyList_GET_ITEM(pyfds, i);
511 if (!PyObject_TypeCheck(pyfd, &PyGPollFD_Type)) {
512 PyErr_SetString(PyExc_TypeError, "'fds' must be a list of gi._glib.PollFD objects");
515 pollfd[i] = ((PyGPollFD *) pyfd)->pollfd;
518 result = g_io_channel_win32_poll(pollfd, len, timeout);
519 for (i = 0; i < len; ++i) {
520 pyfd = PyList_GET_ITEM(pyfds, i);
521 ((PyGPollFD *) pyfd)->pollfd = pollfd[i];
523 return PYGLIB_PyLong_FromLong(result);
527 py_io_channel_win32_make_pollfd(PyObject *self, PyObject *args, PyObject *kwargs)
529 static char *kwlist[] = { "condition", NULL };
534 if (!PyArg_ParseTupleAndKeywords(args, kwargs,
535 "i:gi._glib.IOChannel.win32_make_pollfd",
539 g_io_channel_win32_make_pollfd(((PyGIOChannel *) self)->channel,
541 pypollfd = PyObject_NEW(PyGPollFD, &PyGPollFD_Type);
542 pypollfd->pollfd = pollfd;
543 return (PyObject *) pypollfd;
545 #endif /* def G_OS_WIN32 */
549 py_io_channel_read_line(PyGIOChannel* self, PyObject *args, PyObject *kwargs)
551 static char *kwlist[] = { "size", NULL };
552 PyObject* ret_obj = NULL;
553 gsize length = 0, terminator_pos;
554 gchar *str_return = NULL;
555 GError *error = NULL;
559 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:gi._glib.IOChannel.readline", kwlist,
563 status = g_io_channel_read_line(self->channel, &str_return, &length,
564 &terminator_pos, &error);
565 if (pyglib_error_check(&error))
567 ret_obj = PYGLIB_PyUnicode_FromStringAndSize(str_return, length);
573 py_io_channel_read_lines(PyGIOChannel* self, PyObject *args, PyObject *kwargs)
575 static char *kwlist[] = { "size", NULL };
576 PyObject *line = NULL;
577 gsize length = 0, terminator_pos;
578 gchar *str_return = NULL;
579 GError *error = NULL;
581 GIOStatus status = G_IO_STATUS_NORMAL;
584 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:gi._glib.IOChannel.readlines", kwlist,
588 list = PyList_New(0);
589 while (status == G_IO_STATUS_NORMAL) {
590 status = g_io_channel_read_line(self->channel, &str_return, &length,
591 &terminator_pos, &error);
592 if (pyglib_error_check(&error)) {
596 line = PYGLIB_PyUnicode_FromStringAndSize(str_return, length);
598 if (PyList_Append(list, line)) {
609 py_io_channel_seek(PyGIOChannel* self, PyObject *args, PyObject *kwargs)
611 static char *kwlist[] = { "offset", "whence", NULL };
616 GError* error = NULL;
618 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "L|i:gi._glib.IOChannel.seek",
619 kwlist, &offset, &whence))
624 case 0: seek_type = G_SEEK_SET; break;
625 case 1: seek_type = G_SEEK_CUR; break;
626 case 2: seek_type = G_SEEK_END; break;
628 PyErr_SetString(PyExc_ValueError, "invalid 'whence' value");
632 status = g_io_channel_seek_position(self->channel, offset,
634 if (pyglib_error_check(&error))
637 return PYGLIB_PyLong_FromLong(status);
641 void g_io_channel_set_line_term (GIOChannel *channel,
642 const gchar *line_term,
645 G_CONST_RETURN gchar* g_io_channel_get_line_term (GIOChannel *channel,
650 GIOStatus g_io_channel_read_line_string (GIOChannel *channel,
652 gsize *terminator_pos,
654 GIOStatus g_io_channel_read_to_end (GIOChannel *channel,
658 GIOStatus g_io_channel_read_unichar (GIOChannel *channel,
661 GIOStatus g_io_channel_write_unichar (GIOChannel *channel,
664 #endif // Not wrapped
666 static PyMemberDef py_io_channel_members[] = {
667 { "softspace", T_INT, offsetof(PyGIOChannel, softspace), 0, NULL },
668 { NULL, 0, 0, 0, NULL }
671 static PyMethodDef py_io_channel_methods[] = {
672 { "close", (PyCFunction)py_io_channel_shutdown, METH_VARARGS|METH_KEYWORDS },
673 { "flush", (PyCFunction)py_io_channel_flush, METH_NOARGS },
674 { "set_encoding", (PyCFunction)py_io_channel_set_encoding, METH_VARARGS|METH_KEYWORDS },
675 { "get_encoding", (PyCFunction)py_io_channel_get_encoding, METH_NOARGS },
676 { "set_buffered", (PyCFunction)py_io_channel_set_buffered, METH_VARARGS|METH_KEYWORDS },
677 { "get_buffered", (PyCFunction)py_io_channel_get_buffered, METH_NOARGS },
678 { "set_buffer_size", (PyCFunction)py_io_channel_set_buffer_size, METH_VARARGS|METH_KEYWORDS },
679 { "get_buffer_size", (PyCFunction)py_io_channel_get_buffer_size, METH_NOARGS },
680 { "read", (PyCFunction)py_io_channel_read_chars, METH_VARARGS|METH_KEYWORDS },
681 { "readline", (PyCFunction)py_io_channel_read_line, METH_VARARGS|METH_KEYWORDS },
682 { "readlines", (PyCFunction)py_io_channel_read_lines, METH_VARARGS|METH_KEYWORDS },
683 { "write", (PyCFunction)py_io_channel_write_chars, METH_VARARGS|METH_KEYWORDS },
684 { "writelines", (PyCFunction)py_io_channel_write_lines, METH_VARARGS|METH_KEYWORDS },
685 { "set_flags", (PyCFunction)py_io_channel_set_flags, METH_VARARGS|METH_KEYWORDS },
686 { "get_flags", (PyCFunction)py_io_channel_get_flags, METH_NOARGS },
687 { "get_buffer_condition", (PyCFunction)py_io_channel_get_buffer_condition, METH_NOARGS },
688 { "set_close_on_unref", (PyCFunction)py_io_channel_set_close_on_unref, METH_VARARGS | METH_KEYWORDS },
689 { "get_close_on_unref", (PyCFunction)py_io_channel_get_close_on_unref, METH_NOARGS },
690 { "add_watch", (PyCFunction)py_io_channel_add_watch, METH_VARARGS|METH_KEYWORDS },
691 { "seek", (PyCFunction)py_io_channel_seek, METH_VARARGS|METH_KEYWORDS },
693 { "win32_make_pollfd", (PyCFunction)py_io_channel_win32_make_pollfd, METH_VARARGS | METH_KEYWORDS },
694 { "win32_poll", (PyCFunction)py_io_channel_win32_poll, METH_VARARGS|METH_KEYWORDS|METH_STATIC },
701 py_io_channel_init(PyGIOChannel *self, PyObject *args, PyObject *kwargs)
703 static char *kwlist[] = { "filedes", "filename", "mode",
709 char *mode = "r", *filename = NULL;
710 GError *error = NULL;
715 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|iss"
719 ":gi._glib.IOChannel.__init__",
720 kwlist, &fd, &filename, &mode
728 self->channel = g_io_channel_unix_new(fd);
729 else if (filename != NULL) {
730 self->channel = g_io_channel_new_file(filename, mode, &error);
731 if (pyglib_error_check(&error))
735 else if (hwnd != 0) {
736 self->channel = g_io_channel_win32_new_messages(hwnd);
741 PyErr_SetString(PyExc_TypeError, "either a valid file descriptor, "
742 "file name, or window handle must be supplied");
744 PyErr_SetString(PyExc_TypeError, "either a valid file descriptor "
745 "or file name must be supplied");
753 pyglib_iochannel_register_types(PyObject *d)
755 PyGIOChannel_Type.tp_init = (initproc)py_io_channel_init;
756 PyGIOChannel_Type.tp_dealloc = (destructor)py_io_channel_dealloc;
757 PyGIOChannel_Type.tp_flags = Py_TPFLAGS_DEFAULT;
758 PyGIOChannel_Type.tp_members = py_io_channel_members;
759 PyGIOChannel_Type.tp_methods = py_io_channel_methods;
760 PyGIOChannel_Type.tp_hash = (hashfunc)py_io_channel_hash;
761 PyGIOChannel_Type.tp_richcompare = (richcmpfunc)py_io_channel_richcompare;
762 PyGIOChannel_Type.tp_iter = (getiterfunc)py_io_channel_get_iter;
763 PyGIOChannel_Type.tp_iternext = (iternextfunc)py_io_channel_next;
765 PYGLIB_REGISTER_TYPE(d, PyGIOChannel_Type, "IOChannel");