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