ยปCore Development>Code coverage>Modules/_dbmmodule.c

Python code coverage for Modules/_dbmmodule.c

#countcontent
1n/a
2n/a/* DBM module using dictionary interface */
3n/a
4n/a
5n/a#define PY_SSIZE_T_CLEAN
6n/a#include "Python.h"
7n/a
8n/a#include <sys/types.h>
9n/a#include <sys/stat.h>
10n/a#include <fcntl.h>
11n/a
12n/a/* Some Linux systems install gdbm/ndbm.h, but not ndbm.h. This supports
13n/a * whichever configure was able to locate.
14n/a */
15n/a#if defined(HAVE_NDBM_H)
16n/a#include <ndbm.h>
17n/astatic const char which_dbm[] = "GNU gdbm"; /* EMX port of GDBM */
18n/a#elif defined(HAVE_GDBM_NDBM_H)
19n/a#include <gdbm/ndbm.h>
20n/astatic const char which_dbm[] = "GNU gdbm";
21n/a#elif defined(HAVE_GDBM_DASH_NDBM_H)
22n/a#include <gdbm-ndbm.h>
23n/astatic const char which_dbm[] = "GNU gdbm";
24n/a#elif defined(HAVE_BERKDB_H)
25n/a#include <db.h>
26n/astatic const char which_dbm[] = "Berkeley DB";
27n/a#else
28n/a#error "No ndbm.h available!"
29n/a#endif
30n/a
31n/a/*[clinic input]
32n/amodule _dbm
33n/aclass _dbm.dbm "dbmobject *" "&Dbmtype"
34n/a[clinic start generated code]*/
35n/a/*[clinic end generated code: output=da39a3ee5e6b4b0d input=9b1aa8756d16150e]*/
36n/a
37n/atypedef struct {
38n/a PyObject_HEAD
39n/a int di_size; /* -1 means recompute */
40n/a DBM *di_dbm;
41n/a} dbmobject;
42n/a
43n/a#include "clinic/_dbmmodule.c.h"
44n/a
45n/astatic PyTypeObject Dbmtype;
46n/a
47n/a#define is_dbmobject(v) (Py_TYPE(v) == &Dbmtype)
48n/a#define check_dbmobject_open(v) if ((v)->di_dbm == NULL) \
49n/a { PyErr_SetString(DbmError, "DBM object has already been closed"); \
50n/a return NULL; }
51n/a
52n/astatic PyObject *DbmError;
53n/a
54n/astatic PyObject *
55n/anewdbmobject(const char *file, int flags, int mode)
56n/a{
57n/a dbmobject *dp;
58n/a
59n/a dp = PyObject_New(dbmobject, &Dbmtype);
60n/a if (dp == NULL)
61n/a return NULL;
62n/a dp->di_size = -1;
63n/a /* See issue #19296 */
64n/a if ( (dp->di_dbm = dbm_open((char *)file, flags, mode)) == 0 ) {
65n/a PyErr_SetFromErrno(DbmError);
66n/a Py_DECREF(dp);
67n/a return NULL;
68n/a }
69n/a return (PyObject *)dp;
70n/a}
71n/a
72n/a/* Methods */
73n/a
74n/astatic void
75n/adbm_dealloc(dbmobject *dp)
76n/a{
77n/a if ( dp->di_dbm )
78n/a dbm_close(dp->di_dbm);
79n/a PyObject_Del(dp);
80n/a}
81n/a
82n/astatic Py_ssize_t
83n/adbm_length(dbmobject *dp)
84n/a{
85n/a if (dp->di_dbm == NULL) {
86n/a PyErr_SetString(DbmError, "DBM object has already been closed");
87n/a return -1;
88n/a }
89n/a if ( dp->di_size < 0 ) {
90n/a datum key;
91n/a int size;
92n/a
93n/a size = 0;
94n/a for ( key=dbm_firstkey(dp->di_dbm); key.dptr;
95n/a key = dbm_nextkey(dp->di_dbm))
96n/a size++;
97n/a dp->di_size = size;
98n/a }
99n/a return dp->di_size;
100n/a}
101n/a
102n/astatic PyObject *
103n/adbm_subscript(dbmobject *dp, PyObject *key)
104n/a{
105n/a datum drec, krec;
106n/a Py_ssize_t tmp_size;
107n/a
108n/a if (!PyArg_Parse(key, "s#", &krec.dptr, &tmp_size) )
109n/a return NULL;
110n/a
111n/a krec.dsize = tmp_size;
112n/a check_dbmobject_open(dp);
113n/a drec = dbm_fetch(dp->di_dbm, krec);
114n/a if ( drec.dptr == 0 ) {
115n/a PyErr_SetObject(PyExc_KeyError, key);
116n/a return NULL;
117n/a }
118n/a if ( dbm_error(dp->di_dbm) ) {
119n/a dbm_clearerr(dp->di_dbm);
120n/a PyErr_SetString(DbmError, "");
121n/a return NULL;
122n/a }
123n/a return PyBytes_FromStringAndSize(drec.dptr, drec.dsize);
124n/a}
125n/a
126n/astatic int
127n/adbm_ass_sub(dbmobject *dp, PyObject *v, PyObject *w)
128n/a{
129n/a datum krec, drec;
130n/a Py_ssize_t tmp_size;
131n/a
132n/a if ( !PyArg_Parse(v, "s#", &krec.dptr, &tmp_size) ) {
133n/a PyErr_SetString(PyExc_TypeError,
134n/a "dbm mappings have bytes or string keys only");
135n/a return -1;
136n/a }
137n/a krec.dsize = tmp_size;
138n/a if (dp->di_dbm == NULL) {
139n/a PyErr_SetString(DbmError, "DBM object has already been closed");
140n/a return -1;
141n/a }
142n/a dp->di_size = -1;
143n/a if (w == NULL) {
144n/a if ( dbm_delete(dp->di_dbm, krec) < 0 ) {
145n/a dbm_clearerr(dp->di_dbm);
146n/a PyErr_SetObject(PyExc_KeyError, v);
147n/a return -1;
148n/a }
149n/a } else {
150n/a if ( !PyArg_Parse(w, "s#", &drec.dptr, &tmp_size) ) {
151n/a PyErr_SetString(PyExc_TypeError,
152n/a "dbm mappings have byte or string elements only");
153n/a return -1;
154n/a }
155n/a drec.dsize = tmp_size;
156n/a if ( dbm_store(dp->di_dbm, krec, drec, DBM_REPLACE) < 0 ) {
157n/a dbm_clearerr(dp->di_dbm);
158n/a PyErr_SetString(DbmError,
159n/a "cannot add item to database");
160n/a return -1;
161n/a }
162n/a }
163n/a if ( dbm_error(dp->di_dbm) ) {
164n/a dbm_clearerr(dp->di_dbm);
165n/a PyErr_SetString(DbmError, "");
166n/a return -1;
167n/a }
168n/a return 0;
169n/a}
170n/a
171n/astatic PyMappingMethods dbm_as_mapping = {
172n/a (lenfunc)dbm_length, /*mp_length*/
173n/a (binaryfunc)dbm_subscript, /*mp_subscript*/
174n/a (objobjargproc)dbm_ass_sub, /*mp_ass_subscript*/
175n/a};
176n/a
177n/a/*[clinic input]
178n/a_dbm.dbm.close
179n/a
180n/aClose the database.
181n/a[clinic start generated code]*/
182n/a
183n/astatic PyObject *
184n/a_dbm_dbm_close_impl(dbmobject *self)
185n/a/*[clinic end generated code: output=c8dc5b6709600b86 input=046db72377d51be8]*/
186n/a{
187n/a if (self->di_dbm)
188n/a dbm_close(self->di_dbm);
189n/a self->di_dbm = NULL;
190n/a Py_RETURN_NONE;
191n/a}
192n/a
193n/a/*[clinic input]
194n/a_dbm.dbm.keys
195n/a
196n/aReturn a list of all keys in the database.
197n/a[clinic start generated code]*/
198n/a
199n/astatic PyObject *
200n/a_dbm_dbm_keys_impl(dbmobject *self)
201n/a/*[clinic end generated code: output=434549f7c121b33c input=d210ba778cd9c68a]*/
202n/a{
203n/a PyObject *v, *item;
204n/a datum key;
205n/a int err;
206n/a
207n/a check_dbmobject_open(self);
208n/a v = PyList_New(0);
209n/a if (v == NULL)
210n/a return NULL;
211n/a for (key = dbm_firstkey(self->di_dbm); key.dptr;
212n/a key = dbm_nextkey(self->di_dbm)) {
213n/a item = PyBytes_FromStringAndSize(key.dptr, key.dsize);
214n/a if (item == NULL) {
215n/a Py_DECREF(v);
216n/a return NULL;
217n/a }
218n/a err = PyList_Append(v, item);
219n/a Py_DECREF(item);
220n/a if (err != 0) {
221n/a Py_DECREF(v);
222n/a return NULL;
223n/a }
224n/a }
225n/a return v;
226n/a}
227n/a
228n/astatic int
229n/adbm_contains(PyObject *self, PyObject *arg)
230n/a{
231n/a dbmobject *dp = (dbmobject *)self;
232n/a datum key, val;
233n/a Py_ssize_t size;
234n/a
235n/a if ((dp)->di_dbm == NULL) {
236n/a PyErr_SetString(DbmError,
237n/a "DBM object has already been closed");
238n/a return -1;
239n/a }
240n/a if (PyUnicode_Check(arg)) {
241n/a key.dptr = (char *)PyUnicode_AsUTF8AndSize(arg, &size);
242n/a key.dsize = size;
243n/a if (key.dptr == NULL)
244n/a return -1;
245n/a }
246n/a else if (!PyBytes_Check(arg)) {
247n/a PyErr_Format(PyExc_TypeError,
248n/a "dbm key must be bytes or string, not %.100s",
249n/a arg->ob_type->tp_name);
250n/a return -1;
251n/a }
252n/a else {
253n/a key.dptr = PyBytes_AS_STRING(arg);
254n/a key.dsize = PyBytes_GET_SIZE(arg);
255n/a }
256n/a val = dbm_fetch(dp->di_dbm, key);
257n/a return val.dptr != NULL;
258n/a}
259n/a
260n/astatic PySequenceMethods dbm_as_sequence = {
261n/a 0, /* sq_length */
262n/a 0, /* sq_concat */
263n/a 0, /* sq_repeat */
264n/a 0, /* sq_item */
265n/a 0, /* sq_slice */
266n/a 0, /* sq_ass_item */
267n/a 0, /* sq_ass_slice */
268n/a dbm_contains, /* sq_contains */
269n/a 0, /* sq_inplace_concat */
270n/a 0, /* sq_inplace_repeat */
271n/a};
272n/a
273n/a/*[clinic input]
274n/a_dbm.dbm.get
275n/a
276n/a key: str(accept={str, robuffer}, zeroes=True)
277n/a default: object(c_default="NULL") = b''
278n/a /
279n/a
280n/aReturn the value for key if present, otherwise default.
281n/a[clinic start generated code]*/
282n/a
283n/astatic PyObject *
284n/a_dbm_dbm_get_impl(dbmobject *self, const char *key,
285n/a Py_ssize_clean_t key_length, PyObject *default_value)
286n/a/*[clinic end generated code: output=b44f95eba8203d93 input=a3a279957f85eb6d]*/
287n/a/*[clinic end generated code: output=4f5c0e523eaf1251 input=9402c0af8582dc69]*/
288n/a{
289n/a datum dbm_key, val;
290n/a
291n/a dbm_key.dptr = (char *)key;
292n/a dbm_key.dsize = key_length;
293n/a check_dbmobject_open(self);
294n/a val = dbm_fetch(self->di_dbm, dbm_key);
295n/a if (val.dptr != NULL)
296n/a return PyBytes_FromStringAndSize(val.dptr, val.dsize);
297n/a
298n/a Py_INCREF(default_value);
299n/a return default_value;
300n/a}
301n/a
302n/a/*[clinic input]
303n/a_dbm.dbm.setdefault
304n/a key: str(accept={str, robuffer}, zeroes=True)
305n/a default: object(c_default="NULL") = b''
306n/a /
307n/a
308n/aReturn the value for key if present, otherwise default.
309n/a
310n/aIf key is not in the database, it is inserted with default as the value.
311n/a[clinic start generated code]*/
312n/a
313n/astatic PyObject *
314n/a_dbm_dbm_setdefault_impl(dbmobject *self, const char *key,
315n/a Py_ssize_clean_t key_length,
316n/a PyObject *default_value)
317n/a/*[clinic end generated code: output=52545886cf272161 input=bf40c48edaca01d6]*/
318n/a{
319n/a datum dbm_key, val;
320n/a Py_ssize_t tmp_size;
321n/a
322n/a dbm_key.dptr = (char *)key;
323n/a dbm_key.dsize = key_length;
324n/a check_dbmobject_open(self);
325n/a val = dbm_fetch(self->di_dbm, dbm_key);
326n/a if (val.dptr != NULL)
327n/a return PyBytes_FromStringAndSize(val.dptr, val.dsize);
328n/a if (default_value == NULL) {
329n/a default_value = PyBytes_FromStringAndSize(NULL, 0);
330n/a if (default_value == NULL)
331n/a return NULL;
332n/a val.dptr = NULL;
333n/a val.dsize = 0;
334n/a }
335n/a else {
336n/a if ( !PyArg_Parse(default_value, "s#", &val.dptr, &tmp_size) ) {
337n/a PyErr_SetString(PyExc_TypeError,
338n/a "dbm mappings have byte string elements only");
339n/a return NULL;
340n/a }
341n/a val.dsize = tmp_size;
342n/a Py_INCREF(default_value);
343n/a }
344n/a if (dbm_store(self->di_dbm, dbm_key, val, DBM_INSERT) < 0) {
345n/a dbm_clearerr(self->di_dbm);
346n/a PyErr_SetString(DbmError, "cannot add item to database");
347n/a Py_DECREF(default_value);
348n/a return NULL;
349n/a }
350n/a return default_value;
351n/a}
352n/a
353n/astatic PyObject *
354n/adbm__enter__(PyObject *self, PyObject *args)
355n/a{
356n/a Py_INCREF(self);
357n/a return self;
358n/a}
359n/a
360n/astatic PyObject *
361n/adbm__exit__(PyObject *self, PyObject *args)
362n/a{
363n/a _Py_IDENTIFIER(close);
364n/a return _PyObject_CallMethodId(self, &PyId_close, NULL);
365n/a}
366n/a
367n/a
368n/astatic PyMethodDef dbm_methods[] = {
369n/a _DBM_DBM_CLOSE_METHODDEF
370n/a _DBM_DBM_KEYS_METHODDEF
371n/a _DBM_DBM_GET_METHODDEF
372n/a _DBM_DBM_SETDEFAULT_METHODDEF
373n/a {"__enter__", dbm__enter__, METH_NOARGS, NULL},
374n/a {"__exit__", dbm__exit__, METH_VARARGS, NULL},
375n/a {NULL, NULL} /* sentinel */
376n/a};
377n/a
378n/astatic PyTypeObject Dbmtype = {
379n/a PyVarObject_HEAD_INIT(NULL, 0)
380n/a "_dbm.dbm",
381n/a sizeof(dbmobject),
382n/a 0,
383n/a (destructor)dbm_dealloc, /*tp_dealloc*/
384n/a 0, /*tp_print*/
385n/a 0, /*tp_getattr*/
386n/a 0, /*tp_setattr*/
387n/a 0, /*tp_reserved*/
388n/a 0, /*tp_repr*/
389n/a 0, /*tp_as_number*/
390n/a &dbm_as_sequence, /*tp_as_sequence*/
391n/a &dbm_as_mapping, /*tp_as_mapping*/
392n/a 0, /*tp_hash*/
393n/a 0, /*tp_call*/
394n/a 0, /*tp_str*/
395n/a 0, /*tp_getattro*/
396n/a 0, /*tp_setattro*/
397n/a 0, /*tp_as_buffer*/
398n/a Py_TPFLAGS_DEFAULT, /*tp_flags*/
399n/a 0, /*tp_doc*/
400n/a 0, /*tp_traverse*/
401n/a 0, /*tp_clear*/
402n/a 0, /*tp_richcompare*/
403n/a 0, /*tp_weaklistoffset*/
404n/a 0, /*tp_iter*/
405n/a 0, /*tp_iternext*/
406n/a dbm_methods, /*tp_methods*/
407n/a};
408n/a
409n/a/* ----------------------------------------------------------------- */
410n/a
411n/a/*[clinic input]
412n/a
413n/a_dbm.open as dbmopen
414n/a
415n/a filename: str
416n/a The filename to open.
417n/a
418n/a flags: str="r"
419n/a How to open the file. "r" for reading, "w" for writing, etc.
420n/a
421n/a mode: int(py_default="0o666") = 0o666
422n/a If creating a new file, the mode bits for the new file
423n/a (e.g. os.O_RDWR).
424n/a
425n/a /
426n/a
427n/aReturn a database object.
428n/a
429n/a[clinic start generated code]*/
430n/a
431n/astatic PyObject *
432n/adbmopen_impl(PyObject *module, const char *filename, const char *flags,
433n/a int mode)
434n/a/*[clinic end generated code: output=5fade8cf16e0755f input=226334bade5764e6]*/
435n/a{
436n/a int iflags;
437n/a
438n/a if ( strcmp(flags, "r") == 0 )
439n/a iflags = O_RDONLY;
440n/a else if ( strcmp(flags, "w") == 0 )
441n/a iflags = O_RDWR;
442n/a else if ( strcmp(flags, "rw") == 0 ) /* B/W compat */
443n/a iflags = O_RDWR|O_CREAT;
444n/a else if ( strcmp(flags, "c") == 0 )
445n/a iflags = O_RDWR|O_CREAT;
446n/a else if ( strcmp(flags, "n") == 0 )
447n/a iflags = O_RDWR|O_CREAT|O_TRUNC;
448n/a else {
449n/a PyErr_SetString(DbmError,
450n/a "arg 2 to open should be 'r', 'w', 'c', or 'n'");
451n/a return NULL;
452n/a }
453n/a return newdbmobject(filename, iflags, mode);
454n/a}
455n/a
456n/astatic PyMethodDef dbmmodule_methods[] = {
457n/a DBMOPEN_METHODDEF
458n/a { 0, 0 },
459n/a};
460n/a
461n/a
462n/astatic struct PyModuleDef _dbmmodule = {
463n/a PyModuleDef_HEAD_INIT,
464n/a "_dbm",
465n/a NULL,
466n/a -1,
467n/a dbmmodule_methods,
468n/a NULL,
469n/a NULL,
470n/a NULL,
471n/a NULL
472n/a};
473n/a
474n/aPyMODINIT_FUNC
475n/aPyInit__dbm(void) {
476n/a PyObject *m, *d, *s;
477n/a
478n/a if (PyType_Ready(&Dbmtype) < 0)
479n/a return NULL;
480n/a m = PyModule_Create(&_dbmmodule);
481n/a if (m == NULL)
482n/a return NULL;
483n/a d = PyModule_GetDict(m);
484n/a if (DbmError == NULL)
485n/a DbmError = PyErr_NewException("_dbm.error",
486n/a PyExc_IOError, NULL);
487n/a s = PyUnicode_FromString(which_dbm);
488n/a if (s != NULL) {
489n/a PyDict_SetItemString(d, "library", s);
490n/a Py_DECREF(s);
491n/a }
492n/a if (DbmError != NULL)
493n/a PyDict_SetItemString(d, "error", DbmError);
494n/a if (PyErr_Occurred()) {
495n/a Py_DECREF(m);
496n/a m = NULL;
497n/a }
498n/a return m;
499n/a}