Ruby
2.0.0p247(2013-06-27revision41674)
|
00001 /************************************************ 00002 00003 dbm.c - 00004 00005 $Author: nobu $ 00006 created at: Mon Jan 24 15:59:52 JST 1994 00007 00008 Copyright (C) 1995-2001 Yukihiro Matsumoto 00009 00010 ************************************************/ 00011 00012 #include "ruby.h" 00013 00014 #ifdef HAVE_CDEFS_H 00015 # include <cdefs.h> 00016 #endif 00017 #ifdef HAVE_SYS_CDEFS_H 00018 # include <sys/cdefs.h> 00019 #endif 00020 #include DBM_HDR 00021 #include <fcntl.h> 00022 #include <errno.h> 00023 00024 #define DSIZE_TYPE TYPEOF_DATUM_DSIZE 00025 #if SIZEOF_DATUM_DSIZE > SIZEOF_INT 00026 # define RSTRING_DSIZE(s) RSTRING_LEN(s) 00027 # define TOO_LONG(n) 0 00028 #else 00029 # define RSTRING_DSIZE(s) RSTRING_LENINT(s) 00030 # define TOO_LONG(n) ((long)(+(DSIZE_TYPE)(n)) != (n)) 00031 #endif 00032 00033 static VALUE rb_cDBM, rb_eDBMError; 00034 00035 #define RUBY_DBM_RW_BIT 0x20000000 00036 00037 struct dbmdata { 00038 long di_size; 00039 DBM *di_dbm; 00040 }; 00041 00042 static void 00043 closed_dbm(void) 00044 { 00045 rb_raise(rb_eDBMError, "closed DBM file"); 00046 } 00047 00048 #define GetDBM(obj, dbmp) {\ 00049 Data_Get_Struct((obj), struct dbmdata, (dbmp));\ 00050 if ((dbmp) == 0) closed_dbm();\ 00051 if ((dbmp)->di_dbm == 0) closed_dbm();\ 00052 } 00053 00054 #define GetDBM2(obj, data, dbm) {\ 00055 GetDBM((obj), (data));\ 00056 (dbm) = dbmp->di_dbm;\ 00057 } 00058 00059 static void 00060 free_dbm(struct dbmdata *dbmp) 00061 { 00062 if (dbmp) { 00063 if (dbmp->di_dbm) dbm_close(dbmp->di_dbm); 00064 xfree(dbmp); 00065 } 00066 } 00067 00068 /* 00069 * call-seq: 00070 * dbm.close 00071 * 00072 * Closes the database. 00073 */ 00074 static VALUE 00075 fdbm_close(VALUE obj) 00076 { 00077 struct dbmdata *dbmp; 00078 00079 GetDBM(obj, dbmp); 00080 dbm_close(dbmp->di_dbm); 00081 dbmp->di_dbm = 0; 00082 00083 return Qnil; 00084 } 00085 00086 /* 00087 * call-seq: 00088 * dbm.closed? -> true or false 00089 * 00090 * Returns true if the database is closed, false otherwise. 00091 */ 00092 static VALUE 00093 fdbm_closed(VALUE obj) 00094 { 00095 struct dbmdata *dbmp; 00096 00097 Data_Get_Struct(obj, struct dbmdata, dbmp); 00098 if (dbmp == 0) 00099 return Qtrue; 00100 if (dbmp->di_dbm == 0) 00101 return Qtrue; 00102 00103 return Qfalse; 00104 } 00105 00106 static VALUE 00107 fdbm_alloc(VALUE klass) 00108 { 00109 return Data_Wrap_Struct(klass, 0, free_dbm, 0); 00110 } 00111 00112 /* 00113 * call-seq: 00114 * DBM.new(filename[, mode[, flags]]) -> dbm 00115 * 00116 * Open a dbm database with the specified name, which can include a directory 00117 * path. Any file extensions needed will be supplied automatically by the dbm 00118 * library. For example, Berkeley DB appends '.db', and GNU gdbm uses two 00119 * physical files with extensions '.dir' and '.pag'. 00120 * 00121 * The mode should be an integer, as for Unix chmod. 00122 * 00123 * Flags should be one of READER, WRITER, WRCREAT or NEWDB. 00124 */ 00125 static VALUE 00126 fdbm_initialize(int argc, VALUE *argv, VALUE obj) 00127 { 00128 volatile VALUE file; 00129 VALUE vmode, vflags; 00130 DBM *dbm; 00131 struct dbmdata *dbmp; 00132 int mode, flags = 0; 00133 00134 if (rb_scan_args(argc, argv, "12", &file, &vmode, &vflags) == 1) { 00135 mode = 0666; /* default value */ 00136 } 00137 else if (NIL_P(vmode)) { 00138 mode = -1; /* return nil if DB not exist */ 00139 } 00140 else { 00141 mode = NUM2INT(vmode); 00142 } 00143 00144 if (!NIL_P(vflags)) 00145 flags = NUM2INT(vflags); 00146 00147 FilePathValue(file); 00148 00149 /* 00150 * Note: 00151 * gdbm 1.10 works with O_CLOEXEC. gdbm 1.9.1 silently ignore it. 00152 */ 00153 #ifndef O_CLOEXEC 00154 # define O_CLOEXEC 0 00155 #endif 00156 00157 if (flags & RUBY_DBM_RW_BIT) { 00158 flags &= ~RUBY_DBM_RW_BIT; 00159 dbm = dbm_open(RSTRING_PTR(file), flags|O_CLOEXEC, mode); 00160 } 00161 else { 00162 dbm = 0; 00163 if (mode >= 0) { 00164 dbm = dbm_open(RSTRING_PTR(file), O_RDWR|O_CREAT|O_CLOEXEC, mode); 00165 } 00166 if (!dbm) { 00167 dbm = dbm_open(RSTRING_PTR(file), O_RDWR|O_CLOEXEC, 0); 00168 } 00169 if (!dbm) { 00170 dbm = dbm_open(RSTRING_PTR(file), O_RDONLY|O_CLOEXEC, 0); 00171 } 00172 } 00173 00174 if (dbm) { 00175 /* 00176 * History of dbm_pagfno() and dbm_dirfno() in ndbm and its compatibles. 00177 * (dbm_pagfno() and dbm_dirfno() is not standardized.) 00178 * 00179 * 1986: 4.3BSD provides ndbm. 00180 * It provides dbm_pagfno() and dbm_dirfno() as macros. 00181 * 1991: gdbm-1.5 provides them as functions. 00182 * They returns a same descriptor. 00183 * (Earlier releases may have the functions too.) 00184 * 1991: Net/2 provides Berkeley DB. 00185 * It doesn't provide dbm_pagfno() and dbm_dirfno(). 00186 * 1992: 4.4BSD Alpha provides Berkeley DB with dbm_dirfno() as a function. 00187 * dbm_pagfno() is a macro as DBM_PAGFNO_NOT_AVAILABLE. 00188 * 1997: Berkeley DB 2.0 is released by Sleepycat Software, Inc. 00189 * It defines dbm_pagfno() and dbm_dirfno() as macros. 00190 * 2011: gdbm-1.9 creates a separate dir file. 00191 * dbm_pagfno() and dbm_dirfno() returns different descriptors. 00192 */ 00193 #if defined(HAVE_DBM_PAGFNO) 00194 rb_fd_fix_cloexec(dbm_pagfno(dbm)); 00195 #endif 00196 #if defined(HAVE_DBM_DIRFNO) 00197 rb_fd_fix_cloexec(dbm_dirfno(dbm)); 00198 #endif 00199 00200 #if defined(RUBYDBM_DB_HEADER) && defined(HAVE_TYPE_DBC) 00201 /* Disable Berkeley DB error messages such as: 00202 * DB->put: attempt to modify a read-only database */ 00203 ((DBC*)dbm)->dbp->set_errfile(((DBC*)dbm)->dbp, NULL); 00204 #endif 00205 } 00206 00207 if (!dbm) { 00208 if (mode == -1) return Qnil; 00209 rb_sys_fail_str(file); 00210 } 00211 00212 dbmp = ALLOC(struct dbmdata); 00213 DATA_PTR(obj) = dbmp; 00214 dbmp->di_dbm = dbm; 00215 dbmp->di_size = -1; 00216 00217 return obj; 00218 } 00219 00220 /* 00221 * call-seq: 00222 * DBM.open(filename[, mode[, flags]]) -> dbm 00223 * DBM.open(filename[, mode[, flags]]) {|dbm| block} 00224 * 00225 * Open a dbm database and yields it if a block is given. See also 00226 * <code>DBM.new</code>. 00227 */ 00228 static VALUE 00229 fdbm_s_open(int argc, VALUE *argv, VALUE klass) 00230 { 00231 VALUE obj = Data_Wrap_Struct(klass, 0, free_dbm, 0); 00232 00233 if (NIL_P(fdbm_initialize(argc, argv, obj))) { 00234 return Qnil; 00235 } 00236 00237 if (rb_block_given_p()) { 00238 return rb_ensure(rb_yield, obj, fdbm_close, obj); 00239 } 00240 00241 return obj; 00242 } 00243 00244 static VALUE 00245 fdbm_fetch(VALUE obj, VALUE keystr, VALUE ifnone) 00246 { 00247 datum key, value; 00248 struct dbmdata *dbmp; 00249 DBM *dbm; 00250 long len; 00251 00252 ExportStringValue(keystr); 00253 len = RSTRING_LEN(keystr); 00254 if (TOO_LONG(len)) goto not_found; 00255 key.dptr = RSTRING_PTR(keystr); 00256 key.dsize = (DSIZE_TYPE)len; 00257 00258 GetDBM2(obj, dbmp, dbm); 00259 value = dbm_fetch(dbm, key); 00260 if (value.dptr == 0) { 00261 not_found: 00262 if (ifnone == Qnil && rb_block_given_p()) 00263 return rb_yield(rb_tainted_str_new(key.dptr, key.dsize)); 00264 return ifnone; 00265 } 00266 return rb_tainted_str_new(value.dptr, value.dsize); 00267 } 00268 00269 /* 00270 * call-seq: 00271 * dbm[key] -> string value or nil 00272 * 00273 * Return a value from the database by locating the key string 00274 * provided. If the key is not found, returns nil. 00275 */ 00276 static VALUE 00277 fdbm_aref(VALUE obj, VALUE keystr) 00278 { 00279 return fdbm_fetch(obj, keystr, Qnil); 00280 } 00281 00282 /* 00283 * call-seq: 00284 * dbm.fetch(key[, ifnone]) -> value 00285 * 00286 * Return a value from the database by locating the key string 00287 * provided. If the key is not found, returns +ifnone+. If +ifnone+ 00288 * is not given, raises IndexError. 00289 */ 00290 static VALUE 00291 fdbm_fetch_m(int argc, VALUE *argv, VALUE obj) 00292 { 00293 VALUE keystr, valstr, ifnone; 00294 00295 rb_scan_args(argc, argv, "11", &keystr, &ifnone); 00296 valstr = fdbm_fetch(obj, keystr, ifnone); 00297 if (argc == 1 && !rb_block_given_p() && NIL_P(valstr)) 00298 rb_raise(rb_eIndexError, "key not found"); 00299 00300 return valstr; 00301 } 00302 00303 /* 00304 * call-seq: 00305 * dbm.key(value) -> string 00306 * 00307 * Returns the key for the specified value. 00308 */ 00309 static VALUE 00310 fdbm_key(VALUE obj, VALUE valstr) 00311 { 00312 datum key, val; 00313 struct dbmdata *dbmp; 00314 DBM *dbm; 00315 long len; 00316 00317 ExportStringValue(valstr); 00318 len = RSTRING_LEN(valstr); 00319 if (TOO_LONG(len)) return Qnil; 00320 val.dptr = RSTRING_PTR(valstr); 00321 val.dsize = (DSIZE_TYPE)len; 00322 00323 GetDBM2(obj, dbmp, dbm); 00324 for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { 00325 val = dbm_fetch(dbm, key); 00326 if ((long)val.dsize == RSTRING_LEN(valstr) && 00327 memcmp(val.dptr, RSTRING_PTR(valstr), val.dsize) == 0) { 00328 return rb_tainted_str_new(key.dptr, key.dsize); 00329 } 00330 } 00331 return Qnil; 00332 } 00333 00334 /* :nodoc: */ 00335 static VALUE 00336 fdbm_index(VALUE hash, VALUE value) 00337 { 00338 rb_warn("DBM#index is deprecated; use DBM#key"); 00339 return fdbm_key(hash, value); 00340 } 00341 00342 /* 00343 * call-seq: 00344 * dbm.select {|key, value| block} -> array 00345 * 00346 * Returns a new array consisting of the [key, value] pairs for which the code 00347 * block returns true. 00348 */ 00349 static VALUE 00350 fdbm_select(VALUE obj) 00351 { 00352 VALUE new = rb_ary_new(); 00353 datum key, val; 00354 DBM *dbm; 00355 struct dbmdata *dbmp; 00356 00357 GetDBM2(obj, dbmp, dbm); 00358 for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { 00359 VALUE assoc, v; 00360 val = dbm_fetch(dbm, key); 00361 assoc = rb_assoc_new(rb_tainted_str_new(key.dptr, key.dsize), 00362 rb_tainted_str_new(val.dptr, val.dsize)); 00363 v = rb_yield(assoc); 00364 if (RTEST(v)) { 00365 rb_ary_push(new, assoc); 00366 } 00367 GetDBM2(obj, dbmp, dbm); 00368 } 00369 00370 return new; 00371 } 00372 00373 /* 00374 * call-seq: 00375 * dbm.values_at(key, ...) -> Array 00376 * 00377 * Returns an array containing the values associated with the given keys. 00378 */ 00379 static VALUE 00380 fdbm_values_at(int argc, VALUE *argv, VALUE obj) 00381 { 00382 VALUE new = rb_ary_new2(argc); 00383 int i; 00384 00385 for (i=0; i<argc; i++) { 00386 rb_ary_push(new, fdbm_fetch(obj, argv[i], Qnil)); 00387 } 00388 00389 return new; 00390 } 00391 00392 static void 00393 fdbm_modify(VALUE obj) 00394 { 00395 rb_secure(4); 00396 if (OBJ_FROZEN(obj)) rb_error_frozen("DBM"); 00397 } 00398 00399 /* 00400 * call-seq: 00401 * dbm.delete(key) 00402 * 00403 * Deletes an entry from the database. 00404 */ 00405 static VALUE 00406 fdbm_delete(VALUE obj, VALUE keystr) 00407 { 00408 datum key, value; 00409 struct dbmdata *dbmp; 00410 DBM *dbm; 00411 VALUE valstr; 00412 long len; 00413 00414 fdbm_modify(obj); 00415 ExportStringValue(keystr); 00416 len = RSTRING_LEN(keystr); 00417 if (TOO_LONG(len)) goto not_found; 00418 key.dptr = RSTRING_PTR(keystr); 00419 key.dsize = (DSIZE_TYPE)len; 00420 00421 GetDBM2(obj, dbmp, dbm); 00422 00423 value = dbm_fetch(dbm, key); 00424 if (value.dptr == 0) { 00425 not_found: 00426 if (rb_block_given_p()) return rb_yield(keystr); 00427 return Qnil; 00428 } 00429 00430 /* need to save value before dbm_delete() */ 00431 valstr = rb_tainted_str_new(value.dptr, value.dsize); 00432 00433 if (dbm_delete(dbm, key)) { 00434 dbmp->di_size = -1; 00435 rb_raise(rb_eDBMError, "dbm_delete failed"); 00436 } 00437 else if (dbmp->di_size >= 0) { 00438 dbmp->di_size--; 00439 } 00440 return valstr; 00441 } 00442 00443 /* 00444 * call-seq: 00445 * dbm.shift() -> [key, value] 00446 * 00447 * Removes a [key, value] pair from the database, and returns it. 00448 * If the database is empty, returns nil. 00449 * The order in which values are removed/returned is not guaranteed. 00450 */ 00451 static VALUE 00452 fdbm_shift(VALUE obj) 00453 { 00454 datum key, val; 00455 struct dbmdata *dbmp; 00456 DBM *dbm; 00457 VALUE keystr, valstr; 00458 00459 fdbm_modify(obj); 00460 GetDBM2(obj, dbmp, dbm); 00461 dbmp->di_size = -1; 00462 00463 key = dbm_firstkey(dbm); 00464 if (!key.dptr) return Qnil; 00465 val = dbm_fetch(dbm, key); 00466 keystr = rb_tainted_str_new(key.dptr, key.dsize); 00467 valstr = rb_tainted_str_new(val.dptr, val.dsize); 00468 dbm_delete(dbm, key); 00469 00470 return rb_assoc_new(keystr, valstr); 00471 } 00472 00473 /* 00474 * call-seq: 00475 * dbm.reject! {|key, value| block} -> self 00476 * dbm.delete_if {|key, value| block} -> self 00477 * 00478 * Deletes all entries for which the code block returns true. 00479 * Returns self. 00480 */ 00481 static VALUE 00482 fdbm_delete_if(VALUE obj) 00483 { 00484 datum key, val; 00485 struct dbmdata *dbmp; 00486 DBM *dbm; 00487 VALUE keystr, valstr; 00488 VALUE ret, ary = rb_ary_tmp_new(0); 00489 int i, status = 0; 00490 long n; 00491 00492 fdbm_modify(obj); 00493 GetDBM2(obj, dbmp, dbm); 00494 n = dbmp->di_size; 00495 dbmp->di_size = -1; 00496 00497 for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { 00498 val = dbm_fetch(dbm, key); 00499 keystr = rb_tainted_str_new(key.dptr, key.dsize); 00500 OBJ_FREEZE(keystr); 00501 valstr = rb_tainted_str_new(val.dptr, val.dsize); 00502 ret = rb_protect(rb_yield, rb_assoc_new(rb_str_dup(keystr), valstr), &status); 00503 if (status != 0) break; 00504 if (RTEST(ret)) rb_ary_push(ary, keystr); 00505 GetDBM2(obj, dbmp, dbm); 00506 } 00507 00508 for (i = 0; i < RARRAY_LEN(ary); i++) { 00509 keystr = RARRAY_PTR(ary)[i]; 00510 key.dptr = RSTRING_PTR(keystr); 00511 key.dsize = (DSIZE_TYPE)RSTRING_LEN(keystr); 00512 if (dbm_delete(dbm, key)) { 00513 rb_raise(rb_eDBMError, "dbm_delete failed"); 00514 } 00515 } 00516 if (status) rb_jump_tag(status); 00517 if (n > 0) dbmp->di_size = n - RARRAY_LEN(ary); 00518 rb_ary_clear(ary); 00519 00520 return obj; 00521 } 00522 00523 /* 00524 * call-seq: 00525 * dbm.clear 00526 * 00527 * Deletes all data from the database. 00528 */ 00529 static VALUE 00530 fdbm_clear(VALUE obj) 00531 { 00532 datum key; 00533 struct dbmdata *dbmp; 00534 DBM *dbm; 00535 00536 fdbm_modify(obj); 00537 GetDBM2(obj, dbmp, dbm); 00538 dbmp->di_size = -1; 00539 while (key = dbm_firstkey(dbm), key.dptr) { 00540 if (dbm_delete(dbm, key)) { 00541 rb_raise(rb_eDBMError, "dbm_delete failed"); 00542 } 00543 } 00544 dbmp->di_size = 0; 00545 00546 return obj; 00547 } 00548 00549 /* 00550 * call-seq: 00551 * dbm.invert -> hash 00552 * 00553 * Returns a Hash (not a DBM database) created by using each value in the 00554 * database as a key, with the corresponding key as its value. 00555 */ 00556 static VALUE 00557 fdbm_invert(VALUE obj) 00558 { 00559 datum key, val; 00560 struct dbmdata *dbmp; 00561 DBM *dbm; 00562 VALUE keystr, valstr; 00563 VALUE hash = rb_hash_new(); 00564 00565 GetDBM2(obj, dbmp, dbm); 00566 for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { 00567 val = dbm_fetch(dbm, key); 00568 keystr = rb_tainted_str_new(key.dptr, key.dsize); 00569 valstr = rb_tainted_str_new(val.dptr, val.dsize); 00570 rb_hash_aset(hash, valstr, keystr); 00571 } 00572 return hash; 00573 } 00574 00575 static VALUE fdbm_store(VALUE,VALUE,VALUE); 00576 00577 static VALUE 00578 update_i(VALUE pair, VALUE dbm) 00579 { 00580 Check_Type(pair, T_ARRAY); 00581 if (RARRAY_LEN(pair) < 2) { 00582 rb_raise(rb_eArgError, "pair must be [key, value]"); 00583 } 00584 fdbm_store(dbm, RARRAY_PTR(pair)[0], RARRAY_PTR(pair)[1]); 00585 return Qnil; 00586 } 00587 00588 /* 00589 * call-seq: 00590 * dbm.update(obj) 00591 * 00592 * Updates the database with multiple values from the specified object. 00593 * Takes any object which implements the each_pair method, including 00594 * Hash and DBM objects. 00595 */ 00596 static VALUE 00597 fdbm_update(VALUE obj, VALUE other) 00598 { 00599 rb_block_call(other, rb_intern("each_pair"), 0, 0, update_i, obj); 00600 return obj; 00601 } 00602 00603 /* 00604 * call-seq: 00605 * dbm.replace(obj) 00606 * 00607 * Replaces the contents of the database with the contents of the specified 00608 * object. Takes any object which implements the each_pair method, including 00609 * Hash and DBM objects. 00610 */ 00611 static VALUE 00612 fdbm_replace(VALUE obj, VALUE other) 00613 { 00614 fdbm_clear(obj); 00615 rb_block_call(other, rb_intern("each_pair"), 0, 0, update_i, obj); 00616 return obj; 00617 } 00618 00619 /* 00620 * call-seq: 00621 * dbm.store(key, value) -> value 00622 * dbm[key] = value 00623 * 00624 * Stores the specified string value in the database, indexed via the 00625 * string key provided. 00626 */ 00627 static VALUE 00628 fdbm_store(VALUE obj, VALUE keystr, VALUE valstr) 00629 { 00630 datum key, val; 00631 struct dbmdata *dbmp; 00632 DBM *dbm; 00633 00634 fdbm_modify(obj); 00635 keystr = rb_obj_as_string(keystr); 00636 valstr = rb_obj_as_string(valstr); 00637 00638 key.dptr = RSTRING_PTR(keystr); 00639 key.dsize = RSTRING_DSIZE(keystr); 00640 00641 val.dptr = RSTRING_PTR(valstr); 00642 val.dsize = RSTRING_DSIZE(valstr); 00643 00644 GetDBM2(obj, dbmp, dbm); 00645 dbmp->di_size = -1; 00646 if (dbm_store(dbm, key, val, DBM_REPLACE)) { 00647 dbm_clearerr(dbm); 00648 if (errno == EPERM) rb_sys_fail(0); 00649 rb_raise(rb_eDBMError, "dbm_store failed"); 00650 } 00651 00652 return valstr; 00653 } 00654 00655 /* 00656 * call-seq: 00657 * dbm.length -> integer 00658 * 00659 * Returns the number of entries in the database. 00660 */ 00661 static VALUE 00662 fdbm_length(VALUE obj) 00663 { 00664 datum key; 00665 struct dbmdata *dbmp; 00666 DBM *dbm; 00667 int i = 0; 00668 00669 GetDBM2(obj, dbmp, dbm); 00670 if (dbmp->di_size > 0) return INT2FIX(dbmp->di_size); 00671 00672 for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { 00673 i++; 00674 } 00675 dbmp->di_size = i; 00676 00677 return INT2FIX(i); 00678 } 00679 00680 /* 00681 * call-seq: 00682 * dbm.empty? 00683 * 00684 * Returns true if the database is empty, false otherwise. 00685 */ 00686 static VALUE 00687 fdbm_empty_p(VALUE obj) 00688 { 00689 datum key; 00690 struct dbmdata *dbmp; 00691 DBM *dbm; 00692 00693 GetDBM2(obj, dbmp, dbm); 00694 if (dbmp->di_size < 0) { 00695 dbm = dbmp->di_dbm; 00696 00697 for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { 00698 return Qfalse; 00699 } 00700 } 00701 else { 00702 if (dbmp->di_size) 00703 return Qfalse; 00704 } 00705 return Qtrue; 00706 } 00707 00708 /* 00709 * call-seq: 00710 * dbm.each_value {|value| block} -> self 00711 * 00712 * Calls the block once for each value string in the database. Returns self. 00713 */ 00714 static VALUE 00715 fdbm_each_value(VALUE obj) 00716 { 00717 datum key, val; 00718 struct dbmdata *dbmp; 00719 DBM *dbm; 00720 00721 RETURN_ENUMERATOR(obj, 0, 0); 00722 00723 GetDBM2(obj, dbmp, dbm); 00724 for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { 00725 val = dbm_fetch(dbm, key); 00726 rb_yield(rb_tainted_str_new(val.dptr, val.dsize)); 00727 GetDBM2(obj, dbmp, dbm); 00728 } 00729 return obj; 00730 } 00731 00732 /* 00733 * call-seq: 00734 * dbm.each_key {|key| block} -> self 00735 * 00736 * Calls the block once for each key string in the database. Returns self. 00737 */ 00738 static VALUE 00739 fdbm_each_key(VALUE obj) 00740 { 00741 datum key; 00742 struct dbmdata *dbmp; 00743 DBM *dbm; 00744 00745 RETURN_ENUMERATOR(obj, 0, 0); 00746 00747 GetDBM2(obj, dbmp, dbm); 00748 for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { 00749 rb_yield(rb_tainted_str_new(key.dptr, key.dsize)); 00750 GetDBM2(obj, dbmp, dbm); 00751 } 00752 return obj; 00753 } 00754 00755 /* 00756 * call-seq: 00757 * dbm.each_pair {|key,value| block} -> self 00758 * 00759 * Calls the block once for each [key, value] pair in the database. 00760 * Returns self. 00761 */ 00762 static VALUE 00763 fdbm_each_pair(VALUE obj) 00764 { 00765 datum key, val; 00766 DBM *dbm; 00767 struct dbmdata *dbmp; 00768 VALUE keystr, valstr; 00769 00770 RETURN_ENUMERATOR(obj, 0, 0); 00771 00772 GetDBM2(obj, dbmp, dbm); 00773 00774 for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { 00775 val = dbm_fetch(dbm, key); 00776 keystr = rb_tainted_str_new(key.dptr, key.dsize); 00777 valstr = rb_tainted_str_new(val.dptr, val.dsize); 00778 rb_yield(rb_assoc_new(keystr, valstr)); 00779 GetDBM2(obj, dbmp, dbm); 00780 } 00781 00782 return obj; 00783 } 00784 00785 /* 00786 * call-seq: 00787 * dbm.keys -> array 00788 * 00789 * Returns an array of all the string keys in the database. 00790 */ 00791 static VALUE 00792 fdbm_keys(VALUE obj) 00793 { 00794 datum key; 00795 struct dbmdata *dbmp; 00796 DBM *dbm; 00797 VALUE ary; 00798 00799 GetDBM2(obj, dbmp, dbm); 00800 00801 ary = rb_ary_new(); 00802 for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { 00803 rb_ary_push(ary, rb_tainted_str_new(key.dptr, key.dsize)); 00804 } 00805 00806 return ary; 00807 } 00808 00809 /* 00810 * call-seq: 00811 * dbm.values -> array 00812 * 00813 * Returns an array of all the string values in the database. 00814 */ 00815 static VALUE 00816 fdbm_values(VALUE obj) 00817 { 00818 datum key, val; 00819 struct dbmdata *dbmp; 00820 DBM *dbm; 00821 VALUE ary; 00822 00823 GetDBM2(obj, dbmp, dbm); 00824 ary = rb_ary_new(); 00825 for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { 00826 val = dbm_fetch(dbm, key); 00827 rb_ary_push(ary, rb_tainted_str_new(val.dptr, val.dsize)); 00828 } 00829 00830 return ary; 00831 } 00832 00833 /* 00834 * call-seq: 00835 * dbm.has_key?(key) -> boolean 00836 * 00837 * Returns true if the database contains the specified key, false otherwise. 00838 */ 00839 static VALUE 00840 fdbm_has_key(VALUE obj, VALUE keystr) 00841 { 00842 datum key, val; 00843 struct dbmdata *dbmp; 00844 DBM *dbm; 00845 long len; 00846 00847 ExportStringValue(keystr); 00848 len = RSTRING_LEN(keystr); 00849 if (TOO_LONG(len)) return Qfalse; 00850 key.dptr = RSTRING_PTR(keystr); 00851 key.dsize = (DSIZE_TYPE)len; 00852 00853 GetDBM2(obj, dbmp, dbm); 00854 val = dbm_fetch(dbm, key); 00855 if (val.dptr) return Qtrue; 00856 return Qfalse; 00857 } 00858 00859 /* 00860 * call-seq: 00861 * dbm.has_value?(value) -> boolean 00862 * 00863 * Returns true if the database contains the specified string value, false 00864 * otherwise. 00865 */ 00866 static VALUE 00867 fdbm_has_value(VALUE obj, VALUE valstr) 00868 { 00869 datum key, val; 00870 struct dbmdata *dbmp; 00871 DBM *dbm; 00872 long len; 00873 00874 ExportStringValue(valstr); 00875 len = RSTRING_LEN(valstr); 00876 if (TOO_LONG(len)) return Qfalse; 00877 val.dptr = RSTRING_PTR(valstr); 00878 val.dsize = (DSIZE_TYPE)len; 00879 00880 GetDBM2(obj, dbmp, dbm); 00881 for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { 00882 val = dbm_fetch(dbm, key); 00883 if ((DSIZE_TYPE)val.dsize == (DSIZE_TYPE)RSTRING_LEN(valstr) && 00884 memcmp(val.dptr, RSTRING_PTR(valstr), val.dsize) == 0) 00885 return Qtrue; 00886 } 00887 return Qfalse; 00888 } 00889 00890 /* 00891 * call-seq: 00892 * dbm.to_a -> array 00893 * 00894 * Converts the contents of the database to an array of [key, value] arrays, 00895 * and returns it. 00896 */ 00897 static VALUE 00898 fdbm_to_a(VALUE obj) 00899 { 00900 datum key, val; 00901 struct dbmdata *dbmp; 00902 DBM *dbm; 00903 VALUE ary; 00904 00905 GetDBM2(obj, dbmp, dbm); 00906 ary = rb_ary_new(); 00907 for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { 00908 val = dbm_fetch(dbm, key); 00909 rb_ary_push(ary, rb_assoc_new(rb_tainted_str_new(key.dptr, key.dsize), 00910 rb_tainted_str_new(val.dptr, val.dsize))); 00911 } 00912 00913 return ary; 00914 } 00915 00916 /* 00917 * call-seq: 00918 * dbm.to_hash -> hash 00919 * 00920 * Converts the contents of the database to an in-memory Hash object, and 00921 * returns it. 00922 */ 00923 static VALUE 00924 fdbm_to_hash(VALUE obj) 00925 { 00926 datum key, val; 00927 struct dbmdata *dbmp; 00928 DBM *dbm; 00929 VALUE hash; 00930 00931 GetDBM2(obj, dbmp, dbm); 00932 hash = rb_hash_new(); 00933 for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { 00934 val = dbm_fetch(dbm, key); 00935 rb_hash_aset(hash, rb_tainted_str_new(key.dptr, key.dsize), 00936 rb_tainted_str_new(val.dptr, val.dsize)); 00937 } 00938 00939 return hash; 00940 } 00941 00942 /* 00943 * call-seq: 00944 * dbm.reject {|key,value| block} -> Hash 00945 * 00946 * Converts the contents of the database to an in-memory Hash, then calls 00947 * Hash#reject with the specified code block, returning a new Hash. 00948 */ 00949 static VALUE 00950 fdbm_reject(VALUE obj) 00951 { 00952 return rb_hash_delete_if(fdbm_to_hash(obj)); 00953 } 00954 00955 /* 00956 * Documented by mathew meta@pobox.com. 00957 * = Introduction 00958 * 00959 * The DBM class provides a wrapper to a Unix-style 00960 * {dbm}[http://en.wikipedia.org/wiki/Dbm] or Database Manager library. 00961 * 00962 * Dbm databases do not have tables or columns; they are simple key-value 00963 * data stores, like a Ruby Hash except not resident in RAM. Keys and values 00964 * must be strings. 00965 * 00966 * The exact library used depends on how Ruby was compiled. It could be any 00967 * of the following: 00968 * 00969 * - The original ndbm library is released in 4.3BSD. 00970 * It is based on dbm library in Unix Version 7 but has different API to 00971 * support multiple databases in a process. 00972 * - {Berkeley DB}[http://en.wikipedia.org/wiki/Berkeley_DB] versions 00973 * 1 thru 5, also known as BDB and Sleepycat DB, now owned by Oracle 00974 * Corporation. 00975 * - Berkeley DB 1.x, still found in 4.4BSD derivatives (FreeBSD, OpenBSD, etc). 00976 * - {gdbm}[http://www.gnu.org/software/gdbm/], the GNU implementation of dbm. 00977 * - {qdbm}[http://fallabs.com/qdbm/index.html], another open source 00978 * reimplementation of dbm. 00979 * 00980 * All of these dbm implementations have their own Ruby interfaces 00981 * available, which provide richer (but varying) APIs. 00982 * 00983 * = Cautions 00984 * 00985 * Before you decide to use DBM, there are some issues you should consider: 00986 * 00987 * - Each implementation of dbm has its own file format. Generally, dbm 00988 * libraries will not read each other's files. This makes dbm files 00989 * a bad choice for data exchange. 00990 * 00991 * - Even running the same OS and the same dbm implementation, the database 00992 * file format may depend on the CPU architecture. For example, files may 00993 * not be portable between PowerPC and 386, or between 32 and 64 bit Linux. 00994 * 00995 * - Different versions of Berkeley DB use different file formats. A change to 00996 * the OS may therefore break DBM access to existing files. 00997 * 00998 * - Data size limits vary between implementations. Original Berkeley DB was 00999 * limited to 2GB of data. Dbm libraries also sometimes limit the total 01000 * size of a key/value pair, and the total size of all the keys that hash 01001 * to the same value. These limits can be as little as 512 bytes. That said, 01002 * gdbm and recent versions of Berkeley DB do away with these limits. 01003 * 01004 * Given the above cautions, DBM is not a good choice for long term storage of 01005 * important data. It is probably best used as a fast and easy alternative 01006 * to a Hash for processing large amounts of data. 01007 * 01008 * = Example 01009 * 01010 * require 'dbm' 01011 * db = DBM.open('rfcs', 666, DBM::CREATRW) 01012 * db['822'] = 'Standard for the Format of ARPA Internet Text Messages' 01013 * db['1123'] = 'Requirements for Internet Hosts - Application and Support' 01014 * db['3068'] = 'An Anycast Prefix for 6to4 Relay Routers' 01015 * puts db['822'] 01016 */ 01017 void 01018 Init_dbm(void) 01019 { 01020 rb_cDBM = rb_define_class("DBM", rb_cObject); 01021 /* Document-class: DBMError 01022 * Exception class used to return errors from the dbm library. 01023 */ 01024 rb_eDBMError = rb_define_class("DBMError", rb_eStandardError); 01025 rb_include_module(rb_cDBM, rb_mEnumerable); 01026 01027 rb_define_alloc_func(rb_cDBM, fdbm_alloc); 01028 rb_define_singleton_method(rb_cDBM, "open", fdbm_s_open, -1); 01029 01030 rb_define_method(rb_cDBM, "initialize", fdbm_initialize, -1); 01031 rb_define_method(rb_cDBM, "close", fdbm_close, 0); 01032 rb_define_method(rb_cDBM, "closed?", fdbm_closed, 0); 01033 rb_define_method(rb_cDBM, "[]", fdbm_aref, 1); 01034 rb_define_method(rb_cDBM, "fetch", fdbm_fetch_m, -1); 01035 rb_define_method(rb_cDBM, "[]=", fdbm_store, 2); 01036 rb_define_method(rb_cDBM, "store", fdbm_store, 2); 01037 rb_define_method(rb_cDBM, "index", fdbm_index, 1); 01038 rb_define_method(rb_cDBM, "key", fdbm_key, 1); 01039 rb_define_method(rb_cDBM, "select", fdbm_select, 0); 01040 rb_define_method(rb_cDBM, "values_at", fdbm_values_at, -1); 01041 rb_define_method(rb_cDBM, "length", fdbm_length, 0); 01042 rb_define_method(rb_cDBM, "size", fdbm_length, 0); 01043 rb_define_method(rb_cDBM, "empty?", fdbm_empty_p, 0); 01044 rb_define_method(rb_cDBM, "each", fdbm_each_pair, 0); 01045 rb_define_method(rb_cDBM, "each_value", fdbm_each_value, 0); 01046 rb_define_method(rb_cDBM, "each_key", fdbm_each_key, 0); 01047 rb_define_method(rb_cDBM, "each_pair", fdbm_each_pair, 0); 01048 rb_define_method(rb_cDBM, "keys", fdbm_keys, 0); 01049 rb_define_method(rb_cDBM, "values", fdbm_values, 0); 01050 rb_define_method(rb_cDBM, "shift", fdbm_shift, 0); 01051 rb_define_method(rb_cDBM, "delete", fdbm_delete, 1); 01052 rb_define_method(rb_cDBM, "delete_if", fdbm_delete_if, 0); 01053 rb_define_method(rb_cDBM, "reject!", fdbm_delete_if, 0); 01054 rb_define_method(rb_cDBM, "reject", fdbm_reject, 0); 01055 rb_define_method(rb_cDBM, "clear", fdbm_clear, 0); 01056 rb_define_method(rb_cDBM, "invert", fdbm_invert, 0); 01057 rb_define_method(rb_cDBM, "update", fdbm_update, 1); 01058 rb_define_method(rb_cDBM, "replace", fdbm_replace, 1); 01059 01060 rb_define_method(rb_cDBM, "include?", fdbm_has_key, 1); 01061 rb_define_method(rb_cDBM, "has_key?", fdbm_has_key, 1); 01062 rb_define_method(rb_cDBM, "member?", fdbm_has_key, 1); 01063 rb_define_method(rb_cDBM, "has_value?", fdbm_has_value, 1); 01064 rb_define_method(rb_cDBM, "key?", fdbm_has_key, 1); 01065 rb_define_method(rb_cDBM, "value?", fdbm_has_value, 1); 01066 01067 rb_define_method(rb_cDBM, "to_a", fdbm_to_a, 0); 01068 rb_define_method(rb_cDBM, "to_hash", fdbm_to_hash, 0); 01069 01070 /* Indicates that dbm_open() should open the database in read-only mode */ 01071 rb_define_const(rb_cDBM, "READER", INT2FIX(O_RDONLY|RUBY_DBM_RW_BIT)); 01072 01073 /* Indicates that dbm_open() should open the database in read/write mode */ 01074 rb_define_const(rb_cDBM, "WRITER", INT2FIX(O_RDWR|RUBY_DBM_RW_BIT)); 01075 01076 /* Indicates that dbm_open() should open the database in read/write mode, 01077 * and create it if it does not already exist 01078 */ 01079 rb_define_const(rb_cDBM, "WRCREAT", INT2FIX(O_RDWR|O_CREAT|RUBY_DBM_RW_BIT)); 01080 01081 /* Indicates that dbm_open() should open the database in read/write mode, 01082 * create it if it does not already exist, and delete all contents if it 01083 * does already exist. 01084 */ 01085 rb_define_const(rb_cDBM, "NEWDB", INT2FIX(O_RDWR|O_CREAT|O_TRUNC|RUBY_DBM_RW_BIT)); 01086 01087 { 01088 VALUE version; 01089 #if defined(_DBM_IOERR) 01090 version = rb_str_new2("ndbm (4.3BSD)"); 01091 #elif defined(RUBYDBM_GDBM_HEADER) 01092 # if defined(HAVE_DECLARED_LIBVAR_GDBM_VERSION) 01093 /* since gdbm 1.9 */ 01094 version = rb_str_new2(gdbm_version); 01095 # elif defined(HAVE_UNDECLARED_LIBVAR_GDBM_VERSION) 01096 /* ndbm.h doesn't declare gdbm_version until gdbm 1.8.3. 01097 * See extconf.rb for more information. */ 01098 RUBY_EXTERN char *gdbm_version; 01099 version = rb_str_new2(gdbm_version); 01100 # else 01101 version = rb_str_new2("GDBM (unknown)"); 01102 # endif 01103 #elif defined(RUBYDBM_DB_HEADER) 01104 # if defined(HAVE_DB_VERSION) 01105 /* The version of the dbm library, if using Berkeley DB */ 01106 version = rb_str_new2(db_version(NULL, NULL, NULL)); 01107 # else 01108 version = rb_str_new2("Berkeley DB (unknown)"); 01109 # endif 01110 #elif defined(_RELIC_H) 01111 # if defined(HAVE_DPVERSION) 01112 version = rb_sprintf("QDBM %s", dpversion); 01113 # else 01114 version = rb_str_new2("QDBM (unknown)"); 01115 # endif 01116 #else 01117 version = rb_str_new2("ndbm (unknown)"); 01118 #endif 01119 /* 01120 * Identifies ndbm library version. 01121 * 01122 * Examples: 01123 * 01124 * - "ndbm (4.3BSD)" 01125 * - "Berkeley DB 4.8.30: (April 9, 2010)" 01126 * - "Berkeley DB (unknown)" (4.4BSD, maybe) 01127 * - "GDBM version 1.8.3. 10/15/2002 (built Jul 1 2011 12:32:45)" 01128 * - "QDBM 1.8.78" 01129 * 01130 */ 01131 rb_define_const(rb_cDBM, "VERSION", version); 01132 } 01133 } 01134