Ruby 2.1.5p273(2014-11-13revision48405)

- 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: 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 }
dbmdata::di_dbm
DBM * di_dbm
Definition: dbm.c:39
rb_eStandardError
VALUE rb_eStandardError
Definition: error.c:546
fsdbm_reject
static VALUE fsdbm_reject(VALUE obj)
Definition: init.c:988
RARRAY_LEN
#define RARRAY_LEN(a)
Definition: ruby.h:878
fsdbm_clear
static VALUE fsdbm_clear(VALUE obj)
Definition: init.c:533
fsdbm_to_a
static VALUE fsdbm_to_a(VALUE obj)
Definition: init.c:936
NUM2INT
#define NUM2INT(x)
Definition: ruby.h:630
fsdbm_key
static VALUE fsdbm_key(VALUE obj, VALUE valstr)
Definition: init.c:305
Data_Get_Struct
#define Data_Get_Struct(obj, type, sval)
Definition: ruby.h:1036
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:1655
FilePathValue
#define FilePathValue(v)
Definition: ruby.h:560
Qtrue
#define Qtrue
Definition: ruby.h:426
rb_error_frozen
void rb_error_frozen(const char *what)
Definition: error.c:2077
fsdbm_each_value
static VALUE fsdbm_each_value(VALUE obj)
Definition: init.c:742
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:875
ruby.h
rb_ary_push
VALUE rb_ary_push(VALUE ary, VALUE item)
Definition: array.c:896
dbmdata::di_size
long di_size
Definition: dbm.c:38
rb_protect
VALUE rb_protect(VALUE(*proc)(VALUE), VALUE data, int *state)
Definition: eval.c:807
free_sdbm
static void free_sdbm(struct dbmdata *dbmp)
Definition: init.c:92
Check_Type
#define Check_Type(v, t)
Definition: ruby.h:532
rb_raise
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:1857
fsdbm_update
static VALUE fsdbm_update(VALUE obj, VALUE other)
Definition: init.c:655
rb_define_alloc_func
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
dbmdata
Definition: dbm.c:37
fsdbm_values_at
static VALUE fsdbm_values_at(int argc, VALUE *argv, VALUE obj)
Definition: init.c:384
DATA_PTR
#define DATA_PTR(dta)
Definition: ruby.h:992
rb_include_module
void rb_include_module(VALUE klass, VALUE module)
Definition: class.c:827
datum::dptr
char * dptr
Definition: sdbm.h:51
rb_block_call
VALUE rb_block_call(VALUE, ID, int, const VALUE *, rb_block_call_func_t, VALUE)
T_ARRAY
#define T_ARRAY
Definition: ruby.h:484
fsdbm_invert
static VALUE fsdbm_invert(VALUE obj)
Definition: init.c:569
fsdbm_closed
static VALUE fsdbm_closed(VALUE obj)
Definition: init.c:126
fsdbm_values
static VALUE fsdbm_values(VALUE obj)
Definition: init.c:848
rb_eDBMError
static VALUE rb_eDBMError
Definition: init.c:67
rb_ary_new2
#define rb_ary_new2
Definition: intern.h:90
update_i
static VALUE update_i(RB_BLOCK_CALL_FUNC_ARGLIST(pair, dbm))
Definition: init.c:635
fsdbm_replace
static VALUE fsdbm_replace(VALUE obj, VALUE other)
Definition: init.c:671
Data_Wrap_Struct
#define Data_Wrap_Struct(klass, mark, free, sval)
Definition: ruby.h:1018
RB_BLOCK_CALL_FUNC_ARGLIST
#define RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg)
Definition: ruby.h:1511
sdbm_close
void sdbm_close(register DBM *db)
Definition: _sdbm.c:266
fsdbm_shift
static VALUE fsdbm_shift(VALUE obj)
Definition: init.c:457
GetDBM2
#define GetDBM2(obj, data, dbm)
Definition: init.c:86
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
fsdbm_empty_p
static VALUE fsdbm_empty_p(VALUE obj)
Definition: init.c:711
datum
Definition: sdbm.h:50
rb_block_given_p
int rb_block_given_p(void)
Definition: eval.c:712
rb_hash_aset
VALUE rb_hash_aset(VALUE hash, VALUE key, VALUE val)
Definition: hash.c:1393
DBM_REPLACE
#define DBM_REPLACE
Definition: sdbm.h:67
val
#define val
rb_cObject
RUBY_EXTERN VALUE rb_cObject
Definition: ruby.h:1553
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:495
NIL_P
#define NIL_P(v)
Definition: ruby.h:438
rb_define_class
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition: class.c:630
sdbm_firstkey
datum sdbm_firstkey(register DBM *db)
Definition: _sdbm.c:469
fsdbm_delete
static VALUE fsdbm_delete(VALUE obj, VALUE keystr)
Definition: init.c:415
fsdbm_each_pair
static VALUE fsdbm_each_pair(VALUE obj)
Definition: init.c:797
rb_sys_fail_str
void rb_sys_fail_str(VALUE mesg)
Definition: error.c:1982
OBJ_FROZEN
#define OBJ_FROZEN(x)
Definition: ruby.h:1185
fsdbm_delete_if
static VALUE fsdbm_delete_if(VALUE obj)
Definition: init.c:488
argc
int argc
Definition: ruby.c:131
Qfalse
#define Qfalse
Definition: ruby.h:425
rb_external_str_new
VALUE rb_external_str_new(const char *, long)
Definition: string.c:707
closed_sdbm
static void closed_sdbm()
Definition: init.c:75
rb_eIndexError
VALUE rb_eIndexError
Definition: error.c:550
fsdbm_initialize
static VALUE fsdbm_initialize(int argc, VALUE *argv, VALUE obj)
Definition: init.c:160
ALLOC
#define ALLOC(type)
Definition: ruby.h:1334
RSTRING_LEN
#define RSTRING_LEN(str)
Definition: ruby.h:841
rb_yield
VALUE rb_yield(VALUE)
Definition: vm_eval.c:942
Init_sdbm
void Init_sdbm()
Definition: init.c:994
errno
int errno
rb_mEnumerable
VALUE rb_mEnumerable
Definition: enum.c:20
DBM
Definition: sdbm.h:20
rb_hash_new
VALUE rb_hash_new(void)
Definition: hash.c:298
ruby_xfree
void ruby_xfree(void *x)
Definition: gc.c:6242
rb_scan_args
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:1728
rb_assoc_new
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Definition: array.c:616
Qnil
#define Qnil
Definition: ruby.h:427
datum::dsize
int dsize
Definition: sdbm.h:52
VALUE
unsigned long VALUE
Definition: ruby.h:88
fsdbm_length
static VALUE fsdbm_length(VALUE obj)
Definition: init.c:686
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:839
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
RARRAY_LENINT
#define RARRAY_LENINT(ary)
Definition: ruby.h:884
rb_sys_fail
void rb_sys_fail(const char *mesg)
Definition: error.c:1976
rb_jump_tag
void rb_jump_tag(int tag)
Definition: eval.c:706
rb_str_dup
VALUE rb_str_dup(VALUE)
Definition: string.c:1062
fsdbm_to_hash
static VALUE fsdbm_to_hash(VALUE obj)
Definition: init.c:961
fsdbm_store
static VALUE fsdbm_store(VALUE obj, VALUE keystr, VALUE valstr)
Definition: init.c:600
RSTRING_PTR
#define RSTRING_PTR(str)
Definition: ruby.h:845
sdbm_store
int sdbm_store(register DBM *db, datum key, datum val, int flags)
Definition: _sdbm.c:314
INT2FIX
#define INT2FIX(i)
Definition: ruby.h:231
ExportStringValue
#define ExportStringValue(v)
Definition: ruby.h:553
rb_cDBM
static VALUE rb_cDBM
Definition: init.c:67
GetDBM
#define GetDBM(obj, dbmp)
Definition: init.c:80
RARRAY_PTR
#define RARRAY_PTR(a)
Definition: ruby.h:907
key
uint8_t key[16]
Definition: random.c:1250
fsdbm_fetch
static VALUE fsdbm_fetch(VALUE obj, VALUE keystr, VALUE ifnone)
Definition: init.c:235
RTEST
#define RTEST(v)
Definition: ruby.h:437
fsdbm_s_open
static VALUE fsdbm_s_open(int argc, VALUE *argv, VALUE klass)
Definition: init.c:219
fsdbm_each_key
static VALUE fsdbm_each_key(VALUE obj)
Definition: init.c:769
sdbm.h
hash
static unsigned int hash(const char *str, unsigned int len)
Definition: lex.c:56
RETURN_ENUMERATOR
#define RETURN_ENUMERATOR(obj, argc, argv)
Definition: intern.h:242
sdbm_nextkey
datum sdbm_nextkey(register DBM *db)
Definition: _sdbm.c:488
fsdbm_has_value
static VALUE fsdbm_has_value(VALUE obj, VALUE valstr)
Definition: init.c:899
fsdbm_fetch_m
static VALUE fsdbm_fetch_m(int argc, VALUE *argv, VALUE obj)
Definition: init.c:284
RSTRING_LENINT
#define RSTRING_LENINT(str)
Definition: ruby.h:853
rb_hash_delete_if
VALUE rb_hash_delete_if(VALUE hash)
Definition: hash.c:1094
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)
rb_define_method
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1488
rb_warn
void rb_warn(const char *fmt,...)
Definition: error.c:223
rb_eArgError
VALUE rb_eArgError
Definition: error.c:549
argv
char ** argv
Definition: ruby.c:132
fsdbm_keys
static VALUE fsdbm_keys(VALUE obj)
Definition: init.c:825