Start packaging the bz2 python module as it is needed for building Qt5
[profile/ivi/python.git] / Modules / dbmmodule.c
1
2 /* DBM module using dictionary interface */
3
4
5 #include "Python.h"
6
7 #include <sys/types.h>
8 #include <sys/stat.h>
9 #include <fcntl.h>
10
11 /* Some Linux systems install gdbm/ndbm.h, but not ndbm.h.  This supports
12  * whichever configure was able to locate.
13  */
14 #if defined(HAVE_NDBM_H)
15 #include <ndbm.h>
16 #if defined(PYOS_OS2) && !defined(PYCC_GCC)
17 static char *which_dbm = "ndbm";
18 #else
19 static char *which_dbm = "GNU gdbm";  /* EMX port of GDBM */
20 #endif
21 #elif defined(HAVE_GDBM_NDBM_H)
22 #include <gdbm/ndbm.h>
23 static char *which_dbm = "GNU gdbm";
24 #elif defined(HAVE_GDBM_DASH_NDBM_H)
25 #include <gdbm-ndbm.h>
26 static char *which_dbm = "GNU gdbm";
27 #elif defined(HAVE_BERKDB_H)
28 #include <db.h>
29 static char *which_dbm = "Berkeley DB";
30 #else
31 #error "No ndbm.h available!"
32 #endif
33
34 typedef struct {
35     PyObject_HEAD
36     int di_size;        /* -1 means recompute */
37     DBM *di_dbm;
38 } dbmobject;
39
40 static PyTypeObject Dbmtype;
41
42 #define is_dbmobject(v) (Py_TYPE(v) == &Dbmtype)
43 #define check_dbmobject_open(v) if ((v)->di_dbm == NULL) \
44                { PyErr_SetString(DbmError, "DBM object has already been closed"); \
45                  return NULL; }
46
47 static PyObject *DbmError;
48
49 static PyObject *
50 newdbmobject(char *file, int flags, int mode)
51 {
52     dbmobject *dp;
53
54     dp = PyObject_New(dbmobject, &Dbmtype);
55     if (dp == NULL)
56         return NULL;
57     dp->di_size = -1;
58     if ( (dp->di_dbm = dbm_open(file, flags, mode)) == 0 ) {
59         PyErr_SetFromErrno(DbmError);
60         Py_DECREF(dp);
61         return NULL;
62     }
63     return (PyObject *)dp;
64 }
65
66 /* Methods */
67
68 static void
69 dbm_dealloc(register dbmobject *dp)
70 {
71     if ( dp->di_dbm )
72         dbm_close(dp->di_dbm);
73     PyObject_Del(dp);
74 }
75
76 static Py_ssize_t
77 dbm_length(dbmobject *dp)
78 {
79     if (dp->di_dbm == NULL) {
80              PyErr_SetString(DbmError, "DBM object has already been closed");
81              return -1;
82     }
83     if ( dp->di_size < 0 ) {
84         datum key;
85         int size;
86
87         size = 0;
88         for ( key=dbm_firstkey(dp->di_dbm); key.dptr;
89               key = dbm_nextkey(dp->di_dbm))
90             size++;
91         dp->di_size = size;
92     }
93     return dp->di_size;
94 }
95
96 static PyObject *
97 dbm_subscript(dbmobject *dp, register PyObject *key)
98 {
99     datum drec, krec;
100     int tmp_size;
101
102     if (!PyArg_Parse(key, "s#", &krec.dptr, &tmp_size) )
103         return NULL;
104
105     krec.dsize = tmp_size;
106     check_dbmobject_open(dp);
107     drec = dbm_fetch(dp->di_dbm, krec);
108     if ( drec.dptr == 0 ) {
109         PyErr_SetString(PyExc_KeyError,
110                         PyString_AS_STRING((PyStringObject *)key));
111         return NULL;
112     }
113     if ( dbm_error(dp->di_dbm) ) {
114         dbm_clearerr(dp->di_dbm);
115         PyErr_SetString(DbmError, "");
116         return NULL;
117     }
118     return PyString_FromStringAndSize(drec.dptr, drec.dsize);
119 }
120
121 static int
122 dbm_ass_sub(dbmobject *dp, PyObject *v, PyObject *w)
123 {
124     datum krec, drec;
125     int tmp_size;
126
127     if ( !PyArg_Parse(v, "s#", &krec.dptr, &tmp_size) ) {
128         PyErr_SetString(PyExc_TypeError,
129                         "dbm mappings have string indices only");
130         return -1;
131     }
132     krec.dsize = tmp_size;
133     if (dp->di_dbm == NULL) {
134              PyErr_SetString(DbmError, "DBM object has already been closed");
135              return -1;
136     }
137     dp->di_size = -1;
138     if (w == NULL) {
139         if ( dbm_delete(dp->di_dbm, krec) < 0 ) {
140             dbm_clearerr(dp->di_dbm);
141             PyErr_SetString(PyExc_KeyError,
142                           PyString_AS_STRING((PyStringObject *)v));
143             return -1;
144         }
145     } else {
146         if ( !PyArg_Parse(w, "s#", &drec.dptr, &tmp_size) ) {
147             PyErr_SetString(PyExc_TypeError,
148                          "dbm mappings have string elements only");
149             return -1;
150         }
151         drec.dsize = tmp_size;
152         if ( dbm_store(dp->di_dbm, krec, drec, DBM_REPLACE) < 0 ) {
153             dbm_clearerr(dp->di_dbm);
154             PyErr_SetString(DbmError,
155                             "cannot add item to database");
156             return -1;
157         }
158     }
159     if ( dbm_error(dp->di_dbm) ) {
160         dbm_clearerr(dp->di_dbm);
161         PyErr_SetString(DbmError, "");
162         return -1;
163     }
164     return 0;
165 }
166
167 static int
168 dbm_contains(register dbmobject *dp, PyObject *v)
169 {
170     datum key, val;
171
172     if (PyString_AsStringAndSize(v, (char **)&key.dptr,
173                                  (Py_ssize_t *)&key.dsize)) {
174         return -1;
175     }
176
177     /* Expand check_dbmobject_open to return -1 */
178     if (dp->di_dbm == NULL) {
179         PyErr_SetString(DbmError, "DBM object has already been closed");
180         return -1;
181     }
182     val = dbm_fetch(dp->di_dbm, key);
183     return val.dptr != NULL;
184 }
185
186 static PySequenceMethods dbm_as_sequence = {
187     (lenfunc)dbm_length,        /*_length*/
188     0,                          /*sq_concat*/
189     0,                          /*sq_repeat*/
190     0,                          /*sq_item*/
191     0,                          /*sq_slice*/
192     0,                          /*sq_ass_item*/
193     0,                          /*sq_ass_slice*/
194     (objobjproc)dbm_contains,   /*sq_contains*/
195     0,                          /*sq_inplace_concat*/
196     0                           /*sq_inplace_repeat*/
197 };
198
199 static PyMappingMethods dbm_as_mapping = {
200     (lenfunc)dbm_length,                /*mp_length*/
201     (binaryfunc)dbm_subscript,          /*mp_subscript*/
202     (objobjargproc)dbm_ass_sub,         /*mp_ass_subscript*/
203 };
204
205 static PyObject *
206 dbm__close(register dbmobject *dp, PyObject *unused)
207 {
208     if (dp->di_dbm)
209         dbm_close(dp->di_dbm);
210     dp->di_dbm = NULL;
211     Py_INCREF(Py_None);
212     return Py_None;
213 }
214
215 static PyObject *
216 dbm_keys(register dbmobject *dp, PyObject *unused)
217 {
218     register PyObject *v, *item;
219     datum key;
220     int err;
221
222     check_dbmobject_open(dp);
223     v = PyList_New(0);
224     if (v == NULL)
225         return NULL;
226     for (key = dbm_firstkey(dp->di_dbm); key.dptr;
227          key = dbm_nextkey(dp->di_dbm)) {
228         item = PyString_FromStringAndSize(key.dptr, key.dsize);
229         if (item == NULL) {
230             Py_DECREF(v);
231             return NULL;
232         }
233         err = PyList_Append(v, item);
234         Py_DECREF(item);
235         if (err != 0) {
236             Py_DECREF(v);
237             return NULL;
238         }
239     }
240     return v;
241 }
242
243 static PyObject *
244 dbm_has_key(register dbmobject *dp, PyObject *args)
245 {
246     char *tmp_ptr;
247     datum key, val;
248     int tmp_size;
249
250     if (!PyArg_ParseTuple(args, "s#:has_key", &tmp_ptr, &tmp_size))
251         return NULL;
252     key.dptr = tmp_ptr;
253     key.dsize = tmp_size;
254     check_dbmobject_open(dp);
255     val = dbm_fetch(dp->di_dbm, key);
256     return PyInt_FromLong(val.dptr != NULL);
257 }
258
259 static PyObject *
260 dbm_get(register dbmobject *dp, PyObject *args)
261 {
262     datum key, val;
263     PyObject *defvalue = Py_None;
264     char *tmp_ptr;
265     int tmp_size;
266
267     if (!PyArg_ParseTuple(args, "s#|O:get",
268                           &tmp_ptr, &tmp_size, &defvalue))
269         return NULL;
270     key.dptr = tmp_ptr;
271     key.dsize = tmp_size;
272     check_dbmobject_open(dp);
273     val = dbm_fetch(dp->di_dbm, key);
274     if (val.dptr != NULL)
275         return PyString_FromStringAndSize(val.dptr, val.dsize);
276     else {
277         Py_INCREF(defvalue);
278         return defvalue;
279     }
280 }
281
282 static PyObject *
283 dbm_setdefault(register dbmobject *dp, PyObject *args)
284 {
285     datum key, val;
286     PyObject *defvalue = NULL;
287     char *tmp_ptr;
288     int tmp_size;
289
290     if (!PyArg_ParseTuple(args, "s#|S:setdefault",
291                           &tmp_ptr, &tmp_size, &defvalue))
292         return NULL;
293     key.dptr = tmp_ptr;
294     key.dsize = tmp_size;
295     check_dbmobject_open(dp);
296     val = dbm_fetch(dp->di_dbm, key);
297     if (val.dptr != NULL)
298         return PyString_FromStringAndSize(val.dptr, val.dsize);
299     if (defvalue == NULL) {
300         defvalue = PyString_FromStringAndSize(NULL, 0);
301         if (defvalue == NULL)
302             return NULL;
303     }
304     else
305         Py_INCREF(defvalue);
306     val.dptr = PyString_AS_STRING(defvalue);
307     val.dsize = PyString_GET_SIZE(defvalue);
308     if (dbm_store(dp->di_dbm, key, val, DBM_INSERT) < 0) {
309         dbm_clearerr(dp->di_dbm);
310         PyErr_SetString(DbmError, "cannot add item to database");
311         return NULL;
312     }
313     return defvalue;
314 }
315
316 static PyMethodDef dbm_methods[] = {
317     {"close",           (PyCFunction)dbm__close,        METH_NOARGS,
318      "close()\nClose the database."},
319     {"keys",            (PyCFunction)dbm_keys,          METH_NOARGS,
320      "keys() -> list\nReturn a list of all keys in the database."},
321     {"has_key",         (PyCFunction)dbm_has_key,       METH_VARARGS,
322      "has_key(key} -> boolean\nReturn true iff key is in the database."},
323     {"get",             (PyCFunction)dbm_get,           METH_VARARGS,
324      "get(key[, default]) -> value\n"
325      "Return the value for key if present, otherwise default."},
326     {"setdefault",      (PyCFunction)dbm_setdefault,    METH_VARARGS,
327      "setdefault(key[, default]) -> value\n"
328      "Return the value for key if present, otherwise default.  If key\n"
329      "is not in the database, it is inserted with default as the value."},
330     {NULL,              NULL}           /* sentinel */
331 };
332
333 static PyObject *
334 dbm_getattr(dbmobject *dp, char *name)
335 {
336     return Py_FindMethod(dbm_methods, (PyObject *)dp, name);
337 }
338
339 static PyTypeObject Dbmtype = {
340     PyVarObject_HEAD_INIT(NULL, 0)
341     "dbm.dbm",
342     sizeof(dbmobject),
343     0,
344     (destructor)dbm_dealloc,  /*tp_dealloc*/
345     0,                            /*tp_print*/
346     (getattrfunc)dbm_getattr, /*tp_getattr*/
347     0,                            /*tp_setattr*/
348     0,                            /*tp_compare*/
349     0,                            /*tp_repr*/
350     0,                            /*tp_as_number*/
351     &dbm_as_sequence,     /*tp_as_sequence*/
352     &dbm_as_mapping,              /*tp_as_mapping*/
353     0,                    /*tp_hash*/
354     0,                    /*tp_call*/
355     0,                    /*tp_str*/
356     0,                    /*tp_getattro*/
357     0,                    /*tp_setattro*/
358     0,                    /*tp_as_buffer*/
359     Py_TPFLAGS_DEFAULT,   /*tp_xxx4*/
360 };
361
362 /* ----------------------------------------------------------------- */
363
364 static PyObject *
365 dbmopen(PyObject *self, PyObject *args)
366 {
367     char *name;
368     char *flags = "r";
369     int iflags;
370     int mode = 0666;
371
372     if ( !PyArg_ParseTuple(args, "s|si:open", &name, &flags, &mode) )
373         return NULL;
374     if ( strcmp(flags, "r") == 0 )
375         iflags = O_RDONLY;
376     else if ( strcmp(flags, "w") == 0 )
377         iflags = O_RDWR;
378     else if ( strcmp(flags, "rw") == 0 ) /* B/W compat */
379         iflags = O_RDWR|O_CREAT;
380     else if ( strcmp(flags, "c") == 0 )
381         iflags = O_RDWR|O_CREAT;
382     else if ( strcmp(flags, "n") == 0 )
383         iflags = O_RDWR|O_CREAT|O_TRUNC;
384     else {
385         PyErr_SetString(DbmError,
386                         "arg 2 to open should be 'r', 'w', 'c', or 'n'");
387         return NULL;
388     }
389     return newdbmobject(name, iflags, mode);
390 }
391
392 static PyMethodDef dbmmodule_methods[] = {
393     { "open", (PyCFunction)dbmopen, METH_VARARGS,
394       "open(path[, flag[, mode]]) -> mapping\n"
395       "Return a database object."},
396     { 0, 0 },
397 };
398
399 PyMODINIT_FUNC
400 initdbm(void) {
401     PyObject *m, *d, *s;
402
403     Dbmtype.ob_type = &PyType_Type;
404     m = Py_InitModule("dbm", dbmmodule_methods);
405     if (m == NULL)
406         return;
407     d = PyModule_GetDict(m);
408     if (DbmError == NULL)
409         DbmError = PyErr_NewException("dbm.error", NULL, NULL);
410     s = PyString_FromString(which_dbm);
411     if (s != NULL) {
412         PyDict_SetItemString(d, "library", s);
413         Py_DECREF(s);
414     }
415     if (DbmError != NULL)
416         PyDict_SetItemString(d, "error", DbmError);
417 }