xref: /third_party/python/Modules/_gdbmmodule.c (revision 7db96d56)
1
2/* GDBM module using dictionary interface */
3/* Author: Anthony Baxter, after dbmmodule.c */
4/* Doc strings: Mitch Chapman */
5
6#define PY_SSIZE_T_CLEAN
7#include "Python.h"
8#include "gdbm.h"
9
10#include <fcntl.h>
11#include <stdlib.h>               // free()
12#include <sys/stat.h>
13#include <sys/types.h>
14
15#if defined(WIN32) && !defined(__CYGWIN__)
16#include "gdbmerrno.h"
17extern const char * gdbm_strerror(gdbm_error);
18#endif
19
20typedef struct {
21    PyTypeObject *gdbm_type;
22    PyObject *gdbm_error;
23} _gdbm_state;
24
25static inline _gdbm_state*
26get_gdbm_state(PyObject *module)
27{
28    void *state = PyModule_GetState(module);
29    assert(state != NULL);
30    return (_gdbm_state *)state;
31}
32
33/*[clinic input]
34module _gdbm
35class _gdbm.gdbm "gdbmobject *" "&Gdbmtype"
36[clinic start generated code]*/
37/*[clinic end generated code: output=da39a3ee5e6b4b0d input=38ae71cedfc7172b]*/
38
39PyDoc_STRVAR(gdbmmodule__doc__,
40"This module provides an interface to the GNU DBM (GDBM) library.\n\
41\n\
42This module is quite similar to the dbm module, but uses GDBM instead to\n\
43provide some additional functionality.  Please note that the file formats\n\
44created by GDBM and dbm are incompatible.\n\
45\n\
46GDBM objects behave like mappings (dictionaries), except that keys and\n\
47values are always immutable bytes-like objects or strings.  Printing\n\
48a GDBM object doesn't print the keys and values, and the items() and\n\
49values() methods are not supported.");
50
51typedef struct {
52    PyObject_HEAD
53    Py_ssize_t di_size;        /* -1 means recompute */
54    GDBM_FILE di_dbm;
55} gdbmobject;
56
57#include "clinic/_gdbmmodule.c.h"
58
59#define check_gdbmobject_open(v, err)                                 \
60    if ((v)->di_dbm == NULL) {                                       \
61        PyErr_SetString(err, "GDBM object has already been closed"); \
62        return NULL;                                                 \
63    }
64
65PyDoc_STRVAR(gdbm_object__doc__,
66"This object represents a GDBM database.\n\
67GDBM objects behave like mappings (dictionaries), except that keys and\n\
68values are always immutable bytes-like objects or strings.  Printing\n\
69a GDBM object doesn't print the keys and values, and the items() and\n\
70values() methods are not supported.\n\
71\n\
72GDBM objects also support additional operations such as firstkey,\n\
73nextkey, reorganize, and sync.");
74
75static PyObject *
76newgdbmobject(_gdbm_state *state, const char *file, int flags, int mode)
77{
78    gdbmobject *dp = PyObject_GC_New(gdbmobject, state->gdbm_type);
79    if (dp == NULL) {
80        return NULL;
81    }
82    dp->di_size = -1;
83    errno = 0;
84    PyObject_GC_Track(dp);
85
86    if ((dp->di_dbm = gdbm_open((char *)file, 0, flags, mode, NULL)) == 0) {
87        if (errno != 0) {
88            PyErr_SetFromErrnoWithFilename(state->gdbm_error, file);
89        }
90        else {
91            PyErr_SetString(state->gdbm_error, gdbm_strerror(gdbm_errno));
92        }
93        Py_DECREF(dp);
94        return NULL;
95    }
96    return (PyObject *)dp;
97}
98
99/* Methods */
100static int
101gdbm_traverse(gdbmobject *dp, visitproc visit, void *arg)
102{
103    Py_VISIT(Py_TYPE(dp));
104    return 0;
105}
106
107static void
108gdbm_dealloc(gdbmobject *dp)
109{
110    PyObject_GC_UnTrack(dp);
111    if (dp->di_dbm) {
112        gdbm_close(dp->di_dbm);
113    }
114    PyTypeObject *tp = Py_TYPE(dp);
115    tp->tp_free(dp);
116    Py_DECREF(tp);
117}
118
119static Py_ssize_t
120gdbm_length(gdbmobject *dp)
121{
122    _gdbm_state *state = PyType_GetModuleState(Py_TYPE(dp));
123    if (dp->di_dbm == NULL) {
124        PyErr_SetString(state->gdbm_error, "GDBM object has already been closed");
125        return -1;
126    }
127    if (dp->di_size < 0) {
128#if GDBM_VERSION_MAJOR >= 1 && GDBM_VERSION_MINOR >= 11
129        errno = 0;
130        gdbm_count_t count;
131        if (gdbm_count(dp->di_dbm, &count) == -1) {
132            if (errno != 0) {
133                PyErr_SetFromErrno(state->gdbm_error);
134            }
135            else {
136                PyErr_SetString(state->gdbm_error, gdbm_strerror(gdbm_errno));
137            }
138            return -1;
139        }
140        if (count > PY_SSIZE_T_MAX) {
141            PyErr_SetString(PyExc_OverflowError, "count exceeds PY_SSIZE_T_MAX");
142            return -1;
143        }
144        dp->di_size = count;
145#else
146        datum key,okey;
147        okey.dsize=0;
148        okey.dptr=NULL;
149
150        Py_ssize_t size = 0;
151        for (key = gdbm_firstkey(dp->di_dbm); key.dptr;
152             key = gdbm_nextkey(dp->di_dbm,okey)) {
153            size++;
154            if (okey.dsize) {
155                free(okey.dptr);
156            }
157            okey=key;
158        }
159        dp->di_size = size;
160#endif
161    }
162    return dp->di_size;
163}
164
165// Wrapper function for PyArg_Parse(o, "s#", &d.dptr, &d.size).
166// This function is needed to support PY_SSIZE_T_CLEAN.
167// Return 1 on success, same to PyArg_Parse().
168static int
169parse_datum(PyObject *o, datum *d, const char *failmsg)
170{
171    Py_ssize_t size;
172    if (!PyArg_Parse(o, "s#", &d->dptr, &size)) {
173        if (failmsg != NULL) {
174            PyErr_SetString(PyExc_TypeError, failmsg);
175        }
176        return 0;
177    }
178    if (INT_MAX < size) {
179        PyErr_SetString(PyExc_OverflowError, "size does not fit in an int");
180        return 0;
181    }
182    d->dsize = size;
183    return 1;
184}
185
186static PyObject *
187gdbm_subscript(gdbmobject *dp, PyObject *key)
188{
189    PyObject *v;
190    datum drec, krec;
191    _gdbm_state *state = PyType_GetModuleState(Py_TYPE(dp));
192
193    if (!parse_datum(key, &krec, NULL)) {
194        return NULL;
195    }
196    if (dp->di_dbm == NULL) {
197        PyErr_SetString(state->gdbm_error,
198                        "GDBM object has already been closed");
199        return NULL;
200    }
201    drec = gdbm_fetch(dp->di_dbm, krec);
202    if (drec.dptr == 0) {
203        PyErr_SetObject(PyExc_KeyError, key);
204        return NULL;
205    }
206    v = PyBytes_FromStringAndSize(drec.dptr, drec.dsize);
207    free(drec.dptr);
208    return v;
209}
210
211/*[clinic input]
212_gdbm.gdbm.get
213
214    key: object
215    default: object = None
216    /
217
218Get the value for key, or default if not present.
219[clinic start generated code]*/
220
221static PyObject *
222_gdbm_gdbm_get_impl(gdbmobject *self, PyObject *key, PyObject *default_value)
223/*[clinic end generated code: output=92421838f3a852f4 input=a9c20423f34c17b6]*/
224{
225    PyObject *res;
226
227    res = gdbm_subscript(self, key);
228    if (res == NULL && PyErr_ExceptionMatches(PyExc_KeyError)) {
229        PyErr_Clear();
230        Py_INCREF(default_value);
231        return default_value;
232    }
233    return res;
234}
235
236static int
237gdbm_ass_sub(gdbmobject *dp, PyObject *v, PyObject *w)
238{
239    datum krec, drec;
240    const char *failmsg = "gdbm mappings have bytes or string indices only";
241    _gdbm_state *state = PyType_GetModuleState(Py_TYPE(dp));
242
243    if (!parse_datum(v, &krec, failmsg)) {
244        return -1;
245    }
246    if (dp->di_dbm == NULL) {
247        PyErr_SetString(state->gdbm_error,
248                        "GDBM object has already been closed");
249        return -1;
250    }
251    dp->di_size = -1;
252    if (w == NULL) {
253        if (gdbm_delete(dp->di_dbm, krec) < 0) {
254            if (gdbm_errno == GDBM_ITEM_NOT_FOUND) {
255                PyErr_SetObject(PyExc_KeyError, v);
256            }
257            else {
258                PyErr_SetString(state->gdbm_error, gdbm_strerror(gdbm_errno));
259            }
260            return -1;
261        }
262    }
263    else {
264        if (!parse_datum(w, &drec, failmsg)) {
265            return -1;
266        }
267        errno = 0;
268        if (gdbm_store(dp->di_dbm, krec, drec, GDBM_REPLACE) < 0) {
269            if (errno != 0)
270                PyErr_SetFromErrno(state->gdbm_error);
271            else
272                PyErr_SetString(state->gdbm_error,
273                                gdbm_strerror(gdbm_errno));
274            return -1;
275        }
276    }
277    return 0;
278}
279
280/*[clinic input]
281_gdbm.gdbm.setdefault
282
283    key: object
284    default: object = None
285    /
286
287Get value for key, or set it to default and return default if not present.
288[clinic start generated code]*/
289
290static PyObject *
291_gdbm_gdbm_setdefault_impl(gdbmobject *self, PyObject *key,
292                           PyObject *default_value)
293/*[clinic end generated code: output=f3246e880509f142 input=0db46b69e9680171]*/
294{
295    PyObject *res;
296
297    res = gdbm_subscript(self, key);
298    if (res == NULL && PyErr_ExceptionMatches(PyExc_KeyError)) {
299        PyErr_Clear();
300        if (gdbm_ass_sub(self, key, default_value) < 0)
301            return NULL;
302        return gdbm_subscript(self, key);
303    }
304    return res;
305}
306
307/*[clinic input]
308_gdbm.gdbm.close
309
310Close the database.
311[clinic start generated code]*/
312
313static PyObject *
314_gdbm_gdbm_close_impl(gdbmobject *self)
315/*[clinic end generated code: output=f5abb4d6bb9e52d5 input=0a203447379b45fd]*/
316{
317    if (self->di_dbm) {
318        gdbm_close(self->di_dbm);
319    }
320    self->di_dbm = NULL;
321    Py_RETURN_NONE;
322}
323
324/* XXX Should return a set or a set view */
325/*[clinic input]
326_gdbm.gdbm.keys
327
328    cls: defining_class
329
330Get a list of all keys in the database.
331[clinic start generated code]*/
332
333static PyObject *
334_gdbm_gdbm_keys_impl(gdbmobject *self, PyTypeObject *cls)
335/*[clinic end generated code: output=c24b824e81404755 input=1428b7c79703d7d5]*/
336{
337    PyObject *v, *item;
338    datum key, nextkey;
339    int err;
340
341    _gdbm_state *state = PyType_GetModuleState(cls);
342    assert(state != NULL);
343
344    if (self == NULL || !Py_IS_TYPE(self, state->gdbm_type)) {
345        PyErr_BadInternalCall();
346        return NULL;
347    }
348    check_gdbmobject_open(self, state->gdbm_error);
349
350    v = PyList_New(0);
351    if (v == NULL)
352        return NULL;
353
354    key = gdbm_firstkey(self->di_dbm);
355    while (key.dptr) {
356        item = PyBytes_FromStringAndSize(key.dptr, key.dsize);
357        if (item == NULL) {
358            free(key.dptr);
359            Py_DECREF(v);
360            return NULL;
361        }
362        err = PyList_Append(v, item);
363        Py_DECREF(item);
364        if (err != 0) {
365            free(key.dptr);
366            Py_DECREF(v);
367            return NULL;
368        }
369        nextkey = gdbm_nextkey(self->di_dbm, key);
370        free(key.dptr);
371        key = nextkey;
372    }
373    return v;
374}
375
376static int
377gdbm_contains(PyObject *self, PyObject *arg)
378{
379    gdbmobject *dp = (gdbmobject *)self;
380    datum key;
381    Py_ssize_t size;
382    _gdbm_state *state = PyType_GetModuleState(Py_TYPE(dp));
383
384    if ((dp)->di_dbm == NULL) {
385        PyErr_SetString(state->gdbm_error,
386                        "GDBM object has already been closed");
387        return -1;
388    }
389    if (PyUnicode_Check(arg)) {
390        key.dptr = (char *)PyUnicode_AsUTF8AndSize(arg, &size);
391        key.dsize = size;
392        if (key.dptr == NULL)
393            return -1;
394    }
395    else if (!PyBytes_Check(arg)) {
396        PyErr_Format(PyExc_TypeError,
397                     "gdbm key must be bytes or string, not %.100s",
398                     Py_TYPE(arg)->tp_name);
399        return -1;
400    }
401    else {
402        key.dptr = PyBytes_AS_STRING(arg);
403        key.dsize = PyBytes_GET_SIZE(arg);
404    }
405    return gdbm_exists(dp->di_dbm, key);
406}
407
408/*[clinic input]
409_gdbm.gdbm.firstkey
410
411    cls: defining_class
412
413Return the starting key for the traversal.
414
415It's possible to loop over every key in the database using this method
416and the nextkey() method.  The traversal is ordered by GDBM's internal
417hash values, and won't be sorted by the key values.
418[clinic start generated code]*/
419
420static PyObject *
421_gdbm_gdbm_firstkey_impl(gdbmobject *self, PyTypeObject *cls)
422/*[clinic end generated code: output=139275e9c8b60827 input=ed8782a029a5d299]*/
423{
424    PyObject *v;
425    datum key;
426    _gdbm_state *state = PyType_GetModuleState(cls);
427    assert(state != NULL);
428
429    check_gdbmobject_open(self, state->gdbm_error);
430    key = gdbm_firstkey(self->di_dbm);
431    if (key.dptr) {
432        v = PyBytes_FromStringAndSize(key.dptr, key.dsize);
433        free(key.dptr);
434        return v;
435    }
436    else {
437        Py_RETURN_NONE;
438    }
439}
440
441/*[clinic input]
442_gdbm.gdbm.nextkey
443
444    cls: defining_class
445    key: str(accept={str, robuffer}, zeroes=True)
446    /
447
448Returns the key that follows key in the traversal.
449
450The following code prints every key in the database db, without having
451to create a list in memory that contains them all:
452
453      k = db.firstkey()
454      while k is not None:
455          print(k)
456          k = db.nextkey(k)
457[clinic start generated code]*/
458
459static PyObject *
460_gdbm_gdbm_nextkey_impl(gdbmobject *self, PyTypeObject *cls, const char *key,
461                        Py_ssize_t key_length)
462/*[clinic end generated code: output=c81a69300ef41766 input=365e297bc0b3db48]*/
463{
464    PyObject *v;
465    datum dbm_key, nextkey;
466    _gdbm_state *state = PyType_GetModuleState(cls);
467    assert(state != NULL);
468
469    dbm_key.dptr = (char *)key;
470    dbm_key.dsize = key_length;
471    check_gdbmobject_open(self, state->gdbm_error);
472    nextkey = gdbm_nextkey(self->di_dbm, dbm_key);
473    if (nextkey.dptr) {
474        v = PyBytes_FromStringAndSize(nextkey.dptr, nextkey.dsize);
475        free(nextkey.dptr);
476        return v;
477    }
478    else {
479        Py_RETURN_NONE;
480    }
481}
482
483/*[clinic input]
484_gdbm.gdbm.reorganize
485
486    cls: defining_class
487
488Reorganize the database.
489
490If you have carried out a lot of deletions and would like to shrink
491the space used by the GDBM file, this routine will reorganize the
492database.  GDBM will not shorten the length of a database file except
493by using this reorganization; otherwise, deleted file space will be
494kept and reused as new (key,value) pairs are added.
495[clinic start generated code]*/
496
497static PyObject *
498_gdbm_gdbm_reorganize_impl(gdbmobject *self, PyTypeObject *cls)
499/*[clinic end generated code: output=d77c69e8e3dd644a input=e1359faeef844e46]*/
500{
501    _gdbm_state *state = PyType_GetModuleState(cls);
502    assert(state != NULL);
503    check_gdbmobject_open(self, state->gdbm_error);
504    errno = 0;
505    if (gdbm_reorganize(self->di_dbm) < 0) {
506        if (errno != 0)
507            PyErr_SetFromErrno(state->gdbm_error);
508        else
509            PyErr_SetString(state->gdbm_error, gdbm_strerror(gdbm_errno));
510        return NULL;
511    }
512    Py_RETURN_NONE;
513}
514
515/*[clinic input]
516_gdbm.gdbm.sync
517
518    cls: defining_class
519
520Flush the database to the disk file.
521
522When the database has been opened in fast mode, this method forces
523any unwritten data to be written to the disk.
524[clinic start generated code]*/
525
526static PyObject *
527_gdbm_gdbm_sync_impl(gdbmobject *self, PyTypeObject *cls)
528/*[clinic end generated code: output=bb680a2035c3f592 input=3d749235f79b6f2a]*/
529{
530    _gdbm_state *state = PyType_GetModuleState(cls);
531    assert(state != NULL);
532    check_gdbmobject_open(self, state->gdbm_error);
533    gdbm_sync(self->di_dbm);
534    Py_RETURN_NONE;
535}
536
537static PyObject *
538gdbm__enter__(PyObject *self, PyObject *args)
539{
540    Py_INCREF(self);
541    return self;
542}
543
544static PyObject *
545gdbm__exit__(PyObject *self, PyObject *args)
546{
547    return _gdbm_gdbm_close_impl((gdbmobject *)self);
548}
549
550static PyMethodDef gdbm_methods[] = {
551    _GDBM_GDBM_CLOSE_METHODDEF
552    _GDBM_GDBM_KEYS_METHODDEF
553    _GDBM_GDBM_FIRSTKEY_METHODDEF
554    _GDBM_GDBM_NEXTKEY_METHODDEF
555    _GDBM_GDBM_REORGANIZE_METHODDEF
556    _GDBM_GDBM_SYNC_METHODDEF
557    _GDBM_GDBM_GET_METHODDEF
558    _GDBM_GDBM_SETDEFAULT_METHODDEF
559    {"__enter__", gdbm__enter__, METH_NOARGS, NULL},
560    {"__exit__",  gdbm__exit__, METH_VARARGS, NULL},
561    {NULL,              NULL}           /* sentinel */
562};
563
564static PyType_Slot gdbmtype_spec_slots[] = {
565    {Py_tp_dealloc, gdbm_dealloc},
566    {Py_tp_traverse, gdbm_traverse},
567    {Py_tp_methods, gdbm_methods},
568    {Py_sq_contains, gdbm_contains},
569    {Py_mp_length, gdbm_length},
570    {Py_mp_subscript, gdbm_subscript},
571    {Py_mp_ass_subscript, gdbm_ass_sub},
572    {Py_tp_doc, (char*)gdbm_object__doc__},
573    {0, 0}
574};
575
576static PyType_Spec gdbmtype_spec = {
577    .name = "_gdbm.gdbm",
578    .basicsize = sizeof(gdbmobject),
579    // Calling PyType_GetModuleState() on a subclass is not safe.
580    // dbmtype_spec does not have Py_TPFLAGS_BASETYPE flag
581    // which prevents to create a subclass.
582    // So calling PyType_GetModuleState() in this file is always safe.
583    .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION |
584              Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE),
585    .slots = gdbmtype_spec_slots,
586};
587
588/* ----------------------------------------------------------------- */
589
590/*[clinic input]
591_gdbm.open as dbmopen
592
593    filename: object
594    flags: str="r"
595    mode: int(py_default="0o666") = 0o666
596    /
597
598Open a dbm database and return a dbm object.
599
600The filename argument is the name of the database file.
601
602The optional flags argument can be 'r' (to open an existing database
603for reading only -- default), 'w' (to open an existing database for
604reading and writing), 'c' (which creates the database if it doesn't
605exist), or 'n' (which always creates a new empty database).
606
607Some versions of gdbm support additional flags which must be
608appended to one of the flags described above.  The module constant
609'open_flags' is a string of valid additional flags.  The 'f' flag
610opens the database in fast mode; altered data will not automatically
611be written to the disk after every change.  This results in faster
612writes to the database, but may result in an inconsistent database
613if the program crashes while the database is still open.  Use the
614sync() method to force any unwritten data to be written to the disk.
615The 's' flag causes all database operations to be synchronized to
616disk.  The 'u' flag disables locking of the database file.
617
618The optional mode argument is the Unix mode of the file, used only
619when the database has to be created.  It defaults to octal 0o666.
620[clinic start generated code]*/
621
622static PyObject *
623dbmopen_impl(PyObject *module, PyObject *filename, const char *flags,
624             int mode)
625/*[clinic end generated code: output=9527750f5df90764 input=bca6ec81dc49292c]*/
626{
627    int iflags;
628    _gdbm_state *state = get_gdbm_state(module);
629    assert(state != NULL);
630
631    switch (flags[0]) {
632    case 'r':
633        iflags = GDBM_READER;
634        break;
635    case 'w':
636        iflags = GDBM_WRITER;
637        break;
638    case 'c':
639        iflags = GDBM_WRCREAT;
640        break;
641    case 'n':
642        iflags = GDBM_NEWDB;
643        break;
644    default:
645        PyErr_SetString(state->gdbm_error,
646                        "First flag must be one of 'r', 'w', 'c' or 'n'");
647        return NULL;
648    }
649    for (flags++; *flags != '\0'; flags++) {
650        char buf[40];
651        switch (*flags) {
652#ifdef GDBM_FAST
653            case 'f':
654                iflags |= GDBM_FAST;
655                break;
656#endif
657#ifdef GDBM_SYNC
658            case 's':
659                iflags |= GDBM_SYNC;
660                break;
661#endif
662#ifdef GDBM_NOLOCK
663            case 'u':
664                iflags |= GDBM_NOLOCK;
665                break;
666#endif
667            default:
668                PyOS_snprintf(buf, sizeof(buf), "Flag '%c' is not supported.",
669                              *flags);
670                PyErr_SetString(state->gdbm_error, buf);
671                return NULL;
672        }
673    }
674
675    PyObject *filenamebytes;
676    if (!PyUnicode_FSConverter(filename, &filenamebytes)) {
677        return NULL;
678    }
679
680    const char *name = PyBytes_AS_STRING(filenamebytes);
681    if (strlen(name) != (size_t)PyBytes_GET_SIZE(filenamebytes)) {
682        Py_DECREF(filenamebytes);
683        PyErr_SetString(PyExc_ValueError, "embedded null character");
684        return NULL;
685    }
686    PyObject *self = newgdbmobject(state, name, iflags, mode);
687    Py_DECREF(filenamebytes);
688    return self;
689}
690
691static const char gdbmmodule_open_flags[] = "rwcn"
692#ifdef GDBM_FAST
693                                     "f"
694#endif
695#ifdef GDBM_SYNC
696                                     "s"
697#endif
698#ifdef GDBM_NOLOCK
699                                     "u"
700#endif
701                                     ;
702
703static PyMethodDef _gdbm_module_methods[] = {
704    DBMOPEN_METHODDEF
705    { 0, 0 },
706};
707
708static int
709_gdbm_exec(PyObject *module)
710{
711    _gdbm_state *state = get_gdbm_state(module);
712    state->gdbm_type = (PyTypeObject *)PyType_FromModuleAndSpec(module,
713                                                        &gdbmtype_spec, NULL);
714    if (state->gdbm_type == NULL) {
715        return -1;
716    }
717    state->gdbm_error = PyErr_NewException("_gdbm.error", PyExc_OSError, NULL);
718    if (state->gdbm_error == NULL) {
719        return -1;
720    }
721    if (PyModule_AddType(module, (PyTypeObject *)state->gdbm_error) < 0) {
722        return -1;
723    }
724    if (PyModule_AddStringConstant(module, "open_flags",
725                                   gdbmmodule_open_flags) < 0) {
726        return -1;
727    }
728
729#if defined(GDBM_VERSION_MAJOR) && defined(GDBM_VERSION_MINOR) && \
730    defined(GDBM_VERSION_PATCH)
731    PyObject *obj = Py_BuildValue("iii", GDBM_VERSION_MAJOR,
732                                  GDBM_VERSION_MINOR, GDBM_VERSION_PATCH);
733    if (obj == NULL) {
734        return -1;
735    }
736    if (PyModule_AddObject(module, "_GDBM_VERSION", obj) < 0) {
737        Py_DECREF(obj);
738        return -1;
739    }
740#endif
741    return 0;
742}
743
744static int
745_gdbm_module_traverse(PyObject *module, visitproc visit, void *arg)
746{
747    _gdbm_state *state = get_gdbm_state(module);
748    Py_VISIT(state->gdbm_error);
749    Py_VISIT(state->gdbm_type);
750    return 0;
751}
752
753static int
754_gdbm_module_clear(PyObject *module)
755{
756    _gdbm_state *state = get_gdbm_state(module);
757    Py_CLEAR(state->gdbm_error);
758    Py_CLEAR(state->gdbm_type);
759    return 0;
760}
761
762static void
763_gdbm_module_free(void *module)
764{
765    _gdbm_module_clear((PyObject *)module);
766}
767
768static PyModuleDef_Slot _gdbm_module_slots[] = {
769    {Py_mod_exec, _gdbm_exec},
770    {0, NULL}
771};
772
773static struct PyModuleDef _gdbmmodule = {
774    PyModuleDef_HEAD_INIT,
775    .m_name = "_gdbm",
776    .m_doc = gdbmmodule__doc__,
777    .m_size = sizeof(_gdbm_state),
778    .m_methods = _gdbm_module_methods,
779    .m_slots = _gdbm_module_slots,
780    .m_traverse = _gdbm_module_traverse,
781    .m_clear = _gdbm_module_clear,
782    .m_free = _gdbm_module_free,
783};
784
785PyMODINIT_FUNC
786PyInit__gdbm(void)
787{
788    return PyModuleDef_Init(&_gdbmmodule);
789}
790