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