1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
|
import cffi, os
ffi = cffi.FFI()
ffi.cdef('''
#define GDBM_READER ...
#define GDBM_WRITER ...
#define GDBM_WRCREAT ...
#define GDBM_NEWDB ...
#define GDBM_FAST ...
#define GDBM_SYNC ...
#define GDBM_NOLOCK ...
#define GDBM_REPLACE ...
void* gdbm_open(char *, int, int, int, void (*)());
void gdbm_close(void*);
typedef struct {
char *dptr;
int dsize;
} datum;
datum gdbm_fetch(void*, datum);
int gdbm_delete(void*, datum);
int gdbm_store(void*, datum, datum, int);
int gdbm_exists(void*, datum);
int gdbm_reorganize(void*);
datum gdbm_firstkey(void*);
datum gdbm_nextkey(void*, datum);
void gdbm_sync(void*);
char* gdbm_strerror(int);
int gdbm_errno;
void free(void*);
''')
try:
lib = ffi.verify('''
#include "gdbm.h"
''', libraries=['gdbm'])
except cffi.VerificationError as e:
# distutils does not preserve the actual message,
# but the verification is simple enough that the
# failure must be due to missing gdbm dev libs
raise ImportError('%s: %s' %(e.__class__.__name__, e))
class error(Exception):
pass
def _fromstr(key):
if isinstance(key, unicode):
key = key.encode("ascii")
if not isinstance(key, str):
raise TypeError("gdbm mappings have string indices only")
return {'dptr': ffi.new("char[]", key), 'dsize': len(key)}
class gdbm(object):
ll_dbm = None
def __init__(self, filename, iflags, mode):
res = lib.gdbm_open(filename, 0, iflags, mode, ffi.NULL)
self.size = -1
if not res:
self._raise_from_errno()
self.ll_dbm = res
def close(self):
if self.ll_dbm:
lib.gdbm_close(self.ll_dbm)
self.ll_dbm = None
def _raise_from_errno(self):
if ffi.errno:
raise error(ffi.errno, os.strerror(ffi.errno))
raise error(lib.gdbm_errno, lib.gdbm_strerror(lib.gdbm_errno))
def __len__(self):
if self.size < 0:
self.size = len(self.keys())
return self.size
def __setitem__(self, key, value):
self._check_closed()
self._size = -1
r = lib.gdbm_store(self.ll_dbm, _fromstr(key), _fromstr(value),
lib.GDBM_REPLACE)
if r < 0:
self._raise_from_errno()
def __delitem__(self, key):
self._check_closed()
res = lib.gdbm_delete(self.ll_dbm, _fromstr(key))
if res < 0:
raise KeyError(key)
def __contains__(self, key):
self._check_closed()
return lib.gdbm_exists(self.ll_dbm, _fromstr(key))
has_key = __contains__
def __getitem__(self, key):
self._check_closed()
drec = lib.gdbm_fetch(self.ll_dbm, _fromstr(key))
if not drec.dptr:
raise KeyError(key)
res = str(ffi.buffer(drec.dptr, drec.dsize))
lib.free(drec.dptr)
return res
def keys(self):
self._check_closed()
l = []
key = lib.gdbm_firstkey(self.ll_dbm)
while key.dptr:
l.append(str(ffi.buffer(key.dptr, key.dsize)))
nextkey = lib.gdbm_nextkey(self.ll_dbm, key)
lib.free(key.dptr)
key = nextkey
return l
def firstkey(self):
self._check_closed()
key = lib.gdbm_firstkey(self.ll_dbm)
if key.dptr:
res = str(ffi.buffer(key.dptr, key.dsize))
lib.free(key.dptr)
return res
def nextkey(self, key):
self._check_closed()
key = lib.gdbm_nextkey(self.ll_dbm, _fromstr(key))
if key.dptr:
res = str(ffi.buffer(key.dptr, key.dsize))
lib.free(key.dptr)
return res
def reorganize(self):
self._check_closed()
if lib.gdbm_reorganize(self.ll_dbm) < 0:
self._raise_from_errno()
def _check_closed(self):
if not self.ll_dbm:
raise error(0, "GDBM object has already been closed")
__del__ = close
def sync(self):
self._check_closed()
lib.gdbm_sync(self.ll_dbm)
def open(filename, flags='r', mode=0666):
if flags[0] == 'r':
iflags = lib.GDBM_READER
elif flags[0] == 'w':
iflags = lib.GDBM_WRITER
elif flags[0] == 'c':
iflags = lib.GDBM_WRCREAT
elif flags[0] == 'n':
iflags = lib.GDBM_NEWDB
else:
raise error(0, "First flag must be one of 'r', 'w', 'c' or 'n'")
for flag in flags[1:]:
if flag == 'f':
iflags |= lib.GDBM_FAST
elif flag == 's':
iflags |= lib.GDBM_SYNC
elif flag == 'u':
iflags |= lib.GDBM_NOLOCK
else:
raise error(0, "Flag '%s' not supported" % flag)
return gdbm(filename, iflags, mode)
open_flags = "rwcnfsu"
|