bpo-1635741: Port _gdbm module to multiphase initialization (GH-20920)
This commit is contained in:
parent
51c5896b62
commit
c4862e333a
|
@ -0,0 +1 @@
|
|||
Port :mod:`_gdbm` to multiphase initialization.
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
/* DBM module using dictionary interface */
|
||||
/* GDBM module using dictionary interface */
|
||||
/* Author: Anthony Baxter, after dbmmodule.c */
|
||||
/* Doc strings: Mitch Chapman */
|
||||
|
||||
|
@ -16,11 +16,24 @@
|
|||
extern const char * gdbm_strerror(gdbm_error);
|
||||
#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]
|
||||
module _gdbm
|
||||
class _gdbm.gdbm "dbmobject *" "&Dbmtype"
|
||||
class _gdbm.gdbm "gdbmobject *" "&Gdbmtype"
|
||||
[clinic start generated code]*/
|
||||
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=113927c6170729b2]*/
|
||||
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=38ae71cedfc7172b]*/
|
||||
|
||||
PyDoc_STRVAR(gdbmmodule__doc__,
|
||||
"This module provides an interface to the GNU DBM (GDBM) library.\n\
|
||||
|
@ -38,20 +51,15 @@ typedef struct {
|
|||
PyObject_HEAD
|
||||
Py_ssize_t di_size; /* -1 means recompute */
|
||||
GDBM_FILE di_dbm;
|
||||
} dbmobject;
|
||||
|
||||
static PyTypeObject Dbmtype;
|
||||
} gdbmobject;
|
||||
|
||||
#include "clinic/_gdbmmodule.c.h"
|
||||
|
||||
#define is_dbmobject(v) Py_IS_TYPE(v, &Dbmtype)
|
||||
#define check_dbmobject_open(v) if ((v)->di_dbm == NULL) \
|
||||
{ PyErr_SetString(DbmError, "GDBM object has already been closed"); \
|
||||
return NULL; }
|
||||
|
||||
|
||||
|
||||
static PyObject *DbmError;
|
||||
#define check_gdbmobject_open(v, err) \
|
||||
if ((v)->di_dbm == NULL) { \
|
||||
PyErr_SetString(err, "GDBM object has already been closed"); \
|
||||
return NULL; \
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(gdbm_object__doc__,
|
||||
"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.");
|
||||
|
||||
static PyObject *
|
||||
newdbmobject(const char *file, int flags, int mode)
|
||||
newgdbmobject(_gdbm_state *state, const char *file, int flags, int mode)
|
||||
{
|
||||
dbmobject *dp;
|
||||
|
||||
dp = PyObject_New(dbmobject, &Dbmtype);
|
||||
if (dp == NULL)
|
||||
gdbmobject *dp = PyObject_New(gdbmobject, state->gdbm_type);
|
||||
if (dp == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
dp->di_size = -1;
|
||||
errno = 0;
|
||||
if ((dp->di_dbm = gdbm_open((char *)file, 0, flags, mode, NULL)) == 0) {
|
||||
if (errno != 0)
|
||||
PyErr_SetFromErrnoWithFilename(DbmError, file);
|
||||
else
|
||||
PyErr_SetString(DbmError, gdbm_strerror(gdbm_errno));
|
||||
if (errno != 0) {
|
||||
PyErr_SetFromErrnoWithFilename(state->gdbm_error, file);
|
||||
}
|
||||
else {
|
||||
PyErr_SetString(state->gdbm_error, gdbm_strerror(gdbm_errno));
|
||||
}
|
||||
Py_DECREF(dp);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -87,18 +96,22 @@ newdbmobject(const char *file, int flags, int mode)
|
|||
/* Methods */
|
||||
|
||||
static void
|
||||
dbm_dealloc(dbmobject *dp)
|
||||
gdbm_dealloc(gdbmobject *dp)
|
||||
{
|
||||
if (dp->di_dbm)
|
||||
if (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
|
||||
dbm_length(dbmobject *dp)
|
||||
gdbm_length(gdbmobject *dp)
|
||||
{
|
||||
_gdbm_state *state = PyType_GetModuleState(Py_TYPE(dp));
|
||||
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;
|
||||
}
|
||||
if (dp->di_size < 0) {
|
||||
|
@ -107,10 +120,10 @@ dbm_length(dbmobject *dp)
|
|||
gdbm_count_t count;
|
||||
if (gdbm_count(dp->di_dbm, &count) == -1) {
|
||||
if (errno != 0) {
|
||||
PyErr_SetFromErrno(DbmError);
|
||||
PyErr_SetFromErrno(state->gdbm_error);
|
||||
}
|
||||
else {
|
||||
PyErr_SetString(DbmError, gdbm_strerror(gdbm_errno));
|
||||
PyErr_SetString(state->gdbm_error, gdbm_strerror(gdbm_errno));
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
@ -161,16 +174,17 @@ parse_datum(PyObject *o, datum *d, const char *failmsg)
|
|||
}
|
||||
|
||||
static PyObject *
|
||||
dbm_subscript(dbmobject *dp, PyObject *key)
|
||||
gdbm_subscript(gdbmobject *dp, PyObject *key)
|
||||
{
|
||||
PyObject *v;
|
||||
datum drec, krec;
|
||||
_gdbm_state *state = PyType_GetModuleState(Py_TYPE(dp));
|
||||
|
||||
if (!parse_datum(key, &krec, NULL)) {
|
||||
return NULL;
|
||||
}
|
||||
if (dp->di_dbm == NULL) {
|
||||
PyErr_SetString(DbmError,
|
||||
PyErr_SetString(state->gdbm_error,
|
||||
"GDBM object has already been closed");
|
||||
return NULL;
|
||||
}
|
||||
|
@ -195,12 +209,12 @@ Get the value for key, or default if not present.
|
|||
[clinic start generated code]*/
|
||||
|
||||
static PyObject *
|
||||
_gdbm_gdbm_get_impl(dbmobject *self, PyObject *key, PyObject *default_value)
|
||||
/*[clinic end generated code: output=19b7c585ad4f554a input=a9c20423f34c17b6]*/
|
||||
_gdbm_gdbm_get_impl(gdbmobject *self, PyObject *key, PyObject *default_value)
|
||||
/*[clinic end generated code: output=92421838f3a852f4 input=a9c20423f34c17b6]*/
|
||||
{
|
||||
PyObject *res;
|
||||
|
||||
res = dbm_subscript(self, key);
|
||||
res = gdbm_subscript(self, key);
|
||||
if (res == NULL && PyErr_ExceptionMatches(PyExc_KeyError)) {
|
||||
PyErr_Clear();
|
||||
Py_INCREF(default_value);
|
||||
|
@ -210,16 +224,17 @@ _gdbm_gdbm_get_impl(dbmobject *self, PyObject *key, PyObject *default_value)
|
|||
}
|
||||
|
||||
static int
|
||||
dbm_ass_sub(dbmobject *dp, PyObject *v, PyObject *w)
|
||||
gdbm_ass_sub(gdbmobject *dp, PyObject *v, PyObject *w)
|
||||
{
|
||||
datum krec, drec;
|
||||
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)) {
|
||||
return -1;
|
||||
}
|
||||
if (dp->di_dbm == NULL) {
|
||||
PyErr_SetString(DbmError,
|
||||
PyErr_SetString(state->gdbm_error,
|
||||
"GDBM object has already been closed");
|
||||
return -1;
|
||||
}
|
||||
|
@ -230,7 +245,7 @@ dbm_ass_sub(dbmobject *dp, PyObject *v, PyObject *w)
|
|||
PyErr_SetObject(PyExc_KeyError, v);
|
||||
}
|
||||
else {
|
||||
PyErr_SetString(DbmError, gdbm_strerror(gdbm_errno));
|
||||
PyErr_SetString(state->gdbm_error, gdbm_strerror(gdbm_errno));
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
@ -242,9 +257,9 @@ dbm_ass_sub(dbmobject *dp, PyObject *v, PyObject *w)
|
|||
errno = 0;
|
||||
if (gdbm_store(dp->di_dbm, krec, drec, GDBM_REPLACE) < 0) {
|
||||
if (errno != 0)
|
||||
PyErr_SetFromErrno(DbmError);
|
||||
PyErr_SetFromErrno(state->gdbm_error);
|
||||
else
|
||||
PyErr_SetString(DbmError,
|
||||
PyErr_SetString(state->gdbm_error,
|
||||
gdbm_strerror(gdbm_errno));
|
||||
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]*/
|
||||
|
||||
static PyObject *
|
||||
_gdbm_gdbm_setdefault_impl(dbmobject *self, PyObject *key,
|
||||
_gdbm_gdbm_setdefault_impl(gdbmobject *self, PyObject *key,
|
||||
PyObject *default_value)
|
||||
/*[clinic end generated code: output=88760ee520329012 input=0db46b69e9680171]*/
|
||||
/*[clinic end generated code: output=f3246e880509f142 input=0db46b69e9680171]*/
|
||||
{
|
||||
PyObject *res;
|
||||
|
||||
res = dbm_subscript(self, key);
|
||||
res = gdbm_subscript(self, key);
|
||||
if (res == NULL && PyErr_ExceptionMatches(PyExc_KeyError)) {
|
||||
PyErr_Clear();
|
||||
if (dbm_ass_sub(self, key, default_value) < 0)
|
||||
if (gdbm_ass_sub(self, key, default_value) < 0)
|
||||
return NULL;
|
||||
return dbm_subscript(self, key);
|
||||
return gdbm_subscript(self, key);
|
||||
}
|
||||
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]
|
||||
_gdbm.gdbm.close
|
||||
|
||||
|
@ -292,11 +301,12 @@ Close the database.
|
|||
[clinic start generated code]*/
|
||||
|
||||
static PyObject *
|
||||
_gdbm_gdbm_close_impl(dbmobject *self)
|
||||
/*[clinic end generated code: output=23512a594598b563 input=0a203447379b45fd]*/
|
||||
_gdbm_gdbm_close_impl(gdbmobject *self)
|
||||
/*[clinic end generated code: output=f5abb4d6bb9e52d5 input=0a203447379b45fd]*/
|
||||
{
|
||||
if (self->di_dbm)
|
||||
if (self->di_dbm) {
|
||||
gdbm_close(self->di_dbm);
|
||||
}
|
||||
self->di_dbm = NULL;
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
@ -305,22 +315,27 @@ _gdbm_gdbm_close_impl(dbmobject *self)
|
|||
/*[clinic input]
|
||||
_gdbm.gdbm.keys
|
||||
|
||||
cls: defining_class
|
||||
|
||||
Get a list of all keys in the database.
|
||||
[clinic start generated code]*/
|
||||
|
||||
static PyObject *
|
||||
_gdbm_gdbm_keys_impl(dbmobject *self)
|
||||
/*[clinic end generated code: output=cb4b1776c3645dcc input=1832ee0a3132cfaf]*/
|
||||
_gdbm_gdbm_keys_impl(gdbmobject *self, PyTypeObject *cls)
|
||||
/*[clinic end generated code: output=c24b824e81404755 input=1428b7c79703d7d5]*/
|
||||
{
|
||||
PyObject *v, *item;
|
||||
datum key, nextkey;
|
||||
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();
|
||||
return NULL;
|
||||
}
|
||||
check_dbmobject_open(self);
|
||||
check_gdbmobject_open(self, state->gdbm_error);
|
||||
|
||||
v = PyList_New(0);
|
||||
if (v == NULL)
|
||||
|
@ -349,14 +364,15 @@ _gdbm_gdbm_keys_impl(dbmobject *self)
|
|||
}
|
||||
|
||||
static int
|
||||
dbm_contains(PyObject *self, PyObject *arg)
|
||||
gdbm_contains(PyObject *self, PyObject *arg)
|
||||
{
|
||||
dbmobject *dp = (dbmobject *)self;
|
||||
gdbmobject *dp = (gdbmobject *)self;
|
||||
datum key;
|
||||
Py_ssize_t size;
|
||||
_gdbm_state *state = PyType_GetModuleState(Py_TYPE(dp));
|
||||
|
||||
if ((dp)->di_dbm == NULL) {
|
||||
PyErr_SetString(DbmError,
|
||||
PyErr_SetString(state->gdbm_error,
|
||||
"GDBM object has already been closed");
|
||||
return -1;
|
||||
}
|
||||
|
@ -379,22 +395,11 @@ dbm_contains(PyObject *self, PyObject *arg)
|
|||
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]
|
||||
_gdbm.gdbm.firstkey
|
||||
|
||||
cls: defining_class
|
||||
|
||||
Return the starting key for the traversal.
|
||||
|
||||
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]*/
|
||||
|
||||
static PyObject *
|
||||
_gdbm_gdbm_firstkey_impl(dbmobject *self)
|
||||
/*[clinic end generated code: output=9ff85628d84b65d2 input=0dbd6a335d69bba0]*/
|
||||
_gdbm_gdbm_firstkey_impl(gdbmobject *self, PyTypeObject *cls)
|
||||
/*[clinic end generated code: output=139275e9c8b60827 input=ed8782a029a5d299]*/
|
||||
{
|
||||
PyObject *v;
|
||||
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);
|
||||
if (key.dptr) {
|
||||
v = PyBytes_FromStringAndSize(key.dptr, key.dsize);
|
||||
|
@ -424,6 +431,7 @@ _gdbm_gdbm_firstkey_impl(dbmobject *self)
|
|||
/*[clinic input]
|
||||
_gdbm.gdbm.nextkey
|
||||
|
||||
cls: defining_class
|
||||
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]*/
|
||||
|
||||
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)
|
||||
/*[clinic end generated code: output=192ab892de6eb2f6 input=1f1606943614e36f]*/
|
||||
/*[clinic end generated code: output=204964441fdbaf02 input=fcf6a51a96ce0172]*/
|
||||
{
|
||||
PyObject *v;
|
||||
datum dbm_key, nextkey;
|
||||
_gdbm_state *state = PyType_GetModuleState(cls);
|
||||
assert(state != NULL);
|
||||
|
||||
dbm_key.dptr = (char *)key;
|
||||
dbm_key.dsize = key_length;
|
||||
check_dbmobject_open(self);
|
||||
check_gdbmobject_open(self, state->gdbm_error);
|
||||
nextkey = gdbm_nextkey(self->di_dbm, dbm_key);
|
||||
if (nextkey.dptr) {
|
||||
v = PyBytes_FromStringAndSize(nextkey.dptr, nextkey.dsize);
|
||||
|
@ -463,6 +473,8 @@ _gdbm_gdbm_nextkey_impl(dbmobject *self, const char *key,
|
|||
/*[clinic input]
|
||||
_gdbm.gdbm.reorganize
|
||||
|
||||
cls: defining_class
|
||||
|
||||
Reorganize the database.
|
||||
|
||||
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]*/
|
||||
|
||||
static PyObject *
|
||||
_gdbm_gdbm_reorganize_impl(dbmobject *self)
|
||||
/*[clinic end generated code: output=38d9624df92e961d input=f6bea85bcfd40dd2]*/
|
||||
_gdbm_gdbm_reorganize_impl(gdbmobject *self, PyTypeObject *cls)
|
||||
/*[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;
|
||||
if (gdbm_reorganize(self->di_dbm) < 0) {
|
||||
if (errno != 0)
|
||||
PyErr_SetFromErrno(DbmError);
|
||||
PyErr_SetFromErrno(state->gdbm_error);
|
||||
else
|
||||
PyErr_SetString(DbmError, gdbm_strerror(gdbm_errno));
|
||||
PyErr_SetString(state->gdbm_error, gdbm_strerror(gdbm_errno));
|
||||
return NULL;
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
|
@ -491,6 +505,8 @@ _gdbm_gdbm_reorganize_impl(dbmobject *self)
|
|||
/*[clinic input]
|
||||
_gdbm.gdbm.sync
|
||||
|
||||
cls: defining_class
|
||||
|
||||
Flush the database to the disk file.
|
||||
|
||||
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]*/
|
||||
|
||||
static PyObject *
|
||||
_gdbm_gdbm_sync_impl(dbmobject *self)
|
||||
/*[clinic end generated code: output=488b15f47028f125 input=2a47d2c9e153ab8a]*/
|
||||
_gdbm_gdbm_sync_impl(gdbmobject *self, PyTypeObject *cls)
|
||||
/*[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);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
dbm__enter__(PyObject *self, PyObject *args)
|
||||
gdbm__enter__(PyObject *self, PyObject *args)
|
||||
{
|
||||
Py_INCREF(self);
|
||||
return self;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
dbm__exit__(PyObject *self, PyObject *args)
|
||||
gdbm__exit__(PyObject *self, PyObject *args)
|
||||
{
|
||||
_Py_IDENTIFIER(close);
|
||||
return _PyObject_CallMethodIdNoArgs(self, &PyId_close);
|
||||
}
|
||||
|
||||
static PyMethodDef dbm_methods[] = {
|
||||
static PyMethodDef gdbm_methods[] = {
|
||||
_GDBM_GDBM_CLOSE_METHODDEF
|
||||
_GDBM_GDBM_KEYS_METHODDEF
|
||||
_GDBM_GDBM_FIRSTKEY_METHODDEF
|
||||
|
@ -529,46 +547,38 @@ static PyMethodDef dbm_methods[] = {
|
|||
_GDBM_GDBM_SYNC_METHODDEF
|
||||
_GDBM_GDBM_GET_METHODDEF
|
||||
_GDBM_GDBM_SETDEFAULT_METHODDEF
|
||||
{"__enter__", dbm__enter__, METH_NOARGS, NULL},
|
||||
{"__exit__", dbm__exit__, METH_VARARGS, NULL},
|
||||
{"__enter__", gdbm__enter__, METH_NOARGS, NULL},
|
||||
{"__exit__", gdbm__exit__, METH_VARARGS, NULL},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
static PyTypeObject Dbmtype = {
|
||||
PyVarObject_HEAD_INIT(0, 0)
|
||||
"_gdbm.gdbm",
|
||||
sizeof(dbmobject),
|
||||
0,
|
||||
(destructor)dbm_dealloc, /*tp_dealloc*/
|
||||
0, /*tp_vectorcall_offset*/
|
||||
0, /*tp_getattr*/
|
||||
0, /*tp_setattr*/
|
||||
0, /*tp_as_async*/
|
||||
0, /*tp_repr*/
|
||||
0, /*tp_as_number*/
|
||||
&dbm_as_sequence, /*tp_as_sequence*/
|
||||
&dbm_as_mapping, /*tp_as_mapping*/
|
||||
0, /*tp_hash*/
|
||||
0, /*tp_call*/
|
||||
0, /*tp_str*/
|
||||
0, /*tp_getattro*/
|
||||
0, /*tp_setattro*/
|
||||
0, /*tp_as_buffer*/
|
||||
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*/
|
||||
static PyType_Slot gdbmtype_spec_slots[] = {
|
||||
{Py_tp_dealloc, gdbm_dealloc},
|
||||
{Py_tp_methods, gdbm_methods},
|
||||
{Py_sq_contains, gdbm_contains},
|
||||
{Py_mp_length, gdbm_length},
|
||||
{Py_mp_subscript, gdbm_subscript},
|
||||
{Py_mp_ass_subscript, gdbm_ass_sub},
|
||||
{Py_tp_doc, (char*)gdbm_object__doc__},
|
||||
{0, 0}
|
||||
};
|
||||
|
||||
static PyType_Spec gdbmtype_spec = {
|
||||
.name = "_gdbm.gdbm",
|
||||
.basicsize = sizeof(gdbmobject),
|
||||
// Calling PyType_GetModuleState() on a subclass is not safe.
|
||||
// dbmtype_spec does not have Py_TPFLAGS_BASETYPE flag
|
||||
// which prevents to create a subclass.
|
||||
// So calling PyType_GetModuleState() in this file is always safe.
|
||||
.flags = Py_TPFLAGS_DEFAULT,
|
||||
.slots = gdbmtype_spec_slots,
|
||||
};
|
||||
|
||||
/* ----------------------------------------------------------------- */
|
||||
|
||||
/*[clinic input]
|
||||
_gdbm.open as dbmopen
|
||||
|
||||
filename: unicode
|
||||
flags: str="r"
|
||||
mode: int(py_default="0o666") = 0o666
|
||||
|
@ -601,9 +611,11 @@ when the database has to be created. It defaults to octal 0o666.
|
|||
static PyObject *
|
||||
dbmopen_impl(PyObject *module, PyObject *filename, const char *flags,
|
||||
int mode)
|
||||
/*[clinic end generated code: output=9527750f5df90764 input=3be0b0875974b928]*/
|
||||
/*[clinic end generated code: output=9527750f5df90764 input=812b7d74399ceb0e]*/
|
||||
{
|
||||
int iflags;
|
||||
_gdbm_state *state = get_gdbm_state(module);
|
||||
assert(state != NULL);
|
||||
|
||||
switch (flags[0]) {
|
||||
case 'r':
|
||||
|
@ -619,7 +631,7 @@ dbmopen_impl(PyObject *module, PyObject *filename, const char *flags,
|
|||
iflags = GDBM_NEWDB;
|
||||
break;
|
||||
default:
|
||||
PyErr_SetString(DbmError,
|
||||
PyErr_SetString(state->gdbm_error,
|
||||
"First flag must be one of 'r', 'w', 'c' or 'n'");
|
||||
return NULL;
|
||||
}
|
||||
|
@ -644,7 +656,7 @@ dbmopen_impl(PyObject *module, PyObject *filename, const char *flags,
|
|||
default:
|
||||
PyOS_snprintf(buf, sizeof(buf), "Flag '%c' is not supported.",
|
||||
*flags);
|
||||
PyErr_SetString(DbmError, buf);
|
||||
PyErr_SetString(state->gdbm_error, buf);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
@ -659,12 +671,12 @@ dbmopen_impl(PyObject *module, PyObject *filename, const char *flags,
|
|||
PyErr_SetString(PyExc_ValueError, "embedded null character");
|
||||
return NULL;
|
||||
}
|
||||
PyObject *self = newdbmobject(name, iflags, mode);
|
||||
PyObject *self = newgdbmobject(state, name, iflags, mode);
|
||||
Py_DECREF(filenamebytes);
|
||||
return self;
|
||||
}
|
||||
|
||||
static const char dbmmodule_open_flags[] = "rwcn"
|
||||
static const char gdbmmodule_open_flags[] = "rwcn"
|
||||
#ifdef GDBM_FAST
|
||||
"f"
|
||||
#endif
|
||||
|
@ -676,48 +688,30 @@ static const char dbmmodule_open_flags[] = "rwcn"
|
|||
#endif
|
||||
;
|
||||
|
||||
static PyMethodDef dbmmodule_methods[] = {
|
||||
static PyMethodDef _gdbm_module_methods[] = {
|
||||
DBMOPEN_METHODDEF
|
||||
{ 0, 0 },
|
||||
};
|
||||
|
||||
|
||||
static struct PyModuleDef _gdbmmodule = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
"_gdbm",
|
||||
gdbmmodule__doc__,
|
||||
-1,
|
||||
dbmmodule_methods,
|
||||
NULL,
|
||||
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;
|
||||
static int
|
||||
_gdbm_exec(PyObject *module)
|
||||
{
|
||||
_gdbm_state *state = get_gdbm_state(module);
|
||||
state->gdbm_type = (PyTypeObject *)PyType_FromModuleAndSpec(module,
|
||||
&gdbmtype_spec, NULL);
|
||||
if (state->gdbm_type == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
DbmError = PyErr_NewException("_gdbm.error", PyExc_OSError, NULL);
|
||||
if (DbmError == NULL) {
|
||||
goto error;
|
||||
state->gdbm_error = PyErr_NewException("_gdbm.error", PyExc_OSError, NULL);
|
||||
if (state->gdbm_error == NULL) {
|
||||
return -1;
|
||||
}
|
||||
Py_INCREF(DbmError);
|
||||
if (PyModule_AddObject(m, "error", DbmError) < 0) {
|
||||
Py_DECREF(DbmError);
|
||||
goto error;
|
||||
if (PyModule_AddType(module, (PyTypeObject *)state->gdbm_error) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (PyModule_AddStringConstant(m, "open_flags",
|
||||
dbmmodule_open_flags) < 0) {
|
||||
goto error;
|
||||
if (PyModule_AddStringConstant(module, "open_flags",
|
||||
gdbmmodule_open_flags) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if defined(GDBM_VERSION_MAJOR) && defined(GDBM_VERSION_MINOR) && \
|
||||
|
@ -725,17 +719,59 @@ PyInit__gdbm(void) {
|
|||
PyObject *obj = Py_BuildValue("iii", GDBM_VERSION_MAJOR,
|
||||
GDBM_VERSION_MINOR, GDBM_VERSION_PATCH);
|
||||
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);
|
||||
goto error;
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m;
|
||||
|
||||
error:
|
||||
Py_DECREF(m);
|
||||
return NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
_gdbm_module_traverse(PyObject *module, visitproc visit, void *arg)
|
||||
{
|
||||
_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);
|
||||
}
|
||||
|
|
|
@ -12,10 +12,10 @@ PyDoc_STRVAR(_gdbm_gdbm_get__doc__,
|
|||
{"get", (PyCFunction)(void(*)(void))_gdbm_gdbm_get, METH_FASTCALL, _gdbm_gdbm_get__doc__},
|
||||
|
||||
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 *
|
||||
_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 *key;
|
||||
|
@ -46,11 +46,11 @@ PyDoc_STRVAR(_gdbm_gdbm_setdefault__doc__,
|
|||
{"setdefault", (PyCFunction)(void(*)(void))_gdbm_gdbm_setdefault, METH_FASTCALL, _gdbm_gdbm_setdefault__doc__},
|
||||
|
||||
static PyObject *
|
||||
_gdbm_gdbm_setdefault_impl(dbmobject *self, PyObject *key,
|
||||
_gdbm_gdbm_setdefault_impl(gdbmobject *self, PyObject *key,
|
||||
PyObject *default_value);
|
||||
|
||||
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 *key;
|
||||
|
@ -81,10 +81,10 @@ PyDoc_STRVAR(_gdbm_gdbm_close__doc__,
|
|||
{"close", (PyCFunction)_gdbm_gdbm_close, METH_NOARGS, _gdbm_gdbm_close__doc__},
|
||||
|
||||
static PyObject *
|
||||
_gdbm_gdbm_close_impl(dbmobject *self);
|
||||
_gdbm_gdbm_close_impl(gdbmobject *self);
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -96,15 +96,26 @@ PyDoc_STRVAR(_gdbm_gdbm_keys__doc__,
|
|||
"Get a list of all keys in the database.");
|
||||
|
||||
#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 *
|
||||
_gdbm_gdbm_keys_impl(dbmobject *self);
|
||||
_gdbm_gdbm_keys_impl(gdbmobject *self, PyTypeObject *cls);
|
||||
|
||||
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__,
|
||||
|
@ -118,15 +129,26 @@ PyDoc_STRVAR(_gdbm_gdbm_firstkey__doc__,
|
|||
"hash values, and won\'t be sorted by the key values.");
|
||||
|
||||
#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 *
|
||||
_gdbm_gdbm_firstkey_impl(dbmobject *self);
|
||||
_gdbm_gdbm_firstkey_impl(gdbmobject *self, PyTypeObject *cls);
|
||||
|
||||
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__,
|
||||
|
@ -144,23 +166,26 @@ PyDoc_STRVAR(_gdbm_gdbm_nextkey__doc__,
|
|||
" k = db.nextkey(k)");
|
||||
|
||||
#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 *
|
||||
_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);
|
||||
|
||||
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;
|
||||
static const char * const _keywords[] = {"", NULL};
|
||||
static _PyArg_Parser _parser = {"s#:nextkey", _keywords, 0};
|
||||
const char *key;
|
||||
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;
|
||||
}
|
||||
return_value = _gdbm_gdbm_nextkey_impl(self, key, key_length);
|
||||
return_value = _gdbm_gdbm_nextkey_impl(self, cls, key, key_length);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
|
@ -179,15 +204,26 @@ PyDoc_STRVAR(_gdbm_gdbm_reorganize__doc__,
|
|||
"kept and reused as new (key,value) pairs are added.");
|
||||
|
||||
#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 *
|
||||
_gdbm_gdbm_reorganize_impl(dbmobject *self);
|
||||
_gdbm_gdbm_reorganize_impl(gdbmobject *self, PyTypeObject *cls);
|
||||
|
||||
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__,
|
||||
|
@ -200,15 +236,26 @@ PyDoc_STRVAR(_gdbm_gdbm_sync__doc__,
|
|||
"any unwritten data to be written to the disk.");
|
||||
|
||||
#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 *
|
||||
_gdbm_gdbm_sync_impl(dbmobject *self);
|
||||
_gdbm_gdbm_sync_impl(gdbmobject *self, PyTypeObject *cls);
|
||||
|
||||
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__,
|
||||
|
@ -293,4 +340,4 @@ skip_optional:
|
|||
exit:
|
||||
return return_value;
|
||||
}
|
||||
/*[clinic end generated code: output=c9d43f42677f4efb input=a9049054013a1b77]*/
|
||||
/*[clinic end generated code: output=e84bc6ac82fcb6d4 input=a9049054013a1b77]*/
|
||||
|
|
Loading…
Reference in New Issue