Release 0.32-5.5.
[python-cdb] / src / cdbmodule.c
1 /**
2 python-cdb 0.32
3 Copyright 2001, 2002 Michael J. Pomraning <mjp@pilcrow.madison.wi.us>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, 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
36 static char cdbo_object_doc[] = "\
37 This object represents a CDB database: a reliable, constant\n\
38 database mapping strings of bytes (\"keys\") to strings of bytes\n\
39 (\"data\"), and designed for fast lookups.\n\
40 \n\
41 Unlike a conventional mapping, CDBs can meaningfully store multiple\n\
42 records under one key (though this feature is not often used).\n\
43 \n\
44 A 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
67 typedef 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
78 staticforward PyTypeObject CdbType;
79
80 PyObject * CDBError;
81 #define CDBerr PyErr_SetFromErrno(CDBError)
82
83 static PyObject *
84 cdb_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
135 static char cdbo_has_key_doc[] =
136 "cdb_o.has_key(k) -> 1 (or 0)\n\
137 \n\
138 Returns true if the CDB contains key k.";
139
140 static PyObject *
141 cdbo_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
158 static char cdbo_get_doc[] =
159 "cdb_o.get(k [, i]) -> data (or None)\n\
160 \n\
161 Fetches the record stored under key k, skipping past the first i\n\
162 records under that key (default: 0). Prepares the next call to\n\
163 getnext().\n\
164 \n\
165 Assuming cdb_o.has_key(k) == 1, then all of the following return:\n\
166 the first record stored under key k:\n\
167 \n\
168 cdb_o.get(k) == cdb_o[k] == cdb_o.getall(k)[0]\n";
169
170 static PyObject *
171 cdbo_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
200 static char cdbo_getall_doc[] =
201 "cdb_o.getall(k) -> ['data', ... ]\n\
202 \n\
203 Return a list of all records stored under key k.";
204
205 static PyObject *
206 cdbo_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
244 static char cdbo_getnext_doc[] =
245 "cdb_o.getnext() -> 'data' (or None)\n\
246 \n\
247 For iteration over the records stored under one key, avoiding loading\n\
248 all items into memory). The \"current key\" is determined by the most\n\
249 recent call to get().\n\
250 \n\
251 The 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
259 static PyObject *
260 cdbo_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
286 uint32
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
311 static 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
362 static char cdbo_keys_doc[] =
363 "cdb_o.keys() -> ['k1', 'k2', ... ]\n\
364 \n\
365 Returns a list of all (distinct) keys in the database.";
366
367 static PyObject *
368 cdbo_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
404 static char cdbo_firstkey_doc[] =
405 "cdb_o.firstkey() -> key (or None)\n\
406 \n\
407 Return the first key in the database, resetting the internal\n\
408 iteration cursor. firstkey() and nextkey() may be used to\n\
409 traverse all distinct keys in the cdb. See each() for raw\n\
410 iteration.";
411
412 static PyObject *
413 cdbo_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
424 static char cdbo_nextkey_doc[] =
425 "cdb_o.nextkey() -> key (or None)\n\
426 \n\
427 Return the next distinct key in the cdb.\n\
428 \n\
429 The 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
436 static PyObject *
437 cdbo_nextkey(CdbObject *self, PyObject *args) {
438
439 if (! PyArg_ParseTuple(args, ":nextkey"))
440 return NULL;
441
442 return _cdbo_keyiter(self);
443
444 }
445
446 static char cdbo_each_doc[] =
447 "cdb_o.each() -> (key, data) (or None)\n\
448 \n\
449 Fetch the next ('key', 'data') record from the underlying cdb file,\n\
450 returning None and resetting the iteration cursor when all records\n\
451 have been fetched.\n\
452 \n\
453 Keys 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\
455 disk. Both keys() and (for GDBM fanciers) firstkey()/nextkey()-style\n\
456 iteration go to pains to present the user with only distinct keys.";
457
458 static PyObject *
459 cdbo_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
508 static int
509 cdbo_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
532 static PyObject *
533 cdbo_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
553 static PyMappingMethods cdbo_as_mapping = {
554 (inquiry)cdbo_length,
555 (binaryfunc)cdbo_subscript,
556 (objobjargproc)0
557 };
558
559 static 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
582 static 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
603 static PyObject *
604 cdbo_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
642 static void
643 cdbo_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
658 PyObject_Del((PyObject *)self);
659 }
660
661 static PyObject *
662 cdbo_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
698 static 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
709 typedef struct {
710 PyObject_HEAD
711 struct cdb_make cm;
712 PyObject * fn;
713 PyObject * fntmp;
714 } cdbmakeobject;
715
716 staticforward PyTypeObject CdbMakeType;
717
718 #define CDBMAKEerr PyErr_SetFromErrno(PyExc_IOError)
719
720
721 /* ----------------- CdbMake methods ------------------ */
722
723 static PyObject *
724 CdbMake_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
739 static PyObject *
740 CdbMake_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
765 static PyMethodDef cdbmake_methods[] = {
766 {"add", (PyCFunction)CdbMake_add, METH_VARARGS,
767 "cm.add(key, data) -> None\n\
768 \n\
769 Add 'key' -> 'data' pair to the underlying CDB." },
770 {"finish", (PyCFunction)CdbMake_finish, METH_VARARGS,
771 "cm.finish() -> None\n\
772 \n\
773 Finish safely composing a new CDB, renaming cm.fntmp to\n\
774 cm.fn." },
775 { NULL, NULL }
776 };
777
778 /* ----------------- cdbmake operations ------------------ */
779
780 static PyObject *
781 new_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
813 static void
814 cdbmake_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
826 PyObject_Del((PyObject *)self);
827 }
828
829 static PyObject *
830 cdbmake_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
856 statichere 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
884 statichere 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 ------------------ */
913 static 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
928 static PyMethodDef module_functions[] = {
929 {"init", cdbo_constructor, METH_VARARGS,
930 "cdb.init(f) -> cdb_object\n\
931 \n\
932 Open a CDB specified by f and return a cdb object.\n\
933 f 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\
938 Interface to the creation of a new CDB file \"cdb\".\n\
939 \n\
940 The cdbmake object first writes records to the temporary file\n\
941 \"tmp\" (records are inserted via the object's add() method).\n\
942 The finish() method then atomically renames \"tmp\" to \"cdb\",\n\
943 ensuring that readers of \"cdb\" need never wait for updates to\n\
944 complete."
945 },
946 {"hash", _wrap_cdb_hash, METH_VARARGS,
947 "hash(s) -> hashval\n\
948 \n\
949 Compute the 32-bit hash value of some sequence of bytes s."},
950 {NULL, NULL}
951 };
952
953 static char module_doc[] =
954 "Python adaptation of D. J. Bernstein's constant database (CDB)\n\
955 package. See <http://cr.yp.to/cdb.html>\n\
956 \n\
957 CDB objects, created by init(), provide read-only, dict-like\n\
958 access to cdb files, as well as iterative methods.\n\
959 \n\
960 CDBMake objects, created by cdbmake(), allow for creation and\n\
961 atomic replacement of CDBs.\n\
962 \n\
963 This module defines a new Exception \"error\".";
964
965 DL_EXPORT(void)
966 initcdb() {
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 }