Home | History | Annotate | Download | only in Modules
      1 
      2 /* DBM module using dictionary interface */
      3 /* Author: Anthony Baxter, after dbmmodule.c */
      4 /* Doc strings: Mitch Chapman */
      5 
      6 
      7 #include "Python.h"
      8 
      9 #include <sys/types.h>
     10 #include <sys/stat.h>
     11 #include <fcntl.h>
     12 #include "gdbm.h"
     13 
     14 #if defined(WIN32) && !defined(__CYGWIN__)
     15 #include "gdbmerrno.h"
     16 extern const char * gdbm_strerror(gdbm_error);
     17 #endif
     18 
     19 PyDoc_STRVAR(gdbmmodule__doc__,
     20 "This module provides an interface to the GNU DBM (GDBM) library.\n\
     21 \n\
     22 This module is quite similar to the dbm module, but uses GDBM instead to\n\
     23 provide some additional functionality. Please note that the file formats\n\
     24 created by GDBM and dbm are incompatible. \n\
     25 \n\
     26 GDBM objects behave like mappings (dictionaries), except that keys and\n\
     27 values are always strings. Printing a GDBM object doesn't print the\n\
     28 keys and values, and the items() and values() methods are not\n\
     29 supported.");
     30 
     31 typedef struct {
     32     PyObject_HEAD
     33     int di_size;	/* -1 means recompute */
     34     GDBM_FILE di_dbm;
     35 } dbmobject;
     36 
     37 static PyTypeObject Dbmtype;
     38 
     39 #define is_dbmobject(v) (Py_TYPE(v) == &Dbmtype)
     40 #define check_dbmobject_open(v) if ((v)->di_dbm == NULL) \
     41     { PyErr_SetString(DbmError, "GDBM object has already been closed"); \
     42       return NULL; }
     43 
     44 
     45 
     46 static PyObject *DbmError;
     47 
     48 PyDoc_STRVAR(gdbm_object__doc__,
     49 "This object represents a GDBM database.\n\
     50 GDBM objects behave like mappings (dictionaries), except that keys and\n\
     51 values are always strings. Printing a GDBM object doesn't print the\n\
     52 keys and values, and the items() and values() methods are not\n\
     53 supported.\n\
     54 \n\
     55 GDBM objects also support additional operations such as firstkey,\n\
     56 nextkey, reorganize, and sync.");
     57 
     58 static PyObject *
     59 newdbmobject(char *file, int flags, int mode)
     60 {
     61     dbmobject *dp;
     62 
     63     dp = PyObject_New(dbmobject, &Dbmtype);
     64     if (dp == NULL)
     65         return NULL;
     66     dp->di_size = -1;
     67     errno = 0;
     68     if ((dp->di_dbm = gdbm_open(file, 0, flags, mode, NULL)) == 0) {
     69         if (errno != 0)
     70             PyErr_SetFromErrno(DbmError);
     71         else
     72             PyErr_SetString(DbmError, gdbm_strerror(gdbm_errno));
     73         Py_DECREF(dp);
     74         return NULL;
     75     }
     76     return (PyObject *)dp;
     77 }
     78 
     79 /* Methods */
     80 
     81 static void
     82 dbm_dealloc(register dbmobject *dp)
     83 {
     84     if (dp->di_dbm)
     85         gdbm_close(dp->di_dbm);
     86     PyObject_Del(dp);
     87 }
     88 
     89 static Py_ssize_t
     90 dbm_length(dbmobject *dp)
     91 {
     92     if (dp->di_dbm == NULL) {
     93         PyErr_SetString(DbmError, "GDBM object has already been closed");
     94         return -1;
     95     }
     96     if (dp->di_size < 0) {
     97         datum key,okey;
     98         int size;
     99         okey.dsize=0;
    100         okey.dptr=NULL;
    101 
    102         size = 0;
    103         for (key=gdbm_firstkey(dp->di_dbm); key.dptr;
    104              key = gdbm_nextkey(dp->di_dbm,okey)) {
    105             size++;
    106             if(okey.dsize) free(okey.dptr);
    107             okey=key;
    108         }
    109         dp->di_size = size;
    110     }
    111     return dp->di_size;
    112 }
    113 
    114 static PyObject *
    115 dbm_subscript(dbmobject *dp, register PyObject *key)
    116 {
    117     PyObject *v;
    118     datum drec, krec;
    119 
    120     if (!PyArg_Parse(key, "s#", &krec.dptr, &krec.dsize) )
    121         return NULL;
    122 
    123     if (dp->di_dbm == NULL) {
    124         PyErr_SetString(DbmError,
    125                         "GDBM object has already been closed");
    126         return NULL;
    127     }
    128     drec = gdbm_fetch(dp->di_dbm, krec);
    129     if (drec.dptr == 0) {
    130         PyErr_SetString(PyExc_KeyError,
    131                         PyString_AS_STRING((PyStringObject *)key));
    132         return NULL;
    133     }
    134     v = PyString_FromStringAndSize(drec.dptr, drec.dsize);
    135     free(drec.dptr);
    136     return v;
    137 }
    138 
    139 static int
    140 dbm_ass_sub(dbmobject *dp, PyObject *v, PyObject *w)
    141 {
    142     datum krec, drec;
    143 
    144     if (!PyArg_Parse(v, "s#", &krec.dptr, &krec.dsize) ) {
    145         PyErr_SetString(PyExc_TypeError,
    146                         "gdbm mappings have string indices only");
    147         return -1;
    148     }
    149     if (dp->di_dbm == NULL) {
    150         PyErr_SetString(DbmError,
    151                         "GDBM object has already been closed");
    152         return -1;
    153     }
    154     dp->di_size = -1;
    155     if (w == NULL) {
    156         if (gdbm_delete(dp->di_dbm, krec) < 0) {
    157             PyErr_SetString(PyExc_KeyError,
    158                             PyString_AS_STRING((PyStringObject *)v));
    159             return -1;
    160         }
    161     }
    162     else {
    163         if (!PyArg_Parse(w, "s#", &drec.dptr, &drec.dsize)) {
    164             PyErr_SetString(PyExc_TypeError,
    165                             "gdbm mappings have string elements only");
    166             return -1;
    167         }
    168         errno = 0;
    169         if (gdbm_store(dp->di_dbm, krec, drec, GDBM_REPLACE) < 0) {
    170             if (errno != 0)
    171                 PyErr_SetFromErrno(DbmError);
    172             else
    173                 PyErr_SetString(DbmError,
    174                                 gdbm_strerror(gdbm_errno));
    175             return -1;
    176         }
    177     }
    178     return 0;
    179 }
    180 
    181 static int
    182 dbm_contains(register dbmobject *dp, PyObject *arg)
    183 {
    184     datum key;
    185 
    186     if ((dp)->di_dbm == NULL) {
    187         PyErr_SetString(DbmError,
    188                         "GDBM object has already been closed");
    189         return -1;
    190     }
    191     if (!PyString_Check(arg)) {
    192         PyErr_Format(PyExc_TypeError,
    193                      "gdbm key must be string, not %.100s",
    194                      arg->ob_type->tp_name);
    195         return -1;
    196     }
    197     key.dptr = PyString_AS_STRING(arg);
    198     key.dsize = PyString_GET_SIZE(arg);
    199     return gdbm_exists(dp->di_dbm, key);
    200 }
    201 
    202 static PySequenceMethods dbm_as_sequence = {
    203     (lenfunc)dbm_length,               /*_length*/
    204        0,              /*sq_concat*/
    205        0,                      /*sq_repeat*/
    206        0,                      /*sq_item*/
    207        0,                      /*sq_slice*/
    208        0,                      /*sq_ass_item*/
    209        0,                  /*sq_ass_slice*/
    210        (objobjproc)dbm_contains,               /*sq_contains*/
    211        0,                  /*sq_inplace_concat*/
    212        0                   /*sq_inplace_repeat*/
    213 };
    214 
    215 static PyMappingMethods dbm_as_mapping = {
    216     (lenfunc)dbm_length,		/*mp_length*/
    217     (binaryfunc)dbm_subscript,          /*mp_subscript*/
    218     (objobjargproc)dbm_ass_sub,         /*mp_ass_subscript*/
    219 };
    220 
    221 PyDoc_STRVAR(dbm_close__doc__,
    222 "close() -> None\n\
    223 Closes the database.");
    224 
    225 static PyObject *
    226 dbm_close(register dbmobject *dp, PyObject *unused)
    227 {
    228     if (dp->di_dbm)
    229         gdbm_close(dp->di_dbm);
    230     dp->di_dbm = NULL;
    231     Py_INCREF(Py_None);
    232     return Py_None;
    233 }
    234 
    235 PyDoc_STRVAR(dbm_keys__doc__,
    236 "keys() -> list_of_keys\n\
    237 Get a list of all keys in the database.");
    238 
    239 static PyObject *
    240 dbm_keys(register dbmobject *dp, PyObject *unused)
    241 {
    242     register PyObject *v, *item;
    243     datum key, nextkey;
    244     int err;
    245 
    246     if (dp == NULL || !is_dbmobject(dp)) {
    247         PyErr_BadInternalCall();
    248         return NULL;
    249     }
    250     check_dbmobject_open(dp);
    251 
    252     v = PyList_New(0);
    253     if (v == NULL)
    254         return NULL;
    255 
    256     key = gdbm_firstkey(dp->di_dbm);
    257     while (key.dptr) {
    258         item = PyString_FromStringAndSize(key.dptr, key.dsize);
    259         if (item == NULL) {
    260             free(key.dptr);
    261             Py_DECREF(v);
    262             return NULL;
    263         }
    264         err = PyList_Append(v, item);
    265         Py_DECREF(item);
    266         if (err != 0) {
    267             free(key.dptr);
    268             Py_DECREF(v);
    269             return NULL;
    270         }
    271         nextkey = gdbm_nextkey(dp->di_dbm, key);
    272         free(key.dptr);
    273         key = nextkey;
    274     }
    275     return v;
    276 }
    277 
    278 PyDoc_STRVAR(dbm_has_key__doc__,
    279 "has_key(key) -> boolean\n\
    280 Find out whether or not the database contains a given key.");
    281 
    282 static PyObject *
    283 dbm_has_key(register dbmobject *dp, PyObject *args)
    284 {
    285     datum key;
    286 
    287     if (!PyArg_ParseTuple(args, "s#:has_key", &key.dptr, &key.dsize))
    288         return NULL;
    289     check_dbmobject_open(dp);
    290     return PyInt_FromLong((long) gdbm_exists(dp->di_dbm, key));
    291 }
    292 
    293 PyDoc_STRVAR(dbm_firstkey__doc__,
    294 "firstkey() -> key\n\
    295 It's possible to loop over every key in the database using this method\n\
    296 and the nextkey() method. The traversal is ordered by GDBM's internal\n\
    297 hash values, and won't be sorted by the key values. This method\n\
    298 returns the starting key.");
    299 
    300 static PyObject *
    301 dbm_firstkey(register dbmobject *dp, PyObject *unused)
    302 {
    303     register PyObject *v;
    304     datum key;
    305 
    306     check_dbmobject_open(dp);
    307     key = gdbm_firstkey(dp->di_dbm);
    308     if (key.dptr) {
    309         v = PyString_FromStringAndSize(key.dptr, key.dsize);
    310         free(key.dptr);
    311         return v;
    312     }
    313     else {
    314         Py_INCREF(Py_None);
    315         return Py_None;
    316     }
    317 }
    318 
    319 PyDoc_STRVAR(dbm_nextkey__doc__,
    320 "nextkey(key) -> next_key\n\
    321 Returns the key that follows key in the traversal.\n\
    322 The following code prints every key in the database db, without having\n\
    323 to create a list in memory that contains them all:\n\
    324 \n\
    325       k = db.firstkey()\n\
    326       while k != None:\n\
    327           print k\n\
    328           k = db.nextkey(k)");
    329 
    330 static PyObject *
    331 dbm_nextkey(register dbmobject *dp, PyObject *args)
    332 {
    333     register PyObject *v;
    334     datum key, nextkey;
    335 
    336     if (!PyArg_ParseTuple(args, "s#:nextkey", &key.dptr, &key.dsize))
    337         return NULL;
    338     check_dbmobject_open(dp);
    339     nextkey = gdbm_nextkey(dp->di_dbm, key);
    340     if (nextkey.dptr) {
    341         v = PyString_FromStringAndSize(nextkey.dptr, nextkey.dsize);
    342         free(nextkey.dptr);
    343         return v;
    344     }
    345     else {
    346         Py_INCREF(Py_None);
    347         return Py_None;
    348     }
    349 }
    350 
    351 PyDoc_STRVAR(dbm_reorganize__doc__,
    352 "reorganize() -> None\n\
    353 If you have carried out a lot of deletions and would like to shrink\n\
    354 the space used by the GDBM file, this routine will reorganize the\n\
    355 database. GDBM will not shorten the length of a database file except\n\
    356 by using this reorganization; otherwise, deleted file space will be\n\
    357 kept and reused as new (key,value) pairs are added.");
    358 
    359 static PyObject *
    360 dbm_reorganize(register dbmobject *dp, PyObject *unused)
    361 {
    362     check_dbmobject_open(dp);
    363     errno = 0;
    364     if (gdbm_reorganize(dp->di_dbm) < 0) {
    365         if (errno != 0)
    366             PyErr_SetFromErrno(DbmError);
    367         else
    368             PyErr_SetString(DbmError, gdbm_strerror(gdbm_errno));
    369         return NULL;
    370     }
    371     Py_INCREF(Py_None);
    372     return Py_None;
    373 }
    374 
    375 PyDoc_STRVAR(dbm_sync__doc__,
    376 "sync() -> None\n\
    377 When the database has been opened in fast mode, this method forces\n\
    378 any unwritten data to be written to the disk.");
    379 
    380 static PyObject *
    381 dbm_sync(register dbmobject *dp, PyObject *unused)
    382 {
    383     check_dbmobject_open(dp);
    384     gdbm_sync(dp->di_dbm);
    385     Py_INCREF(Py_None);
    386     return Py_None;
    387 }
    388 
    389 static PyMethodDef dbm_methods[] = {
    390     {"close",	  (PyCFunction)dbm_close,   METH_NOARGS, dbm_close__doc__},
    391     {"keys",	  (PyCFunction)dbm_keys,    METH_NOARGS, dbm_keys__doc__},
    392     {"has_key",   (PyCFunction)dbm_has_key, METH_VARARGS, dbm_has_key__doc__},
    393     {"firstkey",  (PyCFunction)dbm_firstkey,METH_NOARGS, dbm_firstkey__doc__},
    394     {"nextkey",	  (PyCFunction)dbm_nextkey, METH_VARARGS, dbm_nextkey__doc__},
    395     {"reorganize",(PyCFunction)dbm_reorganize,METH_NOARGS, dbm_reorganize__doc__},
    396     {"sync",      (PyCFunction)dbm_sync,    METH_NOARGS, dbm_sync__doc__},
    397     {NULL,		NULL}		/* sentinel */
    398 };
    399 
    400 static PyObject *
    401 dbm_getattr(dbmobject *dp, char *name)
    402 {
    403     return Py_FindMethod(dbm_methods, (PyObject *)dp, name);
    404 }
    405 
    406 static PyTypeObject Dbmtype = {
    407     PyVarObject_HEAD_INIT(0, 0)
    408     "gdbm.gdbm",
    409     sizeof(dbmobject),
    410     0,
    411     (destructor)dbm_dealloc,            /*tp_dealloc*/
    412     0,                                  /*tp_print*/
    413     (getattrfunc)dbm_getattr,           /*tp_getattr*/
    414     0,                                  /*tp_setattr*/
    415     0,                                  /*tp_compare*/
    416     0,                                  /*tp_repr*/
    417     0,                                  /*tp_as_number*/
    418     &dbm_as_sequence,                   /*tp_as_sequence*/
    419     &dbm_as_mapping,                    /*tp_as_mapping*/
    420     0,                                  /*tp_hash*/
    421     0,                                  /*tp_call*/
    422     0,                                  /*tp_str*/
    423     0,                                  /*tp_getattro*/
    424     0,                                  /*tp_setattro*/
    425     0,                                  /*tp_as_buffer*/
    426     Py_TPFLAGS_DEFAULT,                 /*tp_xxx4*/
    427     gdbm_object__doc__,                 /*tp_doc*/
    428 };
    429 
    430 /* ----------------------------------------------------------------- */
    431 
    432 PyDoc_STRVAR(dbmopen__doc__,
    433 "open(filename, [flags, [mode]])  -> dbm_object\n\
    434 Open a dbm database and return a dbm object. The filename argument is\n\
    435 the name of the database file.\n\
    436 \n\
    437 The optional flags argument can be 'r' (to open an existing database\n\
    438 for reading only -- default), 'w' (to open an existing database for\n\
    439 reading and writing), 'c' (which creates the database if it doesn't\n\
    440 exist), or 'n' (which always creates a new empty database).\n\
    441 \n\
    442 Some versions of gdbm support additional flags which must be\n\
    443 appended to one of the flags described above. The module constant\n\
    444 'open_flags' is a string of valid additional flags. The 'f' flag\n\
    445 opens the database in fast mode; altered data will not automatically\n\
    446 be written to the disk after every change. This results in faster\n\
    447 writes to the database, but may result in an inconsistent database\n\
    448 if the program crashes while the database is still open. Use the\n\
    449 sync() method to force any unwritten data to be written to the disk.\n\
    450 The 's' flag causes all database operations to be synchronized to\n\
    451 disk. The 'u' flag disables locking of the database file.\n\
    452 \n\
    453 The optional mode argument is the Unix mode of the file, used only\n\
    454 when the database has to be created. It defaults to octal 0666. ");
    455 
    456 static PyObject *
    457 dbmopen(PyObject *self, PyObject *args)
    458 {
    459     char *name;
    460     char *flags = "r";
    461     int iflags;
    462     int mode = 0666;
    463 
    464     if (!PyArg_ParseTuple(args, "s|si:open", &name, &flags, &mode))
    465         return NULL;
    466     switch (flags[0]) {
    467     case 'r':
    468         iflags = GDBM_READER;
    469         break;
    470     case 'w':
    471         iflags = GDBM_WRITER;
    472         break;
    473     case 'c':
    474         iflags = GDBM_WRCREAT;
    475         break;
    476     case 'n':
    477         iflags = GDBM_NEWDB;
    478         break;
    479     default:
    480         PyErr_SetString(DbmError,
    481                         "First flag must be one of 'r', 'w', 'c' or 'n'");
    482         return NULL;
    483     }
    484     for (flags++; *flags != '\0'; flags++) {
    485         char buf[40];
    486         switch (*flags) {
    487 #ifdef GDBM_FAST
    488             case 'f':
    489                 iflags |= GDBM_FAST;
    490                 break;
    491 #endif
    492 #ifdef GDBM_SYNC
    493             case 's':
    494                 iflags |= GDBM_SYNC;
    495                 break;
    496 #endif
    497 #ifdef GDBM_NOLOCK
    498             case 'u':
    499                 iflags |= GDBM_NOLOCK;
    500                 break;
    501 #endif
    502             default:
    503                 PyOS_snprintf(buf, sizeof(buf), "Flag '%c' is not supported.",
    504                 	      *flags);
    505                 PyErr_SetString(DbmError, buf);
    506                 return NULL;
    507         }
    508     }
    509 
    510     return newdbmobject(name, iflags, mode);
    511 }
    512 
    513 static char dbmmodule_open_flags[] = "rwcn"
    514 #ifdef GDBM_FAST
    515                                      "f"
    516 #endif
    517 #ifdef GDBM_SYNC
    518                                      "s"
    519 #endif
    520 #ifdef GDBM_NOLOCK
    521                                      "u"
    522 #endif
    523                                      ;
    524 
    525 static PyMethodDef dbmmodule_methods[] = {
    526     { "open", (PyCFunction)dbmopen, METH_VARARGS, dbmopen__doc__},
    527     { 0, 0 },
    528 };
    529 
    530 PyMODINIT_FUNC
    531 initgdbm(void) {
    532     PyObject *m, *d, *s;
    533 
    534     Dbmtype.ob_type = &PyType_Type;
    535     m = Py_InitModule4("gdbm", dbmmodule_methods,
    536                        gdbmmodule__doc__, (PyObject *)NULL,
    537                        PYTHON_API_VERSION);
    538     if (m == NULL)
    539 	return;
    540     d = PyModule_GetDict(m);
    541     DbmError = PyErr_NewException("gdbm.error", NULL, NULL);
    542     if (DbmError != NULL) {
    543         PyDict_SetItemString(d, "error", DbmError);
    544         s = PyString_FromString(dbmmodule_open_flags);
    545         PyDict_SetItemString(d, "open_flags", s);
    546         Py_DECREF(s);
    547     }
    548 }
    549