Ruby 2.0.0p353(2013-11-22revision43784)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

init.c
Go to the documentation of this file.
1 /************************************************
2
3 sdbminit.c -
4
5 $Author: naruse $
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 rb_secure(4);
400 if (OBJ_FROZEN(obj)) rb_error_frozen("SDBM");
401 }
402
403 /*
404 * call-seq:
405 * sdbm.delete(key) -> value or nil
406 * sdbm.delete(key) { |key, value| ... }
407 *
408 * Deletes the key-value pair corresponding to the given +key+. If the
409 * +key+ exists, the deleted value will be returned, otherwise +nil+.
410 *
411 * If a block is provided, the deleted +key+ and +value+ will be passed to
412 * the block as arguments. If the +key+ does not exist in the database, the
413 * value will be +nil+.
414 */
415 static VALUE
416 fsdbm_delete(VALUE obj, VALUE keystr)
417 {
418 datum key, value;
419 struct dbmdata *dbmp;
420 DBM *dbm;
421 VALUE valstr;
422
423 fdbm_modify(obj);
424 ExportStringValue(keystr);
425 key.dptr = RSTRING_PTR(keystr);
426 key.dsize = RSTRING_LENINT(keystr);
427
428 GetDBM2(obj, dbmp, dbm);
429 dbmp->di_size = -1;
430
431 value = sdbm_fetch(dbm, key);
432 if (value.dptr == 0) {
433 if (rb_block_given_p()) return rb_yield(keystr);
434 return Qnil;
435 }
436
437 /* need to save value before sdbm_delete() */
438 valstr = rb_external_str_new(value.dptr, value.dsize);
439
440 if (sdbm_delete(dbm, key)) {
441 dbmp->di_size = -1;
442 rb_raise(rb_eDBMError, "dbm_delete failed");
443 }
444 else if (dbmp->di_size >= 0) {
445 dbmp->di_size--;
446 }
447 return valstr;
448 }
449
450 /*
451 * call-seq:
452 * sdbm.shift -> Array or nil
453 *
454 * Removes a key-value pair from the database and returns them as an
455 * Array. If the database is empty, returns +nil+.
456 */
457 static VALUE
458 fsdbm_shift(VALUE obj)
459 {
460 datum key, val;
461 struct dbmdata *dbmp;
462 DBM *dbm;
463 VALUE keystr, valstr;
464
465 fdbm_modify(obj);
466 GetDBM2(obj, dbmp, dbm);
467 key = sdbm_firstkey(dbm);
468 if (!key.dptr) return Qnil;
469 val = sdbm_fetch(dbm, key);
470 keystr = rb_external_str_new(key.dptr, key.dsize);
471 valstr = rb_external_str_new(val.dptr, val.dsize);
472 sdbm_delete(dbm, key);
473 if (dbmp->di_size >= 0) {
474 dbmp->di_size--;
475 }
476
477 return rb_assoc_new(keystr, valstr);
478 }
479
480 /*
481 * call-seq:
482 * sdbm.delete_if { |key, value| ... } -> self
483 * sdbm.reject! { |key, value| ... } -> self
484 *
485 * Iterates over the key-value pairs in the database, deleting those for
486 * which the block returns +true+.
487 */
488 static VALUE
489 fsdbm_delete_if(VALUE obj)
490 {
491 datum key, val;
492 struct dbmdata *dbmp;
493 DBM *dbm;
494 VALUE keystr, valstr;
495 VALUE ret, ary = rb_ary_new();
496 int i, status = 0, n;
497
498 fdbm_modify(obj);
499 GetDBM2(obj, dbmp, dbm);
500 n = dbmp->di_size;
501 dbmp->di_size = -1;
502 for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) {
503 val = sdbm_fetch(dbm, key);
504 keystr = rb_external_str_new(key.dptr, key.dsize);
505 valstr = rb_external_str_new(val.dptr, val.dsize);
506 ret = rb_protect(rb_yield, rb_assoc_new(rb_str_dup(keystr), valstr), &status);
507 if (status != 0) break;
508 if (RTEST(ret)) rb_ary_push(ary, keystr);
509 GetDBM2(obj, dbmp, dbm);
510 }
511
512 for (i = 0; i < RARRAY_LEN(ary); i++) {
513 keystr = RARRAY_PTR(ary)[i];
514 ExportStringValue(keystr);
515 key.dptr = RSTRING_PTR(keystr);
516 key.dsize = RSTRING_LENINT(keystr);
517 if (sdbm_delete(dbm, key)) {
518 rb_raise(rb_eDBMError, "sdbm_delete failed");
519 }
520 }
521 if (status) rb_jump_tag(status);
522 if (n > 0) dbmp->di_size = n - RARRAY_LENINT(ary);
523
524 return obj;
525 }
526
527 /*
528 * call-seq:
529 * sdbm.clear -> self
530 *
531 * Deletes all data from the database.
532 */
533 static VALUE
534 fsdbm_clear(VALUE obj)
535 {
536 datum key;
537 struct dbmdata *dbmp;
538 DBM *dbm;
539
540 fdbm_modify(obj);
541 GetDBM2(obj, dbmp, dbm);
542 dbmp->di_size = -1;
543 while (key = sdbm_firstkey(dbm), key.dptr) {
544 if (sdbm_delete(dbm, key)) {
545 rb_raise(rb_eDBMError, "sdbm_delete failed");
546 }
547 }
548 dbmp->di_size = 0;
549
550 return obj;
551 }
552
553 /*
554 * call-seq:
555 * sdbm.invert -> Hash
556 *
557 * Returns a Hash in which the key-value pairs have been inverted.
558 *
559 * Example:
560 *
561 * require 'sdbm'
562 *
563 * SDBM.open 'my_database' do |db|
564 * db.update('apple' => 'fruit', 'spinach' => 'vegetable')
565 *
566 * db.invert #=> {"fruit" => "apple", "vegetable" => "spinach"}
567 * end
568 */
569 static VALUE
570 fsdbm_invert(VALUE obj)
571 {
572 datum key, val;
573 struct dbmdata *dbmp;
574 DBM *dbm;
575 VALUE keystr, valstr;
576 VALUE hash = rb_hash_new();
577
578 GetDBM2(obj, dbmp, dbm);
579 for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) {
580 val = sdbm_fetch(dbm, key);
581 keystr = rb_external_str_new(key.dptr, key.dsize);
582 valstr = rb_external_str_new(val.dptr, val.dsize);
583 rb_hash_aset(hash, valstr, keystr);
584 }
585 return hash;
586 }
587
588 /*
589 * call-seq:
590 * sdbm[key] = value -> value
591 * sdbm.store(key, value) -> value
592 *
593 * Stores a new +value+ in the database with the given +key+ as an index.
594 *
595 * If the +key+ already exists, this will update the +value+ associated with
596 * the +key+.
597 *
598 * Returns the given +value+.
599 */
600 static VALUE
601 fsdbm_store(VALUE obj, VALUE keystr, VALUE valstr)
602 {
603 datum key, val;
604 struct dbmdata *dbmp;
605 DBM *dbm;
606
607 if (valstr == Qnil) {
608 fsdbm_delete(obj, keystr);
609 return Qnil;
610 }
611
612 fdbm_modify(obj);
613 ExportStringValue(keystr);
614 ExportStringValue(valstr);
615
616 key.dptr = RSTRING_PTR(keystr);
617 key.dsize = RSTRING_LENINT(keystr);
618
619 val.dptr = RSTRING_PTR(valstr);
620 val.dsize = RSTRING_LENINT(valstr);
621
622 GetDBM2(obj, dbmp, dbm);
623 dbmp->di_size = -1;
624 if (sdbm_store(dbm, key, val, DBM_REPLACE)) {
625 #ifdef HAVE_DBM_CLAERERR
626 sdbm_clearerr(dbm);
627 #endif
628 if (errno == EPERM) rb_sys_fail(0);
629 rb_raise(rb_eDBMError, "sdbm_store failed");
630 }
631
632 return valstr;
633 }
634
635 static VALUE
636 update_i(VALUE pair, VALUE dbm)
637 {
638 Check_Type(pair, T_ARRAY);
639 if (RARRAY_LEN(pair) < 2) {
640 rb_raise(rb_eArgError, "pair must be [key, value]");
641 }
642 fsdbm_store(dbm, RARRAY_PTR(pair)[0], RARRAY_PTR(pair)[1]);
643 return Qnil;
644 }
645
646 /*
647 * call-seq:
648 * sdbm.update(pairs) -> self
649 *
650 * Insert or update key-value pairs.
651 *
652 * This method will work with any object which implements an each_pair
653 * method, such as a Hash.
654 */
655 static VALUE
656 fsdbm_update(VALUE obj, VALUE other)
657 {
658 rb_block_call(other, rb_intern("each_pair"), 0, 0, update_i, obj);
659 return obj;
660 }
661
662 /*
663 * call-seq:
664 * sdbm.replace(pairs) -> self
665 *
666 * Empties the database, then inserts the given key-value pairs.
667 *
668 * This method will work with any object which implements an each_pair
669 * method, such as a Hash.
670 */
671 static VALUE
672 fsdbm_replace(VALUE obj, VALUE other)
673 {
674 fsdbm_clear(obj);
675 rb_block_call(other, rb_intern("each_pair"), 0, 0, update_i, obj);
676 return obj;
677 }
678
679 /*
680 * call-seq:
681 * sdbm.length -> integer
682 * sdbm.size -> integer
683 *
684 * Returns the number of keys in the database.
685 */
686 static VALUE
687 fsdbm_length(VALUE obj)
688 {
689 datum key;
690 struct dbmdata *dbmp;
691 DBM *dbm;
692 int i = 0;
693
694 GetDBM2(obj, dbmp, dbm);
695 if (dbmp->di_size > 0) return INT2FIX(dbmp->di_size);
696
697 for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) {
698 i++;
699 }
700 dbmp->di_size = i;
701
702 return INT2FIX(i);
703 }
704
705 /*
706 * call-seq:
707 * sdbm.empty? -> true or false
708 *
709 * Returns +true+ if the database is empty.
710 */
711 static VALUE
712 fsdbm_empty_p(VALUE obj)
713 {
714 datum key;
715 struct dbmdata *dbmp;
716 DBM *dbm;
717
718 GetDBM(obj, dbmp);
719 if (dbmp->di_size < 0) {
720 dbm = dbmp->di_dbm;
721
722 for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) {
723 return Qfalse;
724 }
725 }
726 else {
727 if (dbmp->di_size)
728 return Qfalse;
729 }
730 return Qtrue;
731 }
732
733 /*
734 * call-seq:
735 * sdbm.each_value
736 * sdbm.each_value { |value| ... }
737 *
738 * Iterates over each +value+ in the database.
739 *
740 * If no block is given, returns an Enumerator.
741 */
742 static VALUE
743 fsdbm_each_value(VALUE obj)
744 {
745 datum key, val;
746 struct dbmdata *dbmp;
747 DBM *dbm;
748
749 RETURN_ENUMERATOR(obj, 0, 0);
750
751 GetDBM2(obj, dbmp, dbm);
752 for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) {
753 val = sdbm_fetch(dbm, key);
754 rb_yield(rb_external_str_new(val.dptr, val.dsize));
755 GetDBM2(obj, dbmp, dbm);
756 }
757 return obj;
758 }
759
760 /*
761 * call-seq:
762 * sdbm.each_key
763 * sdbm.each_key { |key| ... }
764 *
765 * Iterates over each +key+ in the database.
766 *
767 * If no block is given, returns an Enumerator.
768 */
769 static VALUE
770 fsdbm_each_key(VALUE obj)
771 {
772 datum key;
773 struct dbmdata *dbmp;
774 DBM *dbm;
775
776 RETURN_ENUMERATOR(obj, 0, 0);
777
778 GetDBM2(obj, dbmp, dbm);
779 for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) {
780 rb_yield(rb_external_str_new(key.dptr, key.dsize));
781 GetDBM2(obj, dbmp, dbm);
782 }
783 return obj;
784 }
785
786 /*
787 * call-seq:
788 * sdbm.each
789 * sdbm.each { |key, value| ... }
790 * sdbm.each_pair
791 * sdbm.each_pair { |key, value| ... }
792 *
793 * Iterates over each key-value pair in the database.
794 *
795 * If no block is given, returns an Enumerator.
796 */
797 static VALUE
798 fsdbm_each_pair(VALUE obj)
799 {
800 datum key, val;
801 DBM *dbm;
802 struct dbmdata *dbmp;
803 VALUE keystr, valstr;
804
805 RETURN_ENUMERATOR(obj, 0, 0);
806
807 GetDBM2(obj, dbmp, dbm);
808 for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) {
809 val = sdbm_fetch(dbm, key);
810 keystr = rb_external_str_new(key.dptr, key.dsize);
811 valstr = rb_external_str_new(val.dptr, val.dsize);
812 rb_yield(rb_assoc_new(keystr, valstr));
813 GetDBM2(obj, dbmp, dbm);
814 }
815
816 return obj;
817 }
818
819 /*
820 * call-seq:
821 * sdbm.keys -> Array
822 *
823 * Returns a new Array containing the keys in the database.
824 */
825 static VALUE
826 fsdbm_keys(VALUE obj)
827 {
828 datum key;
829 struct dbmdata *dbmp;
830 DBM *dbm;
831 VALUE ary;
832
833 GetDBM2(obj, dbmp, dbm);
834 ary = rb_ary_new();
835 for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) {
836 rb_ary_push(ary, rb_external_str_new(key.dptr, key.dsize));
837 }
838
839 return ary;
840 }
841
842 /*
843 * call-seq:
844 * sdbm.values -> Array
845 *
846 * Returns a new Array containing the values in the database.
847 */
848 static VALUE
849 fsdbm_values(VALUE obj)
850 {
851 datum key, val;
852 struct dbmdata *dbmp;
853 DBM *dbm;
854 VALUE ary;
855
856 GetDBM2(obj, dbmp, dbm);
857 ary = rb_ary_new();
858 for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) {
859 val = sdbm_fetch(dbm, key);
860 rb_ary_push(ary, rb_external_str_new(val.dptr, val.dsize));
861 }
862
863 return ary;
864 }
865
866 /*
867 * call-seq:
868 * sdbm.include?(key) -> true or false
869 * sdbm.key?(key) -> true or false
870 * sdbm.member?(key) -> true or false
871 * sdbm.has_key?(key) -> true or false
872 *
873 * Returns +true+ if the database contains the given +key+.
874 */
875 static VALUE
876 fsdbm_has_key(VALUE obj, VALUE keystr)
877 {
878 datum key, val;
879 struct dbmdata *dbmp;
880 DBM *dbm;
881
882 ExportStringValue(keystr);
883 key.dptr = RSTRING_PTR(keystr);
884 key.dsize = RSTRING_LENINT(keystr);
885
886 GetDBM2(obj, dbmp, dbm);
887 val = sdbm_fetch(dbm, key);
888 if (val.dptr) return Qtrue;
889 return Qfalse;
890 }
891
892 /*
893 * call-seq:
894 * sdbm.value?(key) -> true or false
895 * sdbm.has_value?(key) -> true or false
896 *
897 * Returns +true+ if the database contains the given +value+.
898 */
899 static VALUE
900 fsdbm_has_value(VALUE obj, VALUE valstr)
901 {
902 datum key, val;
903 struct dbmdata *dbmp;
904 DBM *dbm;
905
906 ExportStringValue(valstr);
907 val.dptr = RSTRING_PTR(valstr);
908 val.dsize = RSTRING_LENINT(valstr);
909
910 GetDBM2(obj, dbmp, dbm);
911 for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) {
912 val = sdbm_fetch(dbm, key);
913 if (val.dsize == RSTRING_LENINT(valstr) &&
914 memcmp(val.dptr, RSTRING_PTR(valstr), val.dsize) == 0)
915 return Qtrue;
916 }
917 return Qfalse;
918 }
919
920 /*
921 * call-seq:
922 * sdbm.to_a -> Array
923 *
924 * Returns a new Array containing each key-value pair in the database.
925 *
926 * Example:
927 *
928 * require 'sdbm'
929 *
930 * SDBM.open 'my_database' do |db|
931 * db.update('apple' => 'fruit', 'spinach' => 'vegetable')
932 *
933 * db.to_a #=> [["apple", "fruit"], ["spinach", "vegetable"]]
934 * end
935 */
936 static VALUE
937 fsdbm_to_a(VALUE obj)
938 {
939 datum key, val;
940 struct dbmdata *dbmp;
941 DBM *dbm;
942 VALUE ary;
943
944 GetDBM2(obj, dbmp, dbm);
945 ary = rb_ary_new();
946 for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) {
947 val = sdbm_fetch(dbm, key);
948 rb_ary_push(ary, rb_assoc_new(rb_external_str_new(key.dptr, key.dsize),
949 rb_external_str_new(val.dptr, val.dsize)));
950 }
951
952 return ary;
953 }
954
955 /*
956 * call-seq:
957 * sdbm.to_hash -> Hash
958 *
959 * Returns a new Hash containing each key-value pair in the database.
960 */
961 static VALUE
962 fsdbm_to_hash(VALUE obj)
963 {
964 datum key, val;
965 struct dbmdata *dbmp;
966 DBM *dbm;
967 VALUE hash;
968
969 GetDBM2(obj, dbmp, dbm);
970 hash = rb_hash_new();
971 for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) {
972 val = sdbm_fetch(dbm, key);
973 rb_hash_aset(hash, rb_external_str_new(key.dptr, key.dsize),
974 rb_external_str_new(val.dptr, val.dsize));
975 }
976
977 return hash;
978 }
979
980 /*
981 * call-seq:
982 * sdbm.reject { |key, value| ... } -> Hash
983 *
984 * Creates a new Hash using the key-value pairs from the database, then
985 * calls Hash#reject with the given block, which returns a Hash with
986 * only the key-value pairs for which the block returns +false+.
987 */
988 static VALUE
989 fsdbm_reject(VALUE obj)
990 {
991 return rb_hash_delete_if(fsdbm_to_hash(obj));
992 }
993
994 void
995 Init_sdbm()
996 {
997 rb_cDBM = rb_define_class("SDBM", rb_cObject);
998 rb_eDBMError = rb_define_class("SDBMError", rb_eStandardError);
999 /* Document-class: SDBMError
1000 * Exception class used to return errors from the sdbm library.
1001 */
1002 rb_include_module(rb_cDBM, rb_mEnumerable);
1003
1004 rb_define_alloc_func(rb_cDBM, fsdbm_alloc);
1005 rb_define_singleton_method(rb_cDBM, "open", fsdbm_s_open, -1);
1006
1007 rb_define_method(rb_cDBM, "initialize", fsdbm_initialize, -1);
1008 rb_define_method(rb_cDBM, "close", fsdbm_close, 0);
1009 rb_define_method(rb_cDBM, "closed?", fsdbm_closed, 0);
1010 rb_define_method(rb_cDBM, "[]", fsdbm_aref, 1);
1011 rb_define_method(rb_cDBM, "fetch", fsdbm_fetch_m, -1);
1012 rb_define_method(rb_cDBM, "[]=", fsdbm_store, 2);
1013 rb_define_method(rb_cDBM, "store", fsdbm_store, 2);
1014 rb_define_method(rb_cDBM, "index", fsdbm_index, 1);
1015 rb_define_method(rb_cDBM, "key", fsdbm_key, 1);
1016 rb_define_method(rb_cDBM, "select", fsdbm_select, 0);
1017 rb_define_method(rb_cDBM, "values_at", fsdbm_values_at, -1);
1018 rb_define_method(rb_cDBM, "length", fsdbm_length, 0);
1019 rb_define_method(rb_cDBM, "size", fsdbm_length, 0);
1020 rb_define_method(rb_cDBM, "empty?", fsdbm_empty_p, 0);
1021 rb_define_method(rb_cDBM, "each", fsdbm_each_pair, 0);
1022 rb_define_method(rb_cDBM, "each_value", fsdbm_each_value, 0);
1023 rb_define_method(rb_cDBM, "each_key", fsdbm_each_key, 0);
1024 rb_define_method(rb_cDBM, "each_pair", fsdbm_each_pair, 0);
1025 rb_define_method(rb_cDBM, "keys", fsdbm_keys, 0);
1026 rb_define_method(rb_cDBM, "values", fsdbm_values, 0);
1027 rb_define_method(rb_cDBM, "shift", fsdbm_shift, 0);
1028 rb_define_method(rb_cDBM, "delete", fsdbm_delete, 1);
1029 rb_define_method(rb_cDBM, "delete_if", fsdbm_delete_if, 0);
1030 rb_define_method(rb_cDBM, "reject!", fsdbm_delete_if, 0);
1031 rb_define_method(rb_cDBM, "reject", fsdbm_reject, 0);
1032 rb_define_method(rb_cDBM, "clear", fsdbm_clear, 0);
1033 rb_define_method(rb_cDBM,"invert", fsdbm_invert, 0);
1034 rb_define_method(rb_cDBM,"update", fsdbm_update, 1);
1035 rb_define_method(rb_cDBM,"replace", fsdbm_replace, 1);
1036
1037 rb_define_method(rb_cDBM, "has_key?", fsdbm_has_key, 1);
1038 rb_define_method(rb_cDBM, "include?", fsdbm_has_key, 1);
1039 rb_define_method(rb_cDBM, "key?", fsdbm_has_key, 1);
1040 rb_define_method(rb_cDBM, "member?", fsdbm_has_key, 1);
1041 rb_define_method(rb_cDBM, "has_value?", fsdbm_has_value, 1);
1042 rb_define_method(rb_cDBM, "value?", fsdbm_has_value, 1);
1043
1044 rb_define_method(rb_cDBM, "to_a", fsdbm_to_a, 0);
1045 rb_define_method(rb_cDBM, "to_hash", fsdbm_to_hash, 0);
1046 }
RARRAY_PTR
RARRAY_PTR(q->result)[0]
dbmdata::di_dbm
DBM * di_dbm
Definition: dbm.c:39
ALLOC
#define ALLOC(type)
rb_eStandardError
VALUE rb_eStandardError
Definition: error.c:509
FilePathValue
#define FilePathValue(v)
n
ssize_t n
Definition: bigdecimal.c:5655
fsdbm_reject
static VALUE fsdbm_reject(VALUE obj)
Definition: init.c:989
ary
volatile VALUE ary
Definition: tcltklib.c:9713
fsdbm_clear
static VALUE fsdbm_clear(VALUE obj)
Definition: init.c:534
fsdbm_to_a
static VALUE fsdbm_to_a(VALUE obj)
Definition: init.c:937
fsdbm_key
static VALUE fsdbm_key(VALUE obj, VALUE valstr)
Definition: init.c:305
pair
volatile VALUE pair
Definition: tkutil.c:554
rb_define_singleton_method
void rb_define_singleton_method(VALUE obj, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a singleton method for obj.
Definition: class.c:1497
rb_secure
void rb_secure(int)
Definition: safe.c:79
i
ssize_t i
Definition: bigdecimal.c:5655
rb_error_frozen
void rb_error_frozen(const char *what)
Definition: error.c:1972
fsdbm_each_value
static VALUE fsdbm_each_value(VALUE obj)
Definition: init.c:743
fsdbm_alloc
static VALUE fsdbm_alloc(VALUE klass)
Definition: init.c:140
fsdbm_has_key
static VALUE fsdbm_has_key(VALUE obj, VALUE keystr)
Definition: init.c:876
ruby.h
ret
int ret
Definition: tcltklib.c:280
status
int status
Definition: tcltklib.c:2197
rb_define_alloc_func
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
rb_ary_push
VALUE rb_ary_push(VALUE ary, VALUE item)
Definition: array.c:822
dbmdata::di_size
long di_size
Definition: dbm.c:38
RSTRING_PTR
#define RSTRING_PTR(str)
NIL_P
NIL_P(eventloop_thread)
Definition: tcltklib.c:4068
T_ARRAY
#define T_ARRAY
rb_protect
VALUE rb_protect(VALUE(*proc)(VALUE), VALUE data, int *state)
Definition: eval.c:771
free_sdbm
static void free_sdbm(struct dbmdata *dbmp)
Definition: init.c:92
rb_raise
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:1780
Qtrue
return Qtrue
Definition: tcltklib.c:9610
RETURN_ENUMERATOR
#define RETURN_ENUMERATOR(obj, argc, argv)
fsdbm_update
static VALUE fsdbm_update(VALUE obj, VALUE other)
Definition: init.c:656
rb_external_str_new
VALUE rb_external_str_new(const char *, long)
Definition: string.c:584
dbmdata
Definition: dbm.c:37
fsdbm_values_at
static VALUE fsdbm_values_at(int argc, VALUE *argv, VALUE obj)
Definition: init.c:384
rb_include_module
void rb_include_module(VALUE klass, VALUE module)
Definition: class.c:695
datum::dptr
char * dptr
Definition: sdbm.h:51
fsdbm_invert
static VALUE fsdbm_invert(VALUE obj)
Definition: init.c:570
fsdbm_closed
static VALUE fsdbm_closed(VALUE obj)
Definition: init.c:126
fsdbm_values
static VALUE fsdbm_values(VALUE obj)
Definition: init.c:849
rb_eDBMError
static VALUE rb_eDBMError
Definition: init.c:67
fsdbm_replace
static VALUE fsdbm_replace(VALUE obj, VALUE other)
Definition: init.c:672
hash
VALUE hash
Definition: tkutil.c:267
sdbm_close
void sdbm_close(register DBM *db)
Definition: _sdbm.c:266
fsdbm_shift
static VALUE fsdbm_shift(VALUE obj)
Definition: init.c:458
GetDBM2
#define GetDBM2(obj, data, dbm)
Definition: init.c:86
Data_Wrap_Struct
return Data_Wrap_Struct(CLASS_OF(interp), 0, ip_free, slave)
sdbm_open
DBM * sdbm_open(register char *file, register int flags, register int mode)
Definition: _sdbm.c:149
fdbm_modify
static void fdbm_modify(VALUE obj)
Definition: init.c:397
Qfalse
return Qfalse
Definition: tcltklib.c:6779
fsdbm_empty_p
static VALUE fsdbm_empty_p(VALUE obj)
Definition: init.c:712
datum
Definition: sdbm.h:50
rb_block_given_p
int rb_block_given_p(void)
Definition: eval.c:672
DBM_REPLACE
#define DBM_REPLACE
Definition: sdbm.h:67
RARRAY_LEN
#define RARRAY_LEN(a)
Qnil
#define Qnil
Definition: tcltklib.c:1896
val
#define val
Definition: tcltklib.c:1949
fsdbm_aref
static VALUE fsdbm_aref(VALUE obj, VALUE keystr)
Definition: init.c:264
rb_ary_new
VALUE rb_ary_new(void)
Definition: array.c:424
Check_Type
#define Check_Type(v, t)
rb_define_class
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition: class.c:499
sdbm_firstkey
datum sdbm_firstkey(register DBM *db)
Definition: _sdbm.c:469
obj
static VALUE VALUE obj
Definition: tcltklib.c:3158
RSTRING_LEN
#define RSTRING_LEN(str)
fsdbm_delete
static VALUE fsdbm_delete(VALUE obj, VALUE keystr)
Definition: init.c:416
INT2FIX
#define INT2FIX(i)
fsdbm_each_pair
static VALUE fsdbm_each_pair(VALUE obj)
Definition: init.c:798
rb_sys_fail_str
void rb_sys_fail_str(VALUE mesg)
Definition: error.c:1905
fsdbm_delete_if
static VALUE fsdbm_delete_if(VALUE obj)
Definition: init.c:489
assoc
static VALUE VALUE assoc
Definition: tkutil.c:545
closed_sdbm
static void closed_sdbm()
Definition: init.c:75
rb_eIndexError
VALUE rb_eIndexError
Definition: error.c:513
key
static int VALUE key
Definition: tkutil.c:265
fsdbm_initialize
static VALUE fsdbm_initialize(int argc, VALUE *argv, VALUE obj)
Definition: init.c:160
rb_str_dup
VALUE rb_str_dup(VALUE)
Definition: string.c:946
ExportStringValue
#define ExportStringValue(v)
argv
VALUE * argv
Definition: tcltklib.c:1971
rb_hash_aset
VALUE rb_hash_aset(VALUE, VALUE, VALUE)
rb_yield
VALUE rb_yield(VALUE)
Definition: vm_eval.c:934
RTEST
#define RTEST(v)
Init_sdbm
void Init_sdbm()
Definition: init.c:995
errno
int errno
rb_mEnumerable
VALUE rb_mEnumerable
Definition: enum.c:20
value
volatile VALUE value
Definition: tcltklib.c:9442
DBM
Definition: sdbm.h:20
ruby_xfree
void ruby_xfree(void *x)
Definition: gc.c:3651
mode
VALUE mode
Definition: tcltklib.c:1664
rb_scan_args
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:1570
rb_block_call
VALUE rb_block_call(VALUE, ID, int, VALUE *, VALUE(*)(ANYARGS), VALUE)
Definition: vm_eval.c:1131
rb_assoc_new
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Definition: array.c:545
OBJ_FROZEN
#define OBJ_FROZEN(x)
datum::dsize
int dsize
Definition: sdbm.h:52
argc
int argc
Definition: tcltklib.c:1970
fsdbm_length
static VALUE fsdbm_length(VALUE obj)
Definition: init.c:687
EPERM
#define EPERM
Definition: _sdbm.c:94
rb_ensure
VALUE rb_ensure(VALUE(*b_proc)(ANYARGS), VALUE data1, VALUE(*e_proc)(ANYARGS), VALUE data2)
Definition: eval.c:804
memcmp
int memcmp(const void *s1, const void *s2, size_t len)
Definition: memcmp.c:7
sdbm_clearerr
#define sdbm_clearerr(db)
Definition: sdbm.h:45
rb_sys_fail
void rb_sys_fail(const char *mesg)
Definition: error.c:1899
rb_jump_tag
void rb_jump_tag(int tag)
Definition: eval.c:666
fsdbm_to_hash
static VALUE fsdbm_to_hash(VALUE obj)
Definition: init.c:962
fsdbm_store
static VALUE fsdbm_store(VALUE obj, VALUE keystr, VALUE valstr)
Definition: init.c:601
sdbm_store
int sdbm_store(register DBM *db, datum key, datum val, int flags)
Definition: _sdbm.c:314
rb_cDBM
static VALUE rb_cDBM
Definition: init.c:67
GetDBM
#define GetDBM(obj, dbmp)
Definition: init.c:80
DATA_PTR
DATA_PTR(self)
rb_cObject
RUBY_EXTERN VALUE rb_cObject
Definition: ripper.y:1426
fsdbm_fetch
static VALUE fsdbm_fetch(VALUE obj, VALUE keystr, VALUE ifnone)
Definition: init.c:235
RARRAY_LENINT
#define RARRAY_LENINT(ary)
fsdbm_s_open
static VALUE fsdbm_s_open(int argc, VALUE *argv, VALUE klass)
Definition: init.c:219
klass
klass
Definition: tcltklib.c:3504
fsdbm_each_key
static VALUE fsdbm_each_key(VALUE obj)
Definition: init.c:770
sdbm.h
Data_Get_Struct
#define Data_Get_Struct(obj, type, sval)
RSTRING_LENINT
#define RSTRING_LENINT(str)
sdbm_nextkey
datum sdbm_nextkey(register DBM *db)
Definition: _sdbm.c:488
rb_ary_new2
VALUE rb_ary_new2(long capa)
Definition: array.c:417
fsdbm_has_value
static VALUE fsdbm_has_value(VALUE obj, VALUE valstr)
Definition: init.c:900
rb_hash_delete_if
VALUE rb_hash_delete_if(VALUE)
Definition: hash.c:959
update_i
static VALUE update_i(VALUE pair, VALUE dbm)
Definition: init.c:636
NUM2INT
#define NUM2INT(x)
rb_hash_new
VALUE rb_hash_new(void)
Definition: hash.c:234
fsdbm_fetch_m
static VALUE fsdbm_fetch_m(int argc, VALUE *argv, VALUE obj)
Definition: init.c:284
VALUE
unsigned long VALUE
Definition: ripper.y:104
fsdbm_index
static VALUE fsdbm_index(VALUE hash, VALUE value)
Definition: init.c:329
sdbm_delete
int sdbm_delete(register DBM *db, datum key)
Definition: _sdbm.c:290
fsdbm_select
static VALUE fsdbm_select(VALUE obj)
Definition: init.c:355
sdbm_fetch
datum sdbm_fetch(register DBM *db, datum key)
Definition: _sdbm.c:278
fsdbm_close
static VALUE fsdbm_close(VALUE obj)
Definition: init.c:108
rb_intern
#define rb_intern(str)
v
BDIGIT v
Definition: bigdecimal.c:5656
rb_define_method
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1344
rb_warn
void rb_warn(const char *fmt,...)
Definition: error.c:216
rb_eArgError
VALUE rb_eArgError
Definition: error.c:512
fsdbm_keys
static VALUE fsdbm_keys(VALUE obj)
Definition: init.c:826