17db96d56Sopenharmony_ci
27db96d56Sopenharmony_ci/* GDBM module using dictionary interface */
37db96d56Sopenharmony_ci/* Author: Anthony Baxter, after dbmmodule.c */
47db96d56Sopenharmony_ci/* Doc strings: Mitch Chapman */
57db96d56Sopenharmony_ci
67db96d56Sopenharmony_ci#define PY_SSIZE_T_CLEAN
77db96d56Sopenharmony_ci#include "Python.h"
87db96d56Sopenharmony_ci#include "gdbm.h"
97db96d56Sopenharmony_ci
107db96d56Sopenharmony_ci#include <fcntl.h>
117db96d56Sopenharmony_ci#include <stdlib.h>               // free()
127db96d56Sopenharmony_ci#include <sys/stat.h>
137db96d56Sopenharmony_ci#include <sys/types.h>
147db96d56Sopenharmony_ci
157db96d56Sopenharmony_ci#if defined(WIN32) && !defined(__CYGWIN__)
167db96d56Sopenharmony_ci#include "gdbmerrno.h"
177db96d56Sopenharmony_ciextern const char * gdbm_strerror(gdbm_error);
187db96d56Sopenharmony_ci#endif
197db96d56Sopenharmony_ci
207db96d56Sopenharmony_citypedef struct {
217db96d56Sopenharmony_ci    PyTypeObject *gdbm_type;
227db96d56Sopenharmony_ci    PyObject *gdbm_error;
237db96d56Sopenharmony_ci} _gdbm_state;
247db96d56Sopenharmony_ci
257db96d56Sopenharmony_cistatic inline _gdbm_state*
267db96d56Sopenharmony_ciget_gdbm_state(PyObject *module)
277db96d56Sopenharmony_ci{
287db96d56Sopenharmony_ci    void *state = PyModule_GetState(module);
297db96d56Sopenharmony_ci    assert(state != NULL);
307db96d56Sopenharmony_ci    return (_gdbm_state *)state;
317db96d56Sopenharmony_ci}
327db96d56Sopenharmony_ci
337db96d56Sopenharmony_ci/*[clinic input]
347db96d56Sopenharmony_cimodule _gdbm
357db96d56Sopenharmony_ciclass _gdbm.gdbm "gdbmobject *" "&Gdbmtype"
367db96d56Sopenharmony_ci[clinic start generated code]*/
377db96d56Sopenharmony_ci/*[clinic end generated code: output=da39a3ee5e6b4b0d input=38ae71cedfc7172b]*/
387db96d56Sopenharmony_ci
397db96d56Sopenharmony_ciPyDoc_STRVAR(gdbmmodule__doc__,
407db96d56Sopenharmony_ci"This module provides an interface to the GNU DBM (GDBM) library.\n\
417db96d56Sopenharmony_ci\n\
427db96d56Sopenharmony_ciThis module is quite similar to the dbm module, but uses GDBM instead to\n\
437db96d56Sopenharmony_ciprovide some additional functionality.  Please note that the file formats\n\
447db96d56Sopenharmony_cicreated by GDBM and dbm are incompatible.\n\
457db96d56Sopenharmony_ci\n\
467db96d56Sopenharmony_ciGDBM objects behave like mappings (dictionaries), except that keys and\n\
477db96d56Sopenharmony_civalues are always immutable bytes-like objects or strings.  Printing\n\
487db96d56Sopenharmony_cia GDBM object doesn't print the keys and values, and the items() and\n\
497db96d56Sopenharmony_civalues() methods are not supported.");
507db96d56Sopenharmony_ci
517db96d56Sopenharmony_citypedef struct {
527db96d56Sopenharmony_ci    PyObject_HEAD
537db96d56Sopenharmony_ci    Py_ssize_t di_size;        /* -1 means recompute */
547db96d56Sopenharmony_ci    GDBM_FILE di_dbm;
557db96d56Sopenharmony_ci} gdbmobject;
567db96d56Sopenharmony_ci
577db96d56Sopenharmony_ci#include "clinic/_gdbmmodule.c.h"
587db96d56Sopenharmony_ci
597db96d56Sopenharmony_ci#define check_gdbmobject_open(v, err)                                 \
607db96d56Sopenharmony_ci    if ((v)->di_dbm == NULL) {                                       \
617db96d56Sopenharmony_ci        PyErr_SetString(err, "GDBM object has already been closed"); \
627db96d56Sopenharmony_ci        return NULL;                                                 \
637db96d56Sopenharmony_ci    }
647db96d56Sopenharmony_ci
657db96d56Sopenharmony_ciPyDoc_STRVAR(gdbm_object__doc__,
667db96d56Sopenharmony_ci"This object represents a GDBM database.\n\
677db96d56Sopenharmony_ciGDBM objects behave like mappings (dictionaries), except that keys and\n\
687db96d56Sopenharmony_civalues are always immutable bytes-like objects or strings.  Printing\n\
697db96d56Sopenharmony_cia GDBM object doesn't print the keys and values, and the items() and\n\
707db96d56Sopenharmony_civalues() methods are not supported.\n\
717db96d56Sopenharmony_ci\n\
727db96d56Sopenharmony_ciGDBM objects also support additional operations such as firstkey,\n\
737db96d56Sopenharmony_cinextkey, reorganize, and sync.");
747db96d56Sopenharmony_ci
757db96d56Sopenharmony_cistatic PyObject *
767db96d56Sopenharmony_cinewgdbmobject(_gdbm_state *state, const char *file, int flags, int mode)
777db96d56Sopenharmony_ci{
787db96d56Sopenharmony_ci    gdbmobject *dp = PyObject_GC_New(gdbmobject, state->gdbm_type);
797db96d56Sopenharmony_ci    if (dp == NULL) {
807db96d56Sopenharmony_ci        return NULL;
817db96d56Sopenharmony_ci    }
827db96d56Sopenharmony_ci    dp->di_size = -1;
837db96d56Sopenharmony_ci    errno = 0;
847db96d56Sopenharmony_ci    PyObject_GC_Track(dp);
857db96d56Sopenharmony_ci
867db96d56Sopenharmony_ci    if ((dp->di_dbm = gdbm_open((char *)file, 0, flags, mode, NULL)) == 0) {
877db96d56Sopenharmony_ci        if (errno != 0) {
887db96d56Sopenharmony_ci            PyErr_SetFromErrnoWithFilename(state->gdbm_error, file);
897db96d56Sopenharmony_ci        }
907db96d56Sopenharmony_ci        else {
917db96d56Sopenharmony_ci            PyErr_SetString(state->gdbm_error, gdbm_strerror(gdbm_errno));
927db96d56Sopenharmony_ci        }
937db96d56Sopenharmony_ci        Py_DECREF(dp);
947db96d56Sopenharmony_ci        return NULL;
957db96d56Sopenharmony_ci    }
967db96d56Sopenharmony_ci    return (PyObject *)dp;
977db96d56Sopenharmony_ci}
987db96d56Sopenharmony_ci
997db96d56Sopenharmony_ci/* Methods */
1007db96d56Sopenharmony_cistatic int
1017db96d56Sopenharmony_cigdbm_traverse(gdbmobject *dp, visitproc visit, void *arg)
1027db96d56Sopenharmony_ci{
1037db96d56Sopenharmony_ci    Py_VISIT(Py_TYPE(dp));
1047db96d56Sopenharmony_ci    return 0;
1057db96d56Sopenharmony_ci}
1067db96d56Sopenharmony_ci
1077db96d56Sopenharmony_cistatic void
1087db96d56Sopenharmony_cigdbm_dealloc(gdbmobject *dp)
1097db96d56Sopenharmony_ci{
1107db96d56Sopenharmony_ci    PyObject_GC_UnTrack(dp);
1117db96d56Sopenharmony_ci    if (dp->di_dbm) {
1127db96d56Sopenharmony_ci        gdbm_close(dp->di_dbm);
1137db96d56Sopenharmony_ci    }
1147db96d56Sopenharmony_ci    PyTypeObject *tp = Py_TYPE(dp);
1157db96d56Sopenharmony_ci    tp->tp_free(dp);
1167db96d56Sopenharmony_ci    Py_DECREF(tp);
1177db96d56Sopenharmony_ci}
1187db96d56Sopenharmony_ci
1197db96d56Sopenharmony_cistatic Py_ssize_t
1207db96d56Sopenharmony_cigdbm_length(gdbmobject *dp)
1217db96d56Sopenharmony_ci{
1227db96d56Sopenharmony_ci    _gdbm_state *state = PyType_GetModuleState(Py_TYPE(dp));
1237db96d56Sopenharmony_ci    if (dp->di_dbm == NULL) {
1247db96d56Sopenharmony_ci        PyErr_SetString(state->gdbm_error, "GDBM object has already been closed");
1257db96d56Sopenharmony_ci        return -1;
1267db96d56Sopenharmony_ci    }
1277db96d56Sopenharmony_ci    if (dp->di_size < 0) {
1287db96d56Sopenharmony_ci#if GDBM_VERSION_MAJOR >= 1 && GDBM_VERSION_MINOR >= 11
1297db96d56Sopenharmony_ci        errno = 0;
1307db96d56Sopenharmony_ci        gdbm_count_t count;
1317db96d56Sopenharmony_ci        if (gdbm_count(dp->di_dbm, &count) == -1) {
1327db96d56Sopenharmony_ci            if (errno != 0) {
1337db96d56Sopenharmony_ci                PyErr_SetFromErrno(state->gdbm_error);
1347db96d56Sopenharmony_ci            }
1357db96d56Sopenharmony_ci            else {
1367db96d56Sopenharmony_ci                PyErr_SetString(state->gdbm_error, gdbm_strerror(gdbm_errno));
1377db96d56Sopenharmony_ci            }
1387db96d56Sopenharmony_ci            return -1;
1397db96d56Sopenharmony_ci        }
1407db96d56Sopenharmony_ci        if (count > PY_SSIZE_T_MAX) {
1417db96d56Sopenharmony_ci            PyErr_SetString(PyExc_OverflowError, "count exceeds PY_SSIZE_T_MAX");
1427db96d56Sopenharmony_ci            return -1;
1437db96d56Sopenharmony_ci        }
1447db96d56Sopenharmony_ci        dp->di_size = count;
1457db96d56Sopenharmony_ci#else
1467db96d56Sopenharmony_ci        datum key,okey;
1477db96d56Sopenharmony_ci        okey.dsize=0;
1487db96d56Sopenharmony_ci        okey.dptr=NULL;
1497db96d56Sopenharmony_ci
1507db96d56Sopenharmony_ci        Py_ssize_t size = 0;
1517db96d56Sopenharmony_ci        for (key = gdbm_firstkey(dp->di_dbm); key.dptr;
1527db96d56Sopenharmony_ci             key = gdbm_nextkey(dp->di_dbm,okey)) {
1537db96d56Sopenharmony_ci            size++;
1547db96d56Sopenharmony_ci            if (okey.dsize) {
1557db96d56Sopenharmony_ci                free(okey.dptr);
1567db96d56Sopenharmony_ci            }
1577db96d56Sopenharmony_ci            okey=key;
1587db96d56Sopenharmony_ci        }
1597db96d56Sopenharmony_ci        dp->di_size = size;
1607db96d56Sopenharmony_ci#endif
1617db96d56Sopenharmony_ci    }
1627db96d56Sopenharmony_ci    return dp->di_size;
1637db96d56Sopenharmony_ci}
1647db96d56Sopenharmony_ci
1657db96d56Sopenharmony_ci// Wrapper function for PyArg_Parse(o, "s#", &d.dptr, &d.size).
1667db96d56Sopenharmony_ci// This function is needed to support PY_SSIZE_T_CLEAN.
1677db96d56Sopenharmony_ci// Return 1 on success, same to PyArg_Parse().
1687db96d56Sopenharmony_cistatic int
1697db96d56Sopenharmony_ciparse_datum(PyObject *o, datum *d, const char *failmsg)
1707db96d56Sopenharmony_ci{
1717db96d56Sopenharmony_ci    Py_ssize_t size;
1727db96d56Sopenharmony_ci    if (!PyArg_Parse(o, "s#", &d->dptr, &size)) {
1737db96d56Sopenharmony_ci        if (failmsg != NULL) {
1747db96d56Sopenharmony_ci            PyErr_SetString(PyExc_TypeError, failmsg);
1757db96d56Sopenharmony_ci        }
1767db96d56Sopenharmony_ci        return 0;
1777db96d56Sopenharmony_ci    }
1787db96d56Sopenharmony_ci    if (INT_MAX < size) {
1797db96d56Sopenharmony_ci        PyErr_SetString(PyExc_OverflowError, "size does not fit in an int");
1807db96d56Sopenharmony_ci        return 0;
1817db96d56Sopenharmony_ci    }
1827db96d56Sopenharmony_ci    d->dsize = size;
1837db96d56Sopenharmony_ci    return 1;
1847db96d56Sopenharmony_ci}
1857db96d56Sopenharmony_ci
1867db96d56Sopenharmony_cistatic PyObject *
1877db96d56Sopenharmony_cigdbm_subscript(gdbmobject *dp, PyObject *key)
1887db96d56Sopenharmony_ci{
1897db96d56Sopenharmony_ci    PyObject *v;
1907db96d56Sopenharmony_ci    datum drec, krec;
1917db96d56Sopenharmony_ci    _gdbm_state *state = PyType_GetModuleState(Py_TYPE(dp));
1927db96d56Sopenharmony_ci
1937db96d56Sopenharmony_ci    if (!parse_datum(key, &krec, NULL)) {
1947db96d56Sopenharmony_ci        return NULL;
1957db96d56Sopenharmony_ci    }
1967db96d56Sopenharmony_ci    if (dp->di_dbm == NULL) {
1977db96d56Sopenharmony_ci        PyErr_SetString(state->gdbm_error,
1987db96d56Sopenharmony_ci                        "GDBM object has already been closed");
1997db96d56Sopenharmony_ci        return NULL;
2007db96d56Sopenharmony_ci    }
2017db96d56Sopenharmony_ci    drec = gdbm_fetch(dp->di_dbm, krec);
2027db96d56Sopenharmony_ci    if (drec.dptr == 0) {
2037db96d56Sopenharmony_ci        PyErr_SetObject(PyExc_KeyError, key);
2047db96d56Sopenharmony_ci        return NULL;
2057db96d56Sopenharmony_ci    }
2067db96d56Sopenharmony_ci    v = PyBytes_FromStringAndSize(drec.dptr, drec.dsize);
2077db96d56Sopenharmony_ci    free(drec.dptr);
2087db96d56Sopenharmony_ci    return v;
2097db96d56Sopenharmony_ci}
2107db96d56Sopenharmony_ci
2117db96d56Sopenharmony_ci/*[clinic input]
2127db96d56Sopenharmony_ci_gdbm.gdbm.get
2137db96d56Sopenharmony_ci
2147db96d56Sopenharmony_ci    key: object
2157db96d56Sopenharmony_ci    default: object = None
2167db96d56Sopenharmony_ci    /
2177db96d56Sopenharmony_ci
2187db96d56Sopenharmony_ciGet the value for key, or default if not present.
2197db96d56Sopenharmony_ci[clinic start generated code]*/
2207db96d56Sopenharmony_ci
2217db96d56Sopenharmony_cistatic PyObject *
2227db96d56Sopenharmony_ci_gdbm_gdbm_get_impl(gdbmobject *self, PyObject *key, PyObject *default_value)
2237db96d56Sopenharmony_ci/*[clinic end generated code: output=92421838f3a852f4 input=a9c20423f34c17b6]*/
2247db96d56Sopenharmony_ci{
2257db96d56Sopenharmony_ci    PyObject *res;
2267db96d56Sopenharmony_ci
2277db96d56Sopenharmony_ci    res = gdbm_subscript(self, key);
2287db96d56Sopenharmony_ci    if (res == NULL && PyErr_ExceptionMatches(PyExc_KeyError)) {
2297db96d56Sopenharmony_ci        PyErr_Clear();
2307db96d56Sopenharmony_ci        Py_INCREF(default_value);
2317db96d56Sopenharmony_ci        return default_value;
2327db96d56Sopenharmony_ci    }
2337db96d56Sopenharmony_ci    return res;
2347db96d56Sopenharmony_ci}
2357db96d56Sopenharmony_ci
2367db96d56Sopenharmony_cistatic int
2377db96d56Sopenharmony_cigdbm_ass_sub(gdbmobject *dp, PyObject *v, PyObject *w)
2387db96d56Sopenharmony_ci{
2397db96d56Sopenharmony_ci    datum krec, drec;
2407db96d56Sopenharmony_ci    const char *failmsg = "gdbm mappings have bytes or string indices only";
2417db96d56Sopenharmony_ci    _gdbm_state *state = PyType_GetModuleState(Py_TYPE(dp));
2427db96d56Sopenharmony_ci
2437db96d56Sopenharmony_ci    if (!parse_datum(v, &krec, failmsg)) {
2447db96d56Sopenharmony_ci        return -1;
2457db96d56Sopenharmony_ci    }
2467db96d56Sopenharmony_ci    if (dp->di_dbm == NULL) {
2477db96d56Sopenharmony_ci        PyErr_SetString(state->gdbm_error,
2487db96d56Sopenharmony_ci                        "GDBM object has already been closed");
2497db96d56Sopenharmony_ci        return -1;
2507db96d56Sopenharmony_ci    }
2517db96d56Sopenharmony_ci    dp->di_size = -1;
2527db96d56Sopenharmony_ci    if (w == NULL) {
2537db96d56Sopenharmony_ci        if (gdbm_delete(dp->di_dbm, krec) < 0) {
2547db96d56Sopenharmony_ci            if (gdbm_errno == GDBM_ITEM_NOT_FOUND) {
2557db96d56Sopenharmony_ci                PyErr_SetObject(PyExc_KeyError, v);
2567db96d56Sopenharmony_ci            }
2577db96d56Sopenharmony_ci            else {
2587db96d56Sopenharmony_ci                PyErr_SetString(state->gdbm_error, gdbm_strerror(gdbm_errno));
2597db96d56Sopenharmony_ci            }
2607db96d56Sopenharmony_ci            return -1;
2617db96d56Sopenharmony_ci        }
2627db96d56Sopenharmony_ci    }
2637db96d56Sopenharmony_ci    else {
2647db96d56Sopenharmony_ci        if (!parse_datum(w, &drec, failmsg)) {
2657db96d56Sopenharmony_ci            return -1;
2667db96d56Sopenharmony_ci        }
2677db96d56Sopenharmony_ci        errno = 0;
2687db96d56Sopenharmony_ci        if (gdbm_store(dp->di_dbm, krec, drec, GDBM_REPLACE) < 0) {
2697db96d56Sopenharmony_ci            if (errno != 0)
2707db96d56Sopenharmony_ci                PyErr_SetFromErrno(state->gdbm_error);
2717db96d56Sopenharmony_ci            else
2727db96d56Sopenharmony_ci                PyErr_SetString(state->gdbm_error,
2737db96d56Sopenharmony_ci                                gdbm_strerror(gdbm_errno));
2747db96d56Sopenharmony_ci            return -1;
2757db96d56Sopenharmony_ci        }
2767db96d56Sopenharmony_ci    }
2777db96d56Sopenharmony_ci    return 0;
2787db96d56Sopenharmony_ci}
2797db96d56Sopenharmony_ci
2807db96d56Sopenharmony_ci/*[clinic input]
2817db96d56Sopenharmony_ci_gdbm.gdbm.setdefault
2827db96d56Sopenharmony_ci
2837db96d56Sopenharmony_ci    key: object
2847db96d56Sopenharmony_ci    default: object = None
2857db96d56Sopenharmony_ci    /
2867db96d56Sopenharmony_ci
2877db96d56Sopenharmony_ciGet value for key, or set it to default and return default if not present.
2887db96d56Sopenharmony_ci[clinic start generated code]*/
2897db96d56Sopenharmony_ci
2907db96d56Sopenharmony_cistatic PyObject *
2917db96d56Sopenharmony_ci_gdbm_gdbm_setdefault_impl(gdbmobject *self, PyObject *key,
2927db96d56Sopenharmony_ci                           PyObject *default_value)
2937db96d56Sopenharmony_ci/*[clinic end generated code: output=f3246e880509f142 input=0db46b69e9680171]*/
2947db96d56Sopenharmony_ci{
2957db96d56Sopenharmony_ci    PyObject *res;
2967db96d56Sopenharmony_ci
2977db96d56Sopenharmony_ci    res = gdbm_subscript(self, key);
2987db96d56Sopenharmony_ci    if (res == NULL && PyErr_ExceptionMatches(PyExc_KeyError)) {
2997db96d56Sopenharmony_ci        PyErr_Clear();
3007db96d56Sopenharmony_ci        if (gdbm_ass_sub(self, key, default_value) < 0)
3017db96d56Sopenharmony_ci            return NULL;
3027db96d56Sopenharmony_ci        return gdbm_subscript(self, key);
3037db96d56Sopenharmony_ci    }
3047db96d56Sopenharmony_ci    return res;
3057db96d56Sopenharmony_ci}
3067db96d56Sopenharmony_ci
3077db96d56Sopenharmony_ci/*[clinic input]
3087db96d56Sopenharmony_ci_gdbm.gdbm.close
3097db96d56Sopenharmony_ci
3107db96d56Sopenharmony_ciClose the database.
3117db96d56Sopenharmony_ci[clinic start generated code]*/
3127db96d56Sopenharmony_ci
3137db96d56Sopenharmony_cistatic PyObject *
3147db96d56Sopenharmony_ci_gdbm_gdbm_close_impl(gdbmobject *self)
3157db96d56Sopenharmony_ci/*[clinic end generated code: output=f5abb4d6bb9e52d5 input=0a203447379b45fd]*/
3167db96d56Sopenharmony_ci{
3177db96d56Sopenharmony_ci    if (self->di_dbm) {
3187db96d56Sopenharmony_ci        gdbm_close(self->di_dbm);
3197db96d56Sopenharmony_ci    }
3207db96d56Sopenharmony_ci    self->di_dbm = NULL;
3217db96d56Sopenharmony_ci    Py_RETURN_NONE;
3227db96d56Sopenharmony_ci}
3237db96d56Sopenharmony_ci
3247db96d56Sopenharmony_ci/* XXX Should return a set or a set view */
3257db96d56Sopenharmony_ci/*[clinic input]
3267db96d56Sopenharmony_ci_gdbm.gdbm.keys
3277db96d56Sopenharmony_ci
3287db96d56Sopenharmony_ci    cls: defining_class
3297db96d56Sopenharmony_ci
3307db96d56Sopenharmony_ciGet a list of all keys in the database.
3317db96d56Sopenharmony_ci[clinic start generated code]*/
3327db96d56Sopenharmony_ci
3337db96d56Sopenharmony_cistatic PyObject *
3347db96d56Sopenharmony_ci_gdbm_gdbm_keys_impl(gdbmobject *self, PyTypeObject *cls)
3357db96d56Sopenharmony_ci/*[clinic end generated code: output=c24b824e81404755 input=1428b7c79703d7d5]*/
3367db96d56Sopenharmony_ci{
3377db96d56Sopenharmony_ci    PyObject *v, *item;
3387db96d56Sopenharmony_ci    datum key, nextkey;
3397db96d56Sopenharmony_ci    int err;
3407db96d56Sopenharmony_ci
3417db96d56Sopenharmony_ci    _gdbm_state *state = PyType_GetModuleState(cls);
3427db96d56Sopenharmony_ci    assert(state != NULL);
3437db96d56Sopenharmony_ci
3447db96d56Sopenharmony_ci    if (self == NULL || !Py_IS_TYPE(self, state->gdbm_type)) {
3457db96d56Sopenharmony_ci        PyErr_BadInternalCall();
3467db96d56Sopenharmony_ci        return NULL;
3477db96d56Sopenharmony_ci    }
3487db96d56Sopenharmony_ci    check_gdbmobject_open(self, state->gdbm_error);
3497db96d56Sopenharmony_ci
3507db96d56Sopenharmony_ci    v = PyList_New(0);
3517db96d56Sopenharmony_ci    if (v == NULL)
3527db96d56Sopenharmony_ci        return NULL;
3537db96d56Sopenharmony_ci
3547db96d56Sopenharmony_ci    key = gdbm_firstkey(self->di_dbm);
3557db96d56Sopenharmony_ci    while (key.dptr) {
3567db96d56Sopenharmony_ci        item = PyBytes_FromStringAndSize(key.dptr, key.dsize);
3577db96d56Sopenharmony_ci        if (item == NULL) {
3587db96d56Sopenharmony_ci            free(key.dptr);
3597db96d56Sopenharmony_ci            Py_DECREF(v);
3607db96d56Sopenharmony_ci            return NULL;
3617db96d56Sopenharmony_ci        }
3627db96d56Sopenharmony_ci        err = PyList_Append(v, item);
3637db96d56Sopenharmony_ci        Py_DECREF(item);
3647db96d56Sopenharmony_ci        if (err != 0) {
3657db96d56Sopenharmony_ci            free(key.dptr);
3667db96d56Sopenharmony_ci            Py_DECREF(v);
3677db96d56Sopenharmony_ci            return NULL;
3687db96d56Sopenharmony_ci        }
3697db96d56Sopenharmony_ci        nextkey = gdbm_nextkey(self->di_dbm, key);
3707db96d56Sopenharmony_ci        free(key.dptr);
3717db96d56Sopenharmony_ci        key = nextkey;
3727db96d56Sopenharmony_ci    }
3737db96d56Sopenharmony_ci    return v;
3747db96d56Sopenharmony_ci}
3757db96d56Sopenharmony_ci
3767db96d56Sopenharmony_cistatic int
3777db96d56Sopenharmony_cigdbm_contains(PyObject *self, PyObject *arg)
3787db96d56Sopenharmony_ci{
3797db96d56Sopenharmony_ci    gdbmobject *dp = (gdbmobject *)self;
3807db96d56Sopenharmony_ci    datum key;
3817db96d56Sopenharmony_ci    Py_ssize_t size;
3827db96d56Sopenharmony_ci    _gdbm_state *state = PyType_GetModuleState(Py_TYPE(dp));
3837db96d56Sopenharmony_ci
3847db96d56Sopenharmony_ci    if ((dp)->di_dbm == NULL) {
3857db96d56Sopenharmony_ci        PyErr_SetString(state->gdbm_error,
3867db96d56Sopenharmony_ci                        "GDBM object has already been closed");
3877db96d56Sopenharmony_ci        return -1;
3887db96d56Sopenharmony_ci    }
3897db96d56Sopenharmony_ci    if (PyUnicode_Check(arg)) {
3907db96d56Sopenharmony_ci        key.dptr = (char *)PyUnicode_AsUTF8AndSize(arg, &size);
3917db96d56Sopenharmony_ci        key.dsize = size;
3927db96d56Sopenharmony_ci        if (key.dptr == NULL)
3937db96d56Sopenharmony_ci            return -1;
3947db96d56Sopenharmony_ci    }
3957db96d56Sopenharmony_ci    else if (!PyBytes_Check(arg)) {
3967db96d56Sopenharmony_ci        PyErr_Format(PyExc_TypeError,
3977db96d56Sopenharmony_ci                     "gdbm key must be bytes or string, not %.100s",
3987db96d56Sopenharmony_ci                     Py_TYPE(arg)->tp_name);
3997db96d56Sopenharmony_ci        return -1;
4007db96d56Sopenharmony_ci    }
4017db96d56Sopenharmony_ci    else {
4027db96d56Sopenharmony_ci        key.dptr = PyBytes_AS_STRING(arg);
4037db96d56Sopenharmony_ci        key.dsize = PyBytes_GET_SIZE(arg);
4047db96d56Sopenharmony_ci    }
4057db96d56Sopenharmony_ci    return gdbm_exists(dp->di_dbm, key);
4067db96d56Sopenharmony_ci}
4077db96d56Sopenharmony_ci
4087db96d56Sopenharmony_ci/*[clinic input]
4097db96d56Sopenharmony_ci_gdbm.gdbm.firstkey
4107db96d56Sopenharmony_ci
4117db96d56Sopenharmony_ci    cls: defining_class
4127db96d56Sopenharmony_ci
4137db96d56Sopenharmony_ciReturn the starting key for the traversal.
4147db96d56Sopenharmony_ci
4157db96d56Sopenharmony_ciIt's possible to loop over every key in the database using this method
4167db96d56Sopenharmony_ciand the nextkey() method.  The traversal is ordered by GDBM's internal
4177db96d56Sopenharmony_cihash values, and won't be sorted by the key values.
4187db96d56Sopenharmony_ci[clinic start generated code]*/
4197db96d56Sopenharmony_ci
4207db96d56Sopenharmony_cistatic PyObject *
4217db96d56Sopenharmony_ci_gdbm_gdbm_firstkey_impl(gdbmobject *self, PyTypeObject *cls)
4227db96d56Sopenharmony_ci/*[clinic end generated code: output=139275e9c8b60827 input=ed8782a029a5d299]*/
4237db96d56Sopenharmony_ci{
4247db96d56Sopenharmony_ci    PyObject *v;
4257db96d56Sopenharmony_ci    datum key;
4267db96d56Sopenharmony_ci    _gdbm_state *state = PyType_GetModuleState(cls);
4277db96d56Sopenharmony_ci    assert(state != NULL);
4287db96d56Sopenharmony_ci
4297db96d56Sopenharmony_ci    check_gdbmobject_open(self, state->gdbm_error);
4307db96d56Sopenharmony_ci    key = gdbm_firstkey(self->di_dbm);
4317db96d56Sopenharmony_ci    if (key.dptr) {
4327db96d56Sopenharmony_ci        v = PyBytes_FromStringAndSize(key.dptr, key.dsize);
4337db96d56Sopenharmony_ci        free(key.dptr);
4347db96d56Sopenharmony_ci        return v;
4357db96d56Sopenharmony_ci    }
4367db96d56Sopenharmony_ci    else {
4377db96d56Sopenharmony_ci        Py_RETURN_NONE;
4387db96d56Sopenharmony_ci    }
4397db96d56Sopenharmony_ci}
4407db96d56Sopenharmony_ci
4417db96d56Sopenharmony_ci/*[clinic input]
4427db96d56Sopenharmony_ci_gdbm.gdbm.nextkey
4437db96d56Sopenharmony_ci
4447db96d56Sopenharmony_ci    cls: defining_class
4457db96d56Sopenharmony_ci    key: str(accept={str, robuffer}, zeroes=True)
4467db96d56Sopenharmony_ci    /
4477db96d56Sopenharmony_ci
4487db96d56Sopenharmony_ciReturns the key that follows key in the traversal.
4497db96d56Sopenharmony_ci
4507db96d56Sopenharmony_ciThe following code prints every key in the database db, without having
4517db96d56Sopenharmony_cito create a list in memory that contains them all:
4527db96d56Sopenharmony_ci
4537db96d56Sopenharmony_ci      k = db.firstkey()
4547db96d56Sopenharmony_ci      while k is not None:
4557db96d56Sopenharmony_ci          print(k)
4567db96d56Sopenharmony_ci          k = db.nextkey(k)
4577db96d56Sopenharmony_ci[clinic start generated code]*/
4587db96d56Sopenharmony_ci
4597db96d56Sopenharmony_cistatic PyObject *
4607db96d56Sopenharmony_ci_gdbm_gdbm_nextkey_impl(gdbmobject *self, PyTypeObject *cls, const char *key,
4617db96d56Sopenharmony_ci                        Py_ssize_t key_length)
4627db96d56Sopenharmony_ci/*[clinic end generated code: output=c81a69300ef41766 input=365e297bc0b3db48]*/
4637db96d56Sopenharmony_ci{
4647db96d56Sopenharmony_ci    PyObject *v;
4657db96d56Sopenharmony_ci    datum dbm_key, nextkey;
4667db96d56Sopenharmony_ci    _gdbm_state *state = PyType_GetModuleState(cls);
4677db96d56Sopenharmony_ci    assert(state != NULL);
4687db96d56Sopenharmony_ci
4697db96d56Sopenharmony_ci    dbm_key.dptr = (char *)key;
4707db96d56Sopenharmony_ci    dbm_key.dsize = key_length;
4717db96d56Sopenharmony_ci    check_gdbmobject_open(self, state->gdbm_error);
4727db96d56Sopenharmony_ci    nextkey = gdbm_nextkey(self->di_dbm, dbm_key);
4737db96d56Sopenharmony_ci    if (nextkey.dptr) {
4747db96d56Sopenharmony_ci        v = PyBytes_FromStringAndSize(nextkey.dptr, nextkey.dsize);
4757db96d56Sopenharmony_ci        free(nextkey.dptr);
4767db96d56Sopenharmony_ci        return v;
4777db96d56Sopenharmony_ci    }
4787db96d56Sopenharmony_ci    else {
4797db96d56Sopenharmony_ci        Py_RETURN_NONE;
4807db96d56Sopenharmony_ci    }
4817db96d56Sopenharmony_ci}
4827db96d56Sopenharmony_ci
4837db96d56Sopenharmony_ci/*[clinic input]
4847db96d56Sopenharmony_ci_gdbm.gdbm.reorganize
4857db96d56Sopenharmony_ci
4867db96d56Sopenharmony_ci    cls: defining_class
4877db96d56Sopenharmony_ci
4887db96d56Sopenharmony_ciReorganize the database.
4897db96d56Sopenharmony_ci
4907db96d56Sopenharmony_ciIf you have carried out a lot of deletions and would like to shrink
4917db96d56Sopenharmony_cithe space used by the GDBM file, this routine will reorganize the
4927db96d56Sopenharmony_cidatabase.  GDBM will not shorten the length of a database file except
4937db96d56Sopenharmony_ciby using this reorganization; otherwise, deleted file space will be
4947db96d56Sopenharmony_cikept and reused as new (key,value) pairs are added.
4957db96d56Sopenharmony_ci[clinic start generated code]*/
4967db96d56Sopenharmony_ci
4977db96d56Sopenharmony_cistatic PyObject *
4987db96d56Sopenharmony_ci_gdbm_gdbm_reorganize_impl(gdbmobject *self, PyTypeObject *cls)
4997db96d56Sopenharmony_ci/*[clinic end generated code: output=d77c69e8e3dd644a input=e1359faeef844e46]*/
5007db96d56Sopenharmony_ci{
5017db96d56Sopenharmony_ci    _gdbm_state *state = PyType_GetModuleState(cls);
5027db96d56Sopenharmony_ci    assert(state != NULL);
5037db96d56Sopenharmony_ci    check_gdbmobject_open(self, state->gdbm_error);
5047db96d56Sopenharmony_ci    errno = 0;
5057db96d56Sopenharmony_ci    if (gdbm_reorganize(self->di_dbm) < 0) {
5067db96d56Sopenharmony_ci        if (errno != 0)
5077db96d56Sopenharmony_ci            PyErr_SetFromErrno(state->gdbm_error);
5087db96d56Sopenharmony_ci        else
5097db96d56Sopenharmony_ci            PyErr_SetString(state->gdbm_error, gdbm_strerror(gdbm_errno));
5107db96d56Sopenharmony_ci        return NULL;
5117db96d56Sopenharmony_ci    }
5127db96d56Sopenharmony_ci    Py_RETURN_NONE;
5137db96d56Sopenharmony_ci}
5147db96d56Sopenharmony_ci
5157db96d56Sopenharmony_ci/*[clinic input]
5167db96d56Sopenharmony_ci_gdbm.gdbm.sync
5177db96d56Sopenharmony_ci
5187db96d56Sopenharmony_ci    cls: defining_class
5197db96d56Sopenharmony_ci
5207db96d56Sopenharmony_ciFlush the database to the disk file.
5217db96d56Sopenharmony_ci
5227db96d56Sopenharmony_ciWhen the database has been opened in fast mode, this method forces
5237db96d56Sopenharmony_ciany unwritten data to be written to the disk.
5247db96d56Sopenharmony_ci[clinic start generated code]*/
5257db96d56Sopenharmony_ci
5267db96d56Sopenharmony_cistatic PyObject *
5277db96d56Sopenharmony_ci_gdbm_gdbm_sync_impl(gdbmobject *self, PyTypeObject *cls)
5287db96d56Sopenharmony_ci/*[clinic end generated code: output=bb680a2035c3f592 input=3d749235f79b6f2a]*/
5297db96d56Sopenharmony_ci{
5307db96d56Sopenharmony_ci    _gdbm_state *state = PyType_GetModuleState(cls);
5317db96d56Sopenharmony_ci    assert(state != NULL);
5327db96d56Sopenharmony_ci    check_gdbmobject_open(self, state->gdbm_error);
5337db96d56Sopenharmony_ci    gdbm_sync(self->di_dbm);
5347db96d56Sopenharmony_ci    Py_RETURN_NONE;
5357db96d56Sopenharmony_ci}
5367db96d56Sopenharmony_ci
5377db96d56Sopenharmony_cistatic PyObject *
5387db96d56Sopenharmony_cigdbm__enter__(PyObject *self, PyObject *args)
5397db96d56Sopenharmony_ci{
5407db96d56Sopenharmony_ci    Py_INCREF(self);
5417db96d56Sopenharmony_ci    return self;
5427db96d56Sopenharmony_ci}
5437db96d56Sopenharmony_ci
5447db96d56Sopenharmony_cistatic PyObject *
5457db96d56Sopenharmony_cigdbm__exit__(PyObject *self, PyObject *args)
5467db96d56Sopenharmony_ci{
5477db96d56Sopenharmony_ci    return _gdbm_gdbm_close_impl((gdbmobject *)self);
5487db96d56Sopenharmony_ci}
5497db96d56Sopenharmony_ci
5507db96d56Sopenharmony_cistatic PyMethodDef gdbm_methods[] = {
5517db96d56Sopenharmony_ci    _GDBM_GDBM_CLOSE_METHODDEF
5527db96d56Sopenharmony_ci    _GDBM_GDBM_KEYS_METHODDEF
5537db96d56Sopenharmony_ci    _GDBM_GDBM_FIRSTKEY_METHODDEF
5547db96d56Sopenharmony_ci    _GDBM_GDBM_NEXTKEY_METHODDEF
5557db96d56Sopenharmony_ci    _GDBM_GDBM_REORGANIZE_METHODDEF
5567db96d56Sopenharmony_ci    _GDBM_GDBM_SYNC_METHODDEF
5577db96d56Sopenharmony_ci    _GDBM_GDBM_GET_METHODDEF
5587db96d56Sopenharmony_ci    _GDBM_GDBM_SETDEFAULT_METHODDEF
5597db96d56Sopenharmony_ci    {"__enter__", gdbm__enter__, METH_NOARGS, NULL},
5607db96d56Sopenharmony_ci    {"__exit__",  gdbm__exit__, METH_VARARGS, NULL},
5617db96d56Sopenharmony_ci    {NULL,              NULL}           /* sentinel */
5627db96d56Sopenharmony_ci};
5637db96d56Sopenharmony_ci
5647db96d56Sopenharmony_cistatic PyType_Slot gdbmtype_spec_slots[] = {
5657db96d56Sopenharmony_ci    {Py_tp_dealloc, gdbm_dealloc},
5667db96d56Sopenharmony_ci    {Py_tp_traverse, gdbm_traverse},
5677db96d56Sopenharmony_ci    {Py_tp_methods, gdbm_methods},
5687db96d56Sopenharmony_ci    {Py_sq_contains, gdbm_contains},
5697db96d56Sopenharmony_ci    {Py_mp_length, gdbm_length},
5707db96d56Sopenharmony_ci    {Py_mp_subscript, gdbm_subscript},
5717db96d56Sopenharmony_ci    {Py_mp_ass_subscript, gdbm_ass_sub},
5727db96d56Sopenharmony_ci    {Py_tp_doc, (char*)gdbm_object__doc__},
5737db96d56Sopenharmony_ci    {0, 0}
5747db96d56Sopenharmony_ci};
5757db96d56Sopenharmony_ci
5767db96d56Sopenharmony_cistatic PyType_Spec gdbmtype_spec = {
5777db96d56Sopenharmony_ci    .name = "_gdbm.gdbm",
5787db96d56Sopenharmony_ci    .basicsize = sizeof(gdbmobject),
5797db96d56Sopenharmony_ci    // Calling PyType_GetModuleState() on a subclass is not safe.
5807db96d56Sopenharmony_ci    // dbmtype_spec does not have Py_TPFLAGS_BASETYPE flag
5817db96d56Sopenharmony_ci    // which prevents to create a subclass.
5827db96d56Sopenharmony_ci    // So calling PyType_GetModuleState() in this file is always safe.
5837db96d56Sopenharmony_ci    .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION |
5847db96d56Sopenharmony_ci              Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE),
5857db96d56Sopenharmony_ci    .slots = gdbmtype_spec_slots,
5867db96d56Sopenharmony_ci};
5877db96d56Sopenharmony_ci
5887db96d56Sopenharmony_ci/* ----------------------------------------------------------------- */
5897db96d56Sopenharmony_ci
5907db96d56Sopenharmony_ci/*[clinic input]
5917db96d56Sopenharmony_ci_gdbm.open as dbmopen
5927db96d56Sopenharmony_ci
5937db96d56Sopenharmony_ci    filename: object
5947db96d56Sopenharmony_ci    flags: str="r"
5957db96d56Sopenharmony_ci    mode: int(py_default="0o666") = 0o666
5967db96d56Sopenharmony_ci    /
5977db96d56Sopenharmony_ci
5987db96d56Sopenharmony_ciOpen a dbm database and return a dbm object.
5997db96d56Sopenharmony_ci
6007db96d56Sopenharmony_ciThe filename argument is the name of the database file.
6017db96d56Sopenharmony_ci
6027db96d56Sopenharmony_ciThe optional flags argument can be 'r' (to open an existing database
6037db96d56Sopenharmony_cifor reading only -- default), 'w' (to open an existing database for
6047db96d56Sopenharmony_cireading and writing), 'c' (which creates the database if it doesn't
6057db96d56Sopenharmony_ciexist), or 'n' (which always creates a new empty database).
6067db96d56Sopenharmony_ci
6077db96d56Sopenharmony_ciSome versions of gdbm support additional flags which must be
6087db96d56Sopenharmony_ciappended to one of the flags described above.  The module constant
6097db96d56Sopenharmony_ci'open_flags' is a string of valid additional flags.  The 'f' flag
6107db96d56Sopenharmony_ciopens the database in fast mode; altered data will not automatically
6117db96d56Sopenharmony_cibe written to the disk after every change.  This results in faster
6127db96d56Sopenharmony_ciwrites to the database, but may result in an inconsistent database
6137db96d56Sopenharmony_ciif the program crashes while the database is still open.  Use the
6147db96d56Sopenharmony_cisync() method to force any unwritten data to be written to the disk.
6157db96d56Sopenharmony_ciThe 's' flag causes all database operations to be synchronized to
6167db96d56Sopenharmony_cidisk.  The 'u' flag disables locking of the database file.
6177db96d56Sopenharmony_ci
6187db96d56Sopenharmony_ciThe optional mode argument is the Unix mode of the file, used only
6197db96d56Sopenharmony_ciwhen the database has to be created.  It defaults to octal 0o666.
6207db96d56Sopenharmony_ci[clinic start generated code]*/
6217db96d56Sopenharmony_ci
6227db96d56Sopenharmony_cistatic PyObject *
6237db96d56Sopenharmony_cidbmopen_impl(PyObject *module, PyObject *filename, const char *flags,
6247db96d56Sopenharmony_ci             int mode)
6257db96d56Sopenharmony_ci/*[clinic end generated code: output=9527750f5df90764 input=bca6ec81dc49292c]*/
6267db96d56Sopenharmony_ci{
6277db96d56Sopenharmony_ci    int iflags;
6287db96d56Sopenharmony_ci    _gdbm_state *state = get_gdbm_state(module);
6297db96d56Sopenharmony_ci    assert(state != NULL);
6307db96d56Sopenharmony_ci
6317db96d56Sopenharmony_ci    switch (flags[0]) {
6327db96d56Sopenharmony_ci    case 'r':
6337db96d56Sopenharmony_ci        iflags = GDBM_READER;
6347db96d56Sopenharmony_ci        break;
6357db96d56Sopenharmony_ci    case 'w':
6367db96d56Sopenharmony_ci        iflags = GDBM_WRITER;
6377db96d56Sopenharmony_ci        break;
6387db96d56Sopenharmony_ci    case 'c':
6397db96d56Sopenharmony_ci        iflags = GDBM_WRCREAT;
6407db96d56Sopenharmony_ci        break;
6417db96d56Sopenharmony_ci    case 'n':
6427db96d56Sopenharmony_ci        iflags = GDBM_NEWDB;
6437db96d56Sopenharmony_ci        break;
6447db96d56Sopenharmony_ci    default:
6457db96d56Sopenharmony_ci        PyErr_SetString(state->gdbm_error,
6467db96d56Sopenharmony_ci                        "First flag must be one of 'r', 'w', 'c' or 'n'");
6477db96d56Sopenharmony_ci        return NULL;
6487db96d56Sopenharmony_ci    }
6497db96d56Sopenharmony_ci    for (flags++; *flags != '\0'; flags++) {
6507db96d56Sopenharmony_ci        char buf[40];
6517db96d56Sopenharmony_ci        switch (*flags) {
6527db96d56Sopenharmony_ci#ifdef GDBM_FAST
6537db96d56Sopenharmony_ci            case 'f':
6547db96d56Sopenharmony_ci                iflags |= GDBM_FAST;
6557db96d56Sopenharmony_ci                break;
6567db96d56Sopenharmony_ci#endif
6577db96d56Sopenharmony_ci#ifdef GDBM_SYNC
6587db96d56Sopenharmony_ci            case 's':
6597db96d56Sopenharmony_ci                iflags |= GDBM_SYNC;
6607db96d56Sopenharmony_ci                break;
6617db96d56Sopenharmony_ci#endif
6627db96d56Sopenharmony_ci#ifdef GDBM_NOLOCK
6637db96d56Sopenharmony_ci            case 'u':
6647db96d56Sopenharmony_ci                iflags |= GDBM_NOLOCK;
6657db96d56Sopenharmony_ci                break;
6667db96d56Sopenharmony_ci#endif
6677db96d56Sopenharmony_ci            default:
6687db96d56Sopenharmony_ci                PyOS_snprintf(buf, sizeof(buf), "Flag '%c' is not supported.",
6697db96d56Sopenharmony_ci                              *flags);
6707db96d56Sopenharmony_ci                PyErr_SetString(state->gdbm_error, buf);
6717db96d56Sopenharmony_ci                return NULL;
6727db96d56Sopenharmony_ci        }
6737db96d56Sopenharmony_ci    }
6747db96d56Sopenharmony_ci
6757db96d56Sopenharmony_ci    PyObject *filenamebytes;
6767db96d56Sopenharmony_ci    if (!PyUnicode_FSConverter(filename, &filenamebytes)) {
6777db96d56Sopenharmony_ci        return NULL;
6787db96d56Sopenharmony_ci    }
6797db96d56Sopenharmony_ci
6807db96d56Sopenharmony_ci    const char *name = PyBytes_AS_STRING(filenamebytes);
6817db96d56Sopenharmony_ci    if (strlen(name) != (size_t)PyBytes_GET_SIZE(filenamebytes)) {
6827db96d56Sopenharmony_ci        Py_DECREF(filenamebytes);
6837db96d56Sopenharmony_ci        PyErr_SetString(PyExc_ValueError, "embedded null character");
6847db96d56Sopenharmony_ci        return NULL;
6857db96d56Sopenharmony_ci    }
6867db96d56Sopenharmony_ci    PyObject *self = newgdbmobject(state, name, iflags, mode);
6877db96d56Sopenharmony_ci    Py_DECREF(filenamebytes);
6887db96d56Sopenharmony_ci    return self;
6897db96d56Sopenharmony_ci}
6907db96d56Sopenharmony_ci
6917db96d56Sopenharmony_cistatic const char gdbmmodule_open_flags[] = "rwcn"
6927db96d56Sopenharmony_ci#ifdef GDBM_FAST
6937db96d56Sopenharmony_ci                                     "f"
6947db96d56Sopenharmony_ci#endif
6957db96d56Sopenharmony_ci#ifdef GDBM_SYNC
6967db96d56Sopenharmony_ci                                     "s"
6977db96d56Sopenharmony_ci#endif
6987db96d56Sopenharmony_ci#ifdef GDBM_NOLOCK
6997db96d56Sopenharmony_ci                                     "u"
7007db96d56Sopenharmony_ci#endif
7017db96d56Sopenharmony_ci                                     ;
7027db96d56Sopenharmony_ci
7037db96d56Sopenharmony_cistatic PyMethodDef _gdbm_module_methods[] = {
7047db96d56Sopenharmony_ci    DBMOPEN_METHODDEF
7057db96d56Sopenharmony_ci    { 0, 0 },
7067db96d56Sopenharmony_ci};
7077db96d56Sopenharmony_ci
7087db96d56Sopenharmony_cistatic int
7097db96d56Sopenharmony_ci_gdbm_exec(PyObject *module)
7107db96d56Sopenharmony_ci{
7117db96d56Sopenharmony_ci    _gdbm_state *state = get_gdbm_state(module);
7127db96d56Sopenharmony_ci    state->gdbm_type = (PyTypeObject *)PyType_FromModuleAndSpec(module,
7137db96d56Sopenharmony_ci                                                        &gdbmtype_spec, NULL);
7147db96d56Sopenharmony_ci    if (state->gdbm_type == NULL) {
7157db96d56Sopenharmony_ci        return -1;
7167db96d56Sopenharmony_ci    }
7177db96d56Sopenharmony_ci    state->gdbm_error = PyErr_NewException("_gdbm.error", PyExc_OSError, NULL);
7187db96d56Sopenharmony_ci    if (state->gdbm_error == NULL) {
7197db96d56Sopenharmony_ci        return -1;
7207db96d56Sopenharmony_ci    }
7217db96d56Sopenharmony_ci    if (PyModule_AddType(module, (PyTypeObject *)state->gdbm_error) < 0) {
7227db96d56Sopenharmony_ci        return -1;
7237db96d56Sopenharmony_ci    }
7247db96d56Sopenharmony_ci    if (PyModule_AddStringConstant(module, "open_flags",
7257db96d56Sopenharmony_ci                                   gdbmmodule_open_flags) < 0) {
7267db96d56Sopenharmony_ci        return -1;
7277db96d56Sopenharmony_ci    }
7287db96d56Sopenharmony_ci
7297db96d56Sopenharmony_ci#if defined(GDBM_VERSION_MAJOR) && defined(GDBM_VERSION_MINOR) && \
7307db96d56Sopenharmony_ci    defined(GDBM_VERSION_PATCH)
7317db96d56Sopenharmony_ci    PyObject *obj = Py_BuildValue("iii", GDBM_VERSION_MAJOR,
7327db96d56Sopenharmony_ci                                  GDBM_VERSION_MINOR, GDBM_VERSION_PATCH);
7337db96d56Sopenharmony_ci    if (obj == NULL) {
7347db96d56Sopenharmony_ci        return -1;
7357db96d56Sopenharmony_ci    }
7367db96d56Sopenharmony_ci    if (PyModule_AddObject(module, "_GDBM_VERSION", obj) < 0) {
7377db96d56Sopenharmony_ci        Py_DECREF(obj);
7387db96d56Sopenharmony_ci        return -1;
7397db96d56Sopenharmony_ci    }
7407db96d56Sopenharmony_ci#endif
7417db96d56Sopenharmony_ci    return 0;
7427db96d56Sopenharmony_ci}
7437db96d56Sopenharmony_ci
7447db96d56Sopenharmony_cistatic int
7457db96d56Sopenharmony_ci_gdbm_module_traverse(PyObject *module, visitproc visit, void *arg)
7467db96d56Sopenharmony_ci{
7477db96d56Sopenharmony_ci    _gdbm_state *state = get_gdbm_state(module);
7487db96d56Sopenharmony_ci    Py_VISIT(state->gdbm_error);
7497db96d56Sopenharmony_ci    Py_VISIT(state->gdbm_type);
7507db96d56Sopenharmony_ci    return 0;
7517db96d56Sopenharmony_ci}
7527db96d56Sopenharmony_ci
7537db96d56Sopenharmony_cistatic int
7547db96d56Sopenharmony_ci_gdbm_module_clear(PyObject *module)
7557db96d56Sopenharmony_ci{
7567db96d56Sopenharmony_ci    _gdbm_state *state = get_gdbm_state(module);
7577db96d56Sopenharmony_ci    Py_CLEAR(state->gdbm_error);
7587db96d56Sopenharmony_ci    Py_CLEAR(state->gdbm_type);
7597db96d56Sopenharmony_ci    return 0;
7607db96d56Sopenharmony_ci}
7617db96d56Sopenharmony_ci
7627db96d56Sopenharmony_cistatic void
7637db96d56Sopenharmony_ci_gdbm_module_free(void *module)
7647db96d56Sopenharmony_ci{
7657db96d56Sopenharmony_ci    _gdbm_module_clear((PyObject *)module);
7667db96d56Sopenharmony_ci}
7677db96d56Sopenharmony_ci
7687db96d56Sopenharmony_cistatic PyModuleDef_Slot _gdbm_module_slots[] = {
7697db96d56Sopenharmony_ci    {Py_mod_exec, _gdbm_exec},
7707db96d56Sopenharmony_ci    {0, NULL}
7717db96d56Sopenharmony_ci};
7727db96d56Sopenharmony_ci
7737db96d56Sopenharmony_cistatic struct PyModuleDef _gdbmmodule = {
7747db96d56Sopenharmony_ci    PyModuleDef_HEAD_INIT,
7757db96d56Sopenharmony_ci    .m_name = "_gdbm",
7767db96d56Sopenharmony_ci    .m_doc = gdbmmodule__doc__,
7777db96d56Sopenharmony_ci    .m_size = sizeof(_gdbm_state),
7787db96d56Sopenharmony_ci    .m_methods = _gdbm_module_methods,
7797db96d56Sopenharmony_ci    .m_slots = _gdbm_module_slots,
7807db96d56Sopenharmony_ci    .m_traverse = _gdbm_module_traverse,
7817db96d56Sopenharmony_ci    .m_clear = _gdbm_module_clear,
7827db96d56Sopenharmony_ci    .m_free = _gdbm_module_free,
7837db96d56Sopenharmony_ci};
7847db96d56Sopenharmony_ci
7857db96d56Sopenharmony_ciPyMODINIT_FUNC
7867db96d56Sopenharmony_ciPyInit__gdbm(void)
7877db96d56Sopenharmony_ci{
7887db96d56Sopenharmony_ci    return PyModuleDef_Init(&_gdbmmodule);
7897db96d56Sopenharmony_ci}
790