* io.c (rb_open_file): encoding in mode string was ignored if perm is
[ruby-svn.git] / ext / gdbm / gdbm.c
blobe6a6e0d03979622d3dc7a92f5a87b6c1a203c213
1 /************************************************
3 gdbm.c -
5 $Author$
6 modified at: Mon Jan 24 15:59:52 JST 1994
8 Documentation by Peter Adolphs < futzilogik at users dot sourceforge dot net >
10 ************************************************/
12 #include "ruby.h"
14 #include <gdbm.h>
15 #include <fcntl.h>
16 #include <errno.h>
19 * Document-class: GDBM
21 * == Summary
23 * Ruby extension for GNU dbm (gdbm) -- a simple database engine for storing
24 * key-value pairs on disk.
26 * == Description
28 * GNU dbm is a library for simple databases. A database is a file that stores
29 * key-value pairs. Gdbm allows the user to store, retrieve, and delete data by
30 * key. It furthermore allows a non-sorted traversal of all key-value pairs.
31 * A gdbm database thus provides the same functionality as a hash. As
32 * with objects of the Hash class, elements can be accessed with <tt>[]</tt>.
33 * Furthermore, GDBM mixes in the Enumerable module, thus providing convenient
34 * methods such as #find, #collect, #map, etc.
36 * A process is allowed to open several different databases at the same time.
37 * A process can open a database as a "reader" or a "writer". Whereas a reader
38 * has only read-access to the database, a writer has read- and write-access.
39 * A database can be accessed either by any number of readers or by exactly one
40 * writer at the same time.
42 * == Examples
44 * 1. Opening/creating a database, and filling it with some entries:
46 * require 'gdbm'
48 * gdbm = GDBM.new("fruitstore.db")
49 * gdbm["ananas"] = "3"
50 * gdbm["banana"] = "8"
51 * gdbm["cranberry"] = "4909"
52 * gdbm.close
54 * 2. Reading out a database:
56 * require 'gdbm'
58 * gdbm = GDBM.new("fruitstore.db")
59 * gdbm.each_pair do |key, value|
60 * print "#{key}: #{value}\n"
61 * end
62 * gdbm.close
64 * produces
66 * banana: 8
67 * ananas: 3
68 * cranberry: 4909
70 * == Links
72 * * http://www.gnu.org/software/gdbm/
74 static VALUE rb_cGDBM, rb_eGDBMError, rb_eGDBMFatalError;
76 #define RUBY_GDBM_RW_BIT 0x20000000
78 #define MY_BLOCK_SIZE (2048)
79 #define MY_FATAL_FUNC rb_gdbm_fatal
80 static void
81 rb_gdbm_fatal(char *msg)
83 rb_raise(rb_eGDBMFatalError, "%s", msg);
86 struct dbmdata {
87 int di_size;
88 GDBM_FILE di_dbm;
91 static void
92 closed_dbm(void)
94 rb_raise(rb_eRuntimeError, "closed GDBM file");
97 #define GetDBM(obj, dbmp) do {\
98 Data_Get_Struct(obj, struct dbmdata, dbmp);\
99 if (dbmp == 0) closed_dbm();\
100 if (dbmp->di_dbm == 0) closed_dbm();\
101 } while (0)
103 #define GetDBM2(obj, data, dbm) {\
104 GetDBM(obj, data);\
105 (dbm) = dbmp->di_dbm;\
108 static void
109 free_dbm(struct dbmdata *dbmp)
111 if (dbmp) {
112 if (dbmp->di_dbm) gdbm_close(dbmp->di_dbm);
113 xfree(dbmp);
118 * call-seq:
119 * gdbm.close -> nil
121 * Closes the associated database file.
123 static VALUE
124 fgdbm_close(VALUE obj)
126 struct dbmdata *dbmp;
128 GetDBM(obj, dbmp);
129 gdbm_close(dbmp->di_dbm);
130 dbmp->di_dbm = 0;
132 return Qnil;
136 * call-seq:
137 * gdbm.closed? -> true or false
139 * Returns true if the associated database file has been closed.
141 static VALUE
142 fgdbm_closed(VALUE obj)
144 struct dbmdata *dbmp;
146 Data_Get_Struct(obj, struct dbmdata, dbmp);
147 if (dbmp == 0)
148 return Qtrue;
149 if (dbmp->di_dbm == 0)
150 return Qtrue;
152 return Qfalse;
155 static VALUE
156 fgdbm_s_alloc(VALUE klass)
158 return Data_Wrap_Struct(klass, 0, free_dbm, 0);
162 * call-seq:
163 * GDBM.new(filename, mode = 0666, flags = nil)
165 * Creates a new GDBM instance by opening a gdbm file named _filename_.
166 * If the file does not exist, a new file with file mode _mode_ will be
167 * created. _flags_ may be one of the following:
168 * * *READER* - open as a reader
169 * * *WRITER* - open as a writer
170 * * *WRCREAT* - open as a writer; if the database does not exist, create a new one
171 * * *NEWDB* - open as a writer; overwrite any existing databases
173 * The values *WRITER*, *WRCREAT* and *NEWDB* may be combined with the following
174 * values by bitwise or:
175 * * *SYNC* - cause all database operations to be synchronized to the disk
176 * * *NOLOCK* - do not lock the database file
178 * If no _flags_ are specified, the GDBM object will try to open the database
179 * file as a writer and will create it if it does not already exist
180 * (cf. flag <tt>WRCREAT</tt>). If this fails (for instance, if another process
181 * has already opened the database as a reader), it will try to open the
182 * database file as a reader (cf. flag <tt>READER</tt>).
184 static VALUE
185 fgdbm_initialize(int argc, VALUE *argv, VALUE obj)
187 VALUE file, vmode, vflags;
188 GDBM_FILE dbm;
189 struct dbmdata *dbmp;
190 int mode, flags = 0;
192 if (rb_scan_args(argc, argv, "12", &file, &vmode, &vflags) == 1) {
193 mode = 0666; /* default value */
195 else if (NIL_P(vmode)) {
196 mode = -1; /* return nil if DB does not exist */
198 else {
199 mode = NUM2INT(vmode);
202 if (!NIL_P(vflags))
203 flags = NUM2INT(vflags);
205 SafeStringValue(file);
207 if (flags & RUBY_GDBM_RW_BIT) {
208 flags &= ~RUBY_GDBM_RW_BIT;
209 dbm = gdbm_open(RSTRING_PTR(file), MY_BLOCK_SIZE,
210 flags, mode, MY_FATAL_FUNC);
212 else {
213 dbm = 0;
214 if (mode >= 0)
215 dbm = gdbm_open(RSTRING_PTR(file), MY_BLOCK_SIZE,
216 GDBM_WRCREAT|flags, mode, MY_FATAL_FUNC);
217 if (!dbm)
218 dbm = gdbm_open(RSTRING_PTR(file), MY_BLOCK_SIZE,
219 GDBM_WRITER|flags, 0, MY_FATAL_FUNC);
220 if (!dbm)
221 dbm = gdbm_open(RSTRING_PTR(file), MY_BLOCK_SIZE,
222 GDBM_READER|flags, 0, MY_FATAL_FUNC);
225 if (!dbm) {
226 if (mode == -1) return Qnil;
228 if (gdbm_errno == GDBM_FILE_OPEN_ERROR ||
229 gdbm_errno == GDBM_CANT_BE_READER ||
230 gdbm_errno == GDBM_CANT_BE_WRITER)
231 rb_sys_fail(RSTRING_PTR(file));
232 else
233 rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno));
236 dbmp = ALLOC(struct dbmdata);
237 free_dbm(DATA_PTR(obj));
238 DATA_PTR(obj) = dbmp;
239 dbmp->di_dbm = dbm;
240 dbmp->di_size = -1;
242 return obj;
246 * call-seq:
247 * GDBM.open(filename, mode = 0666, flags = nil)
248 * GDBM.open(filename, mode = 0666, flags = nil) { |gdbm| ... }
250 * If called without a block, this is synonymous to GDBM::new.
251 * If a block is given, the new GDBM instance will be passed to the block
252 * as a parameter, and the corresponding database file will be closed
253 * after the execution of the block code has been finished.
255 * Example for an open call with a block:
257 * require 'gdbm'
258 * GDBM.open("fruitstore.db") do |gdbm|
259 * gdbm.each_pair do |key, value|
260 * print "#{key}: #{value}\n"
261 * end
262 * end
264 static VALUE
265 fgdbm_s_open(int argc, VALUE *argv, VALUE klass)
267 VALUE obj = Data_Wrap_Struct(klass, 0, free_dbm, 0);
269 if (NIL_P(fgdbm_initialize(argc, argv, obj))) {
270 return Qnil;
273 if (rb_block_given_p()) {
274 return rb_ensure(rb_yield, obj, fgdbm_close, obj);
277 return obj;
280 static VALUE
281 rb_gdbm_fetch(GDBM_FILE dbm, datum key)
283 datum val;
284 VALUE str;
286 val = gdbm_fetch(dbm, key);
287 if (val.dptr == 0)
288 return Qnil;
290 str = rb_str_new(val.dptr, val.dsize);
291 free(val.dptr);
292 OBJ_TAINT(str);
293 return (VALUE)str;
296 static VALUE
297 rb_gdbm_fetch2(GDBM_FILE dbm, VALUE keystr)
299 datum key;
301 StringValue(keystr);
302 key.dptr = RSTRING_PTR(keystr);
303 key.dsize = RSTRING_LEN(keystr);
305 return rb_gdbm_fetch(dbm, key);
308 static VALUE
309 rb_gdbm_fetch3(VALUE obj, VALUE keystr)
311 struct dbmdata *dbmp;
312 GDBM_FILE dbm;
314 GetDBM2(obj, dbmp, dbm);
315 return rb_gdbm_fetch2(dbm, keystr);
318 static VALUE
319 rb_gdbm_firstkey(GDBM_FILE dbm)
321 datum key;
322 VALUE str;
324 key = gdbm_firstkey(dbm);
325 if (key.dptr == 0)
326 return Qnil;
328 str = rb_str_new(key.dptr, key.dsize);
329 free(key.dptr);
330 OBJ_TAINT(str);
331 return str;
334 static VALUE
335 rb_gdbm_nextkey(GDBM_FILE dbm, VALUE keystr)
337 datum key, key2;
338 VALUE str;
340 key.dptr = RSTRING_PTR(keystr);
341 key.dsize = RSTRING_LEN(keystr);
342 key2 = gdbm_nextkey(dbm, key);
343 if (key2.dptr == 0)
344 return Qnil;
346 str = rb_str_new(key2.dptr, key2.dsize);
347 OBJ_TAINT(str);
348 return str;
351 static VALUE
352 fgdbm_fetch(VALUE obj, VALUE keystr, VALUE ifnone)
354 VALUE valstr;
356 valstr = rb_gdbm_fetch3(obj, keystr);
357 if (NIL_P(valstr)) {
358 if (ifnone == Qnil && rb_block_given_p())
359 return rb_yield(keystr);
360 return ifnone;
362 return valstr;
366 * call-seq:
367 * gdbm[key] -> value
369 * Retrieves the _value_ corresponding to _key_.
371 static VALUE
372 fgdbm_aref(VALUE obj, VALUE keystr)
374 return rb_gdbm_fetch3(obj, keystr);
378 * call-seq:
379 * gdbm.fetch(key [, default]) -> value
381 * Retrieves the _value_ corresponding to _key_. If there is no value
382 * associated with _key_, _default_ will be returned instead.
384 static VALUE
385 fgdbm_fetch_m(int argc, VALUE *argv, VALUE obj)
387 VALUE keystr, valstr, ifnone;
389 rb_scan_args(argc, argv, "11", &keystr, &ifnone);
390 valstr = fgdbm_fetch(obj, keystr, ifnone);
391 if (argc == 1 && !rb_block_given_p() && NIL_P(valstr))
392 rb_raise(rb_eIndexError, "key not found");
394 return valstr;
398 * call-seq:
399 * gdbm.index(value) -> key
401 * Returns the _key_ for a given _value_. If several keys may map to the
402 * same value, the key that is found first will be returned.
404 static VALUE
405 fgdbm_index(VALUE obj, VALUE valstr)
407 struct dbmdata *dbmp;
408 GDBM_FILE dbm;
409 VALUE keystr, valstr2;
411 StringValue(valstr);
412 GetDBM2(obj, dbmp, dbm);
413 for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
414 keystr = rb_gdbm_nextkey(dbm, keystr)) {
416 valstr2 = rb_gdbm_fetch2(dbm, keystr);
417 if (!NIL_P(valstr2) &&
418 RSTRING_LEN(valstr) == RSTRING_LEN(valstr2) &&
419 memcmp(RSTRING_PTR(valstr), RSTRING_PTR(valstr2),
420 RSTRING_LEN(valstr)) == 0) {
421 return keystr;
424 return Qnil;
428 * call-seq:
429 * gdbm.select { |value| block } -> array
431 * Returns a new array of all values of the database for which _block_
432 * evaluates to true.
434 static VALUE
435 fgdbm_select(VALUE obj)
437 VALUE new = rb_ary_new();
438 GDBM_FILE dbm;
439 struct dbmdata *dbmp;
440 VALUE keystr;
442 GetDBM2(obj, dbmp, dbm);
443 for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
444 keystr = rb_gdbm_nextkey(dbm, keystr)) {
445 VALUE assoc = rb_assoc_new(keystr, rb_gdbm_fetch2(dbm, keystr));
446 VALUE v = rb_yield(assoc);
448 if (RTEST(v)) {
449 rb_ary_push(new, assoc);
451 GetDBM2(obj, dbmp, dbm);
454 return new;
458 * call-seq:
459 * gdbm.values_at(key, ...) -> array
461 * Returns an array of the values associated with each specified _key_.
463 static VALUE
464 fgdbm_values_at(int argc, VALUE *argv, VALUE obj)
466 VALUE new = rb_ary_new2(argc);
467 int i;
469 for (i=0; i<argc; i++) {
470 rb_ary_push(new, rb_gdbm_fetch3(obj, argv[i]));
473 return new;
476 static void
477 rb_gdbm_modify(VALUE obj)
479 rb_secure(4);
480 if (OBJ_FROZEN(obj)) rb_error_frozen("GDBM");
483 static VALUE
484 rb_gdbm_delete(VALUE obj, VALUE keystr)
486 datum key;
487 struct dbmdata *dbmp;
488 GDBM_FILE dbm;
490 rb_gdbm_modify(obj);
491 StringValue(keystr);
492 key.dptr = RSTRING_PTR(keystr);
493 key.dsize = RSTRING_LEN(keystr);
495 GetDBM2(obj, dbmp, dbm);
496 if (!gdbm_exists(dbm, key)) {
497 return Qnil;
500 if (gdbm_delete(dbm, key)) {
501 dbmp->di_size = -1;
502 rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno));
504 else if (dbmp->di_size >= 0) {
505 dbmp->di_size--;
507 return obj;
511 * call-seq:
512 * gdbm.delete(key) -> value or nil
514 * Removes the key-value-pair with the specified _key_ from this database and
515 * returns the corresponding _value_. Returns nil if the database is empty.
517 static VALUE
518 fgdbm_delete(VALUE obj, VALUE keystr)
520 VALUE valstr;
522 valstr = fgdbm_fetch(obj, keystr, Qnil);
523 rb_gdbm_delete(obj, keystr);
524 return valstr;
528 * call-seq:
529 * gdbm.shift -> (key, value) or nil
531 * Removes a key-value-pair from this database and returns it as a
532 * two-item array [ _key_, _value_ ]. Returns nil if the database is empty.
534 static VALUE
535 fgdbm_shift(VALUE obj)
537 struct dbmdata *dbmp;
538 GDBM_FILE dbm;
539 VALUE keystr, valstr;
541 rb_gdbm_modify(obj);
542 GetDBM2(obj, dbmp, dbm);
543 keystr = rb_gdbm_firstkey(dbm);
544 if (NIL_P(keystr)) return Qnil;
545 valstr = rb_gdbm_fetch2(dbm, keystr);
546 rb_gdbm_delete(obj, keystr);
548 return rb_assoc_new(keystr, valstr);
552 * call-seq:
553 * gdbm.delete_if { |key, value| block } -> gdbm
554 * gdbm.reject! { |key, value| block } -> gdbm
556 * Deletes every key-value pair from _gdbm_ for which _block_ evaluates to true.
558 static VALUE
559 fgdbm_delete_if(VALUE obj)
561 struct dbmdata *dbmp;
562 GDBM_FILE dbm;
563 VALUE keystr, valstr;
564 VALUE ret, ary = rb_ary_new();
565 int i, status = 0, n;
567 rb_gdbm_modify(obj);
568 GetDBM2(obj, dbmp, dbm);
569 n = dbmp->di_size;
570 dbmp->di_size = -1;
572 for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
573 keystr = rb_gdbm_nextkey(dbm, keystr)) {
575 valstr = rb_gdbm_fetch2(dbm, keystr);
576 ret = rb_protect(rb_yield, rb_assoc_new(keystr, valstr), &status);
577 if (status != 0) break;
578 if (RTEST(ret)) rb_ary_push(ary, keystr);
579 GetDBM2(obj, dbmp, dbm);
582 for (i = 0; i < RARRAY_LEN(ary); i++)
583 rb_gdbm_delete(obj, RARRAY_PTR(ary)[i]);
584 if (status) rb_jump_tag(status);
585 if (n > 0) dbmp->di_size = n - RARRAY_LEN(ary);
587 return obj;
591 * call-seq:
592 * gdbm.clear -> gdbm
594 * Removes all the key-value pairs within _gdbm_.
596 static VALUE
597 fgdbm_clear(VALUE obj)
599 datum key, nextkey;
600 struct dbmdata *dbmp;
601 GDBM_FILE dbm;
603 rb_gdbm_modify(obj);
604 GetDBM2(obj, dbmp, dbm);
605 dbmp->di_size = -1;
607 #if 0
608 while (key = gdbm_firstkey(dbm), key.dptr) {
609 if (gdbm_delete(dbm, key)) {
610 free(key.dptr);
611 rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno));
613 free(key.dptr);
615 #else
616 while (key = gdbm_firstkey(dbm), key.dptr) {
617 for (; key.dptr; key = nextkey) {
618 nextkey = gdbm_nextkey(dbm, key);
619 if (gdbm_delete(dbm, key)) {
620 free(key.dptr);
621 if (nextkey.dptr) free(nextkey.dptr);
622 rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno));
624 free(key.dptr);
627 #endif
628 dbmp->di_size = 0;
630 return obj;
634 * call-seq:
635 * gdbm.invert -> hash
637 * Returns a hash created by using _gdbm_'s values as keys, and the keys
638 * as values.
640 static VALUE
641 fgdbm_invert(VALUE obj)
643 struct dbmdata *dbmp;
644 GDBM_FILE dbm;
645 VALUE keystr, valstr;
646 VALUE hash = rb_hash_new();
648 GetDBM2(obj, dbmp, dbm);
649 for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
650 keystr = rb_gdbm_nextkey(dbm, keystr)) {
651 valstr = rb_gdbm_fetch2(dbm, keystr);
653 rb_hash_aset(hash, valstr, keystr);
655 return hash;
659 * call-seq:
660 * gdbm[key]= value -> value
661 * gdbm.store(key, value) -> value
663 * Associates the value _value_ with the specified _key_.
665 static VALUE
666 fgdbm_store(VALUE obj, VALUE keystr, VALUE valstr)
668 datum key, val;
669 struct dbmdata *dbmp;
670 GDBM_FILE dbm;
672 rb_gdbm_modify(obj);
673 StringValue(keystr);
674 StringValue(valstr);
676 key.dptr = RSTRING_PTR(keystr);
677 key.dsize = RSTRING_LEN(keystr);
679 val.dptr = RSTRING_PTR(valstr);
680 val.dsize = RSTRING_LEN(valstr);
682 GetDBM2(obj, dbmp, dbm);
683 dbmp->di_size = -1;
684 if (gdbm_store(dbm, key, val, GDBM_REPLACE)) {
685 if (errno == EPERM) rb_sys_fail(0);
686 rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno));
689 return valstr;
692 static VALUE
693 update_i(VALUE pair, VALUE dbm)
695 Check_Type(pair, T_ARRAY);
696 if (RARRAY_LEN(pair) < 2) {
697 rb_raise(rb_eArgError, "pair must be [key, value]");
699 fgdbm_store(dbm, RARRAY_PTR(pair)[0], RARRAY_PTR(pair)[1]);
700 return Qnil;
704 * call-seq:
705 * gdbm.update(other) -> gdbm
707 * Adds the key-value pairs of _other_ to _gdbm_, overwriting entries with
708 * duplicate keys with those from _other_. _other_ must have an each_pair
709 * method.
711 static VALUE
712 fgdbm_update(VALUE obj, VALUE other)
714 rb_block_call(other, rb_intern("each_pair"), 0, 0, update_i, obj);
715 return obj;
719 * call-seq:
720 * gdbm.replace(other) -> gdbm
722 * Replaces the content of _gdbm_ with the key-value pairs of _other_.
723 * _other_ must have an each_pair method.
725 static VALUE
726 fgdbm_replace(VALUE obj, VALUE other)
728 fgdbm_clear(obj);
729 rb_block_call(other, rb_intern("each_pair"), 0, 0, update_i, obj);
730 return obj;
734 * call-seq:
735 * gdbm.length -> fixnum
736 * gdbm.size -> fixnum
738 * Returns the number of key-value pairs in this database.
740 static VALUE
741 fgdbm_length(VALUE obj)
743 datum key, nextkey;
744 struct dbmdata *dbmp;
745 GDBM_FILE dbm;
746 int i = 0;
748 GetDBM2(obj, dbmp, dbm);
749 if (dbmp->di_size > 0) return INT2FIX(dbmp->di_size);
751 for (key = gdbm_firstkey(dbm); key.dptr; key = nextkey) {
752 nextkey = gdbm_nextkey(dbm, key);
753 free(key.dptr);
754 i++;
756 dbmp->di_size = i;
758 return INT2FIX(i);
762 * call-seq:
763 * gdbm.empty? -> true or false
765 * Returns true if the database is empty.
767 static VALUE
768 fgdbm_empty_p(VALUE obj)
770 datum key;
771 struct dbmdata *dbmp;
772 GDBM_FILE dbm;
774 GetDBM(obj, dbmp);
775 if (dbmp->di_size < 0) {
776 dbm = dbmp->di_dbm;
778 key = gdbm_firstkey(dbm);
779 if (key.dptr) {
780 free(key.dptr);
781 return Qfalse;
783 return Qtrue;
786 if (dbmp->di_size == 0) return Qtrue;
787 return Qfalse;
791 * call-seq:
792 * gdbm.each_value { |value| block } -> gdbm
794 * Executes _block_ for each key in the database, passing the corresponding
795 * _value_ as a parameter.
797 static VALUE
798 fgdbm_each_value(VALUE obj)
800 struct dbmdata *dbmp;
801 GDBM_FILE dbm;
802 VALUE keystr;
804 RETURN_ENUMERATOR(obj, 0, 0);
806 GetDBM2(obj, dbmp, dbm);
807 for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
808 keystr = rb_gdbm_nextkey(dbm, keystr)) {
810 rb_yield(rb_gdbm_fetch2(dbm, keystr));
811 GetDBM2(obj, dbmp, dbm);
813 return obj;
817 * call-seq:
818 * gdbm.each_key { |key| block } -> gdbm
820 * Executes _block_ for each key in the database, passing the
821 * _key_ as a parameter.
823 static VALUE
824 fgdbm_each_key(VALUE obj)
826 struct dbmdata *dbmp;
827 GDBM_FILE dbm;
828 VALUE keystr;
830 RETURN_ENUMERATOR(obj, 0, 0);
832 GetDBM2(obj, dbmp, dbm);
833 for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
834 keystr = rb_gdbm_nextkey(dbm, keystr)) {
836 rb_yield(keystr);
837 GetDBM2(obj, dbmp, dbm);
839 return obj;
843 * call-seq:
844 * gdbm.each_pair { |key, value| block } -> gdbm
846 * Executes _block_ for each key in the database, passing the _key_ and the
847 * correspoding _value_ as a parameter.
849 static VALUE
850 fgdbm_each_pair(VALUE obj)
852 GDBM_FILE dbm;
853 struct dbmdata *dbmp;
854 VALUE keystr;
856 RETURN_ENUMERATOR(obj, 0, 0);
858 GetDBM2(obj, dbmp, dbm);
859 for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
860 keystr = rb_gdbm_nextkey(dbm, keystr)) {
862 rb_yield(rb_assoc_new(keystr, rb_gdbm_fetch2(dbm, keystr)));
863 GetDBM2(obj, dbmp, dbm);
866 return obj;
870 * call-seq:
871 * gdbm.keys -> array
873 * Returns an array of all keys of this database.
875 static VALUE
876 fgdbm_keys(VALUE obj)
878 struct dbmdata *dbmp;
879 GDBM_FILE dbm;
880 VALUE keystr, ary;
882 GetDBM2(obj, dbmp, dbm);
883 ary = rb_ary_new();
884 for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
885 keystr = rb_gdbm_nextkey(dbm, keystr)) {
887 rb_ary_push(ary, keystr);
890 return ary;
894 * call-seq:
895 * gdbm.values -> array
897 * Returns an array of all values of this database.
899 static VALUE
900 fgdbm_values(VALUE obj)
902 datum key, nextkey;
903 struct dbmdata *dbmp;
904 GDBM_FILE dbm;
905 VALUE valstr, ary;
907 GetDBM2(obj, dbmp, dbm);
908 ary = rb_ary_new();
909 for (key = gdbm_firstkey(dbm); key.dptr; key = nextkey) {
910 nextkey = gdbm_nextkey(dbm, key);
911 valstr = rb_gdbm_fetch(dbm, key);
912 free(key.dptr);
913 rb_ary_push(ary, valstr);
916 return ary;
920 * call-seq:
921 * gdbm.has_key?(k) -> true or false
922 * gdbm.key?(k) -> true or false
924 * Returns true if the given key _k_ exists within the database.
925 * Returns false otherwise.
927 static VALUE
928 fgdbm_has_key(VALUE obj, VALUE keystr)
930 datum key;
931 struct dbmdata *dbmp;
932 GDBM_FILE dbm;
934 StringValue(keystr);
935 key.dptr = RSTRING_PTR(keystr);
936 key.dsize = RSTRING_LEN(keystr);
938 GetDBM2(obj, dbmp, dbm);
939 if (gdbm_exists(dbm, key))
940 return Qtrue;
941 return Qfalse;
945 * call-seq:
946 * gdbm.has_value?(v) -> true or false
947 * gdbm.value?(v) -> true or false
949 * Returns true if the given value _v_ exists within the database.
950 * Returns false otherwise.
952 static VALUE
953 fgdbm_has_value(VALUE obj, VALUE valstr)
955 struct dbmdata *dbmp;
956 GDBM_FILE dbm;
957 VALUE keystr, valstr2;
959 StringValue(valstr);
960 GetDBM2(obj, dbmp, dbm);
961 for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
962 keystr = rb_gdbm_nextkey(dbm, keystr)) {
964 valstr2 = rb_gdbm_fetch2(dbm, keystr);
966 if (!NIL_P(valstr2) &&
967 RSTRING_LEN(valstr) == RSTRING_LEN(valstr2) &&
968 memcmp(RSTRING_PTR(valstr), RSTRING_PTR(valstr2),
969 RSTRING_LEN(valstr)) == 0) {
970 return Qtrue;
973 return Qfalse;
977 * call-seq:
978 * gdbm.to_a -> array
980 * Returns an array of all key-value pairs contained in the database.
982 static VALUE
983 fgdbm_to_a(VALUE obj)
985 struct dbmdata *dbmp;
986 GDBM_FILE dbm;
987 VALUE keystr, ary;
989 GetDBM2(obj, dbmp, dbm);
990 ary = rb_ary_new();
991 for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
992 keystr = rb_gdbm_nextkey(dbm, keystr)) {
994 rb_ary_push(ary, rb_assoc_new(keystr, rb_gdbm_fetch2(dbm, keystr)));
997 return ary;
1001 * call-seq:
1002 * gdbm.reorganize -> gdbm
1004 * Reorganizes the database file. This operation removes reserved space of
1005 * elements that have already been deleted. It is only useful after a lot of
1006 * deletions in the database.
1008 static VALUE
1009 fgdbm_reorganize(VALUE obj)
1011 struct dbmdata *dbmp;
1012 GDBM_FILE dbm;
1014 rb_gdbm_modify(obj);
1015 GetDBM2(obj, dbmp, dbm);
1016 gdbm_reorganize(dbm);
1017 return obj;
1021 * call-seq:
1022 * gdbm.sync -> gdbm
1024 * Unless the _gdbm_ object has been opened with the *SYNC* flag, it is not
1025 * guarenteed that database modification operations are immediately applied to
1026 * the database file. This method ensures that all recent modifications
1027 * to the database are written to the file. Blocks until all writing operations
1028 * to the disk have been finished.
1030 static VALUE
1031 fgdbm_sync(VALUE obj)
1033 struct dbmdata *dbmp;
1034 GDBM_FILE dbm;
1036 rb_gdbm_modify(obj);
1037 GetDBM2(obj, dbmp, dbm);
1038 gdbm_sync(dbm);
1039 return obj;
1043 * call-seq:
1044 * gdbm.cachesize = size -> size
1046 * Sets the size of the internal bucket cache to _size_.
1048 static VALUE
1049 fgdbm_set_cachesize(VALUE obj, VALUE val)
1051 struct dbmdata *dbmp;
1052 GDBM_FILE dbm;
1053 int optval;
1055 GetDBM2(obj, dbmp, dbm);
1056 optval = FIX2INT(val);
1057 if (gdbm_setopt(dbm, GDBM_CACHESIZE, &optval, sizeof(optval)) == -1) {
1058 rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno));
1060 return val;
1064 * call-seq:
1065 * gdbm.fastmode = boolean -> boolean
1067 * Turns the database's fast mode on or off. If fast mode is turned on, gdbm
1068 * does not wait for writes to be flushed to the disk before continuing.
1070 * This option is obsolete for gdbm >= 1.8 since fast mode is turned on by
1071 * default. See also: #syncmode=
1073 static VALUE
1074 fgdbm_set_fastmode(VALUE obj, VALUE val)
1076 struct dbmdata *dbmp;
1077 GDBM_FILE dbm;
1078 int optval;
1080 GetDBM2(obj, dbmp, dbm);
1081 optval = 0;
1082 if (RTEST(val))
1083 optval = 1;
1085 if (gdbm_setopt(dbm, GDBM_FASTMODE, &optval, sizeof(optval)) == -1) {
1086 rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno));
1088 return val;
1092 * call-seq:
1093 * gdbm.syncmode = boolean -> boolean
1095 * Turns the database's synchronization mode on or off. If the synchronization
1096 * mode is turned on, the database's in-memory state will be synchronized to
1097 * disk after every database modification operation. If the synchronization
1098 * mode is turned off, GDBM does not wait for writes to be flushed to the disk
1099 * before continuing.
1101 * This option is only available for gdbm >= 1.8 where syncmode is turned off
1102 * by default. See also: #fastmode=
1104 static VALUE
1105 fgdbm_set_syncmode(VALUE obj, VALUE val)
1107 #if !defined(GDBM_SYNCMODE)
1108 fgdbm_set_fastmode(obj, RTEST(val) ? Qfalse : Qtrue);
1109 return val;
1110 #else
1111 struct dbmdata *dbmp;
1112 GDBM_FILE dbm;
1113 int optval;
1115 GetDBM2(obj, dbmp, dbm);
1116 optval = 0;
1117 if (RTEST(val))
1118 optval = 1;
1120 if (gdbm_setopt(dbm, GDBM_FASTMODE, &optval, sizeof(optval)) == -1) {
1121 rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno));
1123 return val;
1124 #endif
1128 * call-seq:
1129 * gdbm.to_hash -> hash
1131 * Returns a hash of all key-value pairs contained in the database.
1133 static VALUE
1134 fgdbm_to_hash(VALUE obj)
1136 struct dbmdata *dbmp;
1137 GDBM_FILE dbm;
1138 VALUE keystr, hash;
1140 GetDBM2(obj, dbmp, dbm);
1141 hash = rb_hash_new();
1142 for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
1143 keystr = rb_gdbm_nextkey(dbm, keystr)) {
1145 rb_hash_aset(hash, keystr, rb_gdbm_fetch2(dbm, keystr));
1148 return hash;
1152 * call-seq:
1153 * gdbm.reject { |key, value| block } -> hash
1155 * Returns a hash copy of _gdbm_ where all key-value pairs from _gdbm_ for
1156 * which _block_ evaluates to true are removed. See also: #delete_if
1158 static VALUE
1159 fgdbm_reject(VALUE obj)
1161 return rb_hash_delete_if(fgdbm_to_hash(obj));
1164 void
1165 Init_gdbm(void)
1167 rb_cGDBM = rb_define_class("GDBM", rb_cObject);
1168 rb_eGDBMError = rb_define_class("GDBMError", rb_eStandardError);
1169 rb_eGDBMFatalError = rb_define_class("GDBMFatalError", rb_eException);
1170 rb_include_module(rb_cGDBM, rb_mEnumerable);
1172 rb_define_alloc_func(rb_cGDBM, fgdbm_s_alloc);
1173 rb_define_singleton_method(rb_cGDBM, "open", fgdbm_s_open, -1);
1175 rb_define_method(rb_cGDBM, "initialize", fgdbm_initialize, -1);
1176 rb_define_method(rb_cGDBM, "close", fgdbm_close, 0);
1177 rb_define_method(rb_cGDBM, "closed?", fgdbm_closed, 0);
1178 rb_define_method(rb_cGDBM, "[]", fgdbm_aref, 1);
1179 rb_define_method(rb_cGDBM, "fetch", fgdbm_fetch_m, -1);
1180 rb_define_method(rb_cGDBM, "[]=", fgdbm_store, 2);
1181 rb_define_method(rb_cGDBM, "store", fgdbm_store, 2);
1182 rb_define_method(rb_cGDBM, "index", fgdbm_index, 1);
1183 rb_define_method(rb_cGDBM, "select", fgdbm_select, 0);
1184 rb_define_method(rb_cGDBM, "values_at", fgdbm_values_at, -1);
1185 rb_define_method(rb_cGDBM, "length", fgdbm_length, 0);
1186 rb_define_method(rb_cGDBM, "size", fgdbm_length, 0);
1187 rb_define_method(rb_cGDBM, "empty?", fgdbm_empty_p, 0);
1188 rb_define_method(rb_cGDBM, "each", fgdbm_each_pair, 0);
1189 rb_define_method(rb_cGDBM, "each_value", fgdbm_each_value, 0);
1190 rb_define_method(rb_cGDBM, "each_key", fgdbm_each_key, 0);
1191 rb_define_method(rb_cGDBM, "each_pair", fgdbm_each_pair, 0);
1192 rb_define_method(rb_cGDBM, "keys", fgdbm_keys, 0);
1193 rb_define_method(rb_cGDBM, "values", fgdbm_values, 0);
1194 rb_define_method(rb_cGDBM, "shift", fgdbm_shift, 0);
1195 rb_define_method(rb_cGDBM, "delete", fgdbm_delete, 1);
1196 rb_define_method(rb_cGDBM, "delete_if", fgdbm_delete_if, 0);
1197 rb_define_method(rb_cGDBM, "reject!", fgdbm_delete_if, 0);
1198 rb_define_method(rb_cGDBM, "reject", fgdbm_reject, 0);
1199 rb_define_method(rb_cGDBM, "clear", fgdbm_clear, 0);
1200 rb_define_method(rb_cGDBM, "invert", fgdbm_invert, 0);
1201 rb_define_method(rb_cGDBM, "update", fgdbm_update, 1);
1202 rb_define_method(rb_cGDBM, "replace", fgdbm_replace, 1);
1203 rb_define_method(rb_cGDBM, "reorganize", fgdbm_reorganize, 0);
1204 rb_define_method(rb_cGDBM, "sync", fgdbm_sync, 0);
1205 /* rb_define_method(rb_cGDBM, "setopt", fgdbm_setopt, 2); */
1206 rb_define_method(rb_cGDBM, "cachesize=", fgdbm_set_cachesize, 1);
1207 rb_define_method(rb_cGDBM, "fastmode=", fgdbm_set_fastmode, 1);
1208 rb_define_method(rb_cGDBM, "syncmode=", fgdbm_set_syncmode, 1);
1210 rb_define_method(rb_cGDBM, "include?", fgdbm_has_key, 1);
1211 rb_define_method(rb_cGDBM, "has_key?", fgdbm_has_key, 1);
1212 rb_define_method(rb_cGDBM, "member?", fgdbm_has_key, 1);
1213 rb_define_method(rb_cGDBM, "has_value?", fgdbm_has_value, 1);
1214 rb_define_method(rb_cGDBM, "key?", fgdbm_has_key, 1);
1215 rb_define_method(rb_cGDBM, "value?", fgdbm_has_value, 1);
1217 rb_define_method(rb_cGDBM, "to_a", fgdbm_to_a, 0);
1218 rb_define_method(rb_cGDBM, "to_hash", fgdbm_to_hash, 0);
1220 /* flag for #new and #open: open database as a reader */
1221 rb_define_const(rb_cGDBM, "READER", INT2FIX(GDBM_READER|RUBY_GDBM_RW_BIT));
1222 /* flag for #new and #open: open database as a writer */
1223 rb_define_const(rb_cGDBM, "WRITER", INT2FIX(GDBM_WRITER|RUBY_GDBM_RW_BIT));
1224 /* flag for #new and #open: open database as a writer; if the database does not exist, create a new one */
1225 rb_define_const(rb_cGDBM, "WRCREAT", INT2FIX(GDBM_WRCREAT|RUBY_GDBM_RW_BIT));
1226 /* flag for #new and #open: open database as a writer; overwrite any existing databases */
1227 rb_define_const(rb_cGDBM, "NEWDB", INT2FIX(GDBM_NEWDB|RUBY_GDBM_RW_BIT));
1229 /* flag for #new and #open. this flag is obsolete for gdbm >= 1.8 */
1230 rb_define_const(rb_cGDBM, "FAST", INT2FIX(GDBM_FAST));
1231 /* this flag is obsolete in gdbm 1.8.
1232 On gdbm 1.8, fast mode is default behavior. */
1234 /* gdbm version 1.8 specific */
1235 #if defined(GDBM_SYNC)
1236 /* flag for #new and #open. only for gdbm >= 1.8 */
1237 rb_define_const(rb_cGDBM, "SYNC", INT2FIX(GDBM_SYNC));
1238 #endif
1239 #if defined(GDBM_NOLOCK)
1240 /* flag for #new and #open */
1241 rb_define_const(rb_cGDBM, "NOLOCK", INT2FIX(GDBM_NOLOCK));
1242 #endif
1243 /* version of the gdbm library*/
1244 rb_define_const(rb_cGDBM, "VERSION", rb_str_new2(gdbm_version));