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 #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
00119
00120
00121
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
00137
00138
00139
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
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
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;
00194 }
00195 else if (NIL_P(vmode)) {
00196 mode = -1;
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
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
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
00368
00369
00370
00371
00372 static VALUE
00373 fgdbm_aref(VALUE obj, VALUE keystr)
00374 {
00375 return rb_gdbm_fetch3(obj, keystr);
00376 }
00377
00378
00379
00380
00381
00382
00383
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
00400
00401
00402
00403
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
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
00438
00439
00440
00441
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
00468
00469
00470
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
00521
00522
00523
00524
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
00538
00539
00540
00541
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
00562
00563
00564
00565
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
00601
00602
00603
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
00644
00645
00646
00647
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
00669
00670
00671
00672
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
00714
00715
00716
00717
00718
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
00729
00730
00731
00732
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
00744
00745
00746
00747
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
00772
00773
00774
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
00801
00802
00803
00804
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
00827
00828
00829
00830
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
00853
00854
00855
00856
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
00880
00881
00882
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
00904
00905
00906
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
00930
00931
00932
00933
00934
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
00955
00956
00957
00958
00959
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
00987
00988
00989
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
01011
01012
01013
01014
01015
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
01031
01032
01033
01034
01035
01036
01037
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
01053
01054
01055
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
01074
01075
01076
01077
01078
01079
01080
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
01102
01103
01104
01105
01106
01107
01108
01109
01110
01111
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
01138
01139
01140
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
01162
01163
01164
01165
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
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
01231 rb_define_const(rb_cGDBM, "READER", INT2FIX(GDBM_READER|RUBY_GDBM_RW_BIT));
01232
01233 rb_define_const(rb_cGDBM, "WRITER", INT2FIX(GDBM_WRITER|RUBY_GDBM_RW_BIT));
01234
01235 rb_define_const(rb_cGDBM, "WRCREAT", INT2FIX(GDBM_WRCREAT|RUBY_GDBM_RW_BIT));
01236
01237 rb_define_const(rb_cGDBM, "NEWDB", INT2FIX(GDBM_NEWDB|RUBY_GDBM_RW_BIT));
01238
01239
01240 rb_define_const(rb_cGDBM, "FAST", INT2FIX(GDBM_FAST));
01241
01242
01243
01244
01245 #if defined(GDBM_SYNC)
01246
01247 rb_define_const(rb_cGDBM, "SYNC", INT2FIX(GDBM_SYNC));
01248 #endif
01249 #if defined(GDBM_NOLOCK)
01250
01251 rb_define_const(rb_cGDBM, "NOLOCK", INT2FIX(GDBM_NOLOCK));
01252 #endif
01253
01254 rb_define_const(rb_cGDBM, "VERSION", rb_str_new2(gdbm_version));
01255 }
01256