blob: 24d859b56448704e53764ed681837631191f5b82 [file] [log] [blame]
Guido van Rossum1100dca1995-08-30 23:43:03 +00001
2/* Berkeley DB interface.
3 Author: Michael McLay
4 Hacked: Guido van Rossum
5 Btree and Recno additions plus sequence methods: David Ely
6
7 XXX To do:
8 - provide interface to the B-tree and record libraries too
9 - provide a way to access the various hash functions
10 - support more open flags
Guido van Rossum675e9941999-09-20 13:28:18 +000011
12 The windows port of the Berkeley DB code is hard to find on the web:
13 www.nightmare.com/software.html
14*/
Guido van Rossum1100dca1995-08-30 23:43:03 +000015
Guido van Rossumdfe8ad91996-07-24 00:51:20 +000016#include "Python.h"
Guido van Rossum4f199ea1998-04-09 20:56:35 +000017#ifdef WITH_THREAD
Guido van Rossum49b56061998-10-01 20:42:43 +000018#include "pythread.h"
Guido van Rossum4f199ea1998-04-09 20:56:35 +000019#endif
Guido van Rossum1100dca1995-08-30 23:43:03 +000020
21#include <sys/types.h>
22#include <sys/stat.h>
23#include <fcntl.h>
Fred Drakec9cb8472000-08-31 16:11:07 +000024#ifdef HAVE_DB_185_H
25#include <db_185.h>
26#else
Guido van Rossum1100dca1995-08-30 23:43:03 +000027#include <db.h>
Fred Drakec9cb8472000-08-31 16:11:07 +000028#endif
Guido van Rossum1100dca1995-08-30 23:43:03 +000029/* Please don't include internal header files of the Berkeley db package
30 (it messes up the info required in the Setup file) */
31
32typedef struct {
Roger E. Massed9240d11997-01-16 22:05:33 +000033 PyObject_HEAD
34 DB *di_bsddb;
35 int di_size; /* -1 means recompute */
Guido van Rossum4f199ea1998-04-09 20:56:35 +000036#ifdef WITH_THREAD
Guido van Rossum65d5b571998-12-21 19:32:43 +000037 PyThread_type_lock di_lock;
Guido van Rossum4f199ea1998-04-09 20:56:35 +000038#endif
Guido van Rossum1100dca1995-08-30 23:43:03 +000039} bsddbobject;
40
Guido van Rossumdfe8ad91996-07-24 00:51:20 +000041staticforward PyTypeObject Bsddbtype;
Guido van Rossum1100dca1995-08-30 23:43:03 +000042
43#define is_bsddbobject(v) ((v)->ob_type == &Bsddbtype)
Guido van Rossum77eecfa1997-07-17 22:56:01 +000044#define check_bsddbobject_open(v) if ((v)->di_bsddb == NULL) \
45 { PyErr_SetString(BsddbError, "BSDDB object has already been closed"); \
46 return NULL; }
Guido van Rossum1100dca1995-08-30 23:43:03 +000047
Guido van Rossumdfe8ad91996-07-24 00:51:20 +000048static PyObject *BsddbError;
Guido van Rossum1100dca1995-08-30 23:43:03 +000049
Guido van Rossumdfe8ad91996-07-24 00:51:20 +000050static PyObject *
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +000051newdbhashobject(char *file, int flags, int mode,
52 int bsize, int ffactor, int nelem, int cachesize, int hash, int lorder)
Guido van Rossum1100dca1995-08-30 23:43:03 +000053{
Roger E. Massed9240d11997-01-16 22:05:33 +000054 bsddbobject *dp;
55 HASHINFO info;
Guido van Rossum1100dca1995-08-30 23:43:03 +000056
Guido van Rossumb18618d2000-05-03 23:44:39 +000057 if ((dp = PyObject_New(bsddbobject, &Bsddbtype)) == NULL)
Roger E. Massed9240d11997-01-16 22:05:33 +000058 return NULL;
Guido van Rossum1100dca1995-08-30 23:43:03 +000059
Roger E. Massed9240d11997-01-16 22:05:33 +000060 info.bsize = bsize;
61 info.ffactor = ffactor;
62 info.nelem = nelem;
63 info.cachesize = cachesize;
64 info.hash = NULL; /* XXX should derive from hash argument */
65 info.lorder = lorder;
Guido van Rossum1100dca1995-08-30 23:43:03 +000066
Guido van Rossum6beb4791996-09-11 23:22:25 +000067#ifdef O_BINARY
Roger E. Massed9240d11997-01-16 22:05:33 +000068 flags |= O_BINARY;
Guido van Rossum6beb4791996-09-11 23:22:25 +000069#endif
Guido van Rossum4f199ea1998-04-09 20:56:35 +000070 Py_BEGIN_ALLOW_THREADS
71 dp->di_bsddb = dbopen(file, flags, mode, DB_HASH, &info);
72 Py_END_ALLOW_THREADS
73 if (dp->di_bsddb == NULL) {
Roger E. Massed9240d11997-01-16 22:05:33 +000074 PyErr_SetFromErrno(BsddbError);
Guido van Rossum4f199ea1998-04-09 20:56:35 +000075#ifdef WITH_THREAD
76 dp->di_lock = NULL;
77#endif
Roger E. Massed9240d11997-01-16 22:05:33 +000078 Py_DECREF(dp);
79 return NULL;
80 }
Guido van Rossum1100dca1995-08-30 23:43:03 +000081
Roger E. Massed9240d11997-01-16 22:05:33 +000082 dp->di_size = -1;
Guido van Rossum4f199ea1998-04-09 20:56:35 +000083#ifdef WITH_THREAD
Guido van Rossum65d5b571998-12-21 19:32:43 +000084 dp->di_lock = PyThread_allocate_lock();
Guido van Rossum4f199ea1998-04-09 20:56:35 +000085 if (dp->di_lock == NULL) {
86 PyErr_SetString(BsddbError, "can't allocate lock");
87 Py_DECREF(dp);
88 return NULL;
89 }
90#endif
Guido van Rossum1100dca1995-08-30 23:43:03 +000091
Roger E. Massed9240d11997-01-16 22:05:33 +000092 return (PyObject *)dp;
Guido van Rossum1100dca1995-08-30 23:43:03 +000093}
94
Guido van Rossumdfe8ad91996-07-24 00:51:20 +000095static PyObject *
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +000096newdbbtobject(char *file, int flags, int mode,
97 int btflags, int cachesize, int maxkeypage, int minkeypage, int psize, int lorder)
Guido van Rossum1100dca1995-08-30 23:43:03 +000098{
Roger E. Massed9240d11997-01-16 22:05:33 +000099 bsddbobject *dp;
100 BTREEINFO info;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000101
Guido van Rossumb18618d2000-05-03 23:44:39 +0000102 if ((dp = PyObject_New(bsddbobject, &Bsddbtype)) == NULL)
Roger E. Massed9240d11997-01-16 22:05:33 +0000103 return NULL;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000104
Roger E. Massed9240d11997-01-16 22:05:33 +0000105 info.flags = btflags;
106 info.cachesize = cachesize;
107 info.maxkeypage = maxkeypage;
108 info.minkeypage = minkeypage;
109 info.psize = psize;
110 info.lorder = lorder;
111 info.compare = 0; /* Use default comparison functions, for now..*/
112 info.prefix = 0;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000113
Guido van Rossum6beb4791996-09-11 23:22:25 +0000114#ifdef O_BINARY
Roger E. Massed9240d11997-01-16 22:05:33 +0000115 flags |= O_BINARY;
Guido van Rossum6beb4791996-09-11 23:22:25 +0000116#endif
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000117 Py_BEGIN_ALLOW_THREADS
118 dp->di_bsddb = dbopen(file, flags, mode, DB_BTREE, &info);
119 Py_END_ALLOW_THREADS
120 if (dp->di_bsddb == NULL) {
Roger E. Massed9240d11997-01-16 22:05:33 +0000121 PyErr_SetFromErrno(BsddbError);
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000122#ifdef WITH_THREAD
123 dp->di_lock = NULL;
124#endif
Roger E. Massed9240d11997-01-16 22:05:33 +0000125 Py_DECREF(dp);
126 return NULL;
127 }
Guido van Rossum1100dca1995-08-30 23:43:03 +0000128
Roger E. Massed9240d11997-01-16 22:05:33 +0000129 dp->di_size = -1;
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000130#ifdef WITH_THREAD
Guido van Rossum65d5b571998-12-21 19:32:43 +0000131 dp->di_lock = PyThread_allocate_lock();
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000132 if (dp->di_lock == NULL) {
133 PyErr_SetString(BsddbError, "can't allocate lock");
134 Py_DECREF(dp);
135 return NULL;
136 }
137#endif
Guido van Rossum1100dca1995-08-30 23:43:03 +0000138
Roger E. Massed9240d11997-01-16 22:05:33 +0000139 return (PyObject *)dp;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000140}
141
Guido van Rossumdfe8ad91996-07-24 00:51:20 +0000142static PyObject *
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +0000143newdbrnobject(char *file, int flags, int mode,
144 int rnflags, int cachesize, int psize, int lorder, size_t reclen, u_char bval, char *bfname)
Guido van Rossum1100dca1995-08-30 23:43:03 +0000145{
Roger E. Massed9240d11997-01-16 22:05:33 +0000146 bsddbobject *dp;
147 RECNOINFO info;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000148
Guido van Rossumb18618d2000-05-03 23:44:39 +0000149 if ((dp = PyObject_New(bsddbobject, &Bsddbtype)) == NULL)
Roger E. Massed9240d11997-01-16 22:05:33 +0000150 return NULL;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000151
Roger E. Massed9240d11997-01-16 22:05:33 +0000152 info.flags = rnflags;
153 info.cachesize = cachesize;
154 info.psize = psize;
155 info.lorder = lorder;
156 info.reclen = reclen;
157 info.bval = bval;
158 info.bfname = bfname;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000159
Guido van Rossum6beb4791996-09-11 23:22:25 +0000160#ifdef O_BINARY
Roger E. Massed9240d11997-01-16 22:05:33 +0000161 flags |= O_BINARY;
Guido van Rossum6beb4791996-09-11 23:22:25 +0000162#endif
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000163 Py_BEGIN_ALLOW_THREADS
164 dp->di_bsddb = dbopen(file, flags, mode, DB_RECNO, &info);
165 Py_END_ALLOW_THREADS
166 if (dp->di_bsddb == NULL) {
Roger E. Massed9240d11997-01-16 22:05:33 +0000167 PyErr_SetFromErrno(BsddbError);
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000168#ifdef WITH_THREAD
169 dp->di_lock = NULL;
170#endif
Roger E. Massed9240d11997-01-16 22:05:33 +0000171 Py_DECREF(dp);
172 return NULL;
173 }
Guido van Rossum1100dca1995-08-30 23:43:03 +0000174
Roger E. Massed9240d11997-01-16 22:05:33 +0000175 dp->di_size = -1;
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000176#ifdef WITH_THREAD
Guido van Rossum65d5b571998-12-21 19:32:43 +0000177 dp->di_lock = PyThread_allocate_lock();
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000178 if (dp->di_lock == NULL) {
179 PyErr_SetString(BsddbError, "can't allocate lock");
180 Py_DECREF(dp);
181 return NULL;
182 }
183#endif
Guido van Rossum1100dca1995-08-30 23:43:03 +0000184
Roger E. Massed9240d11997-01-16 22:05:33 +0000185 return (PyObject *)dp;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000186}
187
Guido van Rossum1100dca1995-08-30 23:43:03 +0000188static void
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +0000189bsddb_dealloc(bsddbobject *dp)
Guido van Rossum1100dca1995-08-30 23:43:03 +0000190{
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000191#ifdef WITH_THREAD
192 if (dp->di_lock) {
Guido van Rossum65d5b571998-12-21 19:32:43 +0000193 PyThread_acquire_lock(dp->di_lock, 0);
194 PyThread_release_lock(dp->di_lock);
195 PyThread_free_lock(dp->di_lock);
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000196 dp->di_lock = NULL;
197 }
198#endif
Roger E. Massed9240d11997-01-16 22:05:33 +0000199 if (dp->di_bsddb != NULL) {
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000200 int status;
201 Py_BEGIN_ALLOW_THREADS
202 status = (dp->di_bsddb->close)(dp->di_bsddb);
203 Py_END_ALLOW_THREADS
204 if (status != 0)
Roger E. Massed9240d11997-01-16 22:05:33 +0000205 fprintf(stderr,
206 "Python bsddb: close errno %d in dealloc\n",
207 errno);
208 }
Guido van Rossumb18618d2000-05-03 23:44:39 +0000209 PyObject_Del(dp);
Guido van Rossum1100dca1995-08-30 23:43:03 +0000210}
211
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000212#ifdef WITH_THREAD
Guido van Rossum65d5b571998-12-21 19:32:43 +0000213#define BSDDB_BGN_SAVE(_dp) Py_BEGIN_ALLOW_THREADS PyThread_acquire_lock(_dp->di_lock,1);
214#define BSDDB_END_SAVE(_dp) PyThread_release_lock(_dp->di_lock); Py_END_ALLOW_THREADS
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000215#else
216#define BSDDB_BGN_SAVE(_dp) Py_BEGIN_ALLOW_THREADS
217#define BSDDB_END_SAVE(_dp) Py_END_ALLOW_THREADS
218#endif
219
Guido van Rossum1100dca1995-08-30 23:43:03 +0000220static int
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +0000221bsddb_length(bsddbobject *dp)
Guido van Rossum1100dca1995-08-30 23:43:03 +0000222{
Guido van Rossum77eecfa1997-07-17 22:56:01 +0000223 if (dp->di_bsddb == NULL) {
224 PyErr_SetString(BsddbError, "BSDDB object has already been closed");
225 return -1;
226 }
Roger E. Massed9240d11997-01-16 22:05:33 +0000227 if (dp->di_size < 0) {
228 DBT krec, drec;
229 int status;
230 int size = 0;
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000231 BSDDB_BGN_SAVE(dp)
Roger E. Massed9240d11997-01-16 22:05:33 +0000232 for (status = (dp->di_bsddb->seq)(dp->di_bsddb,
233 &krec, &drec,R_FIRST);
234 status == 0;
235 status = (dp->di_bsddb->seq)(dp->di_bsddb,
236 &krec, &drec, R_NEXT))
237 size++;
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000238 BSDDB_END_SAVE(dp)
Roger E. Massed9240d11997-01-16 22:05:33 +0000239 if (status < 0) {
240 PyErr_SetFromErrno(BsddbError);
241 return -1;
242 }
243 dp->di_size = size;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000244 }
Roger E. Massed9240d11997-01-16 22:05:33 +0000245 return dp->di_size;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000246}
247
Guido van Rossumdfe8ad91996-07-24 00:51:20 +0000248static PyObject *
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +0000249bsddb_subscript(bsddbobject *dp, PyObject *key)
Guido van Rossum1100dca1995-08-30 23:43:03 +0000250{
Roger E. Massed9240d11997-01-16 22:05:33 +0000251 int status;
252 DBT krec, drec;
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000253 char *data,buf[4096];
Roger E. Massed9240d11997-01-16 22:05:33 +0000254 int size;
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000255 PyObject *result;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000256
Roger E. Massed9240d11997-01-16 22:05:33 +0000257 if (!PyArg_Parse(key, "s#", &data, &size))
258 return NULL;
Guido van Rossum77eecfa1997-07-17 22:56:01 +0000259 check_bsddbobject_open(dp);
260
Roger E. Massed9240d11997-01-16 22:05:33 +0000261 krec.data = data;
262 krec.size = size;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000263
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000264 BSDDB_BGN_SAVE(dp)
Roger E. Massed9240d11997-01-16 22:05:33 +0000265 status = (dp->di_bsddb->get)(dp->di_bsddb, &krec, &drec, 0);
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000266 if (status == 0) {
267 if (drec.size > sizeof(buf)) data = malloc(drec.size);
268 else data = buf;
269 memcpy(data,drec.data,drec.size);
270 }
271 BSDDB_END_SAVE(dp)
Roger E. Massed9240d11997-01-16 22:05:33 +0000272 if (status != 0) {
273 if (status < 0)
274 PyErr_SetFromErrno(BsddbError);
275 else
276 PyErr_SetObject(PyExc_KeyError, key);
277 return NULL;
278 }
Guido van Rossum1100dca1995-08-30 23:43:03 +0000279
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000280 result = PyString_FromStringAndSize(data, (int)drec.size);
281 if (data != buf) free(data);
282 return result;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000283}
284
285static int
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +0000286bsddb_ass_sub(bsddbobject *dp, PyObject *key, PyObject *value)
Guido van Rossum1100dca1995-08-30 23:43:03 +0000287{
Roger E. Massed9240d11997-01-16 22:05:33 +0000288 int status;
289 DBT krec, drec;
290 char *data;
291 int size;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000292
Roger E. Massed9240d11997-01-16 22:05:33 +0000293 if (!PyArg_Parse(key, "s#", &data, &size)) {
294 PyErr_SetString(PyExc_TypeError,
295 "bsddb key type must be string");
296 return -1;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000297 }
Guido van Rossum77eecfa1997-07-17 22:56:01 +0000298 if (dp->di_bsddb == NULL) {
299 PyErr_SetString(BsddbError, "BSDDB object has already been closed");
300 return -1;
301 }
Roger E. Massed9240d11997-01-16 22:05:33 +0000302 krec.data = data;
303 krec.size = size;
304 dp->di_size = -1;
305 if (value == NULL) {
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000306 BSDDB_BGN_SAVE(dp)
Roger E. Massed9240d11997-01-16 22:05:33 +0000307 status = (dp->di_bsddb->del)(dp->di_bsddb, &krec, 0);
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000308 BSDDB_END_SAVE(dp)
Roger E. Massed9240d11997-01-16 22:05:33 +0000309 }
310 else {
311 if (!PyArg_Parse(value, "s#", &data, &size)) {
312 PyErr_SetString(PyExc_TypeError,
313 "bsddb value type must be string");
314 return -1;
315 }
316 drec.data = data;
317 drec.size = size;
318#if 0
319 /* For RECNO, put fails with 'No space left on device'
320 after a few short records are added?? Looks fine
321 to this point... linked with 1.85 on Solaris Intel
322 Roger E. Masse 1/16/97
323 */
324 printf("before put data: '%s', size: %d\n",
325 drec.data, drec.size);
326 printf("before put key= '%s', size= %d\n",
327 krec.data, krec.size);
328#endif
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000329 BSDDB_BGN_SAVE(dp)
Roger E. Massed9240d11997-01-16 22:05:33 +0000330 status = (dp->di_bsddb->put)(dp->di_bsddb, &krec, &drec, 0);
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000331 BSDDB_END_SAVE(dp)
Roger E. Massed9240d11997-01-16 22:05:33 +0000332 }
333 if (status != 0) {
334 if (status < 0)
335 PyErr_SetFromErrno(BsddbError);
336 else
337 PyErr_SetObject(PyExc_KeyError, key);
338 return -1;
339 }
340 return 0;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000341}
342
Guido van Rossumdfe8ad91996-07-24 00:51:20 +0000343static PyMappingMethods bsddb_as_mapping = {
Roger E. Massed9240d11997-01-16 22:05:33 +0000344 (inquiry)bsddb_length, /*mp_length*/
345 (binaryfunc)bsddb_subscript, /*mp_subscript*/
346 (objobjargproc)bsddb_ass_sub, /*mp_ass_subscript*/
Guido van Rossum1100dca1995-08-30 23:43:03 +0000347};
348
Guido van Rossumdfe8ad91996-07-24 00:51:20 +0000349static PyObject *
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +0000350bsddb_close(bsddbobject *dp, PyObject *args)
Guido van Rossum1100dca1995-08-30 23:43:03 +0000351{
Roger E. Massed9240d11997-01-16 22:05:33 +0000352 if (!PyArg_NoArgs(args))
353 return NULL;
354 if (dp->di_bsddb != NULL) {
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000355 int status;
356 BSDDB_BGN_SAVE(dp)
357 status = (dp->di_bsddb->close)(dp->di_bsddb);
358 BSDDB_END_SAVE(dp)
359 if (status != 0) {
Roger E. Massed9240d11997-01-16 22:05:33 +0000360 dp->di_bsddb = NULL;
361 PyErr_SetFromErrno(BsddbError);
362 return NULL;
363 }
Guido van Rossum1100dca1995-08-30 23:43:03 +0000364 }
Roger E. Massed9240d11997-01-16 22:05:33 +0000365 dp->di_bsddb = NULL;
366 Py_INCREF(Py_None);
367 return Py_None;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000368}
369
Guido van Rossumdfe8ad91996-07-24 00:51:20 +0000370static PyObject *
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +0000371bsddb_keys(bsddbobject *dp, PyObject *args)
Guido van Rossum1100dca1995-08-30 23:43:03 +0000372{
Roger E. Massed9240d11997-01-16 22:05:33 +0000373 PyObject *list, *item;
374 DBT krec, drec;
Guido van Rossum730806d1998-04-10 22:27:42 +0000375 char *data=NULL,buf[4096];
Roger E. Massed9240d11997-01-16 22:05:33 +0000376 int status;
377 int err;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000378
Roger E. Massed9240d11997-01-16 22:05:33 +0000379 if (!PyArg_NoArgs(args))
380 return NULL;
Guido van Rossum77eecfa1997-07-17 22:56:01 +0000381 check_bsddbobject_open(dp);
Roger E. Massed9240d11997-01-16 22:05:33 +0000382 list = PyList_New(0);
383 if (list == NULL)
384 return NULL;
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000385 BSDDB_BGN_SAVE(dp)
386 status = (dp->di_bsddb->seq)(dp->di_bsddb, &krec, &drec, R_FIRST);
387 if (status == 0) {
388 if (krec.size > sizeof(buf)) data = malloc(krec.size);
389 else data = buf;
390 memcpy(data,krec.data,krec.size);
391 }
392 BSDDB_END_SAVE(dp)
393 while (status == 0) {
394 item = PyString_FromStringAndSize(data, (int)krec.size);
395 if (data != buf) free(data);
Roger E. Massed9240d11997-01-16 22:05:33 +0000396 if (item == NULL) {
397 Py_DECREF(list);
398 return NULL;
399 }
400 err = PyList_Append(list, item);
401 Py_DECREF(item);
402 if (err != 0) {
403 Py_DECREF(list);
404 return NULL;
405 }
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000406 BSDDB_BGN_SAVE(dp)
407 status = (dp->di_bsddb->seq)(dp->di_bsddb, &krec, &drec, R_NEXT);
408 if (status == 0) {
409 if (krec.size > sizeof(buf)) data = malloc(krec.size);
410 else data = buf;
411 memcpy(data,krec.data,krec.size);
412 }
413 BSDDB_END_SAVE(dp)
Guido van Rossum1100dca1995-08-30 23:43:03 +0000414 }
Roger E. Massed9240d11997-01-16 22:05:33 +0000415 if (status < 0) {
416 PyErr_SetFromErrno(BsddbError);
417 Py_DECREF(list);
418 return NULL;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000419 }
Roger E. Massed9240d11997-01-16 22:05:33 +0000420 if (dp->di_size < 0)
421 dp->di_size = PyList_Size(list); /* We just did the work */
422 return list;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000423}
424
Guido van Rossumdfe8ad91996-07-24 00:51:20 +0000425static PyObject *
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +0000426bsddb_has_key(bsddbobject *dp, PyObject *args)
Guido van Rossum1100dca1995-08-30 23:43:03 +0000427{
Roger E. Massed9240d11997-01-16 22:05:33 +0000428 DBT krec, drec;
429 int status;
430 char *data;
431 int size;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000432
Roger E. Massed9240d11997-01-16 22:05:33 +0000433 if (!PyArg_Parse(args, "s#", &data, &size))
434 return NULL;
Guido van Rossum77eecfa1997-07-17 22:56:01 +0000435 check_bsddbobject_open(dp);
Roger E. Massed9240d11997-01-16 22:05:33 +0000436 krec.data = data;
437 krec.size = size;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000438
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000439 BSDDB_BGN_SAVE(dp)
Roger E. Massed9240d11997-01-16 22:05:33 +0000440 status = (dp->di_bsddb->get)(dp->di_bsddb, &krec, &drec, 0);
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000441 BSDDB_END_SAVE(dp)
Roger E. Massed9240d11997-01-16 22:05:33 +0000442 if (status < 0) {
443 PyErr_SetFromErrno(BsddbError);
444 return NULL;
445 }
Guido van Rossum1100dca1995-08-30 23:43:03 +0000446
Roger E. Massed9240d11997-01-16 22:05:33 +0000447 return PyInt_FromLong(status == 0);
Guido van Rossum1100dca1995-08-30 23:43:03 +0000448}
449
Guido van Rossumdfe8ad91996-07-24 00:51:20 +0000450static PyObject *
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +0000451bsddb_set_location(bsddbobject *dp, PyObject *key)
Guido van Rossum1100dca1995-08-30 23:43:03 +0000452{
Roger E. Massed9240d11997-01-16 22:05:33 +0000453 int status;
454 DBT krec, drec;
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000455 char *data,buf[4096];
Roger E. Massed9240d11997-01-16 22:05:33 +0000456 int size;
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000457 PyObject *result;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000458
Roger E. Massed9240d11997-01-16 22:05:33 +0000459 if (!PyArg_Parse(key, "s#", &data, &size))
460 return NULL;
Guido van Rossum77eecfa1997-07-17 22:56:01 +0000461 check_bsddbobject_open(dp);
Roger E. Massed9240d11997-01-16 22:05:33 +0000462 krec.data = data;
463 krec.size = size;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000464
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000465 BSDDB_BGN_SAVE(dp)
Roger E. Massed9240d11997-01-16 22:05:33 +0000466 status = (dp->di_bsddb->seq)(dp->di_bsddb, &krec, &drec, R_CURSOR);
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000467 if (status == 0) {
468 if (drec.size > sizeof(buf)) data = malloc(drec.size);
469 else data = buf;
470 memcpy(data,drec.data,drec.size);
471 }
472 BSDDB_END_SAVE(dp)
Roger E. Massed9240d11997-01-16 22:05:33 +0000473 if (status != 0) {
474 if (status < 0)
475 PyErr_SetFromErrno(BsddbError);
476 else
477 PyErr_SetObject(PyExc_KeyError, key);
478 return NULL;
479 }
Guido van Rossum1100dca1995-08-30 23:43:03 +0000480
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000481 result = Py_BuildValue("s#s#", krec.data, krec.size, data, drec.size);
482 if (data != buf) free(data);
483 return result;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000484}
485
Guido van Rossumdfe8ad91996-07-24 00:51:20 +0000486static PyObject *
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +0000487bsddb_seq(bsddbobject *dp, PyObject *args, int sequence_request)
Guido van Rossum1100dca1995-08-30 23:43:03 +0000488{
Roger E. Massed9240d11997-01-16 22:05:33 +0000489 int status;
490 DBT krec, drec;
Guido van Rossum730806d1998-04-10 22:27:42 +0000491 char *kdata=NULL,kbuf[4096];
492 char *ddata=NULL,dbuf[4096];
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000493 PyObject *result;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000494
Roger E. Massed9240d11997-01-16 22:05:33 +0000495 if (!PyArg_NoArgs(args))
496 return NULL;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000497
Guido van Rossum77eecfa1997-07-17 22:56:01 +0000498 check_bsddbobject_open(dp);
Roger E. Massed9240d11997-01-16 22:05:33 +0000499 krec.data = 0;
500 krec.size = 0;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000501
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000502 BSDDB_BGN_SAVE(dp)
Roger E. Massed9240d11997-01-16 22:05:33 +0000503 status = (dp->di_bsddb->seq)(dp->di_bsddb, &krec,
504 &drec, sequence_request);
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000505 if (status == 0) {
506 if (krec.size > sizeof(kbuf)) kdata = malloc(krec.size);
507 else kdata = kbuf;
508 memcpy(kdata,krec.data,krec.size);
509 if (drec.size > sizeof(dbuf)) ddata = malloc(drec.size);
510 else ddata = dbuf;
511 memcpy(ddata,drec.data,drec.size);
512 }
513 BSDDB_END_SAVE(dp)
Roger E. Massed9240d11997-01-16 22:05:33 +0000514 if (status != 0) {
515 if (status < 0)
516 PyErr_SetFromErrno(BsddbError);
517 else
518 PyErr_SetObject(PyExc_KeyError, args);
519 return NULL;
520 }
Guido van Rossum1100dca1995-08-30 23:43:03 +0000521
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000522 result = Py_BuildValue("s#s#", kdata, krec.size, ddata, drec.size);
523 if (kdata != kbuf) free(kdata);
524 if (ddata != dbuf) free(ddata);
525 return result;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000526}
527
Guido van Rossumdfe8ad91996-07-24 00:51:20 +0000528static PyObject *
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +0000529bsddb_next(bsddbobject *dp, PyObject *key)
Guido van Rossum1100dca1995-08-30 23:43:03 +0000530{
Roger E. Massed9240d11997-01-16 22:05:33 +0000531 return bsddb_seq(dp, key, R_NEXT);
Guido van Rossum1100dca1995-08-30 23:43:03 +0000532}
Guido van Rossumdfe8ad91996-07-24 00:51:20 +0000533static PyObject *
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +0000534bsddb_previous(bsddbobject *dp, PyObject *key)
Guido van Rossum1100dca1995-08-30 23:43:03 +0000535{
Roger E. Massed9240d11997-01-16 22:05:33 +0000536 return bsddb_seq(dp, key, R_PREV);
Guido van Rossum1100dca1995-08-30 23:43:03 +0000537}
Guido van Rossumdfe8ad91996-07-24 00:51:20 +0000538static PyObject *
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +0000539bsddb_first(bsddbobject *dp, PyObject *key)
Guido van Rossum1100dca1995-08-30 23:43:03 +0000540{
Roger E. Massed9240d11997-01-16 22:05:33 +0000541 return bsddb_seq(dp, key, R_FIRST);
Guido van Rossum1100dca1995-08-30 23:43:03 +0000542}
Guido van Rossumdfe8ad91996-07-24 00:51:20 +0000543static PyObject *
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +0000544bsddb_last(bsddbobject *dp, PyObject *key)
Guido van Rossum1100dca1995-08-30 23:43:03 +0000545{
Roger E. Massed9240d11997-01-16 22:05:33 +0000546 return bsddb_seq(dp, key, R_LAST);
Guido van Rossum1100dca1995-08-30 23:43:03 +0000547}
Guido van Rossumdfe8ad91996-07-24 00:51:20 +0000548static PyObject *
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +0000549bsddb_sync(bsddbobject *dp, PyObject *args)
Guido van Rossum1100dca1995-08-30 23:43:03 +0000550{
Roger E. Massed9240d11997-01-16 22:05:33 +0000551 int status;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000552
Guido van Rossum77eecfa1997-07-17 22:56:01 +0000553 if (!PyArg_NoArgs(args))
554 return NULL;
555 check_bsddbobject_open(dp);
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000556 BSDDB_BGN_SAVE(dp)
Roger E. Massed9240d11997-01-16 22:05:33 +0000557 status = (dp->di_bsddb->sync)(dp->di_bsddb, 0);
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000558 BSDDB_END_SAVE(dp)
Roger E. Massed9240d11997-01-16 22:05:33 +0000559 if (status != 0) {
560 PyErr_SetFromErrno(BsddbError);
561 return NULL;
562 }
563 return PyInt_FromLong(status = 0);
Guido van Rossum1100dca1995-08-30 23:43:03 +0000564}
Guido van Rossumdfe8ad91996-07-24 00:51:20 +0000565static PyMethodDef bsddb_methods[] = {
Roger E. Massed9240d11997-01-16 22:05:33 +0000566 {"close", (PyCFunction)bsddb_close},
567 {"keys", (PyCFunction)bsddb_keys},
568 {"has_key", (PyCFunction)bsddb_has_key},
569 {"set_location", (PyCFunction)bsddb_set_location},
570 {"next", (PyCFunction)bsddb_next},
571 {"previous", (PyCFunction)bsddb_previous},
572 {"first", (PyCFunction)bsddb_first},
573 {"last", (PyCFunction)bsddb_last},
574 {"sync", (PyCFunction)bsddb_sync},
575 {NULL, NULL} /* sentinel */
Guido van Rossum1100dca1995-08-30 23:43:03 +0000576};
577
Guido van Rossumdfe8ad91996-07-24 00:51:20 +0000578static PyObject *
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +0000579bsddb_getattr(PyObject *dp, char *name)
Guido van Rossum1100dca1995-08-30 23:43:03 +0000580{
Roger E. Massed9240d11997-01-16 22:05:33 +0000581 return Py_FindMethod(bsddb_methods, dp, name);
Guido van Rossum1100dca1995-08-30 23:43:03 +0000582}
583
Guido van Rossumdfe8ad91996-07-24 00:51:20 +0000584static PyTypeObject Bsddbtype = {
Roger E. Massed9240d11997-01-16 22:05:33 +0000585 PyObject_HEAD_INIT(NULL)
586 0,
587 "bsddb",
588 sizeof(bsddbobject),
589 0,
590 (destructor)bsddb_dealloc, /*tp_dealloc*/
591 0, /*tp_print*/
592 (getattrfunc)bsddb_getattr, /*tp_getattr*/
593 0, /*tp_setattr*/
594 0, /*tp_compare*/
595 0, /*tp_repr*/
596 0, /*tp_as_number*/
597 0, /*tp_as_sequence*/
598 &bsddb_as_mapping, /*tp_as_mapping*/
Guido van Rossum1100dca1995-08-30 23:43:03 +0000599};
600
Guido van Rossumdfe8ad91996-07-24 00:51:20 +0000601static PyObject *
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +0000602bsdhashopen(PyObject *self, PyObject *args)
Guido van Rossum1100dca1995-08-30 23:43:03 +0000603{
Roger E. Massed9240d11997-01-16 22:05:33 +0000604 char *file;
605 char *flag = NULL;
606 int flags = O_RDONLY;
607 int mode = 0666;
608 int bsize = 0;
609 int ffactor = 0;
610 int nelem = 0;
611 int cachesize = 0;
612 int hash = 0; /* XXX currently ignored */
613 int lorder = 0;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000614
Guido van Rossum43713e52000-02-29 13:59:29 +0000615 if (!PyArg_ParseTuple(args, "s|siiiiiii:hashopen",
Roger E. Massed9240d11997-01-16 22:05:33 +0000616 &file, &flag, &mode,
617 &bsize, &ffactor, &nelem, &cachesize,
618 &hash, &lorder))
619 return NULL;
620 if (flag != NULL) {
621 /* XXX need to pass O_EXCL, O_EXLOCK, O_NONBLOCK, O_SHLOCK */
622 if (flag[0] == 'r')
623 flags = O_RDONLY;
624 else if (flag[0] == 'w')
625 flags = O_RDWR;
626 else if (flag[0] == 'c')
627 flags = O_RDWR|O_CREAT;
628 else if (flag[0] == 'n')
629 flags = O_RDWR|O_CREAT|O_TRUNC;
630 else {
631 PyErr_SetString(BsddbError,
632 "Flag should begin with 'r', 'w', 'c' or 'n'");
633 return NULL;
634 }
635 if (flag[1] == 'l') {
Guido van Rossum1100dca1995-08-30 23:43:03 +0000636#if defined(O_EXLOCK) && defined(O_SHLOCK)
Roger E. Massed9240d11997-01-16 22:05:33 +0000637 if (flag[0] == 'r')
638 flags |= O_SHLOCK;
639 else
640 flags |= O_EXLOCK;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000641#else
Roger E. Massed9240d11997-01-16 22:05:33 +0000642 PyErr_SetString(BsddbError,
643 "locking not supported on this platform");
644 return NULL;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000645#endif
Roger E. Massed9240d11997-01-16 22:05:33 +0000646 }
Guido van Rossum1100dca1995-08-30 23:43:03 +0000647 }
Roger E. Massed9240d11997-01-16 22:05:33 +0000648 return newdbhashobject(file, flags, mode,
649 bsize, ffactor, nelem, cachesize, hash, lorder);
Guido van Rossum1100dca1995-08-30 23:43:03 +0000650}
651
Guido van Rossumdfe8ad91996-07-24 00:51:20 +0000652static PyObject *
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +0000653bsdbtopen(PyObject *self, PyObject *args)
Guido van Rossum1100dca1995-08-30 23:43:03 +0000654{
Roger E. Massed9240d11997-01-16 22:05:33 +0000655 char *file;
656 char *flag = NULL;
657 int flags = O_RDONLY;
658 int mode = 0666;
659 int cachesize = 0;
660 int maxkeypage = 0;
661 int minkeypage = 0;
662 int btflags = 0;
663 unsigned int psize = 0;
664 int lorder = 0;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000665
Guido van Rossum43713e52000-02-29 13:59:29 +0000666 if (!PyArg_ParseTuple(args, "s|siiiiiii:btopen",
Roger E. Massed9240d11997-01-16 22:05:33 +0000667 &file, &flag, &mode,
668 &btflags, &cachesize, &maxkeypage, &minkeypage,
669 &psize, &lorder))
670 return NULL;
671 if (flag != NULL) {
672 /* XXX need to pass O_EXCL, O_EXLOCK, O_NONBLOCK, O_SHLOCK */
673 if (flag[0] == 'r')
674 flags = O_RDONLY;
675 else if (flag[0] == 'w')
676 flags = O_RDWR;
677 else if (flag[0] == 'c')
678 flags = O_RDWR|O_CREAT;
679 else if (flag[0] == 'n')
680 flags = O_RDWR|O_CREAT|O_TRUNC;
681 else {
682 PyErr_SetString(BsddbError,
683 "Flag should begin with 'r', 'w', 'c' or 'n'");
684 return NULL;
685 }
686 if (flag[1] == 'l') {
Guido van Rossum1100dca1995-08-30 23:43:03 +0000687#if defined(O_EXLOCK) && defined(O_SHLOCK)
Roger E. Massed9240d11997-01-16 22:05:33 +0000688 if (flag[0] == 'r')
689 flags |= O_SHLOCK;
690 else
691 flags |= O_EXLOCK;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000692#else
Roger E. Massed9240d11997-01-16 22:05:33 +0000693 PyErr_SetString(BsddbError,
694 "locking not supported on this platform");
695 return NULL;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000696#endif
Roger E. Massed9240d11997-01-16 22:05:33 +0000697 }
Guido van Rossum1100dca1995-08-30 23:43:03 +0000698 }
Roger E. Massed9240d11997-01-16 22:05:33 +0000699 return newdbbtobject(file, flags, mode,
700 btflags, cachesize, maxkeypage, minkeypage,
701 psize, lorder);
Guido van Rossum1100dca1995-08-30 23:43:03 +0000702}
Guido van Rossumdd96ca71996-05-23 22:57:54 +0000703
Guido van Rossumdfe8ad91996-07-24 00:51:20 +0000704static PyObject *
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +0000705bsdrnopen(PyObject *self, PyObject *args)
Guido van Rossum1100dca1995-08-30 23:43:03 +0000706{
Roger E. Massed9240d11997-01-16 22:05:33 +0000707 char *file;
708 char *flag = NULL;
709 int flags = O_RDONLY;
710 int mode = 0666;
711 int cachesize = 0;
712 int rnflags = 0;
713 unsigned int psize = 0;
714 int lorder = 0;
715 size_t reclen = 0;
716 char *bval = "";
717 char *bfname = NULL;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000718
Guido van Rossum43713e52000-02-29 13:59:29 +0000719 if (!PyArg_ParseTuple(args, "s|siiiiiiss:rnopen",
Roger E. Massed9240d11997-01-16 22:05:33 +0000720 &file, &flag, &mode,
721 &rnflags, &cachesize, &psize, &lorder,
722 &reclen, &bval, &bfname))
723 return NULL;
724
725# if 0
726 printf("file: %s\n", file);
727 printf("flag: %s\n", flag);
728 printf("mode: %d\n", mode);
729 printf("rnflags: 0x%x\n", rnflags);
730 printf("cachesize: %d\n", cachesize);
731 printf("psize: %d\n", psize);
732 printf("lorder: %d\n", 0);
733 printf("reclen: %d\n", reclen);
734 printf("bval: %c\n", bval[0]);
735 printf("bfname %s\n", bfname);
Guido van Rossum1100dca1995-08-30 23:43:03 +0000736#endif
Roger E. Massed9240d11997-01-16 22:05:33 +0000737
738 if (flag != NULL) {
739 /* XXX need to pass O_EXCL, O_EXLOCK, O_NONBLOCK, O_SHLOCK */
740 if (flag[0] == 'r')
741 flags = O_RDONLY;
742 else if (flag[0] == 'w')
743 flags = O_RDWR;
744 else if (flag[0] == 'c')
745 flags = O_RDWR|O_CREAT;
746 else if (flag[0] == 'n')
747 flags = O_RDWR|O_CREAT|O_TRUNC;
748 else {
749 PyErr_SetString(BsddbError,
750 "Flag should begin with 'r', 'w', 'c' or 'n'");
751 return NULL;
752 }
753 if (flag[1] == 'l') {
754#if defined(O_EXLOCK) && defined(O_SHLOCK)
755 if (flag[0] == 'r')
756 flags |= O_SHLOCK;
757 else
758 flags |= O_EXLOCK;
759#else
760 PyErr_SetString(BsddbError,
761 "locking not supported on this platform");
762 return NULL;
763#endif
764 }
765 else if (flag[1] != '\0') {
766 PyErr_SetString(BsddbError,
767 "Flag char 2 should be 'l' or absent");
768 return NULL;
769 }
Guido van Rossum1100dca1995-08-30 23:43:03 +0000770 }
Roger E. Massed9240d11997-01-16 22:05:33 +0000771 return newdbrnobject(file, flags, mode, rnflags, cachesize,
772 psize, lorder, reclen, bval[0], bfname);
Guido van Rossum1100dca1995-08-30 23:43:03 +0000773}
774
Guido van Rossumdfe8ad91996-07-24 00:51:20 +0000775static PyMethodDef bsddbmodule_methods[] = {
Roger E. Massed9240d11997-01-16 22:05:33 +0000776 {"hashopen", (PyCFunction)bsdhashopen, 1},
777 {"btopen", (PyCFunction)bsdbtopen, 1},
778 {"rnopen", (PyCFunction)bsdrnopen, 1},
779 {0, 0},
Guido van Rossum1100dca1995-08-30 23:43:03 +0000780};
781
Guido van Rossum3886bb61998-12-04 18:50:17 +0000782DL_EXPORT(void)
Thomas Wouters58d05102000-07-24 14:43:35 +0000783initbsddb(void) {
Roger E. Massed9240d11997-01-16 22:05:33 +0000784 PyObject *m, *d;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000785
Roger E. Massed9240d11997-01-16 22:05:33 +0000786 Bsddbtype.ob_type = &PyType_Type;
787 m = Py_InitModule("bsddb", bsddbmodule_methods);
788 d = PyModule_GetDict(m);
Guido van Rossum0cb96de1997-10-01 04:29:29 +0000789 BsddbError = PyErr_NewException("bsddb.error", NULL, NULL);
790 if (BsddbError != NULL)
791 PyDict_SetItemString(d, "error", BsddbError);
Guido van Rossum1100dca1995-08-30 23:43:03 +0000792}