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