Ruby 1.9.2p136(2010-12-25revision30365)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

# ext/gdbm/gdbm.c

Go to the documentation of this file.

    00001 /************************************************
    00002
    00003   gdbm.c -
    00004
    00005   $Author: nobu $
    00006   modified at: Mon Jan 24 15:59:52 JST 1994
    00007
    00008   Documentation by Peter Adolphs < futzilogik at users dot sourceforge dot net >
    00009
    00010 ************************************************/
    00011
    00012 #include "ruby.h"
    00013
    00014 #include <gdbm.h>
    00015 #include <fcntl.h>
    00016 #include <errno.h>
    00017
    00018 /*
    00019  * Document-class: GDBM
    00020  *
    00021  * == Summary
    00022  *
    00023  * Ruby extension for GNU dbm (gdbm) -- a simple database engine for storing
    00024  * key-value pairs on disk.
    00025  *
    00026  * == Description
    00027  *
    00028  * GNU dbm is a library for simple databases. A database is a file that stores
    00029  * key-value pairs. Gdbm allows the user to store, retrieve, and delete data by
    00030  * key. It furthermore allows a non-sorted traversal of all key-value pairs.
    00031  * A gdbm database thus provides the same functionality as a hash. As
    00032  * with objects of the Hash class, elements can be accessed with <tt>[]</tt>.
    00033  * Furthermore, GDBM mixes in the Enumerable module, thus providing convenient
    00034  * methods such as #find, #collect, #map, etc.
    00035  *
    00036  * A process is allowed to open several different databases at the same time.
    00037  * A process can open a database as a "reader" or a "writer". Whereas a reader
    00038  * has only read-access to the database, a writer has read- and write-access.
    00039  * A database can be accessed either by any number of readers or by exactly one
    00040  * writer at the same time.
    00041  *
    00042  * == Examples
    00043  *
    00044  * 1. Opening/creating a database, and filling it with some entries:
    00045  *
    00046  *      require 'gdbm'
    00047  *
    00048  *      gdbm = GDBM.new("fruitstore.db")
    00049  *      gdbm["ananas"]    = "3"
    00050  *      gdbm["banana"]    = "8"
    00051  *      gdbm["cranberry"] = "4909"
    00052  *      gdbm.close
    00053  *
    00054  * 2. Reading out a database:
    00055  *
    00056  *      require 'gdbm'
    00057  *
    00058  *      gdbm = GDBM.new("fruitstore.db")
    00059  *      gdbm.each_pair do |key, value|
    00060  *        print "#{key}: #{value}\n"
    00061  *      end
    00062  *      gdbm.close
    00063  *
    00064  *    produces
    00065  *
    00066  *      banana: 8
    00067  *      ananas: 3
    00068  *      cranberry: 4909
    00069  *
    00070  * == Links
    00071  *
    00072  * * http://www.gnu.org/software/gdbm/
    00073  */
    00074 static VALUE rb_cGDBM, rb_eGDBMError, rb_eGDBMFatalError;
    00075
    00076 #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 = 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 = 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             RSTRING_LEN(valstr) == RSTRING_LEN(valstr2) &&
    00420             memcmp(RSTRING_PTR(valstr), RSTRING_PTR(valstr2),
    00421                    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 = 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 - 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 = RSTRING_LEN(keystr);
    00687
    00688     val.dptr = RSTRING_PTR(valstr);
    00689     val.dsize = 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 = 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             RSTRING_LEN(valstr) == RSTRING_LEN(valstr2) &&
    00977             memcmp(RSTRING_PTR(valstr), RSTRING_PTR(valstr2),
    00978                    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