(root)/
Python-3.12.0/
Modules/
_gdbmmodule.c
       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  }