Ruby  1.9.3p392(2013-02-22revision39386)
init.c
Go to the documentation of this file.
1 /************************************************
2 
3  sdbminit.c -
4 
5  $Author: akr $
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 
19 
20 struct dbmdata {
21  int di_size;
22  DBM *di_dbm;
23 };
24 
25 static void
27 {
28  rb_raise(rb_eDBMError, "closed SDBM file");
29 }
30 
31 #define GetDBM(obj, dbmp) {\
32  Data_Get_Struct((obj), struct dbmdata, (dbmp));\
33  if ((dbmp) == 0) closed_sdbm();\
34  if ((dbmp)->di_dbm == 0) closed_sdbm();\
35 }
36 
37 #define GetDBM2(obj, data, dbm) {\
38  GetDBM((obj), (data));\
39  (dbm) = dbmp->di_dbm;\
40 }
41 
42 static void
43 free_sdbm(struct dbmdata *dbmp)
44 {
45 
46  if (dbmp->di_dbm) sdbm_close(dbmp->di_dbm);
47  ruby_xfree(dbmp);
48 }
49 
50 static VALUE
52 {
53  struct dbmdata *dbmp;
54 
55  GetDBM(obj, dbmp);
56  sdbm_close(dbmp->di_dbm);
57  dbmp->di_dbm = 0;
58 
59  return Qnil;
60 }
61 
62 static VALUE
64 {
65  struct dbmdata *dbmp;
66 
67  Data_Get_Struct(obj, struct dbmdata, dbmp);
68  if (dbmp == 0)
69  return Qtrue;
70  if (dbmp->di_dbm == 0)
71  return Qtrue;
72 
73  return Qfalse;
74 }
75 
76 static VALUE
78 {
79  return Data_Wrap_Struct(klass, 0, free_sdbm, 0);
80 }
81 
82 static VALUE
84 {
85  volatile VALUE file;
86  VALUE vmode;
87  DBM *dbm;
88  struct dbmdata *dbmp;
89  int mode;
90 
91  if (rb_scan_args(argc, argv, "11", &file, &vmode) == 1) {
92  mode = 0666; /* default value */
93  }
94  else if (NIL_P(vmode)) {
95  mode = -1; /* return nil if DB not exist */
96  }
97  else {
98  mode = NUM2INT(vmode);
99  }
100  FilePathValue(file);
101 
102  dbm = 0;
103  if (mode >= 0)
104  dbm = sdbm_open(RSTRING_PTR(file), O_RDWR|O_CREAT, mode);
105  if (!dbm)
106  dbm = sdbm_open(RSTRING_PTR(file), O_RDWR, 0);
107  if (!dbm)
108  dbm = sdbm_open(RSTRING_PTR(file), O_RDONLY, 0);
109 
110  if (!dbm) {
111  if (mode == -1) return Qnil;
112  rb_sys_fail(RSTRING_PTR(file));
113  }
114 
115  dbmp = ALLOC(struct dbmdata);
116  DATA_PTR(obj) = dbmp;
117  dbmp->di_dbm = dbm;
118  dbmp->di_size = -1;
119 
120  return obj;
121 }
122 
123 static VALUE
125 {
126  VALUE obj = Data_Wrap_Struct(klass, 0, free_sdbm, 0);
127 
128  if (NIL_P(fsdbm_initialize(argc, argv, obj))) {
129  return Qnil;
130  }
131 
132  if (rb_block_given_p()) {
133  return rb_ensure(rb_yield, obj, fsdbm_close, obj);
134  }
135 
136  return obj;
137 }
138 
139 static VALUE
140 fsdbm_fetch(VALUE obj, VALUE keystr, VALUE ifnone)
141 {
142  datum key, value;
143  struct dbmdata *dbmp;
144  DBM *dbm;
145 
146  ExportStringValue(keystr);
147  key.dptr = RSTRING_PTR(keystr);
148  key.dsize = RSTRING_LENINT(keystr);
149 
150  GetDBM2(obj, dbmp, dbm);
151  value = sdbm_fetch(dbm, key);
152  if (value.dptr == 0) {
153  if (ifnone == Qnil && rb_block_given_p())
154  return rb_yield(rb_external_str_new(key.dptr, key.dsize));
155  return ifnone;
156  }
157  return rb_external_str_new(value.dptr, value.dsize);
158 }
159 
160 static VALUE
161 fsdbm_aref(VALUE obj, VALUE keystr)
162 {
163  return fsdbm_fetch(obj, keystr, Qnil);
164 }
165 
166 static VALUE
168 {
169  VALUE keystr, valstr, ifnone;
170 
171  rb_scan_args(argc, argv, "11", &keystr, &ifnone);
172  valstr = fsdbm_fetch(obj, keystr, ifnone);
173  if (argc == 1 && !rb_block_given_p() && NIL_P(valstr))
174  rb_raise(rb_eIndexError, "key not found");
175 
176  return valstr;
177 }
178 
179 static VALUE
180 fsdbm_key(VALUE obj, VALUE valstr)
181 {
182  datum key, val;
183  struct dbmdata *dbmp;
184  DBM *dbm;
185 
186  ExportStringValue(valstr);
187  val.dptr = RSTRING_PTR(valstr);
188  val.dsize = RSTRING_LENINT(valstr);
189 
190  GetDBM2(obj, dbmp, dbm);
191  for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) {
192  val = sdbm_fetch(dbm, key);
193  if (val.dsize == RSTRING_LEN(valstr) &&
194  memcmp(val.dptr, RSTRING_PTR(valstr), val.dsize) == 0)
195  return rb_external_str_new(key.dptr, key.dsize);
196  }
197  return Qnil;
198 }
199 
200 static VALUE
202 {
203  rb_warn("SDBM#index is deprecated; use SDBM#key");
204  return fsdbm_key(hash, value);
205 }
206 
207 static VALUE
209 {
210  VALUE new = rb_ary_new();
211  datum key, val;
212  DBM *dbm;
213  struct dbmdata *dbmp;
214 
215  GetDBM2(obj, dbmp, dbm);
216  for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) {
217  VALUE assoc, v;
218  val = sdbm_fetch(dbm, key);
219  assoc = rb_assoc_new(rb_external_str_new(key.dptr, key.dsize),
220  rb_external_str_new(val.dptr, val.dsize));
221  v = rb_yield(assoc);
222  if (RTEST(v)) {
223  rb_ary_push(new, assoc);
224  }
225  GetDBM2(obj, dbmp, dbm);
226  }
227 
228  return new;
229 }
230 
231 static VALUE
233 {
234  VALUE new = rb_ary_new2(argc);
235  int i;
236 
237  for (i=0; i<argc; i++) {
238  rb_ary_push(new, fsdbm_fetch(obj, argv[i], Qnil));
239  }
240 
241  return new;
242 }
243 
244 static void
246 {
247  rb_secure(4);
248  if (OBJ_FROZEN(obj)) rb_error_frozen("SDBM");
249 }
250 
251 static VALUE
253 {
254  datum key, value;
255  struct dbmdata *dbmp;
256  DBM *dbm;
257  VALUE valstr;
258 
259  fdbm_modify(obj);
260  ExportStringValue(keystr);
261  key.dptr = RSTRING_PTR(keystr);
262  key.dsize = RSTRING_LENINT(keystr);
263 
264  GetDBM2(obj, dbmp, dbm);
265  dbmp->di_size = -1;
266 
267  value = sdbm_fetch(dbm, key);
268  if (value.dptr == 0) {
269  if (rb_block_given_p()) return rb_yield(keystr);
270  return Qnil;
271  }
272 
273  /* need to save value before sdbm_delete() */
274  valstr = rb_external_str_new(value.dptr, value.dsize);
275 
276  if (sdbm_delete(dbm, key)) {
277  dbmp->di_size = -1;
278  rb_raise(rb_eDBMError, "dbm_delete failed");
279  }
280  else if (dbmp->di_size >= 0) {
281  dbmp->di_size--;
282  }
283  return valstr;
284 }
285 
286 static VALUE
288 {
289  datum key, val;
290  struct dbmdata *dbmp;
291  DBM *dbm;
292  VALUE keystr, valstr;
293 
294  fdbm_modify(obj);
295  GetDBM2(obj, dbmp, dbm);
296  key = sdbm_firstkey(dbm);
297  if (!key.dptr) return Qnil;
298  val = sdbm_fetch(dbm, key);
299  keystr = rb_external_str_new(key.dptr, key.dsize);
300  valstr = rb_external_str_new(val.dptr, val.dsize);
301  sdbm_delete(dbm, key);
302  if (dbmp->di_size >= 0) {
303  dbmp->di_size--;
304  }
305 
306  return rb_assoc_new(keystr, valstr);
307 }
308 
309 static VALUE
311 {
312  datum key, val;
313  struct dbmdata *dbmp;
314  DBM *dbm;
315  VALUE keystr, valstr;
316  VALUE ret, ary = rb_ary_new();
317  int i, status = 0, n;
318 
319  fdbm_modify(obj);
320  GetDBM2(obj, dbmp, dbm);
321  n = dbmp->di_size;
322  dbmp->di_size = -1;
323  for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) {
324  val = sdbm_fetch(dbm, key);
325  keystr = rb_external_str_new(key.dptr, key.dsize);
326  valstr = rb_external_str_new(val.dptr, val.dsize);
327  ret = rb_protect(rb_yield, rb_assoc_new(rb_str_dup(keystr), valstr), &status);
328  if (status != 0) break;
329  if (RTEST(ret)) rb_ary_push(ary, keystr);
330  GetDBM2(obj, dbmp, dbm);
331  }
332 
333  for (i = 0; i < RARRAY_LEN(ary); i++) {
334  keystr = RARRAY_PTR(ary)[i];
335  ExportStringValue(keystr);
336  key.dptr = RSTRING_PTR(keystr);
337  key.dsize = RSTRING_LENINT(keystr);
338  if (sdbm_delete(dbm, key)) {
339  rb_raise(rb_eDBMError, "sdbm_delete failed");
340  }
341  }
342  if (status) rb_jump_tag(status);
343  if (n > 0) dbmp->di_size = n - RARRAY_LENINT(ary);
344 
345  return obj;
346 }
347 
348 static VALUE
350 {
351  datum key;
352  struct dbmdata *dbmp;
353  DBM *dbm;
354 
355  fdbm_modify(obj);
356  GetDBM2(obj, dbmp, dbm);
357  dbmp->di_size = -1;
358  while (key = sdbm_firstkey(dbm), key.dptr) {
359  if (sdbm_delete(dbm, key)) {
360  rb_raise(rb_eDBMError, "sdbm_delete failed");
361  }
362  }
363  dbmp->di_size = 0;
364 
365  return obj;
366 }
367 
368 static VALUE
370 {
371  datum key, val;
372  struct dbmdata *dbmp;
373  DBM *dbm;
374  VALUE keystr, valstr;
375  VALUE hash = rb_hash_new();
376 
377  GetDBM2(obj, dbmp, dbm);
378  for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) {
379  val = sdbm_fetch(dbm, key);
380  keystr = rb_external_str_new(key.dptr, key.dsize);
381  valstr = rb_external_str_new(val.dptr, val.dsize);
382  rb_hash_aset(hash, valstr, keystr);
383  }
384  return hash;
385 }
386 
387 static VALUE
388 fsdbm_store(VALUE obj, VALUE keystr, VALUE valstr)
389 {
390  datum key, val;
391  struct dbmdata *dbmp;
392  DBM *dbm;
393 
394  if (valstr == Qnil) {
395  fsdbm_delete(obj, keystr);
396  return Qnil;
397  }
398 
399  fdbm_modify(obj);
400  ExportStringValue(keystr);
401  ExportStringValue(valstr);
402 
403  key.dptr = RSTRING_PTR(keystr);
404  key.dsize = RSTRING_LENINT(keystr);
405 
406  val.dptr = RSTRING_PTR(valstr);
407  val.dsize = RSTRING_LENINT(valstr);
408 
409  GetDBM2(obj, dbmp, dbm);
410  dbmp->di_size = -1;
411  if (sdbm_store(dbm, key, val, DBM_REPLACE)) {
412 #ifdef HAVE_DBM_CLAERERR
413  sdbm_clearerr(dbm);
414 #endif
415  if (errno == EPERM) rb_sys_fail(0);
416  rb_raise(rb_eDBMError, "sdbm_store failed");
417  }
418 
419  return valstr;
420 }
421 
422 static VALUE
423 update_i(VALUE pair, VALUE dbm)
424 {
425  Check_Type(pair, T_ARRAY);
426  if (RARRAY_LEN(pair) < 2) {
427  rb_raise(rb_eArgError, "pair must be [key, value]");
428  }
429  fsdbm_store(dbm, RARRAY_PTR(pair)[0], RARRAY_PTR(pair)[1]);
430  return Qnil;
431 }
432 
433 static VALUE
435 {
436  rb_block_call(other, rb_intern("each_pair"), 0, 0, update_i, obj);
437  return obj;
438 }
439 
440 static VALUE
442 {
443  fsdbm_clear(obj);
444  rb_block_call(other, rb_intern("each_pair"), 0, 0, update_i, obj);
445  return obj;
446 }
447 
448 static VALUE
450 {
451  datum key;
452  struct dbmdata *dbmp;
453  DBM *dbm;
454  int i = 0;
455 
456  GetDBM2(obj, dbmp, dbm);
457  if (dbmp->di_size > 0) return INT2FIX(dbmp->di_size);
458 
459  for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) {
460  i++;
461  }
462  dbmp->di_size = i;
463 
464  return INT2FIX(i);
465 }
466 
467 static VALUE
469 {
470  datum key;
471  struct dbmdata *dbmp;
472  DBM *dbm;
473  int i = 0;
474 
475  GetDBM(obj, dbmp);
476  if (dbmp->di_size < 0) {
477  dbm = dbmp->di_dbm;
478 
479  for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) {
480  i++;
481  }
482  }
483  else {
484  i = dbmp->di_size;
485  }
486  if (i == 0) return Qtrue;
487  return Qfalse;
488 }
489 
490 static VALUE
492 {
493  datum key, val;
494  struct dbmdata *dbmp;
495  DBM *dbm;
496 
497  RETURN_ENUMERATOR(obj, 0, 0);
498 
499  GetDBM2(obj, dbmp, dbm);
500  for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) {
501  val = sdbm_fetch(dbm, key);
503  GetDBM2(obj, dbmp, dbm);
504  }
505  return obj;
506 }
507 
508 static VALUE
510 {
511  datum key;
512  struct dbmdata *dbmp;
513  DBM *dbm;
514 
515  RETURN_ENUMERATOR(obj, 0, 0);
516 
517  GetDBM2(obj, dbmp, dbm);
518  for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) {
520  GetDBM2(obj, dbmp, dbm);
521  }
522  return obj;
523 }
524 
525 static VALUE
527 {
528  datum key, val;
529  DBM *dbm;
530  struct dbmdata *dbmp;
531  VALUE keystr, valstr;
532 
533  RETURN_ENUMERATOR(obj, 0, 0);
534 
535  GetDBM2(obj, dbmp, dbm);
536  for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) {
537  val = sdbm_fetch(dbm, key);
538  keystr = rb_external_str_new(key.dptr, key.dsize);
539  valstr = rb_external_str_new(val.dptr, val.dsize);
540  rb_yield(rb_assoc_new(keystr, valstr));
541  GetDBM2(obj, dbmp, dbm);
542  }
543 
544  return obj;
545 }
546 
547 static VALUE
549 {
550  datum key;
551  struct dbmdata *dbmp;
552  DBM *dbm;
553  VALUE ary;
554 
555  GetDBM2(obj, dbmp, dbm);
556  ary = rb_ary_new();
557  for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) {
558  rb_ary_push(ary, rb_external_str_new(key.dptr, key.dsize));
559  }
560 
561  return ary;
562 }
563 
564 static VALUE
566 {
567  datum key, val;
568  struct dbmdata *dbmp;
569  DBM *dbm;
570  VALUE ary;
571 
572  GetDBM2(obj, dbmp, dbm);
573  ary = rb_ary_new();
574  for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) {
575  val = sdbm_fetch(dbm, key);
576  rb_ary_push(ary, rb_external_str_new(val.dptr, val.dsize));
577  }
578 
579  return ary;
580 }
581 
582 static VALUE
584 {
585  datum key, val;
586  struct dbmdata *dbmp;
587  DBM *dbm;
588 
589  ExportStringValue(keystr);
590  key.dptr = RSTRING_PTR(keystr);
591  key.dsize = RSTRING_LENINT(keystr);
592 
593  GetDBM2(obj, dbmp, dbm);
594  val = sdbm_fetch(dbm, key);
595  if (val.dptr) return Qtrue;
596  return Qfalse;
597 }
598 
599 static VALUE
601 {
602  datum key, val;
603  struct dbmdata *dbmp;
604  DBM *dbm;
605 
606  ExportStringValue(valstr);
607  val.dptr = RSTRING_PTR(valstr);
608  val.dsize = RSTRING_LENINT(valstr);
609 
610  GetDBM2(obj, dbmp, dbm);
611  for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) {
612  val = sdbm_fetch(dbm, key);
613  if (val.dsize == RSTRING_LENINT(valstr) &&
614  memcmp(val.dptr, RSTRING_PTR(valstr), val.dsize) == 0)
615  return Qtrue;
616  }
617  return Qfalse;
618 }
619 
620 static VALUE
622 {
623  datum key, val;
624  struct dbmdata *dbmp;
625  DBM *dbm;
626  VALUE ary;
627 
628  GetDBM2(obj, dbmp, dbm);
629  ary = rb_ary_new();
630  for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) {
631  val = sdbm_fetch(dbm, key);
633  rb_external_str_new(val.dptr, val.dsize)));
634  }
635 
636  return ary;
637 }
638 
639 static VALUE
641 {
642  datum key, val;
643  struct dbmdata *dbmp;
644  DBM *dbm;
645  VALUE hash;
646 
647  GetDBM2(obj, dbmp, dbm);
648  hash = rb_hash_new();
649  for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) {
650  val = sdbm_fetch(dbm, key);
651  rb_hash_aset(hash, rb_external_str_new(key.dptr, key.dsize),
652  rb_external_str_new(val.dptr, val.dsize));
653  }
654 
655  return hash;
656 }
657 
658 static VALUE
660 {
661  return rb_hash_delete_if(fsdbm_to_hash(obj));
662 }
663 
664 void
666 {
670 
673 
674  rb_define_method(rb_cDBM, "initialize", fsdbm_initialize, -1);
675  rb_define_method(rb_cDBM, "close", fsdbm_close, 0);
676  rb_define_method(rb_cDBM, "closed?", fsdbm_closed, 0);
678  rb_define_method(rb_cDBM, "fetch", fsdbm_fetch_m, -1);
680  rb_define_method(rb_cDBM, "store", fsdbm_store, 2);
681  rb_define_method(rb_cDBM, "index", fsdbm_index, 1);
682  rb_define_method(rb_cDBM, "key", fsdbm_key, 1);
683  rb_define_method(rb_cDBM, "select", fsdbm_select, 0);
684  rb_define_method(rb_cDBM, "values_at", fsdbm_values_at, -1);
685  rb_define_method(rb_cDBM, "length", fsdbm_length, 0);
687  rb_define_method(rb_cDBM, "empty?", fsdbm_empty_p, 0);
689  rb_define_method(rb_cDBM, "each_value", fsdbm_each_value, 0);
690  rb_define_method(rb_cDBM, "each_key", fsdbm_each_key, 0);
691  rb_define_method(rb_cDBM, "each_pair", fsdbm_each_pair, 0);
692  rb_define_method(rb_cDBM, "keys", fsdbm_keys, 0);
693  rb_define_method(rb_cDBM, "values", fsdbm_values, 0);
694  rb_define_method(rb_cDBM, "shift", fsdbm_shift, 0);
695  rb_define_method(rb_cDBM, "delete", fsdbm_delete, 1);
696  rb_define_method(rb_cDBM, "delete_if", fsdbm_delete_if, 0);
697  rb_define_method(rb_cDBM, "reject!", fsdbm_delete_if, 0);
698  rb_define_method(rb_cDBM, "reject", fsdbm_reject, 0);
699  rb_define_method(rb_cDBM, "clear", fsdbm_clear, 0);
700  rb_define_method(rb_cDBM,"invert", fsdbm_invert, 0);
701  rb_define_method(rb_cDBM,"update", fsdbm_update, 1);
702  rb_define_method(rb_cDBM,"replace", fsdbm_replace, 1);
703 
704  rb_define_method(rb_cDBM, "include?", fsdbm_has_key, 1);
705  rb_define_method(rb_cDBM, "has_key?", fsdbm_has_key, 1);
706  rb_define_method(rb_cDBM, "member?", fsdbm_has_key, 1);
707  rb_define_method(rb_cDBM, "has_value?", fsdbm_has_value, 1);
710 
711  rb_define_method(rb_cDBM, "to_a", fsdbm_to_a, 0);
712  rb_define_method(rb_cDBM, "to_hash", fsdbm_to_hash, 0);
713 }
714