+ return PyBool_FromLong(r);
+}
+
+
+static int extract(const char* msg, size_t msg_len,
+ PyObject **key, PyObject **value) {
+ PyObject *k = NULL, *v;
+ const char *delim_ptr;
+
+ delim_ptr = memchr(msg, '=', msg_len);
+ if (!delim_ptr) {
+ PyErr_SetString(PyExc_OSError,
+ "journal gave us a field without '='");
+ return -1;
+ }
+
+ if (key) {
+ k = unicode_FromStringAndSize(msg, delim_ptr - (const char*) msg);
+ if (!k)
+ return -1;
+ }
+
+ if (value) {
+ v = PyBytes_FromStringAndSize(delim_ptr + 1,
+ (const char*) msg + msg_len - (delim_ptr + 1));
+ if (!v) {
+ Py_XDECREF(k);
+ return -1;
+ }
+
+ *value = v;
+ }
+
+ if (key)
+ *key = k;
+
+ return 0;
+}
+
+PyDoc_STRVAR(Reader_get__doc__,
+ "get(str) -> str\n\n"
+ "Return data associated with this key in current log entry.\n"
+ "Throws KeyError is the data is not available.");
+static PyObject* Reader_get(Reader *self, PyObject *args)
+{
+ const char* field;
+ const void* msg;
+ size_t msg_len;
+ PyObject *value;
+ int r;
+
+ assert(self);
+ assert(args);
+
+ if (!PyArg_ParseTuple(args, "s:get", &field))
+ return NULL;
+
+ r = sd_journal_get_data(self->j, field, &msg, &msg_len);
+ if (r == -ENOENT) {
+ PyErr_SetString(PyExc_KeyError, field);
+ return NULL;
+ } else if (set_error(r, NULL, "field name is not valid"))
+ return NULL;
+
+ r = extract(msg, msg_len, NULL, &value);
+ if (r < 0)
+ return NULL;
+ return value;
+}
+
+
+PyDoc_STRVAR(Reader_get_next__doc__,
+ "get_next([skip]) -> dict\n\n"
+ "Return dictionary of the next log entry. Optional skip value will\n"
+ "return the `skip`\\-th log entry. Returns an empty dict on EOF.");
+static PyObject* Reader_get_next(Reader *self, PyObject *args)
+{
+ PyObject _cleanup_Py_DECREF_ *tmp = NULL;
+ PyObject *dict;
+ const void *msg;
+ size_t msg_len;
+ int r;
+
+ tmp = Reader_next(self, args);
+ if (!tmp)
+ return NULL;
+ if (tmp == Py_False) /* EOF */