Ruby
2.0.0p247(2013-06-27revision41674)
|
00001 /************************************************ 00002 00003 gdbm.c - 00004 00005 $Author: nobu $ 00006 modified at: Mon Jan 24 15:59:52 JST 1994 00007 00008 Documentation by Peter Adolphs < futzilogik at users dot sourceforge dot net > 00009 00010 ************************************************/ 00011 00012 #include "ruby.h" 00013 00014 #include <gdbm.h> 00015 #include <fcntl.h> 00016 #include <errno.h> 00017 00018 /* 00019 * Document-class: GDBM 00020 * 00021 * == Summary 00022 * 00023 * Ruby extension for GNU dbm (gdbm) -- a simple database engine for storing 00024 * key-value pairs on disk. 00025 * 00026 * == Description 00027 * 00028 * GNU dbm is a library for simple databases. A database is a file that stores 00029 * key-value pairs. Gdbm allows the user to store, retrieve, and delete data by 00030 * key. It furthermore allows a non-sorted traversal of all key-value pairs. 00031 * A gdbm database thus provides the same functionality as a hash. As 00032 * with objects of the Hash class, elements can be accessed with <tt>[]</tt>. 00033 * Furthermore, GDBM mixes in the Enumerable module, thus providing convenient 00034 * methods such as #find, #collect, #map, etc. 00035 * 00036 * A process is allowed to open several different databases at the same time. 00037 * A process can open a database as a "reader" or a "writer". Whereas a reader 00038 * has only read-access to the database, a writer has read- and write-access. 00039 * A database can be accessed either by any number of readers or by exactly one 00040 * writer at the same time. 00041 * 00042 * == Examples 00043 * 00044 * 1. Opening/creating a database, and filling it with some entries: 00045 * 00046 * require 'gdbm' 00047 * 00048 * gdbm = GDBM.new("fruitstore.db") 00049 * gdbm["ananas"] = "3" 00050 * gdbm["banana"] = "8" 00051 * gdbm["cranberry"] = "4909" 00052 * gdbm.close 00053 * 00054 * 2. Reading out a database: 00055 * 00056 * require 'gdbm' 00057 * 00058 * gdbm = GDBM.new("fruitstore.db") 00059 * gdbm.each_pair do |key, value| 00060 * print "#{key}: #{value}\n" 00061 * end 00062 * gdbm.close 00063 * 00064 * produces 00065 * 00066 * banana: 8 00067 * ananas: 3 00068 * cranberry: 4909 00069 * 00070 * == Links 00071 * 00072 * * http://www.gnu.org/software/gdbm/ 00073 */ 00074 static VALUE rb_cGDBM, rb_eGDBMError, rb_eGDBMFatalError; 00075 00076 #if SIZEOF_LONG > SIZEOF_INT 00077 #define TOO_LONG(n) ((long)(+(int)(n)) != (long)(n)) 00078 #else 00079 #define TOO_LONG(n) 0 00080 #endif 00081 00082 #define RUBY_GDBM_RW_BIT 0x20000000 00083 00084 #define MY_BLOCK_SIZE (2048) 00085 #define MY_FATAL_FUNC rb_gdbm_fatal 00086 static void 00087 rb_gdbm_fatal(const char *msg) 00088 { 00089 rb_raise(rb_eGDBMFatalError, "%s", msg); 00090 } 00091 00092 struct dbmdata { 00093 int di_size; 00094 GDBM_FILE di_dbm; 00095 }; 00096 00097 static void 00098 closed_dbm(void) 00099 { 00100 rb_raise(rb_eRuntimeError, "closed GDBM file"); 00101 } 00102 00103 #define GetDBM(obj, dbmp) do {\ 00104 Data_Get_Struct((obj), struct dbmdata, (dbmp));\ 00105 if ((dbmp) == 0) closed_dbm();\ 00106 if ((dbmp)->di_dbm == 0) closed_dbm();\ 00107 } while (0) 00108 00109 #define GetDBM2(obj, data, dbm) {\ 00110 GetDBM((obj), (data));\ 00111 (dbm) = dbmp->di_dbm;\ 00112 } 00113 00114 static void 00115 free_dbm(struct dbmdata *dbmp) 00116 { 00117 if (dbmp) { 00118 if (dbmp->di_dbm) gdbm_close(dbmp->di_dbm); 00119 xfree(dbmp); 00120 } 00121 } 00122 00123 /* 00124 * call-seq: 00125 * gdbm.close -> nil 00126 * 00127 * Closes the associated database file. 00128 */ 00129 static VALUE 00130 fgdbm_close(VALUE obj) 00131 { 00132 struct dbmdata *dbmp; 00133 00134 GetDBM(obj, dbmp); 00135 gdbm_close(dbmp->di_dbm); 00136 dbmp->di_dbm = 0; 00137 00138 return Qnil; 00139 } 00140 00141 /* 00142 * call-seq: 00143 * gdbm.closed? -> true or false 00144 * 00145 * Returns true if the associated database file has been closed. 00146 */ 00147 static VALUE 00148 fgdbm_closed(VALUE obj) 00149 { 00150 struct dbmdata *dbmp; 00151 00152 Data_Get_Struct(obj, struct dbmdata, dbmp); 00153 if (dbmp == 0) 00154 return Qtrue; 00155 if (dbmp->di_dbm == 0) 00156 return Qtrue; 00157 00158 return Qfalse; 00159 } 00160 00161 static VALUE 00162 fgdbm_s_alloc(VALUE klass) 00163 { 00164 return Data_Wrap_Struct(klass, 0, free_dbm, 0); 00165 } 00166 00167 /* 00168 * call-seq: 00169 * GDBM.new(filename, mode = 0666, flags = nil) 00170 * 00171 * Creates a new GDBM instance by opening a gdbm file named _filename_. 00172 * If the file does not exist, a new file with file mode _mode_ will be 00173 * created. _flags_ may be one of the following: 00174 * * *READER* - open as a reader 00175 * * *WRITER* - open as a writer 00176 * * *WRCREAT* - open as a writer; if the database does not exist, create a new one 00177 * * *NEWDB* - open as a writer; overwrite any existing databases 00178 * 00179 * The values *WRITER*, *WRCREAT* and *NEWDB* may be combined with the following 00180 * values by bitwise or: 00181 * * *SYNC* - cause all database operations to be synchronized to the disk 00182 * * *NOLOCK* - do not lock the database file 00183 * 00184 * If no _flags_ are specified, the GDBM object will try to open the database 00185 * file as a writer and will create it if it does not already exist 00186 * (cf. flag <tt>WRCREAT</tt>). If this fails (for instance, if another process 00187 * has already opened the database as a reader), it will try to open the 00188 * database file as a reader (cf. flag <tt>READER</tt>). 00189 */ 00190 static VALUE 00191 fgdbm_initialize(int argc, VALUE *argv, VALUE obj) 00192 { 00193 VALUE file, vmode, vflags; 00194 GDBM_FILE dbm; 00195 struct dbmdata *dbmp; 00196 int mode, flags = 0; 00197 00198 if (rb_scan_args(argc, argv, "12", &file, &vmode, &vflags) == 1) { 00199 mode = 0666; /* default value */ 00200 } 00201 else if (NIL_P(vmode)) { 00202 mode = -1; /* return nil if DB does not exist */ 00203 } 00204 else { 00205 mode = NUM2INT(vmode); 00206 } 00207 00208 if (!NIL_P(vflags)) 00209 flags = NUM2INT(vflags); 00210 00211 SafeStringValue(file); 00212 00213 #ifdef GDBM_CLOEXEC 00214 /* GDBM_CLOEXEC is available since gdbm 1.10. */ 00215 flags |= GDBM_CLOEXEC; 00216 #endif 00217 00218 if (flags & RUBY_GDBM_RW_BIT) { 00219 flags &= ~RUBY_GDBM_RW_BIT; 00220 dbm = gdbm_open(RSTRING_PTR(file), MY_BLOCK_SIZE, 00221 flags, mode, MY_FATAL_FUNC); 00222 } 00223 else { 00224 dbm = 0; 00225 if (mode >= 0) 00226 dbm = gdbm_open(RSTRING_PTR(file), MY_BLOCK_SIZE, 00227 GDBM_WRCREAT|flags, mode, MY_FATAL_FUNC); 00228 if (!dbm) 00229 dbm = gdbm_open(RSTRING_PTR(file), MY_BLOCK_SIZE, 00230 GDBM_WRITER|flags, 0, MY_FATAL_FUNC); 00231 if (!dbm) 00232 dbm = gdbm_open(RSTRING_PTR(file), MY_BLOCK_SIZE, 00233 GDBM_READER|flags, 0, MY_FATAL_FUNC); 00234 } 00235 00236 if (dbm) { 00237 rb_fd_fix_cloexec(gdbm_fdesc(dbm)); 00238 } 00239 00240 if (!dbm) { 00241 if (mode == -1) return Qnil; 00242 00243 if (gdbm_errno == GDBM_FILE_OPEN_ERROR || 00244 gdbm_errno == GDBM_CANT_BE_READER || 00245 gdbm_errno == GDBM_CANT_BE_WRITER) 00246 rb_sys_fail_str(file); 00247 else 00248 rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno)); 00249 } 00250 00251 dbmp = ALLOC(struct dbmdata); 00252 free_dbm(DATA_PTR(obj)); 00253 DATA_PTR(obj) = dbmp; 00254 dbmp->di_dbm = dbm; 00255 dbmp->di_size = -1; 00256 00257 return obj; 00258 } 00259 00260 /* 00261 * call-seq: 00262 * GDBM.open(filename, mode = 0666, flags = nil) 00263 * GDBM.open(filename, mode = 0666, flags = nil) { |gdbm| ... } 00264 * 00265 * If called without a block, this is synonymous to GDBM::new. 00266 * If a block is given, the new GDBM instance will be passed to the block 00267 * as a parameter, and the corresponding database file will be closed 00268 * after the execution of the block code has been finished. 00269 * 00270 * Example for an open call with a block: 00271 * 00272 * require 'gdbm' 00273 * GDBM.open("fruitstore.db") do |gdbm| 00274 * gdbm.each_pair do |key, value| 00275 * print "#{key}: #{value}\n" 00276 * end 00277 * end 00278 */ 00279 static VALUE 00280 fgdbm_s_open(int argc, VALUE *argv, VALUE klass) 00281 { 00282 VALUE obj = Data_Wrap_Struct(klass, 0, free_dbm, 0); 00283 00284 if (NIL_P(fgdbm_initialize(argc, argv, obj))) { 00285 return Qnil; 00286 } 00287 00288 if (rb_block_given_p()) { 00289 return rb_ensure(rb_yield, obj, fgdbm_close, obj); 00290 } 00291 00292 return obj; 00293 } 00294 00295 static VALUE 00296 rb_gdbm_fetch(GDBM_FILE dbm, datum key) 00297 { 00298 datum val; 00299 VALUE str; 00300 00301 val = gdbm_fetch(dbm, key); 00302 if (val.dptr == 0) 00303 return Qnil; 00304 00305 str = rb_str_new(val.dptr, val.dsize); 00306 free(val.dptr); 00307 OBJ_TAINT(str); 00308 return str; 00309 } 00310 00311 static VALUE 00312 rb_gdbm_fetch2(GDBM_FILE dbm, VALUE keystr) 00313 { 00314 datum key; 00315 long len; 00316 00317 StringValue(keystr); 00318 len = RSTRING_LEN(keystr); 00319 if (TOO_LONG(len)) return Qnil; 00320 key.dptr = RSTRING_PTR(keystr); 00321 key.dsize = (int)len; 00322 00323 return rb_gdbm_fetch(dbm, key); 00324 } 00325 00326 static VALUE 00327 rb_gdbm_fetch3(VALUE obj, VALUE keystr) 00328 { 00329 struct dbmdata *dbmp; 00330 GDBM_FILE dbm; 00331 00332 GetDBM2(obj, dbmp, dbm); 00333 return rb_gdbm_fetch2(dbm, keystr); 00334 } 00335 00336 static VALUE 00337 rb_gdbm_firstkey(GDBM_FILE dbm) 00338 { 00339 datum key; 00340 VALUE str; 00341 00342 key = gdbm_firstkey(dbm); 00343 if (key.dptr == 0) 00344 return Qnil; 00345 00346 str = rb_str_new(key.dptr, key.dsize); 00347 free(key.dptr); 00348 OBJ_TAINT(str); 00349 return str; 00350 } 00351 00352 static VALUE 00353 rb_gdbm_nextkey(GDBM_FILE dbm, VALUE keystr) 00354 { 00355 datum key, key2; 00356 VALUE str; 00357 long len; 00358 00359 len = RSTRING_LEN(keystr); 00360 if (TOO_LONG(len)) return Qnil; 00361 key.dptr = RSTRING_PTR(keystr); 00362 key.dsize = (int)len; 00363 key2 = gdbm_nextkey(dbm, key); 00364 if (key2.dptr == 0) 00365 return Qnil; 00366 00367 str = rb_str_new(key2.dptr, key2.dsize); 00368 free(key2.dptr); 00369 OBJ_TAINT(str); 00370 return str; 00371 } 00372 00373 static VALUE 00374 fgdbm_fetch(VALUE obj, VALUE keystr, VALUE ifnone) 00375 { 00376 VALUE valstr; 00377 00378 valstr = rb_gdbm_fetch3(obj, keystr); 00379 if (NIL_P(valstr)) { 00380 if (ifnone == Qnil && rb_block_given_p()) 00381 return rb_yield(keystr); 00382 return ifnone; 00383 } 00384 return valstr; 00385 } 00386 00387 /* 00388 * call-seq: 00389 * gdbm[key] -> value 00390 * 00391 * Retrieves the _value_ corresponding to _key_. 00392 */ 00393 static VALUE 00394 fgdbm_aref(VALUE obj, VALUE keystr) 00395 { 00396 return rb_gdbm_fetch3(obj, keystr); 00397 } 00398 00399 /* 00400 * call-seq: 00401 * gdbm.fetch(key [, default]) -> value 00402 * 00403 * Retrieves the _value_ corresponding to _key_. If there is no value 00404 * associated with _key_, _default_ will be returned instead. 00405 */ 00406 static VALUE 00407 fgdbm_fetch_m(int argc, VALUE *argv, VALUE obj) 00408 { 00409 VALUE keystr, valstr, ifnone; 00410 00411 rb_scan_args(argc, argv, "11", &keystr, &ifnone); 00412 valstr = fgdbm_fetch(obj, keystr, ifnone); 00413 if (argc == 1 && !rb_block_given_p() && NIL_P(valstr)) 00414 rb_raise(rb_eIndexError, "key not found"); 00415 00416 return valstr; 00417 } 00418 00419 /* 00420 * call-seq: 00421 * gdbm.key(value) -> key 00422 * 00423 * Returns the _key_ for a given _value_. If several keys may map to the 00424 * same value, the key that is found first will be returned. 00425 */ 00426 static VALUE 00427 fgdbm_key(VALUE obj, VALUE valstr) 00428 { 00429 struct dbmdata *dbmp; 00430 GDBM_FILE dbm; 00431 VALUE keystr, valstr2; 00432 00433 StringValue(valstr); 00434 GetDBM2(obj, dbmp, dbm); 00435 for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr); 00436 keystr = rb_gdbm_nextkey(dbm, keystr)) { 00437 00438 valstr2 = rb_gdbm_fetch2(dbm, keystr); 00439 if (!NIL_P(valstr2) && 00440 (int)RSTRING_LEN(valstr) == (int)RSTRING_LEN(valstr2) && 00441 memcmp(RSTRING_PTR(valstr), RSTRING_PTR(valstr2), 00442 (int)RSTRING_LEN(valstr)) == 0) { 00443 return keystr; 00444 } 00445 } 00446 return Qnil; 00447 } 00448 00449 /* :nodoc: */ 00450 static VALUE 00451 fgdbm_index(VALUE obj, VALUE value) 00452 { 00453 rb_warn("GDBM#index is deprecated; use GDBM#key"); 00454 return fgdbm_key(obj, value); 00455 } 00456 00457 /* 00458 * call-seq: 00459 * gdbm.select { |key, value| block } -> array 00460 * 00461 * Returns a new array of all key-value pairs of the database for which _block_ 00462 * evaluates to true. 00463 */ 00464 static VALUE 00465 fgdbm_select(VALUE obj) 00466 { 00467 VALUE new = rb_ary_new(); 00468 GDBM_FILE dbm; 00469 struct dbmdata *dbmp; 00470 VALUE keystr; 00471 00472 GetDBM2(obj, dbmp, dbm); 00473 for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr); 00474 keystr = rb_gdbm_nextkey(dbm, keystr)) { 00475 VALUE assoc = rb_assoc_new(keystr, rb_gdbm_fetch2(dbm, keystr)); 00476 VALUE v = rb_yield(assoc); 00477 00478 if (RTEST(v)) { 00479 rb_ary_push(new, assoc); 00480 } 00481 GetDBM2(obj, dbmp, dbm); 00482 } 00483 00484 return new; 00485 } 00486 00487 /* 00488 * call-seq: 00489 * gdbm.values_at(key, ...) -> array 00490 * 00491 * Returns an array of the values associated with each specified _key_. 00492 */ 00493 static VALUE 00494 fgdbm_values_at(int argc, VALUE *argv, VALUE obj) 00495 { 00496 VALUE new = rb_ary_new2(argc); 00497 int i; 00498 00499 for (i=0; i<argc; i++) { 00500 rb_ary_push(new, rb_gdbm_fetch3(obj, argv[i])); 00501 } 00502 00503 return new; 00504 } 00505 00506 static void 00507 rb_gdbm_modify(VALUE obj) 00508 { 00509 rb_secure(4); 00510 if (OBJ_FROZEN(obj)) rb_error_frozen("GDBM"); 00511 } 00512 00513 static VALUE 00514 rb_gdbm_delete(VALUE obj, VALUE keystr) 00515 { 00516 datum key; 00517 struct dbmdata *dbmp; 00518 GDBM_FILE dbm; 00519 long len; 00520 00521 rb_gdbm_modify(obj); 00522 StringValue(keystr); 00523 len = RSTRING_LEN(keystr); 00524 if (TOO_LONG(len)) return Qnil; 00525 key.dptr = RSTRING_PTR(keystr); 00526 key.dsize = (int)len; 00527 00528 GetDBM2(obj, dbmp, dbm); 00529 if (!gdbm_exists(dbm, key)) { 00530 return Qnil; 00531 } 00532 00533 if (gdbm_delete(dbm, key)) { 00534 dbmp->di_size = -1; 00535 rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno)); 00536 } 00537 else if (dbmp->di_size >= 0) { 00538 dbmp->di_size--; 00539 } 00540 return obj; 00541 } 00542 00543 /* 00544 * call-seq: 00545 * gdbm.delete(key) -> value or nil 00546 * 00547 * Removes the key-value-pair with the specified _key_ from this database and 00548 * returns the corresponding _value_. Returns nil if the database is empty. 00549 */ 00550 static VALUE 00551 fgdbm_delete(VALUE obj, VALUE keystr) 00552 { 00553 VALUE valstr; 00554 00555 valstr = fgdbm_fetch(obj, keystr, Qnil); 00556 rb_gdbm_delete(obj, keystr); 00557 return valstr; 00558 } 00559 00560 /* 00561 * call-seq: 00562 * gdbm.shift -> (key, value) or nil 00563 * 00564 * Removes a key-value-pair from this database and returns it as a 00565 * two-item array [ _key_, _value_ ]. Returns nil if the database is empty. 00566 */ 00567 static VALUE 00568 fgdbm_shift(VALUE obj) 00569 { 00570 struct dbmdata *dbmp; 00571 GDBM_FILE dbm; 00572 VALUE keystr, valstr; 00573 00574 rb_gdbm_modify(obj); 00575 GetDBM2(obj, dbmp, dbm); 00576 keystr = rb_gdbm_firstkey(dbm); 00577 if (NIL_P(keystr)) return Qnil; 00578 valstr = rb_gdbm_fetch2(dbm, keystr); 00579 rb_gdbm_delete(obj, keystr); 00580 00581 return rb_assoc_new(keystr, valstr); 00582 } 00583 00584 /* 00585 * call-seq: 00586 * gdbm.delete_if { |key, value| block } -> gdbm 00587 * gdbm.reject! { |key, value| block } -> gdbm 00588 * 00589 * Deletes every key-value pair from _gdbm_ for which _block_ evaluates to true. 00590 */ 00591 static VALUE 00592 fgdbm_delete_if(VALUE obj) 00593 { 00594 struct dbmdata *dbmp; 00595 GDBM_FILE dbm; 00596 VALUE keystr, valstr; 00597 VALUE ret, ary = rb_ary_tmp_new(0); 00598 int i, status = 0, n; 00599 00600 rb_gdbm_modify(obj); 00601 GetDBM2(obj, dbmp, dbm); 00602 n = dbmp->di_size; 00603 dbmp->di_size = -1; 00604 00605 for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr); 00606 keystr = rb_gdbm_nextkey(dbm, keystr)) { 00607 00608 OBJ_FREEZE(keystr); 00609 valstr = rb_gdbm_fetch2(dbm, keystr); 00610 ret = rb_protect(rb_yield, rb_assoc_new(rb_str_dup(keystr), valstr), &status); 00611 if (status != 0) break; 00612 if (RTEST(ret)) rb_ary_push(ary, keystr); 00613 GetDBM2(obj, dbmp, dbm); 00614 } 00615 00616 for (i = 0; i < RARRAY_LEN(ary); i++) 00617 rb_gdbm_delete(obj, RARRAY_PTR(ary)[i]); 00618 if (status) rb_jump_tag(status); 00619 if (n > 0) dbmp->di_size = n - (int)RARRAY_LEN(ary); 00620 rb_ary_clear(ary); 00621 00622 return obj; 00623 } 00624 00625 /* 00626 * call-seq: 00627 * gdbm.clear -> gdbm 00628 * 00629 * Removes all the key-value pairs within _gdbm_. 00630 */ 00631 static VALUE 00632 fgdbm_clear(VALUE obj) 00633 { 00634 datum key, nextkey; 00635 struct dbmdata *dbmp; 00636 GDBM_FILE dbm; 00637 00638 rb_gdbm_modify(obj); 00639 GetDBM2(obj, dbmp, dbm); 00640 dbmp->di_size = -1; 00641 00642 #if 0 00643 while (key = gdbm_firstkey(dbm), key.dptr) { 00644 if (gdbm_delete(dbm, key)) { 00645 free(key.dptr); 00646 rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno)); 00647 } 00648 free(key.dptr); 00649 } 00650 #else 00651 while (key = gdbm_firstkey(dbm), key.dptr) { 00652 for (; key.dptr; key = nextkey) { 00653 nextkey = gdbm_nextkey(dbm, key); 00654 if (gdbm_delete(dbm, key)) { 00655 free(key.dptr); 00656 if (nextkey.dptr) free(nextkey.dptr); 00657 rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno)); 00658 } 00659 free(key.dptr); 00660 } 00661 } 00662 #endif 00663 dbmp->di_size = 0; 00664 00665 return obj; 00666 } 00667 00668 /* 00669 * call-seq: 00670 * gdbm.invert -> hash 00671 * 00672 * Returns a hash created by using _gdbm_'s values as keys, and the keys 00673 * as values. 00674 */ 00675 static VALUE 00676 fgdbm_invert(VALUE obj) 00677 { 00678 struct dbmdata *dbmp; 00679 GDBM_FILE dbm; 00680 VALUE keystr, valstr; 00681 VALUE hash = rb_hash_new(); 00682 00683 GetDBM2(obj, dbmp, dbm); 00684 for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr); 00685 keystr = rb_gdbm_nextkey(dbm, keystr)) { 00686 valstr = rb_gdbm_fetch2(dbm, keystr); 00687 00688 rb_hash_aset(hash, valstr, keystr); 00689 } 00690 return hash; 00691 } 00692 00693 /* 00694 * call-seq: 00695 * gdbm[key]= value -> value 00696 * gdbm.store(key, value) -> value 00697 * 00698 * Associates the value _value_ with the specified _key_. 00699 */ 00700 static VALUE 00701 fgdbm_store(VALUE obj, VALUE keystr, VALUE valstr) 00702 { 00703 datum key, val; 00704 struct dbmdata *dbmp; 00705 GDBM_FILE dbm; 00706 00707 rb_gdbm_modify(obj); 00708 StringValue(keystr); 00709 StringValue(valstr); 00710 00711 key.dptr = RSTRING_PTR(keystr); 00712 key.dsize = RSTRING_LENINT(keystr); 00713 00714 val.dptr = RSTRING_PTR(valstr); 00715 val.dsize = RSTRING_LENINT(valstr); 00716 00717 GetDBM2(obj, dbmp, dbm); 00718 dbmp->di_size = -1; 00719 if (gdbm_store(dbm, key, val, GDBM_REPLACE)) { 00720 if (errno == EPERM) rb_sys_fail(0); 00721 rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno)); 00722 } 00723 00724 return valstr; 00725 } 00726 00727 static VALUE 00728 update_i(VALUE pair, VALUE dbm) 00729 { 00730 Check_Type(pair, T_ARRAY); 00731 if (RARRAY_LEN(pair) < 2) { 00732 rb_raise(rb_eArgError, "pair must be [key, value]"); 00733 } 00734 fgdbm_store(dbm, RARRAY_PTR(pair)[0], RARRAY_PTR(pair)[1]); 00735 return Qnil; 00736 } 00737 00738 /* 00739 * call-seq: 00740 * gdbm.update(other) -> gdbm 00741 * 00742 * Adds the key-value pairs of _other_ to _gdbm_, overwriting entries with 00743 * duplicate keys with those from _other_. _other_ must have an each_pair 00744 * method. 00745 */ 00746 static VALUE 00747 fgdbm_update(VALUE obj, VALUE other) 00748 { 00749 rb_block_call(other, rb_intern("each_pair"), 0, 0, update_i, obj); 00750 return obj; 00751 } 00752 00753 /* 00754 * call-seq: 00755 * gdbm.replace(other) -> gdbm 00756 * 00757 * Replaces the content of _gdbm_ with the key-value pairs of _other_. 00758 * _other_ must have an each_pair method. 00759 */ 00760 static VALUE 00761 fgdbm_replace(VALUE obj, VALUE other) 00762 { 00763 fgdbm_clear(obj); 00764 rb_block_call(other, rb_intern("each_pair"), 0, 0, update_i, obj); 00765 return obj; 00766 } 00767 00768 /* 00769 * call-seq: 00770 * gdbm.length -> fixnum 00771 * gdbm.size -> fixnum 00772 * 00773 * Returns the number of key-value pairs in this database. 00774 */ 00775 static VALUE 00776 fgdbm_length(VALUE obj) 00777 { 00778 datum key, nextkey; 00779 struct dbmdata *dbmp; 00780 GDBM_FILE dbm; 00781 int i = 0; 00782 00783 GetDBM2(obj, dbmp, dbm); 00784 if (dbmp->di_size > 0) return INT2FIX(dbmp->di_size); 00785 00786 for (key = gdbm_firstkey(dbm); key.dptr; key = nextkey) { 00787 nextkey = gdbm_nextkey(dbm, key); 00788 free(key.dptr); 00789 i++; 00790 } 00791 dbmp->di_size = i; 00792 00793 return INT2FIX(i); 00794 } 00795 00796 /* 00797 * call-seq: 00798 * gdbm.empty? -> true or false 00799 * 00800 * Returns true if the database is empty. 00801 */ 00802 static VALUE 00803 fgdbm_empty_p(VALUE obj) 00804 { 00805 datum key; 00806 struct dbmdata *dbmp; 00807 GDBM_FILE dbm; 00808 00809 GetDBM(obj, dbmp); 00810 if (dbmp->di_size < 0) { 00811 dbm = dbmp->di_dbm; 00812 00813 key = gdbm_firstkey(dbm); 00814 if (key.dptr) { 00815 free(key.dptr); 00816 return Qfalse; 00817 } 00818 return Qtrue; 00819 } 00820 00821 if (dbmp->di_size == 0) return Qtrue; 00822 return Qfalse; 00823 } 00824 00825 /* 00826 * call-seq: 00827 * gdbm.each_value { |value| block } -> gdbm 00828 * 00829 * Executes _block_ for each key in the database, passing the corresponding 00830 * _value_ as a parameter. 00831 */ 00832 static VALUE 00833 fgdbm_each_value(VALUE obj) 00834 { 00835 struct dbmdata *dbmp; 00836 GDBM_FILE dbm; 00837 VALUE keystr; 00838 00839 RETURN_ENUMERATOR(obj, 0, 0); 00840 00841 GetDBM2(obj, dbmp, dbm); 00842 for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr); 00843 keystr = rb_gdbm_nextkey(dbm, keystr)) { 00844 00845 rb_yield(rb_gdbm_fetch2(dbm, keystr)); 00846 GetDBM2(obj, dbmp, dbm); 00847 } 00848 return obj; 00849 } 00850 00851 /* 00852 * call-seq: 00853 * gdbm.each_key { |key| block } -> gdbm 00854 * 00855 * Executes _block_ for each key in the database, passing the 00856 * _key_ as a parameter. 00857 */ 00858 static VALUE 00859 fgdbm_each_key(VALUE obj) 00860 { 00861 struct dbmdata *dbmp; 00862 GDBM_FILE dbm; 00863 VALUE keystr; 00864 00865 RETURN_ENUMERATOR(obj, 0, 0); 00866 00867 GetDBM2(obj, dbmp, dbm); 00868 for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr); 00869 keystr = rb_gdbm_nextkey(dbm, keystr)) { 00870 00871 rb_yield(keystr); 00872 GetDBM2(obj, dbmp, dbm); 00873 } 00874 return obj; 00875 } 00876 00877 /* 00878 * call-seq: 00879 * gdbm.each_pair { |key, value| block } -> gdbm 00880 * 00881 * Executes _block_ for each key in the database, passing the _key_ and the 00882 * correspoding _value_ as a parameter. 00883 */ 00884 static VALUE 00885 fgdbm_each_pair(VALUE obj) 00886 { 00887 GDBM_FILE dbm; 00888 struct dbmdata *dbmp; 00889 VALUE keystr; 00890 00891 RETURN_ENUMERATOR(obj, 0, 0); 00892 00893 GetDBM2(obj, dbmp, dbm); 00894 for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr); 00895 keystr = rb_gdbm_nextkey(dbm, keystr)) { 00896 00897 rb_yield(rb_assoc_new(keystr, rb_gdbm_fetch2(dbm, keystr))); 00898 GetDBM2(obj, dbmp, dbm); 00899 } 00900 00901 return obj; 00902 } 00903 00904 /* 00905 * call-seq: 00906 * gdbm.keys -> array 00907 * 00908 * Returns an array of all keys of this database. 00909 */ 00910 static VALUE 00911 fgdbm_keys(VALUE obj) 00912 { 00913 struct dbmdata *dbmp; 00914 GDBM_FILE dbm; 00915 VALUE keystr, ary; 00916 00917 GetDBM2(obj, dbmp, dbm); 00918 ary = rb_ary_new(); 00919 for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr); 00920 keystr = rb_gdbm_nextkey(dbm, keystr)) { 00921 00922 rb_ary_push(ary, keystr); 00923 } 00924 00925 return ary; 00926 } 00927 00928 /* 00929 * call-seq: 00930 * gdbm.values -> array 00931 * 00932 * Returns an array of all values of this database. 00933 */ 00934 static VALUE 00935 fgdbm_values(VALUE obj) 00936 { 00937 datum key, nextkey; 00938 struct dbmdata *dbmp; 00939 GDBM_FILE dbm; 00940 VALUE valstr, ary; 00941 00942 GetDBM2(obj, dbmp, dbm); 00943 ary = rb_ary_new(); 00944 for (key = gdbm_firstkey(dbm); key.dptr; key = nextkey) { 00945 nextkey = gdbm_nextkey(dbm, key); 00946 valstr = rb_gdbm_fetch(dbm, key); 00947 free(key.dptr); 00948 rb_ary_push(ary, valstr); 00949 } 00950 00951 return ary; 00952 } 00953 00954 /* 00955 * call-seq: 00956 * gdbm.has_key?(k) -> true or false 00957 * gdbm.key?(k) -> true or false 00958 * 00959 * Returns true if the given key _k_ exists within the database. 00960 * Returns false otherwise. 00961 */ 00962 static VALUE 00963 fgdbm_has_key(VALUE obj, VALUE keystr) 00964 { 00965 datum key; 00966 struct dbmdata *dbmp; 00967 GDBM_FILE dbm; 00968 long len; 00969 00970 StringValue(keystr); 00971 len = RSTRING_LENINT(keystr); 00972 if (TOO_LONG(len)) return Qfalse; 00973 key.dptr = RSTRING_PTR(keystr); 00974 key.dsize = (int)len; 00975 00976 GetDBM2(obj, dbmp, dbm); 00977 if (gdbm_exists(dbm, key)) 00978 return Qtrue; 00979 return Qfalse; 00980 } 00981 00982 /* 00983 * call-seq: 00984 * gdbm.has_value?(v) -> true or false 00985 * gdbm.value?(v) -> true or false 00986 * 00987 * Returns true if the given value _v_ exists within the database. 00988 * Returns false otherwise. 00989 */ 00990 static VALUE 00991 fgdbm_has_value(VALUE obj, VALUE valstr) 00992 { 00993 struct dbmdata *dbmp; 00994 GDBM_FILE dbm; 00995 VALUE keystr, valstr2; 00996 00997 StringValue(valstr); 00998 GetDBM2(obj, dbmp, dbm); 00999 for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr); 01000 keystr = rb_gdbm_nextkey(dbm, keystr)) { 01001 01002 valstr2 = rb_gdbm_fetch2(dbm, keystr); 01003 01004 if (!NIL_P(valstr2) && 01005 (int)RSTRING_LEN(valstr) == (int)RSTRING_LEN(valstr2) && 01006 memcmp(RSTRING_PTR(valstr), RSTRING_PTR(valstr2), 01007 (int)RSTRING_LEN(valstr)) == 0) { 01008 return Qtrue; 01009 } 01010 } 01011 return Qfalse; 01012 } 01013 01014 /* 01015 * call-seq: 01016 * gdbm.to_a -> array 01017 * 01018 * Returns an array of all key-value pairs contained in the database. 01019 */ 01020 static VALUE 01021 fgdbm_to_a(VALUE obj) 01022 { 01023 struct dbmdata *dbmp; 01024 GDBM_FILE dbm; 01025 VALUE keystr, ary; 01026 01027 GetDBM2(obj, dbmp, dbm); 01028 ary = rb_ary_new(); 01029 for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr); 01030 keystr = rb_gdbm_nextkey(dbm, keystr)) { 01031 01032 rb_ary_push(ary, rb_assoc_new(keystr, rb_gdbm_fetch2(dbm, keystr))); 01033 } 01034 01035 return ary; 01036 } 01037 01038 /* 01039 * call-seq: 01040 * gdbm.reorganize -> gdbm 01041 * 01042 * Reorganizes the database file. This operation removes reserved space of 01043 * elements that have already been deleted. It is only useful after a lot of 01044 * deletions in the database. 01045 */ 01046 static VALUE 01047 fgdbm_reorganize(VALUE obj) 01048 { 01049 struct dbmdata *dbmp; 01050 GDBM_FILE dbm; 01051 01052 rb_gdbm_modify(obj); 01053 GetDBM2(obj, dbmp, dbm); 01054 gdbm_reorganize(dbm); 01055 rb_fd_fix_cloexec(gdbm_fdesc(dbm)); 01056 return obj; 01057 } 01058 01059 /* 01060 * call-seq: 01061 * gdbm.sync -> gdbm 01062 * 01063 * Unless the _gdbm_ object has been opened with the *SYNC* flag, it is not 01064 * guarenteed that database modification operations are immediately applied to 01065 * the database file. This method ensures that all recent modifications 01066 * to the database are written to the file. Blocks until all writing operations 01067 * to the disk have been finished. 01068 */ 01069 static VALUE 01070 fgdbm_sync(VALUE obj) 01071 { 01072 struct dbmdata *dbmp; 01073 GDBM_FILE dbm; 01074 01075 rb_gdbm_modify(obj); 01076 GetDBM2(obj, dbmp, dbm); 01077 gdbm_sync(dbm); 01078 return obj; 01079 } 01080 01081 /* 01082 * call-seq: 01083 * gdbm.cachesize = size -> size 01084 * 01085 * Sets the size of the internal bucket cache to _size_. 01086 */ 01087 static VALUE 01088 fgdbm_set_cachesize(VALUE obj, VALUE val) 01089 { 01090 struct dbmdata *dbmp; 01091 GDBM_FILE dbm; 01092 int optval; 01093 01094 GetDBM2(obj, dbmp, dbm); 01095 optval = FIX2INT(val); 01096 if (gdbm_setopt(dbm, GDBM_CACHESIZE, &optval, sizeof(optval)) == -1) { 01097 rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno)); 01098 } 01099 return val; 01100 } 01101 01102 /* 01103 * call-seq: 01104 * gdbm.fastmode = boolean -> boolean 01105 * 01106 * Turns the database's fast mode on or off. If fast mode is turned on, gdbm 01107 * does not wait for writes to be flushed to the disk before continuing. 01108 * 01109 * This option is obsolete for gdbm >= 1.8 since fast mode is turned on by 01110 * default. See also: #syncmode= 01111 */ 01112 static VALUE 01113 fgdbm_set_fastmode(VALUE obj, VALUE val) 01114 { 01115 struct dbmdata *dbmp; 01116 GDBM_FILE dbm; 01117 int optval; 01118 01119 GetDBM2(obj, dbmp, dbm); 01120 optval = 0; 01121 if (RTEST(val)) 01122 optval = 1; 01123 01124 if (gdbm_setopt(dbm, GDBM_FASTMODE, &optval, sizeof(optval)) == -1) { 01125 rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno)); 01126 } 01127 return val; 01128 } 01129 01130 /* 01131 * call-seq: 01132 * gdbm.syncmode = boolean -> boolean 01133 * 01134 * Turns the database's synchronization mode on or off. If the synchronization 01135 * mode is turned on, the database's in-memory state will be synchronized to 01136 * disk after every database modification operation. If the synchronization 01137 * mode is turned off, GDBM does not wait for writes to be flushed to the disk 01138 * before continuing. 01139 * 01140 * This option is only available for gdbm >= 1.8 where syncmode is turned off 01141 * by default. See also: #fastmode= 01142 */ 01143 static VALUE 01144 fgdbm_set_syncmode(VALUE obj, VALUE val) 01145 { 01146 #if !defined(GDBM_SYNCMODE) 01147 fgdbm_set_fastmode(obj, RTEST(val) ? Qfalse : Qtrue); 01148 return val; 01149 #else 01150 struct dbmdata *dbmp; 01151 GDBM_FILE dbm; 01152 int optval; 01153 01154 GetDBM2(obj, dbmp, dbm); 01155 optval = 0; 01156 if (RTEST(val)) 01157 optval = 1; 01158 01159 if (gdbm_setopt(dbm, GDBM_FASTMODE, &optval, sizeof(optval)) == -1) { 01160 rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno)); 01161 } 01162 return val; 01163 #endif 01164 } 01165 01166 /* 01167 * call-seq: 01168 * gdbm.to_hash -> hash 01169 * 01170 * Returns a hash of all key-value pairs contained in the database. 01171 */ 01172 static VALUE 01173 fgdbm_to_hash(VALUE obj) 01174 { 01175 struct dbmdata *dbmp; 01176 GDBM_FILE dbm; 01177 VALUE keystr, hash; 01178 01179 GetDBM2(obj, dbmp, dbm); 01180 hash = rb_hash_new(); 01181 for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr); 01182 keystr = rb_gdbm_nextkey(dbm, keystr)) { 01183 01184 rb_hash_aset(hash, keystr, rb_gdbm_fetch2(dbm, keystr)); 01185 } 01186 01187 return hash; 01188 } 01189 01190 /* 01191 * call-seq: 01192 * gdbm.reject { |key, value| block } -> hash 01193 * 01194 * Returns a hash copy of _gdbm_ where all key-value pairs from _gdbm_ for 01195 * which _block_ evaluates to true are removed. See also: #delete_if 01196 */ 01197 static VALUE 01198 fgdbm_reject(VALUE obj) 01199 { 01200 return rb_hash_delete_if(fgdbm_to_hash(obj)); 01201 } 01202 01203 void 01204 Init_gdbm(void) 01205 { 01206 rb_cGDBM = rb_define_class("GDBM", rb_cObject); 01207 rb_eGDBMError = rb_define_class("GDBMError", rb_eStandardError); 01208 rb_eGDBMFatalError = rb_define_class("GDBMFatalError", rb_eException); 01209 rb_include_module(rb_cGDBM, rb_mEnumerable); 01210 01211 rb_define_alloc_func(rb_cGDBM, fgdbm_s_alloc); 01212 rb_define_singleton_method(rb_cGDBM, "open", fgdbm_s_open, -1); 01213 01214 rb_define_method(rb_cGDBM, "initialize", fgdbm_initialize, -1); 01215 rb_define_method(rb_cGDBM, "close", fgdbm_close, 0); 01216 rb_define_method(rb_cGDBM, "closed?", fgdbm_closed, 0); 01217 rb_define_method(rb_cGDBM, "[]", fgdbm_aref, 1); 01218 rb_define_method(rb_cGDBM, "fetch", fgdbm_fetch_m, -1); 01219 rb_define_method(rb_cGDBM, "[]=", fgdbm_store, 2); 01220 rb_define_method(rb_cGDBM, "store", fgdbm_store, 2); 01221 rb_define_method(rb_cGDBM, "index", fgdbm_index, 1); 01222 rb_define_method(rb_cGDBM, "key", fgdbm_key, 1); 01223 rb_define_method(rb_cGDBM, "select", fgdbm_select, 0); 01224 rb_define_method(rb_cGDBM, "values_at", fgdbm_values_at, -1); 01225 rb_define_method(rb_cGDBM, "length", fgdbm_length, 0); 01226 rb_define_method(rb_cGDBM, "size", fgdbm_length, 0); 01227 rb_define_method(rb_cGDBM, "empty?", fgdbm_empty_p, 0); 01228 rb_define_method(rb_cGDBM, "each", fgdbm_each_pair, 0); 01229 rb_define_method(rb_cGDBM, "each_value", fgdbm_each_value, 0); 01230 rb_define_method(rb_cGDBM, "each_key", fgdbm_each_key, 0); 01231 rb_define_method(rb_cGDBM, "each_pair", fgdbm_each_pair, 0); 01232 rb_define_method(rb_cGDBM, "keys", fgdbm_keys, 0); 01233 rb_define_method(rb_cGDBM, "values", fgdbm_values, 0); 01234 rb_define_method(rb_cGDBM, "shift", fgdbm_shift, 0); 01235 rb_define_method(rb_cGDBM, "delete", fgdbm_delete, 1); 01236 rb_define_method(rb_cGDBM, "delete_if", fgdbm_delete_if, 0); 01237 rb_define_method(rb_cGDBM, "reject!", fgdbm_delete_if, 0); 01238 rb_define_method(rb_cGDBM, "reject", fgdbm_reject, 0); 01239 rb_define_method(rb_cGDBM, "clear", fgdbm_clear, 0); 01240 rb_define_method(rb_cGDBM, "invert", fgdbm_invert, 0); 01241 rb_define_method(rb_cGDBM, "update", fgdbm_update, 1); 01242 rb_define_method(rb_cGDBM, "replace", fgdbm_replace, 1); 01243 rb_define_method(rb_cGDBM, "reorganize", fgdbm_reorganize, 0); 01244 rb_define_method(rb_cGDBM, "sync", fgdbm_sync, 0); 01245 /* rb_define_method(rb_cGDBM, "setopt", fgdbm_setopt, 2); */ 01246 rb_define_method(rb_cGDBM, "cachesize=", fgdbm_set_cachesize, 1); 01247 rb_define_method(rb_cGDBM, "fastmode=", fgdbm_set_fastmode, 1); 01248 rb_define_method(rb_cGDBM, "syncmode=", fgdbm_set_syncmode, 1); 01249 01250 rb_define_method(rb_cGDBM, "include?", fgdbm_has_key, 1); 01251 rb_define_method(rb_cGDBM, "has_key?", fgdbm_has_key, 1); 01252 rb_define_method(rb_cGDBM, "member?", fgdbm_has_key, 1); 01253 rb_define_method(rb_cGDBM, "has_value?", fgdbm_has_value, 1); 01254 rb_define_method(rb_cGDBM, "key?", fgdbm_has_key, 1); 01255 rb_define_method(rb_cGDBM, "value?", fgdbm_has_value, 1); 01256 01257 rb_define_method(rb_cGDBM, "to_a", fgdbm_to_a, 0); 01258 rb_define_method(rb_cGDBM, "to_hash", fgdbm_to_hash, 0); 01259 01260 /* flag for #new and #open: open database as a reader */ 01261 rb_define_const(rb_cGDBM, "READER", INT2FIX(GDBM_READER|RUBY_GDBM_RW_BIT)); 01262 /* flag for #new and #open: open database as a writer */ 01263 rb_define_const(rb_cGDBM, "WRITER", INT2FIX(GDBM_WRITER|RUBY_GDBM_RW_BIT)); 01264 /* flag for #new and #open: open database as a writer; if the database does not exist, create a new one */ 01265 rb_define_const(rb_cGDBM, "WRCREAT", INT2FIX(GDBM_WRCREAT|RUBY_GDBM_RW_BIT)); 01266 /* flag for #new and #open: open database as a writer; overwrite any existing databases */ 01267 rb_define_const(rb_cGDBM, "NEWDB", INT2FIX(GDBM_NEWDB|RUBY_GDBM_RW_BIT)); 01268 01269 /* flag for #new and #open. this flag is obsolete for gdbm >= 1.8 */ 01270 rb_define_const(rb_cGDBM, "FAST", INT2FIX(GDBM_FAST)); 01271 /* this flag is obsolete in gdbm 1.8. 01272 On gdbm 1.8, fast mode is default behavior. */ 01273 01274 /* gdbm version 1.8 specific */ 01275 #if defined(GDBM_SYNC) 01276 /* flag for #new and #open. only for gdbm >= 1.8 */ 01277 rb_define_const(rb_cGDBM, "SYNC", INT2FIX(GDBM_SYNC)); 01278 #endif 01279 #if defined(GDBM_NOLOCK) 01280 /* flag for #new and #open */ 01281 rb_define_const(rb_cGDBM, "NOLOCK", INT2FIX(GDBM_NOLOCK)); 01282 #endif 01283 /* version of the gdbm library*/ 01284 rb_define_const(rb_cGDBM, "VERSION", rb_str_new2(gdbm_version)); 01285 } 01286