root/lang/python/pytc/trunk/pytc.c @ 3045

Revision 3045, 54.8 kB (checked in by tasuku, 5 years ago)

made callback functions get General Interpreter Lock

Line 
1/* Copyright(C) 2007- Tasuku SUENAGA
2
3  This library is free software; you can redistribute it and/or
4  modify it under the terms of the GNU Lesser General Public
5  License as published by the Free Software Foundation; either
6  version 2.1 of the License, or (at your option) any later version.
7
8  This library is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  Lesser General Public License for more details.
12
13  You should have received a copy of the GNU Lesser General Public
14  License along with this library; if not, write to the Free Software
15  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16*/
17#include <Python.h>
18#include <tcbdb.h>
19#include <tchdb.h>
20#include <tcutil.h>
21
22/* FIXME: handle error */
23/* FIXME: refactoring */
24/* FIXME: setcmpfunc tcbdbcmplexical/decimal/cmpint32/cmpint64' */
25
26/* Error Objects */
27
28static PyObject *PyTCError;
29
30static void
31raise_pytc_error(int ecode, const char *errmsg) {
32  PyObject *obj;
33
34  obj = Py_BuildValue("(is)", ecode, errmsg);
35  PyErr_SetObject(PyTCError, obj);
36  Py_DECREF(obj);
37}
38
39static void
40raise_tchdb_error(TCHDB *hdb) {
41  int ecode = tchdbecode(hdb);
42  const char *errmsg = tchdberrmsg(ecode);
43  raise_pytc_error(ecode, errmsg);
44}
45
46static void
47raise_tcbdb_error(TCBDB *bdb) {
48  int ecode = tcbdbecode(bdb);
49  const char *errmsg = tcbdberrmsg(ecode);
50  raise_pytc_error(ecode, errmsg);
51}
52
53/* Objects */
54
55typedef struct {
56  PyObject_HEAD
57  TCHDB *hdb;
58} PyTCHDB;
59
60typedef struct {
61  PyObject_HEAD
62  TCBDB *bdb;
63  PyObject *cmp;
64  PyObject *cmpop;
65} PyTCBDB;
66
67typedef struct {
68  PyObject_HEAD
69  PyTCBDB *bdb;
70  BDBCUR *cur;
71} PyBDBCUR;
72
73/* Macros */
74
75#define BOOL_NOARGS(func,type,call,member,err,errmember) \
76  static PyObject * \
77  func(type *self) { \
78    bool result; \
79  \
80    Py_BEGIN_ALLOW_THREADS \
81    result = call(self->member); \
82    Py_END_ALLOW_THREADS \
83  \
84    if (!result) { \
85      err(self->errmember); \
86      return NULL; \
87    } \
88    Py_RETURN_NONE; \
89  }
90
91/* NOTE: this function *doesn't* dealloc pointer returned by tc */
92#define STRING_NOARGS(func,type,call,member,err) \
93  static PyObject * \
94  func(type *self) { \
95    const char *str; \
96    PyObject *ret; \
97  \
98    Py_BEGIN_ALLOW_THREADS \
99    str = call(self->member); \
100    Py_END_ALLOW_THREADS \
101  \
102    if (!str) { \
103      err(self->member); \
104      return NULL; \
105    } \
106    ret = PyString_FromString(str); \
107    return ret; \
108  } \
109
110/* NOTE: this function dealloc pointer returned by tc */
111#define STRINGL_NOARGS(func,type,call,member,err,errmember) \
112  static PyObject * \
113  func(type *self) { \
114    char *str; \
115    int str_len; \
116    PyObject *ret; \
117  \
118    Py_BEGIN_ALLOW_THREADS \
119    str = call(self->member, &str_len); \
120    Py_END_ALLOW_THREADS \
121  \
122    if (!str) { \
123      err(self->errmember); \
124      return NULL; \
125    } \
126    ret = PyString_FromStringAndSize(str, str_len); \
127    free(str); \
128    return ret; \
129  } \
130
131#define PY_NUM_NOARGS(func,type,rettype,call,member,ecode,err,conv) \
132  static PyObject * \
133  func(type *self) { \
134    rettype val; \
135  \
136    Py_BEGIN_ALLOW_THREADS \
137    val = call(self->member); \
138    Py_END_ALLOW_THREADS \
139  \
140    if (ecode(self->member)) { \
141      err(self->member); \
142      return NULL; \
143    } \
144    return conv(val); \
145  }
146
147#define PY_U_LONG_LONG_NOARGS(func,type,call,member,ecode,err) \
148  PY_NUM_NOARGS(func, type, unsigned PY_LONG_LONG, call, member, ecode, err, \
149                PyLong_FromUnsignedLongLong)
150
151#define BOOL_KEYARGS(func,type,method,call,member,error,errmember) \
152  static PyObject * \
153  func(type *self, PyObject *args, PyObject *keywds) { \
154    char *key; \
155    int key_len; \
156    bool result; \
157    static char *kwlist[] = {"key", NULL}; \
158  \
159    if (!PyArg_ParseTupleAndKeywords(args, keywds, "s#:" #method, kwlist, \
160                                     &key, &key_len)) { \
161      return NULL; \
162    } \
163    Py_BEGIN_ALLOW_THREADS \
164    result = call(self->member, key, key_len); \
165    Py_END_ALLOW_THREADS \
166  \
167    if (!result) { \
168      error(self->errmember); \
169      return NULL; \
170    } \
171    Py_RETURN_NONE; \
172  }
173
174#define INT_KEYARGS(func,type,method,call,member,error) \
175  static PyObject * \
176  func(type *self, PyObject *args, PyObject *keywds) { \
177    char *key; \
178    int key_len, ret; \
179    static char *kwlist[] = {"key", NULL}; \
180  \
181    if (!PyArg_ParseTupleAndKeywords(args, keywds, "s#:" #method, kwlist, \
182                                     &key, &key_len)) { \
183      return NULL; \
184    } \
185    Py_BEGIN_ALLOW_THREADS \
186    ret = call(self->member, key, key_len); \
187    Py_END_ALLOW_THREADS \
188  \
189    if (ret == -1) { \
190      error(self->member); \
191      return NULL; \
192    } \
193    return PyInt_FromLong((long)ret); \
194  }
195
196/* NOTE: this function dealloc pointer returned by tc */
197#define STRINGL_KEYARGS(func,type,method,call,member,error) \
198  static PyObject * \
199  func(type *self, PyObject *args, PyObject *keywds) { \
200    PyObject *ret; \
201    char *key, *value; \
202    int key_len, value_len; \
203    static char *kwlist[] = {"key", NULL}; \
204  \
205    if (!PyArg_ParseTupleAndKeywords(args, keywds, "s#:" #method, kwlist, \
206                                     &key, &key_len)) { \
207      return NULL; \
208    } \
209    Py_BEGIN_ALLOW_THREADS \
210    value = call(self->member, key, key_len, &value_len); \
211    Py_END_ALLOW_THREADS \
212  \
213    if (!value) { \
214      error(self->member); \
215      return NULL; \
216    } \
217    ret = PyString_FromStringAndSize(value, value_len); \
218    free(value); \
219    return ret; \
220  }
221
222#define PyTCXDB_PUT(func,type,method,call,member,error) \
223  static PyObject * \
224  func(type *self, PyObject *args, PyObject *keywds) { \
225    bool result; \
226    char *key, *value; \
227    int key_len, value_len; \
228    static char *kwlist[] = {"key", "value", NULL}; \
229  \
230    if (!PyArg_ParseTupleAndKeywords(args, keywds, "s#s#:" #method, kwlist, \
231                                     &key, &key_len, &value, &value_len)) { \
232      return NULL; \
233    } \
234    Py_BEGIN_ALLOW_THREADS \
235    result = call(self->member, key, key_len, value, value_len); \
236    Py_END_ALLOW_THREADS \
237  \
238    if (!result) { \
239      error(self->member); \
240      return NULL; \
241    } \
242    Py_RETURN_NONE; \
243  }
244
245#define PyTCXDB_OPEN(func,type,call_new,call_open,member,call_dealloc,error) \
246  static PyObject * \
247  func(type *self, PyObject *args, PyObject *keywds) { \
248    int omode; \
249    char *path; \
250    bool result; \
251    static char *kwlist[] = {"path", "omode", NULL}; \
252  \
253    if (!PyArg_ParseTupleAndKeywords(args, keywds, "si:open", kwlist, \
254                                     &path, &omode)) { \
255      return NULL; \
256    } \
257    Py_BEGIN_ALLOW_THREADS \
258    result = call_open(self->member, path, omode); \
259    Py_END_ALLOW_THREADS \
260    if (!result) { \
261      error(self->member); \
262      return NULL; \
263    } \
264    Py_RETURN_NONE; \
265  }
266
267#define BOOL_PATHARGS(func,type,method,call,member,error) \
268  static PyObject * \
269  func(type *self, PyObject *args, PyObject *keywds) { \
270    char *str; \
271    bool result; \
272    static char *kwlist[] = {"path", NULL}; \
273  \
274    if (!PyArg_ParseTupleAndKeywords(args, keywds, "s:" #method, kwlist, \
275                                     &str)) { \
276      return NULL; \
277    } \
278    Py_BEGIN_ALLOW_THREADS \
279    result = call(self->member, str); \
280    Py_END_ALLOW_THREADS \
281  \
282    if (!result) { \
283      error(self->member); \
284      return NULL; \
285    } \
286    Py_RETURN_NONE; \
287  }
288
289/* for internal use */
290#define TCXDB_rnum(func,type,call) \
291  static uint64_t \
292  func(type *obj) { \
293    uint64_t ret; \
294    Py_BEGIN_ALLOW_THREADS \
295    ret = call(obj); \
296    Py_END_ALLOW_THREADS \
297    return ret; \
298  }
299
300/*** TCHDB ***/
301
302#define PyTCHDB_TUNE(a,b,c) \
303  static PyObject * \
304  a(PyTCHDB *self, PyObject *args, PyObject *keywds) { \
305    bool result; \
306    char apow, fpow; \
307    PY_LONG_LONG bnum; \
308    unsigned char opts; \
309    static char *kwlist[] = {"bnum", "apow", "fpow", "opts", NULL}; \
310  \
311    if (!PyArg_ParseTupleAndKeywords(args, keywds, "LbbB:" #b, kwlist, \
312                                     &bnum, &apow, &fpow, &opts)) { \
313      return NULL; \
314    } \
315    Py_BEGIN_ALLOW_THREADS \
316    result = c(self->hdb, bnum, apow, fpow, opts); \
317    Py_END_ALLOW_THREADS \
318  \
319    if (!result) { \
320      raise_tchdb_error(self->hdb); \
321      return NULL; \
322    } \
323    Py_RETURN_NONE; \
324  }
325
326static long
327PyTCHDB_Hash(PyObject *self) {
328  PyErr_SetString(PyExc_TypeError, "HDB objects are unhashable");
329  return -1;
330}
331
332static PyObject *
333PyTCHDB_errmsg(PyTypeObject *type, PyObject *args, PyObject *keywds) {
334  int ecode;
335  static char *kwlist[] = {"ecode", NULL};
336
337  if (!PyArg_ParseTupleAndKeywords(args, keywds, "i:errmsg", kwlist,
338                                   &ecode)) {
339    return NULL;
340  }
341  return PyString_FromString(tchdberrmsg(ecode));
342}
343
344static void
345PyTCHDB_dealloc(PyTCHDB *self)
346{
347  /* NOTE: tchdbsel closes hdb implicitly */
348  /*
349  if (self->hdb->flags & HDBFOPEN) {
350    Py_BEGIN_ALLOW_THREADS
351    tchdbclose(self->hdb);
352    Py_END_ALLOW_THREADS
353  }
354  */
355  if (self->hdb) {
356    Py_BEGIN_ALLOW_THREADS
357    tchdbdel(self->hdb);
358    Py_END_ALLOW_THREADS
359  }
360  self->ob_type->tp_free(self);
361}
362
363static PyObject *
364PyTCHDB_new(PyTypeObject *type, PyObject *args, PyObject *keywds)
365{
366  PyTCHDB *self;
367  if (!(self = (PyTCHDB *)type->tp_alloc(type, 0))) {
368    PyErr_SetString(PyExc_MemoryError, "Cannot alloc PyTCHDB instance");
369    return NULL;
370  }
371  if ((self->hdb = tchdbnew())) {
372    int omode = 0;
373    char *path = NULL;
374    static char *kwlist[] = {"path", "omode", NULL};
375
376    if (PyArg_ParseTupleAndKeywords(args, keywds, "|si:open", kwlist,
377                                    &path, &omode)) {
378      if (path && omode) {
379        bool result;
380        Py_BEGIN_ALLOW_THREADS
381        result = tchdbopen(self->hdb, path, omode);
382        Py_END_ALLOW_THREADS
383        if (result) {
384          return (PyObject *)self;
385        }
386      } else {
387        return (PyObject *)self;
388      }
389      raise_tchdb_error(self->hdb);
390    }
391  } else {
392    PyErr_SetString(PyExc_MemoryError, "Cannot alloc TCHDB instance");
393  }
394  PyTCHDB_dealloc(self);
395  return NULL;
396}
397
398static PyObject *
399PyTCHDB_ecode(PyTCHDB *self) {
400  return PyInt_FromLong((long)tchdbecode(self->hdb));
401}
402
403BOOL_NOARGS(PyTCHDB_setmutex,PyTCHDB,tchdbsetmutex,hdb,raise_tchdb_error,hdb)
404PyTCHDB_TUNE(PyTCHDB_tune, tune, tchdbtune)
405PyTCXDB_OPEN(PyTCHDB_open,PyTCHDB,PyTCHDB_new,tchdbopen,hdb,PyTCHDB_dealloc,raise_tchdb_error)
406BOOL_NOARGS(PyTCHDB_close,PyTCHDB,tchdbclose,hdb,raise_tchdb_error,hdb)
407PyTCXDB_PUT(PyTCHDB_put, PyTCHDB, put, tchdbput, hdb, raise_tchdb_error)
408PyTCXDB_PUT(PyTCHDB_putkeep, PyTCHDB, putkeep, tchdbputkeep, hdb, raise_tchdb_error)
409PyTCXDB_PUT(PyTCHDB_putcat, PyTCHDB, putcat, tchdbputcat, hdb, raise_tchdb_error)
410PyTCXDB_PUT(PyTCHDB_putasync, PyTCHDB, putasync, tchdbputasync, hdb, raise_tchdb_error)
411BOOL_KEYARGS(PyTCHDB_out,PyTCHDB,out,tchdbout,hdb,raise_tchdb_error,hdb)
412STRINGL_KEYARGS(PyTCHDB_get,PyTCHDB,get,tchdbget,hdb,raise_tchdb_error)
413INT_KEYARGS(PyTCHDB_vsiz,PyTCHDB,vsiz,tchdbvsiz,hdb,raise_tchdb_error)
414BOOL_NOARGS(PyTCHDB_iterinit,PyTCHDB,tchdbiterinit,hdb,raise_tchdb_error,hdb)
415
416static PyObject *
417PyTCHDB_GetIter(PyObject *self) {
418  if (PyTCHDB_iterinit((PyTCHDB *)self)) {
419    Py_INCREF(self);
420    return self;
421  }
422  return NULL;
423}
424
425static PyObject *
426PyTCHDB_iternext(PyTCHDB *self) {
427  void *key;
428  int key_len;
429
430  Py_BEGIN_ALLOW_THREADS
431  key = tchdbiternext(self->hdb, &key_len);
432  Py_END_ALLOW_THREADS
433
434  if (key) {
435    PyObject *_key;
436    _key = PyString_FromStringAndSize(key, key_len);
437    free(key);
438    return _key;
439  }
440  return NULL;
441}
442
443BOOL_NOARGS(PyTCHDB_sync,PyTCHDB,tchdbsync,hdb,raise_tchdb_error,hdb)
444PyTCHDB_TUNE(PyTCHDB_optimize, optimize, tchdboptimize)
445STRING_NOARGS(PyTCHDB_path,PyTCHDB,tchdbpath,hdb,raise_tchdb_error)
446PY_U_LONG_LONG_NOARGS(PyTCHDB_rnum, PyTCHDB, tchdbrnum, hdb, tchdbecode, raise_tchdb_error)
447PY_U_LONG_LONG_NOARGS(PyTCHDB_fsiz, PyTCHDB, tchdbrnum, hdb, tchdbecode, raise_tchdb_error)
448BOOL_NOARGS(PyTCHDB_vanish,PyTCHDB,tchdbvanish,hdb,raise_tchdb_error,hdb)
449BOOL_PATHARGS(PyTCHDB_copy, PyTCHDB, copy, tchdbcopy, hdb, raise_tchdb_error)
450
451/* TODO: features for experts */
452
453static int
454PyTCHDB_Contains(PyTCHDB *self, PyObject *_key) {
455  char *key = PyString_AS_STRING(_key);
456  int key_len = PyString_GET_SIZE(_key), value_len;
457
458  if (!key || !key_len) {
459    return -1;
460  }
461  Py_BEGIN_ALLOW_THREADS
462  value_len = tchdbvsiz(self->hdb, key, key_len);
463  Py_END_ALLOW_THREADS
464
465  return (value_len != -1);
466}
467
468static PyObject *
469PyTCHDB___contains__(PyTCHDB *self, PyObject *_key) {
470  return PyBool_FromLong(PyTCHDB_Contains(self, _key) != 0);
471}
472
473static PyObject *
474PyTCHDB___getitem__(PyTCHDB *self, PyObject *_key) {
475  PyObject *ret;
476  char *key = PyString_AS_STRING(_key), *value;
477  int key_len = PyString_GET_SIZE(_key), value_len;
478
479  if (!key || !key_len) {
480    return NULL;
481  }
482  Py_BEGIN_ALLOW_THREADS
483  value = tchdbget(self->hdb, key, key_len, &value_len);
484  Py_END_ALLOW_THREADS
485
486  if (!value) {
487    raise_tchdb_error(self->hdb);
488    return NULL;
489  }
490  ret = PyString_FromStringAndSize(value, value_len);
491  free(value);
492  return ret;
493}
494
495TCXDB_rnum(TCHDB_rnum,TCHDB,tchdbrnum)
496
497static PyObject *
498PyTCHDB_keys(PyTCHDB *self) {
499  int i;
500  PyObject *ret;
501  if (!PyTCHDB_iterinit((PyTCHDB *)self) ||
502      !(ret = PyList_New(TCHDB_rnum(self->hdb)))) {
503    return NULL;
504  }
505  for (i = 0; ; i++) {
506    char *key;
507    int key_len;
508    PyObject *_key;
509
510    Py_BEGIN_ALLOW_THREADS
511    key = tchdbiternext(self->hdb, &key_len);
512    Py_END_ALLOW_THREADS
513    if (!key) { break; }
514    _key = PyString_FromStringAndSize(key, key_len);
515    free(key);
516    if (!_key) {
517      Py_DECREF(ret);
518      return NULL;
519    }
520    PyList_SET_ITEM(ret, i, _key);
521  }
522  return ret;
523}
524
525static PyObject *
526PyTCHDB_items(PyTCHDB *self) {
527  int i, n = TCHDB_rnum(self->hdb);
528  PyObject *ret, *item;
529  if (!PyTCHDB_iterinit((PyTCHDB *)self) ||
530      !(ret = PyList_New(n))) {
531    return NULL;
532  }
533  for (i = 0; i < n; i++) {
534    if (!(item = PyTuple_New(2))) {
535      Py_DECREF(ret);
536      return NULL;
537    }
538    PyList_SET_ITEM(ret, i, item);
539  }
540  for (i = 0; ; i++) {
541    char *key, *value;
542    int key_len, value_len;
543
544    Py_BEGIN_ALLOW_THREADS
545    key = tchdbiternext(self->hdb, &key_len);
546    Py_END_ALLOW_THREADS
547    if (!key) { break; }
548
549    Py_BEGIN_ALLOW_THREADS
550    value = tchdbget(self->hdb, key, key_len, &value_len);
551    Py_END_ALLOW_THREADS
552
553    if (value) {
554      PyObject *_key, *_value;
555      _key = PyString_FromStringAndSize(key, key_len);
556      free(key);
557      if (!_key) {
558        Py_DECREF(ret);
559        return NULL;
560      }
561      _value = PyString_FromStringAndSize(value, value_len);
562      free(value);
563      if (!_value) {
564        Py_DECREF(_key);
565        Py_DECREF(ret);
566        return NULL;
567      }
568      item = PyList_GET_ITEM(ret, i);
569      PyTuple_SET_ITEM(item, 0, _key);
570      PyTuple_SET_ITEM(item, 1, _value);
571    } else {
572      free(key);
573    }
574  }
575  return ret;
576}
577
578static PyObject *
579PyTCHDB_values(PyTCHDB *self) {
580  int i;
581  PyObject *ret;
582  if (!PyTCHDB_iterinit((PyTCHDB *)self) ||
583      !(ret = PyList_New(TCHDB_rnum(self->hdb)))) {
584    return NULL;
585  }
586  for (i = 0; ; i++) {
587    char *key, *value;
588    int key_len, value_len;
589
590    Py_BEGIN_ALLOW_THREADS
591    key = tchdbiternext(self->hdb, &key_len);
592    Py_END_ALLOW_THREADS
593
594    if (!key) { break; }
595
596    Py_BEGIN_ALLOW_THREADS
597    value = tchdbget(self->hdb, key, key_len, &value_len);
598    Py_END_ALLOW_THREADS
599    free(key);
600
601    if (value) {
602      PyObject *_value;
603      _value = PyString_FromStringAndSize(value, value_len);
604      free(value);
605      if (!_value) {
606        Py_DECREF(ret);
607        return NULL;
608      }
609      PyList_SET_ITEM(ret, i, _value);
610    }
611  }
612  return ret;
613}
614
615static long
616PyTCHDB_length(PyTCHDB *self) {
617  return TCHDB_rnum(self->hdb);
618}
619
620static PyObject *
621PyTCHDB_subscript(PyTCHDB *self, PyObject *_key) {
622  PyObject *ret;
623  char *key = PyString_AS_STRING(_key), *value;
624  int key_len = PyString_GET_SIZE(_key), value_len;
625
626  if (!key || !key_len) {
627    return NULL;
628  }
629  Py_BEGIN_ALLOW_THREADS
630  value = tchdbget(self->hdb, key, key_len, &value_len);
631  Py_END_ALLOW_THREADS
632
633  if (!value) {
634    raise_tchdb_error(self->hdb);
635    return NULL;
636  }
637  ret = PyString_FromStringAndSize(value, value_len);
638  free(value);
639  return ret;
640}
641
642int
643PyTCHDB_DelItem(PyTCHDB *self, PyObject *_key) {
644  bool result;
645  char *key = PyString_AS_STRING(_key);
646  int key_len = PyString_GET_SIZE(_key);
647
648  if (!key || !key_len) {
649    return -1;
650  }
651  Py_BEGIN_ALLOW_THREADS
652  result = tchdbout(self->hdb, key, key_len);
653  Py_END_ALLOW_THREADS
654
655  if (!result) {
656    raise_tchdb_error(self->hdb);
657    return -1;
658  }
659  return 0;
660}
661
662int
663PyTCHDB_SetItem(PyTCHDB *self, PyObject *_key, PyObject *_value) {
664  bool result;
665  char *key = PyString_AS_STRING(_key), *value = PyString_AS_STRING(_value);
666  int key_len = PyString_GET_SIZE(_key), value_len = PyString_GET_SIZE(_value);
667
668  if (!key || !key_len || !value) {
669    return -1;
670  }
671  Py_BEGIN_ALLOW_THREADS
672  result = tchdbput(self->hdb, key, key_len, value, value_len);
673  Py_END_ALLOW_THREADS
674
675  if (!result) {
676    raise_tchdb_error(self->hdb);
677    return -1;
678  }
679  return 0;
680}
681
682static int
683PyTCHDB_ass_sub(PyTCHDB *self, PyObject *v, PyObject *w)
684{
685  if (w) {
686    return PyTCHDB_SetItem(self, v, w);
687  } else {
688    return PyTCHDB_DelItem(self, v);
689  }
690}
691
692/* methods of classes */
693static PyMethodDef PyTCHDB_methods[] = {
694  {"errmsg", (PyCFunction)PyTCHDB_errmsg,
695   METH_VARARGS | METH_KEYWORDS | METH_CLASS,
696   "Get the message string corresponding to an error code."},
697  {"ecode", (PyCFunction)PyTCHDB_ecode,
698   METH_NOARGS,
699   "Get the last happened error code of a hash database object."},
700  {"setmutex", (PyCFunction)PyTCHDB_setmutex,
701   METH_NOARGS,
702   "Set mutual exclusion control of a hash database object for threading."},
703  {"tune", (PyCFunction)PyTCHDB_tune,
704   METH_VARARGS | METH_KEYWORDS,
705   "Set the tuning parameters of a hash database object."},
706  {"open", (PyCFunction)PyTCHDB_open,
707   METH_VARARGS | METH_KEYWORDS,
708   "Open a database file and connect a hash database object."},
709  {"close", (PyCFunction)PyTCHDB_close,
710   METH_NOARGS,
711   "Close a hash database object."},
712  {"put", (PyCFunction)PyTCHDB_put,
713   METH_VARARGS | METH_KEYWORDS,
714   "Store a record into a hash database object."},
715  {"putkeep", (PyCFunction)PyTCHDB_putkeep,
716   METH_VARARGS | METH_KEYWORDS,
717   "Store a new record into a hash database object."},
718  {"putcat", (PyCFunction)PyTCHDB_putcat,
719   METH_VARARGS | METH_KEYWORDS,
720   "Concatenate a value at the end of the existing record in a hash database object."},
721  {"putasync", (PyCFunction)PyTCHDB_putasync,
722   METH_VARARGS | METH_KEYWORDS,
723   "Store a record into a hash database object in asynchronous fashion."},
724  {"out", (PyCFunction)PyTCHDB_out,
725   METH_VARARGS | METH_KEYWORDS,
726   "Remove a record of a hash database object."},
727  {"get", (PyCFunction)PyTCHDB_get,
728   METH_VARARGS | METH_KEYWORDS,
729   "Retrieve a record in a hash database object."},
730  {"vsiz", (PyCFunction)PyTCHDB_vsiz,
731   METH_VARARGS | METH_KEYWORDS,
732   "Get the size of the value of a record in a hash database object."},
733  {"iterinit", (PyCFunction)PyTCHDB_iterinit,
734   METH_NOARGS,
735   "Initialize the iterator of a hash database object."},
736  {"iternext", (PyCFunction)PyTCHDB_iternext,
737   METH_NOARGS,
738   "Get the next extensible objects of the iterator of a hash database object."},
739  {"sync", (PyCFunction)PyTCHDB_sync,
740   METH_NOARGS,
741   "Synchronize updated contents of a hash database object with the file and the device."},
742  {"optimize", (PyCFunction)PyTCHDB_optimize,
743   METH_VARARGS | METH_KEYWORDS,
744   "Optimize the file of a hash database object."},
745  {"vanish", (PyCFunction)PyTCHDB_vanish,
746   METH_NOARGS,
747   "Remove all records of a hash database object."},
748  {"path", (PyCFunction)PyTCHDB_path,
749   METH_NOARGS,
750   "Get the file path of a hash database object."},
751  {"copy", (PyCFunction)PyTCHDB_copy,
752   METH_VARARGS | METH_KEYWORDS,
753   "Copy the database file of a hash database object."},
754  {"rnum", (PyCFunction)PyTCHDB_rnum,
755   METH_NOARGS,
756   "Get the number of records of a hash database object."},
757  {"fsiz", (PyCFunction)PyTCHDB_fsiz,
758   METH_NOARGS,
759   "Get the size of the database file of a hash database object."},
760  {"__contains__", (PyCFunction)PyTCHDB___contains__,
761   METH_O | METH_COEXIST,
762   ""},
763  {"__getitem__", (PyCFunction)PyTCHDB___getitem__,
764   METH_O | METH_COEXIST,
765   ""},
766  {"has_key", (PyCFunction)PyTCHDB___contains__,
767   METH_O,
768   ""},
769  {"keys", (PyCFunction)PyTCHDB_keys,
770   METH_NOARGS,
771   ""},
772  {"items", (PyCFunction)PyTCHDB_items,
773   METH_NOARGS,
774   ""},
775  {"values", (PyCFunction)PyTCHDB_values,
776   METH_NOARGS,
777   ""},
778  /*
779  {"", (PyCFunction)PyTCHDB_,
780   METH_VARARGS | METH_KEYWORDS,
781   ""},
782  */
783  {NULL, NULL, 0, NULL}
784};
785
786
787/* Hack to implement "key in dict" */
788static PySequenceMethods PyTCHDB_as_sequence = {
789  0,                             /* sq_length */
790  0,                             /* sq_concat */
791  0,                             /* sq_repeat */
792  0,                             /* sq_item */
793  0,                             /* sq_slice */
794  0,                             /* sq_ass_item */
795  0,                             /* sq_ass_slice */
796  (objobjproc)PyTCHDB_Contains,  /* sq_contains */
797  0,                             /* sq_inplace_concat */
798  0,                             /* sq_inplace_repeat */
799};
800
801static PyMappingMethods PyTCHDB_as_mapping = {
802  (inquiry)PyTCHDB_length, /* mp_length (inquiry/lenfunc )*/
803  (binaryfunc)PyTCHDB_subscript, /* mp_subscript */
804  (objobjargproc)PyTCHDB_ass_sub, /* mp_ass_subscript */
805};
806
807static PyTypeObject PyTCHDB_Type = {
808  PyObject_HEAD_INIT(NULL)
809  0,                                           /* ob_size */
810  "pytc.HDB",                                  /* tp_name */
811  sizeof(PyTCHDB),                             /* tp_basicsize */
812  0,                                           /* tp_itemsize */
813  (destructor)PyTCHDB_dealloc,                 /* tp_dealloc */
814  0,                                           /* tp_print */
815  0,                                           /* tp_getattr */
816  0,                                           /* tp_setattr */
817  0,                                           /* tp_compare */
818  0,                                           /* tp_repr */
819  0,                                           /* tp_as_number */
820  &PyTCHDB_as_sequence,                        /* tp_as_sequence */
821  &PyTCHDB_as_mapping,                         /* tp_as_mapping */
822  PyTCHDB_Hash,                                /* tp_hash  */
823  0,                                           /* tp_call */
824  0,                                           /* tp_str */
825  0,                                           /* tp_getattro */
826  0,                                           /* tp_setattro */
827  0,                                           /* tp_as_buffer */
828  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,    /* tp_flags */
829  "tchdb",                                     /* tp_doc */
830  0,                                           /* tp_traverse */
831  0,                                           /* tp_clear */
832  0,                                           /* tp_richcompare */
833  0,                                           /* tp_weaklistoffset */
834  PyTCHDB_GetIter,                             /* tp_iter */
835  (iternextfunc)PyTCHDB_iternext,              /* tp_iternext */
836  PyTCHDB_methods,                             /* tp_methods */
837  0,                                           /* tp_members */
838  0,                                           /* tp_getset */
839  0,                                           /* tp_base */
840  0,                                           /* tp_dict */
841  0,                                           /* tp_descr_get */
842  0,                                           /* tp_descr_set */
843  0,                                           /* tp_dictoffset */
844  0,                                           /* tp_init */
845  0,                                           /* tp_alloc */
846  PyTCHDB_new,                                 /* tp_new */
847};
848
849/* BDBCUR */
850
851static PyTypeObject PyTCBDB_Type;
852
853static PyObject *
854PyBDBCUR_new(PyTypeObject *type, PyObject *args, PyObject *keywds)
855{
856  PyTCBDB *bdb;
857  PyBDBCUR *self;
858  static char *kwlist[] = {"bdb", NULL};
859
860  if (!PyArg_ParseTupleAndKeywords(args, keywds, "O!:new", kwlist,
861                                   &PyTCBDB_Type, &bdb)) {
862    return NULL;
863  }
864  if (!(self = (PyBDBCUR *)type->tp_alloc(type, 0))) {
865    PyErr_SetString(PyExc_MemoryError, "Cannot alloc PyBDBCUR instance");
866    return NULL;
867  }
868
869  Py_BEGIN_ALLOW_THREADS
870  self->cur = tcbdbcurnew(bdb->bdb);
871  Py_END_ALLOW_THREADS
872
873  if (!self->cur) {
874    self->ob_type->tp_free(self);
875    raise_tcbdb_error(bdb->bdb);
876    return NULL;
877  }
878  Py_INCREF(bdb);
879  self->bdb = bdb;
880  return (PyObject *)self;
881}
882
883static PyObject *
884PyBDBCUR_dealloc(PyBDBCUR *self)
885{
886  Py_BEGIN_ALLOW_THREADS
887  tcbdbcurdel(self->cur);
888  Py_END_ALLOW_THREADS
889  Py_XDECREF(self->bdb);
890  self->ob_type->tp_free(self);
891  Py_RETURN_NONE;
892}
893
894BOOL_NOARGS(PyBDBCUR_first,PyBDBCUR,tcbdbcurfirst,cur,raise_tcbdb_error,bdb->bdb)
895BOOL_NOARGS(PyBDBCUR_last,PyBDBCUR,tcbdbcurlast,cur,raise_tcbdb_error,bdb->bdb)
896BOOL_KEYARGS(PyBDBCUR_jump,PyBDBCUR,jump,tcbdbcurjump,cur,raise_tcbdb_error,bdb->bdb)
897BOOL_NOARGS(PyBDBCUR_prev,PyBDBCUR,tcbdbcurprev,cur,raise_tcbdb_error,bdb->bdb)
898BOOL_NOARGS(PyBDBCUR_next,PyBDBCUR,tcbdbcurnext,cur,raise_tcbdb_error,bdb->bdb)
899
900static PyObject *
901PyBDBCUR_put(PyBDBCUR *self, PyObject *args, PyObject *keywds) {
902  bool result;
903  char *value;
904  int value_len, cpmode;
905  static char *kwlist[] = {"value", "cpmode", NULL};
906
907  if (!PyArg_ParseTupleAndKeywords(args, keywds, "s#i:put", kwlist,
908                                   &value, &value_len, &cpmode)) {
909    return NULL;
910  }
911  Py_BEGIN_ALLOW_THREADS
912  result = tcbdbcurput(self->cur, value, value_len, cpmode);
913  Py_END_ALLOW_THREADS
914
915  if (!result) {
916    raise_tcbdb_error(self->bdb->bdb);
917    return NULL;
918  }
919  Py_RETURN_NONE;
920}
921
922BOOL_NOARGS(PyBDBCUR_out,PyBDBCUR,tcbdbcurout,cur,raise_tcbdb_error,bdb->bdb)
923STRINGL_NOARGS(PyBDBCUR_key,PyBDBCUR,tcbdbcurkey,cur,raise_tcbdb_error,bdb->bdb)
924STRINGL_NOARGS(PyBDBCUR_val,PyBDBCUR,tcbdbcurval,cur,raise_tcbdb_error,bdb->bdb)
925
926static PyObject *
927PyBDBCUR_rec(PyBDBCUR *self) {
928  PyObject *ret = NULL;
929  TCXSTR *key, *value;
930
931  key = tcxstrnew();
932  value = tcxstrnew();
933  if (key && value) {
934    bool result;
935
936    Py_BEGIN_ALLOW_THREADS
937    result = tcbdbcurrec(self->cur, key, value);
938    Py_END_ALLOW_THREADS
939
940    if (result) {
941      ret = Py_BuildValue("(s#s#)", tcxstrptr(key), tcxstrsize(key),
942                                    tcxstrptr(value), tcxstrsize(value));
943    }
944  }
945  if (!ret) {
946    raise_tcbdb_error(self->bdb->bdb);
947  }
948  if (key) { tcxstrdel(key); }
949  if (value) { tcxstrdel(value); }
950  return ret;
951}
952
953static PyObject *
954PyBDBCUR_iternext(PyBDBCUR *self) {
955  char *key;
956  int key_len;
957  PyObject *ret;
958
959  Py_BEGIN_ALLOW_THREADS
960  key = tcbdbcurkey(self->cur, &key_len);
961  Py_END_ALLOW_THREADS
962
963  if (key) {
964    ret = PyString_FromStringAndSize(key, key_len);
965    free(key);
966    Py_BEGIN_ALLOW_THREADS
967    tcbdbcurnext(self->cur);
968    Py_END_ALLOW_THREADS
969    return ret;
970  }
971  return NULL;
972}
973
974static PyMethodDef PyBDBCUR_methods[] = {
975  {"first", (PyCFunction)PyBDBCUR_first,
976   METH_NOARGS,
977   "Move a cursor object to the first record."},
978  {"last", (PyCFunction)PyBDBCUR_last,
979   METH_NOARGS,
980   "Move a cursor object to the last record."},
981  {"jump", (PyCFunction)PyBDBCUR_jump,
982   METH_VARARGS | METH_KEYWORDS,
983   "Move a cursor object to the front of records corresponding a key."},
984  {"prev", (PyCFunction)PyBDBCUR_prev,
985   METH_NOARGS,
986   "Move a cursor object to the previous record."},
987  {"next", (PyCFunction)PyBDBCUR_next,
988   METH_NOARGS,
989   "Move a cursor object to the next record."},
990  {"put", (PyCFunction)PyBDBCUR_put,
991   METH_VARARGS | METH_KEYWORDS,
992   "Insert a record around a cursor object."},
993  {"out", (PyCFunction)PyBDBCUR_out,
994   METH_NOARGS,
995   "Delete the record where a cursor object is."},
996  {"key", (PyCFunction)PyBDBCUR_key,
997   METH_NOARGS,
998   "Get the key of the record where the cursor object is."},
999  {"val", (PyCFunction)PyBDBCUR_val,
1000   METH_NOARGS,
1001   "Get the value of the record where the cursor object is."},
1002  {"rec", (PyCFunction)PyBDBCUR_rec,
1003   METH_NOARGS,
1004   "Get the key and the value of the record where the cursor object is."},
1005  /*
1006  {"", (PyCFunction)PyBDBCUR_,
1007   METH_VARARGS | METH_KEYWORDS,
1008   ""},
1009  */
1010  {NULL, NULL, 0, NULL}
1011};
1012
1013static PyTypeObject PyBDBCUR_Type = {
1014  PyObject_HEAD_INIT(NULL)
1015  0,                                           /* ob_size */
1016  "pytc.BDBCUR",                               /* tp_name */
1017  sizeof(PyBDBCUR),                            /* tp_basicsize */
1018  0,                                           /* tp_itemsize */
1019  (destructor)PyBDBCUR_dealloc,                /* tp_dealloc */
1020  0,                                           /* tp_print */
1021  0,                                           /* tp_getattr */
1022  0,                                           /* tp_setattr */
1023  0,                                           /* tp_compare */
1024  0,                                           /* tp_repr */
1025  0,                                           /* tp_as_number */
1026  0,                                           /* tp_as_sequence */
1027  0,                                           /* tp_as_mapping */
1028  0,                                           /* tp_hash  */
1029  0,                                           /* tp_call */
1030  0,                                           /* tp_str */
1031  0,                                           /* tp_getattro */
1032  0,                                           /* tp_setattro */
1033  0,                                           /* tp_as_buffer */
1034  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,    /* tp_flags */
1035  "bdbcur",                                    /* tp_doc */
1036  0,                                           /* tp_traverse */
1037  0,                                           /* tp_clear */
1038  0,                                           /* tp_richcompare */
1039  0,                                           /* tp_weaklistoffset */
1040  PyObject_SelfIter,                           /* tp_iter */
1041  (iternextfunc)PyBDBCUR_iternext,             /* tp_iternext */
1042  PyBDBCUR_methods,                            /* tp_methods */
1043  0,                                           /* tp_members */
1044  0,                                           /* tp_getset */
1045  0,                                           /* tp_base */
1046  0,                                           /* tp_dict */
1047  0,                                           /* tp_descr_get */
1048  0,                                           /* tp_descr_set */
1049  0,                                           /* tp_dictoffset */
1050  0,                                           /* tp_init */
1051  0,                                           /* tp_alloc */
1052  PyBDBCUR_new,                                /* tp_new */
1053};
1054
1055/*** TCBDB ***/
1056
1057#define PyTCBDB_TUNE(a,b,c) \
1058  static PyObject * \
1059  a(PyTCBDB *self, PyObject *args, PyObject *keywds) { \
1060    bool result; \
1061    char apow, fpow; \
1062    int lmemb, nmemb; \
1063    PY_LONG_LONG bnum; \
1064    unsigned char opts; \
1065    static char *kwlist[] = {"lmemb", "nmemb", "bnum", "apow", "fpow", "opts", NULL}; \
1066  \
1067    if (!PyArg_ParseTupleAndKeywords(args, keywds, "iiLbbB:" #b, kwlist, \
1068                                     &lmemb, &nmemb, &bnum, \
1069                                     &apow, &fpow, &opts)) { \
1070      return NULL; \
1071    } \
1072    Py_BEGIN_ALLOW_THREADS \
1073    result = c(self->bdb, lmemb, nmemb, bnum, apow, fpow, opts); \
1074    Py_END_ALLOW_THREADS \
1075  \
1076    if (!result) { \
1077      raise_tcbdb_error(self->bdb); \
1078      return NULL; \
1079    } \
1080    Py_RETURN_NONE; \
1081  }
1082
1083static long
1084PyTCBDB_Hash(PyObject *self) {
1085  PyErr_SetString(PyExc_TypeError, "BDB objects are unhashable");
1086  return -1;
1087}
1088
1089static PyObject *
1090PyTCBDB_errmsg(PyTypeObject *type, PyObject *args, PyObject *keywds) {
1091  int ecode;
1092  static char *kwlist[] = {"ecode", NULL};
1093
1094  if (!PyArg_ParseTupleAndKeywords(args, keywds, "i:errmsg", kwlist,
1095                                   &ecode)) {
1096    return NULL;
1097  }
1098  return PyString_FromString(tcbdberrmsg(ecode));
1099}
1100
1101static void
1102PyTCBDB_dealloc(PyTCBDB *self)
1103{
1104  /* NOTE: tcbdbsel closes bdb implicitly */
1105  /*
1106  if (self->bdb->flags & BDBFOPEN) {
1107    Py_BEGIN_ALLOW_THREADS
1108    tcbdbclose(self->bdb);
1109    Py_END_ALLOW_THREADS
1110  }
1111  */
1112  Py_XDECREF(self->cmp);
1113  Py_XDECREF(self->cmpop);
1114  if (self->bdb) {
1115    Py_BEGIN_ALLOW_THREADS
1116    tcbdbdel(self->bdb);
1117    Py_END_ALLOW_THREADS
1118  }
1119  self->ob_type->tp_free(self);
1120}
1121
1122static PyObject *
1123PyTCBDB_new(PyTypeObject *type, PyObject *args, PyObject *keywds)
1124{
1125  PyTCBDB *self;
1126  if (!(self = (PyTCBDB *)type->tp_alloc(type, 0))) {
1127    PyErr_SetString(PyExc_MemoryError, "Cannot alloc PyTCBDB instance");
1128    return NULL;
1129  }
1130  /* NOTE: initialize member implicitly */
1131  self->cmp = self->cmpop = NULL;
1132  if ((self->bdb = tcbdbnew())) {
1133    int omode = 0;
1134    char *path = NULL;
1135    static char *kwlist[] = {"path", "omode", NULL};
1136
1137    if (PyArg_ParseTupleAndKeywords(args, keywds, "|si:open", kwlist,
1138                                    &path, &omode)) {
1139      if (path && omode) {
1140        bool result;
1141        Py_BEGIN_ALLOW_THREADS
1142        result = tcbdbopen(self->bdb, path, omode);
1143        Py_END_ALLOW_THREADS
1144        if (result) {
1145          return (PyObject *)self;
1146        }
1147      } else {
1148        return (PyObject *)self;
1149      }
1150      raise_tcbdb_error(self->bdb);
1151    }
1152  } else {
1153    PyErr_SetString(PyExc_MemoryError, "Cannot alloc TCBDB instance");
1154  }
1155  PyTCBDB_dealloc(self);
1156  return NULL;
1157}
1158static PyObject *
1159PyTCBDB_ecode(PyTCBDB *self) {
1160  return PyInt_FromLong((long)tcbdbecode(self->bdb));
1161}
1162
1163BOOL_NOARGS(PyTCBDB_setmutex,PyTCBDB,tcbdbsetmutex,bdb,raise_tcbdb_error,bdb)
1164
1165static int
1166TCBDB_cmpfunc(const char *aptr, int asiz,
1167              const char *bptr, int bsiz, PyTCBDB *self) {
1168  int ret = 0;
1169  PyObject *args, *result;
1170  PyGILState_STATE gstate;
1171
1172  if ((args = Py_BuildValue("(s#s#O)", aptr, asiz, bptr, bsiz, self->cmpop))) {
1173    /* TODO: set error */
1174    return 0;
1175  }
1176  gstate = PyGILState_Ensure();
1177  result = PyEval_CallObject(self->cmp, args);
1178  Py_DECREF(args);
1179  if (!result) {
1180    /* TODO: set error */
1181    goto exit;
1182  }
1183  ret = PyLong_AsLong(result);
1184  Py_DECREF(result);
1185exit:
1186  PyGILState_Release(gstate);
1187  return ret;
1188}
1189
1190static PyObject *
1191PyTCBDB_setcmpfunc(PyTCBDB *self, PyObject *args, PyObject *keywds) {
1192  bool result;
1193  PyObject *cmp, *cmpop = NULL;
1194  static char *kwlist[] = {"cmp", "cmpop", NULL};
1195
1196  if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|O:setcmpfunc", kwlist,
1197                                   &cmp, &cmpop)
1198      || !PyCallable_Check(cmp)) {
1199    return NULL;
1200  }
1201  if (!cmpop) {
1202    Py_INCREF(Py_None);
1203    cmpop = Py_None;
1204  }
1205
1206  Py_INCREF(cmp);
1207  Py_XINCREF(cmpop);
1208  Py_XDECREF(self->cmp);
1209  Py_XDECREF(self->cmpop);
1210  self->cmp = cmp;
1211  self->cmpop = cmpop;
1212
1213  Py_BEGIN_ALLOW_THREADS
1214  result = tcbdbsetcmpfunc(self->bdb,
1215                           (BDBCMP)TCBDB_cmpfunc, self);
1216  Py_END_ALLOW_THREADS
1217
1218  if (!result) {
1219    raise_tcbdb_error(self->bdb);
1220    Py_DECREF(self->cmp);
1221    Py_XDECREF(self->cmpop);
1222    self->cmp = self->cmpop = NULL;
1223    return NULL;
1224  }
1225  Py_RETURN_NONE;
1226}
1227
1228PyTCBDB_TUNE(PyTCBDB_tune, tune, tcbdbtune)
1229
1230static PyObject *
1231PyTCBDB_setcache(PyTCBDB *self, PyObject *args, PyObject *keywds) {
1232  int lcnum, ncnum;
1233  bool result;
1234  static char *kwlist[] = {"lcnum", "ncnum", NULL};
1235
1236  if (!PyArg_ParseTupleAndKeywords(args, keywds, "ii:setcache", kwlist,
1237                                   &lcnum, &ncnum)) {
1238    return NULL;
1239  }
1240  Py_BEGIN_ALLOW_THREADS
1241  result = tcbdbsetcache(self->bdb, lcnum, ncnum);
1242  Py_END_ALLOW_THREADS
1243
1244  if (!result) {
1245    raise_tcbdb_error(self->bdb);
1246    return NULL;
1247  }
1248  Py_RETURN_NONE;
1249}
1250
1251PyTCXDB_OPEN(PyTCBDB_open,PyTCBDB,PyTCBDB_new,tcbdbopen,bdb,PyTCBDB_dealloc,raise_tcbdb_error)
1252BOOL_NOARGS(PyTCBDB_close,PyTCBDB,tcbdbclose,bdb,raise_tcbdb_error,bdb)
1253PyTCXDB_PUT(PyTCBDB_put, PyTCBDB, put, tcbdbput, bdb, raise_tcbdb_error)
1254PyTCXDB_PUT(PyTCBDB_putkeep, PyTCBDB, putkeep, tcbdbputkeep, bdb, raise_tcbdb_error)
1255PyTCXDB_PUT(PyTCBDB_putcat, PyTCBDB, putcat, tcbdbputcat, bdb, raise_tcbdb_error)
1256PyTCXDB_PUT(PyTCBDB_putdup, PyTCBDB, putdup, tcbdbputdup, bdb, raise_tcbdb_error)
1257
1258static PyObject *
1259PyTCBDB_putlist(PyTCBDB *self, PyObject *args, PyObject *keywds) {
1260  bool result;
1261  char *key;
1262  TCLIST *tcvalue;
1263  PyObject *value;
1264  int key_len, value_size, i;
1265  static char *kwlist[] = {"key", "value", NULL};
1266
1267  if (!PyArg_ParseTupleAndKeywords(args, keywds, "s#O!:putlist", kwlist,
1268                                   &key, &key_len, &PyList_Type, &value) ||
1269      !(tcvalue = tclistnew())) {
1270    return NULL;
1271  }
1272
1273  value_size = PyList_Size(value);
1274  for (i = 0; i < value_size; i++) {
1275    PyObject *v = PyList_GetItem(value, i);
1276    if (PyString_Check(v)) {
1277      tclistpush(tcvalue, PyString_AsString(v), PyString_Size(v));
1278    }
1279  }
1280  Py_BEGIN_ALLOW_THREADS
1281  result = tcbdbputdup3(self->bdb, key, key_len, tcvalue);
1282  Py_END_ALLOW_THREADS
1283  tclistdel(tcvalue);
1284
1285  if (!result) {
1286    raise_tcbdb_error(self->bdb);
1287    return NULL;
1288  }
1289  Py_RETURN_NONE;
1290}
1291
1292BOOL_KEYARGS(PyTCBDB_out,PyTCBDB,out,tcbdbout,bdb,raise_tcbdb_error,bdb)
1293BOOL_KEYARGS(PyTCBDB_outlist,PyTCBDB,outlist,tcbdbout3,bdb,raise_tcbdb_error,bdb)
1294STRINGL_KEYARGS(PyTCBDB_get,PyTCBDB,get,tcbdbget,bdb,raise_tcbdb_error)
1295
1296static PyObject *
1297PyTCBDB_getlist(PyTCBDB *self, PyObject *args, PyObject *keywds) {
1298  char *key;
1299  int key_len;
1300  TCLIST *list;
1301  static char *kwlist[] = {"key", NULL};
1302
1303  if (!PyArg_ParseTupleAndKeywords(args, keywds, "s#:getlist", kwlist,
1304                                   &key, &key_len)) {
1305    return NULL;
1306  }
1307  Py_BEGIN_ALLOW_THREADS
1308  list = tcbdbget4(self->bdb, key, key_len);
1309  Py_END_ALLOW_THREADS
1310
1311  if (!list) {
1312    raise_tcbdb_error(self->bdb);
1313    return NULL;
1314  } else {
1315    PyObject *ret;
1316    int i, n = tclistnum(list);
1317    if ((ret = PyList_New(n))) {
1318      for (i = 0; i < n; i++) {
1319        int value_len;
1320        PyObject *_value;
1321        const char *value;
1322        value = tclistval(list, i, &value_len);
1323        _value = PyString_FromStringAndSize(value, value_len);
1324        PyList_SET_ITEM(ret, i, _value);
1325      }
1326    }
1327    tclistdel(list);
1328    return ret;
1329  }
1330}
1331
1332INT_KEYARGS(PyTCBDB_vnum,PyTCBDB,vnum,tcbdbvnum,bdb,raise_tcbdb_error)
1333INT_KEYARGS(PyTCBDB_vsiz,PyTCBDB,vsiz,tcbdbvsiz,bdb,raise_tcbdb_error)
1334BOOL_NOARGS(PyTCBDB_sync,PyTCBDB,tcbdbsync,bdb,raise_tcbdb_error,bdb)
1335PyTCBDB_TUNE(PyTCBDB_optimize, optimize, tcbdboptimize)
1336BOOL_PATHARGS(PyTCBDB_copy, PyTCBDB, copy, tcbdbcopy, bdb, raise_tcbdb_error)
1337BOOL_NOARGS(PyTCBDB_vanish,PyTCBDB,tcbdbvanish,bdb,raise_tcbdb_error,bdb)
1338BOOL_NOARGS(PyTCBDB_tranbegin,PyTCBDB,tcbdbtranbegin,bdb,raise_tcbdb_error,bdb)
1339BOOL_NOARGS(PyTCBDB_trancommit,PyTCBDB,tcbdbtrancommit,bdb,raise_tcbdb_error,bdb)
1340BOOL_NOARGS(PyTCBDB_tranabort,PyTCBDB,tcbdbtranabort,bdb,raise_tcbdb_error,bdb)
1341STRING_NOARGS(PyTCBDB_path,PyTCBDB,tcbdbpath,bdb,raise_tcbdb_error)
1342PY_U_LONG_LONG_NOARGS(PyTCBDB_rnum, PyTCBDB, tcbdbrnum, bdb, tcbdbecode, raise_tcbdb_error)
1343PY_U_LONG_LONG_NOARGS(PyTCBDB_fsiz, PyTCBDB, tcbdbrnum, bdb, tcbdbecode, raise_tcbdb_error)
1344
1345/* TODO: features for experts */
1346
1347static int
1348PyTCBDB_Contains(PyTCBDB *self, PyObject *_key) {
1349  char *key = PyString_AS_STRING(_key);
1350  int key_len = PyString_GET_SIZE(_key), value_len;
1351
1352  if (!key || !key_len) {
1353    return -1;
1354  }
1355  Py_BEGIN_ALLOW_THREADS
1356  value_len = tcbdbvsiz(self->bdb, key, key_len);
1357  Py_END_ALLOW_THREADS
1358
1359  return (value_len != -1);
1360}
1361
1362static PyObject *
1363PyTCBDB___contains__(PyTCBDB *self, PyObject *_key) {
1364  return PyBool_FromLong(PyTCBDB_Contains(self, _key) != 0);
1365}
1366
1367static PyObject *
1368PyTCBDB___getitem__(PyTCBDB *self, PyObject *_key) {
1369  PyObject *ret;
1370  char *key = PyString_AS_STRING(_key), *value;
1371  int key_len = PyString_GET_SIZE(_key), value_len;
1372
1373  if (!key || !key_len) {
1374    return NULL;
1375  }
1376  Py_BEGIN_ALLOW_THREADS
1377  value = tcbdbget(self->bdb, key, key_len, &value_len);
1378  Py_END_ALLOW_THREADS
1379
1380  if (!value) {
1381    raise_tcbdb_error(self->bdb);
1382    return NULL;
1383  }
1384  ret = PyString_FromStringAndSize(value, value_len);
1385  free(value);
1386  return ret;
1387}
1388
1389static PyObject *
1390PyTCBDB_curnew(PyTCBDB *self) {
1391  PyBDBCUR *cur;
1392  PyObject *args;
1393
1394  args = Py_BuildValue("(O)", self);
1395  cur = (PyBDBCUR *)PyBDBCUR_new(&PyBDBCUR_Type, args, NULL);
1396  Py_DECREF(args);
1397
1398  if (cur) {
1399    return (PyObject *)cur;
1400  }
1401  raise_tcbdb_error(self->bdb);
1402  return NULL;
1403}
1404
1405static PyObject *
1406PyTCBDB_GetIter(PyObject *self) {
1407  PyBDBCUR *cur;
1408  if ((cur = (PyBDBCUR *)PyTCBDB_curnew((PyTCBDB *)self))) {
1409    if (PyBDBCUR_first(cur)) {
1410      return (PyObject *)cur;
1411    }
1412    PyBDBCUR_dealloc(cur);
1413  }
1414  return NULL;
1415}
1416
1417TCXDB_rnum(TCBDB_rnum,TCBDB,tcbdbrnum)
1418
1419static PyObject *
1420PyTCBDB_keys(PyTCBDB *self) {
1421  int i;
1422  BDBCUR *cur;
1423  PyObject *ret;
1424  bool result;
1425
1426  Py_BEGIN_ALLOW_THREADS
1427  cur = tcbdbcurnew(self->bdb);
1428  Py_END_ALLOW_THREADS
1429
1430  if (!cur) {
1431    return NULL;
1432  }
1433
1434  Py_BEGIN_ALLOW_THREADS
1435  result = tcbdbcurfirst(cur);
1436  Py_END_ALLOW_THREADS
1437
1438  if (!result || !(ret = PyList_New(TCBDB_rnum(self->bdb)))) {
1439    tcbdbcurdel(cur);
1440    return NULL;
1441  }
1442  for (i = 0; result; i++) {
1443    char *key;
1444    int key_len;
1445    PyObject *_key;
1446
1447    Py_BEGIN_ALLOW_THREADS
1448    key = tcbdbcurkey(cur, &key_len);
1449    Py_END_ALLOW_THREADS
1450
1451    if (!key) { break; }
1452    _key = PyString_FromStringAndSize(key, key_len);
1453    free(key);
1454    if (!_key) {
1455      Py_DECREF(ret);
1456      return NULL;
1457    }
1458    PyList_SET_ITEM(ret, i, _key);
1459
1460    Py_BEGIN_ALLOW_THREADS
1461    result = tcbdbcurnext(cur);
1462    Py_END_ALLOW_THREADS
1463  }
1464  tcbdbcurdel(cur);
1465  return ret;
1466}
1467
1468static PyObject *
1469PyTCBDB_items(PyTCBDB *self) {
1470  int i;
1471  bool result;
1472  BDBCUR *cur;
1473  PyObject *ret;
1474  TCXSTR *key, *value;
1475
1476  Py_BEGIN_ALLOW_THREADS
1477  cur = tcbdbcurnew(self->bdb);
1478  Py_END_ALLOW_THREADS
1479
1480  if (cur) {
1481    Py_BEGIN_ALLOW_THREADS
1482    result = tcbdbcurfirst(cur);
1483    Py_END_ALLOW_THREADS
1484    if (result) {
1485      if ((key = tcxstrnew())) {
1486        if ((value = tcxstrnew())) {
1487          if ((ret = PyList_New(TCBDB_rnum(self->bdb)))) {
1488            goto main;
1489          }
1490          tcxstrdel(value);
1491        }
1492        tcxstrdel(key);
1493      }
1494    }
1495    tcbdbcurdel(cur);
1496  }
1497  return NULL;
1498main:
1499  for (i = 0; result; i++) {
1500    Py_BEGIN_ALLOW_THREADS
1501    result = tcbdbcurrec(cur, key, value);
1502    Py_END_ALLOW_THREADS
1503    if (result) {
1504      PyObject *tuple;
1505      tuple = Py_BuildValue("(s#s#)", tcxstrptr(key), tcxstrsize(key),
1506                                      tcxstrptr(value), tcxstrsize(value));
1507      if (tuple) {
1508        PyList_SET_ITEM(ret, i, tuple);
1509        Py_BEGIN_ALLOW_THREADS
1510        result = tcbdbcurnext(cur);
1511        Py_END_ALLOW_THREADS
1512        tcxstrclear(key);
1513        tcxstrclear(value);
1514      } else {
1515        break;
1516      }
1517    }
1518  }
1519  tcxstrdel(key);
1520  tcxstrdel(value);
1521  tcbdbcurdel(cur);
1522  return ret;
1523}
1524
1525static PyObject *
1526PyTCBDB_values(PyTCBDB *self) {
1527  int i;
1528  BDBCUR *cur;
1529  PyObject *ret;
1530  bool result;
1531
1532  Py_BEGIN_ALLOW_THREADS
1533  cur = tcbdbcurnew(self->bdb);
1534  Py_END_ALLOW_THREADS
1535
1536  if (!cur) {
1537    return NULL;
1538  }
1539
1540  Py_BEGIN_ALLOW_THREADS
1541  result = tcbdbcurfirst(cur);
1542  Py_END_ALLOW_THREADS
1543
1544  if (!result || !(ret = PyList_New(TCBDB_rnum(self->bdb)))) {
1545    tcbdbcurdel(cur);
1546    return NULL;
1547  }
1548  for (i = 0; result; i++) {
1549    char *value;
1550    int value_len;
1551    PyObject *_value;
1552
1553    Py_BEGIN_ALLOW_THREADS
1554    value = tcbdbcurval(cur, &value_len);
1555    Py_END_ALLOW_THREADS
1556
1557    if (!value) { break; }
1558    _value = PyString_FromStringAndSize(value, value_len);
1559    free(value);
1560    if (!_value) {
1561      Py_DECREF(ret);
1562      return NULL;
1563    }
1564    PyList_SET_ITEM(ret, i, _value);
1565
1566    Py_BEGIN_ALLOW_THREADS
1567    result = tcbdbcurnext(cur);
1568    Py_END_ALLOW_THREADS
1569  }
1570  tcbdbcurdel(cur);
1571  return ret;
1572}
1573
1574static long
1575PyTCBDB_length(PyTCBDB *self) {
1576  return TCBDB_rnum(self->bdb);
1577}
1578
1579static PyObject *
1580PyTCBDB_subscript(PyTCBDB *self, PyObject *_key) {
1581  PyObject *ret;
1582  char *key = PyString_AS_STRING(_key), *value;
1583  int key_len = PyString_GET_SIZE(_key), value_len;
1584
1585  if (!key || !key_len) {
1586    return NULL;
1587  }
1588  Py_BEGIN_ALLOW_THREADS
1589  value = tcbdbget(self->bdb, key, key_len, &value_len);
1590  Py_END_ALLOW_THREADS
1591
1592  if (!value) {
1593    raise_tcbdb_error(self->bdb);
1594    return NULL;
1595  }
1596  ret = PyString_FromStringAndSize(value, value_len);
1597  free(value);
1598  return ret;
1599}
1600
1601int
1602PyTCBDB_DelItem(PyTCBDB *self, PyObject *_key) {
1603  bool result;
1604  char *key = PyString_AS_STRING(_key);
1605  int key_len = PyString_GET_SIZE(_key);
1606
1607  if (!key || !key_len) {
1608    return -1;
1609  }
1610  Py_BEGIN_ALLOW_THREADS
1611  result = tcbdbout(self->bdb, key, key_len);
1612  Py_END_ALLOW_THREADS
1613
1614  if (!result) {
1615    raise_tcbdb_error(self->bdb);
1616    return -1;
1617  }
1618  return 0;
1619}
1620
1621int
1622PyTCBDB_SetItem(PyTCBDB *self, PyObject *_key, PyObject *_value) {
1623  bool result;
1624  char *key = PyString_AS_STRING(_key), *value = PyString_AS_STRING(_value);
1625  int key_len = PyString_GET_SIZE(_key), value_len = PyString_GET_SIZE(_value);
1626
1627  if (!key || !key_len || !value) {
1628    return -1;
1629  }
1630  Py_BEGIN_ALLOW_THREADS
1631  result = tcbdbput(self->bdb, key, key_len, value, value_len);
1632  Py_END_ALLOW_THREADS
1633
1634  if (!result) {
1635    raise_tcbdb_error(self->bdb);
1636    return -1;
1637  }
1638  return 0;
1639}
1640
1641static int
1642PyTCBDB_ass_sub(PyTCBDB *self, PyObject *v, PyObject *w)
1643{
1644  if (w) {
1645    return PyTCBDB_SetItem(self, v, w);
1646  } else {
1647    return PyTCBDB_DelItem(self, v);
1648  }
1649}
1650
1651static PyMethodDef PyTCBDB_methods[] = {
1652  {"errmsg", (PyCFunction)PyTCBDB_errmsg,
1653   METH_VARARGS | METH_KEYWORDS | METH_CLASS,
1654   "Get the message string corresponding to an error code."},
1655  {"ecode", (PyCFunction)PyTCBDB_ecode,
1656   METH_NOARGS,
1657   "Get the last happened error code of a B+ tree database object."},
1658  {"setcmpfunc", (PyCFunction)PyTCBDB_setcmpfunc,
1659   METH_VARARGS | METH_KEYWORDS,
1660   "Set the custom comparison function of a B+ tree database object."},
1661  {"setmutex", (PyCFunction)PyTCBDB_setmutex,
1662   METH_NOARGS,
1663   "Set mutual exclusion control of a B+ tree database object for threading."},
1664  {"tune", (PyCFunction)PyTCBDB_tune,
1665   METH_VARARGS | METH_KEYWORDS,
1666   "Set the tuning parameters of a B+ tree database object."},
1667  {"setcache", (PyCFunction)PyTCBDB_setcache,
1668   METH_VARARGS | METH_KEYWORDS,
1669   "Set the caching parameters of a B+ tree database object."},
1670  {"open", (PyCFunction)PyTCBDB_open,
1671   METH_VARARGS | METH_KEYWORDS,
1672   "Open a database file and connect a B+ tree database object."},
1673  {"close", (PyCFunction)PyTCBDB_close,
1674   METH_NOARGS,
1675   "Close a B+ tree database object."},
1676  {"put", (PyCFunction)PyTCBDB_put,
1677   METH_VARARGS | METH_KEYWORDS,
1678   "Store a record into a B+ tree database object."},
1679  {"putkeep", (PyCFunction)PyTCBDB_putkeep,
1680   METH_VARARGS | METH_KEYWORDS,
1681   "Store a new record into a B+ tree database object."},
1682  {"putcat", (PyCFunction)PyTCBDB_putcat,
1683   METH_VARARGS | METH_KEYWORDS,
1684   "Concatenate a value at the end of the existing record in a B+ tree database object."},
1685  {"putdup", (PyCFunction)PyTCBDB_putdup,
1686   METH_VARARGS | METH_KEYWORDS,
1687   "Store a record into a B+ tree database object with allowing duplication of keys."},
1688  {"putlist", (PyCFunction)PyTCBDB_putlist,
1689   METH_VARARGS | METH_KEYWORDS,
1690   "Store records into a B+ tree database object with allowing duplication of keys."},
1691  {"out", (PyCFunction)PyTCBDB_out,
1692   METH_VARARGS | METH_KEYWORDS,
1693   "Remove a record of a B+ tree database object."},
1694  {"outlist", (PyCFunction)PyTCBDB_outlist,
1695   METH_VARARGS | METH_KEYWORDS,
1696   "Remove records of a B+ tree database object."},
1697  {"get", (PyCFunction)PyTCBDB_get,
1698   METH_VARARGS | METH_KEYWORDS,
1699   "Retrieve a record in a B+ tree database object.\n"
1700   "If the key of duplicated records is specified, the value of the first record is selected."},
1701  {"getlist", (PyCFunction)PyTCBDB_getlist,
1702   METH_VARARGS | METH_KEYWORDS,
1703   "Retrieve records in a B+ tree database object."},
1704  {"vnum", (PyCFunction)PyTCBDB_vnum,
1705   METH_VARARGS | METH_KEYWORDS,
1706   "Get the number of records corresponding a key in a B+ tree database object."},
1707  {"vsiz", (PyCFunction)PyTCBDB_vsiz,
1708   METH_VARARGS | METH_KEYWORDS,
1709   "Get the size of the value of a record in a B+ tree database object."},
1710  {"sync", (PyCFunction)PyTCBDB_sync,
1711   METH_NOARGS,
1712   "Synchronize updated contents of a B+ tree database object with the file and the device."},
1713  {"optimize", (PyCFunction)PyTCBDB_optimize,
1714   METH_VARARGS | METH_KEYWORDS,
1715   "Optimize the file of a B+ tree database object."},
1716  {"vanish", (PyCFunction)PyTCBDB_vanish,
1717   METH_NOARGS,
1718   "Remove all records of a hash database object."},
1719  {"copy", (PyCFunction)PyTCBDB_copy,
1720   METH_VARARGS | METH_KEYWORDS,
1721   "Copy the database file of a B+ tree database object."},
1722  {"tranbegin", (PyCFunction)PyTCBDB_tranbegin,
1723   METH_NOARGS,
1724   "Begin the transaction of a B+ tree database object."},
1725  {"trancommit", (PyCFunction)PyTCBDB_trancommit,
1726   METH_NOARGS,
1727   "Commit the transaction of a B+ tree database object."},
1728  {"tranabort", (PyCFunction)PyTCBDB_tranabort,
1729   METH_NOARGS,
1730   "Abort the transaction of a B+ tree database object."},
1731  {"path", (PyCFunction)PyTCBDB_path,
1732   METH_NOARGS,
1733   "Get the file path of a hash database object."},
1734  {"rnum", (PyCFunction)PyTCBDB_rnum,
1735   METH_NOARGS,
1736   "Get the number of records of a B+ tree database object."},
1737  {"fsiz", (PyCFunction)PyTCBDB_fsiz,
1738   METH_NOARGS,
1739   "Get the size of the database file of a B+ tree database object."},
1740  {"curnew", (PyCFunction)PyTCBDB_curnew,
1741   METH_NOARGS,
1742   "Create a cursor object."},
1743  {"__contains__", (PyCFunction)PyTCBDB___contains__,
1744   METH_O | METH_COEXIST,
1745   ""},
1746  {"__getitem__", (PyCFunction)PyTCBDB___getitem__,
1747   METH_O | METH_COEXIST,
1748   ""},
1749  {"has_key", (PyCFunction)PyTCBDB___contains__,
1750   METH_O,
1751   ""},
1752  {"keys", (PyCFunction)PyTCBDB_keys,
1753   METH_NOARGS,
1754   ""},
1755  {"items", (PyCFunction)PyTCBDB_items,
1756   METH_NOARGS,
1757   ""},
1758  {"values", (PyCFunction)PyTCBDB_values,
1759   METH_NOARGS,
1760   ""},
1761  /*
1762  {"", (PyCFunction)PyTCBDB_,
1763   METH_VARARGS | METH_KEYWORDS,
1764   ""},
1765  */
1766  {NULL, NULL, 0, NULL}
1767};
1768
1769/* Hack to implement "key in dict" */
1770static PySequenceMethods PyTCBDB_as_sequence = {
1771  0,                             /* sq_length */
1772  0,                             /* sq_concat */
1773  0,                             /* sq_repeat */
1774  0,                             /* sq_item */
1775  0,                             /* sq_slice */
1776  0,                             /* sq_ass_item */
1777  0,                             /* sq_ass_slice */
1778  (objobjproc)PyTCBDB_Contains,  /* sq_contains */
1779  0,                             /* sq_inplace_concat */
1780  0,                             /* sq_inplace_repeat */
1781};
1782
1783static PyMappingMethods PyTCBDB_as_mapping = {
1784  (inquiry)PyTCBDB_length, /* mp_length */
1785  (binaryfunc)PyTCBDB_subscript, /* mp_subscript */
1786  (objobjargproc)PyTCBDB_ass_sub, /* mp_ass_subscript */
1787};
1788
1789/* type objects */
1790
1791static PyTypeObject PyTCBDB_Type = {
1792  PyObject_HEAD_INIT(NULL)
1793  0,                                           /* ob_size */
1794  "pytc.BDB",                                  /* tp_name */
1795  sizeof(PyTCBDB),                             /* tp_basicsize */
1796  0,                                           /* tp_itemsize */
1797  (destructor)PyTCBDB_dealloc,                 /* tp_dealloc */
1798  0,                                           /* tp_print */
1799  0,                                           /* tp_getattr */
1800  0,                                           /* tp_setattr */
1801  0,                                           /* tp_compare */
1802  0,                                           /* tp_repr */
1803  0,                                           /* tp_as_number */
1804  &PyTCBDB_as_sequence,                        /* tp_as_sequence */
1805  &PyTCBDB_as_mapping,                         /* tp_as_mapping */
1806  PyTCBDB_Hash,                                /* tp_hash  */
1807  0,                                           /* tp_call */
1808  0,                                           /* tp_str */
1809  0,                                           /* tp_getattro */
1810  0,                                           /* tp_setattro */
1811  0,                                           /* tp_as_buffer */
1812  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,    /* tp_flags */
1813  "tcbdb",                                     /* tp_doc */
1814  0,                                           /* tp_traverse */
1815  0,                                           /* tp_clear */
1816  0,                                           /* tp_richcompare */
1817  0,                                           /* tp_weaklistoffset */
1818  PyTCBDB_GetIter,                             /* tp_iter */
1819  0,                                           /* tp_iternext */
1820  PyTCBDB_methods,                             /* tp_methods */
1821  0,                                           /* tp_members */
1822  0,                                           /* tp_getset */
1823  0,                                           /* tp_base */
1824  0,                                           /* tp_dict */
1825  0,                                           /* tp_descr_get */
1826  0,                                           /* tp_descr_set */
1827  0,                                           /* tp_dictoffset */
1828  0,                                           /* tp_init */
1829  0,                                           /* tp_alloc */
1830  PyTCBDB_new,                                 /* tp_new */
1831};
1832
1833#define ADD_INT(module,NAME) PyModule_AddIntConstant(module, #NAME, NAME)
1834
1835#ifndef PyMODINIT_FUNC
1836#define PyMODINIT_FUNC void
1837#endif
1838PyMODINIT_FUNC
1839initpytc(void)
1840{
1841  PyObject *m, *mod_dic;
1842
1843  if (!(m = Py_InitModule3("pytc", NULL,
1844                           "TokyoCabinet python bindings."))) {
1845    goto exit;
1846  }
1847
1848  /* register classes */
1849  if (!(mod_dic = PyModule_GetDict(m))) { goto exit; }
1850
1851  if (PyType_Ready(&PyTCHDB_Type) < 0) { goto exit; }
1852  if (PyType_Ready(&PyTCBDB_Type) < 0) { goto exit; }
1853  if (PyType_Ready(&PyBDBCUR_Type) < 0) { goto exit; }
1854
1855  PyTCError = PyErr_NewException("pytc.Error", NULL, NULL);
1856  PyDict_SetItemString(mod_dic, "Error", PyTCError);
1857
1858  Py_INCREF(&PyTCHDB_Type);
1859  PyModule_AddObject(m, "HDB", (PyObject *)&PyTCHDB_Type);
1860  Py_INCREF(&PyTCBDB_Type);
1861  PyModule_AddObject(m, "BDB", (PyObject *)&PyTCBDB_Type);
1862  Py_INCREF(&PyBDBCUR_Type);
1863  PyModule_AddObject(m, "BDBCUR", (PyObject *)&PyBDBCUR_Type);
1864
1865  /* register consts */
1866
1867  /* error */
1868  ADD_INT(m, TCESUCCESS);
1869  ADD_INT(m, TCETHREAD);
1870  ADD_INT(m, TCEINVALID);
1871  ADD_INT(m, TCENOFILE);
1872  ADD_INT(m, TCENOPERM);
1873  ADD_INT(m, TCEMETA);
1874  ADD_INT(m, TCERHEAD);
1875  ADD_INT(m, TCEOPEN);
1876  ADD_INT(m, TCECLOSE);
1877  ADD_INT(m, TCETRUNC);
1878  ADD_INT(m, TCESYNC);
1879  ADD_INT(m, TCESTAT);
1880  ADD_INT(m, TCESEEK);
1881  ADD_INT(m, TCEREAD);
1882  ADD_INT(m, TCEWRITE);
1883  ADD_INT(m, TCEMMAP);
1884  ADD_INT(m, TCELOCK);
1885  ADD_INT(m, TCEUNLINK);
1886  ADD_INT(m, TCERENAME);
1887  ADD_INT(m, TCEMKDIR);
1888  ADD_INT(m, TCERMDIR);
1889  ADD_INT(m, TCEKEEP);
1890  ADD_INT(m, TCENOREC);
1891  ADD_INT(m, TCEMISC);
1892
1893  /* HDB */
1894  ADD_INT(m, HDBTHASH);
1895  ADD_INT(m, HDBTBTREE);
1896
1897  ADD_INT(m, HDBFOPEN);
1898  ADD_INT(m, HDBFFATAL);
1899
1900  ADD_INT(m, HDBTLARGE);
1901  ADD_INT(m, HDBTDEFLATE);
1902  ADD_INT(m, HDBTTCBS);
1903
1904  ADD_INT(m, HDBOREADER);
1905  ADD_INT(m, HDBOWRITER);
1906  ADD_INT(m, HDBOCREAT);
1907  ADD_INT(m, HDBOTRUNC);
1908  ADD_INT(m, HDBONOLCK);
1909  ADD_INT(m, HDBOLCKNB);
1910
1911  /* BDB */
1912  ADD_INT(m, BDBFOPEN);
1913  ADD_INT(m, BDBFFATAL);
1914
1915  ADD_INT(m, BDBTLARGE);
1916  ADD_INT(m, BDBTDEFLATE);
1917  ADD_INT(m, BDBTTCBS);
1918
1919  ADD_INT(m, BDBOREADER);
1920  ADD_INT(m, BDBOWRITER);
1921  ADD_INT(m, BDBOCREAT);
1922  ADD_INT(m, BDBOTRUNC);
1923  ADD_INT(m, BDBONOLCK);
1924  ADD_INT(m, BDBOLCKNB);
1925
1926  ADD_INT(m, BDBCPCURRENT);
1927  ADD_INT(m, BDBCPBEFORE);
1928  ADD_INT(m, BDBCPAFTER);
1929
1930exit:
1931  if (PyErr_Occurred()) {
1932    /* PyErr_Print(); */
1933    PyErr_SetString(PyExc_ImportError, "pytc: init failed");
1934  }
1935}
Note: See TracBrowser for help on using the browser.