bpo-1635741: Port _gdbm module to multiphase initialization (GH-20920)

This commit is contained in:
Dong-hee Na 2020-06-17 01:41:23 +09:00 committed by GitHub
parent 51c5896b62
commit c4862e333a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 283 additions and 199 deletions

View File

@ -0,0 +1 @@
Port :mod:`_gdbm` to multiphase initialization.

View File

@ -1,5 +1,5 @@
/* DBM module using dictionary interface */ /* GDBM module using dictionary interface */
/* Author: Anthony Baxter, after dbmmodule.c */ /* Author: Anthony Baxter, after dbmmodule.c */
/* Doc strings: Mitch Chapman */ /* Doc strings: Mitch Chapman */
@ -16,11 +16,24 @@
extern const char * gdbm_strerror(gdbm_error); extern const char * gdbm_strerror(gdbm_error);
#endif #endif
typedef struct {
PyTypeObject *gdbm_type;
PyObject *gdbm_error;
} _gdbm_state;
static inline _gdbm_state*
get_gdbm_state(PyObject *module)
{
void *state = PyModule_GetState(module);
assert(state != NULL);
return (_gdbm_state *)state;
}
/*[clinic input] /*[clinic input]
module _gdbm module _gdbm
class _gdbm.gdbm "dbmobject *" "&Dbmtype" class _gdbm.gdbm "gdbmobject *" "&Gdbmtype"
[clinic start generated code]*/ [clinic start generated code]*/
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=113927c6170729b2]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=38ae71cedfc7172b]*/
PyDoc_STRVAR(gdbmmodule__doc__, PyDoc_STRVAR(gdbmmodule__doc__,
"This module provides an interface to the GNU DBM (GDBM) library.\n\ "This module provides an interface to the GNU DBM (GDBM) library.\n\
@ -38,20 +51,15 @@ typedef struct {
PyObject_HEAD PyObject_HEAD
Py_ssize_t di_size; /* -1 means recompute */ Py_ssize_t di_size; /* -1 means recompute */
GDBM_FILE di_dbm; GDBM_FILE di_dbm;
} dbmobject; } gdbmobject;
static PyTypeObject Dbmtype;
#include "clinic/_gdbmmodule.c.h" #include "clinic/_gdbmmodule.c.h"
#define is_dbmobject(v) Py_IS_TYPE(v, &Dbmtype) #define check_gdbmobject_open(v, err) \
#define check_dbmobject_open(v) if ((v)->di_dbm == NULL) \ if ((v)->di_dbm == NULL) { \
{ PyErr_SetString(DbmError, "GDBM object has already been closed"); \ PyErr_SetString(err, "GDBM object has already been closed"); \
return NULL; } return NULL; \
}
static PyObject *DbmError;
PyDoc_STRVAR(gdbm_object__doc__, PyDoc_STRVAR(gdbm_object__doc__,
"This object represents a GDBM database.\n\ "This object represents a GDBM database.\n\
@ -64,20 +72,21 @@ GDBM objects also support additional operations such as firstkey,\n\
nextkey, reorganize, and sync."); nextkey, reorganize, and sync.");
static PyObject * static PyObject *
newdbmobject(const char *file, int flags, int mode) newgdbmobject(_gdbm_state *state, const char *file, int flags, int mode)
{ {
dbmobject *dp; gdbmobject *dp = PyObject_New(gdbmobject, state->gdbm_type);
if (dp == NULL) {
dp = PyObject_New(dbmobject, &Dbmtype);
if (dp == NULL)
return NULL; return NULL;
}
dp->di_size = -1; dp->di_size = -1;
errno = 0; errno = 0;
if ((dp->di_dbm = gdbm_open((char *)file, 0, flags, mode, NULL)) == 0) { if ((dp->di_dbm = gdbm_open((char *)file, 0, flags, mode, NULL)) == 0) {
if (errno != 0) if (errno != 0) {
PyErr_SetFromErrnoWithFilename(DbmError, file); PyErr_SetFromErrnoWithFilename(state->gdbm_error, file);
else }
PyErr_SetString(DbmError, gdbm_strerror(gdbm_errno)); else {
PyErr_SetString(state->gdbm_error, gdbm_strerror(gdbm_errno));
}
Py_DECREF(dp); Py_DECREF(dp);
return NULL; return NULL;
} }
@ -87,18 +96,22 @@ newdbmobject(const char *file, int flags, int mode)
/* Methods */ /* Methods */
static void static void
dbm_dealloc(dbmobject *dp) gdbm_dealloc(gdbmobject *dp)
{ {
if (dp->di_dbm) if (dp->di_dbm) {
gdbm_close(dp->di_dbm); gdbm_close(dp->di_dbm);
PyObject_Del(dp); }
PyTypeObject *tp = Py_TYPE(dp);
tp->tp_free(dp);
Py_DECREF(tp);
} }
static Py_ssize_t static Py_ssize_t
dbm_length(dbmobject *dp) gdbm_length(gdbmobject *dp)
{ {
_gdbm_state *state = PyType_GetModuleState(Py_TYPE(dp));
if (dp->di_dbm == NULL) { if (dp->di_dbm == NULL) {
PyErr_SetString(DbmError, "GDBM object has already been closed"); PyErr_SetString(state->gdbm_error, "GDBM object has already been closed");
return -1; return -1;
} }
if (dp->di_size < 0) { if (dp->di_size < 0) {
@ -107,10 +120,10 @@ dbm_length(dbmobject *dp)
gdbm_count_t count; gdbm_count_t count;
if (gdbm_count(dp->di_dbm, &count) == -1) { if (gdbm_count(dp->di_dbm, &count) == -1) {
if (errno != 0) { if (errno != 0) {
PyErr_SetFromErrno(DbmError); PyErr_SetFromErrno(state->gdbm_error);
} }
else { else {
PyErr_SetString(DbmError, gdbm_strerror(gdbm_errno)); PyErr_SetString(state->gdbm_error, gdbm_strerror(gdbm_errno));
} }
return -1; return -1;
} }
@ -161,16 +174,17 @@ parse_datum(PyObject *o, datum *d, const char *failmsg)
} }
static PyObject * static PyObject *
dbm_subscript(dbmobject *dp, PyObject *key) gdbm_subscript(gdbmobject *dp, PyObject *key)
{ {
PyObject *v; PyObject *v;
datum drec, krec; datum drec, krec;
_gdbm_state *state = PyType_GetModuleState(Py_TYPE(dp));
if (!parse_datum(key, &krec, NULL)) { if (!parse_datum(key, &krec, NULL)) {
return NULL; return NULL;
} }
if (dp->di_dbm == NULL) { if (dp->di_dbm == NULL) {
PyErr_SetString(DbmError, PyErr_SetString(state->gdbm_error,
"GDBM object has already been closed"); "GDBM object has already been closed");
return NULL; return NULL;
} }
@ -195,12 +209,12 @@ Get the value for key, or default if not present.
[clinic start generated code]*/ [clinic start generated code]*/
static PyObject * static PyObject *
_gdbm_gdbm_get_impl(dbmobject *self, PyObject *key, PyObject *default_value) _gdbm_gdbm_get_impl(gdbmobject *self, PyObject *key, PyObject *default_value)
/*[clinic end generated code: output=19b7c585ad4f554a input=a9c20423f34c17b6]*/ /*[clinic end generated code: output=92421838f3a852f4 input=a9c20423f34c17b6]*/
{ {
PyObject *res; PyObject *res;
res = dbm_subscript(self, key); res = gdbm_subscript(self, key);
if (res == NULL && PyErr_ExceptionMatches(PyExc_KeyError)) { if (res == NULL && PyErr_ExceptionMatches(PyExc_KeyError)) {
PyErr_Clear(); PyErr_Clear();
Py_INCREF(default_value); Py_INCREF(default_value);
@ -210,16 +224,17 @@ _gdbm_gdbm_get_impl(dbmobject *self, PyObject *key, PyObject *default_value)
} }
static int static int
dbm_ass_sub(dbmobject *dp, PyObject *v, PyObject *w) gdbm_ass_sub(gdbmobject *dp, PyObject *v, PyObject *w)
{ {
datum krec, drec; datum krec, drec;
const char *failmsg = "gdbm mappings have bytes or string indices only"; const char *failmsg = "gdbm mappings have bytes or string indices only";
_gdbm_state *state = PyType_GetModuleState(Py_TYPE(dp));
if (!parse_datum(v, &krec, failmsg)) { if (!parse_datum(v, &krec, failmsg)) {
return -1; return -1;
} }
if (dp->di_dbm == NULL) { if (dp->di_dbm == NULL) {
PyErr_SetString(DbmError, PyErr_SetString(state->gdbm_error,
"GDBM object has already been closed"); "GDBM object has already been closed");
return -1; return -1;
} }
@ -230,7 +245,7 @@ dbm_ass_sub(dbmobject *dp, PyObject *v, PyObject *w)
PyErr_SetObject(PyExc_KeyError, v); PyErr_SetObject(PyExc_KeyError, v);
} }
else { else {
PyErr_SetString(DbmError, gdbm_strerror(gdbm_errno)); PyErr_SetString(state->gdbm_error, gdbm_strerror(gdbm_errno));
} }
return -1; return -1;
} }
@ -242,9 +257,9 @@ dbm_ass_sub(dbmobject *dp, PyObject *v, PyObject *w)
errno = 0; errno = 0;
if (gdbm_store(dp->di_dbm, krec, drec, GDBM_REPLACE) < 0) { if (gdbm_store(dp->di_dbm, krec, drec, GDBM_REPLACE) < 0) {
if (errno != 0) if (errno != 0)
PyErr_SetFromErrno(DbmError); PyErr_SetFromErrno(state->gdbm_error);
else else
PyErr_SetString(DbmError, PyErr_SetString(state->gdbm_error,
gdbm_strerror(gdbm_errno)); gdbm_strerror(gdbm_errno));
return -1; return -1;
} }
@ -263,28 +278,22 @@ Get value for key, or set it to default and return default if not present.
[clinic start generated code]*/ [clinic start generated code]*/
static PyObject * static PyObject *
_gdbm_gdbm_setdefault_impl(dbmobject *self, PyObject *key, _gdbm_gdbm_setdefault_impl(gdbmobject *self, PyObject *key,
PyObject *default_value) PyObject *default_value)
/*[clinic end generated code: output=88760ee520329012 input=0db46b69e9680171]*/ /*[clinic end generated code: output=f3246e880509f142 input=0db46b69e9680171]*/
{ {
PyObject *res; PyObject *res;
res = dbm_subscript(self, key); res = gdbm_subscript(self, key);
if (res == NULL && PyErr_ExceptionMatches(PyExc_KeyError)) { if (res == NULL && PyErr_ExceptionMatches(PyExc_KeyError)) {
PyErr_Clear(); PyErr_Clear();
if (dbm_ass_sub(self, key, default_value) < 0) if (gdbm_ass_sub(self, key, default_value) < 0)
return NULL; return NULL;
return dbm_subscript(self, key); return gdbm_subscript(self, key);
} }
return res; return res;
} }
static PyMappingMethods dbm_as_mapping = {
(lenfunc)dbm_length, /*mp_length*/
(binaryfunc)dbm_subscript, /*mp_subscript*/
(objobjargproc)dbm_ass_sub, /*mp_ass_subscript*/
};
/*[clinic input] /*[clinic input]
_gdbm.gdbm.close _gdbm.gdbm.close
@ -292,11 +301,12 @@ Close the database.
[clinic start generated code]*/ [clinic start generated code]*/
static PyObject * static PyObject *
_gdbm_gdbm_close_impl(dbmobject *self) _gdbm_gdbm_close_impl(gdbmobject *self)
/*[clinic end generated code: output=23512a594598b563 input=0a203447379b45fd]*/ /*[clinic end generated code: output=f5abb4d6bb9e52d5 input=0a203447379b45fd]*/
{ {
if (self->di_dbm) if (self->di_dbm) {
gdbm_close(self->di_dbm); gdbm_close(self->di_dbm);
}
self->di_dbm = NULL; self->di_dbm = NULL;
Py_RETURN_NONE; Py_RETURN_NONE;
} }
@ -305,22 +315,27 @@ _gdbm_gdbm_close_impl(dbmobject *self)
/*[clinic input] /*[clinic input]
_gdbm.gdbm.keys _gdbm.gdbm.keys
cls: defining_class
Get a list of all keys in the database. Get a list of all keys in the database.
[clinic start generated code]*/ [clinic start generated code]*/
static PyObject * static PyObject *
_gdbm_gdbm_keys_impl(dbmobject *self) _gdbm_gdbm_keys_impl(gdbmobject *self, PyTypeObject *cls)
/*[clinic end generated code: output=cb4b1776c3645dcc input=1832ee0a3132cfaf]*/ /*[clinic end generated code: output=c24b824e81404755 input=1428b7c79703d7d5]*/
{ {
PyObject *v, *item; PyObject *v, *item;
datum key, nextkey; datum key, nextkey;
int err; int err;
if (self == NULL || !is_dbmobject(self)) { _gdbm_state *state = PyType_GetModuleState(cls);
assert(state != NULL);
if (self == NULL || !Py_IS_TYPE(self, state->gdbm_type)) {
PyErr_BadInternalCall(); PyErr_BadInternalCall();
return NULL; return NULL;
} }
check_dbmobject_open(self); check_gdbmobject_open(self, state->gdbm_error);
v = PyList_New(0); v = PyList_New(0);
if (v == NULL) if (v == NULL)
@ -349,14 +364,15 @@ _gdbm_gdbm_keys_impl(dbmobject *self)
} }
static int static int
dbm_contains(PyObject *self, PyObject *arg) gdbm_contains(PyObject *self, PyObject *arg)
{ {
dbmobject *dp = (dbmobject *)self; gdbmobject *dp = (gdbmobject *)self;
datum key; datum key;
Py_ssize_t size; Py_ssize_t size;
_gdbm_state *state = PyType_GetModuleState(Py_TYPE(dp));
if ((dp)->di_dbm == NULL) { if ((dp)->di_dbm == NULL) {
PyErr_SetString(DbmError, PyErr_SetString(state->gdbm_error,
"GDBM object has already been closed"); "GDBM object has already been closed");
return -1; return -1;
} }
@ -379,22 +395,11 @@ dbm_contains(PyObject *self, PyObject *arg)
return gdbm_exists(dp->di_dbm, key); return gdbm_exists(dp->di_dbm, key);
} }
static PySequenceMethods dbm_as_sequence = {
0, /* sq_length */
0, /* sq_concat */
0, /* sq_repeat */
0, /* sq_item */
0, /* sq_slice */
0, /* sq_ass_item */
0, /* sq_ass_slice */
dbm_contains, /* sq_contains */
0, /* sq_inplace_concat */
0, /* sq_inplace_repeat */
};
/*[clinic input] /*[clinic input]
_gdbm.gdbm.firstkey _gdbm.gdbm.firstkey
cls: defining_class
Return the starting key for the traversal. Return the starting key for the traversal.
It's possible to loop over every key in the database using this method It's possible to loop over every key in the database using this method
@ -403,13 +408,15 @@ hash values, and won't be sorted by the key values.
[clinic start generated code]*/ [clinic start generated code]*/
static PyObject * static PyObject *
_gdbm_gdbm_firstkey_impl(dbmobject *self) _gdbm_gdbm_firstkey_impl(gdbmobject *self, PyTypeObject *cls)
/*[clinic end generated code: output=9ff85628d84b65d2 input=0dbd6a335d69bba0]*/ /*[clinic end generated code: output=139275e9c8b60827 input=ed8782a029a5d299]*/
{ {
PyObject *v; PyObject *v;
datum key; datum key;
_gdbm_state *state = PyType_GetModuleState(cls);
assert(state != NULL);
check_dbmobject_open(self); check_gdbmobject_open(self, state->gdbm_error);
key = gdbm_firstkey(self->di_dbm); key = gdbm_firstkey(self->di_dbm);
if (key.dptr) { if (key.dptr) {
v = PyBytes_FromStringAndSize(key.dptr, key.dsize); v = PyBytes_FromStringAndSize(key.dptr, key.dsize);
@ -424,6 +431,7 @@ _gdbm_gdbm_firstkey_impl(dbmobject *self)
/*[clinic input] /*[clinic input]
_gdbm.gdbm.nextkey _gdbm.gdbm.nextkey
cls: defining_class
key: str(accept={str, robuffer}, zeroes=True) key: str(accept={str, robuffer}, zeroes=True)
/ /
@ -439,16 +447,18 @@ to create a list in memory that contains them all:
[clinic start generated code]*/ [clinic start generated code]*/
static PyObject * static PyObject *
_gdbm_gdbm_nextkey_impl(dbmobject *self, const char *key, _gdbm_gdbm_nextkey_impl(gdbmobject *self, PyTypeObject *cls, const char *key,
Py_ssize_clean_t key_length) Py_ssize_clean_t key_length)
/*[clinic end generated code: output=192ab892de6eb2f6 input=1f1606943614e36f]*/ /*[clinic end generated code: output=204964441fdbaf02 input=fcf6a51a96ce0172]*/
{ {
PyObject *v; PyObject *v;
datum dbm_key, nextkey; datum dbm_key, nextkey;
_gdbm_state *state = PyType_GetModuleState(cls);
assert(state != NULL);
dbm_key.dptr = (char *)key; dbm_key.dptr = (char *)key;
dbm_key.dsize = key_length; dbm_key.dsize = key_length;
check_dbmobject_open(self); check_gdbmobject_open(self, state->gdbm_error);
nextkey = gdbm_nextkey(self->di_dbm, dbm_key); nextkey = gdbm_nextkey(self->di_dbm, dbm_key);
if (nextkey.dptr) { if (nextkey.dptr) {
v = PyBytes_FromStringAndSize(nextkey.dptr, nextkey.dsize); v = PyBytes_FromStringAndSize(nextkey.dptr, nextkey.dsize);
@ -463,6 +473,8 @@ _gdbm_gdbm_nextkey_impl(dbmobject *self, const char *key,
/*[clinic input] /*[clinic input]
_gdbm.gdbm.reorganize _gdbm.gdbm.reorganize
cls: defining_class
Reorganize the database. Reorganize the database.
If you have carried out a lot of deletions and would like to shrink If you have carried out a lot of deletions and would like to shrink
@ -473,16 +485,18 @@ kept and reused as new (key,value) pairs are added.
[clinic start generated code]*/ [clinic start generated code]*/
static PyObject * static PyObject *
_gdbm_gdbm_reorganize_impl(dbmobject *self) _gdbm_gdbm_reorganize_impl(gdbmobject *self, PyTypeObject *cls)
/*[clinic end generated code: output=38d9624df92e961d input=f6bea85bcfd40dd2]*/ /*[clinic end generated code: output=d77c69e8e3dd644a input=e1359faeef844e46]*/
{ {
check_dbmobject_open(self); _gdbm_state *state = PyType_GetModuleState(cls);
assert(state != NULL);
check_gdbmobject_open(self, state->gdbm_error);
errno = 0; errno = 0;
if (gdbm_reorganize(self->di_dbm) < 0) { if (gdbm_reorganize(self->di_dbm) < 0) {
if (errno != 0) if (errno != 0)
PyErr_SetFromErrno(DbmError); PyErr_SetFromErrno(state->gdbm_error);
else else
PyErr_SetString(DbmError, gdbm_strerror(gdbm_errno)); PyErr_SetString(state->gdbm_error, gdbm_strerror(gdbm_errno));
return NULL; return NULL;
} }
Py_RETURN_NONE; Py_RETURN_NONE;
@ -491,6 +505,8 @@ _gdbm_gdbm_reorganize_impl(dbmobject *self)
/*[clinic input] /*[clinic input]
_gdbm.gdbm.sync _gdbm.gdbm.sync
cls: defining_class
Flush the database to the disk file. Flush the database to the disk file.
When the database has been opened in fast mode, this method forces When the database has been opened in fast mode, this method forces
@ -498,29 +514,31 @@ any unwritten data to be written to the disk.
[clinic start generated code]*/ [clinic start generated code]*/
static PyObject * static PyObject *
_gdbm_gdbm_sync_impl(dbmobject *self) _gdbm_gdbm_sync_impl(gdbmobject *self, PyTypeObject *cls)
/*[clinic end generated code: output=488b15f47028f125 input=2a47d2c9e153ab8a]*/ /*[clinic end generated code: output=bb680a2035c3f592 input=3d749235f79b6f2a]*/
{ {
check_dbmobject_open(self); _gdbm_state *state = PyType_GetModuleState(cls);
assert(state != NULL);
check_gdbmobject_open(self, state->gdbm_error);
gdbm_sync(self->di_dbm); gdbm_sync(self->di_dbm);
Py_RETURN_NONE; Py_RETURN_NONE;
} }
static PyObject * static PyObject *
dbm__enter__(PyObject *self, PyObject *args) gdbm__enter__(PyObject *self, PyObject *args)
{ {
Py_INCREF(self); Py_INCREF(self);
return self; return self;
} }
static PyObject * static PyObject *
dbm__exit__(PyObject *self, PyObject *args) gdbm__exit__(PyObject *self, PyObject *args)
{ {
_Py_IDENTIFIER(close); _Py_IDENTIFIER(close);
return _PyObject_CallMethodIdNoArgs(self, &PyId_close); return _PyObject_CallMethodIdNoArgs(self, &PyId_close);
} }
static PyMethodDef dbm_methods[] = { static PyMethodDef gdbm_methods[] = {
_GDBM_GDBM_CLOSE_METHODDEF _GDBM_GDBM_CLOSE_METHODDEF
_GDBM_GDBM_KEYS_METHODDEF _GDBM_GDBM_KEYS_METHODDEF
_GDBM_GDBM_FIRSTKEY_METHODDEF _GDBM_GDBM_FIRSTKEY_METHODDEF
@ -529,46 +547,38 @@ static PyMethodDef dbm_methods[] = {
_GDBM_GDBM_SYNC_METHODDEF _GDBM_GDBM_SYNC_METHODDEF
_GDBM_GDBM_GET_METHODDEF _GDBM_GDBM_GET_METHODDEF
_GDBM_GDBM_SETDEFAULT_METHODDEF _GDBM_GDBM_SETDEFAULT_METHODDEF
{"__enter__", dbm__enter__, METH_NOARGS, NULL}, {"__enter__", gdbm__enter__, METH_NOARGS, NULL},
{"__exit__", dbm__exit__, METH_VARARGS, NULL}, {"__exit__", gdbm__exit__, METH_VARARGS, NULL},
{NULL, NULL} /* sentinel */ {NULL, NULL} /* sentinel */
}; };
static PyTypeObject Dbmtype = { static PyType_Slot gdbmtype_spec_slots[] = {
PyVarObject_HEAD_INIT(0, 0) {Py_tp_dealloc, gdbm_dealloc},
"_gdbm.gdbm", {Py_tp_methods, gdbm_methods},
sizeof(dbmobject), {Py_sq_contains, gdbm_contains},
0, {Py_mp_length, gdbm_length},
(destructor)dbm_dealloc, /*tp_dealloc*/ {Py_mp_subscript, gdbm_subscript},
0, /*tp_vectorcall_offset*/ {Py_mp_ass_subscript, gdbm_ass_sub},
0, /*tp_getattr*/ {Py_tp_doc, (char*)gdbm_object__doc__},
0, /*tp_setattr*/ {0, 0}
0, /*tp_as_async*/ };
0, /*tp_repr*/
0, /*tp_as_number*/ static PyType_Spec gdbmtype_spec = {
&dbm_as_sequence, /*tp_as_sequence*/ .name = "_gdbm.gdbm",
&dbm_as_mapping, /*tp_as_mapping*/ .basicsize = sizeof(gdbmobject),
0, /*tp_hash*/ // Calling PyType_GetModuleState() on a subclass is not safe.
0, /*tp_call*/ // dbmtype_spec does not have Py_TPFLAGS_BASETYPE flag
0, /*tp_str*/ // which prevents to create a subclass.
0, /*tp_getattro*/ // So calling PyType_GetModuleState() in this file is always safe.
0, /*tp_setattro*/ .flags = Py_TPFLAGS_DEFAULT,
0, /*tp_as_buffer*/ .slots = gdbmtype_spec_slots,
Py_TPFLAGS_DEFAULT, /*tp_xxx4*/
gdbm_object__doc__, /*tp_doc*/
0, /*tp_traverse*/
0, /*tp_clear*/
0, /*tp_richcompare*/
0, /*tp_weaklistoffset*/
0, /*tp_iter*/
0, /*tp_iternext*/
dbm_methods, /*tp_methods*/
}; };
/* ----------------------------------------------------------------- */ /* ----------------------------------------------------------------- */
/*[clinic input] /*[clinic input]
_gdbm.open as dbmopen _gdbm.open as dbmopen
filename: unicode filename: unicode
flags: str="r" flags: str="r"
mode: int(py_default="0o666") = 0o666 mode: int(py_default="0o666") = 0o666
@ -601,9 +611,11 @@ when the database has to be created. It defaults to octal 0o666.
static PyObject * static PyObject *
dbmopen_impl(PyObject *module, PyObject *filename, const char *flags, dbmopen_impl(PyObject *module, PyObject *filename, const char *flags,
int mode) int mode)
/*[clinic end generated code: output=9527750f5df90764 input=3be0b0875974b928]*/ /*[clinic end generated code: output=9527750f5df90764 input=812b7d74399ceb0e]*/
{ {
int iflags; int iflags;
_gdbm_state *state = get_gdbm_state(module);
assert(state != NULL);
switch (flags[0]) { switch (flags[0]) {
case 'r': case 'r':
@ -619,7 +631,7 @@ dbmopen_impl(PyObject *module, PyObject *filename, const char *flags,
iflags = GDBM_NEWDB; iflags = GDBM_NEWDB;
break; break;
default: default:
PyErr_SetString(DbmError, PyErr_SetString(state->gdbm_error,
"First flag must be one of 'r', 'w', 'c' or 'n'"); "First flag must be one of 'r', 'w', 'c' or 'n'");
return NULL; return NULL;
} }
@ -644,7 +656,7 @@ dbmopen_impl(PyObject *module, PyObject *filename, const char *flags,
default: default:
PyOS_snprintf(buf, sizeof(buf), "Flag '%c' is not supported.", PyOS_snprintf(buf, sizeof(buf), "Flag '%c' is not supported.",
*flags); *flags);
PyErr_SetString(DbmError, buf); PyErr_SetString(state->gdbm_error, buf);
return NULL; return NULL;
} }
} }
@ -659,12 +671,12 @@ dbmopen_impl(PyObject *module, PyObject *filename, const char *flags,
PyErr_SetString(PyExc_ValueError, "embedded null character"); PyErr_SetString(PyExc_ValueError, "embedded null character");
return NULL; return NULL;
} }
PyObject *self = newdbmobject(name, iflags, mode); PyObject *self = newgdbmobject(state, name, iflags, mode);
Py_DECREF(filenamebytes); Py_DECREF(filenamebytes);
return self; return self;
} }
static const char dbmmodule_open_flags[] = "rwcn" static const char gdbmmodule_open_flags[] = "rwcn"
#ifdef GDBM_FAST #ifdef GDBM_FAST
"f" "f"
#endif #endif
@ -676,48 +688,30 @@ static const char dbmmodule_open_flags[] = "rwcn"
#endif #endif
; ;
static PyMethodDef dbmmodule_methods[] = { static PyMethodDef _gdbm_module_methods[] = {
DBMOPEN_METHODDEF DBMOPEN_METHODDEF
{ 0, 0 }, { 0, 0 },
}; };
static int
static struct PyModuleDef _gdbmmodule = { _gdbm_exec(PyObject *module)
PyModuleDef_HEAD_INIT, {
"_gdbm", _gdbm_state *state = get_gdbm_state(module);
gdbmmodule__doc__, state->gdbm_type = (PyTypeObject *)PyType_FromModuleAndSpec(module,
-1, &gdbmtype_spec, NULL);
dbmmodule_methods, if (state->gdbm_type == NULL) {
NULL, return -1;
NULL,
NULL,
NULL
};
PyMODINIT_FUNC
PyInit__gdbm(void) {
PyObject *m;
if (PyType_Ready(&Dbmtype) < 0)
return NULL;
m = PyModule_Create(&_gdbmmodule);
if (m == NULL) {
return NULL;
} }
state->gdbm_error = PyErr_NewException("_gdbm.error", PyExc_OSError, NULL);
DbmError = PyErr_NewException("_gdbm.error", PyExc_OSError, NULL); if (state->gdbm_error == NULL) {
if (DbmError == NULL) { return -1;
goto error;
} }
Py_INCREF(DbmError); if (PyModule_AddType(module, (PyTypeObject *)state->gdbm_error) < 0) {
if (PyModule_AddObject(m, "error", DbmError) < 0) { return -1;
Py_DECREF(DbmError);
goto error;
} }
if (PyModule_AddStringConstant(module, "open_flags",
if (PyModule_AddStringConstant(m, "open_flags", gdbmmodule_open_flags) < 0) {
dbmmodule_open_flags) < 0) { return -1;
goto error;
} }
#if defined(GDBM_VERSION_MAJOR) && defined(GDBM_VERSION_MINOR) && \ #if defined(GDBM_VERSION_MAJOR) && defined(GDBM_VERSION_MINOR) && \
@ -725,17 +719,59 @@ PyInit__gdbm(void) {
PyObject *obj = Py_BuildValue("iii", GDBM_VERSION_MAJOR, PyObject *obj = Py_BuildValue("iii", GDBM_VERSION_MAJOR,
GDBM_VERSION_MINOR, GDBM_VERSION_PATCH); GDBM_VERSION_MINOR, GDBM_VERSION_PATCH);
if (obj == NULL) { if (obj == NULL) {
goto error; return -1;
} }
if (PyModule_AddObject(m, "_GDBM_VERSION", obj) < 0) { if (PyModule_AddObject(module, "_GDBM_VERSION", obj) < 0) {
Py_DECREF(obj); Py_DECREF(obj);
goto error; return -1;
} }
#endif #endif
return 0;
return m; }
error: static int
Py_DECREF(m); _gdbm_module_traverse(PyObject *module, visitproc visit, void *arg)
return NULL; {
_gdbm_state *state = get_gdbm_state(module);
Py_VISIT(state->gdbm_error);
Py_VISIT(state->gdbm_type);
return 0;
}
static int
_gdbm_module_clear(PyObject *module)
{
_gdbm_state *state = get_gdbm_state(module);
Py_CLEAR(state->gdbm_error);
Py_CLEAR(state->gdbm_type);
return 0;
}
static void
_gdbm_module_free(void *module)
{
_gdbm_module_clear((PyObject *)module);
}
static PyModuleDef_Slot _gdbm_module_slots[] = {
{Py_mod_exec, _gdbm_exec},
{0, NULL}
};
static struct PyModuleDef _gdbmmodule = {
PyModuleDef_HEAD_INIT,
.m_name = "_gdbm",
.m_doc = gdbmmodule__doc__,
.m_size = sizeof(_gdbm_state),
.m_methods = _gdbm_module_methods,
.m_slots = _gdbm_module_slots,
.m_traverse = _gdbm_module_traverse,
.m_clear = _gdbm_module_clear,
.m_free = _gdbm_module_free,
};
PyMODINIT_FUNC
PyInit__gdbm(void)
{
return PyModuleDef_Init(&_gdbmmodule);
} }

View File

@ -12,10 +12,10 @@ PyDoc_STRVAR(_gdbm_gdbm_get__doc__,
{"get", (PyCFunction)(void(*)(void))_gdbm_gdbm_get, METH_FASTCALL, _gdbm_gdbm_get__doc__}, {"get", (PyCFunction)(void(*)(void))_gdbm_gdbm_get, METH_FASTCALL, _gdbm_gdbm_get__doc__},
static PyObject * static PyObject *
_gdbm_gdbm_get_impl(dbmobject *self, PyObject *key, PyObject *default_value); _gdbm_gdbm_get_impl(gdbmobject *self, PyObject *key, PyObject *default_value);
static PyObject * static PyObject *
_gdbm_gdbm_get(dbmobject *self, PyObject *const *args, Py_ssize_t nargs) _gdbm_gdbm_get(gdbmobject *self, PyObject *const *args, Py_ssize_t nargs)
{ {
PyObject *return_value = NULL; PyObject *return_value = NULL;
PyObject *key; PyObject *key;
@ -46,11 +46,11 @@ PyDoc_STRVAR(_gdbm_gdbm_setdefault__doc__,
{"setdefault", (PyCFunction)(void(*)(void))_gdbm_gdbm_setdefault, METH_FASTCALL, _gdbm_gdbm_setdefault__doc__}, {"setdefault", (PyCFunction)(void(*)(void))_gdbm_gdbm_setdefault, METH_FASTCALL, _gdbm_gdbm_setdefault__doc__},
static PyObject * static PyObject *
_gdbm_gdbm_setdefault_impl(dbmobject *self, PyObject *key, _gdbm_gdbm_setdefault_impl(gdbmobject *self, PyObject *key,
PyObject *default_value); PyObject *default_value);
static PyObject * static PyObject *
_gdbm_gdbm_setdefault(dbmobject *self, PyObject *const *args, Py_ssize_t nargs) _gdbm_gdbm_setdefault(gdbmobject *self, PyObject *const *args, Py_ssize_t nargs)
{ {
PyObject *return_value = NULL; PyObject *return_value = NULL;
PyObject *key; PyObject *key;
@ -81,10 +81,10 @@ PyDoc_STRVAR(_gdbm_gdbm_close__doc__,
{"close", (PyCFunction)_gdbm_gdbm_close, METH_NOARGS, _gdbm_gdbm_close__doc__}, {"close", (PyCFunction)_gdbm_gdbm_close, METH_NOARGS, _gdbm_gdbm_close__doc__},
static PyObject * static PyObject *
_gdbm_gdbm_close_impl(dbmobject *self); _gdbm_gdbm_close_impl(gdbmobject *self);
static PyObject * static PyObject *
_gdbm_gdbm_close(dbmobject *self, PyObject *Py_UNUSED(ignored)) _gdbm_gdbm_close(gdbmobject *self, PyObject *Py_UNUSED(ignored))
{ {
return _gdbm_gdbm_close_impl(self); return _gdbm_gdbm_close_impl(self);
} }
@ -96,15 +96,26 @@ PyDoc_STRVAR(_gdbm_gdbm_keys__doc__,
"Get a list of all keys in the database."); "Get a list of all keys in the database.");
#define _GDBM_GDBM_KEYS_METHODDEF \ #define _GDBM_GDBM_KEYS_METHODDEF \
{"keys", (PyCFunction)_gdbm_gdbm_keys, METH_NOARGS, _gdbm_gdbm_keys__doc__}, {"keys", (PyCFunction)(void(*)(void))_gdbm_gdbm_keys, METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _gdbm_gdbm_keys__doc__},
static PyObject * static PyObject *
_gdbm_gdbm_keys_impl(dbmobject *self); _gdbm_gdbm_keys_impl(gdbmobject *self, PyTypeObject *cls);
static PyObject * static PyObject *
_gdbm_gdbm_keys(dbmobject *self, PyObject *Py_UNUSED(ignored)) _gdbm_gdbm_keys(gdbmobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
{ {
return _gdbm_gdbm_keys_impl(self); PyObject *return_value = NULL;
static const char * const _keywords[] = { NULL};
static _PyArg_Parser _parser = {":keys", _keywords, 0};
if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser
)) {
goto exit;
}
return_value = _gdbm_gdbm_keys_impl(self, cls);
exit:
return return_value;
} }
PyDoc_STRVAR(_gdbm_gdbm_firstkey__doc__, PyDoc_STRVAR(_gdbm_gdbm_firstkey__doc__,
@ -118,15 +129,26 @@ PyDoc_STRVAR(_gdbm_gdbm_firstkey__doc__,
"hash values, and won\'t be sorted by the key values."); "hash values, and won\'t be sorted by the key values.");
#define _GDBM_GDBM_FIRSTKEY_METHODDEF \ #define _GDBM_GDBM_FIRSTKEY_METHODDEF \
{"firstkey", (PyCFunction)_gdbm_gdbm_firstkey, METH_NOARGS, _gdbm_gdbm_firstkey__doc__}, {"firstkey", (PyCFunction)(void(*)(void))_gdbm_gdbm_firstkey, METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _gdbm_gdbm_firstkey__doc__},
static PyObject * static PyObject *
_gdbm_gdbm_firstkey_impl(dbmobject *self); _gdbm_gdbm_firstkey_impl(gdbmobject *self, PyTypeObject *cls);
static PyObject * static PyObject *
_gdbm_gdbm_firstkey(dbmobject *self, PyObject *Py_UNUSED(ignored)) _gdbm_gdbm_firstkey(gdbmobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
{ {
return _gdbm_gdbm_firstkey_impl(self); PyObject *return_value = NULL;
static const char * const _keywords[] = { NULL};
static _PyArg_Parser _parser = {":firstkey", _keywords, 0};
if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser
)) {
goto exit;
}
return_value = _gdbm_gdbm_firstkey_impl(self, cls);
exit:
return return_value;
} }
PyDoc_STRVAR(_gdbm_gdbm_nextkey__doc__, PyDoc_STRVAR(_gdbm_gdbm_nextkey__doc__,
@ -144,23 +166,26 @@ PyDoc_STRVAR(_gdbm_gdbm_nextkey__doc__,
" k = db.nextkey(k)"); " k = db.nextkey(k)");
#define _GDBM_GDBM_NEXTKEY_METHODDEF \ #define _GDBM_GDBM_NEXTKEY_METHODDEF \
{"nextkey", (PyCFunction)_gdbm_gdbm_nextkey, METH_O, _gdbm_gdbm_nextkey__doc__}, {"nextkey", (PyCFunction)(void(*)(void))_gdbm_gdbm_nextkey, METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _gdbm_gdbm_nextkey__doc__},
static PyObject * static PyObject *
_gdbm_gdbm_nextkey_impl(dbmobject *self, const char *key, _gdbm_gdbm_nextkey_impl(gdbmobject *self, PyTypeObject *cls, const char *key,
Py_ssize_clean_t key_length); Py_ssize_clean_t key_length);
static PyObject * static PyObject *
_gdbm_gdbm_nextkey(dbmobject *self, PyObject *arg) _gdbm_gdbm_nextkey(gdbmobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
{ {
PyObject *return_value = NULL; PyObject *return_value = NULL;
static const char * const _keywords[] = {"", NULL};
static _PyArg_Parser _parser = {"s#:nextkey", _keywords, 0};
const char *key; const char *key;
Py_ssize_clean_t key_length; Py_ssize_clean_t key_length;
if (!PyArg_Parse(arg, "s#:nextkey", &key, &key_length)) { if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
&key, &key_length)) {
goto exit; goto exit;
} }
return_value = _gdbm_gdbm_nextkey_impl(self, key, key_length); return_value = _gdbm_gdbm_nextkey_impl(self, cls, key, key_length);
exit: exit:
return return_value; return return_value;
@ -179,15 +204,26 @@ PyDoc_STRVAR(_gdbm_gdbm_reorganize__doc__,
"kept and reused as new (key,value) pairs are added."); "kept and reused as new (key,value) pairs are added.");
#define _GDBM_GDBM_REORGANIZE_METHODDEF \ #define _GDBM_GDBM_REORGANIZE_METHODDEF \
{"reorganize", (PyCFunction)_gdbm_gdbm_reorganize, METH_NOARGS, _gdbm_gdbm_reorganize__doc__}, {"reorganize", (PyCFunction)(void(*)(void))_gdbm_gdbm_reorganize, METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _gdbm_gdbm_reorganize__doc__},
static PyObject * static PyObject *
_gdbm_gdbm_reorganize_impl(dbmobject *self); _gdbm_gdbm_reorganize_impl(gdbmobject *self, PyTypeObject *cls);
static PyObject * static PyObject *
_gdbm_gdbm_reorganize(dbmobject *self, PyObject *Py_UNUSED(ignored)) _gdbm_gdbm_reorganize(gdbmobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
{ {
return _gdbm_gdbm_reorganize_impl(self); PyObject *return_value = NULL;
static const char * const _keywords[] = { NULL};
static _PyArg_Parser _parser = {":reorganize", _keywords, 0};
if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser
)) {
goto exit;
}
return_value = _gdbm_gdbm_reorganize_impl(self, cls);
exit:
return return_value;
} }
PyDoc_STRVAR(_gdbm_gdbm_sync__doc__, PyDoc_STRVAR(_gdbm_gdbm_sync__doc__,
@ -200,15 +236,26 @@ PyDoc_STRVAR(_gdbm_gdbm_sync__doc__,
"any unwritten data to be written to the disk."); "any unwritten data to be written to the disk.");
#define _GDBM_GDBM_SYNC_METHODDEF \ #define _GDBM_GDBM_SYNC_METHODDEF \
{"sync", (PyCFunction)_gdbm_gdbm_sync, METH_NOARGS, _gdbm_gdbm_sync__doc__}, {"sync", (PyCFunction)(void(*)(void))_gdbm_gdbm_sync, METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _gdbm_gdbm_sync__doc__},
static PyObject * static PyObject *
_gdbm_gdbm_sync_impl(dbmobject *self); _gdbm_gdbm_sync_impl(gdbmobject *self, PyTypeObject *cls);
static PyObject * static PyObject *
_gdbm_gdbm_sync(dbmobject *self, PyObject *Py_UNUSED(ignored)) _gdbm_gdbm_sync(gdbmobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
{ {
return _gdbm_gdbm_sync_impl(self); PyObject *return_value = NULL;
static const char * const _keywords[] = { NULL};
static _PyArg_Parser _parser = {":sync", _keywords, 0};
if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser
)) {
goto exit;
}
return_value = _gdbm_gdbm_sync_impl(self, cls);
exit:
return return_value;
} }
PyDoc_STRVAR(dbmopen__doc__, PyDoc_STRVAR(dbmopen__doc__,
@ -293,4 +340,4 @@ skip_optional:
exit: exit:
return return_value; return return_value;
} }
/*[clinic end generated code: output=c9d43f42677f4efb input=a9049054013a1b77]*/ /*[clinic end generated code: output=e84bc6ac82fcb6d4 input=a9049054013a1b77]*/