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 rb_secure(4);
00510 if (OBJ_FROZEN(obj)) rb_error_frozen("GDBM");
00511 }
00512
00513 static VALUE
00514 rb_gdbm_delete(VALUE obj, VALUE keystr)
00515 {
00516 datum key;
00517 struct dbmdata *dbmp;
00518 GDBM_FILE dbm;
00519 long len;
00520
00521 rb_gdbm_modify(obj);
00522 StringValue(keystr);
00523 len = RSTRING_LEN(keystr);
00524 if (TOO_LONG(len)) return Qnil;
00525 key.dptr = RSTRING_PTR(keystr);
00526 key.dsize = (int)len;
00527
00528 GetDBM2(obj, dbmp, dbm);
00529 if (!gdbm_exists(dbm, key)) {
00530 return Qnil;
00531 }
00532
00533 if (gdbm_delete(dbm, key)) {
00534 dbmp->di_size = -1;
00535 rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno));
00536 }
00537 else if (dbmp->di_size >= 0) {
00538 dbmp->di_size--;
00539 }
00540 return obj;
00541 }
00542
00543
00544
00545
00546
00547
00548
00549
00550 static VALUE
00551 fgdbm_delete(VALUE obj, VALUE keystr)
00552 {
00553 VALUE valstr;
00554
00555 valstr = fgdbm_fetch(obj, keystr, Qnil);
00556 rb_gdbm_delete(obj, keystr);
00557 return valstr;
00558 }
00559
00560
00561
00562
00563
00564
00565
00566
00567 static VALUE
00568 fgdbm_shift(VALUE obj)
00569 {
00570 struct dbmdata *dbmp;
00571 GDBM_FILE dbm;
00572 VALUE keystr, valstr;
00573
00574 rb_gdbm_modify(obj);
00575 GetDBM2(obj, dbmp, dbm);
00576 keystr = rb_gdbm_firstkey(dbm);
00577 if (NIL_P(keystr)) return Qnil;
00578 valstr = rb_gdbm_fetch2(dbm, keystr);
00579 rb_gdbm_delete(obj, keystr);
00580
00581 return rb_assoc_new(keystr, valstr);
00582 }
00583
00584
00585
00586
00587
00588
00589
00590
00591 static VALUE
00592 fgdbm_delete_if(VALUE obj)
00593 {
00594 struct dbmdata *dbmp;
00595 GDBM_FILE dbm;
00596 VALUE keystr, valstr;
00597 VALUE ret, ary = rb_ary_tmp_new(0);
00598 int i, status = 0, n;
00599
00600 rb_gdbm_modify(obj);
00601 GetDBM2(obj, dbmp, dbm);
00602 n = dbmp->di_size;
00603 dbmp->di_size = -1;
00604
00605 for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
00606 keystr = rb_gdbm_nextkey(dbm, keystr)) {
00607
00608 OBJ_FREEZE(keystr);
00609 valstr = rb_gdbm_fetch2(dbm, keystr);
00610 ret = rb_protect(rb_yield, rb_assoc_new(rb_str_dup(keystr), valstr), &status);
00611 if (status != 0) break;
00612 if (RTEST(ret)) rb_ary_push(ary, keystr);
00613 GetDBM2(obj, dbmp, dbm);
00614 }
00615
00616 for (i = 0; i < RARRAY_LEN(ary); i++)
00617 rb_gdbm_delete(obj, RARRAY_PTR(ary)[i]);
00618 if (status) rb_jump_tag(status);
00619 if (n > 0) dbmp->di_size = n - (int)RARRAY_LEN(ary);
00620 rb_ary_clear(ary);
00621
00622 return obj;
00623 }
00624
00625
00626
00627
00628
00629
00630
00631 static VALUE
00632 fgdbm_clear(VALUE obj)
00633 {
00634 datum key, nextkey;
00635 struct dbmdata *dbmp;
00636 GDBM_FILE dbm;
00637
00638 rb_gdbm_modify(obj);
00639 GetDBM2(obj, dbmp, dbm);
00640 dbmp->di_size = -1;
00641
00642 #if 0
00643 while (key = gdbm_firstkey(dbm), key.dptr) {
00644 if (gdbm_delete(dbm, key)) {
00645 free(key.dptr);
00646 rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno));
00647 }
00648 free(key.dptr);
00649 }
00650 #else
00651 while (key = gdbm_firstkey(dbm), key.dptr) {
00652 for (; key.dptr; key = nextkey) {
00653 nextkey = gdbm_nextkey(dbm, key);
00654 if (gdbm_delete(dbm, key)) {
00655 free(key.dptr);
00656 if (nextkey.dptr) free(nextkey.dptr);
00657 rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno));
00658 }
00659 free(key.dptr);
00660 }
00661 }
00662 #endif
00663 dbmp->di_size = 0;
00664
00665 return obj;
00666 }
00667
00668
00669
00670
00671
00672
00673
00674
00675 static VALUE
00676 fgdbm_invert(VALUE obj)
00677 {
00678 struct dbmdata *dbmp;
00679 GDBM_FILE dbm;
00680 VALUE keystr, valstr;
00681 VALUE hash = rb_hash_new();
00682
00683 GetDBM2(obj, dbmp, dbm);
00684 for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
00685 keystr = rb_gdbm_nextkey(dbm, keystr)) {
00686 valstr = rb_gdbm_fetch2(dbm, keystr);
00687
00688 rb_hash_aset(hash, valstr, keystr);
00689 }
00690 return hash;
00691 }
00692
00693
00694
00695
00696
00697
00698
00699
00700 static VALUE
00701 fgdbm_store(VALUE obj, VALUE keystr, VALUE valstr)
00702 {
00703 datum key, val;
00704 struct dbmdata *dbmp;
00705 GDBM_FILE dbm;
00706
00707 rb_gdbm_modify(obj);
00708 StringValue(keystr);
00709 StringValue(valstr);
00710
00711 key.dptr = RSTRING_PTR(keystr);
00712 key.dsize = RSTRING_LENINT(keystr);
00713
00714 val.dptr = RSTRING_PTR(valstr);
00715 val.dsize = RSTRING_LENINT(valstr);
00716
00717 GetDBM2(obj, dbmp, dbm);
00718 dbmp->di_size = -1;
00719 if (gdbm_store(dbm, key, val, GDBM_REPLACE)) {
00720 if (errno == EPERM) rb_sys_fail(0);
00721 rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno));
00722 }
00723
00724 return valstr;
00725 }
00726
00727 static VALUE
00728 update_i(VALUE pair, VALUE dbm)
00729 {
00730 Check_Type(pair, T_ARRAY);
00731 if (RARRAY_LEN(pair) < 2) {
00732 rb_raise(rb_eArgError, "pair must be [key, value]");
00733 }
00734 fgdbm_store(dbm, RARRAY_PTR(pair)[0], RARRAY_PTR(pair)[1]);
00735 return Qnil;
00736 }
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746 static VALUE
00747 fgdbm_update(VALUE obj, VALUE other)
00748 {
00749 rb_block_call(other, rb_intern("each_pair"), 0, 0, update_i, obj);
00750 return obj;
00751 }
00752
00753
00754
00755
00756
00757
00758
00759
00760 static VALUE
00761 fgdbm_replace(VALUE obj, VALUE other)
00762 {
00763 fgdbm_clear(obj);
00764 rb_block_call(other, rb_intern("each_pair"), 0, 0, update_i, obj);
00765 return obj;
00766 }
00767
00768
00769
00770
00771
00772
00773
00774
00775 static VALUE
00776 fgdbm_length(VALUE obj)
00777 {
00778 datum key, nextkey;
00779 struct dbmdata *dbmp;
00780 GDBM_FILE dbm;
00781 int i = 0;
00782
00783 GetDBM2(obj, dbmp, dbm);
00784 if (dbmp->di_size > 0) return INT2FIX(dbmp->di_size);
00785
00786 for (key = gdbm_firstkey(dbm); key.dptr; key = nextkey) {
00787 nextkey = gdbm_nextkey(dbm, key);
00788 free(key.dptr);
00789 i++;
00790 }
00791 dbmp->di_size = i;
00792
00793 return INT2FIX(i);
00794 }
00795
00796
00797
00798
00799
00800
00801
00802 static VALUE
00803 fgdbm_empty_p(VALUE obj)
00804 {
00805 datum key;
00806 struct dbmdata *dbmp;
00807 GDBM_FILE dbm;
00808
00809 GetDBM(obj, dbmp);
00810 if (dbmp->di_size < 0) {
00811 dbm = dbmp->di_dbm;
00812
00813 key = gdbm_firstkey(dbm);
00814 if (key.dptr) {
00815 free(key.dptr);
00816 return Qfalse;
00817 }
00818 return Qtrue;
00819 }
00820
00821 if (dbmp->di_size == 0) return Qtrue;
00822 return Qfalse;
00823 }
00824
00825
00826
00827
00828
00829
00830
00831
00832 static VALUE
00833 fgdbm_each_value(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(rb_gdbm_fetch2(dbm, keystr));
00846 GetDBM2(obj, dbmp, dbm);
00847 }
00848 return obj;
00849 }
00850
00851
00852
00853
00854
00855
00856
00857
00858 static VALUE
00859 fgdbm_each_key(VALUE obj)
00860 {
00861 struct dbmdata *dbmp;
00862 GDBM_FILE dbm;
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(keystr);
00872 GetDBM2(obj, dbmp, dbm);
00873 }
00874 return obj;
00875 }
00876
00877
00878
00879
00880
00881
00882
00883
00884 static VALUE
00885 fgdbm_each_pair(VALUE obj)
00886 {
00887 GDBM_FILE dbm;
00888 struct dbmdata *dbmp;
00889 VALUE keystr;
00890
00891 RETURN_ENUMERATOR(obj, 0, 0);
00892
00893 GetDBM2(obj, dbmp, dbm);
00894 for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
00895 keystr = rb_gdbm_nextkey(dbm, keystr)) {
00896
00897 rb_yield(rb_assoc_new(keystr, rb_gdbm_fetch2(dbm, keystr)));
00898 GetDBM2(obj, dbmp, dbm);
00899 }
00900
00901 return obj;
00902 }
00903
00904
00905
00906
00907
00908
00909
00910 static VALUE
00911 fgdbm_keys(VALUE obj)
00912 {
00913 struct dbmdata *dbmp;
00914 GDBM_FILE dbm;
00915 VALUE keystr, ary;
00916
00917 GetDBM2(obj, dbmp, dbm);
00918 ary = rb_ary_new();
00919 for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
00920 keystr = rb_gdbm_nextkey(dbm, keystr)) {
00921
00922 rb_ary_push(ary, keystr);
00923 }
00924
00925 return ary;
00926 }
00927
00928
00929
00930
00931
00932
00933
00934 static VALUE
00935 fgdbm_values(VALUE obj)
00936 {
00937 datum key, nextkey;
00938 struct dbmdata *dbmp;
00939 GDBM_FILE dbm;
00940 VALUE valstr, ary;
00941
00942 GetDBM2(obj, dbmp, dbm);
00943 ary = rb_ary_new();
00944 for (key = gdbm_firstkey(dbm); key.dptr; key = nextkey) {
00945 nextkey = gdbm_nextkey(dbm, key);
00946 valstr = rb_gdbm_fetch(dbm, key);
00947 free(key.dptr);
00948 rb_ary_push(ary, valstr);
00949 }
00950
00951 return ary;
00952 }
00953
00954
00955
00956
00957
00958
00959
00960
00961
00962 static VALUE
00963 fgdbm_has_key(VALUE obj, VALUE keystr)
00964 {
00965 datum key;
00966 struct dbmdata *dbmp;
00967 GDBM_FILE dbm;
00968 long len;
00969
00970 StringValue(keystr);
00971 len = RSTRING_LENINT(keystr);
00972 if (TOO_LONG(len)) return Qfalse;
00973 key.dptr = RSTRING_PTR(keystr);
00974 key.dsize = (int)len;
00975
00976 GetDBM2(obj, dbmp, dbm);
00977 if (gdbm_exists(dbm, key))
00978 return Qtrue;
00979 return Qfalse;
00980 }
00981
00982
00983
00984
00985
00986
00987
00988
00989
00990 static VALUE
00991 fgdbm_has_value(VALUE obj, VALUE valstr)
00992 {
00993 struct dbmdata *dbmp;
00994 GDBM_FILE dbm;
00995 VALUE keystr, valstr2;
00996
00997 StringValue(valstr);
00998 GetDBM2(obj, dbmp, dbm);
00999 for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
01000 keystr = rb_gdbm_nextkey(dbm, keystr)) {
01001
01002 valstr2 = rb_gdbm_fetch2(dbm, keystr);
01003
01004 if (!NIL_P(valstr2) &&
01005 (int)RSTRING_LEN(valstr) == (int)RSTRING_LEN(valstr2) &&
01006 memcmp(RSTRING_PTR(valstr), RSTRING_PTR(valstr2),
01007 (int)RSTRING_LEN(valstr)) == 0) {
01008 return Qtrue;
01009 }
01010 }
01011 return Qfalse;
01012 }
01013
01014
01015
01016
01017
01018
01019
01020 static VALUE
01021 fgdbm_to_a(VALUE obj)
01022 {
01023 struct dbmdata *dbmp;
01024 GDBM_FILE dbm;
01025 VALUE keystr, ary;
01026
01027 GetDBM2(obj, dbmp, dbm);
01028 ary = rb_ary_new();
01029 for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
01030 keystr = rb_gdbm_nextkey(dbm, keystr)) {
01031
01032 rb_ary_push(ary, rb_assoc_new(keystr, rb_gdbm_fetch2(dbm, keystr)));
01033 }
01034
01035 return ary;
01036 }
01037
01038
01039
01040
01041
01042
01043
01044
01045
01046 static VALUE
01047 fgdbm_reorganize(VALUE obj)
01048 {
01049 struct dbmdata *dbmp;
01050 GDBM_FILE dbm;
01051
01052 rb_gdbm_modify(obj);
01053 GetDBM2(obj, dbmp, dbm);
01054 gdbm_reorganize(dbm);
01055 rb_fd_fix_cloexec(gdbm_fdesc(dbm));
01056 return obj;
01057 }
01058
01059
01060
01061
01062
01063
01064
01065
01066
01067
01068
01069 static VALUE
01070 fgdbm_sync(VALUE obj)
01071 {
01072 struct dbmdata *dbmp;
01073 GDBM_FILE dbm;
01074
01075 rb_gdbm_modify(obj);
01076 GetDBM2(obj, dbmp, dbm);
01077 gdbm_sync(dbm);
01078 return obj;
01079 }
01080
01081
01082
01083
01084
01085
01086
01087 static VALUE
01088 fgdbm_set_cachesize(VALUE obj, VALUE val)
01089 {
01090 struct dbmdata *dbmp;
01091 GDBM_FILE dbm;
01092 int optval;
01093
01094 GetDBM2(obj, dbmp, dbm);
01095 optval = FIX2INT(val);
01096 if (gdbm_setopt(dbm, GDBM_CACHESIZE, &optval, sizeof(optval)) == -1) {
01097 rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno));
01098 }
01099 return val;
01100 }
01101
01102
01103
01104
01105
01106
01107
01108
01109
01110
01111
01112 static VALUE
01113 fgdbm_set_fastmode(VALUE obj, VALUE val)
01114 {
01115 struct dbmdata *dbmp;
01116 GDBM_FILE dbm;
01117 int optval;
01118
01119 GetDBM2(obj, dbmp, dbm);
01120 optval = 0;
01121 if (RTEST(val))
01122 optval = 1;
01123
01124 if (gdbm_setopt(dbm, GDBM_FASTMODE, &optval, sizeof(optval)) == -1) {
01125 rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno));
01126 }
01127 return val;
01128 }
01129
01130
01131
01132
01133
01134
01135
01136
01137
01138
01139
01140
01141
01142
01143 static VALUE
01144 fgdbm_set_syncmode(VALUE obj, VALUE val)
01145 {
01146 #if !defined(GDBM_SYNCMODE)
01147 fgdbm_set_fastmode(obj, RTEST(val) ? Qfalse : Qtrue);
01148 return val;
01149 #else
01150 struct dbmdata *dbmp;
01151 GDBM_FILE dbm;
01152 int optval;
01153
01154 GetDBM2(obj, dbmp, dbm);
01155 optval = 0;
01156 if (RTEST(val))
01157 optval = 1;
01158
01159 if (gdbm_setopt(dbm, GDBM_FASTMODE, &optval, sizeof(optval)) == -1) {
01160 rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno));
01161 }
01162 return val;
01163 #endif
01164 }
01165
01166
01167
01168
01169
01170
01171
01172 static VALUE
01173 fgdbm_to_hash(VALUE obj)
01174 {
01175 struct dbmdata *dbmp;
01176 GDBM_FILE dbm;
01177 VALUE keystr, hash;
01178
01179 GetDBM2(obj, dbmp, dbm);
01180 hash = rb_hash_new();
01181 for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
01182 keystr = rb_gdbm_nextkey(dbm, keystr)) {
01183
01184 rb_hash_aset(hash, keystr, rb_gdbm_fetch2(dbm, keystr));
01185 }
01186
01187 return hash;
01188 }
01189
01190
01191
01192
01193
01194
01195
01196
01197 static VALUE
01198 fgdbm_reject(VALUE obj)
01199 {
01200 return rb_hash_delete_if(fgdbm_to_hash(obj));
01201 }
01202
01203 void
01204 Init_gdbm(void)
01205 {
01206 rb_cGDBM = rb_define_class("GDBM", rb_cObject);
01207 rb_eGDBMError = rb_define_class("GDBMError", rb_eStandardError);
01208 rb_eGDBMFatalError = rb_define_class("GDBMFatalError", rb_eException);
01209 rb_include_module(rb_cGDBM, rb_mEnumerable);
01210
01211 rb_define_alloc_func(rb_cGDBM, fgdbm_s_alloc);
01212 rb_define_singleton_method(rb_cGDBM, "open", fgdbm_s_open, -1);
01213
01214 rb_define_method(rb_cGDBM, "initialize", fgdbm_initialize, -1);
01215 rb_define_method(rb_cGDBM, "close", fgdbm_close, 0);
01216 rb_define_method(rb_cGDBM, "closed?", fgdbm_closed, 0);
01217 rb_define_method(rb_cGDBM, "[]", fgdbm_aref, 1);
01218 rb_define_method(rb_cGDBM, "fetch", fgdbm_fetch_m, -1);
01219 rb_define_method(rb_cGDBM, "[]=", fgdbm_store, 2);
01220 rb_define_method(rb_cGDBM, "store", fgdbm_store, 2);
01221 rb_define_method(rb_cGDBM, "index", fgdbm_index, 1);
01222 rb_define_method(rb_cGDBM, "key", fgdbm_key, 1);
01223 rb_define_method(rb_cGDBM, "select", fgdbm_select, 0);
01224 rb_define_method(rb_cGDBM, "values_at", fgdbm_values_at, -1);
01225 rb_define_method(rb_cGDBM, "length", fgdbm_length, 0);
01226 rb_define_method(rb_cGDBM, "size", fgdbm_length, 0);
01227 rb_define_method(rb_cGDBM, "empty?", fgdbm_empty_p, 0);
01228 rb_define_method(rb_cGDBM, "each", fgdbm_each_pair, 0);
01229 rb_define_method(rb_cGDBM, "each_value", fgdbm_each_value, 0);
01230 rb_define_method(rb_cGDBM, "each_key", fgdbm_each_key, 0);
01231 rb_define_method(rb_cGDBM, "each_pair", fgdbm_each_pair, 0);
01232 rb_define_method(rb_cGDBM, "keys", fgdbm_keys, 0);
01233 rb_define_method(rb_cGDBM, "values", fgdbm_values, 0);
01234 rb_define_method(rb_cGDBM, "shift", fgdbm_shift, 0);
01235 rb_define_method(rb_cGDBM, "delete", fgdbm_delete, 1);
01236 rb_define_method(rb_cGDBM, "delete_if", fgdbm_delete_if, 0);
01237 rb_define_method(rb_cGDBM, "reject!", fgdbm_delete_if, 0);
01238 rb_define_method(rb_cGDBM, "reject", fgdbm_reject, 0);
01239 rb_define_method(rb_cGDBM, "clear", fgdbm_clear, 0);
01240 rb_define_method(rb_cGDBM, "invert", fgdbm_invert, 0);
01241 rb_define_method(rb_cGDBM, "update", fgdbm_update, 1);
01242 rb_define_method(rb_cGDBM, "replace", fgdbm_replace, 1);
01243 rb_define_method(rb_cGDBM, "reorganize", fgdbm_reorganize, 0);
01244 rb_define_method(rb_cGDBM, "sync", fgdbm_sync, 0);
01245
01246 rb_define_method(rb_cGDBM, "cachesize=", fgdbm_set_cachesize, 1);
01247 rb_define_method(rb_cGDBM, "fastmode=", fgdbm_set_fastmode, 1);
01248 rb_define_method(rb_cGDBM, "syncmode=", fgdbm_set_syncmode, 1);
01249
01250 rb_define_method(rb_cGDBM, "include?", fgdbm_has_key, 1);
01251 rb_define_method(rb_cGDBM, "has_key?", fgdbm_has_key, 1);
01252 rb_define_method(rb_cGDBM, "member?", fgdbm_has_key, 1);
01253 rb_define_method(rb_cGDBM, "has_value?", fgdbm_has_value, 1);
01254 rb_define_method(rb_cGDBM, "key?", fgdbm_has_key, 1);
01255 rb_define_method(rb_cGDBM, "value?", fgdbm_has_value, 1);
01256
01257 rb_define_method(rb_cGDBM, "to_a", fgdbm_to_a, 0);
01258 rb_define_method(rb_cGDBM, "to_hash", fgdbm_to_hash, 0);
01259
01260
01261 rb_define_const(rb_cGDBM, "READER", INT2FIX(GDBM_READER|RUBY_GDBM_RW_BIT));
01262
01263 rb_define_const(rb_cGDBM, "WRITER", INT2FIX(GDBM_WRITER|RUBY_GDBM_RW_BIT));
01264
01265 rb_define_const(rb_cGDBM, "WRCREAT", INT2FIX(GDBM_WRCREAT|RUBY_GDBM_RW_BIT));
01266
01267 rb_define_const(rb_cGDBM, "NEWDB", INT2FIX(GDBM_NEWDB|RUBY_GDBM_RW_BIT));
01268
01269
01270 rb_define_const(rb_cGDBM, "FAST", INT2FIX(GDBM_FAST));
01271
01272
01273
01274
01275 #if defined(GDBM_SYNC)
01276
01277 rb_define_const(rb_cGDBM, "SYNC", INT2FIX(GDBM_SYNC));
01278 #endif
01279 #if defined(GDBM_NOLOCK)
01280
01281 rb_define_const(rb_cGDBM, "NOLOCK", INT2FIX(GDBM_NOLOCK));
01282 #endif
01283
01284 rb_define_const(rb_cGDBM, "VERSION", rb_str_new2(gdbm_version));
01285 }
01286