home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 15 / AACD15.ISO / AACD / Programming / Python2 / Python20_source / Modules / dbmmodule.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-10-25  |  8.4 KB  |  357 lines

  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. static char *which_dbm = "ndbm";
  17. #elif defined(HAVE_DB1_NDBM_H)
  18. #include <db1/ndbm.h>
  19. static char *which_dbm = "BSD db";
  20. #elif defined(HAVE_GDBM_NDBM_H)
  21. #include <gdbm/ndbm.h>
  22. static char *which_dbm = "GNU gdbm";
  23. #else
  24. #error "No ndbm.h available!"
  25. #endif
  26.  
  27. typedef struct {
  28.     PyObject_HEAD
  29.     int di_size;    /* -1 means recompute */
  30.     DBM *di_dbm;
  31. } dbmobject;
  32.  
  33. staticforward PyTypeObject Dbmtype;
  34.  
  35. #define is_dbmobject(v) ((v)->ob_type == &Dbmtype)
  36. #define check_dbmobject_open(v) if ((v)->di_dbm == NULL) \
  37.                { PyErr_SetString(DbmError, "DBM object has already been closed"); \
  38.                  return NULL; }
  39.  
  40. static PyObject *DbmError;
  41.  
  42. static PyObject *
  43. newdbmobject(char *file, int flags, int mode)
  44. {
  45.         dbmobject *dp;
  46.  
  47.     dp = PyObject_New(dbmobject, &Dbmtype);
  48.     if (dp == NULL)
  49.         return NULL;
  50.     dp->di_size = -1;
  51.     if ( (dp->di_dbm = dbm_open(file, flags, mode)) == 0 ) {
  52.         PyErr_SetFromErrno(DbmError);
  53.         Py_DECREF(dp);
  54.         return NULL;
  55.     }
  56.     return (PyObject *)dp;
  57. }
  58.  
  59. /* Methods */
  60.  
  61. static void
  62. dbm_dealloc(register dbmobject *dp)
  63. {
  64.         if ( dp->di_dbm )
  65.         dbm_close(dp->di_dbm);
  66.     PyObject_Del(dp);
  67. }
  68.  
  69. static int
  70. dbm_length(dbmobject *dp)
  71. {
  72.         if (dp->di_dbm == NULL) {
  73.                  PyErr_SetString(DbmError, "DBM object has already been closed"); 
  74.                  return -1; 
  75.         }
  76.         if ( dp->di_size < 0 ) {
  77.         datum key;
  78.         int size;
  79.  
  80.         size = 0;
  81.         for ( key=dbm_firstkey(dp->di_dbm); key.dptr;
  82.               key = dbm_nextkey(dp->di_dbm))
  83.             size++;
  84.         dp->di_size = size;
  85.     }
  86.     return dp->di_size;
  87. }
  88.  
  89. static PyObject *
  90. dbm_subscript(dbmobject *dp, register PyObject *key)
  91. {
  92.     datum drec, krec;
  93.     
  94.     if (!PyArg_Parse(key, "s#", &krec.dptr, &krec.dsize) )
  95.         return NULL;
  96.     
  97.         check_dbmobject_open(dp);
  98.     drec = dbm_fetch(dp->di_dbm, krec);
  99.     if ( drec.dptr == 0 ) {
  100.         PyErr_SetString(PyExc_KeyError,
  101.                 PyString_AS_STRING((PyStringObject *)key));
  102.         return NULL;
  103.     }
  104.     if ( dbm_error(dp->di_dbm) ) {
  105.         dbm_clearerr(dp->di_dbm);
  106.         PyErr_SetString(DbmError, "");
  107.         return NULL;
  108.     }
  109.     return PyString_FromStringAndSize(drec.dptr, drec.dsize);
  110. }
  111.  
  112. static int
  113. dbm_ass_sub(dbmobject *dp, PyObject *v, PyObject *w)
  114. {
  115.         datum krec, drec;
  116.     
  117.         if ( !PyArg_Parse(v, "s#", &krec.dptr, &krec.dsize) ) {
  118.         PyErr_SetString(PyExc_TypeError,
  119.                 "dbm mappings have string indices only");
  120.         return -1;
  121.     }
  122.         if (dp->di_dbm == NULL) {
  123.                  PyErr_SetString(DbmError, "DBM object has already been closed"); 
  124.                  return -1;
  125.         }
  126.     dp->di_size = -1;
  127.     if (w == NULL) {
  128.         if ( dbm_delete(dp->di_dbm, krec) < 0 ) {
  129.             dbm_clearerr(dp->di_dbm);
  130.             PyErr_SetString(PyExc_KeyError,
  131.                       PyString_AS_STRING((PyStringObject *)v));
  132.             return -1;
  133.         }
  134.     } else {
  135.         if ( !PyArg_Parse(w, "s#", &drec.dptr, &drec.dsize) ) {
  136.             PyErr_SetString(PyExc_TypeError,
  137.                      "dbm mappings have string elements only");
  138.             return -1;
  139.         }
  140.         if ( dbm_store(dp->di_dbm, krec, drec, DBM_REPLACE) < 0 ) {
  141.             dbm_clearerr(dp->di_dbm);
  142.             PyErr_SetString(DbmError,
  143.                     "Cannot add item to database");
  144.             return -1;
  145.         }
  146.     }
  147.     if ( dbm_error(dp->di_dbm) ) {
  148.         dbm_clearerr(dp->di_dbm);
  149.         PyErr_SetString(DbmError, "");
  150.         return -1;
  151.     }
  152.     return 0;
  153. }
  154.  
  155. static PyMappingMethods dbm_as_mapping = {
  156.     (inquiry)dbm_length,        /*mp_length*/
  157.     (binaryfunc)dbm_subscript,    /*mp_subscript*/
  158.     (objobjargproc)dbm_ass_sub,    /*mp_ass_subscript*/
  159. };
  160.  
  161. static PyObject *
  162. dbm__close(register dbmobject *dp, PyObject *args)
  163. {
  164.     if (!PyArg_ParseTuple(args, ":close"))
  165.         return NULL;
  166.         if (dp->di_dbm)
  167.         dbm_close(dp->di_dbm);
  168.     dp->di_dbm = NULL;
  169.     Py_INCREF(Py_None);
  170.     return Py_None;
  171. }
  172.  
  173. static PyObject *
  174. dbm_keys(register dbmobject *dp, PyObject *args)
  175. {
  176.     register PyObject *v, *item;
  177.     datum key;
  178.     int err;
  179.  
  180.     if (!PyArg_ParseTuple(args, ":keys"))
  181.         return NULL;
  182.         check_dbmobject_open(dp);
  183.     v = PyList_New(0);
  184.     if (v == NULL)
  185.         return NULL;
  186.     for (key = dbm_firstkey(dp->di_dbm); key.dptr;
  187.          key = dbm_nextkey(dp->di_dbm)) {
  188.         item = PyString_FromStringAndSize(key.dptr, key.dsize);
  189.         if (item == NULL) {
  190.             Py_DECREF(v);
  191.             return NULL;
  192.         }
  193.         err = PyList_Append(v, item);
  194.         Py_DECREF(item);
  195.         if (err != 0) {
  196.             Py_DECREF(v);
  197.             return NULL;
  198.         }
  199.     }
  200.     return v;
  201. }
  202.  
  203. static PyObject *
  204. dbm_has_key(register dbmobject *dp, PyObject *args)
  205. {
  206.     datum key, val;
  207.     
  208.     if (!PyArg_ParseTuple(args, "s#:has_key", &key.dptr, &key.dsize))
  209.         return NULL;
  210.         check_dbmobject_open(dp);
  211.     val = dbm_fetch(dp->di_dbm, key);
  212.     return PyInt_FromLong(val.dptr != NULL);
  213. }
  214.  
  215. static PyObject *
  216. dbm_get(register dbmobject *dp, PyObject *args)
  217. {
  218.     datum key, val;
  219.     PyObject *defvalue = Py_None;
  220.  
  221.     if (!PyArg_ParseTuple(args, "s#|O:get",
  222.                               &key.dptr, &key.dsize, &defvalue))
  223.         return NULL;
  224.         check_dbmobject_open(dp);
  225.     val = dbm_fetch(dp->di_dbm, key);
  226.     if (val.dptr != NULL)
  227.         return PyString_FromStringAndSize(val.dptr, val.dsize);
  228.     else {
  229.         Py_INCREF(defvalue);
  230.         return defvalue;
  231.     }
  232. }
  233.  
  234. static PyObject *
  235. dbm_setdefault(register dbmobject *dp, PyObject *args)
  236. {
  237.     datum key, val;
  238.     PyObject *defvalue = NULL;
  239.  
  240.     if (!PyArg_ParseTuple(args, "s#|S:setdefault",
  241.                               &key.dptr, &key.dsize, &defvalue))
  242.         return NULL;
  243.         check_dbmobject_open(dp);
  244.     val = dbm_fetch(dp->di_dbm, key);
  245.     if (val.dptr != NULL)
  246.         return PyString_FromStringAndSize(val.dptr, val.dsize);
  247.     if (defvalue == NULL) {
  248.         defvalue = PyString_FromStringAndSize(NULL, 0);
  249.         if (defvalue == NULL)
  250.             return NULL;
  251.     }
  252.     else
  253.         Py_INCREF(defvalue);
  254.     val.dptr = PyString_AS_STRING(defvalue);
  255.     val.dsize = PyString_GET_SIZE(defvalue);
  256.     if (dbm_store(dp->di_dbm, key, val, DBM_INSERT) < 0) {
  257.         dbm_clearerr(dp->di_dbm);
  258.         PyErr_SetString(DbmError, "Cannot add item to database");
  259.         return NULL;
  260.     }
  261.     return defvalue;
  262. }
  263.  
  264. static PyMethodDef dbm_methods[] = {
  265.     {"close",    (PyCFunction)dbm__close,    METH_VARARGS,
  266.      "close()\nClose the database."},
  267.     {"keys",    (PyCFunction)dbm_keys,        METH_VARARGS,
  268.      "keys() -> list\nReturn a list of all keys in the database."},
  269.     {"has_key",    (PyCFunction)dbm_has_key,    METH_VARARGS,
  270.      "has_key(key} -> boolean\nReturn true iff key is in the database."},
  271.     {"get",        (PyCFunction)dbm_get,        METH_VARARGS,
  272.      "get(key[, default]) -> value\n"
  273.      "Return the value for key if present, otherwise default."},
  274.     {"setdefault",    (PyCFunction)dbm_setdefault,    METH_VARARGS,
  275.      "setdefault(key[, default]) -> value\n"
  276.      "Return the value for key if present, otherwise default.  If key\n"
  277.      "is not in the database, it is inserted with default as the value."},
  278.     {NULL,        NULL}        /* sentinel */
  279. };
  280.  
  281. static PyObject *
  282. dbm_getattr(dbmobject *dp, char *name)
  283. {
  284.     return Py_FindMethod(dbm_methods, (PyObject *)dp, name);
  285. }
  286.  
  287. static PyTypeObject Dbmtype = {
  288.     PyObject_HEAD_INIT(&PyType_Type)
  289.     0,
  290.     "dbm",
  291.     sizeof(dbmobject),
  292.     0,
  293.     (destructor)dbm_dealloc,  /*tp_dealloc*/
  294.     0,              /*tp_print*/
  295.     (getattrfunc)dbm_getattr, /*tp_getattr*/
  296.     0,              /*tp_setattr*/
  297.     0,              /*tp_compare*/
  298.     0,              /*tp_repr*/
  299.     0,              /*tp_as_number*/
  300.     0,              /*tp_as_sequence*/
  301.     &dbm_as_mapping,      /*tp_as_mapping*/
  302. };
  303.  
  304. /* ----------------------------------------------------------------- */
  305.  
  306. static PyObject *
  307. dbmopen(PyObject *self, PyObject *args)
  308. {
  309.     char *name;
  310.     char *flags = "r";
  311.     int iflags;
  312.     int mode = 0666;
  313.  
  314.         if ( !PyArg_ParseTuple(args, "s|si:open", &name, &flags, &mode) )
  315.         return NULL;
  316.     if ( strcmp(flags, "r") == 0 )
  317.         iflags = O_RDONLY;
  318.     else if ( strcmp(flags, "w") == 0 )
  319.         iflags = O_RDWR;
  320.     else if ( strcmp(flags, "rw") == 0 ) /* B/W compat */
  321.         iflags = O_RDWR|O_CREAT; 
  322.     else if ( strcmp(flags, "c") == 0 )
  323.         iflags = O_RDWR|O_CREAT;
  324.     else if ( strcmp(flags, "n") == 0 )
  325.         iflags = O_RDWR|O_CREAT|O_TRUNC;
  326.     else {
  327.         PyErr_SetString(DbmError,
  328.                 "Flags should be one of 'r', 'w', 'c' or 'n'");
  329.         return NULL;
  330.     }
  331.         return newdbmobject(name, iflags, mode);
  332. }
  333.  
  334. static PyMethodDef dbmmodule_methods[] = {
  335.     { "open", (PyCFunction)dbmopen, METH_VARARGS,
  336.       "open(path[, flag[, mode]]) -> mapping\n"
  337.       "Return a database object."},
  338.     { 0, 0 },
  339. };
  340.  
  341. DL_EXPORT(void)
  342. initdbm(void) {
  343.     PyObject *m, *d, *s;
  344.  
  345.     m = Py_InitModule("dbm", dbmmodule_methods);
  346.     d = PyModule_GetDict(m);
  347.     if (DbmError == NULL)
  348.         DbmError = PyErr_NewException("dbm.error", NULL, NULL);
  349.     s = PyString_FromString(which_dbm);
  350.     if (s != NULL) {
  351.         PyDict_SetItemString(d, "library", s);
  352.         Py_DECREF(s);
  353.     }
  354.     if (DbmError != NULL)
  355.         PyDict_SetItemString(d, "error", DbmError);
  356. }
  357.