diff options
Diffstat (limited to 'ext/gdbm/gdbm.c')
-rw-r--r-- | ext/gdbm/gdbm.c | 565 |
1 files changed, 437 insertions, 128 deletions
diff --git a/ext/gdbm/gdbm.c b/ext/gdbm/gdbm.c index d84c7bedd4..d43450229f 100644 --- a/ext/gdbm/gdbm.c +++ b/ext/gdbm/gdbm.c @@ -14,7 +14,7 @@ #include <fcntl.h> #include <errno.h> -VALUE cGDBM; +static VALUE cGDBM, rb_eGDBMError; #define MY_BLOCK_SIZE (2048) #define MY_FATAL_FUNC (0) @@ -32,6 +32,7 @@ closed_dbm() #define GetDBM(obj, dbmp) {\ Data_Get_Struct(obj, struct dbmdata, dbmp);\ + if (dbmp == 0) closed_dbm();\ if (dbmp->di_dbm == 0) closed_dbm();\ } @@ -39,23 +40,37 @@ static void free_dbm(dbmp) struct dbmdata *dbmp; { - if (dbmp->di_dbm) gdbm_close(dbmp->di_dbm); - free(dbmp); + if (dbmp) { + if (dbmp->di_dbm) gdbm_close(dbmp->di_dbm); + free(dbmp); + } } +static VALUE fgdbm_close _((VALUE)); + static VALUE -fgdbm_s_open(argc, argv, klass) +fgdbm_s_new(argc, argv, klass) int argc; VALUE *argv; VALUE klass; { - VALUE file, vmode; + VALUE obj = Data_Wrap_Struct(klass, 0, free_dbm, 0); + rb_obj_call_init(obj, argc, argv); + return obj; +} + +static VALUE +fgdbm_initialize(argc, argv, obj) + int argc; + VALUE *argv; + VALUE obj; +{ + VALUE file, vmode, vflags; GDBM_FILE dbm; struct dbmdata *dbmp; - int mode; - VALUE obj; + int mode, flags = 0; - if (rb_scan_args(argc, argv, "11", &file, &vmode) == 1) { + if (rb_scan_args(argc, argv, "12", &file, &vmode, &vflags) == 1) { mode = 0666; /* default value */ } else if (NIL_P(vmode)) { @@ -64,25 +79,37 @@ fgdbm_s_open(argc, argv, klass) else { mode = NUM2INT(vmode); } + + if (!NIL_P(vflags)) + flags = NUM2INT(vflags); + + file = rb_str_to_str(file); Check_SafeStr(file); dbm = 0; if (mode >= 0) dbm = gdbm_open(RSTRING(file)->ptr, MY_BLOCK_SIZE, - O_RDWR|O_CREAT, mode, MY_FATAL_FUNC); + GDBM_WRCREAT|flags, mode, MY_FATAL_FUNC); if (!dbm) dbm = gdbm_open(RSTRING(file)->ptr, MY_BLOCK_SIZE, - O_RDWR, 0, MY_FATAL_FUNC); + GDBM_WRITER|flags, 0, MY_FATAL_FUNC); if (!dbm) dbm = gdbm_open(RSTRING(file)->ptr, MY_BLOCK_SIZE, - O_RDONLY, 0, MY_FATAL_FUNC); + GDBM_READER|flags, 0, MY_FATAL_FUNC); if (!dbm) { if (mode == -1) return Qnil; - rb_sys_fail(RSTRING(file)->ptr); + + if (gdbm_errno == GDBM_FILE_OPEN_ERROR || + gdbm_errno == GDBM_CANT_BE_READER || + gdbm_errno == GDBM_CANT_BE_WRITER) + rb_sys_fail(RSTRING(file)->ptr); + else + rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno)); } - obj = Data_Make_Struct(klass,struct dbmdata,0,free_dbm,dbmp); + dbmp = ALLOC(struct dbmdata); + DATA_PTR(obj) = dbmp; dbmp->di_dbm = dbm; dbmp->di_size = -1; @@ -90,6 +117,25 @@ fgdbm_s_open(argc, argv, klass) } static VALUE +fgdbm_s_open(argc, argv, klass) + int argc; + VALUE *argv; + VALUE klass; +{ + VALUE obj = Data_Wrap_Struct(klass, 0, free_dbm, 0); + + if (NIL_P(fgdbm_initialize(argc, argv, obj))) { + return Qnil; + } + + if (rb_block_given_p()) { + return rb_ensure(rb_yield, obj, fgdbm_close, obj); + } + + return obj; +} + +static VALUE fgdbm_close(obj) VALUE obj; { @@ -103,33 +149,130 @@ fgdbm_close(obj) } static VALUE +rb_gdbm_fetch(dbm, key) + GDBM_FILE dbm; + datum key; +{ + datum val; + NEWOBJ(str, struct RString); + OBJSETUP(str, rb_cString, T_STRING); + + val = gdbm_fetch(dbm, key); + if (val.dptr == 0) + return Qnil; + + str->ptr = 0; + str->len = val.dsize; + str->orig = 0; + str->ptr = REALLOC_N(val.dptr,char,val.dsize+1); + str->ptr[str->len] = '\0'; + + OBJ_TAINT(str); + return (VALUE)str; +} + +static VALUE +rb_gdbm_fetch2(dbm, keystr) + GDBM_FILE dbm; + VALUE keystr; +{ + datum key; + + keystr = rb_str_to_str(keystr); + key.dptr = RSTRING(keystr)->ptr; + key.dsize = RSTRING(keystr)->len; + + return rb_gdbm_fetch(dbm, key); +} + +static VALUE +rb_gdbm_fetch3(obj, keystr) + VALUE obj, keystr; +{ + struct dbmdata *dbmp; + GDBM_FILE dbm; + + GetDBM(obj, dbmp); + dbm = dbmp->di_dbm; + return rb_gdbm_fetch2(dbm, keystr); +} + +static VALUE +rb_gdbm_firstkey(dbm) + GDBM_FILE dbm; +{ + datum key; + NEWOBJ(str, struct RString); + OBJSETUP(str, rb_cString, T_STRING); + + key = gdbm_firstkey(dbm); + if (key.dptr == 0) + return Qnil; + + str->ptr = 0; + str->len = key.dsize; + str->orig = 0; + str->ptr = REALLOC_N(key.dptr,char,key.dsize+1); + str->ptr[str->len] = '\0'; + + OBJ_TAINT(str); + return (VALUE)str; +} + +static VALUE +rb_gdbm_nextkey(dbm, keystr) + GDBM_FILE dbm; + VALUE keystr; +{ + datum key, key2; + NEWOBJ(str, struct RString); + OBJSETUP(str, rb_cString, T_STRING); + + key.dptr = RSTRING(keystr)->ptr; + key.dsize = RSTRING(keystr)->len; + key2 = gdbm_nextkey(dbm, key); + if (key2.dptr == 0) + return Qnil; + + str->ptr = 0; + str->len = key2.dsize; + str->orig = 0; + str->ptr = REALLOC_N(key2.dptr,char,key2.dsize+1); + str->ptr[str->len] = '\0'; + + OBJ_TAINT(str); + return (VALUE)str; +} + +static VALUE fgdbm_fetch(obj, keystr, ifnone) VALUE obj, keystr, ifnone; { - datum key, value; + datum key; struct dbmdata *dbmp; GDBM_FILE dbm; + VALUE valstr; - Check_Type(keystr, T_STRING); + keystr = rb_str_to_str(keystr); key.dptr = RSTRING(keystr)->ptr; key.dsize = RSTRING(keystr)->len; GetDBM(obj, dbmp); dbm = dbmp->di_dbm; - value = gdbm_fetch(dbm, key); - if (value.dptr == 0) { + valstr = rb_gdbm_fetch(dbm, key); + if (NIL_P(valstr)) { if (ifnone == Qnil && rb_block_given_p()) return rb_yield(rb_tainted_str_new(key.dptr, key.dsize)); return ifnone; } - return rb_tainted_str_new(value.dptr, value.dsize); + return valstr; } static VALUE fgdbm_aref(obj, keystr) VALUE obj, keystr; { - return fgdbm_fetch(obj, keystr, Qnil); + return rb_gdbm_fetch3(obj, keystr); } static VALUE @@ -138,31 +281,37 @@ fgdbm_fetch_m(argc, argv, obj) VALUE *argv; VALUE obj; { - VALUE keystr, ifnone; + VALUE keystr, valstr, ifnone; rb_scan_args(argc, argv, "11", &keystr, &ifnone); - return fgdbm_fetch(obj, keystr, ifnone); + valstr = fgdbm_fetch(obj, keystr, ifnone); + if (argc == 1 && !rb_block_given_p() && NIL_P(valstr)) + rb_raise(rb_eIndexError, "key not found"); + + return valstr; } static VALUE fgdbm_index(obj, valstr) VALUE obj, valstr; { - datum key, val; struct dbmdata *dbmp; GDBM_FILE dbm; + VALUE keystr, valstr2; - Check_Type(valstr, T_STRING); - val.dptr = RSTRING(valstr)->ptr; - val.dsize = RSTRING(valstr)->len; - + valstr = rb_str_to_str(valstr); GetDBM(obj, dbmp); dbm = dbmp->di_dbm; - for (key = gdbm_firstkey(dbm); key.dptr; key = gdbm_nextkey(dbm, key)) { - val = gdbm_fetch(dbm, key); - if (val.dsize == RSTRING(valstr)->len && - memcmp(val.dptr, RSTRING(valstr)->ptr, val.dsize) == 0) - return rb_tainted_str_new(key.dptr, key.dsize); + for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr); + keystr = rb_gdbm_nextkey(dbm, keystr)) { + + valstr2 = rb_gdbm_fetch2(dbm, keystr); + if (!NIL_P(valstr2) && + RSTRING(valstr)->len == RSTRING(valstr2)->len && + memcmp(RSTRING(valstr)->ptr, RSTRING(valstr2)->ptr, + RSTRING(valstr)->len) == 0) { + return keystr; + } } return Qnil; } @@ -178,37 +327,66 @@ fgdbm_indexes(argc, argv, obj) new = rb_ary_new2(argc); for (i=0; i<argc; i++) { - rb_ary_push(new, fgdbm_fetch(obj, argv[i])); + rb_ary_push(new, rb_gdbm_fetch3(obj, argv[i])); } return new; } static VALUE +rb_gdbm_delete(obj, keystr) + VALUE obj, keystr; +{ + datum key; + struct dbmdata *dbmp; + GDBM_FILE dbm; + + rb_secure(4); + keystr = rb_str_to_str(keystr); + key.dptr = RSTRING(keystr)->ptr; + key.dsize = RSTRING(keystr)->len; + + GetDBM(obj, dbmp); + dbm = dbmp->di_dbm; + + if (!gdbm_exists(dbm, key)) { + return Qnil; + } + + if (gdbm_delete(dbm, key)) { + dbmp->di_size = -1; + rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno)); + } + else if (dbmp->di_size >= 0) { + dbmp->di_size--; + } + return obj; +} + +static VALUE fgdbm_delete(obj, keystr) VALUE obj, keystr; { - datum key, value; + datum key; struct dbmdata *dbmp; GDBM_FILE dbm; rb_secure(4); - Check_Type(keystr, T_STRING); + keystr = rb_str_to_str(keystr); key.dptr = RSTRING(keystr)->ptr; key.dsize = RSTRING(keystr)->len; GetDBM(obj, dbmp); dbm = dbmp->di_dbm; - value = gdbm_fetch(dbm, key); - if (value.dptr == 0) { + if (!gdbm_exists(dbm, key)) { if (rb_block_given_p()) rb_yield(keystr); return Qnil; } if (gdbm_delete(dbm, key)) { dbmp->di_size = -1; - rb_raise(rb_eRuntimeError, "gdbm_delete failed"); + rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno)); } else if (dbmp->di_size >= 0) { dbmp->di_size--; @@ -220,7 +398,6 @@ static VALUE fgdbm_shift(obj) VALUE obj; { - datum key, val; struct dbmdata *dbmp; GDBM_FILE dbm; VALUE keystr, valstr; @@ -229,13 +406,11 @@ fgdbm_shift(obj) GetDBM(obj, dbmp); dbm = dbmp->di_dbm; - key = gdbm_firstkey(dbm); - if (!key.dptr) return Qnil; - val = gdbm_fetch(dbm, key); - gdbm_delete(dbm, key); + keystr = rb_gdbm_firstkey(dbm); + if (NIL_P(keystr)) return Qnil; + valstr = rb_gdbm_fetch2(dbm, keystr); + rb_gdbm_delete(obj, keystr); - keystr = rb_tainted_str_new(key.dptr, key.dsize); - valstr = rb_tainted_str_new(val.dptr, val.dsize); return rb_assoc_new(keystr, valstr); } @@ -243,24 +418,34 @@ static VALUE fgdbm_delete_if(obj) VALUE obj; { - datum key, val; struct dbmdata *dbmp; GDBM_FILE dbm; VALUE keystr, valstr; + VALUE ret, ary = rb_ary_new(); + int i, status = 0, n; rb_secure(4); GetDBM(obj, dbmp); dbm = dbmp->di_dbm; - for (key = gdbm_firstkey(dbm); key.dptr; key = gdbm_nextkey(dbm, key)) { - val = gdbm_fetch(dbm, key); - keystr = rb_tainted_str_new(key.dptr, key.dsize); - valstr = rb_tainted_str_new(val.dptr, val.dsize); - if (RTEST(rb_yield(rb_assoc_new(keystr, valstr)))) { - if (gdbm_delete(dbm, key)) { - rb_raise(rb_eRuntimeError, "gdbm_delete failed"); - } - } + n = dbmp->di_size; + dbmp->di_size = -1; + + for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr); + keystr = rb_gdbm_nextkey(dbm, keystr)) { + + valstr = rb_gdbm_fetch2(dbm, keystr); + ret = rb_protect(rb_yield, rb_assoc_new(rb_str_dup(keystr), valstr), &status); + if (status != 0) goto delete; + if (RTEST(ret)) rb_ary_push(ary, keystr); + else dbmp->di_size++; } + + delete: + for (i = 0; i < RARRAY(ary)->len; i++) + rb_gdbm_delete(obj, RARRAY(ary)->ptr[i]); + if (status) rb_jump_tag(status); + if (n > 0) dbmp->di_size = n - RARRAY(ary)->len; + return obj; } @@ -276,12 +461,20 @@ fgdbm_clear(obj) GetDBM(obj, dbmp); dbm = dbmp->di_dbm; dbmp->di_size = -1; - for (key = gdbm_firstkey(dbm); key.dptr; key = nextkey) { - nextkey = gdbm_nextkey(dbm, key); - if (gdbm_delete(dbm, key)) { - rb_raise(rb_eRuntimeError, "gdbm_delete failed"); - } + + while (key = gdbm_firstkey(dbm), key.dptr) { + for (; key.dptr; key = nextkey) { + nextkey = gdbm_nextkey(dbm, key); + if (gdbm_delete(dbm, key)) { + free(key.dptr); + if (nextkey.dptr) free(nextkey.dptr); + rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno)); + } + free(key.dptr); + } } + dbmp->di_size = 0; + return obj; } @@ -289,7 +482,6 @@ static VALUE fgdbm_invert(obj) VALUE obj; { - datum key, val; struct dbmdata *dbmp; GDBM_FILE dbm; VALUE keystr, valstr; @@ -297,10 +489,10 @@ fgdbm_invert(obj) GetDBM(obj, dbmp); dbm = dbmp->di_dbm; - for (key = gdbm_firstkey(dbm); key.dptr; key = gdbm_nextkey(dbm, key)) { - val = gdbm_fetch(dbm, key); - keystr = rb_tainted_str_new(key.dptr, key.dsize); - valstr = rb_tainted_str_new(val.dptr, val.dsize); + for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr); + keystr = rb_gdbm_nextkey(dbm, keystr)) { + valstr = rb_gdbm_fetch2(dbm, keystr); + rb_hash_aset(hash, valstr, keystr); } return hash; @@ -353,12 +545,11 @@ fgdbm_store(obj, keystr, valstr) GDBM_FILE dbm; rb_secure(4); - keystr = rb_obj_as_string(keystr); - + keystr = rb_str_to_str(keystr); key.dptr = RSTRING(keystr)->ptr; key.dsize = RSTRING(keystr)->len; - valstr = rb_obj_as_string(valstr); + valstr = rb_str_to_str(valstr); val.dptr = RSTRING(valstr)->ptr; val.dsize = RSTRING(valstr)->len; @@ -367,7 +558,7 @@ fgdbm_store(obj, keystr, valstr) dbm = dbmp->di_dbm; if (gdbm_store(dbm, key, val, GDBM_REPLACE)) { if (errno == EPERM) rb_sys_fail(0); - rb_raise(rb_eRuntimeError, "gdbm_store failed"); + rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno)); } return valstr; @@ -377,7 +568,7 @@ static VALUE fgdbm_length(obj) VALUE obj; { - datum key; + datum key, nextkey; struct dbmdata *dbmp; GDBM_FILE dbm; int i = 0; @@ -386,7 +577,9 @@ fgdbm_length(obj) if (dbmp->di_size > 0) return INT2FIX(dbmp->di_size); dbm = dbmp->di_dbm; - for (key = gdbm_firstkey(dbm); key.dptr; key = gdbm_nextkey(dbm, key)) { + for (key = gdbm_firstkey(dbm); key.dptr; key = nextkey) { + nextkey = gdbm_nextkey(dbm, key); + free(key.dptr); i++; } dbmp->di_size = i; @@ -398,23 +591,23 @@ static VALUE fgdbm_empty_p(obj) VALUE obj; { - datum key; + datum key, nextkey; struct dbmdata *dbmp; GDBM_FILE dbm; - int i = 0; GetDBM(obj, dbmp); if (dbmp->di_size < 0) { dbm = dbmp->di_dbm; - for (key = gdbm_firstkey(dbm); key.dptr; key = gdbm_nextkey(dbm, key)) { - i++; + key = gdbm_firstkey(dbm); + if (key.dptr) { + free(key.dptr); + return Qfalse; } + return Qtrue; } - else { - i = dbmp->di_size; - } - if (i == 0) return Qtrue; + + if (dbmp->di_size == 0) return Qtrue; return Qfalse; } @@ -422,15 +615,17 @@ static VALUE fgdbm_each_value(obj) VALUE obj; { - datum key, val; struct dbmdata *dbmp; GDBM_FILE dbm; + VALUE keystr; GetDBM(obj, dbmp); dbm = dbmp->di_dbm; - for (key = gdbm_firstkey(dbm); key.dptr; key = gdbm_nextkey(dbm, key)) { - val = gdbm_fetch(dbm, key); - rb_yield(rb_tainted_str_new(val.dptr, val.dsize)); + + for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr); + keystr = rb_gdbm_nextkey(dbm, keystr)) { + + rb_yield(rb_gdbm_fetch2(dbm, keystr)); } return obj; } @@ -439,14 +634,17 @@ static VALUE fgdbm_each_key(obj) VALUE obj; { - datum key; struct dbmdata *dbmp; GDBM_FILE dbm; + VALUE keystr; GetDBM(obj, dbmp); dbm = dbmp->di_dbm; - for (key = gdbm_firstkey(dbm); key.dptr; key = gdbm_nextkey(dbm, key)) { - rb_yield(rb_tainted_str_new(key.dptr, key.dsize)); + + for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr); + keystr = rb_gdbm_nextkey(dbm, keystr)) { + + rb_yield(rb_str_dup(keystr)); } return obj; } @@ -455,19 +653,18 @@ static VALUE fgdbm_each_pair(obj) VALUE obj; { - datum key, val; GDBM_FILE dbm; struct dbmdata *dbmp; - VALUE keystr, valstr; + VALUE keystr; GetDBM(obj, dbmp); dbm = dbmp->di_dbm; - for (key = gdbm_firstkey(dbm); key.dptr; key = gdbm_nextkey(dbm, key)) { - val = gdbm_fetch(dbm, key); - keystr = rb_tainted_str_new(key.dptr, key.dsize); - valstr = rb_tainted_str_new(val.dptr, val.dsize); - rb_yield(rb_assoc_new(keystr, valstr)); + for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr); + keystr = rb_gdbm_nextkey(dbm, keystr)) { + + rb_yield(rb_assoc_new(rb_str_dup(keystr), + rb_gdbm_fetch2(dbm, keystr))); } return obj; @@ -477,17 +674,18 @@ static VALUE fgdbm_keys(obj) VALUE obj; { - datum key; struct dbmdata *dbmp; GDBM_FILE dbm; - VALUE ary; + VALUE keystr, ary; GetDBM(obj, dbmp); dbm = dbmp->di_dbm; ary = rb_ary_new(); - for (key = gdbm_firstkey(dbm); key.dptr; key = gdbm_nextkey(dbm, key)) { - rb_ary_push(ary, rb_tainted_str_new(key.dptr, key.dsize)); + for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr); + keystr = rb_gdbm_nextkey(dbm, keystr)) { + + rb_ary_push(ary, keystr); } return ary; @@ -497,18 +695,20 @@ static VALUE fgdbm_values(obj) VALUE obj; { - datum key, val; + datum key, nextkey; struct dbmdata *dbmp; GDBM_FILE dbm; - VALUE ary; + VALUE valstr, ary; GetDBM(obj, dbmp); dbm = dbmp->di_dbm; ary = rb_ary_new(); - for (key = gdbm_firstkey(dbm); key.dptr; key = gdbm_nextkey(dbm, key)) { - val = gdbm_fetch(dbm, key); - rb_ary_push(ary, rb_tainted_str_new(val.dptr, val.dsize)); + for (key = gdbm_firstkey(dbm); key.dptr; key = nextkey) { + nextkey = gdbm_nextkey(dbm, key); + valstr = rb_gdbm_fetch(dbm, key); + free(key.dptr); + rb_ary_push(ary, valstr); } return ary; @@ -518,18 +718,18 @@ static VALUE fgdbm_has_key(obj, keystr) VALUE obj, keystr; { - datum key, val; + datum key; struct dbmdata *dbmp; GDBM_FILE dbm; - Check_Type(keystr, T_STRING); + keystr = rb_str_to_str(keystr); key.dptr = RSTRING(keystr)->ptr; key.dsize = RSTRING(keystr)->len; GetDBM(obj, dbmp); dbm = dbmp->di_dbm; - val = gdbm_fetch(dbm, key); - if (val.dptr) return Qtrue; + if (gdbm_exists(dbm, key)) + return Qtrue; return Qfalse; } @@ -537,21 +737,24 @@ static VALUE fgdbm_has_value(obj, valstr) VALUE obj, valstr; { - datum key, val; struct dbmdata *dbmp; GDBM_FILE dbm; + VALUE keystr, valstr2; - Check_Type(valstr, T_STRING); - val.dptr = RSTRING(valstr)->ptr; - val.dsize = RSTRING(valstr)->len; - + valstr = rb_str_to_str(valstr); GetDBM(obj, dbmp); dbm = dbmp->di_dbm; - for (key = gdbm_firstkey(dbm); key.dptr; key = gdbm_nextkey(dbm, key)) { - val = gdbm_fetch(dbm, key); - if (val.dsize == RSTRING(valstr)->len && - memcmp(val.dptr, RSTRING(valstr)->ptr, val.dsize) == 0) + for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr); + keystr = rb_gdbm_nextkey(dbm, keystr)) { + + valstr2 = rb_gdbm_fetch2(dbm, keystr); + + if (!NIL_P(valstr2) && + RSTRING(valstr)->len == RSTRING(valstr2)->len && + memcmp(RSTRING(valstr)->ptr, RSTRING(valstr2)->ptr, + RSTRING(valstr)->len) == 0) { return Qtrue; + } } return Qfalse; } @@ -560,19 +763,19 @@ static VALUE fgdbm_to_a(obj) VALUE obj; { - datum key, val; struct dbmdata *dbmp; GDBM_FILE dbm; - VALUE ary; + VALUE keystr, ary; GetDBM(obj, dbmp); dbm = dbmp->di_dbm; ary = rb_ary_new(); - for (key = gdbm_firstkey(dbm); key.dptr; key = gdbm_nextkey(dbm, key)) { - val = gdbm_fetch(dbm, key); - rb_ary_push(ary, rb_assoc_new(rb_tainted_str_new(key.dptr, key.dsize), - rb_tainted_str_new(val.dptr, val.dsize))); + for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr); + keystr = rb_gdbm_nextkey(dbm, keystr)) { + + rb_ary_push(ary, rb_assoc_new(rb_str_dup(keystr), + rb_gdbm_fetch2(dbm, keystr))); } return ary; @@ -593,22 +796,100 @@ fgdbm_reorganize(obj) } static VALUE +fgdbm_sync(obj) + VALUE obj; +{ + struct dbmdata *dbmp; + GDBM_FILE dbm; + + rb_secure(4); + GetDBM(obj, dbmp); + dbm = dbmp->di_dbm; + gdbm_sync(dbm); + return obj; +} + +static VALUE +fgdbm_set_cachesize(obj, val) + VALUE obj, val; +{ + struct dbmdata *dbmp; + GDBM_FILE dbm; + int optval; + + GetDBM(obj, dbmp); + dbm = dbmp->di_dbm; + + optval = FIX2INT(val); + if (gdbm_setopt(dbm, GDBM_CACHESIZE, &optval, sizeof(optval)) == -1) { + rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno)); + } + return val; +} + +static VALUE +fgdbm_set_fastmode(obj, val) + VALUE obj, val; +{ + struct dbmdata *dbmp; + GDBM_FILE dbm; + int optval; + + GetDBM(obj, dbmp); + dbm = dbmp->di_dbm; + + optval = 0; + if (RTEST(val)) + optval = 1; + + if (gdbm_setopt(dbm, GDBM_FASTMODE, &optval, sizeof(optval)) == -1) { + rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno)); + } + return val; +} + +static VALUE +fgdbm_set_syncmode(obj, val) + VALUE obj, val; +{ +#if !defined(GDBM_SYNCMODE) + fgdbm_set_fastmode(obj, RTEST(val) ? Qfalse : Qtrue); + return val; +#else + struct dbmdata *dbmp; + GDBM_FILE dbm; + int optval; + + GetDBM(obj, dbmp); + dbm = dbmp->di_dbm; + + optval = 0; + if (RTEST(val)) + optval = 1; + + if (gdbm_setopt(dbm, GDBM_FASTMODE, &optval, sizeof(optval)) == -1) { + rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno)); + } + return val; +#endif +} + +static VALUE fgdbm_to_hash(obj) VALUE obj; { - datum key, val; struct dbmdata *dbmp; GDBM_FILE dbm; - VALUE hash; + VALUE keystr, hash; GetDBM(obj, dbmp); dbm = dbmp->di_dbm; hash = rb_hash_new(); - for (key = gdbm_firstkey(dbm); key.dptr; key = gdbm_nextkey(dbm, key)) { - val = gdbm_fetch(dbm, key); - rb_hash_aset(hash, rb_tainted_str_new(key.dptr, key.dsize), - rb_tainted_str_new(val.dptr, val.dsize)); + for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr); + keystr = rb_gdbm_nextkey(dbm, keystr)) { + + rb_hash_aset(hash, keystr, rb_gdbm_fetch2(dbm, keystr)); } return hash; @@ -625,10 +906,13 @@ void Init_gdbm() { cGDBM = rb_define_class("GDBM", rb_cObject); + rb_eGDBMError = rb_define_class("GDBMError", rb_eStandardError); rb_include_module(cGDBM, rb_mEnumerable); + rb_define_singleton_method(cGDBM, "new", fgdbm_s_new, -1); rb_define_singleton_method(cGDBM, "open", fgdbm_s_open, -1); - rb_define_singleton_method(cGDBM, "new", fgdbm_s_open, -1); + + rb_define_method(cGDBM, "initialize", fgdbm_initialize, -1); rb_define_method(cGDBM, "close", fgdbm_close, 0); rb_define_method(cGDBM, "[]", fgdbm_aref, 1); rb_define_method(cGDBM, "fetch", fgdbm_fetch_m, -1); @@ -646,7 +930,7 @@ Init_gdbm() rb_define_method(cGDBM, "each_pair", fgdbm_each_pair, 0); rb_define_method(cGDBM, "keys", fgdbm_keys, 0); rb_define_method(cGDBM, "values", fgdbm_values, 0); - rb_define_method(cGDBM, "shift", fgdbm_shift, 1); + rb_define_method(cGDBM, "shift", fgdbm_shift, 0); rb_define_method(cGDBM, "delete", fgdbm_delete, 1); rb_define_method(cGDBM, "delete_if", fgdbm_delete_if, 0); rb_define_method(cGDBM, "reject!", fgdbm_delete_if, 0); @@ -656,6 +940,11 @@ Init_gdbm() rb_define_method(cGDBM,"update", fgdbm_update, 1); rb_define_method(cGDBM,"replace", fgdbm_replace, 1); rb_define_method(cGDBM,"reorganize", fgdbm_reorganize, 0); + rb_define_method(cGDBM,"sync", fgdbm_sync, 0); + /* rb_define_method(cGDBM,"setopt", fgdbm_setopt, 2); */ + rb_define_method(cGDBM,"cachesize=", fgdbm_set_cachesize, 1); + rb_define_method(cGDBM,"fastmode=", fgdbm_set_fastmode, 1); + rb_define_method(cGDBM,"syncmode=", fgdbm_set_syncmode, 1); rb_define_method(cGDBM, "include?", fgdbm_has_key, 1); rb_define_method(cGDBM, "has_key?", fgdbm_has_key, 1); @@ -666,4 +955,24 @@ Init_gdbm() rb_define_method(cGDBM, "to_a", fgdbm_to_a, 0); rb_define_method(cGDBM, "to_hash", fgdbm_to_hash, 0); + + /* flags for gdbm_opn() */ + /* + rb_define_const(cGDBM, "READER", INT2FIX(GDBM_READER)); + rb_define_const(cGDBM, "WRITER", INT2FIX(GDBM_WRITER)); + rb_define_const(cGDBM, "WRCREAT", INT2FIX(GDBM_WRCREAT)); + rb_define_const(cGDBM, "NEWDB", INT2FIX(GDBM_NEWDB)); + */ + rb_define_const(cGDBM, "FAST", INT2FIX(GDBM_FAST)); + /* this flag is obsolete in gdbm 1.8. + On gdbm 1.8, fast mode is default behavior. */ + + /* gdbm version 1.8 specific */ +#if defined(GDBM_SYNC) + rb_define_const(cGDBM, "SYNC", INT2FIX(GDBM_SYNC)); +#endif +#if defined(GDBM_NOLOCK) + rb_define_const(cGDBM, "NOLOCK", INT2FIX(GDBM_NOLOCK)); +#endif + rb_define_const(cGDBM, "VERSION", rb_str_new2(gdbm_version)); } |