chiark / gitweb /
cdbmodule.c: Fix deallocation.
[python-cdb] / src / cdbmodule.c
CommitLineData
dc7ddb87
MW
1/**
2python-cdb 0.32
3Copyright 2001, 2002 Michael J. Pomraning <mjp@pilcrow.madison.wi.us>
4
5This program is free software; you can redistribute it and/or modify
6it under the terms of the GNU General Public License as published by
7the Free Software Foundation; either version 2 of the License, or
8(at your option) any later version.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
19**/
20
21#include <Python.h>
22#include <unistd.h>
23#include <sys/types.h>
24#include <fcntl.h>
25#include "cdb.h"
26#include "cdb_make.h"
27
28#define open_read(x) (open((x),O_RDONLY|O_NDELAY))
29/* ala djb's open_foo */
30
31#define VERSION "0.32"
32#define CDBVERSION "0.75"
33
34/* ------------------- cdb object -------------------- */
35
36static char cdbo_object_doc[] = "\
37This object represents a CDB database: a reliable, constant\n\
38database mapping strings of bytes (\"keys\") to strings of bytes\n\
39(\"data\"), and designed for fast lookups.\n\
40\n\
41Unlike a conventional mapping, CDBs can meaningfully store multiple\n\
42records under one key (though this feature is not often used).\n\
43\n\
44A CDB object 'cdb_o' offers the following interesting attributes:\n\
45\n\
46 Dict-like Lookup Methods:\n\
47 cdb_o[key], get(key), getnext(), getall(key)\n\
48\n\
49 Key-based Iteration Methods:\n\
50 keys(), firstkey(), nextkey()\n\
51 (Key-based iteration returns only distinct keys.)\n\
52\n\
53 Raw Iteration Method:\n\
54 each()\n\
55 (\"Dumping\" may return the same key more than once.)\n\
56\n\
57 __members__:\n\
58 fd - File descriptor of the underlying cdb.\n\
59 name - Name of the cdb, or None if not known.\n\
60 size - Size of the cdb, or None if not mmap()d.\n\
61\n\
62 __length__:\n\
63 len(cdb_o) returns the total number of items in a cdb,\n\
64 which may or may not exceed the number of distinct keys.\n";
65
66
67typedef struct {
68 PyObject_HEAD
69 struct cdb c;
70 PyObject * name_py; /* 'filename' or Py_None */
71 PyObject * getkey; /* squirreled away for getnext() */
72 uint32 eod; /* as in cdbdump */
73 uint32 iter_pos;
74 uint32 each_pos;
75 uint32 numrecords;
76} CdbObject;
77
78staticforward PyTypeObject CdbType;
79
80PyObject * CDBError;
81#define CDBerr PyErr_SetFromErrno(CDBError)
82
83static PyObject *
84cdb_pyread(CdbObject *cdb_o, unsigned int len, uint32 pos) {
85 struct cdb *c;
86 PyObject *s = NULL;
87
88 c = &cdb_o->c;
89
90 if (c->map) {
91 if ((pos > c->size) || (c->size - pos < len))
92 goto FORMAT;
93 s = PyString_FromStringAndSize(c->map + pos, len);
94 } else {
95 s = PyString_FromStringAndSize(NULL, len);
96 if (s == NULL)
97 return NULL;
98 if (lseek(c->fd,pos,SEEK_SET) == -1) goto ERRNO;
99 while (len > 0) {
100 int r;
101 char * buf = PyString_AsString(s);
102
103 do {
104 Py_BEGIN_ALLOW_THREADS
105 r = read(c->fd,buf,len);
106 Py_END_ALLOW_THREADS
107 }
108 while ((r == -1) && (errno == EINTR));
109 if (r == -1) goto ERRNO;
110 if (r == 0) goto FORMAT;
111 buf += r;
112 len -= r;
113 }
114 }
115
116 return s;
117
118 FORMAT:
119 Py_XDECREF(s);
120 PyErr_SetFromErrno(PyExc_RuntimeError);
121 return NULL;
122
123 ERRNO:
124 Py_XDECREF(s);
125 return CDBerr;
126
127}
128
129
130#define CDBO_CURDATA(x) (cdb_pyread(x, x->c.dlen, x->c.dpos))
131
132
133/* ------------------- CdbObject methods -------------------- */
134
135static char cdbo_has_key_doc[] =
136"cdb_o.has_key(k) -> 1 (or 0)\n\
137\n\
138Returns true if the CDB contains key k.";
139
140static PyObject *
141cdbo_has_key(CdbObject *self, PyObject *args) {
142
143 char * key;
144 unsigned int klen;
145 int r;
146
147 if (!PyArg_ParseTuple(args, "s#", &key, &klen))
148 return NULL;
149
150 r = cdb_find(&self->c, key, klen);
151 if (r == -1)
152 return CDBerr;
153
154 return Py_BuildValue("i", r);
155
156}
157
158static char cdbo_get_doc[] =
159"cdb_o.get(k [, i]) -> data (or None)\n\
160\n\
161Fetches the record stored under key k, skipping past the first i\n\
162records under that key (default: 0). Prepares the next call to\n\
163getnext().\n\
164\n\
165Assuming cdb_o.has_key(k) == 1, then all of the following return:\n\
166the first record stored under key k:\n\
167\n\
168 cdb_o.get(k) == cdb_o[k] == cdb_o.getall(k)[0]\n";
169
170static PyObject *
171cdbo_get(CdbObject *self, PyObject *args) {
172
173 char * key;
174 unsigned int klen;
175 int r;
176 int i = 0;
177
178 if (!PyArg_ParseTuple(args, "s#|i:get", &key, &klen, &i))
179 return NULL;
180
181 cdb_findstart(&self->c);
182
183 for (;;) {
184 r = cdb_findnext(&self->c, key, klen);
185 if (r == -1) return CDBerr;
186 if (!r) return Py_BuildValue("");
187 if (!i) break;
188 --i;
189 }
190
191 /* prep. possibly ensuing call to getnext() */
192 Py_XDECREF(self->getkey);
193 self->getkey = PyString_FromStringAndSize(key, klen);
194 if (self->getkey == NULL)
195 return NULL;
196
197 return CDBO_CURDATA(self);
198}
199
200static char cdbo_getall_doc[] =
201"cdb_o.getall(k) -> ['data', ... ]\n\
202\n\
203Return a list of all records stored under key k.";
204
205static PyObject *
206cdbo_getall(CdbObject *self, PyObject *args) {
207
208 PyObject * list, * data;
209 char * key;
210 unsigned int klen;
211 int r, err;
212
213 if (!PyArg_ParseTuple(args, "s#:getall", &key, &klen))
214 return NULL;
215
216 list = PyList_New(0);
217
218 if (list == NULL) return NULL;
219
220 cdb_findstart(&self->c);
221
222 while ((r = cdb_findnext(&self->c, key, klen))) {
223 if (r == -1) {
224 Py_DECREF(list);
225 return CDBerr;
226 }
227 data = CDBO_CURDATA(self);
228 if (data == NULL) {
229 Py_DECREF(list);
230 return NULL;
231 }
232 err = PyList_Append(list, data);
233 Py_DECREF(data);
234 if (err != 0) {
235 Py_DECREF(list);
236 return NULL;
237 }
238 }
239
240 return list;
241
242}
243
244static char cdbo_getnext_doc[] =
245"cdb_o.getnext() -> 'data' (or None)\n\
246\n\
247For iteration over the records stored under one key, avoiding loading\n\
248all items into memory). The \"current key\" is determined by the most\n\
249recent call to get().\n\
250\n\
251The following loops through all items stored under key k:\n\
252\n\
253 ## cdb_o.getall(k) possibly too big for memory\n\
254 rec = cdb_o.get(k)\n\
255 while rec is not None:\n\
256 do_something(rec)\n\
257 rec = cdb_o.getnext()\n";
258
259static PyObject *
260cdbo_getnext(CdbObject *self, PyObject *args) {
261
262 if (!PyArg_ParseTuple(args, ":getnext"))
263 return NULL;
264
265 if (self->getkey == NULL) {
266 PyErr_SetString(PyExc_TypeError,
267 "getnext() called without first calling get()");
268 return NULL;
269 }
270
271 switch(cdb_findnext(&self->c,
272 PyString_AsString(self->getkey),
273 PyString_Size(self->getkey))) {
274 case -1:
275 return CDBerr;
276 case 0:
277 Py_DECREF(self->getkey);
278 self->getkey = NULL;
279 return Py_BuildValue("");
280 default:
281 return CDBO_CURDATA(self);
282 }
283 /* not reached */
284}
285
286uint32
287_cdbo_init_eod(CdbObject *self) {
288
289 char nonce[4];
290
291 if (cdb_read(&self->c, nonce, 4, 0) == -1)
292 return 0;
293
294 uint32_unpack(nonce, &self->eod);
295
296 return self->eod;
297
298}
299
300/*
301 * _cdbo_keyiter(cdb_o)
302 *
303 * Whiz-bang all-in-one:
304 * extract current record
305 * compare current pos to pos implied by cdb_find(current_key)
306 * (Different? adv. iter cursor, loop and try again)
307 * advance iteration cursor
308 * return key
309 */
310
311static PyObject *
312_cdbo_keyiter(CdbObject *self) {
313
314 PyObject *key;
315 char buf[8];
316 uint32 klen, dlen;
317
318 if (! self->eod)
319 _cdbo_init_eod(self);
320
321 while (self->iter_pos < self->eod) {
322 if (cdb_read(&self->c, buf, 8, self->iter_pos) == -1)
323 return CDBerr;
324
325 uint32_unpack(buf, &klen);
326 uint32_unpack(buf+4, &dlen);
327
328 key = cdb_pyread(self, klen, self->iter_pos + 8);
329
330 if (key == NULL)
331 return NULL;
332
333 switch(cdb_find(&self->c,PyString_AsString(key),PyString_Size(key))) {
334 case -1:
335 Py_DECREF(key);
336 key = NULL;
337 return CDBerr;
338 case 0:
339 /* bizarre, impossible? PyExc_RuntimeError? */
340 PyErr_SetString(PyExc_KeyError,
341 PyString_AS_STRING((PyStringObject *) key));
342 Py_DECREF(key);
343 key = NULL;
344 default:
345 if (key == NULL) /* already raised error */
346 return NULL;
347
348 if (cdb_datapos(&self->c) == self->iter_pos + klen + 8) {
349 /** first occurrence of key in the cdb **/
350 self->iter_pos += 8 + klen + dlen;
351 return key;
352 }
353 Py_DECREF(key); /* better luck next time around */
354 self->iter_pos += 8 + klen + dlen;
355 }
356 }
357
358 return Py_BuildValue(""); /* iter_pos >= eod; we're done */
359
360}
361
362static char cdbo_keys_doc[] =
363"cdb_o.keys() -> ['k1', 'k2', ... ]\n\
364\n\
365Returns a list of all (distinct) keys in the database.";
366
367static PyObject *
368cdbo_keys(CdbObject *self, PyObject *args) {
369
370 PyObject *r, *key;
371 uint32 pos;
372 int err;
373
374 if (! PyArg_ParseTuple(args, ""))
375 return NULL;
376
377 r = PyList_New(0);
378 if (r == NULL)
379 return NULL;
380
381 pos = self->iter_pos; /* don't interrupt a manual iteration */
382
383 self->iter_pos = 2048;
384
385 key = _cdbo_keyiter(self);
386 while (key != Py_None) {
387 err = PyList_Append(r, key);
388 Py_DECREF(key);
389 if (err != 0) {
390 Py_DECREF(r);
391 self->iter_pos = pos;
392 return NULL;
393 }
394 key = _cdbo_keyiter(self);
395 }
396 Py_DECREF(key);
397
398 self->iter_pos = pos;
399
400 return r;
401
402}
403
404static char cdbo_firstkey_doc[] =
405"cdb_o.firstkey() -> key (or None)\n\
406\n\
407Return the first key in the database, resetting the internal\n\
408iteration cursor. firstkey() and nextkey() may be used to\n\
409traverse all distinct keys in the cdb. See each() for raw\n\
410iteration.";
411
412static PyObject *
413cdbo_firstkey(CdbObject *self, PyObject *args) {
414
415 if (! PyArg_ParseTuple(args, ":firstkey"))
416 return NULL;
417
418 self->iter_pos = 2048;
419
420 return _cdbo_keyiter(self);
421
422}
423
424static char cdbo_nextkey_doc[] =
425"cdb_o.nextkey() -> key (or None)\n\
426\n\
427Return the next distinct key in the cdb.\n\
428\n\
429The following code walks the CDB one key at a time:\n\
430\n\
431 key = cdb_o.firstkey()\n\
432 while key is not None:\n\
433 print key\n\
434 key = cdb_o.nextkey()\n";
435
436static PyObject *
437cdbo_nextkey(CdbObject *self, PyObject *args) {
438
439 if (! PyArg_ParseTuple(args, ":nextkey"))
440 return NULL;
441
442 return _cdbo_keyiter(self);
443
444}
445
446static char cdbo_each_doc[] =
447"cdb_o.each() -> (key, data) (or None)\n\
448\n\
449Fetch the next ('key', 'data') record from the underlying cdb file,\n\
450returning None and resetting the iteration cursor when all records\n\
451have been fetched.\n\
452\n\
453Keys appear with each item under them -- e.g., (key,foo), (key2,bar),\n\
454(key,baz) -- order of records is determined by actual position on\n\
455disk. Both keys() and (for GDBM fanciers) firstkey()/nextkey()-style\n\
456iteration go to pains to present the user with only distinct keys.";
457
458static PyObject *
459cdbo_each(CdbObject *self, PyObject *args) {
460
461 PyObject *tup, *key, *dat;
462 char buf[8];
463 uint32 klen, dlen;
464
465 if (! PyArg_ParseTuple(args, ":each"))
466 return NULL;
467
468 tup = PyTuple_New(2);
469 if (tup == NULL)
470 return NULL;
471
472 if (! self->eod)
473 (void) _cdbo_init_eod(self);
474
475 if (self->each_pos >= self->eod) { /* all done, reset cursor */
476 self->each_pos = 2048;
477 Py_INCREF(Py_None);
478 return Py_None;
479 }
480
481 if (cdb_read(&self->c, buf, 8, self->each_pos) == -1)
482 return CDBerr;
483
484 uint32_unpack(buf, &klen);
485 uint32_unpack(buf+4, &dlen);
486
487 key = cdb_pyread(self, klen, self->each_pos + 8);
488 dat = cdb_pyread(self, dlen, self->each_pos + 8 + klen);
489
490 self->each_pos += klen + dlen + 8;
491
492 if (key == NULL || dat == NULL) {
493 Py_XDECREF(key); Py_XDECREF(dat);
494 Py_DECREF(tup);
495 return NULL;
496 }
497
498 if (PyTuple_SetItem(tup, 0, key) || PyTuple_SetItem(tup, 1, dat)) {
499 Py_DECREF(key); Py_DECREF(dat); Py_DECREF(tup);
500 return NULL;
501 }
502
503 return tup;
504}
505
506/*** cdb object as mapping ***/
507
508static int
509cdbo_length(CdbObject *self) {
510
511 if (! self->numrecords) {
512 char buf[8];
513 uint32 pos, klen, dlen;
514
515 pos = 2048;
516
517 if (! self->eod)
518 (void) _cdbo_init_eod(self);
519
520 while (pos < self->eod) {
521 if (cdb_read(&self->c, buf, 8, pos) == -1)
522 return -1;
523 uint32_unpack(buf, &klen);
524 uint32_unpack(buf + 4, &dlen);
525 pos += 8 + klen + dlen;
526 self->numrecords++;
527 }
528 }
529 return (int) self->numrecords;
530}
531
532static PyObject *
533cdbo_subscript(CdbObject *self, PyObject *k) {
534 char * key;
535 int klen;
536
537 if (! PyArg_Parse(k, "s#", &key, &klen))
538 return NULL;
539
540 switch(cdb_find(&self->c, key, (unsigned int)klen)) {
541 case -1:
542 return CDBerr;
543 case 0:
544 PyErr_SetString(PyExc_KeyError,
545 PyString_AS_STRING((PyStringObject *) k));
546 return NULL;
547 default:
548 return CDBO_CURDATA(self);
549 }
550 /* not reached */
551}
552
553static PyMappingMethods cdbo_as_mapping = {
554 (inquiry)cdbo_length,
555 (binaryfunc)cdbo_subscript,
556 (objobjargproc)0
557};
558
559static PyMethodDef cdb_methods[] = {
560
561 {"get", (PyCFunction)cdbo_get, METH_VARARGS,
562 cdbo_get_doc },
563 {"getnext", (PyCFunction)cdbo_getnext, METH_VARARGS,
564 cdbo_getnext_doc },
565 {"getall", (PyCFunction)cdbo_getall, METH_VARARGS,
566 cdbo_getall_doc },
567 {"has_key", (PyCFunction)cdbo_has_key, METH_VARARGS,
568 cdbo_has_key_doc },
569 {"keys", (PyCFunction)cdbo_keys, METH_VARARGS,
570 cdbo_keys_doc },
571 {"firstkey", (PyCFunction)cdbo_firstkey, METH_VARARGS,
572 cdbo_firstkey_doc },
573 {"nextkey", (PyCFunction)cdbo_nextkey, METH_VARARGS,
574 cdbo_nextkey_doc },
575 {"each", (PyCFunction)cdbo_each, METH_VARARGS,
576 cdbo_each_doc },
577 { NULL, NULL }
578};
579
580/* ------------------- cdb operations -------------------- */
581
582static PyObject *
583_wrap_cdb_init(int fd) { /* constructor implementation */
584
585 CdbObject *self;
586
587 self = PyObject_NEW(CdbObject, &CdbType);
588 if (self == NULL) return NULL;
589
590 self->c.map = 0; /* break encapsulation -- cdb struct init'd to zero */
591 cdb_init(&self->c, fd);
592
593 self->iter_pos = 2048;
594 self->each_pos = 2048;
595 self->numrecords = 0;
596 self->eod = 0;
597 self->getkey = NULL;
598
599 return (PyObject *) self;
600}
601
602
603static PyObject *
604cdbo_constructor(PyObject *ignore, PyObject *args) {
605
606 PyObject *self;
607 PyObject *f;
608 PyObject *name_attr = Py_None;
609 int fd;
610
611 if (! PyArg_ParseTuple(args, "O:new", &f))
612 return NULL;
613
614 if (PyString_Check(f)) {
615
616 if ((fd = open_read(PyString_AsString(f))) == -1)
617 return CDBerr;
618
619 name_attr = f;
620
621 } else if (PyInt_Check(f)) {
622
623 fd = (int) PyInt_AsLong(f);
624
625 } else {
626
627 PyErr_SetString(PyExc_TypeError,
628 "expected filename or file descriptor");
629 return NULL;
630
631 }
632
633 self = _wrap_cdb_init(fd);
634 if (self == NULL) return NULL;
635
636 ((CdbObject *)self)->name_py = name_attr;
637 Py_INCREF(name_attr);
638
639 return self;
640}
641
642static void
643cdbo_dealloc(CdbObject *self) { /* del(cdb_o) */
644
645 if (self->name_py != NULL) {
646
647 /* if cdb_o.name is not None: we open()d it ourselves, so close it */
648 if (PyString_Check(self->name_py))
649 close(self->c.fd);
650
651 Py_DECREF(self->name_py);
652 }
653
654 Py_XDECREF(self->getkey);
655
656 cdb_free(&self->c);
657
e16054cf 658 PyObject_Del((PyObject *)self);
dc7ddb87
MW
659}
660
661static PyObject *
662cdbo_getattr(CdbObject *self, char *name) {
663
664 PyObject * r;
665
666 r = Py_FindMethod(cdb_methods, (PyObject *) self, name);
667
668 if (r != NULL)
669 return r;
670
671 PyErr_Clear();
672
673 if (!strcmp(name,"__members__"))
674 return Py_BuildValue("[sss]", "fd", "name", "size");
675
676 if (!strcmp(name,"fd")) {
677 return Py_BuildValue("i", self->c.fd); /* cdb_o.fd */
678 }
679
680 if (!strcmp(name,"name")) {
681 Py_INCREF(self->name_py);
682 return self->name_py; /* cdb_o.name */
683 }
684
685 if (!strcmp(name,"size")) { /* cdb_o.size */
686 return self->c.map ? /** mmap()d ? stat.st_size : None **/
687 Py_BuildValue("l", (long) self->c.size) :
688 Py_BuildValue("");
689 }
690
691 PyErr_SetString(PyExc_AttributeError, name);
692 return NULL;
693}
694
695
696/* ----------------- cdbmake object ------------------ */
697
698static char cdbmake_object_doc[] =
699"cdbmake objects resemble the struct cdb_make interface:\n\
700\n\
701 CDB Construction Methods:\n\
702 add(k, v), finish()\n\
703\n\
704 __members__:\n\
705 fd - fd of underlying CDB, or -1 if finish()ed\n\
706 fn, fntmp - as from the cdb package's cdbmake utility\n\
707 numentries - current number of records add()ed\n";
708
709typedef struct {
710 PyObject_HEAD
711 struct cdb_make cm;
712 PyObject * fn;
713 PyObject * fntmp;
714} cdbmakeobject;
715
716staticforward PyTypeObject CdbMakeType;
717
718#define CDBMAKEerr PyErr_SetFromErrno(PyExc_IOError)
719
720
721/* ----------------- CdbMake methods ------------------ */
722
723static PyObject *
724CdbMake_add(cdbmakeobject *self, PyObject *args) {
725
726 char * key, * dat;
727 unsigned int klen, dlen;
728
729 if (!PyArg_ParseTuple(args,"s#s#:add",&key,&klen,&dat,&dlen))
730 return NULL;
731
732 if (cdb_make_add(&self->cm, key, klen, dat, dlen) == -1)
733 return CDBMAKEerr;
734
735 return Py_BuildValue("");
736
737}
738
739static PyObject *
740CdbMake_finish(cdbmakeobject *self, PyObject *args) {
741
742 if (!PyArg_ParseTuple(args, ":finish"))
743 return NULL;
744
745 if (cdb_make_finish(&self->cm) == -1)
746 return CDBMAKEerr;
747
748 /* cleanup as in cdb dist's cdbmake */
749
750 if (fsync(fileno(self->cm.fp)) == -1)
751 return CDBMAKEerr;
752
753 if (fclose(self->cm.fp) != 0)
754 return CDBMAKEerr;
755
756 self->cm.fp = NULL;
757
758 if (rename(PyString_AsString(self->fntmp),
759 PyString_AsString(self->fn)) == -1)
760 return CDBMAKEerr;
761
762 return Py_BuildValue("");
763}
764
765static PyMethodDef cdbmake_methods[] = {
766 {"add", (PyCFunction)CdbMake_add, METH_VARARGS,
767"cm.add(key, data) -> None\n\
768\n\
769Add 'key' -> 'data' pair to the underlying CDB." },
770 {"finish", (PyCFunction)CdbMake_finish, METH_VARARGS,
771"cm.finish() -> None\n\
772\n\
773Finish safely composing a new CDB, renaming cm.fntmp to\n\
774cm.fn." },
775 { NULL, NULL }
776};
777
778/* ----------------- cdbmake operations ------------------ */
779
780static PyObject *
781new_cdbmake(PyObject *ignore, PyObject *args) {
782
783 cdbmakeobject *self;
784 PyObject *fn, *fntmp;
785 FILE * f;
786
787 if (! PyArg_ParseTuple(args, "SS|i", &fn, &fntmp))
788 return NULL;
789
790 f = fopen(PyString_AsString(fntmp), "w+b");
791 if (f == NULL) {
792 return CDBMAKEerr;
793 }
794
795 self = PyObject_NEW(cdbmakeobject, &CdbMakeType);
796 if (self == NULL) return NULL;
797
798 self->fn = fn;
799 Py_INCREF(self->fn);
800
801 self->fntmp = fntmp;
802 Py_INCREF(fntmp);
803
804 if (cdb_make_start(&self->cm, f) == -1) {
805 Py_DECREF(self);
806 CDBMAKEerr;
807 return NULL;
808 }
809
810 return (PyObject *) self;
811}
812
813static void
814cdbmake_dealloc(cdbmakeobject *self) {
815
816 Py_XDECREF(self->fn);
817
818 if (self->fntmp != NULL) {
819 if (self->cm.fp != NULL) {
820 fclose(self->cm.fp);
821 unlink(PyString_AsString(self->fntmp));
822 }
823 Py_DECREF(self->fntmp);
824 }
825
e16054cf 826 PyObject_Del((PyObject *)self);
dc7ddb87
MW
827}
828
829static PyObject *
830cdbmake_getattr(cdbmakeobject *self, char *name) {
831
832 if (!strcmp(name,"__members__"))
833 return Py_BuildValue("[ssss]", "fd", "fn", "fntmp", "numentries");
834
835 if (!strcmp(name,"fd"))
836 return Py_BuildValue("i", fileno(self->cm.fp)); /* self.fd */
837
838 if (!strcmp(name,"fn")) {
839 Py_INCREF(self->fn);
840 return self->fn; /* self.fn */
841 }
842
843 if (!strcmp(name,"fntmp")) {
844 Py_INCREF(self->fntmp);
845 return self->fntmp; /* self.fntmp */
846 }
847
848 if (!strcmp(name,"numentries"))
849 return Py_BuildValue("l", self->cm.numentries); /* self.numentries */
850
851 return Py_FindMethod(cdbmake_methods, (PyObject *) self, name);
852}
853
854/* ---------------- Type delineation -------------------- */
855
856statichere PyTypeObject CdbType = {
857 /* The ob_type field must be initialized in the module init function
858 * to be portable to Windows without using C++. */
859 PyObject_HEAD_INIT(NULL)
860 0, /*ob_size*/
861 "cdb", /*tp_name*/
862 sizeof(CdbObject), /*tp_basicsize*/
863 0, /*tp_itemsize*/
864 /* methods */
865 (destructor)cdbo_dealloc, /*tp_dealloc*/
866 0, /*tp_print*/
867 (getattrfunc)cdbo_getattr, /*tp_getattr*/
868 0, /*tp_setattr*/
869 0, /*tp_compare*/
870 0, /*tp_repr*/
871 0, /*tp_as_number*/
872 0, /*tp_as_sequence*/
873 &cdbo_as_mapping, /*tp_as_mapping*/
874 0, /*tp_hash*/
875 0, /*tp_call*/
876 0, /*tp_str*/
877 0, /*tp_getattro*/
878 0, /*tp_setattro*/
879 0, /*tp_as_buffer*/
880 0, /*tp_xxx4*/
881 cdbo_object_doc, /*tp_doc*/
882};
883
884statichere PyTypeObject CdbMakeType = {
885 /* The ob_type field must be initialized in the module init function
886 * to be portable to Windows without using C++. */
887 PyObject_HEAD_INIT(NULL)
888 0, /*ob_size*/
889 "cdbmake", /*tp_name*/
890 sizeof(cdbmakeobject), /*tp_basicsize*/
891 0, /*tp_itemsize*/
892 /* methods */
893 (destructor)cdbmake_dealloc, /*tp_dealloc*/
894 0, /*tp_print*/
895 (getattrfunc)cdbmake_getattr, /*tp_getattr*/
896 0, /*tp_setattr*/
897 0, /*tp_compare*/
898 0, /*tp_repr*/
899 0, /*tp_as_number*/
900 0, /*tp_as_sequence*/
901 0, /*tp_as_mapping*/
902 0, /*tp_hash*/
903 0, /*tp_call*/
904 0, /*tp_str*/
905 0, /*tp_getattro*/
906 0, /*tp_setattro*/
907 0, /*tp_as_buffer*/
908 0, /*tp_xxx4*/
909 cdbmake_object_doc, /*tp_doc*/
910};
911
912/* ---------------- exported functions ------------------ */
913static PyObject *
914_wrap_cdb_hash(PyObject *ignore, PyObject *args) {
915
916 char *s;
917 int sz;
918
919 if (! PyArg_ParseTuple(args, "s#:hash", &s, &sz))
920 return NULL;
921
922 return Py_BuildValue("l", cdb_hash(s, (unsigned int) sz));
923
924}
925
926/* ---------------- cdb Module -------------------- */
927
928static PyMethodDef module_functions[] = {
929 {"init", cdbo_constructor, METH_VARARGS,
930"cdb.init(f) -> cdb_object\n\
931\n\
932Open a CDB specified by f and return a cdb object.\n\
933f may be a filename or an integral file descriptor\n\
934(e.g., init( sys.stdin.fileno() )...)."},
935 {"cdbmake", new_cdbmake, METH_VARARGS,
936"cdb.cdbmake(cdb, tmp) -> cdbmake_object\n\
937\n\
938Interface to the creation of a new CDB file \"cdb\".\n\
939\n\
940The cdbmake object first writes records to the temporary file\n\
941\"tmp\" (records are inserted via the object's add() method).\n\
942The finish() method then atomically renames \"tmp\" to \"cdb\",\n\
943ensuring that readers of \"cdb\" need never wait for updates to\n\
944complete."
945},
946 {"hash", _wrap_cdb_hash, METH_VARARGS,
947"hash(s) -> hashval\n\
948\n\
949Compute the 32-bit hash value of some sequence of bytes s."},
950 {NULL, NULL}
951};
952
953static char module_doc[] =
954"Python adaptation of D. J. Bernstein's constant database (CDB)\n\
955package. See <http://cr.yp.to/cdb.html>\n\
956\n\
957CDB objects, created by init(), provide read-only, dict-like\n\
958access to cdb files, as well as iterative methods.\n\
959\n\
960CDBMake objects, created by cdbmake(), allow for creation and\n\
961atomic replacement of CDBs.\n\
962\n\
963This module defines a new Exception \"error\".";
964
965DL_EXPORT(void)
966initcdb() {
967 PyObject *m, *d, *v;
968
969 CdbType.ob_type = &PyType_Type;
970 CdbMakeType.ob_type = &PyType_Type;
971
972 m = Py_InitModule3("cdb", module_functions, module_doc);
973
974 d = PyModule_GetDict(m);
975
976 CDBError = PyErr_NewException("cdb.error", NULL, NULL);
977 PyDict_SetItemString(d, "error", CDBError);
978
979 PyDict_SetItemString(d, "__version__",
980 v = PyString_FromString(VERSION));
981 PyDict_SetItemString(d, "__cdb_version__",
982 v = PyString_FromString(CDBVERSION));
983 Py_XDECREF(v);
984
985}