Ruby 2.7.0p0(2019-12-25revision647ee6f091eafcce70ffb75ddf7e121e192ab217)

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