+ Py_INCREF(self);
+ return self;
+}
+
+PyDoc_STRVAR(Reader___exit____doc__,
+ "__exit__(type, value, traceback) -> None\n\n"
+ "Part of the context manager protocol.\n"
+ "Closes the journal.\n");
+static PyObject* Reader___exit__(Reader *self, PyObject *args) {
+ return Reader_close(self, NULL);
+}
+
+PyDoc_STRVAR(Reader_next__doc__,
+ "next([skip]) -> bool\n\n"
+ "Go to the next log entry. Optional skip value means to go to\n"
+ "the `skip`\\-th log entry.\n"
+ "Returns False if at end of file, True otherwise.");
+static PyObject* Reader_next(Reader *self, PyObject *args) {
+ int64_t skip = 1LL;
+ int r;
+
+ if (!PyArg_ParseTuple(args, "|L:next", &skip))
+ return NULL;
+
+ if (skip == 0LL) {
+ PyErr_SetString(PyExc_ValueError, "skip must be nonzero");
+ return NULL;
+ }
+
+ Py_BEGIN_ALLOW_THREADS
+ if (skip == 1LL)
+ r = sd_journal_next(self->j);
+ else if (skip == -1LL)
+ r = sd_journal_previous(self->j);
+ else if (skip > 1LL)
+ r = sd_journal_next_skip(self->j, skip);
+ else if (skip < -1LL)
+ r = sd_journal_previous_skip(self->j, -skip);
+ else
+ assert_not_reached("should not be here");
+ Py_END_ALLOW_THREADS
+
+ if (set_error(r, NULL, NULL) < 0)
+ return NULL;
+ return PyBool_FromLong(r);
+}
+
+PyDoc_STRVAR(Reader_previous__doc__,
+ "previous([skip]) -> bool\n\n"
+ "Go to the previous log entry. Optional skip value means to \n"
+ "go to the `skip`\\-th previous log entry.\n"
+ "Returns False if at start of file, True otherwise.");
+static PyObject* Reader_previous(Reader *self, PyObject *args) {
+ int64_t skip = 1LL;
+ if (!PyArg_ParseTuple(args, "|L:previous", &skip))
+ return NULL;
+
+ return PyObject_CallMethod((PyObject *)self, (char*) "_next",
+ (char*) "L", -skip);
+}
+
+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;
+ }
+ if (set_error(r, NULL, "field name is not valid") < 0)
+ return NULL;
+
+ r = extract(msg, msg_len, NULL, &value);
+ if (r < 0)
+ return NULL;
+ return value;
+}
+
+PyDoc_STRVAR(Reader_get_all__doc__,
+ "_get_all() -> dict\n\n"
+ "Return dictionary of the current log entry.");
+static PyObject* Reader_get_all(Reader *self, PyObject *args) {
+ PyObject *dict;
+ const void *msg;
+ size_t msg_len;
+ int r;
+
+ dict = PyDict_New();
+ if (!dict)
+ return NULL;
+
+ SD_JOURNAL_FOREACH_DATA(self->j, msg, msg_len) {
+ _cleanup_Py_DECREF_ PyObject *key = NULL, *value = NULL;
+
+ r = extract(msg, msg_len, &key, &value);
+ if (r < 0)
+ goto error;
+
+ if (PyDict_Contains(dict, key)) {
+ PyObject *cur_value = PyDict_GetItem(dict, key);
+
+ if (PyList_CheckExact(cur_value)) {
+ r = PyList_Append(cur_value, value);
+ if (r < 0)
+ goto error;
+ } else {
+ _cleanup_Py_DECREF_ PyObject *tmp_list = PyList_New(0);
+ if (!tmp_list)
+ goto error;
+
+ r = PyList_Append(tmp_list, cur_value);
+ if (r < 0)
+ goto error;
+
+ r = PyList_Append(tmp_list, value);
+ if (r < 0)
+ goto error;
+
+ r = PyDict_SetItem(dict, key, tmp_list);
+ if (r < 0)
+ goto error;
+ }
+ } else {
+ r = PyDict_SetItem(dict, key, value);
+ if (r < 0)
+ goto error;
+ }
+ }
+
+ return dict;
+
+error:
+ Py_DECREF(dict);