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