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