blob: a8df0279d36b7b2a9409f81ad57296ef1f3b3192 [file] [log] [blame]
Guido van Rossum79ae53e1995-07-18 18:23:44 +00001/***********************************************************
2Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
3The Netherlands.
4
5 All Rights Reserved
6
7Permission to use, copy, modify, and distribute this software and its
8documentation for any purpose and without fee is hereby granted,
9provided that the above copyright notice appear in all copies and that
10both that copyright notice and this permission notice appear in
11supporting documentation, and that the names of Stichting Mathematisch
12Centrum or CWI not be used in advertising or publicity pertaining to
13distribution of the software without specific, written prior permission.
14
15STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
16THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
18FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22
23******************************************************************/
24
25/* Berkeley DB hash interface.
26 Author: Michael McLay
27 Hacked: Guido van Rossum
28
29 XXX To do:
30 - provide interface to the B-tree and record libraries too
31 - provide a way to access the various hash functions
32 - support more open flags
33 */
34
35#include "allobjects.h"
36#include "modsupport.h"
37
38#include <sys/types.h>
39#include <sys/stat.h>
40#include <fcntl.h>
41#include <db.h>
42/* Please don't include internal header files of the Berkeley db package
43 (it messes up the info required in the Setup file) */
44
45typedef struct {
46 OB_HEAD
47 DB *di_dbhash;
48 int di_size; /* -1 means recompute */
49} dbhashobject;
50
51staticforward typeobject Dbhashtype;
52
53#define is_dbhashobject(v) ((v)->ob_type == &Dbhashtype)
54
55static object *DbhashError;
56
57static object *
58newdbhashobject(file, flags, mode,
59 bsize, ffactor, nelem, cachesize, hash, lorder)
60 char *file;
61 int flags;
62 int mode;
63 int bsize;
64 int ffactor;
65 int nelem;
66 int cachesize;
67 int hash; /* XXX ignored */
68 int lorder;
69{
70 dbhashobject *dp;
71 HASHINFO info;
72
73 if ((dp = NEWOBJ(dbhashobject, &Dbhashtype)) == NULL)
74 return NULL;
75
76 info.bsize = bsize;
77 info.ffactor = ffactor;
78 info.nelem = nelem;
79 info.cachesize = cachesize;
80 info.hash = NULL; /* XXX should derive from hash argument */
81 info.lorder = lorder;
82
83 if ((dp->di_dbhash = dbopen(file, flags, mode, DB_HASH, &info)) == NULL) {
84 err_errno(DbhashError);
85 DECREF(dp);
86 return NULL;
87 }
88
89 dp->di_size = -1;
90
91 return (object *)dp;
92}
93
Guido van Rossum79ae53e1995-07-18 18:23:44 +000094static void
95dbhash_dealloc(dp)
96 dbhashobject *dp;
97{
98 if (dp->di_dbhash != NULL) {
99 if ((dp->di_dbhash->close)(dp->di_dbhash) != 0)
100 fprintf(stderr,
101 "Python dbhash: close errno %s in dealloc\n", errno);
102 }
103 DEL(dp);
104}
105
106static int
107dbhash_length(dp)
108 dbhashobject *dp;
109{
110 if (dp->di_size < 0) {
111 DBT krec, drec;
112 int status;
113 int size = 0;
114 for (status = (dp->di_dbhash->seq)(dp->di_dbhash, &krec, &drec,R_FIRST);
115 status == 0;
116 status = (dp->di_dbhash->seq)(dp->di_dbhash, &krec, &drec, R_NEXT))
117 size++;
118 if (status < 0) {
119 err_errno(DbhashError);
120 return -1;
121 }
122 dp->di_size = size;
123 }
124 return dp->di_size;
125}
126
127static object *
128dbhash_subscript(dp, key)
129 dbhashobject *dp;
130 object *key;
131{
132 int status;
133 object *v;
134 DBT krec, drec;
135 char *data;
136 int size;
137
138 if (!getargs(key, "s#", &data, &size))
139 return NULL;
140 krec.data = data;
141 krec.size = size;
142
143 status = (dp->di_dbhash->get)(dp->di_dbhash, &krec, &drec, 0);
144 if (status != 0) {
145 if (status < 0)
146 err_errno(DbhashError);
147 else
148 err_setval(KeyError, key);
149 return NULL;
150 }
151
152 return newsizedstringobject((char *)drec.data, (int)drec.size);
153}
154
155static int
156dbhash_ass_sub(dp, key, value)
157 dbhashobject *dp;
158 object *key, *value;
159{
160 int status;
161 DBT krec, drec;
162 char *data;
163 int size;
164
165 if (!getargs(key, "s#", &data, &size)) {
166 err_setstr(TypeError, "dbhash key type must be string");
167 return -1;
168 }
169 krec.data = data;
170 krec.size = size;
171 dp->di_size = -1;
172 if (value == NULL) {
173 status = (dp->di_dbhash->del)(dp->di_dbhash, &krec, 0);
174 }
175 else {
176 if (!getargs(value, "s#", &data, &size)) {
177 err_setstr(TypeError, "dbhash value type must be string");
178 return -1;
179 }
180 drec.data = data;
181 drec.size = size;
182 status = (dp->di_dbhash->put)(dp->di_dbhash, &krec, &drec, 0);
183 }
184 if (status != 0) {
185 if (status < 0)
186 err_errno(DbhashError);
187 else
188 err_setval(KeyError, key);
189 return -1;
190 }
191 return 0;
192}
193
194static mapping_methods dbhash_as_mapping = {
195 (inquiry)dbhash_length, /*mp_length*/
196 (binaryfunc)dbhash_subscript, /*mp_subscript*/
197 (objobjargproc)dbhash_ass_sub, /*mp_ass_subscript*/
198};
199
200static object *
Guido van Rossumcf1025b1995-07-18 18:33:09 +0000201dbhash_close(dp, args)
202 dbhashobject *dp;
203 object *args;
204{
205 if (!getnoarg(args))
206 return NULL;
207 if (dp->di_dbhash != NULL) {
208 if ((dp->di_dbhash->close)(dp->di_dbhash) != 0) {
209 dp->di_dbhash = NULL;
210 err_errno(DbhashError);
211 return NULL;
212 }
213 }
214 dp->di_dbhash = NULL;
215 INCREF(None);
216 return None;
217}
218
219static object *
Guido van Rossum79ae53e1995-07-18 18:23:44 +0000220dbhash_keys(dp, args)
221 dbhashobject *dp;
222 object *args;
223{
224 object *list, *item;
225 DBT krec, drec;
226 int status;
227 int err;
228
Guido van Rossum79ae53e1995-07-18 18:23:44 +0000229 if (!getnoarg(args))
230 return NULL;
231 list = newlistobject(0);
232 if (list == NULL)
233 return NULL;
234 for (status = (dp->di_dbhash->seq)(dp->di_dbhash, &krec, &drec, R_FIRST);
235 status == 0;
236 status = (dp->di_dbhash->seq)(dp->di_dbhash, &krec, &drec, R_NEXT)) {
237 item = newsizedstringobject((char *)krec.data, (int)krec.size);
238 if (item == NULL) {
239 DECREF(list);
240 return NULL;
241 }
242 err = addlistitem(list, item);
243 DECREF(item);
244 if (err != 0) {
245 DECREF(list);
246 return NULL;
247 }
248 }
249 if (status < 0) {
250 err_errno(DbhashError);
251 DECREF(list);
252 return NULL;
253 }
254 if (dp->di_size < 0)
255 dp->di_size = getlistsize(list); /* We just did the work for this... */
256 return list;
257}
258
259static object *
260dbhash_has_key(dp, args)
261 dbhashobject *dp;
262 object *args;
263{
264 DBT krec, drec;
265 int status;
266 char *data;
267 int size;
268
269 if (!getargs(args, "s#", &data, &size))
270 return NULL;
271 krec.data = data;
272 krec.size = size;
273
274 status = (dp->di_dbhash->get)(dp->di_dbhash, &krec, &drec, 0);
275 if (status < 0) {
276 err_errno(DbhashError);
277 return NULL;
278 }
279
280 return newintobject(status == 0);
281}
282
283static struct methodlist dbhash_methods[] = {
284 {"close", (method)dbhash_close},
285 {"keys", (method)dbhash_keys},
286 {"has_key", (method)dbhash_has_key},
287 {NULL, NULL} /* sentinel */
288};
289
290static object *
291dbhash_getattr(dp, name)
292 object *dp;
293 char *name;
294{
295 return findmethod(dbhash_methods, dp, name);
296}
297
298static typeobject Dbhashtype = {
299 OB_HEAD_INIT(&Typetype)
300 0,
301 "dbhash",
302 sizeof(dbhashobject),
303 0,
304 (destructor)dbhash_dealloc, /*tp_dealloc*/
305 0, /*tp_print*/
306 (getattrfunc)dbhash_getattr, /*tp_getattr*/
307 0, /*tp_setattr*/
308 0, /*tp_compare*/
309 0, /*tp_repr*/
310 0, /*tp_as_number*/
311 0, /*tp_as_sequence*/
312 &dbhash_as_mapping, /*tp_as_mapping*/
313};
314
315static object *
316dbhashopen(self, args)
317 object *self;
318 object *args;
319{
320 char *file;
321 char *flag = NULL;
322 int flags = O_RDONLY;
323 int mode = 0666;
324 int bsize = 0;
325 int ffactor = 0;
326 int nelem = 0;
327 int cachesize = 0;
328 int hash = 0; /* XXX currently ignored */
329 int lorder = 0;
330
331 if (!newgetargs(args, "s|siiiiiii",
332 &file, &flag, &mode,
333 &bsize, &ffactor, &nelem, &cachesize, &hash, &lorder))
334 return NULL;
335 if (flag != NULL) {
336 /* XXX need a way to pass O_EXCL, O_EXLOCK, O_NONBLOCK, O_SHLOCK */
Guido van Rossum07b14dd1995-07-26 17:33:44 +0000337 if (flag[0] == 'r')
Guido van Rossum79ae53e1995-07-18 18:23:44 +0000338 flags = O_RDONLY;
Guido van Rossum07b14dd1995-07-26 17:33:44 +0000339 else if (flag[0] == 'w')
Guido van Rossum79ae53e1995-07-18 18:23:44 +0000340 flags = O_RDWR;
Guido van Rossum07b14dd1995-07-26 17:33:44 +0000341 else if (flag[0] == 'c')
Guido van Rossum79ae53e1995-07-18 18:23:44 +0000342 flags = O_RDWR|O_CREAT;
Guido van Rossum07b14dd1995-07-26 17:33:44 +0000343 else if (flag[0] == 'n')
Guido van Rossum79ae53e1995-07-18 18:23:44 +0000344 flags = O_RDWR|O_CREAT|O_TRUNC;
345 else {
346 err_setstr(DbhashError,
Guido van Rossum07b14dd1995-07-26 17:33:44 +0000347 "Flag should begin with 'r', 'w', 'c' or 'n'");
Guido van Rossum79ae53e1995-07-18 18:23:44 +0000348 return NULL;
349 }
Guido van Rossum07b14dd1995-07-26 17:33:44 +0000350 if (flag[1] == 'l') {
351#if defined(O_EXLOCK) && defined(O_SHLOCK)
352 if (flag[0] == 'r')
353 flags |= O_SHLOCK;
354 else
355 flags |= O_EXLOCK;
356#else
357 err_setstr(DbhashError, "locking not supported on this platform");
358 return NULL;
359#endif
360 }
Guido van Rossum79ae53e1995-07-18 18:23:44 +0000361 }
362 return newdbhashobject(file, flags, mode,
363 bsize, ffactor, nelem, cachesize, hash, lorder);
364}
365
366static struct methodlist dbhashmodule_methods[] = {
367 {"open", (method)dbhashopen, 1},
368 {0, 0},
369};
370
371void
372initdbhash() {
373 object *m, *d;
374
375 m = initmodule("dbhash", dbhashmodule_methods);
376 d = getmoduledict(m);
377 DbhashError = newstringobject("dbhash.error");
378 if (DbhashError == NULL || dictinsert(d, "error", DbhashError))
379 fatal("can't define dbhash.error");
380}