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