Ruby 2.0.0p247(2013-06-27revision41674)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

gdbm.c
Go to the documentation of this file.
1 /************************************************
2
3 gdbm.c -
4
5 $Author: nobu $
6 modified at: Mon Jan 24 15:59:52 JST 1994
7
8 Documentation by Peter Adolphs < futzilogik at users dot sourceforge dot net >
9
10 ************************************************/
11
12 #include "ruby.h"
13
14 #include <gdbm.h>
15 #include <fcntl.h>
16 #include <errno.h>
17
18 /*
19 * Document-class: GDBM
20 *
21 * == Summary
22 *
23 * Ruby extension for GNU dbm (gdbm) -- a simple database engine for storing
24 * key-value pairs on disk.
25 *
26 * == Description
27 *
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.
35 *
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.
41 *
42 * == Examples
43 *
44 * 1. Opening/creating a database, and filling it with some entries:
45 *
46 * require 'gdbm'
47 *
48 * gdbm = GDBM.new("fruitstore.db")
49 * gdbm["ananas"] = "3"
50 * gdbm["banana"] = "8"
51 * gdbm["cranberry"] = "4909"
52 * gdbm.close
53 *
54 * 2. Reading out a database:
55 *
56 * require 'gdbm'
57 *
58 * gdbm = GDBM.new("fruitstore.db")
59 * gdbm.each_pair do |key, value|
60 * print "#{key}: #{value}\n"
61 * end
62 * gdbm.close
63 *
64 * produces
65 *
66 * banana: 8
67 * ananas: 3
68 * cranberry: 4909
69 *
70 * == Links
71 *
72 * * http://www.gnu.org/software/gdbm/
73 */
74 static VALUE rb_cGDBM, rb_eGDBMError, rb_eGDBMFatalError;
75
76 #if SIZEOF_LONG > SIZEOF_INT
77 #define TOO_LONG(n) ((long)(+(int)(n)) != (long)(n))
78 #else
79 #define TOO_LONG(n) 0
80 #endif
81
82 #define RUBY_GDBM_RW_BIT 0x20000000
83
84 #define MY_BLOCK_SIZE (2048)
85 #define MY_FATAL_FUNC rb_gdbm_fatal
86 static void
87 rb_gdbm_fatal(const char *msg)
88 {
89 rb_raise(rb_eGDBMFatalError, "%s", msg);
90 }
91
92 struct dbmdata {
93 int di_size;
94 GDBM_FILE di_dbm;
95 };
96
97 static void
98 closed_dbm(void)
99 {
100 rb_raise(rb_eRuntimeError, "closed GDBM file");
101 }
102
103 #define GetDBM(obj, dbmp) do {\
104 Data_Get_Struct((obj), struct dbmdata, (dbmp));\
105 if ((dbmp) == 0) closed_dbm();\
106 if ((dbmp)->di_dbm == 0) closed_dbm();\
107 } while (0)
108
109 #define GetDBM2(obj, data, dbm) {\
110 GetDBM((obj), (data));\
111 (dbm) = dbmp->di_dbm;\
112 }
113
114 static void
115 free_dbm(struct dbmdata *dbmp)
116 {
117 if (dbmp) {
118 if (dbmp->di_dbm) gdbm_close(dbmp->di_dbm);
119 xfree(dbmp);
120 }
121 }
122
123 /*
124 * call-seq:
125 * gdbm.close -> nil
126 *
127 * Closes the associated database file.
128 */
129 static VALUE
130 fgdbm_close(VALUE obj)
131 {
132 struct dbmdata *dbmp;
133
134 GetDBM(obj, dbmp);
135 gdbm_close(dbmp->di_dbm);
136 dbmp->di_dbm = 0;
137
138 return Qnil;
139 }
140
141 /*
142 * call-seq:
143 * gdbm.closed? -> true or false
144 *
145 * Returns true if the associated database file has been closed.
146 */
147 static VALUE
148 fgdbm_closed(VALUE obj)
149 {
150 struct dbmdata *dbmp;
151
152 Data_Get_Struct(obj, struct dbmdata, dbmp);
153 if (dbmp == 0)
154 return Qtrue;
155 if (dbmp->di_dbm == 0)
156 return Qtrue;
157
158 return Qfalse;
159 }
160
161 static VALUE
162 fgdbm_s_alloc(VALUE klass)
163 {
164 return Data_Wrap_Struct(klass, 0, free_dbm, 0);
165 }
166
167 /*
168 * call-seq:
169 * GDBM.new(filename, mode = 0666, flags = nil)
170 *
171 * Creates a new GDBM instance by opening a gdbm file named _filename_.
172 * If the file does not exist, a new file with file mode _mode_ will be
173 * created. _flags_ may be one of the following:
174 * * *READER* - open as a reader
175 * * *WRITER* - open as a writer
176 * * *WRCREAT* - open as a writer; if the database does not exist, create a new one
177 * * *NEWDB* - open as a writer; overwrite any existing databases
178 *
179 * The values *WRITER*, *WRCREAT* and *NEWDB* may be combined with the following
180 * values by bitwise or:
181 * * *SYNC* - cause all database operations to be synchronized to the disk
182 * * *NOLOCK* - do not lock the database file
183 *
184 * If no _flags_ are specified, the GDBM object will try to open the database
185 * file as a writer and will create it if it does not already exist
186 * (cf. flag <tt>WRCREAT</tt>). If this fails (for instance, if another process
187 * has already opened the database as a reader), it will try to open the
188 * database file as a reader (cf. flag <tt>READER</tt>).
189 */
190 static VALUE
191 fgdbm_initialize(int argc, VALUE *argv, VALUE obj)
192 {
193 VALUE file, vmode, vflags;
194 GDBM_FILE dbm;
195 struct dbmdata *dbmp;
196 int mode, flags = 0;
197
198 if (rb_scan_args(argc, argv, "12", &file, &vmode, &vflags) == 1) {
199 mode = 0666; /* default value */
200 }
201 else if (NIL_P(vmode)) {
202 mode = -1; /* return nil if DB does not exist */
203 }
204 else {
205 mode = NUM2INT(vmode);
206 }
207
208 if (!NIL_P(vflags))
209 flags = NUM2INT(vflags);
210
211 SafeStringValue(file);
212
213 #ifdef GDBM_CLOEXEC
214 /* GDBM_CLOEXEC is available since gdbm 1.10. */
215 flags |= GDBM_CLOEXEC;
216 #endif
217
218 if (flags & RUBY_GDBM_RW_BIT) {
219 flags &= ~RUBY_GDBM_RW_BIT;
220 dbm = gdbm_open(RSTRING_PTR(file), MY_BLOCK_SIZE,
221 flags, mode, MY_FATAL_FUNC);
222 }
223 else {
224 dbm = 0;
225 if (mode >= 0)
226 dbm = gdbm_open(RSTRING_PTR(file), MY_BLOCK_SIZE,
227 GDBM_WRCREAT|flags, mode, MY_FATAL_FUNC);
228 if (!dbm)
229 dbm = gdbm_open(RSTRING_PTR(file), MY_BLOCK_SIZE,
230 GDBM_WRITER|flags, 0, MY_FATAL_FUNC);
231 if (!dbm)
232 dbm = gdbm_open(RSTRING_PTR(file), MY_BLOCK_SIZE,
233 GDBM_READER|flags, 0, MY_FATAL_FUNC);
234 }
235
236 if (dbm) {
237 rb_fd_fix_cloexec(gdbm_fdesc(dbm));
238 }
239
240 if (!dbm) {
241 if (mode == -1) return Qnil;
242
243 if (gdbm_errno == GDBM_FILE_OPEN_ERROR ||
244 gdbm_errno == GDBM_CANT_BE_READER ||
245 gdbm_errno == GDBM_CANT_BE_WRITER)
246 rb_sys_fail_str(file);
247 else
248 rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno));
249 }
250
251 dbmp = ALLOC(struct dbmdata);
252 free_dbm(DATA_PTR(obj));
253 DATA_PTR(obj) = dbmp;
254 dbmp->di_dbm = dbm;
255 dbmp->di_size = -1;
256
257 return obj;
258 }
259
260 /*
261 * call-seq:
262 * GDBM.open(filename, mode = 0666, flags = nil)
263 * GDBM.open(filename, mode = 0666, flags = nil) { |gdbm| ... }
264 *
265 * If called without a block, this is synonymous to GDBM::new.
266 * If a block is given, the new GDBM instance will be passed to the block
267 * as a parameter, and the corresponding database file will be closed
268 * after the execution of the block code has been finished.
269 *
270 * Example for an open call with a block:
271 *
272 * require 'gdbm'
273 * GDBM.open("fruitstore.db") do |gdbm|
274 * gdbm.each_pair do |key, value|
275 * print "#{key}: #{value}\n"
276 * end
277 * end
278 */
279 static VALUE
280 fgdbm_s_open(int argc, VALUE *argv, VALUE klass)
281 {
282 VALUE obj = Data_Wrap_Struct(klass, 0, free_dbm, 0);
283
284 if (NIL_P(fgdbm_initialize(argc, argv, obj))) {
285 return Qnil;
286 }
287
288 if (rb_block_given_p()) {
289 return rb_ensure(rb_yield, obj, fgdbm_close, obj);
290 }
291
292 return obj;
293 }
294
295 static VALUE
296 rb_gdbm_fetch(GDBM_FILE dbm, datum key)
297 {
298 datum val;
299 VALUE str;
300
301 val = gdbm_fetch(dbm, key);
302 if (val.dptr == 0)
303 return Qnil;
304
305 str = rb_str_new(val.dptr, val.dsize);
306 free(val.dptr);
307 OBJ_TAINT(str);
308 return str;
309 }
310
311 static VALUE
312 rb_gdbm_fetch2(GDBM_FILE dbm, VALUE keystr)
313 {
314 datum key;
315 long len;
316
317 StringValue(keystr);
318 len = RSTRING_LEN(keystr);
319 if (TOO_LONG(len)) return Qnil;
320 key.dptr = RSTRING_PTR(keystr);
321 key.dsize = (int)len;
322
323 return rb_gdbm_fetch(dbm, key);
324 }
325
326 static VALUE
327 rb_gdbm_fetch3(VALUE obj, VALUE keystr)
328 {
329 struct dbmdata *dbmp;
330 GDBM_FILE dbm;
331
332 GetDBM2(obj, dbmp, dbm);
333 return rb_gdbm_fetch2(dbm, keystr);
334 }
335
336 static VALUE
337 rb_gdbm_firstkey(GDBM_FILE dbm)
338 {
339 datum key;
340 VALUE str;
341
342 key = gdbm_firstkey(dbm);
343 if (key.dptr == 0)
344 return Qnil;
345
346 str = rb_str_new(key.dptr, key.dsize);
347 free(key.dptr);
348 OBJ_TAINT(str);
349 return str;
350 }
351
352 static VALUE
353 rb_gdbm_nextkey(GDBM_FILE dbm, VALUE keystr)
354 {
355 datum key, key2;
356 VALUE str;
357 long len;
358
359 len = RSTRING_LEN(keystr);
360 if (TOO_LONG(len)) return Qnil;
361 key.dptr = RSTRING_PTR(keystr);
362 key.dsize = (int)len;
363 key2 = gdbm_nextkey(dbm, key);
364 if (key2.dptr == 0)
365 return Qnil;
366
367 str = rb_str_new(key2.dptr, key2.dsize);
368 free(key2.dptr);
369 OBJ_TAINT(str);
370 return str;
371 }
372
373 static VALUE
374 fgdbm_fetch(VALUE obj, VALUE keystr, VALUE ifnone)
375 {
376 VALUE valstr;
377
378 valstr = rb_gdbm_fetch3(obj, keystr);
379 if (NIL_P(valstr)) {
380 if (ifnone == Qnil && rb_block_given_p())
381 return rb_yield(keystr);
382 return ifnone;
383 }
384 return valstr;
385 }
386
387 /*
388 * call-seq:
389 * gdbm[key] -> value
390 *
391 * Retrieves the _value_ corresponding to _key_.
392 */
393 static VALUE
394 fgdbm_aref(VALUE obj, VALUE keystr)
395 {
396 return rb_gdbm_fetch3(obj, keystr);
397 }
398
399 /*
400 * call-seq:
401 * gdbm.fetch(key [, default]) -> value
402 *
403 * Retrieves the _value_ corresponding to _key_. If there is no value
404 * associated with _key_, _default_ will be returned instead.
405 */
406 static VALUE
407 fgdbm_fetch_m(int argc, VALUE *argv, VALUE obj)
408 {
409 VALUE keystr, valstr, ifnone;
410
411 rb_scan_args(argc, argv, "11", &keystr, &ifnone);
412 valstr = fgdbm_fetch(obj, keystr, ifnone);
413 if (argc == 1 && !rb_block_given_p() && NIL_P(valstr))
414 rb_raise(rb_eIndexError, "key not found");
415
416 return valstr;
417 }
418
419 /*
420 * call-seq:
421 * gdbm.key(value) -> key
422 *
423 * Returns the _key_ for a given _value_. If several keys may map to the
424 * same value, the key that is found first will be returned.
425 */
426 static VALUE
427 fgdbm_key(VALUE obj, VALUE valstr)
428 {
429 struct dbmdata *dbmp;
430 GDBM_FILE dbm;
431 VALUE keystr, valstr2;
432
433 StringValue(valstr);
434 GetDBM2(obj, dbmp, dbm);
435 for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
436 keystr = rb_gdbm_nextkey(dbm, keystr)) {
437
438 valstr2 = rb_gdbm_fetch2(dbm, keystr);
439 if (!NIL_P(valstr2) &&
440 (int)RSTRING_LEN(valstr) == (int)RSTRING_LEN(valstr2) &&
441 memcmp(RSTRING_PTR(valstr), RSTRING_PTR(valstr2),
442 (int)RSTRING_LEN(valstr)) == 0) {
443 return keystr;
444 }
445 }
446 return Qnil;
447 }
448
449 /* :nodoc: */
450 static VALUE
451 fgdbm_index(VALUE obj, VALUE value)
452 {
453 rb_warn("GDBM#index is deprecated; use GDBM#key");
454 return fgdbm_key(obj, value);
455 }
456
457 /*
458 * call-seq:
459 * gdbm.select { |key, value| block } -> array
460 *
461 * Returns a new array of all key-value pairs of the database for which _block_
462 * evaluates to true.
463 */
464 static VALUE
465 fgdbm_select(VALUE obj)
466 {
467 VALUE new = rb_ary_new();
468 GDBM_FILE dbm;
469 struct dbmdata *dbmp;
470 VALUE keystr;
471
472 GetDBM2(obj, dbmp, dbm);
473 for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
474 keystr = rb_gdbm_nextkey(dbm, keystr)) {
475 VALUE assoc = rb_assoc_new(keystr, rb_gdbm_fetch2(dbm, keystr));
476 VALUE v = rb_yield(assoc);
477
478 if (RTEST(v)) {
479 rb_ary_push(new, assoc);
480 }
481 GetDBM2(obj, dbmp, dbm);
482 }
483
484 return new;
485 }
486
487 /*
488 * call-seq:
489 * gdbm.values_at(key, ...) -> array
490 *
491 * Returns an array of the values associated with each specified _key_.
492 */
493 static VALUE
494 fgdbm_values_at(int argc, VALUE *argv, VALUE obj)
495 {
496 VALUE new = rb_ary_new2(argc);
497 int i;
498
499 for (i=0; i<argc; i++) {
500 rb_ary_push(new, rb_gdbm_fetch3(obj, argv[i]));
501 }
502
503 return new;
504 }
505
506 static void
507 rb_gdbm_modify(VALUE obj)
508 {
509 rb_secure(4);
510 if (OBJ_FROZEN(obj)) rb_error_frozen("GDBM");
511 }
512
513 static VALUE
514 rb_gdbm_delete(VALUE obj, VALUE keystr)
515 {
516 datum key;
517 struct dbmdata *dbmp;
518 GDBM_FILE dbm;
519 long len;
520
521 rb_gdbm_modify(obj);
522 StringValue(keystr);
523 len = RSTRING_LEN(keystr);
524 if (TOO_LONG(len)) return Qnil;
525 key.dptr = RSTRING_PTR(keystr);
526 key.dsize = (int)len;
527
528 GetDBM2(obj, dbmp, dbm);
529 if (!gdbm_exists(dbm, key)) {
530 return Qnil;
531 }
532
533 if (gdbm_delete(dbm, key)) {
534 dbmp->di_size = -1;
535 rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno));
536 }
537 else if (dbmp->di_size >= 0) {
538 dbmp->di_size--;
539 }
540 return obj;
541 }
542
543 /*
544 * call-seq:
545 * gdbm.delete(key) -> value or nil
546 *
547 * Removes the key-value-pair with the specified _key_ from this database and
548 * returns the corresponding _value_. Returns nil if the database is empty.
549 */
550 static VALUE
551 fgdbm_delete(VALUE obj, VALUE keystr)
552 {
553 VALUE valstr;
554
555 valstr = fgdbm_fetch(obj, keystr, Qnil);
556 rb_gdbm_delete(obj, keystr);
557 return valstr;
558 }
559
560 /*
561 * call-seq:
562 * gdbm.shift -> (key, value) or nil
563 *
564 * Removes a key-value-pair from this database and returns it as a
565 * two-item array [ _key_, _value_ ]. Returns nil if the database is empty.
566 */
567 static VALUE
568 fgdbm_shift(VALUE obj)
569 {
570 struct dbmdata *dbmp;
571 GDBM_FILE dbm;
572 VALUE keystr, valstr;
573
574 rb_gdbm_modify(obj);
575 GetDBM2(obj, dbmp, dbm);
576 keystr = rb_gdbm_firstkey(dbm);
577 if (NIL_P(keystr)) return Qnil;
578 valstr = rb_gdbm_fetch2(dbm, keystr);
579 rb_gdbm_delete(obj, keystr);
580
581 return rb_assoc_new(keystr, valstr);
582 }
583
584 /*
585 * call-seq:
586 * gdbm.delete_if { |key, value| block } -> gdbm
587 * gdbm.reject! { |key, value| block } -> gdbm
588 *
589 * Deletes every key-value pair from _gdbm_ for which _block_ evaluates to true.
590 */
591 static VALUE
592 fgdbm_delete_if(VALUE obj)
593 {
594 struct dbmdata *dbmp;
595 GDBM_FILE dbm;
596 VALUE keystr, valstr;
597 VALUE ret, ary = rb_ary_tmp_new(0);
598 int i, status = 0, n;
599
600 rb_gdbm_modify(obj);
601 GetDBM2(obj, dbmp, dbm);
602 n = dbmp->di_size;
603 dbmp->di_size = -1;
604
605 for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
606 keystr = rb_gdbm_nextkey(dbm, keystr)) {
607
608 OBJ_FREEZE(keystr);
609 valstr = rb_gdbm_fetch2(dbm, keystr);
610 ret = rb_protect(rb_yield, rb_assoc_new(rb_str_dup(keystr), valstr), &status);
611 if (status != 0) break;
612 if (RTEST(ret)) rb_ary_push(ary, keystr);
613 GetDBM2(obj, dbmp, dbm);
614 }
615
616 for (i = 0; i < RARRAY_LEN(ary); i++)
617 rb_gdbm_delete(obj, RARRAY_PTR(ary)[i]);
618 if (status) rb_jump_tag(status);
619 if (n > 0) dbmp->di_size = n - (int)RARRAY_LEN(ary);
620 rb_ary_clear(ary);
621
622 return obj;
623 }
624
625 /*
626 * call-seq:
627 * gdbm.clear -> gdbm
628 *
629 * Removes all the key-value pairs within _gdbm_.
630 */
631 static VALUE
632 fgdbm_clear(VALUE obj)
633 {
634 datum key, nextkey;
635 struct dbmdata *dbmp;
636 GDBM_FILE dbm;
637
638 rb_gdbm_modify(obj);
639 GetDBM2(obj, dbmp, dbm);
640 dbmp->di_size = -1;
641
642 #if 0
643 while (key = gdbm_firstkey(dbm), key.dptr) {
644 if (gdbm_delete(dbm, key)) {
645 free(key.dptr);
646 rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno));
647 }
648 free(key.dptr);
649 }
650 #else
651 while (key = gdbm_firstkey(dbm), key.dptr) {
652 for (; key.dptr; key = nextkey) {
653 nextkey = gdbm_nextkey(dbm, key);
654 if (gdbm_delete(dbm, key)) {
655 free(key.dptr);
656 if (nextkey.dptr) free(nextkey.dptr);
657 rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno));
658 }
659 free(key.dptr);
660 }
661 }
662 #endif
663 dbmp->di_size = 0;
664
665 return obj;
666 }
667
668 /*
669 * call-seq:
670 * gdbm.invert -> hash
671 *
672 * Returns a hash created by using _gdbm_'s values as keys, and the keys
673 * as values.
674 */
675 static VALUE
676 fgdbm_invert(VALUE obj)
677 {
678 struct dbmdata *dbmp;
679 GDBM_FILE dbm;
680 VALUE keystr, valstr;
681 VALUE hash = rb_hash_new();
682
683 GetDBM2(obj, dbmp, dbm);
684 for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
685 keystr = rb_gdbm_nextkey(dbm, keystr)) {
686 valstr = rb_gdbm_fetch2(dbm, keystr);
687
688 rb_hash_aset(hash, valstr, keystr);
689 }
690 return hash;
691 }
692
693 /*
694 * call-seq:
695 * gdbm[key]= value -> value
696 * gdbm.store(key, value) -> value
697 *
698 * Associates the value _value_ with the specified _key_.
699 */
700 static VALUE
701 fgdbm_store(VALUE obj, VALUE keystr, VALUE valstr)
702 {
703 datum key, val;
704 struct dbmdata *dbmp;
705 GDBM_FILE dbm;
706
707 rb_gdbm_modify(obj);
708 StringValue(keystr);
709 StringValue(valstr);
710
711 key.dptr = RSTRING_PTR(keystr);
712 key.dsize = RSTRING_LENINT(keystr);
713
714 val.dptr = RSTRING_PTR(valstr);
715 val.dsize = RSTRING_LENINT(valstr);
716
717 GetDBM2(obj, dbmp, dbm);
718 dbmp->di_size = -1;
719 if (gdbm_store(dbm, key, val, GDBM_REPLACE)) {
720 if (errno == EPERM) rb_sys_fail(0);
721 rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno));
722 }
723
724 return valstr;
725 }
726
727 static VALUE
728 update_i(VALUE pair, VALUE dbm)
729 {
730 Check_Type(pair, T_ARRAY);
731 if (RARRAY_LEN(pair) < 2) {
732 rb_raise(rb_eArgError, "pair must be [key, value]");
733 }
734 fgdbm_store(dbm, RARRAY_PTR(pair)[0], RARRAY_PTR(pair)[1]);
735 return Qnil;
736 }
737
738 /*
739 * call-seq:
740 * gdbm.update(other) -> gdbm
741 *
742 * Adds the key-value pairs of _other_ to _gdbm_, overwriting entries with
743 * duplicate keys with those from _other_. _other_ must have an each_pair
744 * method.
745 */
746 static VALUE
747 fgdbm_update(VALUE obj, VALUE other)
748 {
749 rb_block_call(other, rb_intern("each_pair"), 0, 0, update_i, obj);
750 return obj;
751 }
752
753 /*
754 * call-seq:
755 * gdbm.replace(other) -> gdbm
756 *
757 * Replaces the content of _gdbm_ with the key-value pairs of _other_.
758 * _other_ must have an each_pair method.
759 */
760 static VALUE
761 fgdbm_replace(VALUE obj, VALUE other)
762 {
763 fgdbm_clear(obj);
764 rb_block_call(other, rb_intern("each_pair"), 0, 0, update_i, obj);
765 return obj;
766 }
767
768 /*
769 * call-seq:
770 * gdbm.length -> fixnum
771 * gdbm.size -> fixnum
772 *
773 * Returns the number of key-value pairs in this database.
774 */
775 static VALUE
776 fgdbm_length(VALUE obj)
777 {
778 datum key, nextkey;
779 struct dbmdata *dbmp;
780 GDBM_FILE dbm;
781 int i = 0;
782
783 GetDBM2(obj, dbmp, dbm);
784 if (dbmp->di_size > 0) return INT2FIX(dbmp->di_size);
785
786 for (key = gdbm_firstkey(dbm); key.dptr; key = nextkey) {
787 nextkey = gdbm_nextkey(dbm, key);
788 free(key.dptr);
789 i++;
790 }
791 dbmp->di_size = i;
792
793 return INT2FIX(i);
794 }
795
796 /*
797 * call-seq:
798 * gdbm.empty? -> true or false
799 *
800 * Returns true if the database is empty.
801 */
802 static VALUE
803 fgdbm_empty_p(VALUE obj)
804 {
805 datum key;
806 struct dbmdata *dbmp;
807 GDBM_FILE dbm;
808
809 GetDBM(obj, dbmp);
810 if (dbmp->di_size < 0) {
811 dbm = dbmp->di_dbm;
812
813 key = gdbm_firstkey(dbm);
814 if (key.dptr) {
815 free(key.dptr);
816 return Qfalse;
817 }
818 return Qtrue;
819 }
820
821 if (dbmp->di_size == 0) return Qtrue;
822 return Qfalse;
823 }
824
825 /*
826 * call-seq:
827 * gdbm.each_value { |value| block } -> gdbm
828 *
829 * Executes _block_ for each key in the database, passing the corresponding
830 * _value_ as a parameter.
831 */
832 static VALUE
833 fgdbm_each_value(VALUE obj)
834 {
835 struct dbmdata *dbmp;
836 GDBM_FILE dbm;
837 VALUE keystr;
838
839 RETURN_ENUMERATOR(obj, 0, 0);
840
841 GetDBM2(obj, dbmp, dbm);
842 for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
843 keystr = rb_gdbm_nextkey(dbm, keystr)) {
844
845 rb_yield(rb_gdbm_fetch2(dbm, keystr));
846 GetDBM2(obj, dbmp, dbm);
847 }
848 return obj;
849 }
850
851 /*
852 * call-seq:
853 * gdbm.each_key { |key| block } -> gdbm
854 *
855 * Executes _block_ for each key in the database, passing the
856 * _key_ as a parameter.
857 */
858 static VALUE
859 fgdbm_each_key(VALUE obj)
860 {
861 struct dbmdata *dbmp;
862 GDBM_FILE dbm;
863 VALUE keystr;
864
865 RETURN_ENUMERATOR(obj, 0, 0);
866
867 GetDBM2(obj, dbmp, dbm);
868 for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
869 keystr = rb_gdbm_nextkey(dbm, keystr)) {
870
871 rb_yield(keystr);
872 GetDBM2(obj, dbmp, dbm);
873 }
874 return obj;
875 }
876
877 /*
878 * call-seq:
879 * gdbm.each_pair { |key, value| block } -> gdbm
880 *
881 * Executes _block_ for each key in the database, passing the _key_ and the
882 * correspoding _value_ as a parameter.
883 */
884 static VALUE
885 fgdbm_each_pair(VALUE obj)
886 {
887 GDBM_FILE dbm;
888 struct dbmdata *dbmp;
889 VALUE keystr;
890
891 RETURN_ENUMERATOR(obj, 0, 0);
892
893 GetDBM2(obj, dbmp, dbm);
894 for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
895 keystr = rb_gdbm_nextkey(dbm, keystr)) {
896
897 rb_yield(rb_assoc_new(keystr, rb_gdbm_fetch2(dbm, keystr)));
898 GetDBM2(obj, dbmp, dbm);
899 }
900
901 return obj;
902 }
903
904 /*
905 * call-seq:
906 * gdbm.keys -> array
907 *
908 * Returns an array of all keys of this database.
909 */
910 static VALUE
911 fgdbm_keys(VALUE obj)
912 {
913 struct dbmdata *dbmp;
914 GDBM_FILE dbm;
915 VALUE keystr, ary;
916
917 GetDBM2(obj, dbmp, dbm);
918 ary = rb_ary_new();
919 for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
920 keystr = rb_gdbm_nextkey(dbm, keystr)) {
921
922 rb_ary_push(ary, keystr);
923 }
924
925 return ary;
926 }
927
928 /*
929 * call-seq:
930 * gdbm.values -> array
931 *
932 * Returns an array of all values of this database.
933 */
934 static VALUE
935 fgdbm_values(VALUE obj)
936 {
937 datum key, nextkey;
938 struct dbmdata *dbmp;
939 GDBM_FILE dbm;
940 VALUE valstr, ary;
941
942 GetDBM2(obj, dbmp, dbm);
943 ary = rb_ary_new();
944 for (key = gdbm_firstkey(dbm); key.dptr; key = nextkey) {
945 nextkey = gdbm_nextkey(dbm, key);
946 valstr = rb_gdbm_fetch(dbm, key);
947 free(key.dptr);
948 rb_ary_push(ary, valstr);
949 }
950
951 return ary;
952 }
953
954 /*
955 * call-seq:
956 * gdbm.has_key?(k) -> true or false
957 * gdbm.key?(k) -> true or false
958 *
959 * Returns true if the given key _k_ exists within the database.
960 * Returns false otherwise.
961 */
962 static VALUE
963 fgdbm_has_key(VALUE obj, VALUE keystr)
964 {
965 datum key;
966 struct dbmdata *dbmp;
967 GDBM_FILE dbm;
968 long len;
969
970 StringValue(keystr);
971 len = RSTRING_LENINT(keystr);
972 if (TOO_LONG(len)) return Qfalse;
973 key.dptr = RSTRING_PTR(keystr);
974 key.dsize = (int)len;
975
976 GetDBM2(obj, dbmp, dbm);
977 if (gdbm_exists(dbm, key))
978 return Qtrue;
979 return Qfalse;
980 }
981
982 /*
983 * call-seq:
984 * gdbm.has_value?(v) -> true or false
985 * gdbm.value?(v) -> true or false
986 *
987 * Returns true if the given value _v_ exists within the database.
988 * Returns false otherwise.
989 */
990 static VALUE
991 fgdbm_has_value(VALUE obj, VALUE valstr)
992 {
993 struct dbmdata *dbmp;
994 GDBM_FILE dbm;
995 VALUE keystr, valstr2;
996
997 StringValue(valstr);
998 GetDBM2(obj, dbmp, dbm);
999 for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
1000 keystr = rb_gdbm_nextkey(dbm, keystr)) {
1001
1002 valstr2 = rb_gdbm_fetch2(dbm, keystr);
1003
1004 if (!NIL_P(valstr2) &&
1005 (int)RSTRING_LEN(valstr) == (int)RSTRING_LEN(valstr2) &&
1006 memcmp(RSTRING_PTR(valstr), RSTRING_PTR(valstr2),
1007 (int)RSTRING_LEN(valstr)) == 0) {
1008 return Qtrue;
1009 }
1010 }
1011 return Qfalse;
1012 }
1013
1014 /*
1015 * call-seq:
1016 * gdbm.to_a -> array
1017 *
1018 * Returns an array of all key-value pairs contained in the database.
1019 */
1020 static VALUE
1021 fgdbm_to_a(VALUE obj)
1022 {
1023 struct dbmdata *dbmp;
1024 GDBM_FILE dbm;
1025 VALUE keystr, ary;
1026
1027 GetDBM2(obj, dbmp, dbm);
1028 ary = rb_ary_new();
1029 for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
1030 keystr = rb_gdbm_nextkey(dbm, keystr)) {
1031
1032 rb_ary_push(ary, rb_assoc_new(keystr, rb_gdbm_fetch2(dbm, keystr)));
1033 }
1034
1035 return ary;
1036 }
1037
1038 /*
1039 * call-seq:
1040 * gdbm.reorganize -> gdbm
1041 *
1042 * Reorganizes the database file. This operation removes reserved space of
1043 * elements that have already been deleted. It is only useful after a lot of
1044 * deletions in the database.
1045 */
1046 static VALUE
1047 fgdbm_reorganize(VALUE obj)
1048 {
1049 struct dbmdata *dbmp;
1050 GDBM_FILE dbm;
1051
1052 rb_gdbm_modify(obj);
1053 GetDBM2(obj, dbmp, dbm);
1054 gdbm_reorganize(dbm);
1055 rb_fd_fix_cloexec(gdbm_fdesc(dbm));
1056 return obj;
1057 }
1058
1059 /*
1060 * call-seq:
1061 * gdbm.sync -> gdbm
1062 *
1063 * Unless the _gdbm_ object has been opened with the *SYNC* flag, it is not
1064 * guarenteed that database modification operations are immediately applied to
1065 * the database file. This method ensures that all recent modifications
1066 * to the database are written to the file. Blocks until all writing operations
1067 * to the disk have been finished.
1068 */
1069 static VALUE
1070 fgdbm_sync(VALUE obj)
1071 {
1072 struct dbmdata *dbmp;
1073 GDBM_FILE dbm;
1074
1075 rb_gdbm_modify(obj);
1076 GetDBM2(obj, dbmp, dbm);
1077 gdbm_sync(dbm);
1078 return obj;
1079 }
1080
1081 /*
1082 * call-seq:
1083 * gdbm.cachesize = size -> size
1084 *
1085 * Sets the size of the internal bucket cache to _size_.
1086 */
1087 static VALUE
1088 fgdbm_set_cachesize(VALUE obj, VALUE val)
1089 {
1090 struct dbmdata *dbmp;
1091 GDBM_FILE dbm;
1092 int optval;
1093
1094 GetDBM2(obj, dbmp, dbm);
1095 optval = FIX2INT(val);
1096 if (gdbm_setopt(dbm, GDBM_CACHESIZE, &optval, sizeof(optval)) == -1) {
1097 rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno));
1098 }
1099 return val;
1100 }
1101
1102 /*
1103 * call-seq:
1104 * gdbm.fastmode = boolean -> boolean
1105 *
1106 * Turns the database's fast mode on or off. If fast mode is turned on, gdbm
1107 * does not wait for writes to be flushed to the disk before continuing.
1108 *
1109 * This option is obsolete for gdbm >= 1.8 since fast mode is turned on by
1110 * default. See also: #syncmode=
1111 */
1112 static VALUE
1113 fgdbm_set_fastmode(VALUE obj, VALUE val)
1114 {
1115 struct dbmdata *dbmp;
1116 GDBM_FILE dbm;
1117 int optval;
1118
1119 GetDBM2(obj, dbmp, dbm);
1120 optval = 0;
1121 if (RTEST(val))
1122 optval = 1;
1123
1124 if (gdbm_setopt(dbm, GDBM_FASTMODE, &optval, sizeof(optval)) == -1) {
1125 rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno));
1126 }
1127 return val;
1128 }
1129
1130 /*
1131 * call-seq:
1132 * gdbm.syncmode = boolean -> boolean
1133 *
1134 * Turns the database's synchronization mode on or off. If the synchronization
1135 * mode is turned on, the database's in-memory state will be synchronized to
1136 * disk after every database modification operation. If the synchronization
1137 * mode is turned off, GDBM does not wait for writes to be flushed to the disk
1138 * before continuing.
1139 *
1140 * This option is only available for gdbm >= 1.8 where syncmode is turned off
1141 * by default. See also: #fastmode=
1142 */
1143 static VALUE
1144 fgdbm_set_syncmode(VALUE obj, VALUE val)
1145 {
1146 #if !defined(GDBM_SYNCMODE)
1147 fgdbm_set_fastmode(obj, RTEST(val) ? Qfalse : Qtrue);
1148 return val;
1149 #else
1150 struct dbmdata *dbmp;
1151 GDBM_FILE dbm;
1152 int optval;
1153
1154 GetDBM2(obj, dbmp, dbm);
1155 optval = 0;
1156 if (RTEST(val))
1157 optval = 1;
1158
1159 if (gdbm_setopt(dbm, GDBM_FASTMODE, &optval, sizeof(optval)) == -1) {
1160 rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno));
1161 }
1162 return val;
1163 #endif
1164 }
1165
1166 /*
1167 * call-seq:
1168 * gdbm.to_hash -> hash
1169 *
1170 * Returns a hash of all key-value pairs contained in the database.
1171 */
1172 static VALUE
1173 fgdbm_to_hash(VALUE obj)
1174 {
1175 struct dbmdata *dbmp;
1176 GDBM_FILE dbm;
1177 VALUE keystr, hash;
1178
1179 GetDBM2(obj, dbmp, dbm);
1180 hash = rb_hash_new();
1181 for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
1182 keystr = rb_gdbm_nextkey(dbm, keystr)) {
1183
1184 rb_hash_aset(hash, keystr, rb_gdbm_fetch2(dbm, keystr));
1185 }
1186
1187 return hash;
1188 }
1189
1190 /*
1191 * call-seq:
1192 * gdbm.reject { |key, value| block } -> hash
1193 *
1194 * Returns a hash copy of _gdbm_ where all key-value pairs from _gdbm_ for
1195 * which _block_ evaluates to true are removed. See also: #delete_if
1196 */
1197 static VALUE
1198 fgdbm_reject(VALUE obj)
1199 {
1200 return rb_hash_delete_if(fgdbm_to_hash(obj));
1201 }
1202
1203 void
1204 Init_gdbm(void)
1205 {
1206 rb_cGDBM = rb_define_class("GDBM", rb_cObject);
1207 rb_eGDBMError = rb_define_class("GDBMError", rb_eStandardError);
1208 rb_eGDBMFatalError = rb_define_class("GDBMFatalError", rb_eException);
1209 rb_include_module(rb_cGDBM, rb_mEnumerable);
1210
1211 rb_define_alloc_func(rb_cGDBM, fgdbm_s_alloc);
1212 rb_define_singleton_method(rb_cGDBM, "open", fgdbm_s_open, -1);
1213
1214 rb_define_method(rb_cGDBM, "initialize", fgdbm_initialize, -1);
1215 rb_define_method(rb_cGDBM, "close", fgdbm_close, 0);
1216 rb_define_method(rb_cGDBM, "closed?", fgdbm_closed, 0);
1217 rb_define_method(rb_cGDBM, "[]", fgdbm_aref, 1);
1218 rb_define_method(rb_cGDBM, "fetch", fgdbm_fetch_m, -1);
1219 rb_define_method(rb_cGDBM, "[]=", fgdbm_store, 2);
1220 rb_define_method(rb_cGDBM, "store", fgdbm_store, 2);
1221 rb_define_method(rb_cGDBM, "index", fgdbm_index, 1);
1222 rb_define_method(rb_cGDBM, "key", fgdbm_key, 1);
1223 rb_define_method(rb_cGDBM, "select", fgdbm_select, 0);
1224 rb_define_method(rb_cGDBM, "values_at", fgdbm_values_at, -1);
1225 rb_define_method(rb_cGDBM, "length", fgdbm_length, 0);
1226 rb_define_method(rb_cGDBM, "size", fgdbm_length, 0);
1227 rb_define_method(rb_cGDBM, "empty?", fgdbm_empty_p, 0);
1228 rb_define_method(rb_cGDBM, "each", fgdbm_each_pair, 0);
1229 rb_define_method(rb_cGDBM, "each_value", fgdbm_each_value, 0);
1230 rb_define_method(rb_cGDBM, "each_key", fgdbm_each_key, 0);
1231 rb_define_method(rb_cGDBM, "each_pair", fgdbm_each_pair, 0);
1232 rb_define_method(rb_cGDBM, "keys", fgdbm_keys, 0);
1233 rb_define_method(rb_cGDBM, "values", fgdbm_values, 0);
1234 rb_define_method(rb_cGDBM, "shift", fgdbm_shift, 0);
1235 rb_define_method(rb_cGDBM, "delete", fgdbm_delete, 1);
1236 rb_define_method(rb_cGDBM, "delete_if", fgdbm_delete_if, 0);
1237 rb_define_method(rb_cGDBM, "reject!", fgdbm_delete_if, 0);
1238 rb_define_method(rb_cGDBM, "reject", fgdbm_reject, 0);
1239 rb_define_method(rb_cGDBM, "clear", fgdbm_clear, 0);
1240 rb_define_method(rb_cGDBM, "invert", fgdbm_invert, 0);
1241 rb_define_method(rb_cGDBM, "update", fgdbm_update, 1);
1242 rb_define_method(rb_cGDBM, "replace", fgdbm_replace, 1);
1243 rb_define_method(rb_cGDBM, "reorganize", fgdbm_reorganize, 0);
1244 rb_define_method(rb_cGDBM, "sync", fgdbm_sync, 0);
1245 /* rb_define_method(rb_cGDBM, "setopt", fgdbm_setopt, 2); */
1246 rb_define_method(rb_cGDBM, "cachesize=", fgdbm_set_cachesize, 1);
1247 rb_define_method(rb_cGDBM, "fastmode=", fgdbm_set_fastmode, 1);
1248 rb_define_method(rb_cGDBM, "syncmode=", fgdbm_set_syncmode, 1);
1249
1250 rb_define_method(rb_cGDBM, "include?", fgdbm_has_key, 1);
1251 rb_define_method(rb_cGDBM, "has_key?", fgdbm_has_key, 1);
1252 rb_define_method(rb_cGDBM, "member?", fgdbm_has_key, 1);
1253 rb_define_method(rb_cGDBM, "has_value?", fgdbm_has_value, 1);
1254 rb_define_method(rb_cGDBM, "key?", fgdbm_has_key, 1);
1255 rb_define_method(rb_cGDBM, "value?", fgdbm_has_value, 1);
1256
1257 rb_define_method(rb_cGDBM, "to_a", fgdbm_to_a, 0);
1258 rb_define_method(rb_cGDBM, "to_hash", fgdbm_to_hash, 0);
1259
1260 /* flag for #new and #open: open database as a reader */
1261 rb_define_const(rb_cGDBM, "READER", INT2FIX(GDBM_READER|RUBY_GDBM_RW_BIT));
1262 /* flag for #new and #open: open database as a writer */
1263 rb_define_const(rb_cGDBM, "WRITER", INT2FIX(GDBM_WRITER|RUBY_GDBM_RW_BIT));
1264 /* flag for #new and #open: open database as a writer; if the database does not exist, create a new one */
1265 rb_define_const(rb_cGDBM, "WRCREAT", INT2FIX(GDBM_WRCREAT|RUBY_GDBM_RW_BIT));
1266 /* flag for #new and #open: open database as a writer; overwrite any existing databases */
1267 rb_define_const(rb_cGDBM, "NEWDB", INT2FIX(GDBM_NEWDB|RUBY_GDBM_RW_BIT));
1268
1269 /* flag for #new and #open. this flag is obsolete for gdbm >= 1.8 */
1270 rb_define_const(rb_cGDBM, "FAST", INT2FIX(GDBM_FAST));
1271 /* this flag is obsolete in gdbm 1.8.
1272 On gdbm 1.8, fast mode is default behavior. */
1273
1274 /* gdbm version 1.8 specific */
1275 #if defined(GDBM_SYNC)
1276 /* flag for #new and #open. only for gdbm >= 1.8 */
1277 rb_define_const(rb_cGDBM, "SYNC", INT2FIX(GDBM_SYNC));
1278 #endif
1279 #if defined(GDBM_NOLOCK)
1280 /* flag for #new and #open */
1281 rb_define_const(rb_cGDBM, "NOLOCK", INT2FIX(GDBM_NOLOCK));
1282 #endif
1283 /* version of the gdbm library*/
1284 rb_define_const(rb_cGDBM, "VERSION", rb_str_new2(gdbm_version));
1285 }
1286