Ruby: ext/dbm/dbm.c Source File

Ruby 3.0.5p211 (2022-11-24 revision ba5cf0f7c52d4d35cc6a173c89eda98ceffa2dcf)

dbm.c
Go to the documentation of this file.
1/************************************************
2
3 dbm.c -
4
5 $Author$
6 created at: Mon Jan 24 15:59:52 JST 1994
7
8 Copyright (C) 1995-2001 Yukihiro Matsumoto
9
10************************************************/
11
12#include "ruby.h"
13
14#ifdef HAVE_CDEFS_H
15# include <cdefs.h>
16#endif
17#ifdef HAVE_SYS_CDEFS_H
18# include <sys/cdefs.h>
19#endif
20#include DBM_HDR
21#include <fcntl.h>
22#include <errno.h>
23
24#define DSIZE_TYPE TYPEOF_DATUM_DSIZE
25#if SIZEOF_DATUM_DSIZE > SIZEOF_INT
26# define RSTRING_DSIZE(s) RSTRING_LEN(s)
27# define TOO_LONG(n) ((void)(n),0)
28#else
29# define RSTRING_DSIZE(s) RSTRING_LENINT(s)
30# define TOO_LONG(n) ((long)(+(DSIZE_TYPE)(n)) != (n))
31#endif
32
33static VALUE rb_cDBM, rb_eDBMError;
34
35#define RUBY_DBM_RW_BIT 0x20000000
36
37 struct dbmdata {
38 long di_size;
39 DBM *di_dbm;
40};
41
42 NORETURN(static void closed_dbm(void));
43
44static void
45closed_dbm(void)
46{
47 rb_raise(rb_eDBMError, "closed DBM file");
48}
49
50#define GetDBM(obj, dbmp) do {\
51 TypedData_Get_Struct((obj), struct dbmdata, &dbm_type, (dbmp));\
52 if ((dbmp)->di_dbm == 0) closed_dbm();\
53} while (0)
54
55#define GetDBM2(obj, dbmp, dbm) do {\
56 GetDBM((obj), (dbmp));\
57 (dbm) = (dbmp)->di_dbm;\
58} while (0)
59
60static void
61free_dbm(void *ptr)
62{
63 struct dbmdata *dbmp = ptr;
64 if (dbmp->di_dbm)
65 dbm_close(dbmp->di_dbm);
66 xfree(dbmp);
67}
68
69static size_t
70memsize_dbm(const void *ptr)
71{
72 const struct dbmdata *dbmp = ptr;
73 size_t size = sizeof(*dbmp);
74 if (dbmp->di_dbm)
75 size += DBM_SIZEOF_DBM;
76 return size;
77}
78
79static const rb_data_type_t dbm_type = {
80 "dbm",
81 {0, free_dbm, memsize_dbm,},
82 0, 0,
83 RUBY_TYPED_FREE_IMMEDIATELY,
84};
85
86/*
87 * call-seq:
88 * dbm.close
89 *
90 * Closes the database.
91 */
92static VALUE
93fdbm_close(VALUE obj)
94{
95 struct dbmdata *dbmp;
96
97 GetDBM(obj, dbmp);
98 dbm_close(dbmp->di_dbm);
99 dbmp->di_dbm = 0;
100
101 return Qnil;
102}
103
104/*
105 * call-seq:
106 * dbm.closed? -> true or false
107 *
108 * Returns true if the database is closed, false otherwise.
109 */
110static VALUE
111fdbm_closed(VALUE obj)
112{
113 struct dbmdata *dbmp;
114
115 TypedData_Get_Struct(obj, struct dbmdata, &dbm_type, dbmp);
116 if (dbmp->di_dbm == 0)
117 return Qtrue;
118
119 return Qfalse;
120}
121
122static VALUE
123fdbm_alloc(VALUE klass)
124{
125 struct dbmdata *dbmp;
126
127 return TypedData_Make_Struct(klass, struct dbmdata, &dbm_type, dbmp);
128}
129
130/*
131 * call-seq:
132 * DBM.new(filename[, mode[, flags]]) -> dbm
133 *
134 * Open a dbm database with the specified name, which can include a directory
135 * path. Any file extensions needed will be supplied automatically by the dbm
136 * library. For example, Berkeley DB appends '.db', and GNU gdbm uses two
137 * physical files with extensions '.dir' and '.pag'.
138 *
139 * The mode should be an integer, as for Unix chmod.
140 *
141 * Flags should be one of READER, WRITER, WRCREAT or NEWDB.
142 */
143static VALUE
144fdbm_initialize(int argc, VALUE *argv, VALUE obj)
145{
146 VALUE file, vmode, vflags;
147 DBM *dbm;
148 struct dbmdata *dbmp;
149 int mode, flags = 0;
150
151 TypedData_Get_Struct(obj, struct dbmdata, &dbm_type, dbmp);
152 if (rb_scan_args(argc, argv, "12", &file, &vmode, &vflags) == 1) {
153 mode = 0666; /* default value */
154 }
155 else if (NIL_P(vmode)) {
156 mode = -1; /* return nil if DB not exist */
157 }
158 else {
159 mode = NUM2INT(vmode);
160 }
161
162 if (!NIL_P(vflags))
163 flags = NUM2INT(vflags);
164
165 FilePathValue(file);
166
167 /*
168 * Note:
169 * gdbm 1.10 works with O_CLOEXEC. gdbm 1.9.1 silently ignore it.
170 */
171#ifndef O_CLOEXEC
172# define O_CLOEXEC 0
173#endif
174
175 if (flags & RUBY_DBM_RW_BIT) {
176 flags &= ~RUBY_DBM_RW_BIT;
177 dbm = dbm_open(RSTRING_PTR(file), flags|O_CLOEXEC, mode);
178 }
179 else {
180 dbm = 0;
181 if (mode >= 0) {
182 dbm = dbm_open(RSTRING_PTR(file), O_RDWR|O_CREAT|O_CLOEXEC, mode);
183 }
184 if (!dbm) {
185 dbm = dbm_open(RSTRING_PTR(file), O_RDWR|O_CLOEXEC, 0);
186 }
187 if (!dbm) {
188 dbm = dbm_open(RSTRING_PTR(file), O_RDONLY|O_CLOEXEC, 0);
189 }
190 }
191
192 if (dbm) {
193 /*
194 * History of dbm_pagfno() and dbm_dirfno() in ndbm and its compatibles.
195 * (dbm_pagfno() and dbm_dirfno() is not standardized.)
196 *
197 * 1986: 4.3BSD provides ndbm.
198 * It provides dbm_pagfno() and dbm_dirfno() as macros.
199 * 1991: gdbm-1.5 provides them as functions.
200 * They returns a same descriptor.
201 * (Earlier releases may have the functions too.)
202 * 1991: Net/2 provides Berkeley DB.
203 * It doesn't provide dbm_pagfno() and dbm_dirfno().
204 * 1992: 4.4BSD Alpha provides Berkeley DB with dbm_dirfno() as a function.
205 * dbm_pagfno() is a macro as DBM_PAGFNO_NOT_AVAILABLE.
206 * 1997: Berkeley DB 2.0 is released by Sleepycat Software, Inc.
207 * It defines dbm_pagfno() and dbm_dirfno() as macros.
208 * 2011: gdbm-1.9 creates a separate dir file.
209 * dbm_pagfno() and dbm_dirfno() returns different descriptors.
210 */
211#if defined(HAVE_DBM_PAGFNO)
212 rb_fd_fix_cloexec(dbm_pagfno(dbm));
213#endif
214#if defined(HAVE_DBM_DIRFNO)
215 rb_fd_fix_cloexec(dbm_dirfno(dbm));
216#endif
217
218#if defined(RUBYDBM_DB_HEADER) && defined(HAVE_TYPE_DBC)
219 /* Disable Berkeley DB error messages such as:
220 * DB->put: attempt to modify a read-only database */
221 ((DBC*)dbm)->dbp->set_errfile(((DBC*)dbm)->dbp, NULL);
222#endif
223 }
224
225 if (!dbm) {
226 if (mode == -1) return Qnil;
227 rb_sys_fail_str(file);
228 }
229
230 if (dbmp->di_dbm)
231 dbm_close(dbmp->di_dbm);
232 dbmp->di_dbm = dbm;
233 dbmp->di_size = -1;
234
235 return obj;
236}
237
238/*
239 * call-seq:
240 * DBM.open(filename[, mode[, flags]]) -> dbm
241 * DBM.open(filename[, mode[, flags]]) {|dbm| block}
242 *
243 * Open a dbm database and yields it if a block is given. See also
244 * <code>DBM.new</code>.
245 */
246static VALUE
247fdbm_s_open(int argc, VALUE *argv, VALUE klass)
248{
249 VALUE obj = fdbm_alloc(klass);
250
251 if (NIL_P(fdbm_initialize(argc, argv, obj))) {
252 return Qnil;
253 }
254
255 if (rb_block_given_p()) {
256 return rb_ensure(rb_yield, obj, fdbm_close, obj);
257 }
258
259 return obj;
260}
261
262static VALUE
263fdbm_fetch(VALUE obj, VALUE keystr, VALUE ifnone)
264{
265 datum key, value;
266 struct dbmdata *dbmp;
267 DBM *dbm;
268 long len;
269
270 ExportStringValue(keystr);
271 len = RSTRING_LEN(keystr);
272 if (TOO_LONG(len)) goto not_found;
273 key.dptr = RSTRING_PTR(keystr);
274 key.dsize = (DSIZE_TYPE)len;
275
276 GetDBM2(obj, dbmp, dbm);
277 value = dbm_fetch(dbm, key);
278 if (value.dptr == 0) {
279 not_found:
280 if (NIL_P(ifnone) && rb_block_given_p()) {
281 keystr = rb_str_dup(keystr);
282 return rb_yield(keystr);
283 }
284 return ifnone;
285 }
286 return rb_str_new(value.dptr, value.dsize);
287}
288
289/*
290 * call-seq:
291 * dbm[key] -> string value or nil
292 *
293 * Return a value from the database by locating the key string
294 * provided. If the key is not found, returns nil.
295 */
296static VALUE
297fdbm_aref(VALUE obj, VALUE keystr)
298{
299 return fdbm_fetch(obj, keystr, Qnil);
300}
301
302/*
303 * call-seq:
304 * dbm.fetch(key[, ifnone]) -> value
305 *
306 * Return a value from the database by locating the key string
307 * provided. If the key is not found, returns +ifnone+. If +ifnone+
308 * is not given, raises IndexError.
309 */
310static VALUE
311fdbm_fetch_m(int argc, VALUE *argv, VALUE obj)
312{
313 VALUE keystr, valstr, ifnone;
314
315 rb_scan_args(argc, argv, "11", &keystr, &ifnone);
316 valstr = fdbm_fetch(obj, keystr, ifnone);
317 if (argc == 1 && !rb_block_given_p() && NIL_P(valstr))
318 rb_raise(rb_eIndexError, "key not found");
319
320 return valstr;
321}
322
323/*
324 * call-seq:
325 * dbm.key(value) -> string
326 *
327 * Returns the key for the specified value.
328 */
329static VALUE
330fdbm_key(VALUE obj, VALUE valstr)
331{
332 datum key, val;
333 struct dbmdata *dbmp;
334 DBM *dbm;
335 long len;
336
337 ExportStringValue(valstr);
338 len = RSTRING_LEN(valstr);
339 if (TOO_LONG(len)) return Qnil;
340
341 GetDBM2(obj, dbmp, dbm);
342 for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
343 val = dbm_fetch(dbm, key);
344 if ((long)val.dsize == RSTRING_LEN(valstr) &&
345 memcmp(val.dptr, RSTRING_PTR(valstr), val.dsize) == 0) {
346 return rb_str_new(key.dptr, key.dsize);
347 }
348 }
349 return Qnil;
350}
351
352/* :nodoc: */
353static VALUE
354fdbm_index(VALUE hash, VALUE value)
355{
356 rb_warn("DBM#index is deprecated; use DBM#key");
357 return fdbm_key(hash, value);
358}
359
360/*
361 * call-seq:
362 * dbm.select {|key, value| block} -> array
363 *
364 * Returns a new array consisting of the [key, value] pairs for which the code
365 * block returns true.
366 */
367static VALUE
368fdbm_select(VALUE obj)
369{
370 VALUE new = rb_ary_new();
371 datum key, val;
372 DBM *dbm;
373 struct dbmdata *dbmp;
374
375 GetDBM2(obj, dbmp, dbm);
376 for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
377 VALUE assoc, v;
378 val = dbm_fetch(dbm, key);
379 assoc = rb_assoc_new(rb_str_new(key.dptr, key.dsize),
380 rb_str_new(val.dptr, val.dsize));
381 v = rb_yield(assoc);
382 if (RTEST(v)) {
383 rb_ary_push(new, assoc);
384 }
385 GetDBM2(obj, dbmp, dbm);
386 }
387
388 return new;
389}
390
391/*
392 * call-seq:
393 * dbm.values_at(key, ...) -> Array
394 *
395 * Returns an array containing the values associated with the given keys.
396 */
397static VALUE
398fdbm_values_at(int argc, VALUE *argv, VALUE obj)
399{
400 VALUE new = rb_ary_new2(argc);
401 int i;
402
403 for (i=0; i<argc; i++) {
404 rb_ary_push(new, fdbm_fetch(obj, argv[i], Qnil));
405 }
406
407 return new;
408}
409
410static void
411fdbm_modify(VALUE obj)
412{
413 if (OBJ_FROZEN(obj)) rb_error_frozen("DBM");
414}
415
416/*
417 * call-seq:
418 * dbm.delete(key)
419 *
420 * Deletes an entry from the database.
421 */
422static VALUE
423fdbm_delete(VALUE obj, VALUE keystr)
424{
425 datum key, value;
426 struct dbmdata *dbmp;
427 DBM *dbm;
428 VALUE valstr;
429 long len;
430
431 fdbm_modify(obj);
432 ExportStringValue(keystr);
433 len = RSTRING_LEN(keystr);
434 if (TOO_LONG(len)) goto not_found;
435 key.dptr = RSTRING_PTR(keystr);
436 key.dsize = (DSIZE_TYPE)len;
437
438 GetDBM2(obj, dbmp, dbm);
439
440 value = dbm_fetch(dbm, key);
441 if (value.dptr == 0) {
442 not_found:
443 if (rb_block_given_p()) return rb_yield(keystr);
444 return Qnil;
445 }
446
447 /* need to save value before dbm_delete() */
448 valstr = rb_str_new(value.dptr, value.dsize);
449
450 if (dbm_delete(dbm, key)) {
451 dbmp->di_size = -1;
452 rb_raise(rb_eDBMError, "dbm_delete failed");
453 }
454 else if (dbmp->di_size >= 0) {
455 dbmp->di_size--;
456 }
457 return valstr;
458}
459
460/*
461 * call-seq:
462 * dbm.shift() -> [key, value]
463 *
464 * Removes a [key, value] pair from the database, and returns it.
465 * If the database is empty, returns nil.
466 * The order in which values are removed/returned is not guaranteed.
467 */
468static VALUE
469fdbm_shift(VALUE obj)
470{
471 datum key, val;
472 struct dbmdata *dbmp;
473 DBM *dbm;
474 VALUE keystr, valstr;
475
476 fdbm_modify(obj);
477 GetDBM2(obj, dbmp, dbm);
478 dbmp->di_size = -1;
479
480 key = dbm_firstkey(dbm);
481 if (!key.dptr) return Qnil;
482 val = dbm_fetch(dbm, key);
483 keystr = rb_str_new(key.dptr, key.dsize);
484 valstr = rb_str_new(val.dptr, val.dsize);
485 dbm_delete(dbm, key);
486
487 return rb_assoc_new(keystr, valstr);
488}
489
490/*
491 * call-seq:
492 * dbm.reject! {|key, value| block} -> self
493 * dbm.delete_if {|key, value| block} -> self
494 *
495 * Deletes all entries for which the code block returns true.
496 * Returns self.
497 */
498static VALUE
499fdbm_delete_if(VALUE obj)
500{
501 datum key, val;
502 struct dbmdata *dbmp;
503 DBM *dbm;
504 VALUE keystr, valstr;
505 VALUE ret, ary = rb_ary_tmp_new(0);
506 int status = 0;
507 long i, n;
508
509 fdbm_modify(obj);
510 GetDBM2(obj, dbmp, dbm);
511 n = dbmp->di_size;
512 dbmp->di_size = -1;
513
514 for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
515 val = dbm_fetch(dbm, key);
516 keystr = rb_str_new(key.dptr, key.dsize);
517 OBJ_FREEZE(keystr);
518 valstr = rb_str_new(val.dptr, val.dsize);
519 ret = rb_protect(rb_yield, rb_assoc_new(rb_str_dup(keystr), valstr), &status);
520 if (status != 0) break;
521 if (RTEST(ret)) rb_ary_push(ary, keystr);
522 GetDBM2(obj, dbmp, dbm);
523 }
524
525 for (i = 0; i < RARRAY_LEN(ary); i++) {
526 keystr = RARRAY_AREF(ary, i);
527 key.dptr = RSTRING_PTR(keystr);
528 key.dsize = (DSIZE_TYPE)RSTRING_LEN(keystr);
529 if (dbm_delete(dbm, key)) {
530 rb_raise(rb_eDBMError, "dbm_delete failed");
531 }
532 }
533 if (status) rb_jump_tag(status);
534 if (n > 0) dbmp->di_size = n - RARRAY_LEN(ary);
535 rb_ary_clear(ary);
536
537 return obj;
538}
539
540/*
541 * call-seq:
542 * dbm.clear
543 *
544 * Deletes all data from the database.
545 */
546static VALUE
547fdbm_clear(VALUE obj)
548{
549 datum key;
550 struct dbmdata *dbmp;
551 DBM *dbm;
552
553 fdbm_modify(obj);
554 GetDBM2(obj, dbmp, dbm);
555 dbmp->di_size = -1;
556 while (key = dbm_firstkey(dbm), key.dptr) {
557 if (dbm_delete(dbm, key)) {
558 rb_raise(rb_eDBMError, "dbm_delete failed");
559 }
560 }
561 dbmp->di_size = 0;
562
563 return obj;
564}
565
566/*
567 * call-seq:
568 * dbm.invert -> hash
569 *
570 * Returns a Hash (not a DBM database) created by using each value in the
571 * database as a key, with the corresponding key as its value.
572 */
573static VALUE
574fdbm_invert(VALUE obj)
575{
576 datum key, val;
577 struct dbmdata *dbmp;
578 DBM *dbm;
579 VALUE keystr, valstr;
580 VALUE hash = rb_hash_new();
581
582 GetDBM2(obj, dbmp, dbm);
583 for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
584 val = dbm_fetch(dbm, key);
585 keystr = rb_str_new(key.dptr, key.dsize);
586 valstr = rb_str_new(val.dptr, val.dsize);
587 rb_hash_aset(hash, valstr, keystr);
588 }
589 return hash;
590}
591
592static VALUE fdbm_store(VALUE,VALUE,VALUE);
593
594static VALUE
595update_i(RB_BLOCK_CALL_FUNC_ARGLIST(pair, dbm))
596{
597 const VALUE *ptr;
598 Check_Type(pair, T_ARRAY);
599 if (RARRAY_LEN(pair) < 2) {
600 rb_raise(rb_eArgError, "pair must be [key, value]");
601 }
602 ptr = RARRAY_CONST_PTR(pair);
603 fdbm_store(dbm, ptr[0], ptr[1]);
604 return Qnil;
605}
606
607/*
608 * call-seq:
609 * dbm.update(obj)
610 *
611 * Updates the database with multiple values from the specified object.
612 * Takes any object which implements the each_pair method, including
613 * Hash and DBM objects.
614 */
615static VALUE
616fdbm_update(VALUE obj, VALUE other)
617{
618 rb_block_call(other, rb_intern("each_pair"), 0, 0, update_i, obj);
619 return obj;
620}
621
622/*
623 * call-seq:
624 * dbm.replace(obj)
625 *
626 * Replaces the contents of the database with the contents of the specified
627 * object. Takes any object which implements the each_pair method, including
628 * Hash and DBM objects.
629 */
630static VALUE
631fdbm_replace(VALUE obj, VALUE other)
632{
633 fdbm_clear(obj);
634 rb_block_call(other, rb_intern("each_pair"), 0, 0, update_i, obj);
635 return obj;
636}
637
638/*
639 * call-seq:
640 * dbm.store(key, value) -> value
641 * dbm[key] = value
642 *
643 * Stores the specified string value in the database, indexed via the
644 * string key provided.
645 */
646static VALUE
647fdbm_store(VALUE obj, VALUE keystr, VALUE valstr)
648{
649 datum key, val;
650 struct dbmdata *dbmp;
651 DBM *dbm;
652
653 fdbm_modify(obj);
654 keystr = rb_obj_as_string(keystr);
655 valstr = rb_obj_as_string(valstr);
656
657 key.dptr = RSTRING_PTR(keystr);
658 key.dsize = RSTRING_DSIZE(keystr);
659
660 val.dptr = RSTRING_PTR(valstr);
661 val.dsize = RSTRING_DSIZE(valstr);
662
663 GetDBM2(obj, dbmp, dbm);
664 dbmp->di_size = -1;
665 if (dbm_store(dbm, key, val, DBM_REPLACE)) {
666 dbm_clearerr(dbm);
667 if (errno == EPERM) rb_sys_fail(0);
668 rb_raise(rb_eDBMError, "dbm_store failed");
669 }
670
671 return valstr;
672}
673
674/*
675 * call-seq:
676 * dbm.length -> integer
677 * dbm.size -> integer
678 *
679 * Returns the number of entries in the database.
680 */
681static VALUE
682fdbm_length(VALUE obj)
683{
684 datum key;
685 struct dbmdata *dbmp;
686 DBM *dbm;
687 int i = 0;
688
689 GetDBM2(obj, dbmp, dbm);
690 if (dbmp->di_size > 0) return INT2FIX(dbmp->di_size);
691
692 for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
693 i++;
694 }
695 dbmp->di_size = i;
696
697 return INT2FIX(i);
698}
699
700/*
701 * call-seq:
702 * dbm.empty?
703 *
704 * Returns true if the database is empty, false otherwise.
705 */
706static VALUE
707fdbm_empty_p(VALUE obj)
708{
709 datum key;
710 struct dbmdata *dbmp;
711 DBM *dbm;
712
713 GetDBM2(obj, dbmp, dbm);
714 if (dbmp->di_size < 0) {
715 dbm = dbmp->di_dbm;
716
717 for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
718 return Qfalse;
719 }
720 }
721 else {
722 if (dbmp->di_size)
723 return Qfalse;
724 }
725 return Qtrue;
726}
727
728/*
729 * call-seq:
730 * dbm.each_value {|value| block} -> self
731 *
732 * Calls the block once for each value string in the database. Returns self.
733 */
734static VALUE
735fdbm_each_value(VALUE obj)
736{
737 datum key, val;
738 struct dbmdata *dbmp;
739 DBM *dbm;
740
741 RETURN_ENUMERATOR(obj, 0, 0);
742
743 GetDBM2(obj, dbmp, dbm);
744 for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
745 val = dbm_fetch(dbm, key);
746 rb_yield(rb_str_new(val.dptr, val.dsize));
747 GetDBM2(obj, dbmp, dbm);
748 }
749 return obj;
750}
751
752/*
753 * call-seq:
754 * dbm.each_key {|key| block} -> self
755 *
756 * Calls the block once for each key string in the database. Returns self.
757 */
758static VALUE
759fdbm_each_key(VALUE obj)
760{
761 datum key;
762 struct dbmdata *dbmp;
763 DBM *dbm;
764
765 RETURN_ENUMERATOR(obj, 0, 0);
766
767 GetDBM2(obj, dbmp, dbm);
768 for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
769 rb_yield(rb_str_new(key.dptr, key.dsize));
770 GetDBM2(obj, dbmp, dbm);
771 }
772 return obj;
773}
774
775/*
776 * call-seq:
777 * dbm.each_pair {|key,value| block} -> self
778 *
779 * Calls the block once for each [key, value] pair in the database.
780 * Returns self.
781 */
782static VALUE
783fdbm_each_pair(VALUE obj)
784{
785 datum key, val;
786 DBM *dbm;
787 struct dbmdata *dbmp;
788 VALUE keystr, valstr;
789
790 RETURN_ENUMERATOR(obj, 0, 0);
791
792 GetDBM2(obj, dbmp, dbm);
793
794 for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
795 val = dbm_fetch(dbm, key);
796 keystr = rb_str_new(key.dptr, key.dsize);
797 valstr = rb_str_new(val.dptr, val.dsize);
798 rb_yield(rb_assoc_new(keystr, valstr));
799 GetDBM2(obj, dbmp, dbm);
800 }
801
802 return obj;
803}
804
805/*
806 * call-seq:
807 * dbm.keys -> array
808 *
809 * Returns an array of all the string keys in the database.
810 */
811static VALUE
812fdbm_keys(VALUE obj)
813{
814 datum key;
815 struct dbmdata *dbmp;
816 DBM *dbm;
817 VALUE ary;
818
819 GetDBM2(obj, dbmp, dbm);
820
821 ary = rb_ary_new();
822 for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
823 rb_ary_push(ary, rb_str_new(key.dptr, key.dsize));
824 }
825
826 return ary;
827}
828
829/*
830 * call-seq:
831 * dbm.values -> array
832 *
833 * Returns an array of all the string values in the database.
834 */
835static VALUE
836fdbm_values(VALUE obj)
837{
838 datum key, val;
839 struct dbmdata *dbmp;
840 DBM *dbm;
841 VALUE ary;
842
843 GetDBM2(obj, dbmp, dbm);
844 ary = rb_ary_new();
845 for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
846 val = dbm_fetch(dbm, key);
847 rb_ary_push(ary, rb_str_new(val.dptr, val.dsize));
848 }
849
850 return ary;
851}
852
853/*
854 * call-seq:
855 * dbm.include?(key) -> boolean
856 * dbm.has_key?(key) -> boolean
857 * dbm.member?(key) -> boolean
858 * dbm.key?(key) -> boolean
859 *
860 * Returns true if the database contains the specified key, false otherwise.
861 */
862static VALUE
863fdbm_has_key(VALUE obj, VALUE keystr)
864{
865 datum key, val;
866 struct dbmdata *dbmp;
867 DBM *dbm;
868 long len;
869
870 ExportStringValue(keystr);
871 len = RSTRING_LEN(keystr);
872 if (TOO_LONG(len)) return Qfalse;
873 key.dptr = RSTRING_PTR(keystr);
874 key.dsize = (DSIZE_TYPE)len;
875
876 GetDBM2(obj, dbmp, dbm);
877 val = dbm_fetch(dbm, key);
878 if (val.dptr) return Qtrue;
879 return Qfalse;
880}
881
882/*
883 * call-seq:
884 * dbm.has_value?(value) -> boolean
885 * dbm.value?(value) -> boolean
886 *
887 * Returns true if the database contains the specified string value, false
888 * otherwise.
889 */
890static VALUE
891fdbm_has_value(VALUE obj, VALUE valstr)
892{
893 datum key, val;
894 struct dbmdata *dbmp;
895 DBM *dbm;
896 long len;
897
898 ExportStringValue(valstr);
899 len = RSTRING_LEN(valstr);
900 if (TOO_LONG(len)) return Qfalse;
901 val.dptr = RSTRING_PTR(valstr);
902 val.dsize = (DSIZE_TYPE)len;
903
904 GetDBM2(obj, dbmp, dbm);
905 for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
906 val = dbm_fetch(dbm, key);
907 if ((DSIZE_TYPE)val.dsize == (DSIZE_TYPE)RSTRING_LEN(valstr) &&
908 memcmp(val.dptr, RSTRING_PTR(valstr), val.dsize) == 0)
909 return Qtrue;
910 }
911 return Qfalse;
912}
913
914/*
915 * call-seq:
916 * dbm.to_a -> array
917 *
918 * Converts the contents of the database to an array of [key, value] arrays,
919 * and returns it.
920 */
921static VALUE
922fdbm_to_a(VALUE obj)
923{
924 datum key, val;
925 struct dbmdata *dbmp;
926 DBM *dbm;
927 VALUE ary;
928
929 GetDBM2(obj, dbmp, dbm);
930 ary = rb_ary_new();
931 for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
932 val = dbm_fetch(dbm, key);
933 rb_ary_push(ary, rb_assoc_new(rb_str_new(key.dptr, key.dsize),
934 rb_str_new(val.dptr, val.dsize)));
935 }
936
937 return ary;
938}
939
940/*
941 * call-seq:
942 * dbm.to_hash -> hash
943 *
944 * Converts the contents of the database to an in-memory Hash object, and
945 * returns it.
946 */
947static VALUE
948fdbm_to_hash(VALUE obj)
949{
950 datum key, val;
951 struct dbmdata *dbmp;
952 DBM *dbm;
953 VALUE hash;
954
955 GetDBM2(obj, dbmp, dbm);
956 hash = rb_hash_new();
957 for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
958 val = dbm_fetch(dbm, key);
959 rb_hash_aset(hash, rb_str_new(key.dptr, key.dsize),
960 rb_str_new(val.dptr, val.dsize));
961 }
962
963 return hash;
964}
965
966/*
967 * call-seq:
968 * dbm.reject {|key,value| block} -> Hash
969 *
970 * Converts the contents of the database to an in-memory Hash, then calls
971 * Hash#reject with the specified code block, returning a new Hash.
972 */
973static VALUE
974fdbm_reject(VALUE obj)
975{
976 return rb_hash_delete_if(fdbm_to_hash(obj));
977}
978
979/*
980 * == Introduction
981 *
982 * The DBM class provides a wrapper to a Unix-style
983 * {dbm}[https://en.wikipedia.org/wiki/Dbm] or Database Manager library.
984 *
985 * Dbm databases do not have tables or columns; they are simple key-value
986 * data stores, like a Ruby Hash except not resident in RAM. Keys and values
987 * must be strings.
988 *
989 * The exact library used depends on how Ruby was compiled. It could be any
990 * of the following:
991 *
992 * - The original ndbm library is released in 4.3BSD.
993 * It is based on dbm library in Unix Version 7 but has different API to
994 * support multiple databases in a process.
995 * - {Berkeley DB}[https://en.wikipedia.org/wiki/Berkeley_DB] versions
996 * 1 thru 6, also known as BDB and Sleepycat DB, now owned by Oracle
997 * Corporation.
998 * - Berkeley DB 1.x, still found in 4.4BSD derivatives (FreeBSD, OpenBSD, etc).
999 * - {gdbm}[http://www.gnu.org/software/gdbm/], the GNU implementation of dbm.
1000 * - {qdbm}[http://fallabs.com/qdbm/index.html], another open source
1001 * reimplementation of dbm.
1002 *
1003 * All of these dbm implementations have their own Ruby interfaces
1004 * available, which provide richer (but varying) APIs.
1005 *
1006 * == Cautions
1007 *
1008 * Before you decide to use DBM, there are some issues you should consider:
1009 *
1010 * - Each implementation of dbm has its own file format. Generally, dbm
1011 * libraries will not read each other's files. This makes dbm files
1012 * a bad choice for data exchange.
1013 *
1014 * - Even running the same OS and the same dbm implementation, the database
1015 * file format may depend on the CPU architecture. For example, files may
1016 * not be portable between PowerPC and 386, or between 32 and 64 bit Linux.
1017 *
1018 * - Different versions of Berkeley DB use different file formats. A change to
1019 * the OS may therefore break DBM access to existing files.
1020 *
1021 * - Data size limits vary between implementations. Original Berkeley DB was
1022 * limited to 2GB of data. Dbm libraries also sometimes limit the total
1023 * size of a key/value pair, and the total size of all the keys that hash
1024 * to the same value. These limits can be as little as 512 bytes. That said,
1025 * gdbm and recent versions of Berkeley DB do away with these limits.
1026 *
1027 * Given the above cautions, DBM is not a good choice for long term storage of
1028 * important data. It is probably best used as a fast and easy alternative
1029 * to a Hash for processing large amounts of data.
1030 *
1031 * == Example
1032 *
1033 * require 'dbm'
1034 * db = DBM.open('rfcs', 0666, DBM::WRCREAT)
1035 * db['822'] = 'Standard for the Format of ARPA Internet Text Messages'
1036 * db['1123'] = 'Requirements for Internet Hosts - Application and Support'
1037 * db['3068'] = 'An Anycast Prefix for 6to4 Relay Routers'
1038 * puts db['822']
1039 */
1040void
1041Init_dbm(void)
1042{
1043 rb_cDBM = rb_define_class("DBM", rb_cObject);
1044 /* Document-class: DBMError
1045 * Exception class used to return errors from the dbm library.
1046 */
1047 rb_eDBMError = rb_define_class("DBMError", rb_eStandardError);
1048 rb_include_module(rb_cDBM, rb_mEnumerable);
1049
1050 rb_define_alloc_func(rb_cDBM, fdbm_alloc);
1051 rb_define_singleton_method(rb_cDBM, "open", fdbm_s_open, -1);
1052
1053 rb_define_method(rb_cDBM, "initialize", fdbm_initialize, -1);
1054 rb_define_method(rb_cDBM, "close", fdbm_close, 0);
1055 rb_define_method(rb_cDBM, "closed?", fdbm_closed, 0);
1056 rb_define_method(rb_cDBM, "[]", fdbm_aref, 1);
1057 rb_define_method(rb_cDBM, "fetch", fdbm_fetch_m, -1);
1058 rb_define_method(rb_cDBM, "[]=", fdbm_store, 2);
1059 rb_define_method(rb_cDBM, "store", fdbm_store, 2);
1060 rb_define_method(rb_cDBM, "index", fdbm_index, 1);
1061 rb_define_method(rb_cDBM, "key", fdbm_key, 1);
1062 rb_define_method(rb_cDBM, "select", fdbm_select, 0);
1063 rb_define_method(rb_cDBM, "values_at", fdbm_values_at, -1);
1064 rb_define_method(rb_cDBM, "length", fdbm_length, 0);
1065 rb_define_method(rb_cDBM, "size", fdbm_length, 0);
1066 rb_define_method(rb_cDBM, "empty?", fdbm_empty_p, 0);
1067 rb_define_method(rb_cDBM, "each", fdbm_each_pair, 0);
1068 rb_define_method(rb_cDBM, "each_value", fdbm_each_value, 0);
1069 rb_define_method(rb_cDBM, "each_key", fdbm_each_key, 0);
1070 rb_define_method(rb_cDBM, "each_pair", fdbm_each_pair, 0);
1071 rb_define_method(rb_cDBM, "keys", fdbm_keys, 0);
1072 rb_define_method(rb_cDBM, "values", fdbm_values, 0);
1073 rb_define_method(rb_cDBM, "shift", fdbm_shift, 0);
1074 rb_define_method(rb_cDBM, "delete", fdbm_delete, 1);
1075 rb_define_method(rb_cDBM, "delete_if", fdbm_delete_if, 0);
1076 rb_define_method(rb_cDBM, "reject!", fdbm_delete_if, 0);
1077 rb_define_method(rb_cDBM, "reject", fdbm_reject, 0);
1078 rb_define_method(rb_cDBM, "clear", fdbm_clear, 0);
1079 rb_define_method(rb_cDBM, "invert", fdbm_invert, 0);
1080 rb_define_method(rb_cDBM, "update", fdbm_update, 1);
1081 rb_define_method(rb_cDBM, "replace", fdbm_replace, 1);
1082
1083 rb_define_method(rb_cDBM, "include?", fdbm_has_key, 1);
1084 rb_define_method(rb_cDBM, "has_key?", fdbm_has_key, 1);
1085 rb_define_method(rb_cDBM, "member?", fdbm_has_key, 1);
1086 rb_define_method(rb_cDBM, "has_value?", fdbm_has_value, 1);
1087 rb_define_method(rb_cDBM, "key?", fdbm_has_key, 1);
1088 rb_define_method(rb_cDBM, "value?", fdbm_has_value, 1);
1089
1090 rb_define_method(rb_cDBM, "to_a", fdbm_to_a, 0);
1091 rb_define_method(rb_cDBM, "to_hash", fdbm_to_hash, 0);
1092
1093 /* Indicates that dbm_open() should open the database in read-only mode */
1094 rb_define_const(rb_cDBM, "READER", INT2FIX(O_RDONLY|RUBY_DBM_RW_BIT));
1095
1096 /* Indicates that dbm_open() should open the database in read/write mode */
1097 rb_define_const(rb_cDBM, "WRITER", INT2FIX(O_RDWR|RUBY_DBM_RW_BIT));
1098
1099 /* Indicates that dbm_open() should open the database in read/write mode,
1100 * and create it if it does not already exist
1101 */
1102 rb_define_const(rb_cDBM, "WRCREAT", INT2FIX(O_RDWR|O_CREAT|RUBY_DBM_RW_BIT));
1103
1104 /* Indicates that dbm_open() should open the database in read/write mode,
1105 * create it if it does not already exist, and delete all contents if it
1106 * does already exist.
1107 */
1108 rb_define_const(rb_cDBM, "NEWDB", INT2FIX(O_RDWR|O_CREAT|O_TRUNC|RUBY_DBM_RW_BIT));
1109
1110 {
1111 VALUE version;
1112#if defined(_DBM_IOERR)
1113 version = rb_str_new2("ndbm (4.3BSD)");
1114#elif defined(RUBYDBM_GDBM_HEADER)
1115# if defined(HAVE_DECLARED_LIBVAR_GDBM_VERSION)
1116 /* since gdbm 1.9 */
1117 version = rb_str_new2(gdbm_version);
1118# elif defined(HAVE_UNDECLARED_LIBVAR_GDBM_VERSION)
1119 /* ndbm.h doesn't declare gdbm_version until gdbm 1.8.3.
1120 * See extconf.rb for more information. */
1121 RUBY_EXTERN char *gdbm_version;
1122 version = rb_str_new2(gdbm_version);
1123# else
1124 version = rb_str_new2("GDBM (unknown)");
1125# endif
1126#elif defined(RUBYDBM_DB_HEADER)
1127# if defined(HAVE_DB_VERSION)
1128 /* The version of the dbm library, if using Berkeley DB */
1129 version = rb_str_new2(db_version(NULL, NULL, NULL));
1130# else
1131 version = rb_str_new2("Berkeley DB (unknown)");
1132# endif
1133#elif defined(_RELIC_H)
1134# if defined(HAVE_DPVERSION)
1135 version = rb_sprintf("QDBM %s", dpversion);
1136# else
1137 version = rb_str_new2("QDBM (unknown)");
1138# endif
1139#else
1140 version = rb_str_new2("ndbm (unknown)");
1141#endif
1142 /*
1143 * Identifies ndbm library version.
1144 *
1145 * Examples:
1146 *
1147 * - "ndbm (4.3BSD)"
1148 * - "Berkeley DB 4.8.30: (April 9, 2010)"
1149 * - "Berkeley DB (unknown)" (4.4BSD, maybe)
1150 * - "GDBM version 1.8.3. 10/15/2002 (built Jul 1 2011 12:32:45)"
1151 * - "QDBM 1.8.78"
1152 *
1153 */
1154 rb_define_const(rb_cDBM, "VERSION", version);
1155 }
1156}
rb_ary_push
VALUE rb_ary_push(VALUE ary, VALUE item)
Definition: array.c:1301
rb_ary_new
VALUE rb_ary_new(void)
Definition: array.c:749
rb_ary_tmp_new
VALUE rb_ary_tmp_new(long capa)
Definition: array.c:846
rb_ary_clear
VALUE rb_ary_clear(VALUE ary)
Definition: array.c:4534
rb_assoc_new
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Definition: array.c:975
NORETURN
#define NORETURN(x)
Definition: attributes.h:152
rb_define_method
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
Definition: cxxanyargs.hpp:653
rb_define_singleton_method
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
Definition: cxxanyargs.hpp:668
GetDBM2
#define GetDBM2(obj, dbmp, dbm)
Definition: dbm.c:55
RSTRING_DSIZE
#define RSTRING_DSIZE(s)
Definition: dbm.c:29
DSIZE_TYPE
#define DSIZE_TYPE
Definition: dbm.c:24
RUBY_DBM_RW_BIT
#define RUBY_DBM_RW_BIT
Definition: dbm.c:35
O_CLOEXEC
#define O_CLOEXEC
GetDBM
#define GetDBM(obj, dbmp)
Definition: dbm.c:50
TOO_LONG
#define TOO_LONG(n)
Definition: dbm.c:30
Init_dbm
void Init_dbm(void)
Definition: dbm.c:1041
ptr
struct RIMemo * ptr
Definition: debug.c:88
RUBY_EXTERN
#define RUBY_EXTERN
Definition: dllexport.h:36
rb_mEnumerable
VALUE rb_mEnumerable
Definition: enum.c:27
len
uint8_t len
Definition: escape.c:17
RSTRING_LEN
#define RSTRING_LEN(string)
Definition: fbuffer.h:22
RSTRING_PTR
#define RSTRING_PTR(string)
Definition: fbuffer.h:19
rb_include_module
void rb_include_module(VALUE klass, VALUE module)
Definition: class.c:962
rb_define_class
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition: class.c:748
rb_scan_args
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:2296
rb_block_given_p
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition: eval.c:935
OBJ_FROZEN
#define OBJ_FROZEN
Definition: fl_type.h:136
OBJ_FREEZE
#define OBJ_FREEZE
Definition: fl_type.h:134
rb_raise
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:2917
rb_eStandardError
VALUE rb_eStandardError
Definition: error.c:1054
rb_error_frozen
void rb_error_frozen(const char *what)
Definition: error.c:3228
rb_sys_fail_str
void rb_sys_fail_str(VALUE mesg)
Definition: error.c:3047
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:1105
rb_warn
void rb_warn(const char *fmt,...)
Definition: error.c:408
rb_eArgError
VALUE rb_eArgError
Definition: error.c:1058
rb_eIndexError
VALUE rb_eIndexError
Definition: error.c:1059
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:1148
rb_jump_tag
void rb_jump_tag(int tag)
Continues the exception caught by rb_protect() and rb_eval_string_protect().
Definition: eval.c:921
rb_sys_fail
void rb_sys_fail(const char *mesg)
Definition: error.c:3041
rb_cObject
VALUE rb_cObject
Object class.
Definition: object.c:49
rb_hash_delete_if
VALUE rb_hash_delete_if(VALUE hash)
Definition: hash.c:2490
rb_hash_aset
VALUE rb_hash_aset(VALUE hash, VALUE key, VALUE val)
Definition: hash.c:2901
rb_hash_new
VALUE rb_hash_new(void)
Definition: hash.c:1538
rb_ary_new2
#define rb_ary_new2
Definition: array.h:72
RETURN_ENUMERATOR
#define RETURN_ENUMERATOR(obj, argc, argv)
Definition: enumerator.h:74
rb_fd_fix_cloexec
void rb_fd_fix_cloexec(int fd)
Definition: io.c:283
rb_str_new2
#define rb_str_new2
Definition: string.h:276
rb_str_new
#define rb_str_new(str, len)
Definition: string.h:213
rb_obj_as_string
VALUE rb_obj_as_string(VALUE)
Definition: string.c:1529
rb_str_dup
VALUE rb_str_dup(VALUE)
Definition: string.c:1631
rb_define_alloc_func
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
rb_intern
ID rb_intern(const char *)
Definition: symbol.c:785
rb_define_const
void rb_define_const(VALUE, const char *, VALUE)
Definition: variable.c:3150
NUM2INT
#define NUM2INT
Definition: int.h:44
size
voidpf void uLong size
Definition: ioapi.h:138
mode
const char int mode
Definition: ioapi.h:137
RB_BLOCK_CALL_FUNC_ARGLIST
#define RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg)
Definition: iterator.h:31
rb_yield
VALUE rb_yield(VALUE)
Definition: vm_eval.c:1341
INT2FIX
#define INT2FIX
Definition: long.h:48
memcmp
int memcmp(const void *s1, const void *s2, size_t len)
Definition: memcmp.c:7
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:230
key
key
Definition: openssl_missing.h:185
RARRAY_CONST_PTR
#define RARRAY_CONST_PTR(s)
Definition: psych_emitter.c:4
RARRAY_AREF
#define RARRAY_AREF(a, i)
Definition: psych_emitter.c:7
RARRAY_LEN
#define RARRAY_LEN
Definition: rarray.h:52
NULL
#define NULL
Definition: regenc.h:69
ExportStringValue
#define ExportStringValue(v)
Definition: rstring.h:54
TypedData_Get_Struct
#define TypedData_Get_Struct(obj, type, data_type, sval)
Definition: rtypeddata.h:130
RUBY_TYPED_FREE_IMMEDIATELY
@ RUBY_TYPED_FREE_IMMEDIATELY
Definition: rtypeddata.h:62
TypedData_Make_Struct
#define TypedData_Make_Struct(klass, type, data_type, sval)
Definition: rtypeddata.h:122
ruby.h
FilePathValue
#define FilePathValue(v)
Definition: ruby.h:61
argc
int argc
Definition: ruby.c:240
argv
char ** argv
Definition: ruby.c:241
Qtrue
#define Qtrue
Definition: special_consts.h:52
RTEST
#define RTEST
Definition: special_consts.h:42
Qnil
#define Qnil
Definition: special_consts.h:51
Qfalse
#define Qfalse
Definition: special_consts.h:50
NIL_P
#define NIL_P
Definition: special_consts.h:46
rb_sprintf
VALUE rb_sprintf(const char *,...)
Definition: sprintf.c:1203
dbmdata
Definition: dbm.c:37
dbmdata::di_size
long di_size
Definition: dbm.c:38
dbmdata::di_dbm
DBM * di_dbm
Definition: dbm.c:39
file
Definition: gzappend.c:170
rb_data_type_struct
Definition: rtypeddata.h:70
VALUE
unsigned long VALUE
Definition: value.h:38
T_ARRAY
#define T_ARRAY
Definition: value_type.h:55
xfree
#define xfree
Definition: xmalloc.h:49