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"
179 "files (in bytes). If `SD_JOURNAL_LOCAL_ONLY` was"
180 "passed when opening the journal this value will only reflect"
181 "the size of journal files of the local host, otherwise"
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.");
632 static PyObject* Reader_wait(Reader *self, PyObject *args)
637 if (!PyArg_ParseTuple(args, "|L:wait", &timeout))
640 Py_BEGIN_ALLOW_THREADS
641 r = sd_journal_wait(self->j, timeout);
643 if (set_error(r, NULL, NULL) < 0)
646 return long_FromLong(r);
650 PyDoc_STRVAR(Reader_seek_cursor__doc__,
651 "seek_cursor(cursor) -> None\n\n"
652 "Seek to journal entry by given unique reference `cursor`.");
653 static PyObject* Reader_seek_cursor(Reader *self, PyObject *args)
658 if (!PyArg_ParseTuple(args, "s:seek_cursor", &cursor))
661 Py_BEGIN_ALLOW_THREADS
662 r = sd_journal_seek_cursor(self->j, cursor);
664 if (set_error(r, NULL, "Invalid cursor"))
670 PyDoc_STRVAR(Reader_get_cursor__doc__,
671 "get_cursor() -> str\n\n"
672 "Return a cursor string for the current journal entry.\n\n"
673 "Wraps sd_journal_get_cursor(). See man:sd_journal_get_cursor(3).");
674 static PyObject* Reader_get_cursor(Reader *self, PyObject *args)
676 char _cleanup_free_ *cursor = NULL;
682 r = sd_journal_get_cursor(self->j, &cursor);
683 if (set_error(r, NULL, NULL))
686 return unicode_FromString(cursor);
690 PyDoc_STRVAR(Reader_test_cursor__doc__,
691 "test_cursor(str) -> bool\n\n"
692 "Test whether the cursor string matches current journal entry.\n\n"
693 "Wraps sd_journal_test_cursor(). See man:sd_journal_test_cursor(3).");
694 static PyObject* Reader_test_cursor(Reader *self, PyObject *args)
702 if (!PyArg_ParseTuple(args, "s:test_cursor", &cursor))
705 r = sd_journal_test_cursor(self->j, cursor);
706 set_error(r, NULL, NULL);
710 return PyBool_FromLong(r);
714 static PyObject* Reader_iter(PyObject *self)
720 static PyObject* Reader_iternext(PyObject *self)
723 Py_ssize_t dict_size;
725 dict = PyObject_CallMethod(self, (char*) "get_next", (char*) "");
726 if (PyErr_Occurred())
728 dict_size = PyDict_Size(dict);
729 if ((int64_t) dict_size > 0LL) {
733 PyErr_SetNone(PyExc_StopIteration);
739 PyDoc_STRVAR(Reader_query_unique__doc__,
740 "query_unique(field) -> a set of values\n\n"
741 "Return a set of unique values appearing in journal for the\n"
742 "given `field`. Note this does not respect any journal matches.");
743 static PyObject* Reader_query_unique(Reader *self, PyObject *args)
749 PyObject *value_set, *key, *value;
751 if (!PyArg_ParseTuple(args, "s:query_unique", &query))
754 Py_BEGIN_ALLOW_THREADS
755 r = sd_journal_query_unique(self->j, query);
757 if (set_error(r, NULL, "Invalid field name"))
760 value_set = PySet_New(0);
761 key = unicode_FromString(query);
763 SD_JOURNAL_FOREACH_UNIQUE(self->j, uniq, uniq_len) {
764 const char *delim_ptr;
766 delim_ptr = memchr(uniq, '=', uniq_len);
767 value = PyBytes_FromStringAndSize(
769 (const char*) uniq + uniq_len - (delim_ptr + 1));
770 PySet_Add(value_set, value);
778 PyDoc_STRVAR(Reader_get_catalog__doc__,
779 "get_catalog() -> str\n\n"
780 "Retrieve a message catalog entry for the current journal entry.\n"
781 "Will throw IndexError if the entry has no MESSAGE_ID\n"
782 "and KeyError is the id is specified, but hasn't been found\n"
783 "in the catalog.\n\n"
784 "Wraps man:sd_journal_get_catalog(3).");
785 static PyObject* Reader_get_catalog(Reader *self, PyObject *args)
788 char _cleanup_free_ *msg = NULL;
793 Py_BEGIN_ALLOW_THREADS
794 r = sd_journal_get_catalog(self->j, &msg);
800 r = sd_journal_get_data(self->j, "MESSAGE_ID", &mid, &mid_len);
802 const int l = sizeof("MESSAGE_ID");
804 PyErr_Format(PyExc_KeyError, "%.*s", (int) mid_len - l,
805 (const char*) mid + l);
806 } else if (r == -ENOENT)
807 PyErr_SetString(PyExc_IndexError, "no MESSAGE_ID field");
809 set_error(r, NULL, NULL);
811 } else if (set_error(r, NULL, NULL))
814 return unicode_FromString(msg);
818 PyDoc_STRVAR(get_catalog__doc__,
819 "get_catalog(id128) -> str\n\n"
820 "Retrieve a message catalog entry for the given id.\n"
821 "Wraps man:sd_journal_get_catalog_for_message_id(3).");
822 static PyObject* get_catalog(PyObject *self, PyObject *args)
827 char _cleanup_free_ *msg = NULL;
832 if (!PyArg_ParseTuple(args, "z:get_catalog", &id_))
835 r = sd_id128_from_string(id_, &id);
836 if (set_error(r, NULL, "Invalid id128"))
839 Py_BEGIN_ALLOW_THREADS
840 r = sd_journal_get_catalog_for_message_id(id, &msg);
842 if (set_error(r, NULL, NULL))
845 return unicode_FromString(msg);
849 PyDoc_STRVAR(data_threshold__doc__,
850 "Threshold for field size truncation in bytes.\n\n"
851 "Fields longer than this will be truncated to the threshold size.\n"
852 "Defaults to 64Kb.");
854 static PyObject* Reader_get_data_threshold(Reader *self, void *closure)
859 r = sd_journal_get_data_threshold(self->j, &cvalue);
860 if (set_error(r, NULL, NULL))
863 return long_FromSize_t(cvalue);
866 static int Reader_set_data_threshold(Reader *self, PyObject *value, void *closure)
870 PyErr_SetString(PyExc_AttributeError, "Cannot delete data threshold");
873 if (!long_Check(value)){
874 PyErr_SetString(PyExc_TypeError, "Data threshold must be an int");
877 r = sd_journal_set_data_threshold(self->j, (size_t) long_AsLong(value));
878 return set_error(r, NULL, NULL);
882 PyDoc_STRVAR(closed__doc__,
883 "True iff journal is closed");
884 static PyObject* Reader_get_closed(Reader *self, void *closure)
886 return PyBool_FromLong(self->j == NULL);
890 static PyGetSetDef Reader_getsetters[] = {
891 {(char*) "data_threshold",
892 (getter) Reader_get_data_threshold,
893 (setter) Reader_set_data_threshold,
894 (char*) data_threshold__doc__,
897 (getter) Reader_get_closed,
899 (char*) closed__doc__,
904 static PyMethodDef Reader_methods[] = {
905 {"fileno", (PyCFunction) Reader_fileno, METH_NOARGS, Reader_fileno__doc__},
906 {"reliable_fd", (PyCFunction) Reader_reliable_fd, METH_NOARGS, Reader_reliable_fd__doc__},
907 {"close", (PyCFunction) Reader_close, METH_NOARGS, Reader_close__doc__},
908 {"get_usage", (PyCFunction) Reader_get_usage, METH_NOARGS, Reader_get_usage__doc__},
909 {"__enter__", (PyCFunction) Reader___enter__, METH_NOARGS, Reader___enter____doc__},
910 {"__exit__", (PyCFunction) Reader___exit__, METH_VARARGS, Reader___exit____doc__},
911 {"next", (PyCFunction) Reader_next, METH_VARARGS, Reader_next__doc__},
912 {"get", (PyCFunction) Reader_get, METH_VARARGS, Reader_get__doc__},
913 {"get_next", (PyCFunction) Reader_get_next, METH_VARARGS, Reader_get_next__doc__},
914 {"get_previous", (PyCFunction) Reader_get_previous, METH_VARARGS, Reader_get_previous__doc__},
915 {"get_realtime", (PyCFunction) Reader_get_realtime, METH_NOARGS, Reader_get_realtime__doc__},
916 {"get_monotonic", (PyCFunction) Reader_get_monotonic, METH_NOARGS, Reader_get_monotonic__doc__},
917 {"add_match", (PyCFunction) Reader_add_match, METH_VARARGS|METH_KEYWORDS, Reader_add_match__doc__},
918 {"add_disjunction", (PyCFunction) Reader_add_disjunction, METH_NOARGS, Reader_add_disjunction__doc__},
919 {"flush_matches", (PyCFunction) Reader_flush_matches, METH_NOARGS, Reader_flush_matches__doc__},
920 {"seek_head", (PyCFunction) Reader_seek_head, METH_NOARGS, Reader_seek_head__doc__},
921 {"seek_tail", (PyCFunction) Reader_seek_tail, METH_NOARGS, Reader_seek_tail__doc__},
922 {"seek_realtime", (PyCFunction) Reader_seek_realtime, METH_VARARGS, Reader_seek_realtime__doc__},
923 {"seek_monotonic", (PyCFunction) Reader_seek_monotonic, METH_VARARGS, Reader_seek_monotonic__doc__},
924 {"wait", (PyCFunction) Reader_wait, METH_VARARGS, Reader_wait__doc__},
925 {"seek_cursor", (PyCFunction) Reader_seek_cursor, METH_VARARGS, Reader_seek_cursor__doc__},
926 {"get_cursor", (PyCFunction) Reader_get_cursor, METH_NOARGS, Reader_get_cursor__doc__},
927 {"test_cursor", (PyCFunction) Reader_test_cursor, METH_VARARGS, Reader_test_cursor__doc__},
928 {"query_unique", (PyCFunction) Reader_query_unique, METH_VARARGS, Reader_query_unique__doc__},
929 {"get_catalog", (PyCFunction) Reader_get_catalog, METH_NOARGS, Reader_get_catalog__doc__},
933 static PyTypeObject ReaderType = {
934 PyVarObject_HEAD_INIT(NULL, 0)
935 "_reader._Reader", /*tp_name*/
936 sizeof(Reader), /*tp_basicsize*/
938 (destructor)Reader_dealloc, /*tp_dealloc*/
945 0, /*tp_as_sequence*/
953 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
954 Reader__doc__, /* tp_doc */
957 0, /* tp_richcompare */
958 0, /* tp_weaklistoffset */
959 Reader_iter, /* tp_iter */
960 Reader_iternext, /* tp_iternext */
961 Reader_methods, /* tp_methods */
963 Reader_getsetters, /* tp_getset */
966 0, /* tp_descr_get */
967 0, /* tp_descr_set */
968 0, /* tp_dictoffset */
969 (initproc) Reader_init, /* tp_init */
971 PyType_GenericNew, /* tp_new */
974 static PyMethodDef methods[] = {
975 { "_get_catalog", get_catalog, METH_VARARGS, get_catalog__doc__},
976 { NULL, NULL, 0, NULL } /* Sentinel */
979 #if PY_MAJOR_VERSION >= 3
980 static PyModuleDef module = {
981 PyModuleDef_HEAD_INIT,
986 NULL, NULL, NULL, NULL
990 #if PY_MAJOR_VERSION >= 3
991 static bool initialized = false;
994 #pragma GCC diagnostic push
995 #pragma GCC diagnostic ignored "-Wmissing-prototypes"
998 #if PY_MAJOR_VERSION >= 3
1008 if (PyType_Ready(&ReaderType) < 0)
1009 #if PY_MAJOR_VERSION >= 3
1015 #if PY_MAJOR_VERSION >= 3
1016 m = PyModule_Create(&module);
1021 PyStructSequence_InitType(&MonotonicType, &Monotonic_desc);
1025 m = Py_InitModule3("_reader", methods, module__doc__);
1030 Py_INCREF(&ReaderType);
1031 #if PY_MAJOR_VERSION >= 3
1032 Py_INCREF(&MonotonicType);
1034 if (PyModule_AddObject(m, "_Reader", (PyObject *) &ReaderType) ||
1035 #if PY_MAJOR_VERSION >= 3
1036 PyModule_AddObject(m, "Monotonic", (PyObject*) &MonotonicType) ||
1038 PyModule_AddIntConstant(m, "NOP", SD_JOURNAL_NOP) ||
1039 PyModule_AddIntConstant(m, "APPEND", SD_JOURNAL_APPEND) ||
1040 PyModule_AddIntConstant(m, "INVALIDATE", SD_JOURNAL_INVALIDATE) ||
1041 PyModule_AddIntConstant(m, "LOCAL_ONLY", SD_JOURNAL_LOCAL_ONLY) ||
1042 PyModule_AddIntConstant(m, "RUNTIME_ONLY", SD_JOURNAL_RUNTIME_ONLY) ||
1043 PyModule_AddIntConstant(m, "SYSTEM_ONLY", SD_JOURNAL_SYSTEM_ONLY)) {
1044 #if PY_MAJOR_VERSION >= 3
1050 #if PY_MAJOR_VERSION >= 3
1055 #pragma GCC diagnostic pop