Ruby  2.1.10p492(2016-04-01revision54464)
init.c
Go to the documentation of this file.
1 /************************************************
2 
3  sdbminit.c -
4 
5  $Author: nobu $
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
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
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  if (OBJ_FROZEN(obj)) rb_error_frozen("SDBM");
400 }
401 
402 /*
403  * call-seq:
404  * sdbm.delete(key) -> value or nil
405  * sdbm.delete(key) { |key, value| ... }
406  *
407  * Deletes the key-value pair corresponding to the given +key+. If the
408  * +key+ exists, the deleted value will be returned, otherwise +nil+.
409  *
410  * If a block is provided, the deleted +key+ and +value+ will be passed to
411  * the block as arguments. If the +key+ does not exist in the database, the
412  * value will be +nil+.
413  */
414 static VALUE
416 {
417  datum key, value;
418  struct dbmdata *dbmp;
419  DBM *dbm;
420  VALUE valstr;
421 
422  fdbm_modify(obj);
423  ExportStringValue(keystr);
424  key.dptr = RSTRING_PTR(keystr);
425  key.dsize = RSTRING_LENINT(keystr);
426 
427  GetDBM2(obj, dbmp, dbm);
428  dbmp->di_size = -1;
429 
430  value = sdbm_fetch(dbm, key);
431  if (value.dptr == 0) {
432  if (rb_block_given_p()) return rb_yield(keystr);
433  return Qnil;
434  }
435 
436  /* need to save value before sdbm_delete() */
437  valstr = rb_external_str_new(value.dptr, value.dsize);
438 
439  if (sdbm_delete(dbm, key)) {
440  dbmp->di_size = -1;
441  rb_raise(rb_eDBMError, "dbm_delete failed");
442  }
443  else if (dbmp->di_size >= 0) {
444  dbmp->di_size--;
445  }
446  return valstr;
447 }
448 
449 /*
450  * call-seq:
451  * sdbm.shift -> Array or nil
452  *
453  * Removes a key-value pair from the database and returns them as an
454  * Array. If the database is empty, returns +nil+.
455  */
456 static VALUE
458 {
459  datum key, val;
460  struct dbmdata *dbmp;
461  DBM *dbm;
462  VALUE keystr, valstr;
463 
464  fdbm_modify(obj);
465  GetDBM2(obj, dbmp, dbm);
466  key = sdbm_firstkey(dbm);
467  if (!key.dptr) return Qnil;
468  val = sdbm_fetch(dbm, key);
469  keystr = rb_external_str_new(key.dptr, key.dsize);
470  valstr = rb_external_str_new(val.dptr, val.dsize);
471  sdbm_delete(dbm, key);
472  if (dbmp->di_size >= 0) {
473  dbmp->di_size--;
474  }
475 
476  return rb_assoc_new(keystr, valstr);
477 }
478 
479 /*
480  * call-seq:
481  * sdbm.delete_if { |key, value| ... } -> self
482  * sdbm.reject! { |key, value| ... } -> self
483  *
484  * Iterates over the key-value pairs in the database, deleting those for
485  * which the block returns +true+.
486  */
487 static VALUE
489 {
490  datum key, val;
491  struct dbmdata *dbmp;
492  DBM *dbm;
493  VALUE keystr, valstr;
494  VALUE ret, ary = rb_ary_new();
495  int i, status = 0, n;
496 
497  fdbm_modify(obj);
498  GetDBM2(obj, dbmp, dbm);
499  n = dbmp->di_size;
500  dbmp->di_size = -1;
501  for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) {
502  val = sdbm_fetch(dbm, key);
503  keystr = rb_external_str_new(key.dptr, key.dsize);
504  valstr = rb_external_str_new(val.dptr, val.dsize);
505  ret = rb_protect(rb_yield, rb_assoc_new(rb_str_dup(keystr), valstr), &status);
506  if (status != 0) break;
507  if (RTEST(ret)) rb_ary_push(ary, keystr);
508  GetDBM2(obj, dbmp, dbm);
509  }
510 
511  for (i = 0; i < RARRAY_LEN(ary); i++) {
512  keystr = RARRAY_PTR(ary)[i];
513  ExportStringValue(keystr);
514  key.dptr = RSTRING_PTR(keystr);
515  key.dsize = RSTRING_LENINT(keystr);
516  if (sdbm_delete(dbm, key)) {
517  rb_raise(rb_eDBMError, "sdbm_delete failed");
518  }
519  }
520  if (status) rb_jump_tag(status);
521  if (n > 0) dbmp->di_size = n - RARRAY_LENINT(ary);
522 
523  return obj;
524 }
525 
526 /*
527  * call-seq:
528  * sdbm.clear -> self
529  *
530  * Deletes all data from the database.
531  */
532 static VALUE
534 {
535  datum key;
536  struct dbmdata *dbmp;
537  DBM *dbm;
538 
539  fdbm_modify(obj);
540  GetDBM2(obj, dbmp, dbm);
541  dbmp->di_size = -1;
542  while (key = sdbm_firstkey(dbm), key.dptr) {
543  if (sdbm_delete(dbm, key)) {
544  rb_raise(rb_eDBMError, "sdbm_delete failed");
545  }
546  }
547  dbmp->di_size = 0;
548 
549  return obj;
550 }
551 
552 /*
553  * call-seq:
554  * sdbm.invert -> Hash
555  *
556  * Returns a Hash in which the key-value pairs have been inverted.
557  *
558  * Example:
559  *
560  * require 'sdbm'
561  *
562  * SDBM.open 'my_database' do |db|
563  * db.update('apple' => 'fruit', 'spinach' => 'vegetable')
564  *
565  * db.invert #=> {"fruit" => "apple", "vegetable" => "spinach"}
566  * end
567  */
568 static VALUE
570 {
571  datum key, val;
572  struct dbmdata *dbmp;
573  DBM *dbm;
574  VALUE keystr, valstr;
575  VALUE hash = rb_hash_new();
576 
577  GetDBM2(obj, dbmp, dbm);
578  for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) {
579  val = sdbm_fetch(dbm, key);
580  keystr = rb_external_str_new(key.dptr, key.dsize);
581  valstr = rb_external_str_new(val.dptr, val.dsize);
582  rb_hash_aset(hash, valstr, keystr);
583  }
584  return hash;
585 }
586 
587 /*
588  * call-seq:
589  * sdbm[key] = value -> value
590  * sdbm.store(key, value) -> value
591  *
592  * Stores a new +value+ in the database with the given +key+ as an index.
593  *
594  * If the +key+ already exists, this will update the +value+ associated with
595  * the +key+.
596  *
597  * Returns the given +value+.
598  */
599 static VALUE
600 fsdbm_store(VALUE obj, VALUE keystr, VALUE valstr)
601 {
602  datum key, val;
603  struct dbmdata *dbmp;
604  DBM *dbm;
605 
606  if (valstr == Qnil) {
607  fsdbm_delete(obj, keystr);
608  return Qnil;
609  }
610 
611  fdbm_modify(obj);
612  ExportStringValue(keystr);
613  ExportStringValue(valstr);
614 
615  key.dptr = RSTRING_PTR(keystr);
616  key.dsize = RSTRING_LENINT(keystr);
617 
618  val.dptr = RSTRING_PTR(valstr);
619  val.dsize = RSTRING_LENINT(valstr);
620 
621  GetDBM2(obj, dbmp, dbm);
622  dbmp->di_size = -1;
623  if (sdbm_store(dbm, key, val, DBM_REPLACE)) {
624 #ifdef HAVE_DBM_CLAERERR
625  sdbm_clearerr(dbm);
626 #endif
627  if (errno == EPERM) rb_sys_fail(0);
628  rb_raise(rb_eDBMError, "sdbm_store failed");
629  }
630 
631  return valstr;
632 }
633 
634 static VALUE
635 update_i(RB_BLOCK_CALL_FUNC_ARGLIST(pair, dbm))
636 {
638  if (RARRAY_LEN(pair) < 2) {
639  rb_raise(rb_eArgError, "pair must be [key, value]");
640  }
641  fsdbm_store(dbm, RARRAY_PTR(pair)[0], RARRAY_PTR(pair)[1]);
642  return Qnil;
643 }
644 
645 /*
646  * call-seq:
647  * sdbm.update(pairs) -> self
648  *
649  * Insert or update key-value pairs.
650  *
651  * This method will work with any object which implements an each_pair
652  * method, such as a Hash.
653  */
654 static VALUE
656 {
657  rb_block_call(other, rb_intern("each_pair"), 0, 0, update_i, obj);
658  return obj;
659 }
660 
661 /*
662  * call-seq:
663  * sdbm.replace(pairs) -> self
664  *
665  * Empties the database, then inserts the given key-value pairs.
666  *
667  * This method will work with any object which implements an each_pair
668  * method, such as a Hash.
669  */
670 static VALUE
672 {
673  fsdbm_clear(obj);
674  rb_block_call(other, rb_intern("each_pair"), 0, 0, update_i, obj);
675  return obj;
676 }
677 
678 /*
679  * call-seq:
680  * sdbm.length -> integer
681  * sdbm.size -> integer
682  *
683  * Returns the number of keys in the database.
684  */
685 static VALUE
687 {
688  datum key;
689  struct dbmdata *dbmp;
690  DBM *dbm;
691  int i = 0;
692 
693  GetDBM2(obj, dbmp, dbm);
694  if (dbmp->di_size > 0) return INT2FIX(dbmp->di_size);
695 
696  for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) {
697  i++;
698  }
699  dbmp->di_size = i;
700 
701  return INT2FIX(i);
702 }
703 
704 /*
705  * call-seq:
706  * sdbm.empty? -> true or false
707  *
708  * Returns +true+ if the database is empty.
709  */
710 static VALUE
712 {
713  datum key;
714  struct dbmdata *dbmp;
715  DBM *dbm;
716 
717  GetDBM(obj, dbmp);
718  if (dbmp->di_size < 0) {
719  dbm = dbmp->di_dbm;
720 
721  for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) {
722  return Qfalse;
723  }
724  }
725  else {
726  if (dbmp->di_size)
727  return Qfalse;
728  }
729  return Qtrue;
730 }
731 
732 /*
733  * call-seq:
734  * sdbm.each_value
735  * sdbm.each_value { |value| ... }
736  *
737  * Iterates over each +value+ in the database.
738  *
739  * If no block is given, returns an Enumerator.
740  */
741 static VALUE
743 {
744  datum key, val;
745  struct dbmdata *dbmp;
746  DBM *dbm;
747 
748  RETURN_ENUMERATOR(obj, 0, 0);
749 
750  GetDBM2(obj, dbmp, dbm);
751  for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) {
752  val = sdbm_fetch(dbm, key);
754  GetDBM2(obj, dbmp, dbm);
755  }
756  return obj;
757 }
758 
759 /*
760  * call-seq:
761  * sdbm.each_key
762  * sdbm.each_key { |key| ... }
763  *
764  * Iterates over each +key+ in the database.
765  *
766  * If no block is given, returns an Enumerator.
767  */
768 static VALUE
770 {
771  datum key;
772  struct dbmdata *dbmp;
773  DBM *dbm;
774 
775  RETURN_ENUMERATOR(obj, 0, 0);
776 
777  GetDBM2(obj, dbmp, dbm);
778  for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) {
780  GetDBM2(obj, dbmp, dbm);
781  }
782  return obj;
783 }
784 
785 /*
786  * call-seq:
787  * sdbm.each
788  * sdbm.each { |key, value| ... }
789  * sdbm.each_pair
790  * sdbm.each_pair { |key, value| ... }
791  *
792  * Iterates over each key-value pair in the database.
793  *
794  * If no block is given, returns an Enumerator.
795  */
796 static VALUE
798 {
799  datum key, val;
800  DBM *dbm;
801  struct dbmdata *dbmp;
802  VALUE keystr, valstr;
803 
804  RETURN_ENUMERATOR(obj, 0, 0);
805 
806  GetDBM2(obj, dbmp, dbm);
807  for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) {
808  val = sdbm_fetch(dbm, key);
809  keystr = rb_external_str_new(key.dptr, key.dsize);
810  valstr = rb_external_str_new(val.dptr, val.dsize);
811  rb_yield(rb_assoc_new(keystr, valstr));
812  GetDBM2(obj, dbmp, dbm);
813  }
814 
815  return obj;
816 }
817 
818 /*
819  * call-seq:
820  * sdbm.keys -> Array
821  *
822  * Returns a new Array containing the keys in the database.
823  */
824 static VALUE
826 {
827  datum key;
828  struct dbmdata *dbmp;
829  DBM *dbm;
830  VALUE ary;
831 
832  GetDBM2(obj, dbmp, dbm);
833  ary = rb_ary_new();
834  for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) {
835  rb_ary_push(ary, rb_external_str_new(key.dptr, key.dsize));
836  }
837 
838  return ary;
839 }
840 
841 /*
842  * call-seq:
843  * sdbm.values -> Array
844  *
845  * Returns a new Array containing the values in the database.
846  */
847 static VALUE
849 {
850  datum key, val;
851  struct dbmdata *dbmp;
852  DBM *dbm;
853  VALUE ary;
854 
855  GetDBM2(obj, dbmp, dbm);
856  ary = rb_ary_new();
857  for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) {
858  val = sdbm_fetch(dbm, key);
859  rb_ary_push(ary, rb_external_str_new(val.dptr, val.dsize));
860  }
861 
862  return ary;
863 }
864 
865 /*
866  * call-seq:
867  * sdbm.include?(key) -> true or false
868  * sdbm.key?(key) -> true or false
869  * sdbm.member?(key) -> true or false
870  * sdbm.has_key?(key) -> true or false
871  *
872  * Returns +true+ if the database contains the given +key+.
873  */
874 static VALUE
876 {
877  datum key, val;
878  struct dbmdata *dbmp;
879  DBM *dbm;
880 
881  ExportStringValue(keystr);
882  key.dptr = RSTRING_PTR(keystr);
883  key.dsize = RSTRING_LENINT(keystr);
884 
885  GetDBM2(obj, dbmp, dbm);
886  val = sdbm_fetch(dbm, key);
887  if (val.dptr) return Qtrue;
888  return Qfalse;
889 }
890 
891 /*
892  * call-seq:
893  * sdbm.value?(key) -> true or false
894  * sdbm.has_value?(key) -> true or false
895  *
896  * Returns +true+ if the database contains the given +value+.
897  */
898 static VALUE
900 {
901  datum key, val;
902  struct dbmdata *dbmp;
903  DBM *dbm;
904 
905  ExportStringValue(valstr);
906  val.dptr = RSTRING_PTR(valstr);
907  val.dsize = RSTRING_LENINT(valstr);
908 
909  GetDBM2(obj, dbmp, dbm);
910  for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) {
911  val = sdbm_fetch(dbm, key);
912  if (val.dsize == RSTRING_LENINT(valstr) &&
913  memcmp(val.dptr, RSTRING_PTR(valstr), val.dsize) == 0)
914  return Qtrue;
915  }
916  return Qfalse;
917 }
918 
919 /*
920  * call-seq:
921  * sdbm.to_a -> Array
922  *
923  * Returns a new Array containing each key-value pair in the database.
924  *
925  * Example:
926  *
927  * require 'sdbm'
928  *
929  * SDBM.open 'my_database' do |db|
930  * db.update('apple' => 'fruit', 'spinach' => 'vegetable')
931  *
932  * db.to_a #=> [["apple", "fruit"], ["spinach", "vegetable"]]
933  * end
934  */
935 static VALUE
937 {
938  datum key, val;
939  struct dbmdata *dbmp;
940  DBM *dbm;
941  VALUE ary;
942 
943  GetDBM2(obj, dbmp, dbm);
944  ary = rb_ary_new();
945  for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) {
946  val = sdbm_fetch(dbm, key);
948  rb_external_str_new(val.dptr, val.dsize)));
949  }
950 
951  return ary;
952 }
953 
954 /*
955  * call-seq:
956  * sdbm.to_hash -> Hash
957  *
958  * Returns a new Hash containing each key-value pair in the database.
959  */
960 static VALUE
962 {
963  datum key, val;
964  struct dbmdata *dbmp;
965  DBM *dbm;
966  VALUE hash;
967 
968  GetDBM2(obj, dbmp, dbm);
969  hash = rb_hash_new();
970  for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) {
971  val = sdbm_fetch(dbm, key);
972  rb_hash_aset(hash, rb_external_str_new(key.dptr, key.dsize),
973  rb_external_str_new(val.dptr, val.dsize));
974  }
975 
976  return hash;
977 }
978 
979 /*
980  * call-seq:
981  * sdbm.reject { |key, value| ... } -> Hash
982  *
983  * Creates a new Hash using the key-value pairs from the database, then
984  * calls Hash#reject with the given block, which returns a Hash with
985  * only the key-value pairs for which the block returns +false+.
986  */
987 static VALUE
989 {
990  return rb_hash_delete_if(fsdbm_to_hash(obj));
991 }
992 
993 void
995 {
998  /* Document-class: SDBMError
999  * Exception class used to return errors from the sdbm library.
1000  */
1002 
1005 
1006  rb_define_method(rb_cDBM, "initialize", fsdbm_initialize, -1);
1007  rb_define_method(rb_cDBM, "close", fsdbm_close, 0);
1008  rb_define_method(rb_cDBM, "closed?", fsdbm_closed, 0);
1009  rb_define_method(rb_cDBM, "[]", fsdbm_aref, 1);
1010  rb_define_method(rb_cDBM, "fetch", fsdbm_fetch_m, -1);
1011  rb_define_method(rb_cDBM, "[]=", fsdbm_store, 2);
1012  rb_define_method(rb_cDBM, "store", fsdbm_store, 2);
1013  rb_define_method(rb_cDBM, "index", fsdbm_index, 1);
1014  rb_define_method(rb_cDBM, "key", fsdbm_key, 1);
1015  rb_define_method(rb_cDBM, "select", fsdbm_select, 0);
1016  rb_define_method(rb_cDBM, "values_at", fsdbm_values_at, -1);
1017  rb_define_method(rb_cDBM, "length", fsdbm_length, 0);
1018  rb_define_method(rb_cDBM, "size", fsdbm_length, 0);
1019  rb_define_method(rb_cDBM, "empty?", fsdbm_empty_p, 0);
1021  rb_define_method(rb_cDBM, "each_value", fsdbm_each_value, 0);
1022  rb_define_method(rb_cDBM, "each_key", fsdbm_each_key, 0);
1023  rb_define_method(rb_cDBM, "each_pair", fsdbm_each_pair, 0);
1024  rb_define_method(rb_cDBM, "keys", fsdbm_keys, 0);
1025  rb_define_method(rb_cDBM, "values", fsdbm_values, 0);
1026  rb_define_method(rb_cDBM, "shift", fsdbm_shift, 0);
1027  rb_define_method(rb_cDBM, "delete", fsdbm_delete, 1);
1028  rb_define_method(rb_cDBM, "delete_if", fsdbm_delete_if, 0);
1029  rb_define_method(rb_cDBM, "reject!", fsdbm_delete_if, 0);
1030  rb_define_method(rb_cDBM, "reject", fsdbm_reject, 0);
1031  rb_define_method(rb_cDBM, "clear", fsdbm_clear, 0);
1032  rb_define_method(rb_cDBM,"invert", fsdbm_invert, 0);
1033  rb_define_method(rb_cDBM,"update", fsdbm_update, 1);
1034  rb_define_method(rb_cDBM,"replace", fsdbm_replace, 1);
1035 
1036  rb_define_method(rb_cDBM, "has_key?", fsdbm_has_key, 1);
1037  rb_define_method(rb_cDBM, "include?", fsdbm_has_key, 1);
1038  rb_define_method(rb_cDBM, "key?", fsdbm_has_key, 1);
1039  rb_define_method(rb_cDBM, "member?", fsdbm_has_key, 1);
1040  rb_define_method(rb_cDBM, "has_value?", fsdbm_has_value, 1);
1041  rb_define_method(rb_cDBM, "value?", fsdbm_has_value, 1);
1042 
1043  rb_define_method(rb_cDBM, "to_a", fsdbm_to_a, 0);
1044  rb_define_method(rb_cDBM, "to_hash", fsdbm_to_hash, 0);
1045 }
RARRAY_PTR(q->result)[0]
DBM * di_dbm
Definition: dbm.c:39
#define ALLOC(type)
VALUE rb_eStandardError
Definition: error.c:546
#define FilePathValue(v)
static VALUE fsdbm_reject(VALUE obj)
Definition: init.c:988
memo u1 value
Definition: enum.c:587
static VALUE fsdbm_clear(VALUE obj)
Definition: init.c:533
static VALUE fsdbm_to_a(VALUE obj)
Definition: init.c:936
static VALUE fsdbm_key(VALUE obj, VALUE valstr)
Definition: init.c:305
volatile VALUE pair
Definition: tkutil.c:554
void rb_define_singleton_method(VALUE obj, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a singleton method for obj.
Definition: class.c:1646
void rb_error_frozen(const char *what)
Definition: error.c:2077
static VALUE fsdbm_each_value(VALUE obj)
Definition: init.c:742
static VALUE fsdbm_alloc(VALUE klass)
Definition: init.c:140
static VALUE fsdbm_has_key(VALUE obj, VALUE keystr)
Definition: init.c:875
int ret
Definition: tcltklib.c:285
int status
Definition: tcltklib.c:2197
rb_yield(i)
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
VALUE rb_ary_push(VALUE ary, VALUE item)
Definition: array.c:900
long di_size
Definition: dbm.c:38
#define RSTRING_PTR(str)
NIL_P(eventloop_thread)
Definition: tcltklib.c:4056
#define T_ARRAY
VALUE rb_protect(VALUE(*proc)(VALUE), VALUE data, int *state)
Definition: eval.c:807
static void free_sdbm(struct dbmdata *dbmp)
Definition: init.c:92
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:1857
return Qtrue
Definition: tcltklib.c:9618
#define RETURN_ENUMERATOR(obj, argc, argv)
static VALUE fsdbm_update(VALUE obj, VALUE other)
Definition: init.c:655
VALUE rb_external_str_new(const char *, long)
Definition: string.c:707
Definition: dbm.c:37
static VALUE fsdbm_values_at(int argc, VALUE *argv, VALUE obj)
Definition: init.c:384
void rb_include_module(VALUE klass, VALUE module)
Definition: class.c:808
char * dptr
Definition: sdbm.h:51
static VALUE fsdbm_invert(VALUE obj)
Definition: init.c:569
static VALUE fsdbm_closed(VALUE obj)
Definition: init.c:126
static VALUE fsdbm_values(VALUE obj)
Definition: init.c:848
static VALUE rb_eDBMError
Definition: init.c:67
#define rb_ary_new2
i
Definition: enum.c:446
VALUE ary
Definition: enum.c:674
static VALUE fsdbm_replace(VALUE obj, VALUE other)
Definition: init.c:671
VALUE hash
Definition: tkutil.c:267
void sdbm_close(register DBM *db)
Definition: _sdbm.c:265
static VALUE fsdbm_shift(VALUE obj)
Definition: init.c:457
#define GetDBM2(obj, data, dbm)
Definition: init.c:86
return Data_Wrap_Struct(CLASS_OF(interp), 0, ip_free, slave)
DBM * sdbm_open(register char *file, register int flags, register int mode)
Definition: _sdbm.c:148
static void fdbm_modify(VALUE obj)
Definition: init.c:397
return Qfalse
Definition: tcltklib.c:6790
static VALUE fsdbm_empty_p(VALUE obj)
Definition: init.c:711
Definition: sdbm.h:50
int rb_block_given_p(void)
Definition: eval.c:712
#define DBM_REPLACE
Definition: sdbm.h:67
#define RARRAY_LEN(a)
#define Qnil
Definition: enum.c:67
#define val
Definition: tcltklib.c:1935
static VALUE fsdbm_aref(VALUE obj, VALUE keystr)
Definition: init.c:264
VALUE rb_ary_new(void)
Definition: array.c:499
Check_Type(i, T_ARRAY)
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition: class.c:611
datum sdbm_firstkey(register DBM *db)
Definition: _sdbm.c:468
static VALUE VALUE obj
Definition: tcltklib.c:3150
#define RSTRING_LEN(str)
static VALUE fsdbm_delete(VALUE obj, VALUE keystr)
Definition: init.c:415
#define INT2FIX(i)
static VALUE fsdbm_each_pair(VALUE obj)
Definition: init.c:797
void rb_sys_fail_str(VALUE mesg)
Definition: error.c:1982
static VALUE fsdbm_delete_if(VALUE obj)
Definition: init.c:488
static VALUE VALUE assoc
Definition: tkutil.c:545
static void closed_sdbm()
Definition: init.c:75
VALUE rb_eIndexError
Definition: error.c:550
static int VALUE key
Definition: tkutil.c:265
static VALUE fsdbm_initialize(int argc, VALUE *argv, VALUE obj)
Definition: init.c:160
VALUE rb_str_dup(VALUE)
Definition: string.c:1062
#define ExportStringValue(v)
VALUE * argv
Definition: tcltklib.c:1969
#define RTEST(v)
void Init_sdbm()
Definition: init.c:994
int errno
VALUE rb_mEnumerable
Definition: enum.c:20
rb_block_call(enumerable, id_each, 0, 0, chunk_ii, arg)
VALUE v
Definition: enum.c:845
Definition: sdbm.h:20
void ruby_xfree(void *x)
Definition: gc.c:6245
VALUE mode
Definition: tcltklib.c:1668
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:1719
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Definition: array.c:620
#define OBJ_FROZEN(x)
int dsize
Definition: sdbm.h:52
int argc
Definition: tcltklib.c:1968
static VALUE fsdbm_length(VALUE obj)
Definition: init.c:686
rb_hash_aset(hash, RARRAY_AREF(key_value_pair, 0), RARRAY_AREF(key_value_pair, 1))
#define EPERM
Definition: _sdbm.c:93
VALUE rb_ensure(VALUE(*b_proc)(ANYARGS), VALUE data1, VALUE(*e_proc)(ANYARGS), VALUE data2)
Definition: eval.c:839
int memcmp(const void *s1, const void *s2, size_t len)
Definition: memcmp.c:7
#define sdbm_clearerr(db)
Definition: sdbm.h:45
void rb_sys_fail(const char *mesg)
Definition: error.c:1976
void rb_jump_tag(int tag)
Definition: eval.c:706
static VALUE fsdbm_to_hash(VALUE obj)
Definition: init.c:961
static VALUE fsdbm_store(VALUE obj, VALUE keystr, VALUE valstr)
Definition: init.c:600
int sdbm_store(register DBM *db, datum key, datum val, int flags)
Definition: _sdbm.c:313
static VALUE rb_cDBM
Definition: init.c:67
#define GetDBM(obj, dbmp)
Definition: init.c:80
DATA_PTR(self)
RUBY_EXTERN VALUE rb_cObject
Definition: ripper.y:1561
static VALUE fsdbm_fetch(VALUE obj, VALUE keystr, VALUE ifnone)
Definition: init.c:235
#define RARRAY_LENINT(ary)
static VALUE fsdbm_s_open(int argc, VALUE *argv, VALUE klass)
Definition: init.c:219
klass
Definition: tcltklib.c:3496
static VALUE fsdbm_each_key(VALUE obj)
Definition: init.c:769
#define Data_Get_Struct(obj, type, sval)
#define RSTRING_LENINT(str)
datum sdbm_nextkey(register DBM *db)
Definition: _sdbm.c:487
static VALUE fsdbm_has_value(VALUE obj, VALUE valstr)
Definition: init.c:899
data n
Definition: enum.c:860
VALUE rb_hash_delete_if(VALUE)
Definition: hash.c:1103
#define NUM2INT(x)
VALUE rb_hash_new(void)
Definition: hash.c:307
static VALUE fsdbm_fetch_m(int argc, VALUE *argv, VALUE obj)
Definition: init.c:284
unsigned long VALUE
Definition: ripper.y:88
static VALUE fsdbm_index(VALUE hash, VALUE value)
Definition: init.c:329
int sdbm_delete(register DBM *db, datum key)
Definition: _sdbm.c:289
static VALUE fsdbm_select(VALUE obj)
Definition: init.c:355
datum sdbm_fetch(register DBM *db, datum key)
Definition: _sdbm.c:277
static VALUE fsdbm_close(VALUE obj)
Definition: init.c:108
#define rb_intern(str)
#define RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg)
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1479
void rb_warn(const char *fmt,...)
Definition: error.c:223
VALUE rb_eArgError
Definition: error.c:549
static VALUE fsdbm_keys(VALUE obj)
Definition: init.c:825