Ruby
2.1.3p242(2014-09-19revision47630)
Main Page
Modules
Data Structures
Files
File List
Globals
ext
sdbm
init.c
Go to the documentation of this file.
1
/************************************************
2
3
sdbminit.c -
4
5
$Author: nobu $
6
created at: Fri May 7 08:34:24 JST 1999
7
8
Copyright (C) 1995-2001 Yukihiro Matsumoto
9
10
************************************************/
11
12
#include "
ruby.h
"
13
14
#include "
sdbm.h
"
15
#include <fcntl.h>
16
#include <errno.h>
17
18
/*
19
* Document-class: SDBM
20
*
21
* SDBM provides a simple file-based key-value store, which can only store
22
* String keys and values.
23
*
24
* Note that Ruby comes with the source code for SDBM, while the DBM and GDBM
25
* standard libraries rely on external libraries and headers.
26
*
27
* === Examples
28
*
29
* Insert values:
30
*
31
* require 'sdbm'
32
*
33
* SDBM.open 'my_database' do |db|
34
* db['apple'] = 'fruit'
35
* db['pear'] = 'fruit'
36
* db['carrot'] = 'vegetable'
37
* db['tomato'] = 'vegetable'
38
* end
39
*
40
* Bulk update:
41
*
42
* require 'sdbm'
43
*
44
* SDBM.open 'my_database' do |db|
45
* db.update('peach' => 'fruit', 'tomato' => 'fruit')
46
* end
47
*
48
* Retrieve values:
49
*
50
* require 'sdbm'
51
*
52
* SDBM.open 'my_database' do |db|
53
* db.each do |key, value|
54
* puts "Key: #{key}, Value: #{value}"
55
* end
56
* end
57
*
58
* Outputs:
59
*
60
* Key: apple, Value: fruit
61
* Key: pear, Value: fruit
62
* Key: carrot, Value: vegetable
63
* Key: peach, Value: fruit
64
* Key: tomato, Value: fruit
65
*/
66
67
static
VALUE
rb_cDBM
,
rb_eDBMError
;
68
69
struct
dbmdata
{
70
int
di_size
;
71
DBM
*
di_dbm
;
72
};
73
74
static
void
75
closed_sdbm
()
76
{
77
rb_raise
(
rb_eDBMError
,
"closed SDBM file"
);
78
}
79
80
#define GetDBM(obj, dbmp) {\
81
Data_Get_Struct((obj), struct dbmdata, (dbmp));\
82
if ((dbmp) == 0) closed_sdbm();\
83
if ((dbmp)->di_dbm == 0) closed_sdbm();\
84
}
85
86
#define GetDBM2(obj, data, dbm) {\
87
GetDBM((obj), (data));\
88
(dbm) = dbmp->di_dbm;\
89
}
90
91
static
void
92
free_sdbm
(
struct
dbmdata
*dbmp)
93
{
94
95
if
(dbmp->
di_dbm
)
sdbm_close
(dbmp->
di_dbm
);
96
ruby_xfree
(dbmp);
97
}
98
99
/*
100
* call-seq:
101
* sdbm.close -> nil
102
*
103
* Closes the database file.
104
*
105
* Raises SDBMError if the database is already closed.
106
*/
107
static
VALUE
108
fsdbm_close
(
VALUE
obj)
109
{
110
struct
dbmdata
*dbmp;
111
112
GetDBM
(obj, dbmp);
113
sdbm_close
(dbmp->
di_dbm
);
114
dbmp->
di_dbm
= 0;
115
116
return
Qnil
;
117
}
118
119
/*
120
* call-seq:
121
* sdbm.closed? -> true or false
122
*
123
* Returns +true+ if the database is closed.
124
*/
125
static
VALUE
126
fsdbm_closed
(
VALUE
obj)
127
{
128
struct
dbmdata
*dbmp;
129
130
Data_Get_Struct
(obj,
struct
dbmdata
, dbmp);
131
if
(dbmp == 0)
132
return
Qtrue
;
133
if
(dbmp->
di_dbm
== 0)
134
return
Qtrue
;
135
136
return
Qfalse
;
137
}
138
139
static
VALUE
140
fsdbm_alloc
(
VALUE
klass)
141
{
142
return
Data_Wrap_Struct
(klass, 0,
free_sdbm
, 0);
143
}
144
/*
145
* call-seq:
146
* SDBM.new(filename, mode = 0666)
147
*
148
* Creates a new database handle by opening the given +filename+. SDBM actually
149
* uses two physical files, with extensions '.dir' and '.pag'. These extensions
150
* will automatically be appended to the +filename+.
151
*
152
* If the file does not exist, a new file will be created using the given
153
* +mode+, unless +mode+ is explicitly set to nil. In the latter case, no
154
* database will be created.
155
*
156
* If the file exists, it will be opened in read/write mode. If this fails, it
157
* will be opened in read-only mode.
158
*/
159
static
VALUE
160
fsdbm_initialize
(
int
argc
,
VALUE
*
argv
,
VALUE
obj)
161
{
162
volatile
VALUE
file;
163
VALUE
vmode;
164
DBM
*dbm;
165
struct
dbmdata
*dbmp;
166
int
mode;
167
168
if
(
rb_scan_args
(argc, argv,
"11"
, &file, &vmode) == 1) {
169
mode = 0666;
/* default value */
170
}
171
else
if
(
NIL_P
(vmode)) {
172
mode = -1;
/* return nil if DB not exist */
173
}
174
else
{
175
mode =
NUM2INT
(vmode);
176
}
177
FilePathValue
(file);
178
179
dbm = 0;
180
if
(mode >= 0)
181
dbm =
sdbm_open
(
RSTRING_PTR
(file), O_RDWR|O_CREAT, mode);
182
if
(!dbm)
183
dbm =
sdbm_open
(
RSTRING_PTR
(file), O_RDWR, 0);
184
if
(!dbm)
185
dbm =
sdbm_open
(
RSTRING_PTR
(file), O_RDONLY, 0);
186
187
if
(!dbm) {
188
if
(mode == -1)
return
Qnil
;
189
rb_sys_fail_str
(file);
190
}
191
192
dbmp =
ALLOC
(
struct
dbmdata
);
193
DATA_PTR
(obj) = dbmp;
194
dbmp->
di_dbm
= dbm;
195
dbmp->
di_size
= -1;
196
197
return
obj;
198
}
199
200
/*
201
* call-seq:
202
* SDBM.open(filename, mode = 0666)
203
* SDBM.open(filename, mode = 0666) { |sdbm| ... }
204
*
205
* If called without a block, this is the same as SDBM.new.
206
*
207
* If a block is given, the new database will be passed to the block and
208
* will be safely closed after the block has executed.
209
*
210
* Example:
211
*
212
* require 'sdbm'
213
*
214
* SDBM.open('my_database') do |db|
215
* db['hello'] = 'world'
216
* end
217
*/
218
static
VALUE
219
fsdbm_s_open
(
int
argc
,
VALUE
*
argv
,
VALUE
klass)
220
{
221
VALUE
obj =
Data_Wrap_Struct
(klass, 0,
free_sdbm
, 0);
222
223
if
(
NIL_P
(
fsdbm_initialize
(argc, argv, obj))) {
224
return
Qnil
;
225
}
226
227
if
(
rb_block_given_p
()) {
228
return
rb_ensure
(
rb_yield
, obj,
fsdbm_close
, obj);
229
}
230
231
return
obj;
232
}
233
234
static
VALUE
235
fsdbm_fetch
(
VALUE
obj,
VALUE
keystr,
VALUE
ifnone)
236
{
237
datum
key
, value;
238
struct
dbmdata
*dbmp;
239
DBM
*dbm;
240
241
ExportStringValue
(keystr);
242
key.
dptr
=
RSTRING_PTR
(keystr);
243
key.
dsize
=
RSTRING_LENINT
(keystr);
244
245
GetDBM2
(obj, dbmp, dbm);
246
value =
sdbm_fetch
(dbm, key);
247
if
(value.
dptr
== 0) {
248
if
(ifnone ==
Qnil
&&
rb_block_given_p
())
249
return
rb_yield
(
rb_external_str_new
(key.
dptr
, key.
dsize
));
250
return
ifnone;
251
}
252
return
rb_external_str_new
(value.
dptr
, value.
dsize
);
253
}
254
255
/*
256
* call-seq:
257
* sdbm[key] -> value or nil
258
*
259
* Returns the +value+ in the database associated with the given +key+ string.
260
*
261
* If no value is found, returns +nil+.
262
*/
263
static
VALUE
264
fsdbm_aref
(
VALUE
obj,
VALUE
keystr)
265
{
266
return
fsdbm_fetch
(obj, keystr,
Qnil
);
267
}
268
269
/*
270
* call-seq:
271
* sdbm.fetch(key) -> value or nil
272
* sdbm.fetch(key) { |key| ... }
273
*
274
* Returns the +value+ in the database associated with the given +key+ string.
275
*
276
* If a block is provided, the block will be called when there is no
277
* +value+ associated with the given +key+. The +key+ will be passed in as an
278
* argument to the block.
279
*
280
* If no block is provided and no value is associated with the given +key+,
281
* then an IndexError will be raised.
282
*/
283
static
VALUE
284
fsdbm_fetch_m
(
int
argc
,
VALUE
*
argv
,
VALUE
obj)
285
{
286
VALUE
keystr, valstr, ifnone;
287
288
rb_scan_args
(argc, argv,
"11"
, &keystr, &ifnone);
289
valstr =
fsdbm_fetch
(obj, keystr, ifnone);
290
if
(argc == 1 && !
rb_block_given_p
() &&
NIL_P
(valstr))
291
rb_raise
(
rb_eIndexError
,
"key not found"
);
292
293
return
valstr;
294
}
295
296
/*
297
* call-seq:
298
* sdbm.key(value) -> key
299
*
300
* Returns the +key+ associated with the given +value+. If more than one
301
* +key+ corresponds to the given +value+, then the first key to be found
302
* will be returned. If no keys are found, +nil+ will be returned.
303
*/
304
static
VALUE
305
fsdbm_key
(
VALUE
obj,
VALUE
valstr)
306
{
307
datum
key
,
val
;
308
struct
dbmdata
*dbmp;
309
DBM
*dbm;
310
311
ExportStringValue
(valstr);
312
val.
dptr
=
RSTRING_PTR
(valstr);
313
val.
dsize
=
RSTRING_LENINT
(valstr);
314
315
GetDBM2
(obj, dbmp, dbm);
316
for
(key =
sdbm_firstkey
(dbm); key.
dptr
; key =
sdbm_nextkey
(dbm)) {
317
val =
sdbm_fetch
(dbm, key);
318
if
(val.
dsize
==
RSTRING_LEN
(valstr) &&
319
memcmp
(val.
dptr
,
RSTRING_PTR
(valstr), val.
dsize
) == 0)
320
return
rb_external_str_new
(key.
dptr
, key.
dsize
);
321
}
322
return
Qnil
;
323
}
324
325
/*
326
* :nodoc:
327
*/
328
static
VALUE
329
fsdbm_index
(
VALUE
hash
,
VALUE
value)
330
{
331
rb_warn
(
"SDBM#index is deprecated; use SDBM#key"
);
332
return
fsdbm_key
(hash, value);
333
}
334
335
/* call-seq:
336
* sdbm.select { |key, value| ... } -> Array
337
*
338
* Returns a new Array of key-value pairs for which the block returns +true+.
339
*
340
* Example:
341
*
342
* require 'sdbm'
343
*
344
* SDBM.open 'my_database' do |db|
345
* db['apple'] = 'fruit'
346
* db['pear'] = 'fruit'
347
* db['spinach'] = 'vegetable'
348
*
349
* veggies = db.select do |key, value|
350
* value == 'vegetable'
351
* end #=> [["apple", "fruit"], ["pear", "fruit"]]
352
* end
353
*/
354
static
VALUE
355
fsdbm_select
(
VALUE
obj)
356
{
357
VALUE
new
=
rb_ary_new
();
358
datum
key
,
val
;
359
DBM
*dbm;
360
struct
dbmdata
*dbmp;
361
362
GetDBM2
(obj, dbmp, dbm);
363
for
(key =
sdbm_firstkey
(dbm); key.
dptr
; key =
sdbm_nextkey
(dbm)) {
364
VALUE
assoc, v;
365
val =
sdbm_fetch
(dbm, key);
366
assoc =
rb_assoc_new
(
rb_external_str_new
(key.
dptr
, key.
dsize
),
367
rb_external_str_new
(val.
dptr
, val.
dsize
));
368
v =
rb_yield
(assoc);
369
if
(
RTEST
(v)) {
370
rb_ary_push
(
new
, assoc);
371
}
372
GetDBM2
(obj, dbmp, dbm);
373
}
374
375
return
new
;
376
}
377
378
/* call-seq:
379
* sdbm.values_at(key, ...) -> Array
380
*
381
* Returns an Array of values corresponding to the given keys.
382
*/
383
static
VALUE
384
fsdbm_values_at
(
int
argc
,
VALUE
*
argv
,
VALUE
obj)
385
{
386
VALUE
new
=
rb_ary_new2
(argc);
387
int
i;
388
389
for
(i=0; i<
argc
; i++) {
390
rb_ary_push
(
new
,
fsdbm_fetch
(obj, argv[i],
Qnil
));
391
}
392
393
return
new
;
394
}
395
396
static
void
397
fdbm_modify
(
VALUE
obj)
398
{
399
if
(
OBJ_FROZEN
(obj))
rb_error_frozen
(
"SDBM"
);
400
}
401
402
/*
403
* call-seq:
404
* sdbm.delete(key) -> value or nil
405
* sdbm.delete(key) { |key, value| ... }
406
*
407
* Deletes the key-value pair corresponding to the given +key+. If the
408
* +key+ exists, the deleted value will be returned, otherwise +nil+.
409
*
410
* If a block is provided, the deleted +key+ and +value+ will be passed to
411
* the block as arguments. If the +key+ does not exist in the database, the
412
* value will be +nil+.
413
*/
414
static
VALUE
415
fsdbm_delete
(
VALUE
obj,
VALUE
keystr)
416
{
417
datum
key
, value;
418
struct
dbmdata
*dbmp;
419
DBM
*dbm;
420
VALUE
valstr;
421
422
fdbm_modify
(obj);
423
ExportStringValue
(keystr);
424
key.
dptr
=
RSTRING_PTR
(keystr);
425
key.
dsize
=
RSTRING_LENINT
(keystr);
426
427
GetDBM2
(obj, dbmp, dbm);
428
dbmp->
di_size
= -1;
429
430
value =
sdbm_fetch
(dbm, key);
431
if
(value.
dptr
== 0) {
432
if
(
rb_block_given_p
())
return
rb_yield
(keystr);
433
return
Qnil
;
434
}
435
436
/* need to save value before sdbm_delete() */
437
valstr =
rb_external_str_new
(value.
dptr
, value.
dsize
);
438
439
if
(
sdbm_delete
(dbm, key)) {
440
dbmp->
di_size
= -1;
441
rb_raise
(
rb_eDBMError
,
"dbm_delete failed"
);
442
}
443
else
if
(dbmp->
di_size
>= 0) {
444
dbmp->
di_size
--;
445
}
446
return
valstr;
447
}
448
449
/*
450
* call-seq:
451
* sdbm.shift -> Array or nil
452
*
453
* Removes a key-value pair from the database and returns them as an
454
* Array. If the database is empty, returns +nil+.
455
*/
456
static
VALUE
457
fsdbm_shift
(
VALUE
obj)
458
{
459
datum
key
,
val
;
460
struct
dbmdata
*dbmp;
461
DBM
*dbm;
462
VALUE
keystr, valstr;
463
464
fdbm_modify
(obj);
465
GetDBM2
(obj, dbmp, dbm);
466
key =
sdbm_firstkey
(dbm);
467
if
(!key.
dptr
)
return
Qnil
;
468
val =
sdbm_fetch
(dbm, key);
469
keystr =
rb_external_str_new
(key.
dptr
, key.
dsize
);
470
valstr =
rb_external_str_new
(val.
dptr
, val.
dsize
);
471
sdbm_delete
(dbm, key);
472
if
(dbmp->
di_size
>= 0) {
473
dbmp->
di_size
--;
474
}
475
476
return
rb_assoc_new
(keystr, valstr);
477
}
478
479
/*
480
* call-seq:
481
* sdbm.delete_if { |key, value| ... } -> self
482
* sdbm.reject! { |key, value| ... } -> self
483
*
484
* Iterates over the key-value pairs in the database, deleting those for
485
* which the block returns +true+.
486
*/
487
static
VALUE
488
fsdbm_delete_if
(
VALUE
obj)
489
{
490
datum
key
,
val
;
491
struct
dbmdata
*dbmp;
492
DBM
*dbm;
493
VALUE
keystr, valstr;
494
VALUE
ret, ary =
rb_ary_new
();
495
int
i, status = 0, n;
496
497
fdbm_modify
(obj);
498
GetDBM2
(obj, dbmp, dbm);
499
n = dbmp->
di_size
;
500
dbmp->
di_size
= -1;
501
for
(key =
sdbm_firstkey
(dbm); key.
dptr
; key =
sdbm_nextkey
(dbm)) {
502
val =
sdbm_fetch
(dbm, key);
503
keystr =
rb_external_str_new
(key.
dptr
, key.
dsize
);
504
valstr =
rb_external_str_new
(val.
dptr
, val.
dsize
);
505
ret =
rb_protect
(
rb_yield
,
rb_assoc_new
(
rb_str_dup
(keystr), valstr), &status);
506
if
(status != 0)
break
;
507
if
(
RTEST
(ret))
rb_ary_push
(ary, keystr);
508
GetDBM2
(obj, dbmp, dbm);
509
}
510
511
for
(i = 0; i <
RARRAY_LEN
(ary); i++) {
512
keystr =
RARRAY_PTR
(ary)[i];
513
ExportStringValue
(keystr);
514
key.
dptr
=
RSTRING_PTR
(keystr);
515
key.
dsize
=
RSTRING_LENINT
(keystr);
516
if
(
sdbm_delete
(dbm, key)) {
517
rb_raise
(
rb_eDBMError
,
"sdbm_delete failed"
);
518
}
519
}
520
if
(status)
rb_jump_tag
(status);
521
if
(n > 0) dbmp->
di_size
= n -
RARRAY_LENINT
(ary);
522
523
return
obj;
524
}
525
526
/*
527
* call-seq:
528
* sdbm.clear -> self
529
*
530
* Deletes all data from the database.
531
*/
532
static
VALUE
533
fsdbm_clear
(
VALUE
obj)
534
{
535
datum
key
;
536
struct
dbmdata
*dbmp;
537
DBM
*dbm;
538
539
fdbm_modify
(obj);
540
GetDBM2
(obj, dbmp, dbm);
541
dbmp->
di_size
= -1;
542
while
(key =
sdbm_firstkey
(dbm), key.
dptr
) {
543
if
(
sdbm_delete
(dbm, key)) {
544
rb_raise
(
rb_eDBMError
,
"sdbm_delete failed"
);
545
}
546
}
547
dbmp->
di_size
= 0;
548
549
return
obj;
550
}
551
552
/*
553
* call-seq:
554
* sdbm.invert -> Hash
555
*
556
* Returns a Hash in which the key-value pairs have been inverted.
557
*
558
* Example:
559
*
560
* require 'sdbm'
561
*
562
* SDBM.open 'my_database' do |db|
563
* db.update('apple' => 'fruit', 'spinach' => 'vegetable')
564
*
565
* db.invert #=> {"fruit" => "apple", "vegetable" => "spinach"}
566
* end
567
*/
568
static
VALUE
569
fsdbm_invert
(
VALUE
obj)
570
{
571
datum
key
,
val
;
572
struct
dbmdata
*dbmp;
573
DBM
*dbm;
574
VALUE
keystr, valstr;
575
VALUE
hash
=
rb_hash_new
();
576
577
GetDBM2
(obj, dbmp, dbm);
578
for
(key =
sdbm_firstkey
(dbm); key.
dptr
; key =
sdbm_nextkey
(dbm)) {
579
val =
sdbm_fetch
(dbm, key);
580
keystr =
rb_external_str_new
(key.
dptr
, key.
dsize
);
581
valstr =
rb_external_str_new
(val.
dptr
, val.
dsize
);
582
rb_hash_aset
(hash, valstr, keystr);
583
}
584
return
hash
;
585
}
586
587
/*
588
* call-seq:
589
* sdbm[key] = value -> value
590
* sdbm.store(key, value) -> value
591
*
592
* Stores a new +value+ in the database with the given +key+ as an index.
593
*
594
* If the +key+ already exists, this will update the +value+ associated with
595
* the +key+.
596
*
597
* Returns the given +value+.
598
*/
599
static
VALUE
600
fsdbm_store
(
VALUE
obj,
VALUE
keystr,
VALUE
valstr)
601
{
602
datum
key
,
val
;
603
struct
dbmdata
*dbmp;
604
DBM
*dbm;
605
606
if
(valstr ==
Qnil
) {
607
fsdbm_delete
(obj, keystr);
608
return
Qnil
;
609
}
610
611
fdbm_modify
(obj);
612
ExportStringValue
(keystr);
613
ExportStringValue
(valstr);
614
615
key.
dptr
=
RSTRING_PTR
(keystr);
616
key.
dsize
=
RSTRING_LENINT
(keystr);
617
618
val.
dptr
=
RSTRING_PTR
(valstr);
619
val.
dsize
=
RSTRING_LENINT
(valstr);
620
621
GetDBM2
(obj, dbmp, dbm);
622
dbmp->
di_size
= -1;
623
if
(
sdbm_store
(dbm, key, val,
DBM_REPLACE
)) {
624
#ifdef HAVE_DBM_CLAERERR
625
sdbm_clearerr
(dbm);
626
#endif
627
if
(
errno
==
EPERM
)
rb_sys_fail
(0);
628
rb_raise
(
rb_eDBMError
,
"sdbm_store failed"
);
629
}
630
631
return
valstr;
632
}
633
634
static
VALUE
635
update_i
(
RB_BLOCK_CALL_FUNC_ARGLIST
(pair, dbm))
636
{
637
Check_Type
(pair,
T_ARRAY
);
638
if
(
RARRAY_LEN
(pair) < 2) {
639
rb_raise
(
rb_eArgError
,
"pair must be [key, value]"
);
640
}
641
fsdbm_store
(dbm,
RARRAY_PTR
(pair)[0],
RARRAY_PTR
(pair)[1]);
642
return
Qnil
;
643
}
644
645
/*
646
* call-seq:
647
* sdbm.update(pairs) -> self
648
*
649
* Insert or update key-value pairs.
650
*
651
* This method will work with any object which implements an each_pair
652
* method, such as a Hash.
653
*/
654
static
VALUE
655
fsdbm_update
(
VALUE
obj,
VALUE
other)
656
{
657
rb_block_call
(other,
rb_intern
(
"each_pair"
), 0, 0,
update_i
, obj);
658
return
obj;
659
}
660
661
/*
662
* call-seq:
663
* sdbm.replace(pairs) -> self
664
*
665
* Empties the database, then inserts the given key-value pairs.
666
*
667
* This method will work with any object which implements an each_pair
668
* method, such as a Hash.
669
*/
670
static
VALUE
671
fsdbm_replace
(
VALUE
obj,
VALUE
other)
672
{
673
fsdbm_clear
(obj);
674
rb_block_call
(other,
rb_intern
(
"each_pair"
), 0, 0,
update_i
, obj);
675
return
obj;
676
}
677
678
/*
679
* call-seq:
680
* sdbm.length -> integer
681
* sdbm.size -> integer
682
*
683
* Returns the number of keys in the database.
684
*/
685
static
VALUE
686
fsdbm_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 =
sdbm_firstkey
(dbm); key.
dptr
; key =
sdbm_nextkey
(dbm)) {
697
i++;
698
}
699
dbmp->
di_size
= i;
700
701
return
INT2FIX
(i);
702
}
703
704
/*
705
* call-seq:
706
* sdbm.empty? -> true or false
707
*
708
* Returns +true+ if the database is empty.
709
*/
710
static
VALUE
711
fsdbm_empty_p
(
VALUE
obj)
712
{
713
datum
key
;
714
struct
dbmdata
*dbmp;
715
DBM
*dbm;
716
717
GetDBM
(obj, dbmp);
718
if
(dbmp->
di_size
< 0) {
719
dbm = dbmp->
di_dbm
;
720
721
for
(key =
sdbm_firstkey
(dbm); key.
dptr
; key =
sdbm_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
* sdbm.each_value
735
* sdbm.each_value { |value| ... }
736
*
737
* Iterates over each +value+ in the database.
738
*
739
* If no block is given, returns an Enumerator.
740
*/
741
static
VALUE
742
fsdbm_each_value
(
VALUE
obj)
743
{
744
datum
key
,
val
;
745
struct
dbmdata
*dbmp;
746
DBM
*dbm;
747
748
RETURN_ENUMERATOR
(obj, 0, 0);
749
750
GetDBM2
(obj, dbmp, dbm);
751
for
(key =
sdbm_firstkey
(dbm); key.
dptr
; key =
sdbm_nextkey
(dbm)) {
752
val =
sdbm_fetch
(dbm, key);
753
rb_yield
(
rb_external_str_new
(val.
dptr
, val.
dsize
));
754
GetDBM2
(obj, dbmp, dbm);
755
}
756
return
obj;
757
}
758
759
/*
760
* call-seq:
761
* sdbm.each_key
762
* sdbm.each_key { |key| ... }
763
*
764
* Iterates over each +key+ in the database.
765
*
766
* If no block is given, returns an Enumerator.
767
*/
768
static
VALUE
769
fsdbm_each_key
(
VALUE
obj)
770
{
771
datum
key
;
772
struct
dbmdata
*dbmp;
773
DBM
*dbm;
774
775
RETURN_ENUMERATOR
(obj, 0, 0);
776
777
GetDBM2
(obj, dbmp, dbm);
778
for
(key =
sdbm_firstkey
(dbm); key.
dptr
; key =
sdbm_nextkey
(dbm)) {
779
rb_yield
(
rb_external_str_new
(key.
dptr
, key.
dsize
));
780
GetDBM2
(obj, dbmp, dbm);
781
}
782
return
obj;
783
}
784
785
/*
786
* call-seq:
787
* sdbm.each
788
* sdbm.each { |key, value| ... }
789
* sdbm.each_pair
790
* sdbm.each_pair { |key, value| ... }
791
*
792
* Iterates over each key-value pair in the database.
793
*
794
* If no block is given, returns an Enumerator.
795
*/
796
static
VALUE
797
fsdbm_each_pair
(
VALUE
obj)
798
{
799
datum
key
,
val
;
800
DBM
*dbm;
801
struct
dbmdata
*dbmp;
802
VALUE
keystr, valstr;
803
804
RETURN_ENUMERATOR
(obj, 0, 0);
805
806
GetDBM2
(obj, dbmp, dbm);
807
for
(key =
sdbm_firstkey
(dbm); key.
dptr
; key =
sdbm_nextkey
(dbm)) {
808
val =
sdbm_fetch
(dbm, key);
809
keystr =
rb_external_str_new
(key.
dptr
, key.
dsize
);
810
valstr =
rb_external_str_new
(val.
dptr
, val.
dsize
);
811
rb_yield
(
rb_assoc_new
(keystr, valstr));
812
GetDBM2
(obj, dbmp, dbm);
813
}
814
815
return
obj;
816
}
817
818
/*
819
* call-seq:
820
* sdbm.keys -> Array
821
*
822
* Returns a new Array containing the keys in the database.
823
*/
824
static
VALUE
825
fsdbm_keys
(
VALUE
obj)
826
{
827
datum
key
;
828
struct
dbmdata
*dbmp;
829
DBM
*dbm;
830
VALUE
ary;
831
832
GetDBM2
(obj, dbmp, dbm);
833
ary =
rb_ary_new
();
834
for
(key =
sdbm_firstkey
(dbm); key.
dptr
; key =
sdbm_nextkey
(dbm)) {
835
rb_ary_push
(ary,
rb_external_str_new
(key.
dptr
, key.
dsize
));
836
}
837
838
return
ary;
839
}
840
841
/*
842
* call-seq:
843
* sdbm.values -> Array
844
*
845
* Returns a new Array containing the values in the database.
846
*/
847
static
VALUE
848
fsdbm_values
(
VALUE
obj)
849
{
850
datum
key
,
val
;
851
struct
dbmdata
*dbmp;
852
DBM
*dbm;
853
VALUE
ary;
854
855
GetDBM2
(obj, dbmp, dbm);
856
ary =
rb_ary_new
();
857
for
(key =
sdbm_firstkey
(dbm); key.
dptr
; key =
sdbm_nextkey
(dbm)) {
858
val =
sdbm_fetch
(dbm, key);
859
rb_ary_push
(ary,
rb_external_str_new
(val.
dptr
, val.
dsize
));
860
}
861
862
return
ary;
863
}
864
865
/*
866
* call-seq:
867
* sdbm.include?(key) -> true or false
868
* sdbm.key?(key) -> true or false
869
* sdbm.member?(key) -> true or false
870
* sdbm.has_key?(key) -> true or false
871
*
872
* Returns +true+ if the database contains the given +key+.
873
*/
874
static
VALUE
875
fsdbm_has_key
(
VALUE
obj,
VALUE
keystr)
876
{
877
datum
key
,
val
;
878
struct
dbmdata
*dbmp;
879
DBM
*dbm;
880
881
ExportStringValue
(keystr);
882
key.
dptr
=
RSTRING_PTR
(keystr);
883
key.
dsize
=
RSTRING_LENINT
(keystr);
884
885
GetDBM2
(obj, dbmp, dbm);
886
val =
sdbm_fetch
(dbm, key);
887
if
(val.
dptr
)
return
Qtrue
;
888
return
Qfalse
;
889
}
890
891
/*
892
* call-seq:
893
* sdbm.value?(key) -> true or false
894
* sdbm.has_value?(key) -> true or false
895
*
896
* Returns +true+ if the database contains the given +value+.
897
*/
898
static
VALUE
899
fsdbm_has_value
(
VALUE
obj,
VALUE
valstr)
900
{
901
datum
key
,
val
;
902
struct
dbmdata
*dbmp;
903
DBM
*dbm;
904
905
ExportStringValue
(valstr);
906
val.
dptr
=
RSTRING_PTR
(valstr);
907
val.
dsize
=
RSTRING_LENINT
(valstr);
908
909
GetDBM2
(obj, dbmp, dbm);
910
for
(key =
sdbm_firstkey
(dbm); key.
dptr
; key =
sdbm_nextkey
(dbm)) {
911
val =
sdbm_fetch
(dbm, key);
912
if
(val.
dsize
==
RSTRING_LENINT
(valstr) &&
913
memcmp
(val.
dptr
,
RSTRING_PTR
(valstr), val.
dsize
) == 0)
914
return
Qtrue
;
915
}
916
return
Qfalse
;
917
}
918
919
/*
920
* call-seq:
921
* sdbm.to_a -> Array
922
*
923
* Returns a new Array containing each key-value pair in the database.
924
*
925
* Example:
926
*
927
* require 'sdbm'
928
*
929
* SDBM.open 'my_database' do |db|
930
* db.update('apple' => 'fruit', 'spinach' => 'vegetable')
931
*
932
* db.to_a #=> [["apple", "fruit"], ["spinach", "vegetable"]]
933
* end
934
*/
935
static
VALUE
936
fsdbm_to_a
(
VALUE
obj)
937
{
938
datum
key
,
val
;
939
struct
dbmdata
*dbmp;
940
DBM
*dbm;
941
VALUE
ary;
942
943
GetDBM2
(obj, dbmp, dbm);
944
ary =
rb_ary_new
();
945
for
(key =
sdbm_firstkey
(dbm); key.
dptr
; key =
sdbm_nextkey
(dbm)) {
946
val =
sdbm_fetch
(dbm, key);
947
rb_ary_push
(ary,
rb_assoc_new
(
rb_external_str_new
(key.
dptr
, key.
dsize
),
948
rb_external_str_new
(val.
dptr
, val.
dsize
)));
949
}
950
951
return
ary;
952
}
953
954
/*
955
* call-seq:
956
* sdbm.to_hash -> Hash
957
*
958
* Returns a new Hash containing each key-value pair in the database.
959
*/
960
static
VALUE
961
fsdbm_to_hash
(
VALUE
obj)
962
{
963
datum
key
,
val
;
964
struct
dbmdata
*dbmp;
965
DBM
*dbm;
966
VALUE
hash
;
967
968
GetDBM2
(obj, dbmp, dbm);
969
hash =
rb_hash_new
();
970
for
(key =
sdbm_firstkey
(dbm); key.
dptr
; key =
sdbm_nextkey
(dbm)) {
971
val =
sdbm_fetch
(dbm, key);
972
rb_hash_aset
(hash,
rb_external_str_new
(key.
dptr
, key.
dsize
),
973
rb_external_str_new
(val.
dptr
, val.
dsize
));
974
}
975
976
return
hash
;
977
}
978
979
/*
980
* call-seq:
981
* sdbm.reject { |key, value| ... } -> Hash
982
*
983
* Creates a new Hash using the key-value pairs from the database, then
984
* calls Hash#reject with the given block, which returns a Hash with
985
* only the key-value pairs for which the block returns +false+.
986
*/
987
static
VALUE
988
fsdbm_reject
(
VALUE
obj)
989
{
990
return
rb_hash_delete_if
(
fsdbm_to_hash
(obj));
991
}
992
993
void
994
Init_sdbm
()
995
{
996
rb_cDBM
=
rb_define_class
(
"SDBM"
,
rb_cObject
);
997
rb_eDBMError
=
rb_define_class
(
"SDBMError"
,
rb_eStandardError
);
998
/* Document-class: SDBMError
999
* Exception class used to return errors from the sdbm library.
1000
*/
1001
rb_include_module
(
rb_cDBM
,
rb_mEnumerable
);
1002
1003
rb_define_alloc_func
(
rb_cDBM
,
fsdbm_alloc
);
1004
rb_define_singleton_method
(
rb_cDBM
,
"open"
,
fsdbm_s_open
, -1);
1005
1006
rb_define_method
(
rb_cDBM
,
"initialize"
,
fsdbm_initialize
, -1);
1007
rb_define_method
(
rb_cDBM
,
"close"
,
fsdbm_close
, 0);
1008
rb_define_method
(
rb_cDBM
,
"closed?"
,
fsdbm_closed
, 0);
1009
rb_define_method
(
rb_cDBM
,
"[]"
,
fsdbm_aref
, 1);
1010
rb_define_method
(
rb_cDBM
,
"fetch"
,
fsdbm_fetch_m
, -1);
1011
rb_define_method
(
rb_cDBM
,
"[]="
,
fsdbm_store
, 2);
1012
rb_define_method
(
rb_cDBM
,
"store"
,
fsdbm_store
, 2);
1013
rb_define_method
(
rb_cDBM
,
"index"
,
fsdbm_index
, 1);
1014
rb_define_method
(
rb_cDBM
,
"key"
,
fsdbm_key
, 1);
1015
rb_define_method
(
rb_cDBM
,
"select"
,
fsdbm_select
, 0);
1016
rb_define_method
(
rb_cDBM
,
"values_at"
,
fsdbm_values_at
, -1);
1017
rb_define_method
(
rb_cDBM
,
"length"
,
fsdbm_length
, 0);
1018
rb_define_method
(
rb_cDBM
,
"size"
,
fsdbm_length
, 0);
1019
rb_define_method
(
rb_cDBM
,
"empty?"
,
fsdbm_empty_p
, 0);
1020
rb_define_method
(
rb_cDBM
,
"each"
,
fsdbm_each_pair
, 0);
1021
rb_define_method
(
rb_cDBM
,
"each_value"
,
fsdbm_each_value
, 0);
1022
rb_define_method
(
rb_cDBM
,
"each_key"
,
fsdbm_each_key
, 0);
1023
rb_define_method
(
rb_cDBM
,
"each_pair"
,
fsdbm_each_pair
, 0);
1024
rb_define_method
(
rb_cDBM
,
"keys"
,
fsdbm_keys
, 0);
1025
rb_define_method
(
rb_cDBM
,
"values"
,
fsdbm_values
, 0);
1026
rb_define_method
(
rb_cDBM
,
"shift"
,
fsdbm_shift
, 0);
1027
rb_define_method
(
rb_cDBM
,
"delete"
,
fsdbm_delete
, 1);
1028
rb_define_method
(
rb_cDBM
,
"delete_if"
,
fsdbm_delete_if
, 0);
1029
rb_define_method
(
rb_cDBM
,
"reject!"
,
fsdbm_delete_if
, 0);
1030
rb_define_method
(
rb_cDBM
,
"reject"
,
fsdbm_reject
, 0);
1031
rb_define_method
(
rb_cDBM
,
"clear"
,
fsdbm_clear
, 0);
1032
rb_define_method
(
rb_cDBM
,
"invert"
,
fsdbm_invert
, 0);
1033
rb_define_method
(
rb_cDBM
,
"update"
,
fsdbm_update
, 1);
1034
rb_define_method
(
rb_cDBM
,
"replace"
,
fsdbm_replace
, 1);
1035
1036
rb_define_method
(
rb_cDBM
,
"has_key?"
,
fsdbm_has_key
, 1);
1037
rb_define_method
(
rb_cDBM
,
"include?"
,
fsdbm_has_key
, 1);
1038
rb_define_method
(
rb_cDBM
,
"key?"
,
fsdbm_has_key
, 1);
1039
rb_define_method
(
rb_cDBM
,
"member?"
,
fsdbm_has_key
, 1);
1040
rb_define_method
(
rb_cDBM
,
"has_value?"
,
fsdbm_has_value
, 1);
1041
rb_define_method
(
rb_cDBM
,
"value?"
,
fsdbm_has_value
, 1);
1042
1043
rb_define_method
(
rb_cDBM
,
"to_a"
,
fsdbm_to_a
, 0);
1044
rb_define_method
(
rb_cDBM
,
"to_hash"
,
fsdbm_to_hash
, 0);
1045
}
1046
Generated on Mon Sep 22 2014 11:05:28 for Ruby by
1.8.2