bdb1 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
data/examples/zeroc.rb ADDED
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/ruby -I../src
2
+
3
+ require 'bdb1'
4
+ module ZeroC
5
+ def bdb1_fetch_value(a)
6
+ a.sub(/\0$/, '')
7
+ end
8
+ def bdb1_store_value(a)
9
+ a + "\0"
10
+ end
11
+ alias bdb1_fetch_key bdb1_fetch_value
12
+ alias bdb1_store_key bdb1_store_value
13
+ end
14
+
15
+ module BDB1
16
+ class A < Btree
17
+ include ZeroC
18
+ end
19
+ end
20
+
21
+ $option = {"set_pagesize" => 1024, "set_cachesize" => 32 * 1024}
22
+
23
+ db = BDB1::A.open "basic", "w", $option
24
+ File.foreach("wordtest") do |line|
25
+ line.chomp!
26
+ db[line] = line.reverse
27
+ end
28
+ db.each do |k, v|
29
+ if k != v.reverse || /\0/ =~ k || /\0/ =~ v
30
+ print "ERROR : #{k.inspect} -- #{v.inspect}\n"
31
+ end
32
+ end
33
+ db.close
34
+
35
+ db = BDB1::Btree.open "basic", $option
36
+ db.each do |k, v|
37
+ if k[-1].to_i != 0 || v[-1].to_i != 0
38
+ print "ERROR : #{k.inspect} -- #{v.inspect}\n"
39
+ end
40
+ end
data/ext/bdb1/bdb1.c ADDED
@@ -0,0 +1,1868 @@
1
+ #include "bdb1.h"
2
+
3
+ VALUE bdb1_eFatal;
4
+ VALUE bdb1_mDb, bdb1_mMarshal, bdb1_cCommon, bdb1_cRecnum;
5
+ static ID id_dump, id_load;
6
+
7
+ ID bdb1_id_current_db;
8
+
9
+ static VALUE bdb1_cBtree, bdb1_cHash, bdb1_cUnknown;
10
+
11
+ static ID id_bt_compare, id_bt_prefix, id_h_hash, bdb1_id_call;
12
+
13
+ static VALUE bdb1_errstr;
14
+ static int bdb1_errcall = 0;
15
+
16
+ static char *
17
+ db_strerror(int err)
18
+ {
19
+ if (err == 0)
20
+ return "" ;
21
+
22
+ if (err > 0)
23
+ return strerror(err) ;
24
+
25
+ return "Unknown Error" ;
26
+ }
27
+
28
+ int
29
+ bdb1_test_error(comm)
30
+ int comm;
31
+ {
32
+ VALUE error;
33
+
34
+ switch (comm) {
35
+ case 0:
36
+ case 1:
37
+ break;
38
+ default:
39
+ error = bdb1_eFatal;
40
+ if (bdb1_errcall) {
41
+ bdb1_errcall = 0;
42
+ rb_raise(error, "%s -- %s", StringValuePtr(bdb1_errstr), db_strerror(comm));
43
+ }
44
+ else
45
+ rb_raise(error, "%s", db_strerror(errno));
46
+ }
47
+ return comm;
48
+ }
49
+
50
+ static VALUE
51
+ test_dump(obj, key, a, type_kv)
52
+ VALUE obj;
53
+ DBT *key;
54
+ VALUE a;
55
+ int type_kv;
56
+ {
57
+ bdb1_DB *dbst;
58
+ int is_nil = 0;
59
+ VALUE tmp = a;
60
+
61
+ Data_Get_Struct(obj, bdb1_DB, dbst);
62
+ if (dbst->filter[type_kv]) {
63
+ if (FIXNUM_P(dbst->filter[type_kv])) {
64
+ tmp = rb_funcall(obj, NUM2INT(dbst->filter[type_kv]), 1, a);
65
+ }
66
+ else {
67
+ tmp = rb_funcall(dbst->filter[type_kv], bdb1_id_call, 1, a);
68
+ }
69
+ }
70
+ if (dbst->marshal) {
71
+ if (rb_obj_is_kind_of(a, bdb1_cDelegate)) {
72
+ tmp = bdb1_deleg_to_orig(tmp);
73
+ }
74
+ tmp = rb_funcall(dbst->marshal, id_dump, 1, tmp);
75
+ if (TYPE(tmp) != T_STRING) {
76
+ rb_raise(rb_eTypeError, "dump() must return String");
77
+ }
78
+ }
79
+ else {
80
+ tmp = rb_obj_as_string(tmp);
81
+ if (a == Qnil)
82
+ is_nil = 1;
83
+ }
84
+ key->data = StringValuePtr(tmp);
85
+ key->size = RSTRING_LEN(tmp) + is_nil;
86
+ return tmp;
87
+ }
88
+
89
+ static VALUE
90
+ test_ret(obj, tmp, a, type_kv)
91
+ VALUE obj, tmp, a;
92
+ int type_kv;
93
+ {
94
+ bdb1_DB *dbst;
95
+ Data_Get_Struct(obj, bdb1_DB, dbst);
96
+ if (dbst->marshal || a == Qnil) {
97
+ return a;
98
+ }
99
+ if (dbst->filter[type_kv]) {
100
+ return rb_obj_as_string(a);
101
+ }
102
+ return tmp;
103
+ }
104
+
105
+ static VALUE
106
+ test_recno(obj, key, recno, a)
107
+ VALUE obj;
108
+ DBT *key;
109
+ db_recno_t *recno;
110
+ VALUE a;
111
+ {
112
+ bdb1_DB *dbst;
113
+ Data_Get_Struct(obj, bdb1_DB, dbst);
114
+ if (dbst->type == DB_RECNO) {
115
+ *recno = NUM2INT(a) + dbst->array_base;
116
+ key->data = recno;
117
+ key->size = sizeof(db_recno_t);
118
+ return a;
119
+ }
120
+ return test_dump(obj, key, a, FILTER_KEY);
121
+ }
122
+
123
+ VALUE
124
+ bdb1_test_load(obj, a, type_kv)
125
+ VALUE obj;
126
+ DBT *a;
127
+ int type_kv;
128
+ {
129
+ VALUE res;
130
+ int i;
131
+ bdb1_DB *dbst;
132
+
133
+ Data_Get_Struct(obj, bdb1_DB, dbst);
134
+ if (dbst->marshal) {
135
+ res = rb_str_new(a->data, a->size);
136
+ if (dbst->filter[2 + type_kv]) {
137
+ if (FIXNUM_P(dbst->filter[2 + type_kv])) {
138
+ res = rb_funcall(obj,
139
+ NUM2INT(dbst->filter[2 + type_kv]), 1, res);
140
+ }
141
+ else {
142
+ res = rb_funcall(dbst->filter[2 + type_kv],
143
+ bdb1_id_call, 1, res);
144
+ }
145
+ }
146
+ res = rb_funcall(dbst->marshal, id_load, 1, res);
147
+ }
148
+ else {
149
+ if (a->size == 1 && ((char *)a->data)[0] == '\000') {
150
+ res = Qnil;
151
+ }
152
+ else {
153
+ res = rb_tainted_str_new(a->data, a->size);
154
+ if (dbst->filter[2 + type_kv]) {
155
+ if (FIXNUM_P(dbst->filter[2 + type_kv])) {
156
+ res = rb_funcall(obj,
157
+ NUM2INT(dbst->filter[2 + type_kv]),
158
+ 1, res);
159
+ }
160
+ else {
161
+ res = rb_funcall(dbst->filter[2 + type_kv],
162
+ bdb1_id_call, 1, res);
163
+ }
164
+ }
165
+ }
166
+ }
167
+ return res;
168
+ }
169
+
170
+ static VALUE
171
+ test_load_dyna(obj, key, val)
172
+ VALUE obj;
173
+ DBT *key, *val;
174
+ {
175
+ bdb1_DB *dbst;
176
+ VALUE del, res, tmp;
177
+ struct deleg_class *delegst;
178
+
179
+ Data_Get_Struct(obj, bdb1_DB, dbst);
180
+ res = bdb1_test_load(obj, val, FILTER_VALUE);
181
+ if (dbst->marshal && !SPECIAL_CONST_P(res)) {
182
+ del = Data_Make_Struct(bdb1_cDelegate, struct deleg_class,
183
+ bdb1_deleg_mark, bdb1_deleg_free, delegst);
184
+ delegst->db = obj;
185
+ if (dbst->type == DB_RECNO) {
186
+ tmp = INT2NUM((*(db_recno_t *)key->data) - dbst->array_base);
187
+ }
188
+ else {
189
+ tmp = rb_str_new(key->data, key->size);
190
+ }
191
+ delegst->key = rb_funcall(dbst->marshal, id_load, 1, tmp);
192
+ delegst->obj = res;
193
+ res = del;
194
+ }
195
+ return res;
196
+ }
197
+
198
+
199
+ static int
200
+ bdb1_bt_compare(a, b)
201
+ DBT *a, *b;
202
+ {
203
+ VALUE obj, av, bv, res;
204
+ bdb1_DB *dbst;
205
+
206
+ if ((obj = rb_thread_local_aref(rb_thread_current(), bdb1_id_current_db)) == Qnil) {
207
+ rb_raise(bdb1_eFatal, "BUG : current_db not set");
208
+ }
209
+ Data_Get_Struct(obj, bdb1_DB, dbst);
210
+ av = bdb1_test_load(obj, a, FILTER_VALUE);
211
+ bv = bdb1_test_load(obj, b, FILTER_VALUE);
212
+ if (dbst->bt_compare == 0)
213
+ res = rb_funcall(obj, id_bt_compare, 2, av, bv);
214
+ else
215
+ res = rb_funcall(dbst->bt_compare, bdb1_id_call, 2, av, bv);
216
+ return NUM2INT(res);
217
+ }
218
+
219
+ static size_t
220
+ bdb1_bt_prefix(a, b)
221
+ DBT *a, *b;
222
+ {
223
+ VALUE obj, av, bv, res;
224
+ bdb1_DB *dbst;
225
+
226
+ if ((obj = rb_thread_local_aref(rb_thread_current(), bdb1_id_current_db)) == Qnil) {
227
+ rb_raise(bdb1_eFatal, "BUG : current_db not set");
228
+ }
229
+ Data_Get_Struct(obj, bdb1_DB, dbst);
230
+ av = bdb1_test_load(obj, a, FILTER_VALUE);
231
+ bv = bdb1_test_load(obj, b, FILTER_VALUE);
232
+ if (dbst->bt_prefix == 0)
233
+ res = rb_funcall(obj, id_bt_prefix, 2, av, bv);
234
+ else
235
+ res = rb_funcall(dbst->bt_prefix, bdb1_id_call, 2, av, bv);
236
+ return NUM2INT(res);
237
+ }
238
+
239
+ static u_int32_t
240
+ bdb1_h_hash(bytes, length)
241
+ void *bytes;
242
+ u_int32_t length;
243
+ {
244
+ VALUE obj, st, res;
245
+ bdb1_DB *dbst;
246
+
247
+ if ((obj = rb_thread_local_aref(rb_thread_current(), bdb1_id_current_db)) == Qnil) {
248
+ rb_raise(bdb1_eFatal, "BUG : current_db not set");
249
+ }
250
+ Data_Get_Struct(obj, bdb1_DB, dbst);
251
+ st = rb_tainted_str_new((char *)bytes, length);
252
+ if (dbst->h_hash == 0)
253
+ res = rb_funcall(obj, id_h_hash, 1, st);
254
+ else
255
+ res = rb_funcall(dbst->h_hash, bdb1_id_call, 1, st);
256
+ return NUM2UINT(res);
257
+ }
258
+
259
+ static void
260
+ bdb1_i_close(dbst)
261
+ bdb1_DB *dbst;
262
+ {
263
+ if (dbst->dbp != NULL && !(dbst->options & BDB1_NOT_OPEN)) {
264
+ dbst->options |= BDB1_NOT_OPEN;
265
+ bdb1_test_error(dbst->dbp->close(dbst->dbp));
266
+ }
267
+ dbst->dbp = NULL;
268
+ }
269
+
270
+ static void
271
+ bdb1_free(dbst)
272
+ bdb1_DB *dbst;
273
+ {
274
+ bdb1_i_close(dbst);
275
+ free(dbst);
276
+ }
277
+
278
+ static void
279
+ bdb1_mark(dbst)
280
+ bdb1_DB *dbst;
281
+ {
282
+ int i;
283
+
284
+ rb_gc_mark(dbst->marshal);
285
+ rb_gc_mark(dbst->bt_compare);
286
+ rb_gc_mark(dbst->bt_prefix);
287
+ rb_gc_mark(dbst->h_hash);
288
+ for (i = 0; i < 4; i++) {
289
+ rb_gc_mark(dbst->filter[i]);
290
+ }
291
+ }
292
+
293
+ static VALUE
294
+ bdb1_i185_btree(obj, dbstobj)
295
+ VALUE obj, dbstobj;
296
+ {
297
+ VALUE key, value;
298
+ bdb1_DB *dbst;
299
+ char *options;
300
+
301
+ Data_Get_Struct(dbstobj, bdb1_DB, dbst);
302
+ key = rb_ary_entry(obj, 0);
303
+ value = rb_ary_entry(obj, 1);
304
+ key = rb_obj_as_string(key);
305
+ options = StringValuePtr(key);
306
+ if (strcmp(options, "set_flags") == 0) {
307
+ dbst->has_info = Qtrue;
308
+ dbst->info.bi.flags = NUM2INT(value);
309
+ }
310
+ else if (strcmp(options, "set_cachesize") == 0) {
311
+ dbst->has_info = Qtrue;
312
+ dbst->info.bi.cachesize = NUM2INT(value);
313
+ }
314
+ else if (strcmp(options, "set_bt_minkey") == 0) {
315
+ dbst->has_info = Qtrue;
316
+ dbst->info.bi.minkeypage = NUM2INT(value);
317
+ }
318
+ else if (strcmp(options, "set_pagesize") == 0) {
319
+ dbst->has_info = Qtrue;
320
+ dbst->info.bi.psize = NUM2INT(value);
321
+ }
322
+ else if (strcmp(options, "set_bt_compare") == 0) {
323
+ if (!rb_respond_to(value, bdb1_id_call)) {
324
+ rb_raise(bdb1_eFatal, "arg must respond to #call");
325
+ }
326
+ dbst->has_info = Qtrue;
327
+ dbst->options |= BDB1_BT_COMPARE;
328
+ dbst->bt_compare = value;
329
+ dbst->info.bi.compare = bdb1_bt_compare;
330
+ }
331
+ else if (strcmp(options, "set_bt_prefix") == 0) {
332
+ if (!rb_respond_to(value, bdb1_id_call)) {
333
+ rb_raise(bdb1_eFatal, "arg must respond to #call");
334
+ }
335
+ dbst->has_info = Qtrue;
336
+ dbst->options |= BDB1_BT_PREFIX;
337
+ dbst->bt_prefix = value;
338
+ dbst->info.bi.prefix = bdb1_bt_prefix;
339
+ }
340
+ else if (strcmp(options, "set_lorder") == 0) {
341
+ dbst->has_info = Qtrue;
342
+ dbst->info.bi.lorder = NUM2INT(value);
343
+ }
344
+ return Qnil;
345
+ }
346
+
347
+ static VALUE
348
+ bdb1_i185_hash(obj, dbstobj)
349
+ VALUE obj, dbstobj;
350
+ {
351
+ VALUE key, value;
352
+ bdb1_DB *dbst;
353
+ char *options;
354
+
355
+ Data_Get_Struct(dbstobj, bdb1_DB, dbst);
356
+ key = rb_ary_entry(obj, 0);
357
+ value = rb_ary_entry(obj, 1);
358
+ key = rb_obj_as_string(key);
359
+ options = StringValuePtr(key);
360
+ if (strcmp(options, "set_h_ffactor") == 0) {
361
+ dbst->has_info = Qtrue;
362
+ dbst->info.hi.ffactor = NUM2INT(value);
363
+ }
364
+ else if (strcmp(options, "set_h_nelem") == 0) {
365
+ dbst->has_info = Qtrue;
366
+ dbst->info.hi.nelem = NUM2INT(value);
367
+ }
368
+ else if (strcmp(options, "set_cachesize") == 0) {
369
+ dbst->has_info = Qtrue;
370
+ dbst->info.hi.cachesize = NUM2INT(value);
371
+ }
372
+ else if (strcmp(options, "set_h_hash") == 0) {
373
+ if (!rb_respond_to(value, bdb1_id_call)) {
374
+ rb_raise(bdb1_eFatal, "arg must respond to #call");
375
+ }
376
+ dbst->has_info = Qtrue;
377
+ dbst->options |= BDB1_H_HASH;
378
+ dbst->h_hash = value;
379
+ dbst->info.hi.hash = bdb1_h_hash;
380
+ }
381
+ else if (strcmp(options, "set_lorder") == 0) {
382
+ dbst->has_info = Qtrue;
383
+ dbst->info.hi.lorder = NUM2INT(value);
384
+ }
385
+ return Qnil;
386
+ }
387
+
388
+ static VALUE
389
+ bdb1_i185_recno(obj, dbstobj)
390
+ VALUE obj, dbstobj;
391
+ {
392
+ VALUE key, value;
393
+ bdb1_DB *dbst;
394
+ char *options, *str;
395
+
396
+ Data_Get_Struct(dbstobj, bdb1_DB, dbst);
397
+ key = rb_ary_entry(obj, 0);
398
+ value = rb_ary_entry(obj, 1);
399
+ key = rb_obj_as_string(key);
400
+ options = StringValuePtr(key);
401
+ if (strcmp(options, "set_flags") == 0) {
402
+ dbst->has_info = Qtrue;
403
+ dbst->info.ri.flags = NUM2INT(value);
404
+ }
405
+ else if (strcmp(options, "set_re_delim") == 0) {
406
+ int ch;
407
+ if (TYPE(value) == T_STRING) {
408
+ str = StringValuePtr(value);
409
+ dbst->info.ri.bval = str[0];
410
+ }
411
+ else {
412
+ dbst->info.ri.bval = NUM2INT(value);
413
+ }
414
+ dbst->has_info = Qtrue;
415
+ dbst->info.ri.flags |= R_FIXEDLEN;
416
+ }
417
+ else if (strcmp(options, "set_re_len") == 0) {
418
+ dbst->has_info = Qtrue;
419
+ dbst->info.ri.reclen = NUM2INT(value);
420
+ dbst->info.ri.flags |= R_FIXEDLEN;
421
+ }
422
+ else if (strcmp(options, "set_re_pad") == 0) {
423
+ int ch;
424
+ if (TYPE(value) == T_STRING) {
425
+ str = StringValuePtr(value);
426
+ dbst->info.ri.bval = str[0];
427
+ }
428
+ else {
429
+ dbst->info.ri.bval = NUM2INT(value);
430
+ }
431
+ dbst->has_info = Qtrue;
432
+ dbst->info.ri.flags |= R_FIXEDLEN;
433
+ }
434
+ else if (strcmp(options, "set_cachesize") == 0) {
435
+ dbst->has_info = Qtrue;
436
+ dbst->info.ri.cachesize = NUM2INT(value);
437
+ }
438
+ else if (strcmp(options, "set_pagesize") == 0) {
439
+ dbst->has_info = Qtrue;
440
+ dbst->info.ri.psize = NUM2INT(value);
441
+ }
442
+ else if (strcmp(options, "set_lorder") == 0) {
443
+ dbst->has_info = Qtrue;
444
+ dbst->info.ri.lorder = NUM2INT(value);
445
+ }
446
+ else if (strcmp(options, "set_array_base") == 0 ||
447
+ strcmp(options, "array_base") == 0) {
448
+ int ary_base = NUM2INT(value);
449
+ switch (ary_base) {
450
+ case 0: dbst->array_base = 1; break;
451
+ case 1: dbst->array_base = 0; break;
452
+ default: rb_raise(bdb1_eFatal, "array base must be 0 or 1");
453
+ }
454
+ }
455
+ return Qnil;
456
+ }
457
+
458
+ static VALUE
459
+ bdb1_load_dump(obj)
460
+ VALUE obj;
461
+ {
462
+ VALUE res;
463
+
464
+ res = rb_funcall(obj, rb_intern("respond_to?"), 2, ID2SYM(id_load), Qtrue);
465
+ if (RTEST(res)) {
466
+ res = rb_funcall(obj, rb_intern("respond_to?"), 2, ID2SYM(id_dump), Qtrue);
467
+ }
468
+ return res;
469
+ }
470
+
471
+ static VALUE
472
+ bdb1_i185_common(obj, dbstobj)
473
+ VALUE obj, dbstobj;
474
+ {
475
+ VALUE key, value;
476
+ bdb1_DB *dbst;
477
+ char *options;
478
+
479
+ Data_Get_Struct(dbstobj, bdb1_DB, dbst);
480
+ key = rb_ary_entry(obj, 0);
481
+ value = rb_ary_entry(obj, 1);
482
+ key = rb_obj_as_string(key);
483
+ options = StringValuePtr(key);
484
+ if (strcmp(options, "marshal") == 0) {
485
+ switch (value) {
486
+ case Qtrue:
487
+ dbst->marshal = bdb1_mMarshal;
488
+ dbst->options |= BDB1_MARSHAL;
489
+ break;
490
+ case Qfalse:
491
+ dbst->marshal = Qfalse;
492
+ dbst->options &= ~BDB1_MARSHAL;
493
+ break;
494
+ default:
495
+ if (!RTEST(bdb1_load_dump(value))) {
496
+ rb_raise(bdb1_eFatal, "marshal value must be true or false");
497
+ }
498
+ dbst->marshal = value;
499
+ dbst->options |= BDB1_MARSHAL;
500
+ break;
501
+ }
502
+ }
503
+ else if (strcmp(options, "set_store_key") == 0) {
504
+ if (!rb_respond_to(value, bdb1_id_call)) {
505
+ rb_raise(bdb1_eFatal, "arg must respond to #call");
506
+ }
507
+ dbst->filter[FILTER_KEY] = value;
508
+ }
509
+ else if (strcmp(options, "set_fetch_key") == 0) {
510
+ if (!rb_respond_to(value, bdb1_id_call)) {
511
+ rb_raise(bdb1_eFatal, "arg must respond to #call");
512
+ }
513
+ dbst->filter[2 + FILTER_KEY] = value;
514
+ }
515
+ else if (strcmp(options, "set_store_value") == 0) {
516
+ if (!rb_respond_to(value, bdb1_id_call)) {
517
+ rb_raise(bdb1_eFatal, "arg must respond to #call");
518
+ }
519
+ dbst->filter[FILTER_VALUE] = value;
520
+ }
521
+ else if (strcmp(options, "set_fetch_value") == 0) {
522
+ if (!rb_respond_to(value, bdb1_id_call)) {
523
+ rb_raise(bdb1_eFatal, "arg must respond to #call");
524
+ }
525
+ dbst->filter[2 + FILTER_VALUE] = value;
526
+ }
527
+ return Qnil;
528
+ }
529
+
530
+ static int
531
+ bdb1_hard_count(dbp)
532
+ DB *dbp;
533
+ {
534
+ DBT key, data;
535
+ db_recno_t recno;
536
+ long count = 0;
537
+
538
+ DATA_ZERO(key);
539
+ key.data = &recno;
540
+ key.size = sizeof(db_recno_t);
541
+ DATA_ZERO(data);
542
+ if (bdb1_test_error(dbp->seq(dbp, &key, &data, DB_LAST)) == 0) {
543
+ count = *(db_recno_t *)key.data;
544
+ }
545
+ return count;
546
+ }
547
+
548
+ /*
549
+ * call-seq:
550
+ *
551
+ * BDB1::Btree.new(name = nil, flags = "r", mode = 0, options = {})
552
+ * BDB1::Hash.new(name = nil, flags = "r", mode = 0, options = {})
553
+ * BDB1::Recnum.new(name = nil, flags = "r", mode = 0, options = {})
554
+ *
555
+ * Open the database.
556
+ *
557
+ * * +name+
558
+ * The argument name is used as the name of a single physical
559
+ * file on disk that will be used to back the database.
560
+ *
561
+ * If +nil+ is given, an on-memory database is created.
562
+ *
563
+ * * +flags+
564
+ * The flags must be the string "r", "r+", "w", "w+", "a", "a+" or
565
+ * and integer value.
566
+ *
567
+ * The flags value must be set to 0 or by bitwise inclusively
568
+ * OR'ing together one or more of the following values
569
+ *
570
+ * * +BDB1::CREATE+
571
+ * Create any underlying files, as necessary. If the files
572
+ * do not already exist and the DB_CREATE flag is not
573
+ * specified, the call will fail.
574
+ *
575
+ * * +BDB1::RDONLY+
576
+ * Open the database for reading only. Any attempt to
577
+ * modify items in the database will fail regardless of the
578
+ * actual permissions of any underlying files.
579
+ *
580
+ * * +BDB1::TRUNCATE+
581
+ * Physically truncate the underlying database file,
582
+ * discarding all previous subdatabases or databases.
583
+ * Underlying filesystem primitives are used to implement
584
+ * this flag. For this reason it is only applicable to the
585
+ * physical database file and cannot be used to discard
586
+ * subdatabases.
587
+ *
588
+ * The DB_TRUNCATE flag cannot be transaction protected,
589
+ * and it is an error to specify it in a transaction
590
+ * protected environment.
591
+ *
592
+ * * +BDB1::WRITE+
593
+ * Open the database for writing. Without this flag, any
594
+ * attempt to modify items in the database will fail.
595
+ *
596
+ * * +mode+
597
+ * mode to create the file
598
+ *
599
+ * * +options+
600
+ * Hash, Possible options are (see the documentation of Berkeley DB
601
+ * for more informations)
602
+ *
603
+ * * +set_flags+: general database configuration
604
+ * * +set_cachesize+: set the database cache size
605
+ * * +set_pagesize+: set the underlying database page size
606
+ * * +set_lorder+: set the database byte order
607
+ * * +set_store_key+: specify a Proc called before a key is stored
608
+ * * +set_fetch_key+: specify a Proc called after a key is read
609
+ * * +set_store_value+: specify a Proc called before a value is stored
610
+ * * +set_fetch_value+: specify a Proc called after a value is read
611
+ *
612
+ * * +options specific to BDB1::Btree+
613
+ *
614
+ * * +set_bt_compare+: specify a Btree comparison function
615
+ * * +set_bt_minkey+: set the minimum number of keys per Btree page
616
+ * * +set_bt_prefix+: specify a Btree prefix comparison function
617
+ *
618
+ * * +options specific to BDB1::Hash+
619
+ *
620
+ * * +set_h_ffactor+: set the Hash table density
621
+ * * +set_h_hash+: specify a hashing function
622
+ * * +set_h_nelem+: set the Hash table size
623
+ *
624
+ * * +options specific to BDB1::Recnum+
625
+ *
626
+ * * +set_re_delim+: set the variable-length record delimiter
627
+ * * +set_re_len+: set the fixed-length record length
628
+ * * +set_re_pad+: set the fixed-length record pad byte
629
+ *
630
+ * Proc given to +set_bt_compare+, +set_bt_prefix+,
631
+ * +set_h_hash+, +set_store_key+, +set_fetch_key+,
632
+ * +set_store_value+ and +set_fetch_value+ can be also
633
+ * specified as a method (replace the prefix +set_+ with
634
+ * +bdb1_+)
635
+ *
636
+ * For example:
637
+ *
638
+ * module BDB1
639
+ * class Btreesort < Btree
640
+ * def bdb1_bt_compare(a, b)
641
+ * b.downcase <=> a.downcase
642
+ * end
643
+ * end
644
+ * end
645
+ */
646
+ VALUE
647
+ bdb1_init(argc, argv, obj)
648
+ int argc;
649
+ VALUE *argv;
650
+ VALUE obj;
651
+ {
652
+ VALUE b, c, d, f;
653
+ int mode, oflags;
654
+ char *name;
655
+ bdb1_DB *dbst;
656
+ void *openinfo = NULL;
657
+
658
+ f = Qnil; name = NULL;
659
+ mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
660
+ oflags = DB_RDONLY;
661
+ if (argc && TYPE(argv[argc - 1]) == T_HASH) {
662
+ f = argv[argc - 1];
663
+ argc--;
664
+ }
665
+ switch(rb_scan_args(argc, argv, "03", &b, &c, &d)) {
666
+ case 3:
667
+ mode = NUM2INT(d);
668
+ /* ... */
669
+ case 2:
670
+ if (TYPE(c) == T_STRING) {
671
+ char *m = StringValuePtr(c);
672
+ if (strcmp(m, "r") == 0) {
673
+ oflags = DB_RDONLY;
674
+ }
675
+ else if (strcmp(m, "r+") == 0) {
676
+ oflags = DB_WRITE;
677
+ }
678
+ else if (strcmp(m, "w") == 0 || strcmp(m, "w+") == 0) {
679
+ oflags = DB_CREATE | DB_TRUNCATE | DB_WRITE;
680
+ }
681
+ else if (strcmp(m, "a") == 0 || strcmp(m, "a+") == 0) {
682
+ oflags = DB_CREATE | DB_WRITE;
683
+ }
684
+ else {
685
+ rb_raise(bdb1_eFatal, "flags must be r, r+, w, w+, a or a+");
686
+ }
687
+ }
688
+ else if (c == Qnil) {
689
+ oflags = DB_RDONLY;
690
+ }
691
+ else {
692
+ oflags = NUM2INT(c);
693
+ }
694
+ /* ... */
695
+ case 1:
696
+ if (!NIL_P(b)) {
697
+ SafeStringValue(b);
698
+ name = StringValuePtr(b);
699
+ }
700
+ else {
701
+ name = NULL;
702
+ }
703
+ /* ... */
704
+ }
705
+ Data_Get_Struct(obj, bdb1_DB, dbst);
706
+ if (dbst->type < DB_BTREE || dbst->type > DB_RECNO) {
707
+ rb_raise(bdb1_eFatal, "Unknown db185 type %d", dbst->type);
708
+ }
709
+ if (!NIL_P(f)) {
710
+ if (TYPE(f) != T_HASH) {
711
+ rb_raise(bdb1_eFatal, "options must be an hash");
712
+ }
713
+ switch(dbst->type) {
714
+ case 0:
715
+ rb_iterate(rb_each, f, bdb1_i185_btree, obj);
716
+ if (dbst->bt_compare == 0 && rb_respond_to(obj, id_bt_compare)) {
717
+ dbst->has_info = Qtrue;
718
+ dbst->options |= BDB1_BT_COMPARE;
719
+ dbst->info.bi.compare = bdb1_bt_compare;
720
+ }
721
+ if (dbst->bt_prefix == 0 && rb_respond_to(obj, id_bt_prefix)) {
722
+ dbst->has_info = Qtrue;
723
+ dbst->options |= BDB1_BT_PREFIX;
724
+ dbst->info.bi.prefix = bdb1_bt_prefix;
725
+ }
726
+ break;
727
+ case 1:
728
+ rb_iterate(rb_each, f, bdb1_i185_hash, obj);
729
+ if (dbst->h_hash == 0 && rb_respond_to(obj, id_h_hash)) {
730
+ dbst->has_info = Qtrue;
731
+ dbst->options |= BDB1_H_HASH;
732
+ dbst->info.hi.hash = bdb1_h_hash;
733
+ }
734
+ break;
735
+ case 2:
736
+ rb_iterate(rb_each, f, bdb1_i185_recno, obj);
737
+ break;
738
+ }
739
+ rb_iterate(rb_each, f, bdb1_i185_common, obj);
740
+ }
741
+ if (name == NULL) oflags = O_CREAT | O_RDWR;
742
+ if (dbst->has_info) openinfo = &dbst->info;
743
+ dbst->dbp = dbopen(name, oflags, mode, dbst->type, openinfo);
744
+ if (dbst->dbp == NULL) {
745
+ rb_raise(bdb1_eFatal, "Failed `%s'", db_strerror(errno));
746
+ }
747
+ dbst->options &= ~BDB1_NOT_OPEN;
748
+ if (dbst->type == 2) {
749
+ dbst->len = bdb1_hard_count(dbst->dbp);
750
+ }
751
+ return obj;
752
+ }
753
+
754
+ /*
755
+ * call-seq:
756
+ * db.close(flags = 0)
757
+ *
758
+ * Closes the file.
759
+ */
760
+ static VALUE
761
+ bdb1_close(obj)
762
+ VALUE obj;
763
+ {
764
+ VALUE opt;
765
+ bdb1_DB *dbst;
766
+
767
+ if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4) {
768
+ rb_raise(rb_eSecurityError, "Insecure: can't close the database");
769
+ }
770
+ Data_Get_Struct(obj, bdb1_DB, dbst);
771
+ bdb1_i_close(dbst);
772
+ return Qnil;
773
+ }
774
+
775
+ VALUE
776
+ bdb1_s_alloc(obj)
777
+ VALUE obj;
778
+ {
779
+ bdb1_DB *dbst;
780
+ VALUE res, cl;
781
+
782
+ res = Data_Make_Struct(obj, bdb1_DB, bdb1_mark, bdb1_free, dbst);
783
+ dbst->options |= BDB1_NOT_OPEN;
784
+ cl = obj;
785
+ while (cl) {
786
+ if (cl == bdb1_cBtree || RCLASS(cl)->m_tbl == RCLASS(bdb1_cBtree)->m_tbl) {
787
+ dbst->type = DB_BTREE;
788
+ break;
789
+ }
790
+ else if (cl == bdb1_cHash || RCLASS(cl)->m_tbl == RCLASS(bdb1_cHash)->m_tbl) {
791
+ dbst->type = DB_HASH;
792
+ break;
793
+ }
794
+ else if (cl == bdb1_cRecnum || RCLASS(cl)->m_tbl == RCLASS(bdb1_cRecnum)->m_tbl) {
795
+ dbst->type = DB_RECNO;
796
+ break;
797
+ }
798
+ cl = RCLASS(cl)->super;
799
+ }
800
+ if (!cl) {
801
+ rb_raise(bdb1_eFatal, "unknown database type");
802
+ }
803
+ if (RTEST(bdb1_load_dump(obj))) {
804
+ dbst->marshal = obj;
805
+ dbst->options |= BDB1_MARSHAL;
806
+ }
807
+ if (rb_method_boundp(obj, rb_intern("bdb1_store_key"), 0) == Qtrue) {
808
+ dbst->filter[FILTER_KEY] = INT2FIX(rb_intern("bdb1_store_key"));
809
+ }
810
+ if (rb_method_boundp(obj, rb_intern("bdb1_fetch_key"), 0) == Qtrue) {
811
+ dbst->filter[2 + FILTER_KEY] = INT2FIX(rb_intern("bdb1_fetch_key"));
812
+ }
813
+ if (rb_method_boundp(obj, rb_intern("bdb1_store_value"), 0) == Qtrue) {
814
+ dbst->filter[FILTER_VALUE] = INT2FIX(rb_intern("bdb1_store_value"));
815
+ }
816
+ if (rb_method_boundp(obj, rb_intern("bdb1_fetch_value"), 0) == Qtrue) {
817
+ dbst->filter[2 + FILTER_VALUE] = INT2FIX(rb_intern("bdb1_fetch_value"));
818
+ }
819
+ return res;
820
+ }
821
+
822
+ /*
823
+ * Same as +new+.
824
+ */
825
+ static VALUE
826
+ bdb1_s_create(argc, argv, obj)
827
+ int argc;
828
+ VALUE *argv;
829
+ VALUE obj;
830
+ {
831
+ VALUE st, res;
832
+
833
+ res = rb_funcall2(obj, rb_intern("allocate"), 0, 0);
834
+ rb_obj_call_init(res, argc, argv);
835
+ return res;
836
+ }
837
+
838
+ static VALUE
839
+ bdb1_i_create(obj, db)
840
+ VALUE obj, db;
841
+ {
842
+ VALUE tmp[2];
843
+ tmp[0] = rb_ary_entry(obj, 0);
844
+ tmp[1] = rb_ary_entry(obj, 1);
845
+ bdb1_put(2, tmp, db);
846
+ return Qnil;
847
+ }
848
+
849
+ /*
850
+ * call-seq:
851
+ * BDB1::Btree[hash]
852
+ * BDB1::Btree[key1, value1, key2, value2, ...]
853
+ * BDB1::Hash[hash]
854
+ * BDB1::Hash[key1, value1, key2, value2, ...]
855
+ * BDB1::Recnum[hash]
856
+ * BDB1::Recnum[key1, value1, key2, value2, ...]
857
+ *
858
+ * Creates a new temporary on-memory database, populated with the
859
+ * given hash or pairs of objects.
860
+ */
861
+ static VALUE
862
+ bdb1_s_aref(argc, argv, obj)
863
+ int argc;
864
+ VALUE *argv;
865
+ VALUE obj;
866
+ {
867
+ VALUE res, tmp[2];
868
+ int i;
869
+
870
+ res = rb_funcall2(obj, rb_intern("new"), 0, 0);
871
+ if (argc == 1 && TYPE(argv[0]) == T_HASH) {
872
+ rb_iterate(rb_each, argv[0], bdb1_i_create, res);
873
+ return res;
874
+ }
875
+ if (argc % 2 != 0) {
876
+ rb_raise(rb_eArgError, "odd number args for %s", rb_class2name(obj));
877
+ }
878
+ for (i = 0; i < argc; i += 2) {
879
+ bdb1_put(2, argv + i, res);
880
+ }
881
+ return res;
882
+ }
883
+
884
+ /*
885
+ * Same as +new+ except that if a block is given it is called with an
886
+ * initialized object which is automatically closed when done.
887
+ */
888
+ static VALUE
889
+ bdb1_s_open(argc, argv, obj)
890
+ int argc;
891
+ VALUE *argv;
892
+ VALUE obj;
893
+ {
894
+ VALUE res = rb_funcall2(obj, rb_intern("new"), argc, argv);
895
+ if (rb_block_given_p()) {
896
+ return rb_ensure(rb_yield, res, bdb1_close, res);
897
+ }
898
+ return res;
899
+ }
900
+
901
+ /*
902
+ * call-seq:
903
+ * db.put(key, value, flags = 0)
904
+ *
905
+ * Stores the +value+ associating with +key+ and returns the value
906
+ * stored.
907
+ *
908
+ * +flags+ can have the value +DBD::NOOVERWRITE+, in this case it will
909
+ * return +nil+ if the specified key exist, otherwise +true+.
910
+ */
911
+ VALUE
912
+ bdb1_put(argc, argv, obj)
913
+ int argc;
914
+ VALUE *argv;
915
+ VALUE obj;
916
+ {
917
+ volatile VALUE a0 = Qnil;
918
+ volatile VALUE b0 = Qnil;
919
+ VALUE a, b, c;
920
+ bdb1_DB *dbst;
921
+ DBT key, data;
922
+ int ret, flags;
923
+ db_recno_t recno;
924
+
925
+ rb_secure(4);
926
+ GetDB(obj, dbst);
927
+ flags = 0;
928
+ a = b = c = Qnil;
929
+ if (rb_scan_args(argc, argv, "21", &a, &b, &c) == 3) {
930
+ flags = NUM2INT(c);
931
+ }
932
+ DATA_ZERO(key);
933
+ DATA_ZERO(data);
934
+ a0 = test_recno(obj, &key, &recno, a);
935
+ b0 = test_dump(obj, &data, b, FILTER_VALUE);
936
+ ret = bdb1_test_error(dbst->dbp->put(dbst->dbp, &key, &data, flags));
937
+ if (ret == DB_KEYEXIST)
938
+ return Qfalse;
939
+ else {
940
+ return test_ret(obj, b0, b, FILTER_VALUE);
941
+ }
942
+ }
943
+
944
+ static VALUE
945
+ bdb1_assign(obj, a, b)
946
+ VALUE obj, a, b;
947
+ {
948
+ VALUE tmp[2];
949
+ tmp[0] = a;
950
+ tmp[1] = b;
951
+ bdb1_put(2, tmp, obj);
952
+ return b;
953
+ }
954
+
955
+ static VALUE
956
+ test_load_key(obj, key)
957
+ VALUE obj;
958
+ DBT *key;
959
+ {
960
+ bdb1_DB *dbst;
961
+ Data_Get_Struct(obj, bdb1_DB, dbst);
962
+ if (dbst->type == DB_RECNO)
963
+ return INT2NUM((*(db_recno_t *)key->data) - dbst->array_base);
964
+ return bdb1_test_load(obj, key, FILTER_KEY);
965
+ }
966
+
967
+ static VALUE
968
+ bdb1_assoc(obj, key, data)
969
+ VALUE obj;
970
+ DBT *key, *data;
971
+ {
972
+ return rb_assoc_new(test_load_key(obj, key),
973
+ bdb1_test_load(obj, data, FILTER_VALUE));
974
+ }
975
+
976
+ static VALUE
977
+ bdb1_assoc_dyna(obj, key, data)
978
+ VALUE obj;
979
+ DBT *key, *data;
980
+ {
981
+ return rb_assoc_new(test_load_key(obj, key),
982
+ test_load_dyna(obj, key, data));
983
+ }
984
+
985
+ static VALUE
986
+ bdb1_get_internal(argc, argv, obj, notfound, dyna)
987
+ int argc;
988
+ VALUE *argv;
989
+ VALUE obj;
990
+ VALUE notfound;
991
+ int dyna;
992
+ {
993
+ volatile VALUE a = Qnil;
994
+ VALUE b, c;
995
+ bdb1_DB *dbst;
996
+ DBT key, data;
997
+ DBT datas;
998
+ int flagss;
999
+ int ret, flags;
1000
+ db_recno_t recno;
1001
+
1002
+ flagss = flags = 0;
1003
+ GetDB(obj, dbst);
1004
+ DATA_ZERO(key);
1005
+ DATA_ZERO(data);
1006
+ switch(rb_scan_args(argc, argv, "12", &a, &b, &c)) {
1007
+ case 3:
1008
+ flags = NUM2INT(c);
1009
+ break;
1010
+ case 2:
1011
+ flagss = flags = NUM2INT(b);
1012
+ break;
1013
+ }
1014
+ a = test_recno(obj, &key, &recno, a);
1015
+ ret = bdb1_test_error(dbst->dbp->get(dbst->dbp, &key, &data, flags));
1016
+ if (ret == DB_NOTFOUND)
1017
+ return notfound;
1018
+ if (dyna) {
1019
+ return test_load_dyna(obj, &key, &data);
1020
+ }
1021
+ else {
1022
+ return bdb1_test_load(obj, &data, FILTER_VALUE);
1023
+ }
1024
+ }
1025
+
1026
+ VALUE
1027
+ bdb1_get(argc, argv, obj)
1028
+ int argc;
1029
+ VALUE *argv;
1030
+ VALUE obj;
1031
+ {
1032
+ return bdb1_get_internal(argc, argv, obj, Qnil, 0);
1033
+ }
1034
+
1035
+ /*
1036
+ * call-seq:
1037
+ * db[key]
1038
+ * db[key, flags = 0]
1039
+ *
1040
+ * Returns the value corresponding to +key+.
1041
+ */
1042
+ static VALUE
1043
+ bdb1_get_dyna(argc, argv, obj)
1044
+ int argc;
1045
+ VALUE *argv;
1046
+ VALUE obj;
1047
+ {
1048
+ return bdb1_get_internal(argc, argv, obj, Qnil, 1);
1049
+ }
1050
+
1051
+ static VALUE
1052
+ bdb1_fetch(argc, argv, obj)
1053
+ int argc;
1054
+ VALUE *argv, obj;
1055
+ {
1056
+ VALUE key, if_none;
1057
+ VALUE val;
1058
+
1059
+ rb_scan_args(argc, argv, "11", &key, &if_none);
1060
+ val = bdb1_get_internal(1, argv, obj, Qundef, 1);
1061
+ if (val == Qundef) {
1062
+ if (rb_block_given_p()) {
1063
+ if (argc > 1) {
1064
+ rb_raise(rb_eArgError, "wrong # of arguments", argc);
1065
+ }
1066
+ return rb_yield(key);
1067
+ }
1068
+ if (argc == 1) {
1069
+ rb_raise(rb_eIndexError, "key not found");
1070
+ }
1071
+ return if_none;
1072
+ }
1073
+ return val;
1074
+ }
1075
+
1076
+ static VALUE
1077
+ bdb1_has_key(obj, key)
1078
+ VALUE obj, key;
1079
+ {
1080
+ return bdb1_get_internal(1, &key, obj, Qfalse);
1081
+ }
1082
+
1083
+ /*
1084
+ * call-seq:
1085
+ * db.has_both?(key, value)
1086
+ *
1087
+ * Returns +true+ if the association from +key+ is +value+.
1088
+ */
1089
+ static VALUE
1090
+ bdb1_has_both(obj, a, b)
1091
+ VALUE obj, a, b;
1092
+ {
1093
+ bdb1_DB *dbst;
1094
+ DBT key, data;
1095
+ DBT keys, datas;
1096
+ int ret, flags;
1097
+ db_recno_t recno;
1098
+ volatile VALUE c = Qnil;
1099
+ volatile VALUE d = Qnil;
1100
+
1101
+ GetDB(obj, dbst);
1102
+ DATA_ZERO(key);
1103
+ DATA_ZERO(data);
1104
+ c = test_recno(obj, &key, &recno, a);
1105
+ d = test_dump(obj, &data, b, FILTER_VALUE);
1106
+ MEMCPY(&keys, &key, DBT, 1);
1107
+ MEMCPY(&datas, &data, DBT, 1);
1108
+ flags = (dbst->type == DB_HASH)?DB_FIRST:R_CURSOR;
1109
+ while (1) {
1110
+ ret = bdb1_test_error(dbst->dbp->seq(dbst->dbp, &key, &data, flags));
1111
+ if (ret == DB_NOTFOUND) {
1112
+ return Qfalse;
1113
+ }
1114
+ if (key.size == keys.size &&
1115
+ memcmp(keys.data, key.data, key.size) == 0 &&
1116
+ data.size == datas.size &&
1117
+ memcmp(datas.data, data.data, data.size) == 0) {
1118
+ return Qtrue;
1119
+ }
1120
+ flags = DB_NEXT;
1121
+ }
1122
+ return Qnil;
1123
+ }
1124
+
1125
+ /*
1126
+ * call-seq:
1127
+ * db.delete(key)
1128
+ *
1129
+ * Removes the association from the +key+.
1130
+ *
1131
+ * It returns the object deleted or +nil+ if the specified key doesn't
1132
+ * exist.
1133
+ */
1134
+ VALUE
1135
+ bdb1_del(obj, a)
1136
+ VALUE a, obj;
1137
+ {
1138
+ bdb1_DB *dbst;
1139
+ DBT key;
1140
+ int ret;
1141
+ db_recno_t recno;
1142
+ volatile VALUE c = Qnil;
1143
+
1144
+ rb_secure(4);
1145
+ GetDB(obj, dbst);
1146
+ if (dbst->type == DB_HASH) {
1147
+ rb_warning("delete can give strange result with DB_HASH");
1148
+ }
1149
+ DATA_ZERO(key);
1150
+ c = test_recno(obj, &key, &recno, a);
1151
+ ret = bdb1_test_error(dbst->dbp->del(dbst->dbp, &key, 0));
1152
+ if (ret == DB_NOTFOUND)
1153
+ return Qnil;
1154
+ else
1155
+ return obj;
1156
+ }
1157
+
1158
+ static VALUE
1159
+ bdb1_empty(obj)
1160
+ VALUE obj;
1161
+ {
1162
+ bdb1_DB *dbst;
1163
+ DBT key, data;
1164
+ int ret, flags;
1165
+ db_recno_t recno;
1166
+
1167
+ GetDB(obj, dbst);
1168
+ INIT_RECNO(dbst, key, recno);
1169
+ DATA_ZERO(data);
1170
+ ret = bdb1_test_error(dbst->dbp->seq(dbst->dbp, &key, &data, DB_FIRST));
1171
+ if (ret == DB_NOTFOUND) {
1172
+ return Qtrue;
1173
+ }
1174
+ FREE_KEY(dbst, key);
1175
+ return Qfalse;
1176
+ }
1177
+
1178
+ static VALUE
1179
+ bdb1_delete_if(obj)
1180
+ VALUE obj;
1181
+ {
1182
+ bdb1_DB *dbst;
1183
+ DBT key, data, save;
1184
+ int ret, ret1, flags;
1185
+ db_recno_t recno;
1186
+
1187
+ rb_secure(4);
1188
+ GetDB(obj, dbst);
1189
+ INIT_RECNO(dbst, key, recno);
1190
+ DATA_ZERO(data);
1191
+ flags = DB_FIRST;
1192
+ do {
1193
+ ret = bdb1_test_error(dbst->dbp->seq(dbst->dbp, &key, &data, flags));
1194
+ if (ret == DB_NOTFOUND) {
1195
+ return Qnil;
1196
+ }
1197
+ flags = DB_NEXT;
1198
+ if (RTEST(rb_yield(bdb1_assoc(obj, &key, &data)))) {
1199
+ bdb1_test_error(dbst->dbp->del(dbst->dbp, 0, R_CURSOR));
1200
+ }
1201
+ } while (1);
1202
+ return obj;
1203
+ }
1204
+
1205
+ VALUE
1206
+ bdb1_clear(obj)
1207
+ VALUE obj;
1208
+ {
1209
+ bdb1_DB *dbst;
1210
+ DBT key, data, save;
1211
+ int ret, value, flags;
1212
+ db_recno_t recno;
1213
+
1214
+ rb_secure(4);
1215
+ GetDB(obj, dbst);
1216
+ INIT_RECNO(dbst, key, recno);
1217
+ DATA_ZERO(data);
1218
+ flags = DB_FIRST;
1219
+ value = 0;
1220
+ do {
1221
+ ret = bdb1_test_error(dbst->dbp->seq(dbst->dbp, &key, &data, flags));
1222
+ if (ret == DB_NOTFOUND) {
1223
+ return INT2NUM(value);
1224
+ }
1225
+ value++;
1226
+ bdb1_test_error(dbst->dbp->del(dbst->dbp, 0, R_CURSOR));
1227
+ } while (1);
1228
+ return INT2NUM(-1);
1229
+ }
1230
+
1231
+ static VALUE
1232
+ bdb1_length(obj)
1233
+ VALUE obj;
1234
+ {
1235
+ bdb1_DB *dbst;
1236
+ DBT key, data;
1237
+ int ret, value, flags;
1238
+ db_recno_t recno;
1239
+
1240
+ GetDB(obj, dbst);
1241
+ if (dbst->type == DB_RECNO) {
1242
+ return INT2NUM(bdb1_hard_count(dbst->dbp));
1243
+ }
1244
+ INIT_RECNO(dbst, key, recno);
1245
+ DATA_ZERO(data);
1246
+ value = 0;
1247
+ flags = DB_FIRST;
1248
+ do {
1249
+ ret = bdb1_test_error(dbst->dbp->seq(dbst->dbp, &key, &data, flags));
1250
+ if (ret == DB_NOTFOUND) {
1251
+ return INT2NUM(value);
1252
+ }
1253
+ flags = DB_NEXT;
1254
+ FREE_KEY(dbst, key);
1255
+ value++;
1256
+ } while (1);
1257
+ return INT2NUM(value);
1258
+ }
1259
+
1260
+ static VALUE
1261
+ bdb1_each_valuec(obj, sens, result)
1262
+ VALUE obj, result;
1263
+ int sens;
1264
+ {
1265
+ bdb1_DB *dbst;
1266
+ DBT key, data;
1267
+ int ret, flags;
1268
+ db_recno_t recno;
1269
+ VALUE interm, rest;
1270
+
1271
+ GetDB(obj, dbst);
1272
+ INIT_RECNO(dbst, key, recno);
1273
+ DATA_ZERO(data);
1274
+ flags = (sens == DB_NEXT)?DB_FIRST:DB_LAST;
1275
+ do {
1276
+ ret = bdb1_test_error(dbst->dbp->seq(dbst->dbp, &key, &data, flags));
1277
+ if (ret == DB_NOTFOUND) {
1278
+ return result;
1279
+ }
1280
+ flags = sens;
1281
+ FREE_KEY(dbst, key);
1282
+ interm = bdb1_test_load(obj, &data, FILTER_VALUE);
1283
+ rest = rb_yield(interm);
1284
+ if (result != Qnil && RTEST(rest)) {
1285
+ rb_ary_push(result, interm);
1286
+ }
1287
+ } while (1);
1288
+ }
1289
+
1290
+ VALUE bdb1_each_value(obj) VALUE obj;{ return bdb1_each_valuec(obj, DB_NEXT, Qnil); }
1291
+ VALUE bdb1_each_eulav(obj) VALUE obj;{ return bdb1_each_valuec(obj, DB_PREV, Qnil); }
1292
+
1293
+ static VALUE
1294
+ bdb1_each_keyc(obj, sens)
1295
+ VALUE obj;
1296
+ int sens;
1297
+ {
1298
+ bdb1_DB *dbst;
1299
+ DBT key, data;
1300
+ int ret, flags;
1301
+ db_recno_t recno;
1302
+
1303
+ GetDB(obj, dbst);
1304
+ INIT_RECNO(dbst, key, recno);
1305
+ DATA_ZERO(data);
1306
+ flags = (sens == DB_NEXT)?DB_FIRST:DB_LAST;
1307
+ do {
1308
+ ret = bdb1_test_error(dbst->dbp->seq(dbst->dbp, &key, &data, flags));
1309
+ if (ret == DB_NOTFOUND) {
1310
+ return Qnil;
1311
+ }
1312
+ rb_yield(test_load_key(obj, &key));
1313
+ flags = sens;
1314
+ } while (1);
1315
+ return obj;
1316
+ }
1317
+
1318
+ VALUE bdb1_each_key(obj) VALUE obj;{ return bdb1_each_keyc(obj, DB_NEXT); }
1319
+ static VALUE bdb1_each_yek(obj) VALUE obj;{ return bdb1_each_keyc(obj, DB_PREV); }
1320
+
1321
+ static VALUE
1322
+ bdb1_each_common(obj, sens)
1323
+ VALUE obj;
1324
+ int sens;
1325
+ {
1326
+ bdb1_DB *dbst;
1327
+ DBT key, data;
1328
+ int ret, flags;
1329
+ db_recno_t recno;
1330
+
1331
+ GetDB(obj, dbst);
1332
+ INIT_RECNO(dbst, key, recno);
1333
+ DATA_ZERO(data);
1334
+ flags = (sens == DB_NEXT)?DB_FIRST:DB_LAST;
1335
+ do {
1336
+ ret = bdb1_test_error(dbst->dbp->seq(dbst->dbp, &key, &data, flags));
1337
+ if (ret == DB_NOTFOUND) {
1338
+ return Qnil;
1339
+ }
1340
+ rb_yield(bdb1_assoc(obj, &key, &data));
1341
+ flags = sens;
1342
+ } while (1);
1343
+ return obj;
1344
+ }
1345
+
1346
+ static VALUE bdb1_each_pair(obj) VALUE obj;{ return bdb1_each_common(obj, DB_NEXT); }
1347
+ static VALUE bdb1_each_riap(obj) VALUE obj;{ return bdb1_each_common(obj, DB_PREV); }
1348
+
1349
+ VALUE
1350
+ bdb1_to_type(obj, result, flag)
1351
+ VALUE obj, result, flag;
1352
+ {
1353
+ bdb1_DB *dbst;
1354
+ DBT key, data;
1355
+ int ret, flags;
1356
+ db_recno_t recno;
1357
+
1358
+ GetDB(obj, dbst);
1359
+ INIT_RECNO(dbst, key, recno);
1360
+ DATA_ZERO(data);
1361
+ flags = (flag == Qnil)?DB_LAST:DB_FIRST;
1362
+ do {
1363
+ ret = bdb1_test_error(dbst->dbp->seq(dbst->dbp, &key, &data, flags));
1364
+ if (ret == DB_NOTFOUND) {
1365
+ return result;
1366
+ }
1367
+ switch (TYPE(result)) {
1368
+ case T_ARRAY:
1369
+ if (flag == Qtrue) {
1370
+ rb_ary_push(result, bdb1_assoc(obj, &key, &data));
1371
+ }
1372
+ else {
1373
+ rb_ary_push(result, bdb1_test_load(obj, &data, FILTER_VALUE));
1374
+ }
1375
+ break;
1376
+ case T_HASH:
1377
+ if (flag == Qtrue) {
1378
+ rb_hash_aset(result, test_load_key(obj, &key),
1379
+ bdb1_test_load(obj, &data, FILTER_VALUE));
1380
+ }
1381
+ else {
1382
+ rb_hash_aset(result, bdb1_test_load(obj, &data, FILTER_VALUE),
1383
+ test_load_key(obj, &key));
1384
+ }
1385
+ }
1386
+ flags = (flag == Qnil)?DB_PREV:DB_NEXT;
1387
+ } while (1);
1388
+ return result;
1389
+ }
1390
+
1391
+ static VALUE
1392
+ bdb1_to_a(obj)
1393
+ VALUE obj;
1394
+ {
1395
+ return bdb1_to_type(obj, rb_ary_new(), Qtrue);
1396
+ }
1397
+
1398
+ static VALUE
1399
+ bdb1_invert(obj)
1400
+ VALUE obj;
1401
+ {
1402
+ return bdb1_to_type(obj, rb_hash_new(), Qfalse);
1403
+ }
1404
+
1405
+ static VALUE
1406
+ bdb1_to_hash(obj)
1407
+ VALUE obj;
1408
+ {
1409
+ return bdb1_to_type(obj, rb_hash_new(), Qtrue);
1410
+ }
1411
+
1412
+ static VALUE
1413
+ bdb1_each_kv(obj, a, result, flag)
1414
+ VALUE obj, a, result, flag;
1415
+ {
1416
+ bdb1_DB *dbst;
1417
+ DBT keys, key, data;
1418
+ int ret, flags;
1419
+ db_recno_t recno;
1420
+ VALUE k;
1421
+ volatile VALUE b = Qnil;
1422
+
1423
+ GetDB(obj, dbst);
1424
+ b = test_recno(obj, &key, &recno, a);
1425
+ MEMCPY(&keys, &key, DBT, 1);
1426
+ DATA_ZERO(data);
1427
+ flags = R_CURSOR;
1428
+ while (1) {
1429
+ ret = bdb1_test_error(dbst->dbp->seq(dbst->dbp, &key, &data, flags));
1430
+ if (ret == DB_NOTFOUND || keys.size != key.size ||
1431
+ memcmp(keys.data, key.data, key.size) != 0) {
1432
+ return (result == Qnil)?obj:result;
1433
+ }
1434
+ k = bdb1_test_load(obj, &data, FILTER_VALUE);
1435
+ if (RTEST(flag)) {
1436
+ k = rb_assoc_new(test_load_key(obj, &key), k);
1437
+ }
1438
+ if (NIL_P(result)) {
1439
+ rb_yield(k);
1440
+ }
1441
+ else {
1442
+ rb_ary_push(result, k);
1443
+ }
1444
+ flags = DB_NEXT;
1445
+ }
1446
+ return Qnil;
1447
+ }
1448
+
1449
+ /*
1450
+ * call-seq:
1451
+ * db.duplicates(key, assoc = true)
1452
+ *
1453
+ * Returns an array of all duplicate associations for the +key+.
1454
+ *
1455
+ * If +assoc+ is +false+ return only the values.
1456
+ */
1457
+ static VALUE
1458
+ bdb1_bt_duplicates(argc, argv, obj)
1459
+ int argc;
1460
+ VALUE *argv, obj;
1461
+ {
1462
+ VALUE a, b;
1463
+
1464
+ if (rb_scan_args(argc, argv, "11", &a, &b) == 1) {
1465
+ b = Qtrue;
1466
+ }
1467
+ return bdb1_each_kv(obj, a, rb_ary_new(), b);
1468
+ }
1469
+
1470
+ /*
1471
+ * call-seq:
1472
+ * db.each_dup(key)
1473
+ *
1474
+ * Iterates over duplicate associations for the +key+.
1475
+ */
1476
+ static VALUE
1477
+ bdb1_bt_dup(obj, a)
1478
+ VALUE a, obj;
1479
+ {
1480
+ return bdb1_each_kv(obj, a, Qnil, Qtrue);
1481
+ }
1482
+
1483
+ /*
1484
+ * call-seq:
1485
+ * db.each_dup_value(key)
1486
+ *
1487
+ * Iterates over duplicate values for the +key+.
1488
+ */
1489
+ static VALUE
1490
+ bdb1_bt_dupval(obj, a)
1491
+ VALUE a, obj;
1492
+ {
1493
+ return bdb1_each_kv(obj, a, Qnil, Qfalse);
1494
+ }
1495
+
1496
+ static VALUE
1497
+ bdb1_reject(obj)
1498
+ VALUE obj;
1499
+ {
1500
+ return rb_hash_delete_if(bdb1_to_hash(obj));
1501
+ }
1502
+
1503
+ static VALUE
1504
+ bdb1_values(obj)
1505
+ VALUE obj;
1506
+ {
1507
+ bdb1_DB *dbst;
1508
+ DBT key, data;
1509
+ int ret, flags;
1510
+ db_recno_t recno;
1511
+ VALUE ary;
1512
+
1513
+ GetDB(obj, dbst);
1514
+ ary = rb_ary_new();
1515
+ INIT_RECNO(dbst, key, recno);
1516
+ DATA_ZERO(data);
1517
+ flags = DB_FIRST;
1518
+ do {
1519
+ ret = bdb1_test_error(dbst->dbp->seq(dbst->dbp, &key, &data, flags));
1520
+ if (ret == DB_NOTFOUND) {
1521
+ return ary;
1522
+ }
1523
+ flags = DB_NEXT;
1524
+ FREE_KEY(dbst, key);
1525
+ rb_ary_push(ary, bdb1_test_load(obj, &data, FILTER_VALUE));
1526
+ } while (1);
1527
+ return ary;
1528
+ }
1529
+
1530
+ VALUE
1531
+ bdb1_internal_value(obj, a, b, sens)
1532
+ VALUE obj, a, b;
1533
+ int sens;
1534
+ {
1535
+ bdb1_DB *dbst;
1536
+ DBT key, data;
1537
+ int ret, flags;
1538
+ db_recno_t recno;
1539
+
1540
+ GetDB(obj, dbst);
1541
+ INIT_RECNO(dbst, key, recno);
1542
+ DATA_ZERO(data);
1543
+ flags = (sens == DB_NEXT)?DB_FIRST:DB_LAST;
1544
+ do {
1545
+ ret = bdb1_test_error(dbst->dbp->seq(dbst->dbp, &key, &data, flags));
1546
+ if (ret == DB_NOTFOUND) {
1547
+ return (b == Qfalse)?Qfalse:Qnil;
1548
+ }
1549
+ flags = sens;
1550
+ if (rb_equal(a, bdb1_test_load(obj, &data, FILTER_VALUE)) == Qtrue) {
1551
+ VALUE d;
1552
+
1553
+ d = (b == Qfalse)?Qtrue:test_load_key(obj, &key);
1554
+ FREE_KEY(dbst, key);
1555
+ return d;
1556
+ }
1557
+ FREE_KEY(dbst, key);
1558
+ } while (1);
1559
+ return (b == Qfalse)?Qfalse:Qnil;
1560
+ }
1561
+
1562
+ VALUE
1563
+ bdb1_index(obj, a)
1564
+ VALUE obj, a;
1565
+ {
1566
+ return bdb1_internal_value(obj, a, Qtrue, DB_NEXT);
1567
+ }
1568
+
1569
+ static VALUE
1570
+ bdb1_indexes(argc, argv, obj)
1571
+ int argc;
1572
+ VALUE obj, *argv;
1573
+ {
1574
+ VALUE indexes;
1575
+ int i;
1576
+
1577
+ #if HAVE_RB_ARY_VALUES_AT
1578
+ rb_warn("BDB1#%s is deprecated; use BDB1#values_at",
1579
+ #if HAVE_RB_FRAME_THIS_FUNC
1580
+ rb_id2name(rb_frame_this_func()));
1581
+ #else
1582
+ rb_id2name(rb_frame_last_func()));
1583
+ #endif
1584
+ #endif
1585
+ indexes = rb_ary_new2(argc);
1586
+ for (i = 0; i < argc; i++) {
1587
+ rb_ary_push(indexes, bdb1_get(1, argv + i, obj));
1588
+ }
1589
+ return indexes;
1590
+ }
1591
+
1592
+ VALUE
1593
+ bdb1_has_value(obj, a)
1594
+ VALUE obj, a;
1595
+ {
1596
+ return bdb1_internal_value(obj, a, Qfalse, DB_NEXT);
1597
+ }
1598
+
1599
+ static VALUE
1600
+ bdb1_keys(obj)
1601
+ VALUE obj;
1602
+ {
1603
+ bdb1_DB *dbst;
1604
+ DBT key, data;
1605
+ int ret, flags;
1606
+ db_recno_t recno;
1607
+ VALUE ary;
1608
+
1609
+ GetDB(obj, dbst);
1610
+ ary = rb_ary_new();
1611
+ INIT_RECNO(dbst, key, recno);
1612
+ DATA_ZERO(data);
1613
+ flags = DB_FIRST;
1614
+ do {
1615
+ ret = bdb1_test_error(dbst->dbp->seq(dbst->dbp, &key, &data, flags));
1616
+ if (ret == DB_NOTFOUND) {
1617
+ return ary;
1618
+ }
1619
+ rb_ary_push(ary, test_load_key(obj, &key));
1620
+ FREE_KEY(dbst, key);
1621
+ flags = DB_NEXT;
1622
+ } while (1);
1623
+ return ary;
1624
+ }
1625
+
1626
+ static VALUE
1627
+ bdb1_sync(obj)
1628
+ VALUE obj;
1629
+ {
1630
+ bdb1_DB *dbst;
1631
+
1632
+ if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4)
1633
+ rb_raise(rb_eSecurityError, "Insecure: can't sync the database");
1634
+ GetDB(obj, dbst);
1635
+ bdb1_test_error(dbst->dbp->sync(dbst->dbp, 0));
1636
+ return Qtrue;
1637
+ }
1638
+
1639
+ #if HAVE_RB_ARY_VALUES_AT
1640
+
1641
+ static VALUE
1642
+ bdb1_values_at(argc, argv, obj)
1643
+ int argc;
1644
+ VALUE *argv, obj;
1645
+ {
1646
+ VALUE result = rb_ary_new2(argc);
1647
+ long i;
1648
+
1649
+ for (i = 0; i < argc; i++) {
1650
+ rb_ary_push(result, bdb1_get(1, argv + i, obj));
1651
+ }
1652
+ return result;
1653
+ }
1654
+
1655
+ #endif
1656
+
1657
+ #if HAVE_RB_ARY_SELECT
1658
+
1659
+ static VALUE
1660
+ bdb1_select(argc, argv, obj)
1661
+ int argc;
1662
+ VALUE *argv, obj;
1663
+ {
1664
+ VALUE result = rb_ary_new();
1665
+ long i;
1666
+
1667
+ if (rb_block_given_p()) {
1668
+ if (argc > 0) {
1669
+ rb_raise(rb_eArgError, "wrong number arguments(%d for 0)", argc);
1670
+ }
1671
+ return bdb1_each_valuec(obj, DB_NEXT, result);
1672
+ }
1673
+ rb_warn("Common#select(index..) is deprecated; use Common#values_at");
1674
+ return bdb1_values_at(argc, argv, obj);
1675
+ }
1676
+
1677
+ #endif
1678
+
1679
+ VALUE
1680
+ bdb1_each_vc(obj, replace, rtest)
1681
+ VALUE obj;
1682
+ int replace, rtest;
1683
+ {
1684
+ bdb1_DB *dbst;
1685
+ DBT key, data;
1686
+ int ret, flags;
1687
+ db_recno_t recno;
1688
+ VALUE res, result, val;
1689
+
1690
+ GetDB(obj, dbst);
1691
+ INIT_RECNO(dbst, key, recno);
1692
+ DATA_ZERO(data);
1693
+ flags = DB_FIRST;
1694
+ result = rb_ary_new();
1695
+ do {
1696
+ ret = bdb1_test_error(dbst->dbp->seq(dbst->dbp, &key, &data, flags));
1697
+ if (ret == DB_NOTFOUND) {
1698
+ return result;
1699
+ }
1700
+ flags = DB_NEXT;
1701
+ FREE_KEY(dbst, key);
1702
+ val = bdb1_test_load(obj, &data, FILTER_VALUE);
1703
+ res = rb_yield(val);
1704
+ if (rtest) {
1705
+ if (RTEST(res)) {
1706
+ rb_ary_push(result, val);
1707
+ }
1708
+ }
1709
+ else {
1710
+ rb_ary_push(result, res);
1711
+ }
1712
+ if (replace == Qtrue) {
1713
+ DATA_ZERO(data);
1714
+ res = test_dump(obj, &data, res, FILTER_VALUE);
1715
+ bdb1_test_error(dbst->dbp->put(dbst->dbp, &key, &data, 0));
1716
+ }
1717
+ } while (1);
1718
+ return Qnil;
1719
+ }
1720
+
1721
+ /*
1722
+ * This interface if for the version 1.85 and 1.86 of Berkeley DB (for
1723
+ * Berkeley version >= 2 see bdb)
1724
+ *
1725
+ * Developers may choose to store data in any of several different
1726
+ * storage structures to satisfy the requirements of a particular
1727
+ * application. In database terminology, these storage structures and
1728
+ * the code that operates on them are called access methods.
1729
+ *
1730
+ * The library includes support for the following access methods:
1731
+ *
1732
+ * * BDB1::Btree
1733
+ *
1734
+ * B+tree: Stores keys in sorted order, using a default function
1735
+ * that does lexicographical ordering of keys.
1736
+ *
1737
+ * * BDB1::Hash
1738
+ *
1739
+ * Hashing: Stores records in a hash table for fast searches based
1740
+ * on strict equality, using a default that hashes on the key as a
1741
+ * bit string. Extended Linear Hashing modifies the hash function
1742
+ * used by the table as new records are inserted, in order to keep
1743
+ * buckets underfull in the steady state.
1744
+ *
1745
+ * * BDB1::Recnum
1746
+ *
1747
+ * Fixed and Variable-Length Records. Stores fixed- or
1748
+ * variable-length records in sequential order.
1749
+ *
1750
+ */
1751
+ void
1752
+ Init_bdb1()
1753
+ {
1754
+ bdb1_mMarshal = rb_const_get(rb_cObject, rb_intern("Marshal"));
1755
+ id_dump = rb_intern("dump");
1756
+ id_load = rb_intern("load");
1757
+ bdb1_id_current_db = rb_intern("bdb1_current_db");
1758
+ id_bt_compare = rb_intern("bdb1_bt_compare");
1759
+ id_bt_prefix = rb_intern("bdb1_bt_prefix");
1760
+ id_h_hash = rb_intern("bdb1_h_hash");
1761
+ bdb1_id_call = rb_intern("call");
1762
+ if (rb_const_defined_at(rb_cObject, rb_intern("BDB1"))) {
1763
+ rb_raise(rb_eNameError, "class already defined");
1764
+ }
1765
+ bdb1_mDb = rb_define_module("BDB1");
1766
+ bdb1_eFatal = rb_define_class_under(bdb1_mDb, "Fatal", rb_eStandardError);
1767
+ /* CONSTANT */
1768
+ rb_define_const(bdb1_mDb, "VERSION_MAJOR", INT2FIX(DB_VERSION_MAJOR));
1769
+ rb_define_const(bdb1_mDb, "VERSION_MINOR", INT2FIX(DB_VERSION_MINOR));
1770
+ rb_define_const(bdb1_mDb, "RELEASE_PATCH", INT2FIX(DB_RELEASE_PATCH));
1771
+ rb_define_const(bdb1_mDb, "VERSION", rb_str_new2("1.x.x"));
1772
+ rb_define_const(bdb1_mDb, "BTREE", INT2FIX(DB_BTREE));
1773
+ rb_define_const(bdb1_mDb, "HASH", INT2FIX(DB_HASH));
1774
+ rb_define_const(bdb1_mDb, "RECNO", INT2FIX(DB_RECNO));
1775
+ rb_define_const(bdb1_mDb, "AFTER", INT2FIX(DB_AFTER));
1776
+ rb_define_const(bdb1_mDb, "BEFORE", INT2FIX(DB_BEFORE));
1777
+ rb_define_const(bdb1_mDb, "CREATE", INT2FIX(DB_CREATE));
1778
+ rb_define_const(bdb1_mDb, "DUP", INT2FIX(DB_DUP));
1779
+ rb_define_const(bdb1_mDb, "FIRST", INT2FIX(DB_FIRST));
1780
+ rb_define_const(bdb1_mDb, "LAST", INT2FIX(DB_LAST));
1781
+ rb_define_const(bdb1_mDb, "NEXT", INT2FIX(DB_NEXT));
1782
+ rb_define_const(bdb1_mDb, "PREV", INT2FIX(DB_PREV));
1783
+ rb_define_const(bdb1_mDb, "RDONLY", INT2FIX(DB_RDONLY));
1784
+ rb_define_const(bdb1_mDb, "SET_RANGE", INT2FIX(DB_SET_RANGE));
1785
+ rb_define_const(bdb1_mDb, "TRUNCATE", INT2FIX(DB_TRUNCATE));
1786
+ rb_define_const(bdb1_mDb, "WRITE", INT2FIX(DB_WRITE));
1787
+ rb_define_const(bdb1_mDb, "NOOVERWRITE", INT2FIX(DB_NOOVERWRITE));
1788
+ /* DATABASE */
1789
+ bdb1_cCommon = rb_define_class_under(bdb1_mDb, "Common", rb_cObject);
1790
+ rb_define_method(bdb1_cCommon, "initialize", bdb1_init, -1);
1791
+ rb_include_module(bdb1_cCommon, rb_mEnumerable);
1792
+ #ifdef HAVE_RB_DEFINE_ALLOC_FUNC
1793
+ rb_define_alloc_func(bdb1_cCommon, bdb1_s_alloc);
1794
+ #else
1795
+ rb_define_singleton_method(bdb1_cCommon, "allocate", bdb1_s_alloc, 0);
1796
+ #endif
1797
+ rb_define_singleton_method(bdb1_cCommon, "create", bdb1_s_create, -1);
1798
+ rb_define_singleton_method(bdb1_cCommon, "open", bdb1_s_open, -1);
1799
+ rb_define_singleton_method(bdb1_cCommon, "[]", bdb1_s_aref, -1);
1800
+ rb_define_method(bdb1_cCommon, "close", bdb1_close, 0);
1801
+ rb_define_method(bdb1_cCommon, "db_close", bdb1_close, 0);
1802
+ rb_define_method(bdb1_cCommon, "put", bdb1_put, -1);
1803
+ rb_define_method(bdb1_cCommon, "db_put", bdb1_put, -1);
1804
+ rb_define_method(bdb1_cCommon, "[]=", bdb1_assign, 2);
1805
+ rb_define_method(bdb1_cCommon, "store", bdb1_put, -1);
1806
+ rb_define_method(bdb1_cCommon, "get", bdb1_get_dyna, -1);
1807
+ rb_define_method(bdb1_cCommon, "db_get", bdb1_get_dyna, -1);
1808
+ rb_define_method(bdb1_cCommon, "[]", bdb1_get_dyna, -1);
1809
+ rb_define_method(bdb1_cCommon, "fetch", bdb1_fetch, -1);
1810
+ rb_define_method(bdb1_cCommon, "delete", bdb1_del, 1);
1811
+ rb_define_method(bdb1_cCommon, "del", bdb1_del, 1);
1812
+ rb_define_method(bdb1_cCommon, "db_del", bdb1_del, 1);
1813
+ rb_define_method(bdb1_cCommon, "sync", bdb1_sync, 0);
1814
+ rb_define_method(bdb1_cCommon, "db_sync", bdb1_sync, 0);
1815
+ rb_define_method(bdb1_cCommon, "flush", bdb1_sync, 0);
1816
+ rb_define_method(bdb1_cCommon, "each", bdb1_each_pair, 0);
1817
+ rb_define_method(bdb1_cCommon, "each_value", bdb1_each_value, 0);
1818
+ rb_define_method(bdb1_cCommon, "reverse_each_value", bdb1_each_eulav, 0);
1819
+ rb_define_method(bdb1_cCommon, "each_key", bdb1_each_key, 0);
1820
+ rb_define_method(bdb1_cCommon, "reverse_each_key", bdb1_each_yek, 0);
1821
+ rb_define_method(bdb1_cCommon, "each_pair", bdb1_each_pair, 0);
1822
+ rb_define_method(bdb1_cCommon, "reverse_each", bdb1_each_riap, 0);
1823
+ rb_define_method(bdb1_cCommon, "reverse_each_pair", bdb1_each_riap, 0);
1824
+ rb_define_method(bdb1_cCommon, "keys", bdb1_keys, 0);
1825
+ rb_define_method(bdb1_cCommon, "values", bdb1_values, 0);
1826
+ rb_define_method(bdb1_cCommon, "delete_if", bdb1_delete_if, 0);
1827
+ rb_define_method(bdb1_cCommon, "reject!", bdb1_delete_if, 0);
1828
+ rb_define_method(bdb1_cCommon, "reject", bdb1_reject, 0);
1829
+ rb_define_method(bdb1_cCommon, "clear", bdb1_clear, 0);
1830
+ rb_define_method(bdb1_cCommon, "include?", bdb1_has_key, 1);
1831
+ rb_define_method(bdb1_cCommon, "has_key?", bdb1_has_key, 1);
1832
+ rb_define_method(bdb1_cCommon, "key?", bdb1_has_key, 1);
1833
+ rb_define_method(bdb1_cCommon, "member?", bdb1_has_key, 1);
1834
+ rb_define_method(bdb1_cCommon, "has_value?", bdb1_has_value, 1);
1835
+ rb_define_method(bdb1_cCommon, "value?", bdb1_has_value, 1);
1836
+ rb_define_method(bdb1_cCommon, "has_both?", bdb1_has_both, 2);
1837
+ rb_define_method(bdb1_cCommon, "both?", bdb1_has_both, 2);
1838
+ rb_define_method(bdb1_cCommon, "to_a", bdb1_to_a, 0);
1839
+ rb_define_method(bdb1_cCommon, "to_hash", bdb1_to_hash, 0);
1840
+ rb_define_method(bdb1_cCommon, "invert", bdb1_invert, 0);
1841
+ rb_define_method(bdb1_cCommon, "empty?", bdb1_empty, 0);
1842
+ rb_define_method(bdb1_cCommon, "length", bdb1_length, 0);
1843
+ rb_define_alias(bdb1_cCommon, "size", "length");
1844
+ rb_define_method(bdb1_cCommon, "index", bdb1_index, 1);
1845
+ rb_define_method(bdb1_cCommon, "indexes", bdb1_indexes, -1);
1846
+ rb_define_method(bdb1_cCommon, "indices", bdb1_indexes, -1);
1847
+ #if HAVE_RB_ARY_SELECT
1848
+ rb_define_method(bdb1_cCommon, "select", bdb1_select, -1);
1849
+ #endif
1850
+ #if HAVE_RB_ARY_VALUES_AT
1851
+ rb_define_method(bdb1_cCommon, "values_at", bdb1_values_at, -1);
1852
+ #endif
1853
+ bdb1_cBtree = rb_define_class_under(bdb1_mDb, "Btree", bdb1_cCommon);
1854
+ rb_define_method(bdb1_cBtree, "duplicates", bdb1_bt_duplicates, -1);
1855
+ rb_define_method(bdb1_cBtree, "each_dup", bdb1_bt_dup, 1);
1856
+ rb_define_method(bdb1_cBtree, "each_dup_value", bdb1_bt_dupval, 1);
1857
+ bdb1_cHash = rb_define_class_under(bdb1_mDb, "Hash", bdb1_cCommon);
1858
+ rb_undef_method(bdb1_cHash, "delete_if");
1859
+ rb_undef_method(bdb1_cHash, "reverse_each_value");
1860
+ rb_undef_method(bdb1_cHash, "reverse_each_key");
1861
+ rb_undef_method(bdb1_cHash, "reverse_each_pair");
1862
+ rb_undef_method(bdb1_cHash, "reverse_each");
1863
+ bdb1_cUnknown = rb_define_class_under(bdb1_mDb, "Unknown", bdb1_cCommon);
1864
+ bdb1_errstr = rb_tainted_str_new(0, 0);
1865
+ rb_global_variable(&bdb1_errstr);
1866
+ bdb1_init_delegator();
1867
+ bdb1_init_recnum();
1868
+ }