ext/dbm/dbm.c

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

Generated on 19 Jul 2016 for Ruby by  doxygen 1.4.7