blob: fce35992599038c1427d75515e60391c8c7c0f69 [file] [log] [blame]
Guido van Rossum4b4c6641994-08-08 08:06:37 +00001/* GDBM module, hacked from the still-breathing corpse of the
2 DBM module by anthony.baxter@aaii.oz.au. Original copyright
3 follows:
4*/
5/***********************************************************
6Copyright 1991, 1992, 1993, 1994 by Stichting Mathematisch Centrum,
7Amsterdam, The Netherlands.
8
9 All Rights Reserved
10
11Permission to use, copy, modify, and distribute this software and its
12documentation for any purpose and without fee is hereby granted,
13provided that the above copyright notice appear in all copies and that
14both that copyright notice and this permission notice appear in
15supporting documentation, and that the names of Stichting Mathematisch
16Centrum or CWI not be used in advertising or publicity pertaining to
17distribution of the software without specific, written prior permission.
18
19STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
20THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
21FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
22FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
23WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
24ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
25OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
26
27******************************************************************/
28
29/* DBM module using dictionary interface */
30
31
32#include "allobjects.h"
33#include "modsupport.h"
34
35#include <sys/types.h>
36#include <sys/stat.h>
37#include <fcntl.h>
38#include "gdbm.h"
39
40typedef struct {
41 OB_HEAD
42 int di_size; /* -1 means recompute */
43 GDBM_FILE di_dbm;
44} dbmobject;
45
46staticforward typeobject Dbmtype;
47
48#define is_dbmobject(v) ((v)->ob_type == &Dbmtype)
49
50static object *DbmError;
51
52static object *
53newdbmobject(file, flags, mode)
54 char *file;
55 int flags;
56 int mode;
57{
58 dbmobject *dp;
59
60 dp = NEWOBJ(dbmobject, &Dbmtype);
61 if (dp == NULL)
62 return NULL;
63 dp->di_size = -1;
64 if ( (dp->di_dbm = gdbm_open(file, 0, flags, mode, NULL)) == 0 ) {
65 err_errno(DbmError);
66 DECREF(dp);
67 return 0;
68 }
69 return (object *)dp;
70}
71
72/* Methods */
73
74static void
75dbm_dealloc(dp)
76 register dbmobject *dp;
77{
78 if ( dp->di_dbm )
79 gdbm_close(dp->di_dbm);
80 DEL(dp);
81}
82
83static int
84dbm_length(dp)
85 dbmobject *dp;
86{
87 if ( dp->di_size < 0 ) {
88 datum key,okey;
89 int size;
90 okey.dsize=0;
91
92 size = 0;
93 for ( key=gdbm_firstkey(dp->di_dbm); key.dptr;
94 key = gdbm_nextkey(dp->di_dbm,okey)) {
95 size++;
96 if(okey.dsize) free(okey);
97 okey=key;
98 }
99 dp->di_size = size;
100 }
101 return dp->di_size;
102}
103
104static object *
105dbm_subscript(dp, key)
106 dbmobject *dp;
107 register object *key;
108{
109 object *v;
110 datum drec, krec;
111
112 if (!getargs(key, "s#", &krec.dptr, &krec.dsize) )
113 return NULL;
114
115 drec = gdbm_fetch(dp->di_dbm, krec);
116 if ( drec.dptr == 0 ) {
117 err_setstr(KeyError, GETSTRINGVALUE((stringobject *)key));
118 return 0;
119 }
120 return newsizedstringobject(drec.dptr, drec.dsize);
121}
122
123static int
124dbm_ass_sub(dp, v, w)
125 dbmobject *dp;
126 object *v, *w;
127{
128 datum krec, drec;
129
130 if ( !getargs(v, "s#", &krec.dptr, &krec.dsize) ) {
131 err_setstr(TypeError, "gdbm mappings have string indices only");
132 return -1;
133 }
134 dp->di_size = -1;
135 if (w == NULL) {
136 if ( gdbm_delete(dp->di_dbm, krec) < 0 ) {
137 err_setstr(KeyError, GETSTRINGVALUE((stringobject *)v));
138 return -1;
139 }
140 } else {
141 if ( !getargs(w, "s#", &drec.dptr, &drec.dsize) ) {
142 err_setstr(TypeError,
143 "gdbm mappings have string elements only");
144 return -1;
145 }
146 if ( gdbm_store(dp->di_dbm, krec, drec, GDBM_REPLACE) < 0 ) {
147 err_setstr(DbmError, "Cannot add item to database");
148 return -1;
149 }
150 }
151 return 0;
152}
153
154static mapping_methods dbm_as_mapping = {
155 (inquiry)dbm_length, /*mp_length*/
156 (binaryfunc)dbm_subscript, /*mp_subscript*/
157 (objobjargproc)dbm_ass_sub, /*mp_ass_subscript*/
158};
159
160static object *
161dbm_keys(dp, args)
162 register dbmobject *dp;
163 object *args;
164{
165 register object *v, *item;
166 datum key, okey={ (char *)NULL, 0};
167
168 if (dp == NULL || !is_dbmobject(dp)) {
169 err_badcall();
170 return NULL;
171 }
172 if (!getnoarg(args))
173 return NULL;
174 v = newlistobject(0);
175 if (v == NULL)
176 return NULL;
177 for (key = gdbm_firstkey(dp->di_dbm); key.dptr;
178 key = gdbm_nextkey(dp->di_dbm,okey) ) {
179 item = newsizedstringobject(key.dptr, key.dsize);
180 if ( item == 0 )
181 return NULL;
182 addlistitem(v, item);
183 if(okey.dsize) free(okey);
184 okey=key;
185 }
186 return v;
187}
188
189
190static object *
191dbm_has_key(dp, args)
192 register dbmobject *dp;
193 object *args;
194{
195 datum key, val;
196
197 if (!getargs(args, "s#", &key.dptr, &key.dsize))
198 return NULL;
199 val = gdbm_fetch(dp->di_dbm, key);
200 return newintobject(val.dptr != NULL);
201}
202
203static struct methodlist dbm_methods[] = {
204 {"keys", (method)dbm_keys},
205 {"has_key", (method)dbm_has_key},
206 {NULL, NULL} /* sentinel */
207};
208
209static object *
210dbm_getattr(dp, name)
211 dbmobject *dp;
212 char *name;
213{
214 return findmethod(dbm_methods, (object *)dp, name);
215}
216
217static typeobject Dbmtype = {
218 OB_HEAD_INIT(&Typetype)
219 0,
220 "Gdbm_dictionary",
221 sizeof(dbmobject),
222 0,
223 (destructor)dbm_dealloc, /*tp_dealloc*/
224 0, /*tp_print*/
225 (getattrfunc)dbm_getattr, /*tp_getattr*/
226 0, /*tp_setattr*/
227 0, /*tp_compare*/
228 0, /*tp_repr*/
229 0, /*tp_as_number*/
230 0, /*tp_as_sequence*/
231 &dbm_as_mapping, /*tp_as_mapping*/
232};
233
234/* ----------------------------------------------------------------- */
235
236static object *
237dbmopen(self, args)
238 object *self;
239 object *args;
240{
241 char *name, *flags;
242 int iflags, mode;
243
244/* XXXX add other flags */
245 if ( !getargs(args, "(ssi)", &name, &flags, &mode) )
246 return 0;
247 if ( strcmp(flags, "r") == 0 )
248 iflags = GDBM_READER;
249 else if ( strcmp(flags, "w") == 0 )
250 iflags = GDBM_WRITER;
251 else if ( strcmp(flags, "c") == 0 )
252 iflags = GDBM_WRCREAT;
253 else if ( strcmp(flags, "n") == 0 )
254 iflags = GDBM_NEWDB;
255 else {
256 err_setstr(DbmError,
257 "Flags should be one of 'r', or 'w'");
258 return 0;
259 }
260 return newdbmobject(name, iflags, mode);
261}
262
263static struct methodlist dbmmodule_methods[] = {
264 { "open", (method)dbmopen },
265 { 0, 0 },
266};
267
268void
269initgdbm() {
270 object *m, *d;
271
272 m = initmodule("gdbm", dbmmodule_methods);
273 d = getmoduledict(m);
274 DbmError = newstringobject("gdbm.error");
275 if ( DbmError == NULL || dictinsert(d, "error", DbmError) )
276 fatal("can't define gdbm.error");
277}
278
279