1 /*-*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Steven Hiscocks, Zbigniew Jędrzejewski-Szmek
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
23 #include <structmember.h>
27 #include <systemd/sd-journal.h>
37 static PyTypeObject ReaderType;
39 static int set_error(int r, const char* path, const char* invalid_message) {
42 if (r == -EINVAL && invalid_message)
43 PyErr_SetString(PyExc_ValueError, invalid_message);
44 else if (r == -ENOMEM)
45 PyErr_SetString(PyExc_MemoryError, "Not enough memory");
48 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
54 PyDoc_STRVAR(module__doc__,
55 "Class to reads the systemd journal similar to journalctl.");
58 #if PY_MAJOR_VERSION >= 3
59 static PyTypeObject MonotonicType;
61 PyDoc_STRVAR(MonotonicType__doc__,
62 "A tuple of (timestamp, bootid) for holding monotonic timestamps");
64 static PyStructSequence_Field MonotonicType_fields[] = {
65 {(char*) "timestamp", (char*) "Time"},
66 {(char*) "bootid", (char*) "Unique identifier of the boot"},
70 static PyStructSequence_Desc Monotonic_desc = {
71 (char*) "journal.Monotonic",
79 static void Reader_dealloc(Reader* self)
81 sd_journal_close(self->j);
82 Py_TYPE(self)->tp_free((PyObject*)self);
85 PyDoc_STRVAR(Reader__doc__,
86 "_Reader([flags | path]) -> ...\n\n"
87 "_Reader allows filtering and retrieval of Journal entries.\n"
88 "Note: this is a low-level interface, and probably not what you\n"
89 "want, use systemd.journal.Reader instead.\n\n"
90 "Argument `flags` sets open flags of the journal, which can be one\n"
91 "of, or ORed combination of constants: LOCAL_ONLY (default) opens\n"
92 "journal on local machine only; RUNTIME_ONLY opens only\n"
93 "volatile journal files; and SYSTEM_ONLY opens only\n"
94 "journal files of system services and the kernel.\n\n"
95 "Argument `path` is the directory of journal files. Note that\n"
96 "`flags` and `path` are exclusive.\n\n"
97 "_Reader implements the context manager protocol: the journal\n"
98 "will be closed when exiting the block.");
99 static int Reader_init(Reader *self, PyObject *args, PyObject *keywds)
104 static const char* const kwlist[] = {"flags", "path", NULL};
105 if (!PyArg_ParseTupleAndKeywords(args, keywds, "|iz", (char**) kwlist,
110 flags = SD_JOURNAL_LOCAL_ONLY;
113 PyErr_SetString(PyExc_ValueError, "cannot use both flags and path");
117 Py_BEGIN_ALLOW_THREADS
119 r = sd_journal_open_directory(&self->j, path, 0);
121 r = sd_journal_open(&self->j, flags);
124 return set_error(r, path, "Invalid flags or path");
128 PyDoc_STRVAR(Reader_fileno__doc__,
129 "fileno() -> int\n\n"
130 "Get a file descriptor to poll for changes in the journal.\n"
131 "This method invokes sd_journal_get_fd().\n"
132 "See man:sd_journal_get_fd(3).");
133 static PyObject* Reader_fileno(Reader *self, PyObject *args)
136 fd = sd_journal_get_fd(self->j);
137 set_error(fd, NULL, NULL);
140 return long_FromLong(fd);
144 PyDoc_STRVAR(Reader_reliable_fd__doc__,
145 "reliable_fd() -> bool\n\n"
146 "Returns True iff the journal can be polled reliably.\n"
147 "This method invokes sd_journal_reliable_fd().\n"
148 "See man:sd_journal_reliable_fd(3).");
149 static PyObject* Reader_reliable_fd(Reader *self, PyObject *args)
152 r = sd_journal_reliable_fd(self->j);
153 set_error(r, NULL, NULL);
156 return PyBool_FromLong(r);
160 PyDoc_STRVAR(Reader_close__doc__,
161 "close() -> None\n\n"
162 "Free resources allocated by this Reader object.\n"
163 "This method invokes sd_journal_close().\n"
164 "See man:sd_journal_close(3).");
165 static PyObject* Reader_close(Reader *self, PyObject *args)
170 sd_journal_close(self->j);
176 PyDoc_STRVAR(Reader_get_usage__doc__,
177 "get_usage() -> int\n\n"
178 "Returns the total disk space currently used by journal\n"
179 "files (in bytes). If `SD_JOURNAL_LOCAL_ONLY` was\n"
180 "passed when opening the journal this value will only reflect\n"
181 "the size of journal files of the local host, otherwise\n"
183 "This method invokes sd_journal_get_usage().\n"
184 "See man:sd_journal_get_usage(3).");
185 static PyObject* Reader_get_usage(Reader *self, PyObject *args)
190 r = sd_journal_get_usage(self->j, &bytes);
191 if (set_error(r, NULL, NULL))
194 assert_cc(sizeof(unsigned long long) == sizeof(bytes));
195 return PyLong_FromUnsignedLongLong(bytes);
199 PyDoc_STRVAR(Reader___enter____doc__,
200 "__enter__() -> self\n\n"
201 "Part of the context manager protocol.\n"
203 static PyObject* Reader___enter__(PyObject *self, PyObject *args)
212 PyDoc_STRVAR(Reader___exit____doc__,
213 "__exit__(type, value, traceback) -> None\n\n"
214 "Part of the context manager protocol.\n"
215 "Closes the journal.\n");
216 static PyObject* Reader___exit__(Reader *self, PyObject *args)
220 sd_journal_close(self->j);
226 PyDoc_STRVAR(Reader_next__doc__,
227 "next([skip]) -> bool\n\n"
228 "Go to the next log entry. Optional skip value means to go to\n"
229 "the `skip`\\-th log entry.\n"
230 "Returns False if at end of file, True otherwise.");
231 static PyObject* Reader_next(Reader *self, PyObject *args)
236 if (!PyArg_ParseTuple(args, "|L:next", &skip))
240 PyErr_SetString(PyExc_ValueError, "skip must be nonzero");
244 Py_BEGIN_ALLOW_THREADS
246 r = sd_journal_next(self->j);
247 else if (skip == -1LL)
248 r = sd_journal_previous(self->j);
250 r = sd_journal_next_skip(self->j, skip);
251 else if (skip < -1LL)
252 r = sd_journal_previous_skip(self->j, -skip);
254 assert_not_reached("should not be here");
257 set_error(r, NULL, NULL);
260 return PyBool_FromLong(r);
264 static int extract(const char* msg, size_t msg_len,
265 PyObject **key, PyObject **value) {
266 PyObject *k = NULL, *v;
267 const char *delim_ptr;
269 delim_ptr = memchr(msg, '=', msg_len);
271 PyErr_SetString(PyExc_OSError,
272 "journal gave us a field without '='");
277 k = unicode_FromStringAndSize(msg, delim_ptr - (const char*) msg);
283 v = PyBytes_FromStringAndSize(delim_ptr + 1,
284 (const char*) msg + msg_len - (delim_ptr + 1));
299 PyDoc_STRVAR(Reader_get__doc__,
300 "get(str) -> str\n\n"
301 "Return data associated with this key in current log entry.\n"
302 "Throws KeyError is the data is not available.");
303 static PyObject* Reader_get(Reader *self, PyObject *args)
314 if (!PyArg_ParseTuple(args, "s:get", &field))
317 r = sd_journal_get_data(self->j, field, &msg, &msg_len);
319 PyErr_SetString(PyExc_KeyError, field);
321 } else if (set_error(r, NULL, "field name is not valid"))
324 r = extract(msg, msg_len, NULL, &value);
331 PyDoc_STRVAR(Reader_get_next__doc__,
332 "get_next([skip]) -> dict\n\n"
333 "Return dictionary of the next log entry. Optional skip value will\n"
334 "return the `skip`\\-th log entry. Returns an empty dict on EOF.");
335 static PyObject* Reader_get_next(Reader *self, PyObject *args)
337 PyObject _cleanup_Py_DECREF_ *tmp = NULL;
343 tmp = Reader_next(self, args);
346 if (tmp == Py_False) /* EOF */
353 SD_JOURNAL_FOREACH_DATA(self->j, msg, msg_len) {
354 PyObject _cleanup_Py_DECREF_ *key = NULL, *value = NULL;
356 r = extract(msg, msg_len, &key, &value);
360 if (PyDict_Contains(dict, key)) {
361 PyObject *cur_value = PyDict_GetItem(dict, key);
363 if (PyList_CheckExact(cur_value)) {
364 r = PyList_Append(cur_value, value);
368 PyObject _cleanup_Py_DECREF_ *tmp_list = PyList_New(0);
372 r = PyList_Append(tmp_list, cur_value);
376 r = PyList_Append(tmp_list, value);
380 r = PyDict_SetItem(dict, key, tmp_list);
385 r = PyDict_SetItem(dict, key, value);
399 PyDoc_STRVAR(Reader_get_realtime__doc__,
400 "get_realtime() -> int\n\n"
401 "Return the realtime timestamp for the current journal entry\n"
402 "in microseconds.\n\n"
403 "Wraps sd_journal_get_realtime_usec().\n"
404 "See man:sd_journal_get_realtime_usec(3).");
405 static PyObject* Reader_get_realtime(Reader *self, PyObject *args)
413 r = sd_journal_get_realtime_usec(self->j, ×tamp);
414 if (set_error(r, NULL, NULL))
417 assert_cc(sizeof(unsigned long long) == sizeof(timestamp));
418 return PyLong_FromUnsignedLongLong(timestamp);
422 PyDoc_STRVAR(Reader_get_monotonic__doc__,
423 "get_monotonic() -> (timestamp, bootid)\n\n"
424 "Return the monotonic timestamp for the current journal entry\n"
425 "as a tuple of time in microseconds and bootid.\n\n"
426 "Wraps sd_journal_get_monotonic_usec().\n"
427 "See man:sd_journal_get_monotonic_usec(3).");
428 static PyObject* Reader_get_monotonic(Reader *self, PyObject *args)
432 PyObject *monotonic, *bootid, *tuple;
438 r = sd_journal_get_monotonic_usec(self->j, ×tamp, &id);
439 if (set_error(r, NULL, NULL))
442 assert_cc(sizeof(unsigned long long) == sizeof(timestamp));
443 monotonic = PyLong_FromUnsignedLongLong(timestamp);
444 bootid = PyBytes_FromStringAndSize((const char*) &id.bytes, sizeof(id.bytes));
445 #if PY_MAJOR_VERSION >= 3
446 tuple = PyStructSequence_New(&MonotonicType);
448 tuple = PyTuple_New(2);
450 if (!monotonic || !bootid || !tuple) {
451 Py_XDECREF(monotonic);
457 #if PY_MAJOR_VERSION >= 3
458 PyStructSequence_SET_ITEM(tuple, 0, monotonic);
459 PyStructSequence_SET_ITEM(tuple, 1, bootid);
461 PyTuple_SET_ITEM(tuple, 0, monotonic);
462 PyTuple_SET_ITEM(tuple, 1, bootid);
469 PyDoc_STRVAR(Reader_get_previous__doc__,
470 "get_previous([skip]) -> dict\n\n"
471 "Return dictionary of the previous log entry. Optional skip value\n"
472 "will return the -`skip`\\-th log entry. Equivalent to get_next(-skip).");
473 static PyObject* Reader_get_previous(Reader *self, PyObject *args)
476 if (!PyArg_ParseTuple(args, "|L:get_previous", &skip))
479 return PyObject_CallMethod((PyObject *)self, (char*) "get_next",
484 PyDoc_STRVAR(Reader_add_match__doc__,
485 "add_match(match) -> None\n\n"
486 "Add a match to filter journal log entries. All matches of different\n"
487 "fields are combined with logical AND, and matches of the same field\n"
488 "are automatically combined with logical OR.\n"
489 "Match is a string of the form \"FIELD=value\".");
490 static PyObject* Reader_add_match(Reader *self, PyObject *args, PyObject *keywds)
494 if (!PyArg_ParseTuple(args, "s#:add_match", &match, &match_len))
497 r = sd_journal_add_match(self->j, match, match_len);
498 set_error(r, NULL, "Invalid match");
506 PyDoc_STRVAR(Reader_add_disjunction__doc__,
507 "add_disjunction() -> None\n\n"
508 "Inserts a logical OR between matches added before and afterwards.");
509 static PyObject* Reader_add_disjunction(Reader *self, PyObject *args)
512 r = sd_journal_add_disjunction(self->j);
513 set_error(r, NULL, NULL);
520 PyDoc_STRVAR(Reader_flush_matches__doc__,
521 "flush_matches() -> None\n\n"
522 "Clear all current match filters.");
523 static PyObject* Reader_flush_matches(Reader *self, PyObject *args)
525 sd_journal_flush_matches(self->j);
530 PyDoc_STRVAR(Reader_seek_head__doc__,
531 "seek_head() -> None\n\n"
532 "Jump to the beginning of the journal.\n"
533 "This method invokes sd_journal_seek_head().\n"
534 "See man:sd_journal_seek_head(3).");
535 static PyObject* Reader_seek_head(Reader *self, PyObject *args)
538 Py_BEGIN_ALLOW_THREADS
539 r = sd_journal_seek_head(self->j);
541 if (set_error(r, NULL, NULL))
547 PyDoc_STRVAR(Reader_seek_tail__doc__,
548 "seek_tail() -> None\n\n"
549 "Jump to the end of the journal.\n"
550 "This method invokes sd_journal_seek_tail().\n"
551 "See man:sd_journal_seek_tail(3).");
552 static PyObject* Reader_seek_tail(Reader *self, PyObject *args)
555 Py_BEGIN_ALLOW_THREADS
556 r = sd_journal_seek_tail(self->j);
558 if (set_error(r, NULL, NULL))
564 PyDoc_STRVAR(Reader_seek_realtime__doc__,
565 "seek_realtime(realtime) -> None\n\n"
566 "Seek to nearest matching journal entry to `realtime`. Argument\n"
567 "`realtime` in specified in seconds.");
568 static PyObject* Reader_seek_realtime(Reader *self, PyObject *args)
573 if (!PyArg_ParseTuple(args, "K:seek_realtime", ×tamp))
576 Py_BEGIN_ALLOW_THREADS
577 r = sd_journal_seek_realtime_usec(self->j, timestamp);
579 if (set_error(r, NULL, NULL))
585 PyDoc_STRVAR(Reader_seek_monotonic__doc__,
586 "seek_monotonic(monotonic[, bootid]) -> None\n\n"
587 "Seek to nearest matching journal entry to `monotonic`. Argument\n"
588 "`monotonic` is an timestamp from boot in microseconds.\n"
589 "Argument `bootid` is a string representing which boot the\n"
590 "monotonic time is reference to. Defaults to current bootid.");
591 static PyObject* Reader_seek_monotonic(Reader *self, PyObject *args)
598 if (!PyArg_ParseTuple(args, "K|z:seek_monotonic", ×tamp, &bootid))
602 r = sd_id128_from_string(bootid, &id);
603 if (set_error(r, NULL, "Invalid bootid"))
606 Py_BEGIN_ALLOW_THREADS
607 r = sd_id128_get_boot(&id);
609 if (set_error(r, NULL, NULL))
613 Py_BEGIN_ALLOW_THREADS
614 r = sd_journal_seek_monotonic_usec(self->j, id, timestamp);
616 if (set_error(r, NULL, NULL))
623 PyDoc_STRVAR(Reader_wait__doc__,
624 "wait([timeout]) -> state change (integer)\n\n"
625 "Wait for a change in the journal. Argument `timeout` specifies\n"
626 "the maximum number of microseconds to wait before returning\n"
627 "regardless of wheter the journal has changed. If `timeout` is -1,\n"
628 "then block forever.\n\n"
629 "Will return constants: NOP if no change; APPEND if new\n"
630 "entries have been added to the end of the journal; and\n"
631 "INVALIDATE if journal files have been added or removed.\n\n"
632 "See man:sd_journal_wait(3) for further discussion.");
633 static PyObject* Reader_wait(Reader *self, PyObject *args)
638 if (!PyArg_ParseTuple(args, "|L:wait", &timeout))
641 Py_BEGIN_ALLOW_THREADS
642 r = sd_journal_wait(self->j, timeout);
644 if (set_error(r, NULL, NULL) < 0)
647 return long_FromLong(r);
651 PyDoc_STRVAR(Reader_seek_cursor__doc__,
652 "seek_cursor(cursor) -> None\n\n"
653 "Seek to journal entry by given unique reference `cursor`.");
654 static PyObject* Reader_seek_cursor(Reader *self, PyObject *args)
659 if (!PyArg_ParseTuple(args, "s:seek_cursor", &cursor))
662 Py_BEGIN_ALLOW_THREADS
663 r = sd_journal_seek_cursor(self->j, cursor);
665 if (set_error(r, NULL, "Invalid cursor"))
671 PyDoc_STRVAR(Reader_get_cursor__doc__,
672 "get_cursor() -> str\n\n"
673 "Return a cursor string for the current journal entry.\n\n"
674 "Wraps sd_journal_get_cursor(). See man:sd_journal_get_cursor(3).");
675 static PyObject* Reader_get_cursor(Reader *self, PyObject *args)
677 char _cleanup_free_ *cursor = NULL;
683 r = sd_journal_get_cursor(self->j, &cursor);
684 if (set_error(r, NULL, NULL))
687 return unicode_FromString(cursor);
691 PyDoc_STRVAR(Reader_test_cursor__doc__,
692 "test_cursor(str) -> bool\n\n"
693 "Test whether the cursor string matches current journal entry.\n\n"
694 "Wraps sd_journal_test_cursor(). See man:sd_journal_test_cursor(3).");
695 static PyObject* Reader_test_cursor(Reader *self, PyObject *args)
703 if (!PyArg_ParseTuple(args, "s:test_cursor", &cursor))
706 r = sd_journal_test_cursor(self->j, cursor);
707 set_error(r, NULL, NULL);
711 return PyBool_FromLong(r);
715 static PyObject* Reader_iter(PyObject *self)
721 static PyObject* Reader_iternext(PyObject *self)
724 Py_ssize_t dict_size;
726 dict = PyObject_CallMethod(self, (char*) "get_next", (char*) "");
727 if (PyErr_Occurred())
729 dict_size = PyDict_Size(dict);
730 if ((int64_t) dict_size > 0LL) {
734 PyErr_SetNone(PyExc_StopIteration);
740 PyDoc_STRVAR(Reader_query_unique__doc__,
741 "query_unique(field) -> a set of values\n\n"
742 "Return a set of unique values appearing in journal for the\n"
743 "given `field`. Note this does not respect any journal matches.");
744 static PyObject* Reader_query_unique(Reader *self, PyObject *args)
750 PyObject *value_set, *key, *value;
752 if (!PyArg_ParseTuple(args, "s:query_unique", &query))
755 Py_BEGIN_ALLOW_THREADS
756 r = sd_journal_query_unique(self->j, query);
758 if (set_error(r, NULL, "Invalid field name"))
761 value_set = PySet_New(0);
762 key = unicode_FromString(query);
764 SD_JOURNAL_FOREACH_UNIQUE(self->j, uniq, uniq_len) {
765 const char *delim_ptr;
767 delim_ptr = memchr(uniq, '=', uniq_len);
768 value = PyBytes_FromStringAndSize(
770 (const char*) uniq + uniq_len - (delim_ptr + 1));
771 PySet_Add(value_set, value);
779 PyDoc_STRVAR(Reader_get_catalog__doc__,
780 "get_catalog() -> str\n\n"
781 "Retrieve a message catalog entry for the current journal entry.\n"
782 "Will throw IndexError if the entry has no MESSAGE_ID\n"
783 "and KeyError is the id is specified, but hasn't been found\n"
784 "in the catalog.\n\n"
785 "Wraps man:sd_journal_get_catalog(3).");
786 static PyObject* Reader_get_catalog(Reader *self, PyObject *args)
789 char _cleanup_free_ *msg = NULL;
794 Py_BEGIN_ALLOW_THREADS
795 r = sd_journal_get_catalog(self->j, &msg);
801 r = sd_journal_get_data(self->j, "MESSAGE_ID", &mid, &mid_len);
803 const int l = sizeof("MESSAGE_ID");
805 PyErr_Format(PyExc_KeyError, "%.*s", (int) mid_len - l,
806 (const char*) mid + l);
807 } else if (r == -ENOENT)
808 PyErr_SetString(PyExc_IndexError, "no MESSAGE_ID field");
810 set_error(r, NULL, NULL);
812 } else if (set_error(r, NULL, NULL))
815 return unicode_FromString(msg);
819 PyDoc_STRVAR(get_catalog__doc__,
820 "get_catalog(id128) -> str\n\n"
821 "Retrieve a message catalog entry for the given id.\n"
822 "Wraps man:sd_journal_get_catalog_for_message_id(3).");
823 static PyObject* get_catalog(PyObject *self, PyObject *args)
828 char _cleanup_free_ *msg = NULL;
833 if (!PyArg_ParseTuple(args, "z:get_catalog", &id_))
836 r = sd_id128_from_string(id_, &id);
837 if (set_error(r, NULL, "Invalid id128"))
840 Py_BEGIN_ALLOW_THREADS
841 r = sd_journal_get_catalog_for_message_id(id, &msg);
843 if (set_error(r, NULL, NULL))
846 return unicode_FromString(msg);
850 PyDoc_STRVAR(data_threshold__doc__,
851 "Threshold for field size truncation in bytes.\n\n"
852 "Fields longer than this will be truncated to the threshold size.\n"
853 "Defaults to 64Kb.");
855 static PyObject* Reader_get_data_threshold(Reader *self, void *closure)
860 r = sd_journal_get_data_threshold(self->j, &cvalue);
861 if (set_error(r, NULL, NULL))
864 return long_FromSize_t(cvalue);
867 static int Reader_set_data_threshold(Reader *self, PyObject *value, void *closure)
871 PyErr_SetString(PyExc_AttributeError, "Cannot delete data threshold");
874 if (!long_Check(value)){
875 PyErr_SetString(PyExc_TypeError, "Data threshold must be an int");
878 r = sd_journal_set_data_threshold(self->j, (size_t) long_AsLong(value));
879 return set_error(r, NULL, NULL);
883 PyDoc_STRVAR(closed__doc__,
884 "True iff journal is closed");
885 static PyObject* Reader_get_closed(Reader *self, void *closure)
887 return PyBool_FromLong(self->j == NULL);
891 static PyGetSetDef Reader_getsetters[] = {
892 {(char*) "data_threshold",
893 (getter) Reader_get_data_threshold,
894 (setter) Reader_set_data_threshold,
895 (char*) data_threshold__doc__,
898 (getter) Reader_get_closed,
900 (char*) closed__doc__,
905 static PyMethodDef Reader_methods[] = {
906 {"fileno", (PyCFunction) Reader_fileno, METH_NOARGS, Reader_fileno__doc__},
907 {"reliable_fd", (PyCFunction) Reader_reliable_fd, METH_NOARGS, Reader_reliable_fd__doc__},
908 {"close", (PyCFunction) Reader_close, METH_NOARGS, Reader_close__doc__},
909 {"get_usage", (PyCFunction) Reader_get_usage, METH_NOARGS, Reader_get_usage__doc__},
910 {"__enter__", (PyCFunction) Reader___enter__, METH_NOARGS, Reader___enter____doc__},
911 {"__exit__", (PyCFunction) Reader___exit__, METH_VARARGS, Reader___exit____doc__},
912 {"next", (PyCFunction) Reader_next, METH_VARARGS, Reader_next__doc__},
913 {"get", (PyCFunction) Reader_get, METH_VARARGS, Reader_get__doc__},
914 {"get_next", (PyCFunction) Reader_get_next, METH_VARARGS, Reader_get_next__doc__},
915 {"get_previous", (PyCFunction) Reader_get_previous, METH_VARARGS, Reader_get_previous__doc__},
916 {"get_realtime", (PyCFunction) Reader_get_realtime, METH_NOARGS, Reader_get_realtime__doc__},
917 {"get_monotonic", (PyCFunction) Reader_get_monotonic, METH_NOARGS, Reader_get_monotonic__doc__},
918 {"add_match", (PyCFunction) Reader_add_match, METH_VARARGS|METH_KEYWORDS, Reader_add_match__doc__},
919 {"add_disjunction", (PyCFunction) Reader_add_disjunction, METH_NOARGS, Reader_add_disjunction__doc__},
920 {"flush_matches", (PyCFunction) Reader_flush_matches, METH_NOARGS, Reader_flush_matches__doc__},
921 {"seek_head", (PyCFunction) Reader_seek_head, METH_NOARGS, Reader_seek_head__doc__},
922 {"seek_tail", (PyCFunction) Reader_seek_tail, METH_NOARGS, Reader_seek_tail__doc__},
923 {"seek_realtime", (PyCFunction) Reader_seek_realtime, METH_VARARGS, Reader_seek_realtime__doc__},
924 {"seek_monotonic", (PyCFunction) Reader_seek_monotonic, METH_VARARGS, Reader_seek_monotonic__doc__},
925 {"wait", (PyCFunction) Reader_wait, METH_VARARGS, Reader_wait__doc__},
926 {"seek_cursor", (PyCFunction) Reader_seek_cursor, METH_VARARGS, Reader_seek_cursor__doc__},
927 {"get_cursor", (PyCFunction) Reader_get_cursor, METH_NOARGS, Reader_get_cursor__doc__},
928 {"test_cursor", (PyCFunction) Reader_test_cursor, METH_VARARGS, Reader_test_cursor__doc__},
929 {"query_unique", (PyCFunction) Reader_query_unique, METH_VARARGS, Reader_query_unique__doc__},
930 {"get_catalog", (PyCFunction) Reader_get_catalog, METH_NOARGS, Reader_get_catalog__doc__},
934 static PyTypeObject ReaderType = {
935 PyVarObject_HEAD_INIT(NULL, 0)
936 "_reader._Reader", /*tp_name*/
937 sizeof(Reader), /*tp_basicsize*/
939 (destructor)Reader_dealloc, /*tp_dealloc*/
946 0, /*tp_as_sequence*/
954 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
955 Reader__doc__, /* tp_doc */
958 0, /* tp_richcompare */
959 0, /* tp_weaklistoffset */
960 Reader_iter, /* tp_iter */
961 Reader_iternext, /* tp_iternext */
962 Reader_methods, /* tp_methods */
964 Reader_getsetters, /* tp_getset */
967 0, /* tp_descr_get */
968 0, /* tp_descr_set */
969 0, /* tp_dictoffset */
970 (initproc) Reader_init, /* tp_init */
972 PyType_GenericNew, /* tp_new */
975 static PyMethodDef methods[] = {
976 { "_get_catalog", get_catalog, METH_VARARGS, get_catalog__doc__},
977 { NULL, NULL, 0, NULL } /* Sentinel */
980 #if PY_MAJOR_VERSION >= 3
981 static PyModuleDef module = {
982 PyModuleDef_HEAD_INIT,
987 NULL, NULL, NULL, NULL
991 #if PY_MAJOR_VERSION >= 3
992 static bool initialized = false;
995 #pragma GCC diagnostic push
996 #pragma GCC diagnostic ignored "-Wmissing-prototypes"
999 #if PY_MAJOR_VERSION >= 3
1000 PyInit__reader(void)
1009 if (PyType_Ready(&ReaderType) < 0)
1010 #if PY_MAJOR_VERSION >= 3
1016 #if PY_MAJOR_VERSION >= 3
1017 m = PyModule_Create(&module);
1022 PyStructSequence_InitType(&MonotonicType, &Monotonic_desc);
1026 m = Py_InitModule3("_reader", methods, module__doc__);
1031 Py_INCREF(&ReaderType);
1032 #if PY_MAJOR_VERSION >= 3
1033 Py_INCREF(&MonotonicType);
1035 if (PyModule_AddObject(m, "_Reader", (PyObject *) &ReaderType) ||
1036 #if PY_MAJOR_VERSION >= 3
1037 PyModule_AddObject(m, "Monotonic", (PyObject*) &MonotonicType) ||
1039 PyModule_AddIntConstant(m, "NOP", SD_JOURNAL_NOP) ||
1040 PyModule_AddIntConstant(m, "APPEND", SD_JOURNAL_APPEND) ||
1041 PyModule_AddIntConstant(m, "INVALIDATE", SD_JOURNAL_INVALIDATE) ||
1042 PyModule_AddIntConstant(m, "LOCAL_ONLY", SD_JOURNAL_LOCAL_ONLY) ||
1043 PyModule_AddIntConstant(m, "RUNTIME_ONLY", SD_JOURNAL_RUNTIME_ONLY) ||
1044 PyModule_AddIntConstant(m, "SYSTEM_ONLY", SD_JOURNAL_SYSTEM_ONLY)) {
1045 #if PY_MAJOR_VERSION >= 3
1051 #if PY_MAJOR_VERSION >= 3
1056 #pragma GCC diagnostic pop