dbm 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/ext/dbm/dbm.c +1160 -0
- data/ext/dbm/extconf.rb +290 -0
- metadata +75 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 31cec15138a9142216ad46055bc42306214cdd19
|
4
|
+
data.tar.gz: ec6c97382c6c3cce47c2613dafb48ea70ff54263
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6ba19f6220f2af16c7f5390ac6c25d183db149925029a5585e96939a70bf921fbf33e259ed9f760036bff830468739893c288db1567e23530b61ee190a4792db
|
7
|
+
data.tar.gz: 3256035cb393c4c8f986576a50923889f3cb60c53e37b0bd1ad3fe4f911243470268ea28c415f89220a89c378afba720efd88ee09749db7a74be99a6dd5adef9
|
data/ext/dbm/dbm.c
ADDED
@@ -0,0 +1,1160 @@
|
|
1
|
+
/************************************************
|
2
|
+
|
3
|
+
dbm.c -
|
4
|
+
|
5
|
+
$Author$
|
6
|
+
created at: Mon Jan 24 15:59:52 JST 1994
|
7
|
+
|
8
|
+
Copyright (C) 1995-2001 Yukihiro Matsumoto
|
9
|
+
|
10
|
+
************************************************/
|
11
|
+
|
12
|
+
#include "ruby.h"
|
13
|
+
|
14
|
+
#ifdef HAVE_CDEFS_H
|
15
|
+
# include <cdefs.h>
|
16
|
+
#endif
|
17
|
+
#ifdef HAVE_SYS_CDEFS_H
|
18
|
+
# include <sys/cdefs.h>
|
19
|
+
#endif
|
20
|
+
#include DBM_HDR
|
21
|
+
#include <fcntl.h>
|
22
|
+
#include <errno.h>
|
23
|
+
|
24
|
+
#define DSIZE_TYPE TYPEOF_DATUM_DSIZE
|
25
|
+
#if SIZEOF_DATUM_DSIZE > SIZEOF_INT
|
26
|
+
# define RSTRING_DSIZE(s) RSTRING_LEN(s)
|
27
|
+
# define TOO_LONG(n) 0
|
28
|
+
#else
|
29
|
+
# define RSTRING_DSIZE(s) RSTRING_LENINT(s)
|
30
|
+
# define TOO_LONG(n) ((long)(+(DSIZE_TYPE)(n)) != (n))
|
31
|
+
#endif
|
32
|
+
|
33
|
+
static VALUE rb_cDBM, rb_eDBMError;
|
34
|
+
|
35
|
+
#define RUBY_DBM_RW_BIT 0x20000000
|
36
|
+
|
37
|
+
struct dbmdata {
|
38
|
+
long di_size;
|
39
|
+
DBM *di_dbm;
|
40
|
+
};
|
41
|
+
|
42
|
+
static void
|
43
|
+
closed_dbm(void)
|
44
|
+
{
|
45
|
+
rb_raise(rb_eDBMError, "closed DBM file");
|
46
|
+
}
|
47
|
+
|
48
|
+
#define GetDBM(obj, dbmp) do {\
|
49
|
+
TypedData_Get_Struct((obj), struct dbmdata, &dbm_type, (dbmp));\
|
50
|
+
if ((dbmp) == 0) closed_dbm();\
|
51
|
+
if ((dbmp)->di_dbm == 0) closed_dbm();\
|
52
|
+
} while (0)
|
53
|
+
|
54
|
+
#define GetDBM2(obj, dbmp, dbm) do {\
|
55
|
+
GetDBM((obj), (dbmp));\
|
56
|
+
(dbm) = (dbmp)->di_dbm;\
|
57
|
+
} while (0)
|
58
|
+
|
59
|
+
static void
|
60
|
+
free_dbm(void *ptr)
|
61
|
+
{
|
62
|
+
struct dbmdata *dbmp = ptr;
|
63
|
+
if (dbmp) {
|
64
|
+
if (dbmp->di_dbm) dbm_close(dbmp->di_dbm);
|
65
|
+
xfree(dbmp);
|
66
|
+
}
|
67
|
+
}
|
68
|
+
|
69
|
+
static size_t
|
70
|
+
memsize_dbm(const void *ptr)
|
71
|
+
{
|
72
|
+
size_t size = 0;
|
73
|
+
const struct dbmdata *dbmp = ptr;
|
74
|
+
if (dbmp) {
|
75
|
+
size += sizeof(*dbmp);
|
76
|
+
if (dbmp->di_dbm) size += DBM_SIZEOF_DBM;
|
77
|
+
}
|
78
|
+
return size;
|
79
|
+
}
|
80
|
+
|
81
|
+
static const rb_data_type_t dbm_type = {
|
82
|
+
"dbm",
|
83
|
+
{0, free_dbm, memsize_dbm,},
|
84
|
+
0, 0,
|
85
|
+
RUBY_TYPED_FREE_IMMEDIATELY,
|
86
|
+
};
|
87
|
+
|
88
|
+
/*
|
89
|
+
* call-seq:
|
90
|
+
* dbm.close
|
91
|
+
*
|
92
|
+
* Closes the database.
|
93
|
+
*/
|
94
|
+
static VALUE
|
95
|
+
fdbm_close(VALUE obj)
|
96
|
+
{
|
97
|
+
struct dbmdata *dbmp;
|
98
|
+
|
99
|
+
GetDBM(obj, dbmp);
|
100
|
+
dbm_close(dbmp->di_dbm);
|
101
|
+
dbmp->di_dbm = 0;
|
102
|
+
|
103
|
+
return Qnil;
|
104
|
+
}
|
105
|
+
|
106
|
+
/*
|
107
|
+
* call-seq:
|
108
|
+
* dbm.closed? -> true or false
|
109
|
+
*
|
110
|
+
* Returns true if the database is closed, false otherwise.
|
111
|
+
*/
|
112
|
+
static VALUE
|
113
|
+
fdbm_closed(VALUE obj)
|
114
|
+
{
|
115
|
+
struct dbmdata *dbmp;
|
116
|
+
|
117
|
+
TypedData_Get_Struct(obj, struct dbmdata, &dbm_type, dbmp);
|
118
|
+
if (dbmp == 0)
|
119
|
+
return Qtrue;
|
120
|
+
if (dbmp->di_dbm == 0)
|
121
|
+
return Qtrue;
|
122
|
+
|
123
|
+
return Qfalse;
|
124
|
+
}
|
125
|
+
|
126
|
+
static VALUE
|
127
|
+
fdbm_alloc(VALUE klass)
|
128
|
+
{
|
129
|
+
return TypedData_Wrap_Struct(klass, &dbm_type, 0);
|
130
|
+
}
|
131
|
+
|
132
|
+
/*
|
133
|
+
* call-seq:
|
134
|
+
* DBM.new(filename[, mode[, flags]]) -> dbm
|
135
|
+
*
|
136
|
+
* Open a dbm database with the specified name, which can include a directory
|
137
|
+
* path. Any file extensions needed will be supplied automatically by the dbm
|
138
|
+
* library. For example, Berkeley DB appends '.db', and GNU gdbm uses two
|
139
|
+
* physical files with extensions '.dir' and '.pag'.
|
140
|
+
*
|
141
|
+
* The mode should be an integer, as for Unix chmod.
|
142
|
+
*
|
143
|
+
* Flags should be one of READER, WRITER, WRCREAT or NEWDB.
|
144
|
+
*/
|
145
|
+
static VALUE
|
146
|
+
fdbm_initialize(int argc, VALUE *argv, VALUE obj)
|
147
|
+
{
|
148
|
+
VALUE file, vmode, vflags;
|
149
|
+
DBM *dbm;
|
150
|
+
struct dbmdata *dbmp;
|
151
|
+
int mode, flags = 0;
|
152
|
+
|
153
|
+
if (rb_scan_args(argc, argv, "12", &file, &vmode, &vflags) == 1) {
|
154
|
+
mode = 0666; /* default value */
|
155
|
+
}
|
156
|
+
else if (NIL_P(vmode)) {
|
157
|
+
mode = -1; /* return nil if DB not exist */
|
158
|
+
}
|
159
|
+
else {
|
160
|
+
mode = NUM2INT(vmode);
|
161
|
+
}
|
162
|
+
|
163
|
+
if (!NIL_P(vflags))
|
164
|
+
flags = NUM2INT(vflags);
|
165
|
+
|
166
|
+
FilePathValue(file);
|
167
|
+
|
168
|
+
/*
|
169
|
+
* Note:
|
170
|
+
* gdbm 1.10 works with O_CLOEXEC. gdbm 1.9.1 silently ignore it.
|
171
|
+
*/
|
172
|
+
#ifndef O_CLOEXEC
|
173
|
+
# define O_CLOEXEC 0
|
174
|
+
#endif
|
175
|
+
|
176
|
+
if (flags & RUBY_DBM_RW_BIT) {
|
177
|
+
flags &= ~RUBY_DBM_RW_BIT;
|
178
|
+
dbm = dbm_open(RSTRING_PTR(file), flags|O_CLOEXEC, mode);
|
179
|
+
}
|
180
|
+
else {
|
181
|
+
dbm = 0;
|
182
|
+
if (mode >= 0) {
|
183
|
+
dbm = dbm_open(RSTRING_PTR(file), O_RDWR|O_CREAT|O_CLOEXEC, mode);
|
184
|
+
}
|
185
|
+
if (!dbm) {
|
186
|
+
dbm = dbm_open(RSTRING_PTR(file), O_RDWR|O_CLOEXEC, 0);
|
187
|
+
}
|
188
|
+
if (!dbm) {
|
189
|
+
dbm = dbm_open(RSTRING_PTR(file), O_RDONLY|O_CLOEXEC, 0);
|
190
|
+
}
|
191
|
+
}
|
192
|
+
|
193
|
+
if (dbm) {
|
194
|
+
/*
|
195
|
+
* History of dbm_pagfno() and dbm_dirfno() in ndbm and its compatibles.
|
196
|
+
* (dbm_pagfno() and dbm_dirfno() is not standardized.)
|
197
|
+
*
|
198
|
+
* 1986: 4.3BSD provides ndbm.
|
199
|
+
* It provides dbm_pagfno() and dbm_dirfno() as macros.
|
200
|
+
* 1991: gdbm-1.5 provides them as functions.
|
201
|
+
* They returns a same descriptor.
|
202
|
+
* (Earlier releases may have the functions too.)
|
203
|
+
* 1991: Net/2 provides Berkeley DB.
|
204
|
+
* It doesn't provide dbm_pagfno() and dbm_dirfno().
|
205
|
+
* 1992: 4.4BSD Alpha provides Berkeley DB with dbm_dirfno() as a function.
|
206
|
+
* dbm_pagfno() is a macro as DBM_PAGFNO_NOT_AVAILABLE.
|
207
|
+
* 1997: Berkeley DB 2.0 is released by Sleepycat Software, Inc.
|
208
|
+
* It defines dbm_pagfno() and dbm_dirfno() as macros.
|
209
|
+
* 2011: gdbm-1.9 creates a separate dir file.
|
210
|
+
* dbm_pagfno() and dbm_dirfno() returns different descriptors.
|
211
|
+
*/
|
212
|
+
#if defined(HAVE_DBM_PAGFNO)
|
213
|
+
rb_fd_fix_cloexec(dbm_pagfno(dbm));
|
214
|
+
#endif
|
215
|
+
#if defined(HAVE_DBM_DIRFNO)
|
216
|
+
rb_fd_fix_cloexec(dbm_dirfno(dbm));
|
217
|
+
#endif
|
218
|
+
|
219
|
+
#if defined(RUBYDBM_DB_HEADER) && defined(HAVE_TYPE_DBC)
|
220
|
+
/* Disable Berkeley DB error messages such as:
|
221
|
+
* DB->put: attempt to modify a read-only database */
|
222
|
+
((DBC*)dbm)->dbp->set_errfile(((DBC*)dbm)->dbp, NULL);
|
223
|
+
#endif
|
224
|
+
}
|
225
|
+
|
226
|
+
if (!dbm) {
|
227
|
+
if (mode == -1) return Qnil;
|
228
|
+
rb_sys_fail_str(file);
|
229
|
+
}
|
230
|
+
|
231
|
+
dbmp = ALLOC(struct dbmdata);
|
232
|
+
DATA_PTR(obj) = dbmp;
|
233
|
+
dbmp->di_dbm = dbm;
|
234
|
+
dbmp->di_size = -1;
|
235
|
+
|
236
|
+
return obj;
|
237
|
+
}
|
238
|
+
|
239
|
+
/*
|
240
|
+
* call-seq:
|
241
|
+
* DBM.open(filename[, mode[, flags]]) -> dbm
|
242
|
+
* DBM.open(filename[, mode[, flags]]) {|dbm| block}
|
243
|
+
*
|
244
|
+
* Open a dbm database and yields it if a block is given. See also
|
245
|
+
* <code>DBM.new</code>.
|
246
|
+
*/
|
247
|
+
static VALUE
|
248
|
+
fdbm_s_open(int argc, VALUE *argv, VALUE klass)
|
249
|
+
{
|
250
|
+
VALUE obj = fdbm_alloc(klass);
|
251
|
+
|
252
|
+
if (NIL_P(fdbm_initialize(argc, argv, obj))) {
|
253
|
+
return Qnil;
|
254
|
+
}
|
255
|
+
|
256
|
+
if (rb_block_given_p()) {
|
257
|
+
return rb_ensure(rb_yield, obj, fdbm_close, obj);
|
258
|
+
}
|
259
|
+
|
260
|
+
return obj;
|
261
|
+
}
|
262
|
+
|
263
|
+
static VALUE
|
264
|
+
fdbm_fetch(VALUE obj, VALUE keystr, VALUE ifnone)
|
265
|
+
{
|
266
|
+
datum key, value;
|
267
|
+
struct dbmdata *dbmp;
|
268
|
+
DBM *dbm;
|
269
|
+
long len;
|
270
|
+
|
271
|
+
ExportStringValue(keystr);
|
272
|
+
len = RSTRING_LEN(keystr);
|
273
|
+
if (TOO_LONG(len)) goto not_found;
|
274
|
+
key.dptr = RSTRING_PTR(keystr);
|
275
|
+
key.dsize = (DSIZE_TYPE)len;
|
276
|
+
|
277
|
+
GetDBM2(obj, dbmp, dbm);
|
278
|
+
value = dbm_fetch(dbm, key);
|
279
|
+
if (value.dptr == 0) {
|
280
|
+
not_found:
|
281
|
+
if (NIL_P(ifnone) && rb_block_given_p()) {
|
282
|
+
keystr = rb_str_dup(keystr);
|
283
|
+
OBJ_TAINT(keystr);
|
284
|
+
return rb_yield(keystr);
|
285
|
+
}
|
286
|
+
return ifnone;
|
287
|
+
}
|
288
|
+
return rb_tainted_str_new(value.dptr, value.dsize);
|
289
|
+
}
|
290
|
+
|
291
|
+
/*
|
292
|
+
* call-seq:
|
293
|
+
* dbm[key] -> string value or nil
|
294
|
+
*
|
295
|
+
* Return a value from the database by locating the key string
|
296
|
+
* provided. If the key is not found, returns nil.
|
297
|
+
*/
|
298
|
+
static VALUE
|
299
|
+
fdbm_aref(VALUE obj, VALUE keystr)
|
300
|
+
{
|
301
|
+
return fdbm_fetch(obj, keystr, Qnil);
|
302
|
+
}
|
303
|
+
|
304
|
+
/*
|
305
|
+
* call-seq:
|
306
|
+
* dbm.fetch(key[, ifnone]) -> value
|
307
|
+
*
|
308
|
+
* Return a value from the database by locating the key string
|
309
|
+
* provided. If the key is not found, returns +ifnone+. If +ifnone+
|
310
|
+
* is not given, raises IndexError.
|
311
|
+
*/
|
312
|
+
static VALUE
|
313
|
+
fdbm_fetch_m(int argc, VALUE *argv, VALUE obj)
|
314
|
+
{
|
315
|
+
VALUE keystr, valstr, ifnone;
|
316
|
+
|
317
|
+
rb_scan_args(argc, argv, "11", &keystr, &ifnone);
|
318
|
+
valstr = fdbm_fetch(obj, keystr, ifnone);
|
319
|
+
if (argc == 1 && !rb_block_given_p() && NIL_P(valstr))
|
320
|
+
rb_raise(rb_eIndexError, "key not found");
|
321
|
+
|
322
|
+
return valstr;
|
323
|
+
}
|
324
|
+
|
325
|
+
/*
|
326
|
+
* call-seq:
|
327
|
+
* dbm.key(value) -> string
|
328
|
+
*
|
329
|
+
* Returns the key for the specified value.
|
330
|
+
*/
|
331
|
+
static VALUE
|
332
|
+
fdbm_key(VALUE obj, VALUE valstr)
|
333
|
+
{
|
334
|
+
datum key, val;
|
335
|
+
struct dbmdata *dbmp;
|
336
|
+
DBM *dbm;
|
337
|
+
long len;
|
338
|
+
|
339
|
+
ExportStringValue(valstr);
|
340
|
+
len = RSTRING_LEN(valstr);
|
341
|
+
if (TOO_LONG(len)) return Qnil;
|
342
|
+
val.dptr = RSTRING_PTR(valstr);
|
343
|
+
val.dsize = (DSIZE_TYPE)len;
|
344
|
+
|
345
|
+
GetDBM2(obj, dbmp, dbm);
|
346
|
+
for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
|
347
|
+
val = dbm_fetch(dbm, key);
|
348
|
+
if ((long)val.dsize == RSTRING_LEN(valstr) &&
|
349
|
+
memcmp(val.dptr, RSTRING_PTR(valstr), val.dsize) == 0) {
|
350
|
+
return rb_tainted_str_new(key.dptr, key.dsize);
|
351
|
+
}
|
352
|
+
}
|
353
|
+
return Qnil;
|
354
|
+
}
|
355
|
+
|
356
|
+
/* :nodoc: */
|
357
|
+
static VALUE
|
358
|
+
fdbm_index(VALUE hash, VALUE value)
|
359
|
+
{
|
360
|
+
rb_warn("DBM#index is deprecated; use DBM#key");
|
361
|
+
return fdbm_key(hash, value);
|
362
|
+
}
|
363
|
+
|
364
|
+
/*
|
365
|
+
* call-seq:
|
366
|
+
* dbm.select {|key, value| block} -> array
|
367
|
+
*
|
368
|
+
* Returns a new array consisting of the [key, value] pairs for which the code
|
369
|
+
* block returns true.
|
370
|
+
*/
|
371
|
+
static VALUE
|
372
|
+
fdbm_select(VALUE obj)
|
373
|
+
{
|
374
|
+
VALUE new = rb_ary_new();
|
375
|
+
datum key, val;
|
376
|
+
DBM *dbm;
|
377
|
+
struct dbmdata *dbmp;
|
378
|
+
|
379
|
+
GetDBM2(obj, dbmp, dbm);
|
380
|
+
for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
|
381
|
+
VALUE assoc, v;
|
382
|
+
val = dbm_fetch(dbm, key);
|
383
|
+
assoc = rb_assoc_new(rb_tainted_str_new(key.dptr, key.dsize),
|
384
|
+
rb_tainted_str_new(val.dptr, val.dsize));
|
385
|
+
v = rb_yield(assoc);
|
386
|
+
if (RTEST(v)) {
|
387
|
+
rb_ary_push(new, assoc);
|
388
|
+
}
|
389
|
+
GetDBM2(obj, dbmp, dbm);
|
390
|
+
}
|
391
|
+
|
392
|
+
return new;
|
393
|
+
}
|
394
|
+
|
395
|
+
/*
|
396
|
+
* call-seq:
|
397
|
+
* dbm.values_at(key, ...) -> Array
|
398
|
+
*
|
399
|
+
* Returns an array containing the values associated with the given keys.
|
400
|
+
*/
|
401
|
+
static VALUE
|
402
|
+
fdbm_values_at(int argc, VALUE *argv, VALUE obj)
|
403
|
+
{
|
404
|
+
VALUE new = rb_ary_new2(argc);
|
405
|
+
int i;
|
406
|
+
|
407
|
+
for (i=0; i<argc; i++) {
|
408
|
+
rb_ary_push(new, fdbm_fetch(obj, argv[i], Qnil));
|
409
|
+
}
|
410
|
+
|
411
|
+
return new;
|
412
|
+
}
|
413
|
+
|
414
|
+
static void
|
415
|
+
fdbm_modify(VALUE obj)
|
416
|
+
{
|
417
|
+
if (OBJ_FROZEN(obj)) rb_error_frozen("DBM");
|
418
|
+
}
|
419
|
+
|
420
|
+
/*
|
421
|
+
* call-seq:
|
422
|
+
* dbm.delete(key)
|
423
|
+
*
|
424
|
+
* Deletes an entry from the database.
|
425
|
+
*/
|
426
|
+
static VALUE
|
427
|
+
fdbm_delete(VALUE obj, VALUE keystr)
|
428
|
+
{
|
429
|
+
datum key, value;
|
430
|
+
struct dbmdata *dbmp;
|
431
|
+
DBM *dbm;
|
432
|
+
VALUE valstr;
|
433
|
+
long len;
|
434
|
+
|
435
|
+
fdbm_modify(obj);
|
436
|
+
ExportStringValue(keystr);
|
437
|
+
len = RSTRING_LEN(keystr);
|
438
|
+
if (TOO_LONG(len)) goto not_found;
|
439
|
+
key.dptr = RSTRING_PTR(keystr);
|
440
|
+
key.dsize = (DSIZE_TYPE)len;
|
441
|
+
|
442
|
+
GetDBM2(obj, dbmp, dbm);
|
443
|
+
|
444
|
+
value = dbm_fetch(dbm, key);
|
445
|
+
if (value.dptr == 0) {
|
446
|
+
not_found:
|
447
|
+
if (rb_block_given_p()) return rb_yield(keystr);
|
448
|
+
return Qnil;
|
449
|
+
}
|
450
|
+
|
451
|
+
/* need to save value before dbm_delete() */
|
452
|
+
valstr = rb_tainted_str_new(value.dptr, value.dsize);
|
453
|
+
|
454
|
+
if (dbm_delete(dbm, key)) {
|
455
|
+
dbmp->di_size = -1;
|
456
|
+
rb_raise(rb_eDBMError, "dbm_delete failed");
|
457
|
+
}
|
458
|
+
else if (dbmp->di_size >= 0) {
|
459
|
+
dbmp->di_size--;
|
460
|
+
}
|
461
|
+
return valstr;
|
462
|
+
}
|
463
|
+
|
464
|
+
/*
|
465
|
+
* call-seq:
|
466
|
+
* dbm.shift() -> [key, value]
|
467
|
+
*
|
468
|
+
* Removes a [key, value] pair from the database, and returns it.
|
469
|
+
* If the database is empty, returns nil.
|
470
|
+
* The order in which values are removed/returned is not guaranteed.
|
471
|
+
*/
|
472
|
+
static VALUE
|
473
|
+
fdbm_shift(VALUE obj)
|
474
|
+
{
|
475
|
+
datum key, val;
|
476
|
+
struct dbmdata *dbmp;
|
477
|
+
DBM *dbm;
|
478
|
+
VALUE keystr, valstr;
|
479
|
+
|
480
|
+
fdbm_modify(obj);
|
481
|
+
GetDBM2(obj, dbmp, dbm);
|
482
|
+
dbmp->di_size = -1;
|
483
|
+
|
484
|
+
key = dbm_firstkey(dbm);
|
485
|
+
if (!key.dptr) return Qnil;
|
486
|
+
val = dbm_fetch(dbm, key);
|
487
|
+
keystr = rb_tainted_str_new(key.dptr, key.dsize);
|
488
|
+
valstr = rb_tainted_str_new(val.dptr, val.dsize);
|
489
|
+
dbm_delete(dbm, key);
|
490
|
+
|
491
|
+
return rb_assoc_new(keystr, valstr);
|
492
|
+
}
|
493
|
+
|
494
|
+
/*
|
495
|
+
* call-seq:
|
496
|
+
* dbm.reject! {|key, value| block} -> self
|
497
|
+
* dbm.delete_if {|key, value| block} -> self
|
498
|
+
*
|
499
|
+
* Deletes all entries for which the code block returns true.
|
500
|
+
* Returns self.
|
501
|
+
*/
|
502
|
+
static VALUE
|
503
|
+
fdbm_delete_if(VALUE obj)
|
504
|
+
{
|
505
|
+
datum key, val;
|
506
|
+
struct dbmdata *dbmp;
|
507
|
+
DBM *dbm;
|
508
|
+
VALUE keystr, valstr;
|
509
|
+
VALUE ret, ary = rb_ary_tmp_new(0);
|
510
|
+
int status = 0;
|
511
|
+
long i, n;
|
512
|
+
|
513
|
+
fdbm_modify(obj);
|
514
|
+
GetDBM2(obj, dbmp, dbm);
|
515
|
+
n = dbmp->di_size;
|
516
|
+
dbmp->di_size = -1;
|
517
|
+
|
518
|
+
for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
|
519
|
+
val = dbm_fetch(dbm, key);
|
520
|
+
keystr = rb_tainted_str_new(key.dptr, key.dsize);
|
521
|
+
OBJ_FREEZE(keystr);
|
522
|
+
valstr = rb_tainted_str_new(val.dptr, val.dsize);
|
523
|
+
ret = rb_protect(rb_yield, rb_assoc_new(rb_str_dup(keystr), valstr), &status);
|
524
|
+
if (status != 0) break;
|
525
|
+
if (RTEST(ret)) rb_ary_push(ary, keystr);
|
526
|
+
GetDBM2(obj, dbmp, dbm);
|
527
|
+
}
|
528
|
+
|
529
|
+
for (i = 0; i < RARRAY_LEN(ary); i++) {
|
530
|
+
keystr = RARRAY_AREF(ary, i);
|
531
|
+
key.dptr = RSTRING_PTR(keystr);
|
532
|
+
key.dsize = (DSIZE_TYPE)RSTRING_LEN(keystr);
|
533
|
+
if (dbm_delete(dbm, key)) {
|
534
|
+
rb_raise(rb_eDBMError, "dbm_delete failed");
|
535
|
+
}
|
536
|
+
}
|
537
|
+
if (status) rb_jump_tag(status);
|
538
|
+
if (n > 0) dbmp->di_size = n - RARRAY_LEN(ary);
|
539
|
+
rb_ary_clear(ary);
|
540
|
+
|
541
|
+
return obj;
|
542
|
+
}
|
543
|
+
|
544
|
+
/*
|
545
|
+
* call-seq:
|
546
|
+
* dbm.clear
|
547
|
+
*
|
548
|
+
* Deletes all data from the database.
|
549
|
+
*/
|
550
|
+
static VALUE
|
551
|
+
fdbm_clear(VALUE obj)
|
552
|
+
{
|
553
|
+
datum key;
|
554
|
+
struct dbmdata *dbmp;
|
555
|
+
DBM *dbm;
|
556
|
+
|
557
|
+
fdbm_modify(obj);
|
558
|
+
GetDBM2(obj, dbmp, dbm);
|
559
|
+
dbmp->di_size = -1;
|
560
|
+
while (key = dbm_firstkey(dbm), key.dptr) {
|
561
|
+
if (dbm_delete(dbm, key)) {
|
562
|
+
rb_raise(rb_eDBMError, "dbm_delete failed");
|
563
|
+
}
|
564
|
+
}
|
565
|
+
dbmp->di_size = 0;
|
566
|
+
|
567
|
+
return obj;
|
568
|
+
}
|
569
|
+
|
570
|
+
/*
|
571
|
+
* call-seq:
|
572
|
+
* dbm.invert -> hash
|
573
|
+
*
|
574
|
+
* Returns a Hash (not a DBM database) created by using each value in the
|
575
|
+
* database as a key, with the corresponding key as its value.
|
576
|
+
*/
|
577
|
+
static VALUE
|
578
|
+
fdbm_invert(VALUE obj)
|
579
|
+
{
|
580
|
+
datum key, val;
|
581
|
+
struct dbmdata *dbmp;
|
582
|
+
DBM *dbm;
|
583
|
+
VALUE keystr, valstr;
|
584
|
+
VALUE hash = rb_hash_new();
|
585
|
+
|
586
|
+
GetDBM2(obj, dbmp, dbm);
|
587
|
+
for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
|
588
|
+
val = dbm_fetch(dbm, key);
|
589
|
+
keystr = rb_tainted_str_new(key.dptr, key.dsize);
|
590
|
+
valstr = rb_tainted_str_new(val.dptr, val.dsize);
|
591
|
+
rb_hash_aset(hash, valstr, keystr);
|
592
|
+
}
|
593
|
+
return hash;
|
594
|
+
}
|
595
|
+
|
596
|
+
static VALUE fdbm_store(VALUE,VALUE,VALUE);
|
597
|
+
|
598
|
+
static VALUE
|
599
|
+
update_i(RB_BLOCK_CALL_FUNC_ARGLIST(pair, dbm))
|
600
|
+
{
|
601
|
+
const VALUE *ptr;
|
602
|
+
Check_Type(pair, T_ARRAY);
|
603
|
+
if (RARRAY_LEN(pair) < 2) {
|
604
|
+
rb_raise(rb_eArgError, "pair must be [key, value]");
|
605
|
+
}
|
606
|
+
ptr = RARRAY_CONST_PTR(pair);
|
607
|
+
fdbm_store(dbm, ptr[0], ptr[1]);
|
608
|
+
return Qnil;
|
609
|
+
}
|
610
|
+
|
611
|
+
/*
|
612
|
+
* call-seq:
|
613
|
+
* dbm.update(obj)
|
614
|
+
*
|
615
|
+
* Updates the database with multiple values from the specified object.
|
616
|
+
* Takes any object which implements the each_pair method, including
|
617
|
+
* Hash and DBM objects.
|
618
|
+
*/
|
619
|
+
static VALUE
|
620
|
+
fdbm_update(VALUE obj, VALUE other)
|
621
|
+
{
|
622
|
+
rb_block_call(other, rb_intern("each_pair"), 0, 0, update_i, obj);
|
623
|
+
return obj;
|
624
|
+
}
|
625
|
+
|
626
|
+
/*
|
627
|
+
* call-seq:
|
628
|
+
* dbm.replace(obj)
|
629
|
+
*
|
630
|
+
* Replaces the contents of the database with the contents of the specified
|
631
|
+
* object. Takes any object which implements the each_pair method, including
|
632
|
+
* Hash and DBM objects.
|
633
|
+
*/
|
634
|
+
static VALUE
|
635
|
+
fdbm_replace(VALUE obj, VALUE other)
|
636
|
+
{
|
637
|
+
fdbm_clear(obj);
|
638
|
+
rb_block_call(other, rb_intern("each_pair"), 0, 0, update_i, obj);
|
639
|
+
return obj;
|
640
|
+
}
|
641
|
+
|
642
|
+
/*
|
643
|
+
* call-seq:
|
644
|
+
* dbm.store(key, value) -> value
|
645
|
+
* dbm[key] = value
|
646
|
+
*
|
647
|
+
* Stores the specified string value in the database, indexed via the
|
648
|
+
* string key provided.
|
649
|
+
*/
|
650
|
+
static VALUE
|
651
|
+
fdbm_store(VALUE obj, VALUE keystr, VALUE valstr)
|
652
|
+
{
|
653
|
+
datum key, val;
|
654
|
+
struct dbmdata *dbmp;
|
655
|
+
DBM *dbm;
|
656
|
+
|
657
|
+
fdbm_modify(obj);
|
658
|
+
keystr = rb_obj_as_string(keystr);
|
659
|
+
valstr = rb_obj_as_string(valstr);
|
660
|
+
|
661
|
+
key.dptr = RSTRING_PTR(keystr);
|
662
|
+
key.dsize = RSTRING_DSIZE(keystr);
|
663
|
+
|
664
|
+
val.dptr = RSTRING_PTR(valstr);
|
665
|
+
val.dsize = RSTRING_DSIZE(valstr);
|
666
|
+
|
667
|
+
GetDBM2(obj, dbmp, dbm);
|
668
|
+
dbmp->di_size = -1;
|
669
|
+
if (dbm_store(dbm, key, val, DBM_REPLACE)) {
|
670
|
+
dbm_clearerr(dbm);
|
671
|
+
if (errno == EPERM) rb_sys_fail(0);
|
672
|
+
rb_raise(rb_eDBMError, "dbm_store failed");
|
673
|
+
}
|
674
|
+
|
675
|
+
return valstr;
|
676
|
+
}
|
677
|
+
|
678
|
+
/*
|
679
|
+
* call-seq:
|
680
|
+
* dbm.length -> integer
|
681
|
+
* dbm.size -> integer
|
682
|
+
*
|
683
|
+
* Returns the number of entries in the database.
|
684
|
+
*/
|
685
|
+
static VALUE
|
686
|
+
fdbm_length(VALUE obj)
|
687
|
+
{
|
688
|
+
datum key;
|
689
|
+
struct dbmdata *dbmp;
|
690
|
+
DBM *dbm;
|
691
|
+
int i = 0;
|
692
|
+
|
693
|
+
GetDBM2(obj, dbmp, dbm);
|
694
|
+
if (dbmp->di_size > 0) return INT2FIX(dbmp->di_size);
|
695
|
+
|
696
|
+
for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
|
697
|
+
i++;
|
698
|
+
}
|
699
|
+
dbmp->di_size = i;
|
700
|
+
|
701
|
+
return INT2FIX(i);
|
702
|
+
}
|
703
|
+
|
704
|
+
/*
|
705
|
+
* call-seq:
|
706
|
+
* dbm.empty?
|
707
|
+
*
|
708
|
+
* Returns true if the database is empty, false otherwise.
|
709
|
+
*/
|
710
|
+
static VALUE
|
711
|
+
fdbm_empty_p(VALUE obj)
|
712
|
+
{
|
713
|
+
datum key;
|
714
|
+
struct dbmdata *dbmp;
|
715
|
+
DBM *dbm;
|
716
|
+
|
717
|
+
GetDBM2(obj, dbmp, dbm);
|
718
|
+
if (dbmp->di_size < 0) {
|
719
|
+
dbm = dbmp->di_dbm;
|
720
|
+
|
721
|
+
for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
|
722
|
+
return Qfalse;
|
723
|
+
}
|
724
|
+
}
|
725
|
+
else {
|
726
|
+
if (dbmp->di_size)
|
727
|
+
return Qfalse;
|
728
|
+
}
|
729
|
+
return Qtrue;
|
730
|
+
}
|
731
|
+
|
732
|
+
/*
|
733
|
+
* call-seq:
|
734
|
+
* dbm.each_value {|value| block} -> self
|
735
|
+
*
|
736
|
+
* Calls the block once for each value string in the database. Returns self.
|
737
|
+
*/
|
738
|
+
static VALUE
|
739
|
+
fdbm_each_value(VALUE obj)
|
740
|
+
{
|
741
|
+
datum key, val;
|
742
|
+
struct dbmdata *dbmp;
|
743
|
+
DBM *dbm;
|
744
|
+
|
745
|
+
RETURN_ENUMERATOR(obj, 0, 0);
|
746
|
+
|
747
|
+
GetDBM2(obj, dbmp, dbm);
|
748
|
+
for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
|
749
|
+
val = dbm_fetch(dbm, key);
|
750
|
+
rb_yield(rb_tainted_str_new(val.dptr, val.dsize));
|
751
|
+
GetDBM2(obj, dbmp, dbm);
|
752
|
+
}
|
753
|
+
return obj;
|
754
|
+
}
|
755
|
+
|
756
|
+
/*
|
757
|
+
* call-seq:
|
758
|
+
* dbm.each_key {|key| block} -> self
|
759
|
+
*
|
760
|
+
* Calls the block once for each key string in the database. Returns self.
|
761
|
+
*/
|
762
|
+
static VALUE
|
763
|
+
fdbm_each_key(VALUE obj)
|
764
|
+
{
|
765
|
+
datum key;
|
766
|
+
struct dbmdata *dbmp;
|
767
|
+
DBM *dbm;
|
768
|
+
|
769
|
+
RETURN_ENUMERATOR(obj, 0, 0);
|
770
|
+
|
771
|
+
GetDBM2(obj, dbmp, dbm);
|
772
|
+
for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
|
773
|
+
rb_yield(rb_tainted_str_new(key.dptr, key.dsize));
|
774
|
+
GetDBM2(obj, dbmp, dbm);
|
775
|
+
}
|
776
|
+
return obj;
|
777
|
+
}
|
778
|
+
|
779
|
+
/*
|
780
|
+
* call-seq:
|
781
|
+
* dbm.each_pair {|key,value| block} -> self
|
782
|
+
*
|
783
|
+
* Calls the block once for each [key, value] pair in the database.
|
784
|
+
* Returns self.
|
785
|
+
*/
|
786
|
+
static VALUE
|
787
|
+
fdbm_each_pair(VALUE obj)
|
788
|
+
{
|
789
|
+
datum key, val;
|
790
|
+
DBM *dbm;
|
791
|
+
struct dbmdata *dbmp;
|
792
|
+
VALUE keystr, valstr;
|
793
|
+
|
794
|
+
RETURN_ENUMERATOR(obj, 0, 0);
|
795
|
+
|
796
|
+
GetDBM2(obj, dbmp, dbm);
|
797
|
+
|
798
|
+
for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
|
799
|
+
val = dbm_fetch(dbm, key);
|
800
|
+
keystr = rb_tainted_str_new(key.dptr, key.dsize);
|
801
|
+
valstr = rb_tainted_str_new(val.dptr, val.dsize);
|
802
|
+
rb_yield(rb_assoc_new(keystr, valstr));
|
803
|
+
GetDBM2(obj, dbmp, dbm);
|
804
|
+
}
|
805
|
+
|
806
|
+
return obj;
|
807
|
+
}
|
808
|
+
|
809
|
+
/*
|
810
|
+
* call-seq:
|
811
|
+
* dbm.keys -> array
|
812
|
+
*
|
813
|
+
* Returns an array of all the string keys in the database.
|
814
|
+
*/
|
815
|
+
static VALUE
|
816
|
+
fdbm_keys(VALUE obj)
|
817
|
+
{
|
818
|
+
datum key;
|
819
|
+
struct dbmdata *dbmp;
|
820
|
+
DBM *dbm;
|
821
|
+
VALUE ary;
|
822
|
+
|
823
|
+
GetDBM2(obj, dbmp, dbm);
|
824
|
+
|
825
|
+
ary = rb_ary_new();
|
826
|
+
for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
|
827
|
+
rb_ary_push(ary, rb_tainted_str_new(key.dptr, key.dsize));
|
828
|
+
}
|
829
|
+
|
830
|
+
return ary;
|
831
|
+
}
|
832
|
+
|
833
|
+
/*
|
834
|
+
* call-seq:
|
835
|
+
* dbm.values -> array
|
836
|
+
*
|
837
|
+
* Returns an array of all the string values in the database.
|
838
|
+
*/
|
839
|
+
static VALUE
|
840
|
+
fdbm_values(VALUE obj)
|
841
|
+
{
|
842
|
+
datum key, val;
|
843
|
+
struct dbmdata *dbmp;
|
844
|
+
DBM *dbm;
|
845
|
+
VALUE ary;
|
846
|
+
|
847
|
+
GetDBM2(obj, dbmp, dbm);
|
848
|
+
ary = rb_ary_new();
|
849
|
+
for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
|
850
|
+
val = dbm_fetch(dbm, key);
|
851
|
+
rb_ary_push(ary, rb_tainted_str_new(val.dptr, val.dsize));
|
852
|
+
}
|
853
|
+
|
854
|
+
return ary;
|
855
|
+
}
|
856
|
+
|
857
|
+
/*
|
858
|
+
* call-seq:
|
859
|
+
* dbm.include?(key) -> boolean
|
860
|
+
* dbm.has_key?(key) -> boolean
|
861
|
+
* dbm.member?(key) -> boolean
|
862
|
+
* dbm.key?(key) -> boolean
|
863
|
+
*
|
864
|
+
* Returns true if the database contains the specified key, false otherwise.
|
865
|
+
*/
|
866
|
+
static VALUE
|
867
|
+
fdbm_has_key(VALUE obj, VALUE keystr)
|
868
|
+
{
|
869
|
+
datum key, val;
|
870
|
+
struct dbmdata *dbmp;
|
871
|
+
DBM *dbm;
|
872
|
+
long len;
|
873
|
+
|
874
|
+
ExportStringValue(keystr);
|
875
|
+
len = RSTRING_LEN(keystr);
|
876
|
+
if (TOO_LONG(len)) return Qfalse;
|
877
|
+
key.dptr = RSTRING_PTR(keystr);
|
878
|
+
key.dsize = (DSIZE_TYPE)len;
|
879
|
+
|
880
|
+
GetDBM2(obj, dbmp, dbm);
|
881
|
+
val = dbm_fetch(dbm, key);
|
882
|
+
if (val.dptr) return Qtrue;
|
883
|
+
return Qfalse;
|
884
|
+
}
|
885
|
+
|
886
|
+
/*
|
887
|
+
* call-seq:
|
888
|
+
* dbm.has_value?(value) -> boolean
|
889
|
+
* dbm.value?(value) -> boolean
|
890
|
+
*
|
891
|
+
* Returns true if the database contains the specified string value, false
|
892
|
+
* otherwise.
|
893
|
+
*/
|
894
|
+
static VALUE
|
895
|
+
fdbm_has_value(VALUE obj, VALUE valstr)
|
896
|
+
{
|
897
|
+
datum key, val;
|
898
|
+
struct dbmdata *dbmp;
|
899
|
+
DBM *dbm;
|
900
|
+
long len;
|
901
|
+
|
902
|
+
ExportStringValue(valstr);
|
903
|
+
len = RSTRING_LEN(valstr);
|
904
|
+
if (TOO_LONG(len)) return Qfalse;
|
905
|
+
val.dptr = RSTRING_PTR(valstr);
|
906
|
+
val.dsize = (DSIZE_TYPE)len;
|
907
|
+
|
908
|
+
GetDBM2(obj, dbmp, dbm);
|
909
|
+
for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
|
910
|
+
val = dbm_fetch(dbm, key);
|
911
|
+
if ((DSIZE_TYPE)val.dsize == (DSIZE_TYPE)RSTRING_LEN(valstr) &&
|
912
|
+
memcmp(val.dptr, RSTRING_PTR(valstr), val.dsize) == 0)
|
913
|
+
return Qtrue;
|
914
|
+
}
|
915
|
+
return Qfalse;
|
916
|
+
}
|
917
|
+
|
918
|
+
/*
|
919
|
+
* call-seq:
|
920
|
+
* dbm.to_a -> array
|
921
|
+
*
|
922
|
+
* Converts the contents of the database to an array of [key, value] arrays,
|
923
|
+
* and returns it.
|
924
|
+
*/
|
925
|
+
static VALUE
|
926
|
+
fdbm_to_a(VALUE obj)
|
927
|
+
{
|
928
|
+
datum key, val;
|
929
|
+
struct dbmdata *dbmp;
|
930
|
+
DBM *dbm;
|
931
|
+
VALUE ary;
|
932
|
+
|
933
|
+
GetDBM2(obj, dbmp, dbm);
|
934
|
+
ary = rb_ary_new();
|
935
|
+
for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
|
936
|
+
val = dbm_fetch(dbm, key);
|
937
|
+
rb_ary_push(ary, rb_assoc_new(rb_tainted_str_new(key.dptr, key.dsize),
|
938
|
+
rb_tainted_str_new(val.dptr, val.dsize)));
|
939
|
+
}
|
940
|
+
|
941
|
+
return ary;
|
942
|
+
}
|
943
|
+
|
944
|
+
/*
|
945
|
+
* call-seq:
|
946
|
+
* dbm.to_hash -> hash
|
947
|
+
*
|
948
|
+
* Converts the contents of the database to an in-memory Hash object, and
|
949
|
+
* returns it.
|
950
|
+
*/
|
951
|
+
static VALUE
|
952
|
+
fdbm_to_hash(VALUE obj)
|
953
|
+
{
|
954
|
+
datum key, val;
|
955
|
+
struct dbmdata *dbmp;
|
956
|
+
DBM *dbm;
|
957
|
+
VALUE hash;
|
958
|
+
|
959
|
+
GetDBM2(obj, dbmp, dbm);
|
960
|
+
hash = rb_hash_new();
|
961
|
+
for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
|
962
|
+
val = dbm_fetch(dbm, key);
|
963
|
+
rb_hash_aset(hash, rb_tainted_str_new(key.dptr, key.dsize),
|
964
|
+
rb_tainted_str_new(val.dptr, val.dsize));
|
965
|
+
}
|
966
|
+
|
967
|
+
return hash;
|
968
|
+
}
|
969
|
+
|
970
|
+
/*
|
971
|
+
* call-seq:
|
972
|
+
* dbm.reject {|key,value| block} -> Hash
|
973
|
+
*
|
974
|
+
* Converts the contents of the database to an in-memory Hash, then calls
|
975
|
+
* Hash#reject with the specified code block, returning a new Hash.
|
976
|
+
*/
|
977
|
+
static VALUE
|
978
|
+
fdbm_reject(VALUE obj)
|
979
|
+
{
|
980
|
+
return rb_hash_delete_if(fdbm_to_hash(obj));
|
981
|
+
}
|
982
|
+
|
983
|
+
/*
|
984
|
+
* == Introduction
|
985
|
+
*
|
986
|
+
* The DBM class provides a wrapper to a Unix-style
|
987
|
+
* {dbm}[http://en.wikipedia.org/wiki/Dbm] or Database Manager library.
|
988
|
+
*
|
989
|
+
* Dbm databases do not have tables or columns; they are simple key-value
|
990
|
+
* data stores, like a Ruby Hash except not resident in RAM. Keys and values
|
991
|
+
* must be strings.
|
992
|
+
*
|
993
|
+
* The exact library used depends on how Ruby was compiled. It could be any
|
994
|
+
* of the following:
|
995
|
+
*
|
996
|
+
* - The original ndbm library is released in 4.3BSD.
|
997
|
+
* It is based on dbm library in Unix Version 7 but has different API to
|
998
|
+
* support multiple databases in a process.
|
999
|
+
* - {Berkeley DB}[http://en.wikipedia.org/wiki/Berkeley_DB] versions
|
1000
|
+
* 1 thru 5, also known as BDB and Sleepycat DB, now owned by Oracle
|
1001
|
+
* Corporation.
|
1002
|
+
* - Berkeley DB 1.x, still found in 4.4BSD derivatives (FreeBSD, OpenBSD, etc).
|
1003
|
+
* - {gdbm}[http://www.gnu.org/software/gdbm/], the GNU implementation of dbm.
|
1004
|
+
* - {qdbm}[http://fallabs.com/qdbm/index.html], another open source
|
1005
|
+
* reimplementation of dbm.
|
1006
|
+
*
|
1007
|
+
* All of these dbm implementations have their own Ruby interfaces
|
1008
|
+
* available, which provide richer (but varying) APIs.
|
1009
|
+
*
|
1010
|
+
* == Cautions
|
1011
|
+
*
|
1012
|
+
* Before you decide to use DBM, there are some issues you should consider:
|
1013
|
+
*
|
1014
|
+
* - Each implementation of dbm has its own file format. Generally, dbm
|
1015
|
+
* libraries will not read each other's files. This makes dbm files
|
1016
|
+
* a bad choice for data exchange.
|
1017
|
+
*
|
1018
|
+
* - Even running the same OS and the same dbm implementation, the database
|
1019
|
+
* file format may depend on the CPU architecture. For example, files may
|
1020
|
+
* not be portable between PowerPC and 386, or between 32 and 64 bit Linux.
|
1021
|
+
*
|
1022
|
+
* - Different versions of Berkeley DB use different file formats. A change to
|
1023
|
+
* the OS may therefore break DBM access to existing files.
|
1024
|
+
*
|
1025
|
+
* - Data size limits vary between implementations. Original Berkeley DB was
|
1026
|
+
* limited to 2GB of data. Dbm libraries also sometimes limit the total
|
1027
|
+
* size of a key/value pair, and the total size of all the keys that hash
|
1028
|
+
* to the same value. These limits can be as little as 512 bytes. That said,
|
1029
|
+
* gdbm and recent versions of Berkeley DB do away with these limits.
|
1030
|
+
*
|
1031
|
+
* Given the above cautions, DBM is not a good choice for long term storage of
|
1032
|
+
* important data. It is probably best used as a fast and easy alternative
|
1033
|
+
* to a Hash for processing large amounts of data.
|
1034
|
+
*
|
1035
|
+
* == Example
|
1036
|
+
*
|
1037
|
+
* require 'dbm'
|
1038
|
+
* db = DBM.open('rfcs', 0666, DBM::WRCREAT)
|
1039
|
+
* db['822'] = 'Standard for the Format of ARPA Internet Text Messages'
|
1040
|
+
* db['1123'] = 'Requirements for Internet Hosts - Application and Support'
|
1041
|
+
* db['3068'] = 'An Anycast Prefix for 6to4 Relay Routers'
|
1042
|
+
* puts db['822']
|
1043
|
+
*/
|
1044
|
+
void
|
1045
|
+
Init_dbm(void)
|
1046
|
+
{
|
1047
|
+
rb_cDBM = rb_define_class("DBM", rb_cObject);
|
1048
|
+
/* Document-class: DBMError
|
1049
|
+
* Exception class used to return errors from the dbm library.
|
1050
|
+
*/
|
1051
|
+
rb_eDBMError = rb_define_class("DBMError", rb_eStandardError);
|
1052
|
+
rb_include_module(rb_cDBM, rb_mEnumerable);
|
1053
|
+
|
1054
|
+
rb_define_alloc_func(rb_cDBM, fdbm_alloc);
|
1055
|
+
rb_define_singleton_method(rb_cDBM, "open", fdbm_s_open, -1);
|
1056
|
+
|
1057
|
+
rb_define_method(rb_cDBM, "initialize", fdbm_initialize, -1);
|
1058
|
+
rb_define_method(rb_cDBM, "close", fdbm_close, 0);
|
1059
|
+
rb_define_method(rb_cDBM, "closed?", fdbm_closed, 0);
|
1060
|
+
rb_define_method(rb_cDBM, "[]", fdbm_aref, 1);
|
1061
|
+
rb_define_method(rb_cDBM, "fetch", fdbm_fetch_m, -1);
|
1062
|
+
rb_define_method(rb_cDBM, "[]=", fdbm_store, 2);
|
1063
|
+
rb_define_method(rb_cDBM, "store", fdbm_store, 2);
|
1064
|
+
rb_define_method(rb_cDBM, "index", fdbm_index, 1);
|
1065
|
+
rb_define_method(rb_cDBM, "key", fdbm_key, 1);
|
1066
|
+
rb_define_method(rb_cDBM, "select", fdbm_select, 0);
|
1067
|
+
rb_define_method(rb_cDBM, "values_at", fdbm_values_at, -1);
|
1068
|
+
rb_define_method(rb_cDBM, "length", fdbm_length, 0);
|
1069
|
+
rb_define_method(rb_cDBM, "size", fdbm_length, 0);
|
1070
|
+
rb_define_method(rb_cDBM, "empty?", fdbm_empty_p, 0);
|
1071
|
+
rb_define_method(rb_cDBM, "each", fdbm_each_pair, 0);
|
1072
|
+
rb_define_method(rb_cDBM, "each_value", fdbm_each_value, 0);
|
1073
|
+
rb_define_method(rb_cDBM, "each_key", fdbm_each_key, 0);
|
1074
|
+
rb_define_method(rb_cDBM, "each_pair", fdbm_each_pair, 0);
|
1075
|
+
rb_define_method(rb_cDBM, "keys", fdbm_keys, 0);
|
1076
|
+
rb_define_method(rb_cDBM, "values", fdbm_values, 0);
|
1077
|
+
rb_define_method(rb_cDBM, "shift", fdbm_shift, 0);
|
1078
|
+
rb_define_method(rb_cDBM, "delete", fdbm_delete, 1);
|
1079
|
+
rb_define_method(rb_cDBM, "delete_if", fdbm_delete_if, 0);
|
1080
|
+
rb_define_method(rb_cDBM, "reject!", fdbm_delete_if, 0);
|
1081
|
+
rb_define_method(rb_cDBM, "reject", fdbm_reject, 0);
|
1082
|
+
rb_define_method(rb_cDBM, "clear", fdbm_clear, 0);
|
1083
|
+
rb_define_method(rb_cDBM, "invert", fdbm_invert, 0);
|
1084
|
+
rb_define_method(rb_cDBM, "update", fdbm_update, 1);
|
1085
|
+
rb_define_method(rb_cDBM, "replace", fdbm_replace, 1);
|
1086
|
+
|
1087
|
+
rb_define_method(rb_cDBM, "include?", fdbm_has_key, 1);
|
1088
|
+
rb_define_method(rb_cDBM, "has_key?", fdbm_has_key, 1);
|
1089
|
+
rb_define_method(rb_cDBM, "member?", fdbm_has_key, 1);
|
1090
|
+
rb_define_method(rb_cDBM, "has_value?", fdbm_has_value, 1);
|
1091
|
+
rb_define_method(rb_cDBM, "key?", fdbm_has_key, 1);
|
1092
|
+
rb_define_method(rb_cDBM, "value?", fdbm_has_value, 1);
|
1093
|
+
|
1094
|
+
rb_define_method(rb_cDBM, "to_a", fdbm_to_a, 0);
|
1095
|
+
rb_define_method(rb_cDBM, "to_hash", fdbm_to_hash, 0);
|
1096
|
+
|
1097
|
+
/* Indicates that dbm_open() should open the database in read-only mode */
|
1098
|
+
rb_define_const(rb_cDBM, "READER", INT2FIX(O_RDONLY|RUBY_DBM_RW_BIT));
|
1099
|
+
|
1100
|
+
/* Indicates that dbm_open() should open the database in read/write mode */
|
1101
|
+
rb_define_const(rb_cDBM, "WRITER", INT2FIX(O_RDWR|RUBY_DBM_RW_BIT));
|
1102
|
+
|
1103
|
+
/* Indicates that dbm_open() should open the database in read/write mode,
|
1104
|
+
* and create it if it does not already exist
|
1105
|
+
*/
|
1106
|
+
rb_define_const(rb_cDBM, "WRCREAT", INT2FIX(O_RDWR|O_CREAT|RUBY_DBM_RW_BIT));
|
1107
|
+
|
1108
|
+
/* Indicates that dbm_open() should open the database in read/write mode,
|
1109
|
+
* create it if it does not already exist, and delete all contents if it
|
1110
|
+
* does already exist.
|
1111
|
+
*/
|
1112
|
+
rb_define_const(rb_cDBM, "NEWDB", INT2FIX(O_RDWR|O_CREAT|O_TRUNC|RUBY_DBM_RW_BIT));
|
1113
|
+
|
1114
|
+
{
|
1115
|
+
VALUE version;
|
1116
|
+
#if defined(_DBM_IOERR)
|
1117
|
+
version = rb_str_new2("ndbm (4.3BSD)");
|
1118
|
+
#elif defined(RUBYDBM_GDBM_HEADER)
|
1119
|
+
# if defined(HAVE_DECLARED_LIBVAR_GDBM_VERSION)
|
1120
|
+
/* since gdbm 1.9 */
|
1121
|
+
version = rb_str_new2(gdbm_version);
|
1122
|
+
# elif defined(HAVE_UNDECLARED_LIBVAR_GDBM_VERSION)
|
1123
|
+
/* ndbm.h doesn't declare gdbm_version until gdbm 1.8.3.
|
1124
|
+
* See extconf.rb for more information. */
|
1125
|
+
RUBY_EXTERN char *gdbm_version;
|
1126
|
+
version = rb_str_new2(gdbm_version);
|
1127
|
+
# else
|
1128
|
+
version = rb_str_new2("GDBM (unknown)");
|
1129
|
+
# endif
|
1130
|
+
#elif defined(RUBYDBM_DB_HEADER)
|
1131
|
+
# if defined(HAVE_DB_VERSION)
|
1132
|
+
/* The version of the dbm library, if using Berkeley DB */
|
1133
|
+
version = rb_str_new2(db_version(NULL, NULL, NULL));
|
1134
|
+
# else
|
1135
|
+
version = rb_str_new2("Berkeley DB (unknown)");
|
1136
|
+
# endif
|
1137
|
+
#elif defined(_RELIC_H)
|
1138
|
+
# if defined(HAVE_DPVERSION)
|
1139
|
+
version = rb_sprintf("QDBM %s", dpversion);
|
1140
|
+
# else
|
1141
|
+
version = rb_str_new2("QDBM (unknown)");
|
1142
|
+
# endif
|
1143
|
+
#else
|
1144
|
+
version = rb_str_new2("ndbm (unknown)");
|
1145
|
+
#endif
|
1146
|
+
/*
|
1147
|
+
* Identifies ndbm library version.
|
1148
|
+
*
|
1149
|
+
* Examples:
|
1150
|
+
*
|
1151
|
+
* - "ndbm (4.3BSD)"
|
1152
|
+
* - "Berkeley DB 4.8.30: (April 9, 2010)"
|
1153
|
+
* - "Berkeley DB (unknown)" (4.4BSD, maybe)
|
1154
|
+
* - "GDBM version 1.8.3. 10/15/2002 (built Jul 1 2011 12:32:45)"
|
1155
|
+
* - "QDBM 1.8.78"
|
1156
|
+
*
|
1157
|
+
*/
|
1158
|
+
rb_define_const(rb_cDBM, "VERSION", version);
|
1159
|
+
}
|
1160
|
+
}
|