summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ToDo1
-rw-r--r--array.c65
-rw-r--r--bignum.c2
-rw-r--r--dir.c6
-rw-r--r--eval.c10
-rw-r--r--ext/dbm/testdbm.rb570
-rw-r--r--ext/gdbm/gdbm.c84
-rw-r--r--ext/gdbm/testgdbm.rb643
-rw-r--r--ext/nkf/nkf.c18
-rw-r--r--ext/pty/pty.c2
-rw-r--r--ext/readline/extconf.rb3
-rw-r--r--ext/readline/readline.c24
-rw-r--r--ext/sdbm/init.c115
-rw-r--r--ext/sdbm/testsdbm.rb536
-rw-r--r--ext/socket/socket.c100
-rw-r--r--ext/tcltklib/tcltklib.c39
-rw-r--r--ext/tk/lib/tk.rb43
-rw-r--r--ext/tk/lib/tkvirtevent.rb33
-rw-r--r--intern.h4
-rw-r--r--io.c2
-rw-r--r--lib/cgi/session.rb17
-rw-r--r--lib/date.rb5
-rw-r--r--lib/e2mmap.rb3
-rw-r--r--lib/getopts.rb4
-rw-r--r--lib/mathn.rb6
-rw-r--r--lib/mutex_m.rb3
-rw-r--r--lib/pstore.rb46
-rw-r--r--lib/singleton.rb2
-rw-r--r--lib/sync.rb3
-rw-r--r--lib/tempfile.rb49
-rw-r--r--misc/ruby-mode.el2
-rw-r--r--missing/alloca.c9
-rw-r--r--rubytest.rb2
-rw-r--r--sample/test.rb7
-rw-r--r--string.c26
-rw-r--r--win32/win32.c2
36 files changed, 2190 insertions, 296 deletions
diff --git a/ToDo b/ToDo
index 78b7100..517a2ea 100644
--- a/ToDo
+++ b/ToDo
@@ -26,6 +26,7 @@ Language Spec.
* to_i returns nil if str contains no digit.
* raise exception by `` error
* jar like combined library package.
+* "@foo ||= 44" should not warn you.
Hacking Interpreter
diff --git a/array.c b/array.c
index f92f207..4d6a96e 100644
--- a/array.c
+++ b/array.c
@@ -541,12 +541,21 @@ rb_ary_indexes(argc, argv, ary)
}
static void
-rb_ary_update(ary, beg, len, rpl, rlen)
+rb_ary_update(ary, beg, len, rpl)
VALUE ary;
long beg, len;
- VALUE *rpl;
- long rlen;
+ VALUE rpl;
{
+ long rlen;
+
+ if (NIL_P(rpl)) {
+ rpl = rb_ary_new2(0);
+ }
+ else if (TYPE(rpl) != T_ARRAY) {
+ rpl = rb_ary_new3(1, rpl);
+ }
+ rlen = RARRAY(rpl)->len;
+
if (len < 0) rb_raise(rb_eIndexError, "negative length %d", len);
if (beg < 0) {
beg += RARRAY(ary)->len;
@@ -567,7 +576,7 @@ rb_ary_update(ary, beg, len, rpl, rlen)
REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->capa);
}
rb_mem_clear(RARRAY(ary)->ptr+RARRAY(ary)->len, beg-RARRAY(ary)->len);
- MEMCPY(RARRAY(ary)->ptr+beg, rpl, VALUE, rlen);
+ MEMCPY(RARRAY(ary)->ptr+beg, RARRAY(rpl)->ptr, VALUE, rlen);
RARRAY(ary)->len = len;
}
else {
@@ -579,7 +588,7 @@ rb_ary_update(ary, beg, len, rpl, rlen)
alen = RARRAY(ary)->len + rlen - len;
if (alen >= RARRAY(ary)->capa) {
- RARRAY(ary)->capa=alen;
+ RARRAY(ary)->capa = alen;
REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->capa);
}
@@ -588,24 +597,8 @@ rb_ary_update(ary, beg, len, rpl, rlen)
VALUE, RARRAY(ary)->len-(beg+len));
RARRAY(ary)->len = alen;
}
- MEMMOVE(RARRAY(ary)->ptr+beg, rpl, VALUE, rlen);
- }
-}
-
-static void
-rb_ary_replace(ary, beg, len, rpl)
- VALUE ary, rpl;
- long beg, len;
-{
- long rlen;
-
- if (NIL_P(rpl)) {
- rpl = rb_ary_new2(0);
- }
- else if (TYPE(rpl) != T_ARRAY) {
- rpl = rb_ary_new3(1, rpl);
+ MEMMOVE(RARRAY(ary)->ptr+beg, RARRAY(rpl)->ptr, VALUE, rlen);
}
- rb_ary_update(ary, beg, len, RARRAY(rpl)->ptr, RARRAY(rpl)->len);
}
static VALUE
@@ -617,7 +610,7 @@ rb_ary_aset(argc, argv, ary)
long offset, beg, len;
if (argc == 3) {
- rb_ary_replace(ary, NUM2LONG(argv[0]), NUM2LONG(argv[1]), argv[2]);
+ rb_ary_update(ary, NUM2LONG(argv[0]), NUM2LONG(argv[1]), argv[2]);
return argv[2];
}
if (argc != 2) {
@@ -629,7 +622,7 @@ rb_ary_aset(argc, argv, ary)
}
else if (rb_range_beg_len(argv[0], &beg, &len, RARRAY(ary)->len, 1)) {
/* check if idx is Range */
- rb_ary_replace(ary, beg, len, argv[1]);
+ rb_ary_update(ary, beg, len, argv[1]);
return argv[1];
}
if (TYPE(argv[0]) == T_BIGNUM) {
@@ -648,10 +641,20 @@ rb_ary_insert(argc, argv, ary)
VALUE *argv;
VALUE ary;
{
+ long pos;
+
if (argc < 2) {
rb_raise(rb_eArgError, "wrong # of arguments(at least 2)");
}
- rb_ary_update(ary, NUM2LONG(argv[0]), 0, argv+1, argc-1);
+ pos = NUM2LONG(argv[0]);
+ if (pos == -1) {
+ pos = RSTRING(ary)->len;
+ }
+ else if (pos < 0) {
+ pos++;
+ }
+
+ rb_ary_update(ary, pos, 0, rb_ary_new4(argc-1, argv+1));
return ary;
}
@@ -1146,7 +1149,7 @@ rb_ary_slice_bang(argc, argv, ary)
pos = RARRAY(ary)->len + pos;
}
arg2 = rb_ary_subseq(ary, pos, len);
- rb_ary_replace(ary, pos, len, Qnil); /* Qnil/rb_ary_new2(0) */
+ rb_ary_update(ary, pos, len, Qnil); /* Qnil/rb_ary_new2(0) */
return arg2;
}
@@ -1199,11 +1202,11 @@ rb_ary_delete_if(ary)
}
static VALUE
-rb_ary_replace_m(ary, ary2)
+rb_ary_replace(ary, ary2)
VALUE ary, ary2;
{
ary2 = to_ary(ary2);
- rb_ary_replace(ary, 0, RARRAY(ary)->len, ary2);
+ rb_ary_update(ary, 0, RARRAY(ary)->len, ary2);
return ary;
}
@@ -1292,7 +1295,7 @@ rb_ary_concat(x, y)
y = to_ary(y);
if (RARRAY(y)->len > 0) {
- rb_ary_replace(x, RARRAY(x)->len, 0, y);
+ rb_ary_update(x, RARRAY(x)->len, 0, y);
}
return x;
}
@@ -1626,7 +1629,7 @@ flatten(ary, idx, ary2, memo)
rb_raise(rb_eArgError, "tried to flatten recursive array");
}
rb_ary_push(memo, id);
- rb_ary_replace(ary, idx, 1, ary2);
+ rb_ary_update(ary, idx, 1, ary2);
while (i < lim) {
if (TYPE(RARRAY(ary)->ptr[i]) == T_ARRAY) {
n = flatten(ary, i, RARRAY(ary)->ptr[i], memo);
@@ -1730,7 +1733,7 @@ Init_Array()
rb_define_method(rb_cArray, "delete_at", rb_ary_delete_at_m, 1);
rb_define_method(rb_cArray, "delete_if", rb_ary_delete_if, 0);
rb_define_method(rb_cArray, "reject!", rb_ary_reject_bang, 0);
- rb_define_method(rb_cArray, "replace", rb_ary_replace_m, 1);
+ rb_define_method(rb_cArray, "replace", rb_ary_replace, 1);
rb_define_method(rb_cArray, "clear", rb_ary_clear, 0);
rb_define_method(rb_cArray, "fill", rb_ary_fill, -1);
rb_define_method(rb_cArray, "include?", rb_ary_includes, 1);
diff --git a/bignum.c b/bignum.c
index 14efc7d..3ddc50c 100644
--- a/bignum.c
+++ b/bignum.c
@@ -23,7 +23,7 @@ VALUE rb_cBignum;
#if SIZEOF_INT*2 <= SIZEOF_LONG_LONG
typedef unsigned int BDIGIT;
typedef unsigned LONG_LONG BDIGIT_DBL;
-typedef long long BDIGIT_DBL_SIGNED;
+typedef LONG_LONG BDIGIT_DBL_SIGNED;
#elif SIZEOF_ING*2 <= SIZEOF_LONG
typedef unsigned int BDIGIT;
typedef unsigned long BDIGIT_DBL;
diff --git a/dir.c b/dir.c
index 0289b66..772d53f 100644
--- a/dir.c
+++ b/dir.c
@@ -750,7 +750,7 @@ glob_helper(path, flag, func, arg)
void
rb_glob(path, func, arg)
char *path;
- void (*func)();
+ void (*func) _((const char*, VALUE));
VALUE arg;
{
glob_helper(path, FNM_PERIOD, func, arg);
@@ -765,9 +765,11 @@ rb_globi(path, func, arg)
glob_helper(path, FNM_PERIOD|FNM_NOCASE, func, arg);
}
+static void push_pattern _((const char *path, VALUE ary));
+
static void
push_pattern(path, ary)
- char *path;
+ const char *path;
VALUE ary;
{
VALUE str = rb_tainted_str_new2(path);
diff --git a/eval.c b/eval.c
index 031dd4d..54d4a72 100644
--- a/eval.c
+++ b/eval.c
@@ -3929,7 +3929,7 @@ rb_rescue(b_proc, data1, r_proc, data2)
VALUE
rb_protect(proc, data, state)
- VALUE (*proc)();
+ VALUE (*proc) _((VALUE));
VALUE data;
int *state;
{
@@ -5731,7 +5731,7 @@ static struct end_proc_data *end_procs, *ephemeral_end_procs;
void
rb_set_end_proc(func, data)
- void (*func)();
+ void (*func) _((VALUE));
VALUE data;
{
struct end_proc_data *link = ALLOC(struct end_proc_data);
@@ -5762,6 +5762,8 @@ rb_mark_end_proc()
}
}
+static void call_end_proc _((VALUE data));
+
static void
call_end_proc(data)
VALUE data;
@@ -5804,7 +5806,7 @@ rb_exec_end_proc()
link = end_procs;
while (link) {
- rb_protect((VALUE(*)())link->func, link->data, &status);
+ rb_protect((VALUE(*)_((VALUE)))link->func, link->data, &status);
if (status) {
error_handle(status);
}
@@ -5813,7 +5815,7 @@ rb_exec_end_proc()
while (ephemeral_end_procs) {
link = ephemeral_end_procs;
ephemeral_end_procs = link->next;
- rb_protect((VALUE(*)())link->func, link->data, &status);
+ rb_protect((VALUE(*)_((VALUE)))link->func, link->data, &status);
if (status) {
error_handle(status);
}
diff --git a/ext/dbm/testdbm.rb b/ext/dbm/testdbm.rb
new file mode 100644
index 0000000..c6b26e0
--- /dev/null
+++ b/ext/dbm/testdbm.rb
@@ -0,0 +1,570 @@
+require 'runit/testcase'
+require 'runit/cui/testrunner'
+
+if $".grep(/\bdbm.so\b/).empty?
+ begin
+ require './dbm'
+ rescue LoadError
+ require 'dbm'
+ end
+end
+
+def uname_s
+ require 'rbconfig'
+ case Config::CONFIG['host_os']
+ when 'cygwin'
+ require 'Win32API'
+ uname = Win32API.new 'cygwin1', 'uname', 'P', 'I'
+ utsname = ' ' * 100
+ raise 'cannot get system name' if uname.call(utsname) == -1
+
+ utsname.unpack('A20' * 5)[0]
+ else
+ Config::CONFIG['host_os']
+ end
+end
+
+SYSTEM = uname_s
+
+class TestDBM < RUNIT::TestCase
+ def setup
+ @path = "tmptest_dbm_"
+ assert_instance_of(DBM, @dbm = DBM.new(@path))
+
+ # prepare to make readonly DBM file
+ DBM.open("tmptest_dbm_rdonly", 0400) {|dbm|
+ dbm['foo'] = 'FOO'
+ }
+ assert_instance_of(DBM, @dbm_rdonly = DBM.new("tmptest_dbm_rdonly", nil))
+ end
+ def teardown
+ assert_nil(@dbm.close)
+ assert_nil(@dbm_rdonly.close)
+ GC.start
+ File.delete *Dir.glob("tmptest_dbm*").to_a
+ p Dir.glob("tmptest_dbm*") if $DEBUG
+ end
+
+ def check_size(expect, dbm=@dbm)
+ assert_equals(expect, dbm.size)
+ n = 0
+ dbm.each { n+=1 }
+ assert_equals(expect, n)
+ if expect == 0
+ assert_equals(true, dbm.empty?)
+ else
+ assert_equals(false, dbm.empty?)
+ end
+ end
+
+ def test_version
+ STDERR.print DBM::VERSION
+ end
+
+ def test_s_new_has_no_block
+ # DBM.new ignore the block
+ foo = true
+ assert_instance_of(DBM, dbm = DBM.new("tmptest_dbm") { foo = false })
+ assert_equals(foo, true)
+ assert_nil(dbm.close)
+ end
+ def test_s_open_no_create
+ assert_nil(dbm = DBM.open("tmptest_dbm", nil))
+ ensure
+ dbm.close if dbm
+ end
+ def test_s_open_with_block
+ assert_equals(DBM.open("tmptest_dbm") { :foo }, :foo)
+ end
+ def test_s_open_lock
+ fork() {
+ assert_instance_of(DBM, dbm = DBM.open("tmptest_dbm", 0644))
+ sleep 2
+ }
+ begin
+ sleep 1
+ assert_exception(Errno::EWOULDBLOCK) {
+ begin
+ assert_instance_of(DBM, dbm2 = DBM.open("tmptest_dbm", 0644))
+ rescue Errno::EAGAIN, Errno::EACCES, Errno::EINVAL
+ raise Errno::EWOULDBLOCK
+ end
+ }
+ ensure
+ Process.wait
+ end
+ end
+
+=begin
+ # Is it guaranteed on many OS?
+ def test_s_open_lock_one_process
+ # locking on one process
+ assert_instance_of(DBM, dbm = DBM.open("tmptest_dbm", 0644))
+ assert_exception(Errno::EWOULDBLOCK) {
+ begin
+ DBM.open("tmptest_dbm", 0644)
+ rescue Errno::EAGAIN
+ raise Errno::EWOULDBLOCK
+ end
+ }
+ end
+=end
+
+ def test_s_open_nolock
+ # dbm 1.8.0 specific
+ if not defined? DBM::NOLOCK
+ return
+ end
+
+ fork() {
+ assert_instance_of(DBM, dbm = DBM.open("tmptest_dbm", 0644,
+ DBM::NOLOCK))
+ sleep 2
+ }
+ sleep 1
+ begin
+ dbm2 = nil
+ assert_no_exception(Errno::EWOULDBLOCK, Errno::EAGAIN, Errno::EACCES) {
+ assert_instance_of(DBM, dbm2 = DBM.open("tmptest_dbm", 0644))
+ }
+ ensure
+ Process.wait
+ dbm2.close if dbm2
+ end
+
+ p Dir.glob("tmptest_dbm*") if $DEBUG
+
+ fork() {
+ assert_instance_of(DBM, dbm = DBM.open("tmptest_dbm", 0644))
+ sleep 2
+ }
+ begin
+ sleep 1
+ dbm2 = nil
+ assert_no_exception(Errno::EWOULDBLOCK, Errno::EAGAIN, Errno::EACCES) {
+ # this test is failed on Cygwin98 (???)
+ assert_instance_of(DBM, dbm2 = DBM.open("tmptest_dbm", 0644,
+ DBM::NOLOCK))
+ }
+ ensure
+ Process.wait
+ dbm2.close if dbm2
+ end
+ end
+
+ def test_s_open_error
+ assert_instance_of(DBM, dbm = DBM.open("tmptest_dbm", 0))
+ assert_exception(Errno::EACCES) {
+ DBM.open("tmptest_dbm", 0)
+ }
+ dbm.close
+ end
+
+ def test_close
+ assert_instance_of(DBM, dbm = DBM.open("tmptest_dbm"))
+ assert_nil(dbm.close)
+
+ # closed DBM file
+ assert_exception(RuntimeError) { dbm.close }
+ end
+
+ def test_aref
+ assert_equals('bar', @dbm['foo'] = 'bar')
+ assert_equals('bar', @dbm['foo'])
+
+ assert_nil(@dbm['bar'])
+ end
+
+ def test_fetch
+ assert_equals('bar', @dbm['foo']='bar')
+ assert_equals('bar', @dbm.fetch('foo'))
+
+ # key not found
+ assert_exception(IndexError) {
+ @dbm.fetch('bar')
+ }
+
+ # test for `ifnone' arg
+ assert_equals('baz', @dbm.fetch('bar', 'baz'))
+
+ # test for `ifnone' block
+ assert_equals('foobar', @dbm.fetch('bar') {|key| 'foo' + key })
+ end
+
+ def test_aset
+ num = 0
+ 2.times {|i|
+ assert_equals('foo', @dbm['foo'] = 'foo')
+ assert_equals('foo', @dbm['foo'])
+ assert_equals('bar', @dbm['foo'] = 'bar')
+ assert_equals('bar', @dbm['foo'])
+
+ num += 1 if i == 0
+ assert_equals(num, @dbm.size)
+
+ # assign nil
+ assert_equals('', @dbm['bar'] = '')
+ assert_equals('', @dbm['bar'])
+
+ num += 1 if i == 0
+ assert_equals(num, @dbm.size)
+
+ # empty string
+ assert_equals('', @dbm[''] = '')
+ assert_equals('', @dbm[''])
+
+ num += 1 if i == 0
+ assert_equals(num, @dbm.size)
+
+ # Fixnum
+ assert_equals('200', @dbm['100'] = '200')
+ assert_equals('200', @dbm['100'])
+
+ num += 1 if i == 0
+ assert_equals(num, @dbm.size)
+
+ # Big key and value
+ assert_equals('y' * 100, @dbm['x' * 100] = 'y' * 100)
+ assert_equals('y' * 100, @dbm['x' * 100])
+
+ num += 1 if i == 0
+ assert_equals(num, @dbm.size)
+ }
+ end
+
+ def test_index
+ assert_equals('bar', @dbm['foo'] = 'bar')
+ assert_equals('foo', @dbm.index('bar'))
+ assert_nil(@dbm['bar'])
+ end
+
+ def test_indexes
+ keys = %w(foo bar baz)
+ values = %w(FOO BAR BAZ)
+ @dbm[keys[0]], @dbm[keys[1]], @dbm[keys[2]] = values
+ assert_equals(values.reverse, @dbm.indexes(*keys.reverse))
+ end
+
+ def test_length
+ num = 10
+ assert_equals(0, @dbm.size)
+ num.times {|i|
+ i = i.to_s
+ @dbm[i] = i
+ }
+ assert_equals(num, @dbm.size)
+
+ @dbm.shift
+
+ assert_equals(num - 1, @dbm.size)
+ end
+
+ def test_empty?
+ assert_equals(true, @dbm.empty?)
+ @dbm['foo'] = 'FOO'
+ assert_equals(false, @dbm.empty?)
+ end
+
+ def test_each_pair
+ n = 0
+ @dbm.each_pair { n += 1 }
+ assert_equals(0, n)
+
+ keys = %w(foo bar baz)
+ values = %w(FOO BAR BAZ)
+
+ @dbm[keys[0]], @dbm[keys[1]], @dbm[keys[2]] = values
+
+ n = 0
+ ret = @dbm.each_pair {|key, val|
+ assert_not_nil(i = keys.index(key))
+ assert_equals(val, values[i])
+
+ n += 1
+ }
+ assert_equals(keys.size, n)
+ assert_equals(@dbm, ret)
+ end
+
+ def test_each_value
+ n = 0
+ @dbm.each_value { n += 1 }
+ assert_equals(0, n)
+
+ keys = %w(foo bar baz)
+ values = %w(FOO BAR BAZ)
+
+ @dbm[keys[0]], @dbm[keys[1]], @dbm[keys[2]] = values
+
+ n = 0
+ ret = @dbm.each_value {|val|
+ assert_not_nil(key = @dbm.index(val))
+ assert_not_nil(i = keys.index(key))
+ assert_equals(val, values[i])
+
+ n += 1
+ }
+ assert_equals(keys.size, n)
+ assert_equals(@dbm, ret)
+ end
+
+ def test_each_key
+ n = 0
+ @dbm.each_key { n += 1 }
+ assert_equals(0, n)
+
+ keys = %w(foo bar baz)
+ values = %w(FOO BAR BAZ)
+
+ @dbm[keys[0]], @dbm[keys[1]], @dbm[keys[2]] = values
+
+ n = 0
+ ret = @dbm.each_key {|key|
+ assert_not_nil(i = keys.index(key))
+ assert_equals(@dbm[key], values[i])
+
+ n += 1
+ }
+ assert_equals(keys.size, n)
+ assert_equals(@dbm, ret)
+ end
+
+ def test_keys
+ assert_equals([], @dbm.keys)
+
+ keys = %w(foo bar baz)
+ values = %w(FOO BAR BAZ)
+
+ @dbm[keys[0]], @dbm[keys[1]], @dbm[keys[2]] = values
+
+ assert_equals(keys.sort, @dbm.keys.sort)
+ assert_equals(values.sort, @dbm.values.sort)
+ end
+
+ def test_values
+ test_keys
+ end
+
+ def test_shift
+ assert_nil(@dbm.shift)
+ assert_equals(0, @dbm.size)
+
+ keys = %w(foo bar baz)
+ values = %w(FOO BAR BAZ)
+
+ @dbm[keys[0]], @dbm[keys[1]], @dbm[keys[2]] = values
+
+ ret_keys = []
+ ret_values = []
+ while ret = @dbm.shift
+ ret_keys.push ret[0]
+ ret_values.push ret[1]
+
+ assert_equals(keys.size - ret_keys.size, @dbm.size)
+ end
+
+ assert_equals(keys.sort, ret_keys.sort)
+ assert_equals(values.sort, ret_values.sort)
+ end
+
+ def test_delete
+ keys = %w(foo bar baz)
+ values = %w(FOO BAR BAZ)
+ key = keys[1]
+
+ assert_nil(@dbm.delete(key))
+ assert_equals(0, @dbm.size)
+
+ @dbm[keys[0]], @dbm[keys[1]], @dbm[keys[2]] = values
+
+ assert_equals(@dbm, @dbm.delete(key))
+ assert_nil(@dbm[key])
+ assert_equals(2, @dbm.size)
+
+ assert_nil(@dbm.delete(key))
+
+ if /^CYGWIN_9/ !~ SYSTEM
+ assert_exception(DBMError) {
+ @dbm_rdonly.delete("foo")
+ }
+
+ assert_nil(@dbm_rdonly.delete("bar"))
+ end
+ end
+ def test_delete_with_block
+ key = 'no called block'
+ @dbm[key] = 'foo'
+ assert_equals(@dbm, @dbm.delete(key) {|k| k.replace 'called block'})
+ assert_equals('no called block', key)
+ assert_equals(0, @dbm.size)
+
+ key = 'no called block'
+ assert_nil(@dbm.delete(key) {|k| k.replace 'called block'})
+ assert_equals('called block', key)
+ assert_equals(0, @dbm.size)
+ end
+
+ def test_delete_if
+ v = "0"
+ 100.times {@dbm[v] = v; v = v.next}
+
+ ret = @dbm.delete_if {|key, val| key.to_i < 50}
+ assert_equals(@dbm, ret)
+ check_size(50, @dbm)
+
+ ret = @dbm.delete_if {|key, val| key.to_i >= 50}
+ assert_equals(@dbm, ret)
+ check_size(0, @dbm)
+
+ # break
+ v = "0"
+ 100.times {@dbm[v] = v; v = v.next}
+ check_size(100, @dbm)
+ n = 0;
+ @dbm.delete_if {|key, val|
+ break if n > 50
+ n+=1
+ true
+ }
+ assert_equals(51, n)
+ check_size(49, @dbm)
+
+ @dbm.clear
+
+ # raise
+ v = "0"
+ 100.times {@dbm[v] = v; v = v.next}
+ check_size(100, @dbm)
+ n = 0;
+ begin
+ @dbm.delete_if {|key, val|
+ raise "runtime error" if n > 50
+ n+=1
+ true
+ }
+ rescue
+ end
+ assert_equals(51, n)
+ check_size(49, @dbm)
+ end
+
+ def test_reject
+ v = "0"
+ 100.times {@dbm[v] = v; v = v.next}
+
+ hash = @dbm.reject {|key, val| key.to_i < 50}
+ assert_instance_of(Hash, hash)
+ assert_equals(100, @dbm.size)
+
+ assert_equals(50, hash.size)
+ hash.each_pair {|key,val|
+ assert_equals(false, key.to_i < 50)
+ assert_equals(key, val)
+ }
+
+ hash = @dbm.reject {|key, val| key.to_i < 100}
+ assert_instance_of(Hash, hash)
+ assert_equals(true, hash.empty?)
+ end
+
+ def test_clear
+ v = "1"
+ 100.times {v = v.next; @dbm[v] = v}
+
+ assert_equals(@dbm, @dbm.clear)
+
+ # validate DBM#size
+ i = 0
+ @dbm.each { i += 1 }
+ assert_equals(@dbm.size, i)
+ assert_equals(0, i)
+ end
+
+ def test_invert
+ v = "0"
+ 100.times {@dbm[v] = v; v = v.next}
+
+ hash = @dbm.invert
+ assert_instance_of(Hash, hash)
+ assert_equals(100, hash.size)
+ hash.each_pair {|key, val|
+ assert_equals(key.to_i, val.to_i)
+ }
+ end
+
+ def test_update
+ hash = {}
+ v = "0"
+ 100.times {v = v.next; hash[v] = v}
+
+ @dbm["101"] = "101"
+ @dbm.update hash
+ assert_equals(101, @dbm.size)
+ @dbm.each_pair {|key, val|
+ assert_equals(key.to_i, val.to_i)
+ }
+ end
+
+ def test_replace
+ hash = {}
+ v = "0"
+ 100.times {v = v.next; hash[v] = v}
+
+ @dbm["101"] = "101"
+ @dbm.replace hash
+ assert_equals(100, @dbm.size)
+ @dbm.each_pair {|key, val|
+ assert_equals(key.to_i, val.to_i)
+ }
+ end
+
+ def test_haskey?
+ assert_equals('bar', @dbm['foo']='bar')
+ assert_equals(true, @dbm.has_key?('foo'))
+ assert_equals(false, @dbm.has_key?('bar'))
+ end
+
+ def test_has_value?
+ assert_equals('bar', @dbm['foo']='bar')
+ assert_equals(true, @dbm.has_value?('bar'))
+ assert_equals(false, @dbm.has_value?('foo'))
+ end
+
+ def test_to_a
+ v = "0"
+ 100.times {v = v.next; @dbm[v] = v}
+
+ ary = @dbm.to_a
+ assert_instance_of(Array, ary)
+ assert_equals(100, ary.size)
+ ary.each {|key,val|
+ assert_equals(key.to_i, val.to_i)
+ }
+ end
+
+ def test_to_hash
+ v = "0"
+ 100.times {v = v.next; @dbm[v] = v}
+
+ hash = @dbm.to_hash
+ assert_instance_of(Hash, hash)
+ assert_equals(100, hash.size)
+ hash.each {|key,val|
+ assert_equals(key.to_i, val.to_i)
+ }
+ end
+end
+
+if $0 == __FILE__
+ if ARGV.size == 0
+ suite = RUNIT::TestSuite.new
+ suite.add_test(TestDBM.suite)
+ else
+ suite = RUNIT::TestSuite.new
+ ARGV.each do |testmethod|
+ suite.add_test(TestDBM.new(testmethod))
+ end
+ end
+
+ RUNIT::CUI::TestRunner.run(suite)
+end
diff --git a/ext/gdbm/gdbm.c b/ext/gdbm/gdbm.c
index ccfaead..f20286a 100644
--- a/ext/gdbm/gdbm.c
+++ b/ext/gdbm/gdbm.c
@@ -14,10 +14,16 @@
#include <fcntl.h>
#include <errno.h>
-static VALUE cGDBM, rb_eGDBMError;
+static VALUE cGDBM, rb_eGDBMError, rb_eGDBMFatalErrors;
#define MY_BLOCK_SIZE (2048)
-#define MY_FATAL_FUNC (0)
+#define MY_FATAL_FUNC rb_gdbm_fatal
+void
+rb_gdbm_fatal(msg)
+ char *msg;
+{
+ rb_raise(rb_eGDBMFatalErrors, msg);
+}
struct dbmdata {
int di_size;
@@ -185,6 +191,18 @@ rb_gdbm_fetch2(dbm, keystr)
}
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;
{
@@ -235,21 +253,12 @@ static VALUE
fgdbm_fetch(obj, keystr, ifnone)
VALUE obj, keystr, ifnone;
{
- datum key;
- struct dbmdata *dbmp;
- GDBM_FILE dbm;
VALUE valstr;
- StringValue(keystr);
- key.dptr = RSTRING(keystr)->ptr;
- key.dsize = RSTRING(keystr)->len;
-
- GetDBM(obj, dbmp);
- dbm = dbmp->di_dbm;
- valstr = rb_gdbm_fetch(dbm, key);
+ valstr = rb_gdbm_fetch3(obj, keystr);
if (NIL_P(valstr)) {
if (ifnone == Qnil && rb_block_given_p())
- return rb_yield(rb_tainted_str_new(key.dptr, key.dsize));
+ return rb_yield(keystr);
return ifnone;
}
return valstr;
@@ -259,7 +268,7 @@ static VALUE
fgdbm_aref(obj, keystr)
VALUE obj, keystr;
{
- return fgdbm_fetch(obj, keystr, Qnil);
+ return rb_gdbm_fetch3(obj, keystr);
}
static VALUE
@@ -314,7 +323,7 @@ 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;
@@ -354,31 +363,11 @@ static VALUE
fgdbm_delete(obj, keystr)
VALUE obj, keystr;
{
- datum key;
- struct dbmdata *dbmp;
- GDBM_FILE dbm;
-
- rb_secure(4);
- StringValue(keystr);
- key.dptr = RSTRING(keystr)->ptr;
- key.dsize = RSTRING(keystr)->len;
-
- GetDBM(obj, dbmp);
- dbm = dbmp->di_dbm;
-
- if (!gdbm_exists(dbm, key)) {
- if (rb_block_given_p()) rb_yield(keystr);
- return Qnil;
- }
+ VALUE valstr;
- 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;
+ valstr = fgdbm_fetch(obj, keystr, Qnil);
+ rb_gdbm_delete(obj, keystr);
+ return valstr;
}
static VALUE
@@ -438,7 +427,7 @@ static VALUE
fgdbm_clear(obj)
VALUE obj;
{
- datum key;
+ datum key, nextkey;
struct dbmdata *dbmp;
GDBM_FILE dbm;
@@ -447,6 +436,7 @@ fgdbm_clear(obj)
dbm = dbmp->di_dbm;
dbmp->di_size = -1;
+#if 0
while (key = gdbm_firstkey(dbm), key.dptr) {
if (gdbm_delete(dbm, key)) {
free(key.dptr);
@@ -454,6 +444,19 @@ fgdbm_clear(obj)
}
free(key.dptr);
}
+#else
+ 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);
+ }
+ }
+#endif
dbmp->di_size = 0;
return obj;
@@ -888,6 +891,7 @@ Init_gdbm()
{
cGDBM = rb_define_class("GDBM", rb_cObject);
rb_eGDBMError = rb_define_class("GDBMError", rb_eStandardError);
+ rb_eGDBMFatalError = rb_define_class("GDBMFatalError", rb_eException);
rb_include_module(cGDBM, rb_mEnumerable);
rb_define_singleton_method(cGDBM, "new", fgdbm_s_new, -1);
diff --git a/ext/gdbm/testgdbm.rb b/ext/gdbm/testgdbm.rb
new file mode 100644
index 0000000..06f598c
--- /dev/null
+++ b/ext/gdbm/testgdbm.rb
@@ -0,0 +1,643 @@
+require 'runit/testcase'
+require 'runit/cui/testrunner'
+
+if $".grep(/\bgdbm.so\b/).empty?
+ begin
+ require './gdbm'
+ rescue LoadError
+ require 'gdbm'
+ end
+end
+
+def uname_s
+ require 'rbconfig'
+ case Config::CONFIG['host_os']
+ when 'cygwin'
+ require 'Win32API'
+ uname = Win32API.new 'cygwin1', 'uname', 'P', 'I'
+ utsname = ' ' * 100
+ raise 'cannot get system name' if uname.call(utsname) == -1
+
+ utsname.unpack('A20' * 5)[0]
+ else
+ Config::CONFIG['host_os']
+ end
+end
+
+SYSTEM = uname_s
+
+class TestGDBM < RUNIT::TestCase
+ def setup
+ @path = "tmptest_gdbm_"
+ assert_instance_of(GDBM, @gdbm = GDBM.new(@path))
+
+ # prepare to make readonly GDBM file
+ GDBM.open("tmptest_gdbm_rdonly", 0400) {|gdbm|
+ gdbm['foo'] = 'FOO'
+ }
+ assert_instance_of(GDBM, @gdbm_rdonly = GDBM.new("tmptest_gdbm_rdonly", nil))
+ end
+ def teardown
+ assert_nil(@gdbm.close)
+ assert_nil(@gdbm_rdonly.close)
+ GC.start
+ File.delete *Dir.glob("tmptest_gdbm*").to_a
+ p Dir.glob("tmptest_gdbm*") if $DEBUG
+ end
+
+ def check_size(expect, gdbm=@gdbm)
+ assert_equals(expect, gdbm.size)
+ n = 0
+ gdbm.each { n+=1 }
+ assert_equals(expect, n)
+ if expect == 0
+ assert_equals(true, gdbm.empty?)
+ else
+ assert_equals(false, gdbm.empty?)
+ end
+ end
+
+ def test_version
+ STDERR.print GDBM::VERSION
+ end
+
+ def test_s_new_has_no_block
+ # GDBM.new ignore the block
+ foo = true
+ assert_instance_of(GDBM, gdbm = GDBM.new("tmptest_gdbm") { foo = false })
+ assert_equals(foo, true)
+ assert_nil(gdbm.close)
+ end
+ def test_s_open_create_new
+ return if /^CYGWIN_9/ =~ SYSTEM
+
+ save_mask = File.umask(0)
+ begin
+ assert_instance_of(GDBM, gdbm = GDBM.open("tmptest_gdbm"))
+ gdbm.close
+ assert_equals(File.stat("tmptest_gdbm").mode & 0777, 0666)
+ assert_instance_of(GDBM, gdbm = GDBM.open("tmptest_gdbm2", 0644))
+ gdbm.close
+ assert_equals(File.stat("tmptest_gdbm2").mode & 0777, 0644)
+ ensure
+ File.umask save_mask
+ end
+ end
+ def test_s_open_no_create
+ # this test is failed on libgdbm 1.8.0
+ assert_nil(gdbm = GDBM.open("tmptest_gdbm", nil))
+ ensure
+ gdbm.close if gdbm
+ end
+ def test_s_open_3rd_arg
+ assert_instance_of(GDBM, gdbm = GDBM.open("tmptest_gdbm", 0644,
+ GDBM::FAST))
+ gdbm.close
+
+ # gdbm 1.8.0 specific
+ if defined? GDBM::SYNC
+ assert_instance_of(GDBM, gdbm = GDBM.open("tmptest_gdbm", 0644,
+ GDBM::SYNC))
+ gdbm.close
+ end
+ # gdbm 1.8.0 specific
+ if defined? GDBM::NOLOCK
+ assert_instance_of(GDBM, gdbm = GDBM.open("tmptest_gdbm", 0644,
+ GDBM::NOLOCK))
+ gdbm.close
+ end
+ end
+ def test_s_open_with_block
+ assert_equals(GDBM.open("tmptest_gdbm") { :foo }, :foo)
+ end
+ def test_s_open_lock
+ fork() {
+ assert_instance_of(GDBM, gdbm = GDBM.open("tmptest_gdbm", 0644))
+ sleep 2
+ }
+ begin
+ sleep 1
+ assert_exception(Errno::EWOULDBLOCK) {
+ begin
+ assert_instance_of(GDBM, gdbm2 = GDBM.open("tmptest_gdbm", 0644))
+ rescue Errno::EAGAIN, Errno::EACCES
+ raise Errno::EWOULDBLOCK
+ end
+ }
+ ensure
+ Process.wait
+ end
+ end
+
+=begin
+ # Is it guaranteed on many OS?
+ def test_s_open_lock_one_process
+ # locking on one process
+ assert_instance_of(GDBM, gdbm = GDBM.open("tmptest_gdbm", 0644))
+ assert_exception(Errno::EWOULDBLOCK) {
+ begin
+ GDBM.open("tmptest_gdbm", 0644)
+ rescue Errno::EAGAIN
+ raise Errno::EWOULDBLOCK
+ end
+ }
+ end
+=end
+
+ def test_s_open_nolock
+ # gdbm 1.8.0 specific
+ if not defined? GDBM::NOLOCK
+ return
+ end
+
+ fork() {
+ assert_instance_of(GDBM, gdbm = GDBM.open("tmptest_gdbm", 0644,
+ GDBM::NOLOCK))
+ sleep 2
+ }
+ sleep 1
+ begin
+ gdbm2 = nil
+ assert_no_exception(Errno::EWOULDBLOCK, Errno::EAGAIN, Errno::EACCES) {
+ assert_instance_of(GDBM, gdbm2 = GDBM.open("tmptest_gdbm", 0644))
+ }
+ ensure
+ Process.wait
+ gdbm2.close if gdbm2
+ end
+
+ p Dir.glob("tmptest_gdbm*") if $DEBUG
+
+ fork() {
+ assert_instance_of(GDBM, gdbm = GDBM.open("tmptest_gdbm", 0644))
+ sleep 2
+ }
+ begin
+ sleep 1
+ gdbm2 = nil
+ assert_no_exception(Errno::EWOULDBLOCK, Errno::EAGAIN, Errno::EACCES) {
+ # this test is failed on Cygwin98 (???)
+ assert_instance_of(GDBM, gdbm2 = GDBM.open("tmptest_gdbm", 0644,
+ GDBM::NOLOCK))
+ }
+ ensure
+ Process.wait
+ gdbm2.close if gdbm2
+ end
+ end
+
+ def test_s_open_error
+ assert_instance_of(GDBM, gdbm = GDBM.open("tmptest_gdbm", 0))
+ assert_exception(Errno::EACCES) {
+ GDBM.open("tmptest_gdbm", 0)
+ }
+ gdbm.close
+ end
+
+ def test_close
+ assert_instance_of(GDBM, gdbm = GDBM.open("tmptest_gdbm"))
+ assert_nil(gdbm.close)
+
+ # closed GDBM file
+ assert_exception(RuntimeError) { gdbm.close }
+ end
+
+ def test_aref
+ assert_equals('bar', @gdbm['foo'] = 'bar')
+ assert_equals('bar', @gdbm['foo'])
+
+ assert_nil(@gdbm['bar'])
+ end
+
+ def test_fetch
+ assert_equals('bar', @gdbm['foo']='bar')
+ assert_equals('bar', @gdbm.fetch('foo'))
+
+ # key not found
+ assert_exception(IndexError) {
+ @gdbm.fetch('bar')
+ }
+
+ # test for `ifnone' arg
+ assert_equals('baz', @gdbm.fetch('bar', 'baz'))
+
+ # test for `ifnone' block
+ assert_equals('foobar', @gdbm.fetch('bar') {|key| 'foo' + key })
+ end
+
+ def test_aset
+ num = 0
+ 2.times {|i|
+ assert_equals('foo', @gdbm['foo'] = 'foo')
+ assert_equals('foo', @gdbm['foo'])
+ assert_equals('bar', @gdbm['foo'] = 'bar')
+ assert_equals('bar', @gdbm['foo'])
+
+ num += 1 if i == 0
+ assert_equals(num, @gdbm.size)
+
+ # assign nil
+ assert_equals('', @gdbm['bar'] = '')
+ assert_equals('', @gdbm['bar'])
+
+ num += 1 if i == 0
+ assert_equals(num, @gdbm.size)
+
+ # empty string
+ assert_equals('', @gdbm[''] = '')
+ assert_equals('', @gdbm[''])
+
+ num += 1 if i == 0
+ assert_equals(num, @gdbm.size)
+
+ # Fixnum
+ assert_equals('200', @gdbm['100'] = '200')
+ assert_equals('200', @gdbm['100'])
+
+ num += 1 if i == 0
+ assert_equals(num, @gdbm.size)
+
+ # Big key and value
+ assert_equals('y' * 100, @gdbm['x' * 100] = 'y' * 100)
+ assert_equals('y' * 100, @gdbm['x' * 100])
+
+ num += 1 if i == 0
+ assert_equals(num, @gdbm.size)
+ }
+ end
+
+ def test_index
+ assert_equals('bar', @gdbm['foo'] = 'bar')
+ assert_equals('foo', @gdbm.index('bar'))
+ assert_nil(@gdbm['bar'])
+ end
+
+ def test_indexes
+ keys = %w(foo bar baz)
+ values = %w(FOO BAR BAZ)
+ @gdbm[keys[0]], @gdbm[keys[1]], @gdbm[keys[2]] = values
+ assert_equals(values.reverse, @gdbm.indexes(*keys.reverse))
+ end
+
+ def test_length
+ num = 10
+ assert_equals(0, @gdbm.size)
+ num.times {|i|
+ i = i.to_s
+ @gdbm[i] = i
+ }
+ assert_equals(num, @gdbm.size)
+
+ @gdbm.shift
+
+ assert_equals(num - 1, @gdbm.size)
+ end
+
+ def test_empty?
+ assert_equals(true, @gdbm.empty?)
+ @gdbm['foo'] = 'FOO'
+ assert_equals(false, @gdbm.empty?)
+ end
+
+ def test_each_pair
+ n = 0
+ @gdbm.each_pair { n += 1 }
+ assert_equals(0, n)
+
+ keys = %w(foo bar baz)
+ values = %w(FOO BAR BAZ)
+
+ @gdbm[keys[0]], @gdbm[keys[1]], @gdbm[keys[2]] = values
+
+ n = 0
+ ret = @gdbm.each_pair {|key, val|
+ assert_not_nil(i = keys.index(key))
+ assert_equals(val, values[i])
+
+ n += 1
+ }
+ assert_equals(keys.size, n)
+ assert_equals(@gdbm, ret)
+ end
+
+ def test_each_value
+ n = 0
+ @gdbm.each_value { n += 1 }
+ assert_equals(0, n)
+
+ keys = %w(foo bar baz)
+ values = %w(FOO BAR BAZ)
+
+ @gdbm[keys[0]], @gdbm[keys[1]], @gdbm[keys[2]] = values
+
+ n = 0
+ ret = @gdbm.each_value {|val|
+ assert_not_nil(key = @gdbm.index(val))
+ assert_not_nil(i = keys.index(key))
+ assert_equals(val, values[i])
+
+ n += 1
+ }
+ assert_equals(keys.size, n)
+ assert_equals(@gdbm, ret)
+ end
+
+ def test_each_key
+ n = 0
+ @gdbm.each_key { n += 1 }
+ assert_equals(0, n)
+
+ keys = %w(foo bar baz)
+ values = %w(FOO BAR BAZ)
+
+ @gdbm[keys[0]], @gdbm[keys[1]], @gdbm[keys[2]] = values
+
+ n = 0
+ ret = @gdbm.each_key {|key|
+ assert_not_nil(i = keys.index(key))
+ assert_equals(@gdbm[key], values[i])
+
+ n += 1
+ }
+ assert_equals(keys.size, n)
+ assert_equals(@gdbm, ret)
+ end
+
+ def test_keys
+ assert_equals([], @gdbm.keys)
+
+ keys = %w(foo bar baz)
+ values = %w(FOO BAR BAZ)
+
+ @gdbm[keys[0]], @gdbm[keys[1]], @gdbm[keys[2]] = values
+
+ assert_equals(keys.sort, @gdbm.keys.sort)
+ assert_equals(values.sort, @gdbm.values.sort)
+ end
+
+ def test_values
+ test_keys
+ end
+
+ def test_shift
+ assert_nil(@gdbm.shift)
+ assert_equals(0, @gdbm.size)
+
+ keys = %w(foo bar baz)
+ values = %w(FOO BAR BAZ)
+
+ @gdbm[keys[0]], @gdbm[keys[1]], @gdbm[keys[2]] = values
+
+ ret_keys = []
+ ret_values = []
+ while ret = @gdbm.shift
+ ret_keys.push ret[0]
+ ret_values.push ret[1]
+
+ assert_equals(keys.size - ret_keys.size, @gdbm.size)
+ end
+
+ assert_equals(keys.sort, ret_keys.sort)
+ assert_equals(values.sort, ret_values.sort)
+ end
+
+ def test_delete
+ keys = %w(foo bar baz)
+ values = %w(FOO BAR BAZ)
+ key = keys[1]
+
+ assert_nil(@gdbm.delete(key))
+ assert_equals(0, @gdbm.size)
+
+ @gdbm[keys[0]], @gdbm[keys[1]], @gdbm[keys[2]] = values
+
+ assert_equals(@gdbm, @gdbm.delete(key))
+ assert_nil(@gdbm[key])
+ assert_equals(2, @gdbm.size)
+
+ assert_nil(@gdbm.delete(key))
+
+ if /^CYGWIN_9/ !~ SYSTEM
+ assert_exception(GDBMError) {
+ @gdbm_rdonly.delete("foo")
+ }
+
+ assert_nil(@gdbm_rdonly.delete("bar"))
+ end
+ end
+ def test_delete_with_block
+ key = 'no called block'
+ @gdbm[key] = 'foo'
+ assert_equals(@gdbm, @gdbm.delete(key) {|k| k.replace 'called block'})
+ assert_equals('no called block', key)
+ assert_equals(0, @gdbm.size)
+
+ key = 'no called block'
+ assert_nil(@gdbm.delete(key) {|k| k.replace 'called block'})
+ assert_equals('called block', key)
+ assert_equals(0, @gdbm.size)
+ end
+
+ def test_delete_if
+ v = "0"
+ 100.times {@gdbm[v] = v; v = v.next}
+
+ ret = @gdbm.delete_if {|key, val| key.to_i < 50}
+ assert_equals(@gdbm, ret)
+ check_size(50, @gdbm)
+
+ ret = @gdbm.delete_if {|key, val| key.to_i >= 50}
+ assert_equals(@gdbm, ret)
+ check_size(0, @gdbm)
+
+ # break
+ v = "0"
+ 100.times {@gdbm[v] = v; v = v.next}
+ check_size(100, @gdbm)
+ n = 0;
+ @gdbm.delete_if {|key, val|
+ break if n > 50
+ n+=1
+ true
+ }
+ assert_equals(51, n)
+ check_size(49, @gdbm)
+
+ @gdbm.clear
+
+ # raise
+ v = "0"
+ 100.times {@gdbm[v] = v; v = v.next}
+ check_size(100, @gdbm)
+ n = 0;
+ begin
+ @gdbm.delete_if {|key, val|
+ raise "runtime error" if n > 50
+ n+=1
+ true
+ }
+ rescue
+ end
+ assert_equals(51, n)
+ check_size(49, @gdbm)
+ end
+
+ def test_reject
+ v = "0"
+ 100.times {@gdbm[v] = v; v = v.next}
+
+ hash = @gdbm.reject {|key, val| key.to_i < 50}
+ assert_instance_of(Hash, hash)
+ assert_equals(100, @gdbm.size)
+
+ assert_equals(50, hash.size)
+ hash.each_pair {|key,val|
+ assert_equals(false, key.to_i < 50)
+ assert_equals(key, val)
+ }
+
+ hash = @gdbm.reject {|key, val| key.to_i < 100}
+ assert_instance_of(Hash, hash)
+ assert_equals(true, hash.empty?)
+ end
+
+ def test_clear
+ v = "1"
+ 100.times {v = v.next; @gdbm[v] = v}
+
+ assert_equals(@gdbm, @gdbm.clear)
+
+ # validate GDBM#size
+ i = 0
+ @gdbm.each { i += 1 }
+ assert_equals(@gdbm.size, i)
+ assert_equals(0, i)
+ end
+
+ def test_invert
+ v = "0"
+ 100.times {@gdbm[v] = v; v = v.next}
+
+ hash = @gdbm.invert
+ assert_instance_of(Hash, hash)
+ assert_equals(100, hash.size)
+ hash.each_pair {|key, val|
+ assert_equals(key.to_i, val.to_i)
+ }
+ end
+
+ def test_update
+ hash = {}
+ v = "0"
+ 100.times {v = v.next; hash[v] = v}
+
+ @gdbm["101"] = "101"
+ @gdbm.update hash
+ assert_equals(101, @gdbm.size)
+ @gdbm.each_pair {|key, val|
+ assert_equals(key.to_i, val.to_i)
+ }
+ end
+
+ def test_replace
+ hash = {}
+ v = "0"
+ 100.times {v = v.next; hash[v] = v}
+
+ @gdbm["101"] = "101"
+ @gdbm.replace hash
+ assert_equals(100, @gdbm.size)
+ @gdbm.each_pair {|key, val|
+ assert_equals(key.to_i, val.to_i)
+ }
+ end
+
+ def test_reorganize
+ size1 = File.size(@path)
+ i = "1"
+ 1000.times {i = i.next; @gdbm[i] = i}
+ @gdbm.clear
+ @gdbm.sync
+
+ size2 = File.size(@path)
+ @gdbm.reorganize
+ size3 = File.size(@path)
+
+ # p [size1, size2, size3]
+ assert_equals(true, size1 < size2)
+ # this test is failed on Cygwin98. `GDBM version 1.8.0, as of May 19, 1999'
+ assert_equals(true, size3 < size2)
+ assert_equals(size1, size3)
+ end
+
+ def test_sync
+ assert_instance_of(GDBM, gdbm = GDBM.open('tmptest_gdbm', 0666, GDBM::FAST))
+ assert_equals(gdbm.sync, gdbm)
+ gdbm.close
+ assert_instance_of(GDBM, gdbm = GDBM.open('tmptest_gdbm', 0666))
+ assert_equals(gdbm.sync, gdbm)
+ gdbm.close
+ end
+
+ def test_cachesize=
+ assert_equals(@gdbm.cachesize = 1024, 1024)
+ end
+
+ def test_fastmode=
+ assert_equals(@gdbm.fastmode = true, true)
+ end
+
+ def test_syncmode=
+ assert_equals(@gdbm.syncmode = true, true)
+ end
+
+ def test_haskey?
+ assert_equals('bar', @gdbm['foo']='bar')
+ assert_equals(true, @gdbm.has_key?('foo'))
+ assert_equals(false, @gdbm.has_key?('bar'))
+ end
+
+ def test_has_value?
+ assert_equals('bar', @gdbm['foo']='bar')
+ assert_equals(true, @gdbm.has_value?('bar'))
+ assert_equals(false, @gdbm.has_value?('foo'))
+ end
+
+ def test_to_a
+ v = "0"
+ 100.times {v = v.next; @gdbm[v] = v}
+
+ ary = @gdbm.to_a
+ assert_instance_of(Array, ary)
+ assert_equals(100, ary.size)
+ ary.each {|key,val|
+ assert_equals(key.to_i, val.to_i)
+ }
+ end
+
+ def test_to_hash
+ v = "0"
+ 100.times {v = v.next; @gdbm[v] = v}
+
+ hash = @gdbm.to_hash
+ assert_instance_of(Hash, hash)
+ assert_equals(100, hash.size)
+ hash.each {|key,val|
+ assert_equals(key.to_i, val.to_i)
+ }
+ end
+end
+
+if $0 == __FILE__
+ if ARGV.size == 0
+ suite = RUNIT::TestSuite.new
+ suite.add_test(TestGDBM.suite)
+ else
+ suite = RUNIT::TestSuite.new
+ ARGV.each do |testmethod|
+ suite.add_test(TestGDBM.new(testmethod))
+ end
+ end
+
+ RUNIT::CUI::TestRunner.run(suite)
+end
diff --git a/ext/nkf/nkf.c b/ext/nkf/nkf.c
index b59688c..58daad1 100644
--- a/ext/nkf/nkf.c
+++ b/ext/nkf/nkf.c
@@ -47,13 +47,13 @@ static VALUE
rb_nkf_kconv(obj, opt, src)
VALUE obj, opt, src;
{
- int i;
char *opt_ptr, *opt_end;
volatile VALUE v;
reinit();
- opt_ptr = str2cstr(opt, &i);
- opt_end = opt_ptr + i;
+ StringValue(opt);
+ opt_ptr = RSTRING(opt)->ptr;
+ opt_end = opt_ptr + RSTRING(opt)->len;
for (; opt_ptr < opt_end; opt_ptr++) {
if (*opt_ptr != '-') {
continue;
@@ -64,7 +64,9 @@ rb_nkf_kconv(obj, opt, src)
incsize = INCSIZE;
input_ctr = 0;
- input = str2cstr(src, &i_len);
+ StringValue(src);
+ input = RSTRING(src)->ptr;
+ i_len = RSTRING(src)->len;
dst = rb_str_new(0, i_len*3 + 10);
v = dst;
@@ -96,13 +98,11 @@ rb_nkf_guess(obj, src)
{
unsigned char *p;
unsigned char *pend;
- int plen;
int sequence_counter = 0;
- Check_Type(src, T_STRING);
-
- p = str2cstr(src, &plen);
- pend = p + plen;
+ StringValue(src);
+ p = RSTRING(src)->ptr;
+ pend = p + RSTRING(src)->len;
#define INCR do {\
p++;\
diff --git a/ext/pty/pty.c b/ext/pty/pty.c
index 6690741..12063f9 100644
--- a/ext/pty/pty.c
+++ b/ext/pty/pty.c
@@ -452,7 +452,7 @@ pty_getpty(self, shell)
wfptr->f = fdopen(dup(info.fd), "w");
wfptr->path = strdup(RSTRING(shell)->ptr);
- res = rb_ary_new2(2);
+ res = rb_ary_new2(3);
rb_ary_store(res,0,(VALUE)rport);
rb_ary_store(res,1,(VALUE)wport);
rb_ary_store(res,2,INT2FIX(info.child_pid));
diff --git a/ext/readline/extconf.rb b/ext/readline/extconf.rb
index 7db6274..431ed21 100644
--- a/ext/readline/extconf.rb
+++ b/ext/readline/extconf.rb
@@ -9,5 +9,8 @@ have_library("ncurses", "tgetnum") or
if have_header("readline/readline.h") and
have_header("readline/history.h") and
have_library("readline", "readline")
+ if have_func("rl_filename_completion_function")
+ $CFLAGS += "-DREADLINE_42_OR_LATER"
+ end
create_makefile("readline")
end
diff --git a/ext/readline/readline.c b/ext/readline/readline.c
index 02b2979..765a002 100644
--- a/ext/readline/readline.c
+++ b/ext/readline/readline.c
@@ -1,5 +1,5 @@
/* readline.c -- GNU Readline module
- Copyright (C) 1997-1998 Shugo Maeda */
+ Copyright (C) 1997-2001 Shugo Maeda */
#include <stdio.h>
#include <readline/readline.h>
@@ -15,6 +15,11 @@ static VALUE mReadline;
#define COMPLETION_PROC "completion_proc"
#define COMPLETION_CASE_FOLD "completion_case_fold"
+#ifndef READLINE_42_OR_LATER
+# define rl_filename_completion_function filename_completion_function
+# define rl_username_completion_function username_completion_function
+#endif
+
static int
readline_event()
{
@@ -33,7 +38,7 @@ readline_readline(argc, argv, self)
char *buff;
if (rb_scan_args(argc, argv, "02", &tmp, &add_hist) > 0) {
- prompt = STR2CSTR(tmp);
+ prompt = StringValuePtr(tmp);
}
buff = readline(prompt);
if (RTEST(add_hist) && buff) {
@@ -190,6 +195,7 @@ hist_set(self, index, str)
VALUE str;
{
HISTORY_STATE *state;
+ VALUE s = str;
int i;
state = history_get_history_state();
@@ -197,7 +203,7 @@ hist_set(self, index, str)
if (i < 0 || i > state->length - 1) {
rb_raise(rb_eIndexError, "Invalid index");
}
- replace_history_entry(i, STR2CSTR(str), NULL);
+ replace_history_entry(i, StringValuePtr(s), NULL);
return str;
}
@@ -206,7 +212,7 @@ hist_push(self, str)
VALUE self;
VALUE str;
{
- add_history(STR2CSTR(str));
+ add_history(StringValuePtr(str));
return self;
}
@@ -220,7 +226,7 @@ hist_push_method(argc, argv, self)
while (argc--) {
str = *argv++;
- add_history(STR2CSTR(str));
+ add_history(StringValuePtr(str));
}
return self;
}
@@ -321,8 +327,8 @@ filename_completion_proc_call(self, str)
char **matches;
int i;
- matches = completion_matches(STR2CSTR(str),
- filename_completion_function);
+ matches = completion_matches(StringValuePtr(str),
+ rl_filename_completion_function);
if (matches) {
result = rb_ary_new();
for (i = 0; matches[i]; i++) {
@@ -348,8 +354,8 @@ username_completion_proc_call(self, str)
char **matches;
int i;
- matches = completion_matches(STR2CSTR(str),
- username_completion_function);
+ matches = completion_matches(StringValuePtr(str),
+ rl_username_completion_function);
if (matches) {
result = rb_ary_new();
for (i = 0; matches[i]; i++) {
diff --git a/ext/sdbm/init.c b/ext/sdbm/init.c
index d6cda91..507fae6 100644
--- a/ext/sdbm/init.c
+++ b/ext/sdbm/init.c
@@ -16,7 +16,7 @@
#include <fcntl.h>
#include <errno.h>
-VALUE cSDBM;
+static VALUE cSDBM;
struct dbmdata {
int di_size;
@@ -44,16 +44,28 @@ free_sdbm(dbmp)
}
static VALUE
-fsdbm_s_open(argc, argv, klass)
+fsdbm_close(obj)
+ VALUE obj;
+{
+ struct dbmdata *dbmp;
+
+ GetDBM(obj, dbmp);
+ sdbm_close(dbmp->di_dbm);
+ dbmp->di_dbm = 0;
+
+ return Qnil;
+}
+
+static VALUE
+fsdbm_initialize(argc, argv, obj)
int argc;
VALUE *argv;
- VALUE klass;
+ VALUE obj;
{
VALUE file, vmode;
DBM *dbm;
struct dbmdata *dbmp;
int mode;
- VALUE obj;
if (rb_scan_args(argc, argv, "11", &file, &vmode) == 1) {
mode = 0666; /* default value */
@@ -64,7 +76,7 @@ fsdbm_s_open(argc, argv, klass)
else {
mode = NUM2INT(vmode);
}
- Check_SafeStr(file);
+ SafeStringValue(file);
dbm = 0;
if (mode >= 0)
@@ -79,7 +91,8 @@ fsdbm_s_open(argc, argv, klass)
rb_sys_fail(RSTRING(file)->ptr);
}
- obj = Data_Make_Struct(klass,struct dbmdata,0,free_sdbm,dbmp);
+ dbmp = ALLOC(struct dbmdata);
+ DATA_PTR(obj) = dbmp;
dbmp->di_dbm = dbm;
dbmp->di_size = -1;
@@ -87,16 +100,33 @@ fsdbm_s_open(argc, argv, klass)
}
static VALUE
-fsdbm_close(obj)
- VALUE obj;
+fsdbm_s_new(argc, argv, klass)
+ int argc;
+ VALUE *argv;
+ VALUE klass;
{
- struct dbmdata *dbmp;
+ VALUE obj = Data_Wrap_Struct(klass, 0, free_sdbm, 0);
+ rb_obj_call_init(obj, argc, argv);
+ return obj;
+}
- GetDBM(obj, dbmp);
- sdbm_close(dbmp->di_dbm);
- dbmp->di_dbm = 0;
+static VALUE
+fsdbm_s_open(argc, argv, klass)
+ int argc;
+ VALUE *argv;
+ VALUE klass;
+{
+ VALUE obj = Data_Wrap_Struct(klass, 0, free_sdbm, 0);
- return Qnil;
+ if (NIL_P(fsdbm_initialize(argc, argv, obj))) {
+ return Qnil;
+ }
+
+ if (rb_block_given_p()) {
+ return rb_ensure(rb_yield, obj, fsdbm_close, obj);
+ }
+
+ return obj;
}
static VALUE
@@ -107,7 +137,7 @@ fsdbm_fetch(obj, keystr, ifnone)
struct dbmdata *dbmp;
DBM *dbm;
- Check_Type(keystr, T_STRING);
+ StringValue(keystr);
key.dptr = RSTRING(keystr)->ptr;
key.dsize = RSTRING(keystr)->len;
@@ -135,10 +165,14 @@ fsdbm_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 fsdbm_fetch(obj, keystr, ifnone);
+ valstr = fsdbm_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
@@ -149,7 +183,7 @@ fsdbm_index(obj, valstr)
struct dbmdata *dbmp;
DBM *dbm;
- Check_Type(valstr, T_STRING);
+ StringValue(valstr);
val.dptr = RSTRING(valstr)->ptr;
val.dsize = RSTRING(valstr)->len;
@@ -190,12 +224,13 @@ fsdbm_delete(obj, keystr)
DBM *dbm;
rb_secure(4);
- Check_Type(keystr, T_STRING);
+ StringValue(keystr);
key.dptr = RSTRING(keystr)->ptr;
key.dsize = RSTRING(keystr)->len;
GetDBM(obj, dbmp);
dbm = dbmp->di_dbm;
+ dbmp->di_size = -1;
value = sdbm_fetch(dbm, key);
if (value.dptr == 0) {
@@ -229,10 +264,13 @@ fsdbm_shift(obj)
key = sdbm_firstkey(dbm);
if (!key.dptr) return Qnil;
val = sdbm_fetch(dbm, key);
- sdbm_delete(dbm, key);
-
keystr = rb_tainted_str_new(key.dptr, key.dsize);
valstr = rb_tainted_str_new(val.dptr, val.dsize);
+ sdbm_delete(dbm, key);
+ if (dbmp->di_size >= 0) {
+ dbmp->di_size--;
+ }
+
return rb_assoc_new(keystr, valstr);
}
@@ -244,20 +282,34 @@ fsdbm_delete_if(obj)
struct dbmdata *dbmp;
DBM *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;
+ n = dbmp->di_size;
+ dbmp->di_size = -1;
for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) {
val = sdbm_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 (sdbm_delete(dbm, key)) {
- rb_raise(rb_eRuntimeError, "sdbm_delete failed");
- }
+ ret = rb_protect(rb_yield, rb_assoc_new(rb_str_dup(keystr), valstr), &status);
+ if (status != 0) break;
+ if (RTEST(ret)) rb_ary_push(ary, keystr);
+ }
+
+ for (i = 0; i < RARRAY(ary)->len; i++) {
+ keystr = RARRAY(ary)->ptr[i];
+ key.dptr = RSTRING(keystr)->ptr;
+ key.dsize = RSTRING(keystr)->len;
+ if (sdbm_delete(dbm, key)) {
+ rb_raise(rb_eRuntimeError, "sdbm_delete failed");
}
}
+ if (status) rb_jump_tag(status);
+ if (n > 0) dbmp->di_size = n - RARRAY(ary)->len;
+
return obj;
}
@@ -273,11 +325,13 @@ fsdbm_clear(obj)
GetDBM(obj, dbmp);
dbm = dbmp->di_dbm;
dbmp->di_size = -1;
- for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) {
+ while (key = sdbm_firstkey(dbm), key.dptr) {
if (sdbm_delete(dbm, key)) {
rb_raise(rb_eRuntimeError, "sdbm_delete failed");
}
}
+ dbmp->di_size = 0;
+
return obj;
}
@@ -299,7 +353,7 @@ fsdbm_invert(obj)
valstr = rb_tainted_str_new(val.dptr, val.dsize);
rb_hash_aset(hash, valstr, keystr);
}
- return obj;
+ return hash;
}
static VALUE
@@ -528,7 +582,7 @@ fsdbm_has_key(obj, keystr)
struct dbmdata *dbmp;
DBM *dbm;
- Check_Type(keystr, T_STRING);
+ StringValue(keystr);
key.dptr = RSTRING(keystr)->ptr;
key.dsize = RSTRING(keystr)->len;
@@ -547,7 +601,7 @@ fsdbm_has_value(obj, valstr)
struct dbmdata *dbmp;
DBM *dbm;
- Check_Type(valstr, T_STRING);
+ StringValue(valstr);
val.dptr = RSTRING(valstr)->ptr;
val.dsize = RSTRING(valstr)->len;
@@ -620,7 +674,8 @@ Init_sdbm()
rb_include_module(cSDBM, rb_mEnumerable);
rb_define_singleton_method(cSDBM, "open", fsdbm_s_open, -1);
- rb_define_singleton_method(cSDBM, "new", fsdbm_s_open, -1);
+ rb_define_singleton_method(cSDBM, "new", fsdbm_s_new, -1);
+ rb_define_method(cSDBM, "initialize", fsdbm_initialize, -1);
rb_define_method(cSDBM, "close", fsdbm_close, 0);
rb_define_method(cSDBM, "[]", fsdbm_aref, 1);
rb_define_method(cSDBM, "fetch", fsdbm_fetch_m, -1);
@@ -638,7 +693,7 @@ Init_sdbm()
rb_define_method(cSDBM, "each_pair", fsdbm_each_pair, 0);
rb_define_method(cSDBM, "keys", fsdbm_keys, 0);
rb_define_method(cSDBM, "values", fsdbm_values, 0);
- rb_define_method(cSDBM, "shift", fsdbm_shift, 1);
+ rb_define_method(cSDBM, "shift", fsdbm_shift, 0);
rb_define_method(cSDBM, "delete", fsdbm_delete, 1);
rb_define_method(cSDBM, "delete_if", fsdbm_delete_if, 0);
rb_define_method(cSDBM, "reject!", fsdbm_delete_if, 0);
diff --git a/ext/sdbm/testsdbm.rb b/ext/sdbm/testsdbm.rb
new file mode 100644
index 0000000..2cea1e4
--- /dev/null
+++ b/ext/sdbm/testsdbm.rb
@@ -0,0 +1,536 @@
+require 'runit/testcase'
+require 'runit/cui/testrunner'
+
+if $".grep(/\bsdbm.so\b/).empty?
+ begin
+ require './sdbm'
+ rescue LoadError
+ require 'sdbm'
+ end
+end
+
+def uname_s
+ require 'rbconfig'
+ case Config::CONFIG['host_os']
+ when 'cygwin'
+ require 'Win32API'
+ uname = Win32API.new 'cygwin1', 'uname', 'P', 'I'
+ utsname = ' ' * 100
+ raise 'cannot get system name' if uname.call(utsname) == -1
+
+ utsname.unpack('A20' * 5)[0]
+ else
+ Config::CONFIG['host_os']
+ end
+end
+
+SYSTEM = uname_s
+
+class TestSDBM < RUNIT::TestCase
+ def setup
+ @path = "tmptest_sdbm_"
+ assert_instance_of(SDBM, @sdbm = SDBM.new(@path))
+ end
+ def teardown
+ assert_nil(@sdbm.close)
+ GC.start
+ File.delete *Dir.glob("tmptest_sdbm*").to_a
+ p Dir.glob("tmptest_sdbm*") if $DEBUG
+ end
+
+ def check_size(expect, sdbm=@sdbm)
+ assert_equals(expect, sdbm.size)
+ n = 0
+ sdbm.each { n+=1 }
+ assert_equals(expect, n)
+ if expect == 0
+ assert_equals(true, sdbm.empty?)
+ else
+ assert_equals(false, sdbm.empty?)
+ end
+ end
+
+ def test_version
+ STDERR.print SDBM::VERSION
+ end
+
+ def test_s_new_has_no_block
+ # SDBM.new ignore the block
+ foo = true
+ assert_instance_of(SDBM, sdbm = SDBM.new("tmptest_sdbm") { foo = false })
+ assert_equals(foo, true)
+ assert_nil(sdbm.close)
+ end
+ def test_s_open_no_create
+ assert_nil(sdbm = SDBM.open("tmptest_sdbm", nil))
+ ensure
+ sdbm.close if sdbm
+ end
+ def test_s_open_with_block
+ assert_equals(SDBM.open("tmptest_sdbm") { :foo }, :foo)
+ end
+=begin
+ # Is it guaranteed on many OS?
+ def test_s_open_lock_one_process
+ # locking on one process
+ assert_instance_of(SDBM, sdbm = SDBM.open("tmptest_sdbm", 0644))
+ assert_exception(Errno::EWOULDBLOCK) {
+ begin
+ SDBM.open("tmptest_sdbm", 0644)
+ rescue Errno::EAGAIN
+ raise Errno::EWOULDBLOCK
+ end
+ }
+ end
+=end
+
+ def test_s_open_nolock
+ # sdbm 1.8.0 specific
+ if not defined? SDBM::NOLOCK
+ return
+ end
+
+ fork() {
+ assert_instance_of(SDBM, sdbm = SDBM.open("tmptest_sdbm", 0644,
+ SDBM::NOLOCK))
+ sleep 2
+ }
+ sleep 1
+ begin
+ sdbm2 = nil
+ assert_no_exception(Errno::EWOULDBLOCK, Errno::EAGAIN, Errno::EACCES) {
+ assert_instance_of(SDBM, sdbm2 = SDBM.open("tmptest_sdbm", 0644))
+ }
+ ensure
+ Process.wait
+ sdbm2.close if sdbm2
+ end
+
+ p Dir.glob("tmptest_sdbm*") if $DEBUG
+
+ fork() {
+ assert_instance_of(SDBM, sdbm = SDBM.open("tmptest_sdbm", 0644))
+ sleep 2
+ }
+ begin
+ sleep 1
+ sdbm2 = nil
+ assert_no_exception(Errno::EWOULDBLOCK, Errno::EAGAIN, Errno::EACCES) {
+ # this test is failed on Cygwin98 (???)
+ assert_instance_of(SDBM, sdbm2 = SDBM.open("tmptest_sdbm", 0644,
+ SDBM::NOLOCK))
+ }
+ ensure
+ Process.wait
+ sdbm2.close if sdbm2
+ end
+ end
+
+ def test_s_open_error
+ assert_instance_of(SDBM, sdbm = SDBM.open("tmptest_sdbm", 0))
+ assert_exception(Errno::EACCES) {
+ SDBM.open("tmptest_sdbm", 0)
+ }
+ sdbm.close
+ end
+
+ def test_close
+ assert_instance_of(SDBM, sdbm = SDBM.open("tmptest_sdbm"))
+ assert_nil(sdbm.close)
+
+ # closed SDBM file
+ assert_exception(RuntimeError) { sdbm.close }
+ end
+
+ def test_aref
+ assert_equals('bar', @sdbm['foo'] = 'bar')
+ assert_equals('bar', @sdbm['foo'])
+
+ assert_nil(@sdbm['bar'])
+ end
+
+ def test_fetch
+ assert_equals('bar', @sdbm['foo']='bar')
+ assert_equals('bar', @sdbm.fetch('foo'))
+
+ # key not found
+ assert_exception(IndexError) {
+ @sdbm.fetch('bar')
+ }
+
+ # test for `ifnone' arg
+ assert_equals('baz', @sdbm.fetch('bar', 'baz'))
+
+ # test for `ifnone' block
+ assert_equals('foobar', @sdbm.fetch('bar') {|key| 'foo' + key })
+ end
+
+ def test_aset
+ num = 0
+ 2.times {|i|
+ assert_equals('foo', @sdbm['foo'] = 'foo')
+ assert_equals('foo', @sdbm['foo'])
+ assert_equals('bar', @sdbm['foo'] = 'bar')
+ assert_equals('bar', @sdbm['foo'])
+
+ num += 1 if i == 0
+ assert_equals(num, @sdbm.size)
+
+ # assign nil
+ assert_equals('', @sdbm['bar'] = '')
+ assert_equals('', @sdbm['bar'])
+
+ num += 1 if i == 0
+ assert_equals(num, @sdbm.size)
+
+ # empty string
+ assert_equals('', @sdbm[''] = '')
+ assert_equals('', @sdbm[''])
+
+ num += 1 if i == 0
+ assert_equals(num, @sdbm.size)
+
+ # Fixnum
+ assert_equals('200', @sdbm['100'] = '200')
+ assert_equals('200', @sdbm['100'])
+
+ num += 1 if i == 0
+ assert_equals(num, @sdbm.size)
+
+ # Big key and value
+ assert_equals('y' * 100, @sdbm['x' * 100] = 'y' * 100)
+ assert_equals('y' * 100, @sdbm['x' * 100])
+
+ num += 1 if i == 0
+ assert_equals(num, @sdbm.size)
+ }
+ end
+
+ def test_index
+ assert_equals('bar', @sdbm['foo'] = 'bar')
+ assert_equals('foo', @sdbm.index('bar'))
+ assert_nil(@sdbm['bar'])
+ end
+
+ def test_indexes
+ keys = %w(foo bar baz)
+ values = %w(FOO BAR BAZ)
+ @sdbm[keys[0]], @sdbm[keys[1]], @sdbm[keys[2]] = values
+ assert_equals(values.reverse, @sdbm.indexes(*keys.reverse))
+ end
+
+ def test_length
+ num = 10
+ assert_equals(0, @sdbm.size)
+ num.times {|i|
+ i = i.to_s
+ @sdbm[i] = i
+ }
+ assert_equals(num, @sdbm.size)
+
+ @sdbm.shift
+
+ assert_equals(num - 1, @sdbm.size)
+ end
+
+ def test_empty?
+ assert_equals(true, @sdbm.empty?)
+ @sdbm['foo'] = 'FOO'
+ assert_equals(false, @sdbm.empty?)
+ end
+
+ def test_each_pair
+ n = 0
+ @sdbm.each_pair { n += 1 }
+ assert_equals(0, n)
+
+ keys = %w(foo bar baz)
+ values = %w(FOO BAR BAZ)
+
+ @sdbm[keys[0]], @sdbm[keys[1]], @sdbm[keys[2]] = values
+
+ n = 0
+ ret = @sdbm.each_pair {|key, val|
+ assert_not_nil(i = keys.index(key))
+ assert_equals(val, values[i])
+
+ n += 1
+ }
+ assert_equals(keys.size, n)
+ assert_equals(@sdbm, ret)
+ end
+
+ def test_each_value
+ n = 0
+ @sdbm.each_value { n += 1 }
+ assert_equals(0, n)
+
+ keys = %w(foo bar baz)
+ values = %w(FOO BAR BAZ)
+
+ @sdbm[keys[0]], @sdbm[keys[1]], @sdbm[keys[2]] = values
+
+ n = 0
+ ret = @sdbm.each_value {|val|
+ assert_not_nil(key = @sdbm.index(val))
+ assert_not_nil(i = keys.index(key))
+ assert_equals(val, values[i])
+
+ n += 1
+ }
+ assert_equals(keys.size, n)
+ assert_equals(@sdbm, ret)
+ end
+
+ def test_each_key
+ n = 0
+ @sdbm.each_key { n += 1 }
+ assert_equals(0, n)
+
+ keys = %w(foo bar baz)
+ values = %w(FOO BAR BAZ)
+
+ @sdbm[keys[0]], @sdbm[keys[1]], @sdbm[keys[2]] = values
+
+ n = 0
+ ret = @sdbm.each_key {|key|
+ assert_not_nil(i = keys.index(key))
+ assert_equals(@sdbm[key], values[i])
+
+ n += 1
+ }
+ assert_equals(keys.size, n)
+ assert_equals(@sdbm, ret)
+ end
+
+ def test_keys
+ assert_equals([], @sdbm.keys)
+
+ keys = %w(foo bar baz)
+ values = %w(FOO BAR BAZ)
+
+ @sdbm[keys[0]], @sdbm[keys[1]], @sdbm[keys[2]] = values
+
+ assert_equals(keys.sort, @sdbm.keys.sort)
+ assert_equals(values.sort, @sdbm.values.sort)
+ end
+
+ def test_values
+ test_keys
+ end
+
+ def test_shift
+ assert_nil(@sdbm.shift)
+ assert_equals(0, @sdbm.size)
+
+ keys = %w(foo bar baz)
+ values = %w(FOO BAR BAZ)
+
+ @sdbm[keys[0]], @sdbm[keys[1]], @sdbm[keys[2]] = values
+
+ ret_keys = []
+ ret_values = []
+ while ret = @sdbm.shift
+ ret_keys.push ret[0]
+ ret_values.push ret[1]
+
+ assert_equals(keys.size - ret_keys.size, @sdbm.size)
+ end
+
+ assert_equals(keys.sort, ret_keys.sort)
+ assert_equals(values.sort, ret_values.sort)
+ end
+
+ def test_delete
+ keys = %w(foo bar baz)
+ values = %w(FOO BAR BAZ)
+ key = keys[1]
+
+ assert_nil(@sdbm.delete(key))
+ assert_equals(0, @sdbm.size)
+
+ @sdbm[keys[0]], @sdbm[keys[1]], @sdbm[keys[2]] = values
+
+ assert_equals(@sdbm, @sdbm.delete(key))
+ assert_nil(@sdbm[key])
+ assert_equals(2, @sdbm.size)
+
+ assert_nil(@sdbm.delete(key))
+ end
+ def test_delete_with_block
+ key = 'no called block'
+ @sdbm[key] = 'foo'
+ assert_equals(@sdbm, @sdbm.delete(key) {|k| k.replace 'called block'})
+ assert_equals('no called block', key)
+ assert_equals(0, @sdbm.size)
+
+ key = 'no called block'
+ assert_nil(@sdbm.delete(key) {|k| k.replace 'called block'})
+ assert_equals('called block', key)
+ assert_equals(0, @sdbm.size)
+ end
+
+ def test_delete_if
+ v = "0"
+ 100.times {@sdbm[v] = v; v = v.next}
+
+ ret = @sdbm.delete_if {|key, val| key.to_i < 50}
+ assert_equals(@sdbm, ret)
+ check_size(50, @sdbm)
+
+ ret = @sdbm.delete_if {|key, val| key.to_i >= 50}
+ assert_equals(@sdbm, ret)
+ check_size(0, @sdbm)
+
+ # break
+ v = "0"
+ 100.times {@sdbm[v] = v; v = v.next}
+ check_size(100, @sdbm)
+ n = 0;
+ @sdbm.delete_if {|key, val|
+ break if n > 50
+ n+=1
+ true
+ }
+ assert_equals(51, n)
+ check_size(49, @sdbm)
+
+ @sdbm.clear
+
+ # raise
+ v = "0"
+ 100.times {@sdbm[v] = v; v = v.next}
+ check_size(100, @sdbm)
+ n = 0;
+ begin
+ @sdbm.delete_if {|key, val|
+ raise "runtime error" if n > 50
+ n+=1
+ true
+ }
+ rescue
+ end
+ assert_equals(51, n)
+ check_size(49, @sdbm)
+ end
+
+ def test_reject
+ v = "0"
+ 100.times {@sdbm[v] = v; v = v.next}
+
+ hash = @sdbm.reject {|key, val| key.to_i < 50}
+ assert_instance_of(Hash, hash)
+ assert_equals(100, @sdbm.size)
+
+ assert_equals(50, hash.size)
+ hash.each_pair {|key,val|
+ assert_equals(false, key.to_i < 50)
+ assert_equals(key, val)
+ }
+
+ hash = @sdbm.reject {|key, val| key.to_i < 100}
+ assert_instance_of(Hash, hash)
+ assert_equals(true, hash.empty?)
+ end
+
+ def test_clear
+ v = "1"
+ 100.times {v = v.next; @sdbm[v] = v}
+
+ assert_equals(@sdbm, @sdbm.clear)
+
+ # validate SDBM#size
+ i = 0
+ @sdbm.each { i += 1 }
+ assert_equals(@sdbm.size, i)
+ assert_equals(0, i)
+ end
+
+ def test_invert
+ v = "0"
+ 100.times {@sdbm[v] = v; v = v.next}
+
+ hash = @sdbm.invert
+ assert_instance_of(Hash, hash)
+ assert_equals(100, hash.size)
+ hash.each_pair {|key, val|
+ assert_equals(key.to_i, val.to_i)
+ }
+ end
+
+ def test_update
+ hash = {}
+ v = "0"
+ 100.times {v = v.next; hash[v] = v}
+
+ @sdbm["101"] = "101"
+ @sdbm.update hash
+ assert_equals(101, @sdbm.size)
+ @sdbm.each_pair {|key, val|
+ assert_equals(key.to_i, val.to_i)
+ }
+ end
+
+ def test_replace
+ hash = {}
+ v = "0"
+ 100.times {v = v.next; hash[v] = v}
+
+ @sdbm["101"] = "101"
+ @sdbm.replace hash
+ assert_equals(100, @sdbm.size)
+ @sdbm.each_pair {|key, val|
+ assert_equals(key.to_i, val.to_i)
+ }
+ end
+
+ def test_haskey?
+ assert_equals('bar', @sdbm['foo']='bar')
+ assert_equals(true, @sdbm.has_key?('foo'))
+ assert_equals(false, @sdbm.has_key?('bar'))
+ end
+
+ def test_has_value?
+ assert_equals('bar', @sdbm['foo']='bar')
+ assert_equals(true, @sdbm.has_value?('bar'))
+ assert_equals(false, @sdbm.has_value?('foo'))
+ end
+
+ def test_to_a
+ v = "0"
+ 100.times {v = v.next; @sdbm[v] = v}
+
+ ary = @sdbm.to_a
+ assert_instance_of(Array, ary)
+ assert_equals(100, ary.size)
+ ary.each {|key,val|
+ assert_equals(key.to_i, val.to_i)
+ }
+ end
+
+ def test_to_hash
+ v = "0"
+ 100.times {v = v.next; @sdbm[v] = v}
+
+ hash = @sdbm.to_hash
+ assert_instance_of(Hash, hash)
+ assert_equals(100, hash.size)
+ hash.each {|key,val|
+ assert_equals(key.to_i, val.to_i)
+ }
+ end
+end
+
+if $0 == __FILE__
+ if ARGV.size == 0
+ suite = RUNIT::TestSuite.new
+ suite.add_test(TestSDBM.suite)
+ else
+ suite = RUNIT::TestSuite.new
+ ARGV.each do |testmethod|
+ suite.add_test(TestSDBM.new(testmethod))
+ end
+ end
+
+ RUNIT::CUI::TestRunner.run(suite)
+end
diff --git a/ext/socket/socket.c b/ext/socket/socket.c
index 668b332..13a94ae 100644
--- a/ext/socket/socket.c
+++ b/ext/socket/socket.c
@@ -155,6 +155,8 @@ rb_getaddrinfo(nodename, servname, hints, res)
#endif
#ifdef NT
+static void sock_finalize _((OpenFile *fptr));
+
static void
sock_finalize(fptr)
OpenFile *fptr;
@@ -284,7 +286,10 @@ bsock_setsockopt(sock, lev, optname, val)
v = (char*)&i; vlen = sizeof(i);
break;
default:
- v = rb_str2cstr(val, &vlen);
+ StringValue(val);
+ v = RSTRING(val)->ptr;
+ vlen = RSTRING(val)->len;
+ break;
}
GetOpenFile(sock, fptr);
@@ -353,30 +358,28 @@ bsock_send(argc, argv, sock)
VALUE *argv;
VALUE sock;
{
- VALUE msg, to;
+ VALUE mesg, to;
VALUE flags;
OpenFile *fptr;
FILE *f;
int fd, n;
- char *m, *t;
- int mlen, tlen;
rb_secure(4);
- rb_scan_args(argc, argv, "21", &msg, &flags, &to);
+ rb_scan_args(argc, argv, "21", &mesg, &flags, &to);
GetOpenFile(sock, fptr);
f = GetWriteFile(fptr);
fd = fileno(f);
retry:
rb_thread_fd_writable(fd);
- m = rb_str2cstr(msg, &mlen);
+ StringValue(mesg);
if (!NIL_P(to)) {
- t = rb_str2cstr(to, &tlen);
- n = sendto(fd, m, mlen, NUM2INT(flags),
- (struct sockaddr*)t, tlen);
+ StringValue(to);
+ n = sendto(fd, RSTRING(mesg)->ptr, RSTRING(mesg)->len, NUM2INT(flags),
+ (struct sockaddr*)RSTRING(to)->ptr, RSTRING(to)->len);
}
else {
- n = send(fd, m, mlen, NUM2INT(flags));
+ n = send(fd, RSTRING(mesg)->ptr, RSTRING(mesg)->len, NUM2INT(flags));
}
if (n < 0) {
switch (errno) {
@@ -582,8 +585,8 @@ ip_addrsetup(host, port)
portp = pbuf;
}
else {
- Check_SafeStr(port);
- portp = STR2CSTR(port);
+ SafeStringValue(port);
+ portp = RSTRING(port)->ptr;
}
MEMZERO(&hints, struct addrinfo, 1);
@@ -1295,8 +1298,6 @@ udp_send(argc, argv, sock)
OpenFile *fptr;
FILE *f;
int n;
- char *m;
- int mlen;
struct addrinfo *res0, *res;
if (argc == 2 || argc == 3) {
@@ -1308,11 +1309,11 @@ udp_send(argc, argv, sock)
GetOpenFile(sock, fptr);
res0 = ip_addrsetup(host, port);
f = GetWriteFile(fptr);
- m = rb_str2cstr(mesg, &mlen);
+ StringValue(mesg);
for (res = res0; res; res = res->ai_next) {
retry:
- n = sendto(fileno(f), m, mlen, NUM2INT(flags), res->ai_addr,
- res->ai_addrlen);
+ n = sendto(fileno(f), RSTRING(mesg)->ptr, RSTRING(mesg)->len, NUM2INT(flags),
+ res->ai_addr, res->ai_addrlen);
if (n >= 0) {
freeaddrinfo(res0);
return INT2FIX(n);
@@ -1784,22 +1785,13 @@ sock_s_gethostbyaddr(argc, argv)
int argc;
VALUE *argv;
{
- VALUE vaddr, vtype;
- int type;
- int alen;
- char *addr;
+ VALUE addr, type;
struct hostent *h;
- rb_scan_args(argc, argv, "11", &vaddr, &vtype);
- addr = rb_str2cstr(vaddr, &alen);
- if (!NIL_P(vtype)) {
- type = NUM2INT(vtype);
- }
- else {
- type = AF_INET;
- }
-
- h = gethostbyaddr(addr, alen, type);
+ rb_scan_args(argc, argv, "11", &addr, &type);
+ StringValue(addr);
+ h = gethostbyaddr(RSTRING(addr)->ptr, RSTRING(addr)->len,
+ NIL_P(type)?AF_INET:NUM2INT(type));
return mkhostent(h);
}
@@ -1816,14 +1808,15 @@ sock_s_getservbyaname(argc, argv)
rb_scan_args(argc, argv, "11", &service, &protocol);
if (NIL_P(protocol)) proto = "tcp";
- else proto = STR2CSTR(protocol);
+ else proto = StringValuePtr(protocol);
- sp = getservbyname(STR2CSTR(service), proto);
+ StringValue(service);
+ sp = getservbyname(RSTRING(service)->ptr, proto);
if (sp) {
port = ntohs(sp->s_port);
}
else {
- char *s = STR2CSTR(service);
+ char *s = RSTRING(service)->ptr;
char *end;
port = strtoul(s, &end, 0);
@@ -1831,7 +1824,6 @@ sock_s_getservbyaname(argc, argv)
rb_raise(rb_eSocket, "no such service %s/%s", s, proto);
}
}
-
return INT2FIX(port);
}
@@ -1852,7 +1844,7 @@ sock_s_getaddrinfo(argc, argv)
hptr = NULL;
}
else {
- strncpy(hbuf, STR2CSTR(host), sizeof(hbuf));
+ strncpy(hbuf, StringValuePtr(host), sizeof(hbuf));
hbuf[sizeof(hbuf) - 1] = '\0';
hptr = hbuf;
}
@@ -1864,7 +1856,7 @@ sock_s_getaddrinfo(argc, argv)
pptr = pbuf;
}
else {
- strncpy(pbuf, STR2CSTR(port), sizeof(pbuf));
+ strncpy(pbuf, StringValuePtr(port), sizeof(pbuf));
pbuf[sizeof(pbuf) - 1] = '\0';
pptr = pbuf;
}
@@ -1876,14 +1868,17 @@ sock_s_getaddrinfo(argc, argv)
else if (FIXNUM_P(family)) {
hints.ai_family = FIX2INT(family);
}
- else if (strcmp(STR2CSTR(family), "AF_INET") == 0) {
- hints.ai_family = PF_INET;
- }
+ else {
+ StringValue(family);
+ if (strcmp(RSTRING(family)->ptr, "AF_INET") == 0) {
+ hints.ai_family = PF_INET;
+ }
#ifdef INET6
- else if (strcmp(STR2CSTR(family), "AF_INET6") == 0) {
- hints.ai_family = PF_INET6;
- }
+ else if (strcmp(RSTRING(family)->ptr, "AF_INET6") == 0) {
+ hints.ai_family = PF_INET6;
+ }
#endif
+ }
if (!NIL_P(socktype)) {
hints.ai_socktype = NUM2INT(socktype);
@@ -1967,7 +1962,7 @@ sock_s_getnameinfo(argc, argv)
hptr = NULL;
}
else {
- strncpy(hbuf, STR2CSTR(host), sizeof(hbuf));
+ strncpy(hbuf, StringValuePtr(host), sizeof(hbuf));
hbuf[sizeof(hbuf) - 1] = '\0';
hptr = hbuf;
}
@@ -1981,7 +1976,7 @@ sock_s_getnameinfo(argc, argv)
pptr = pbuf;
}
else {
- strncpy(pbuf, STR2CSTR(port), sizeof(pbuf));
+ strncpy(pbuf, StringValuePtr(port), sizeof(pbuf));
pbuf[sizeof(pbuf) - 1] = '\0';
pptr = pbuf;
}
@@ -1993,14 +1988,17 @@ sock_s_getnameinfo(argc, argv)
else if (FIXNUM_P(af)) {
hints.ai_family = FIX2INT(af);
}
- else if (strcmp(STR2CSTR(af), "AF_INET") == 0) {
- hints.ai_family = PF_INET;
- }
+ else {
+ StringValue(af);
+ if (strcmp(RSTRING(af)->ptr, "AF_INET") == 0) {
+ hints.ai_family = PF_INET;
+ }
#ifdef INET6
- else if (strcmp(STR2CSTR(af), "AF_INET6") == 0) {
- hints.ai_family = PF_INET6;
- }
+ else if (strcmp(RSTRING(af)->ptr, "AF_INET6") == 0) {
+ hints.ai_family = PF_INET6;
+ }
#endif
+ }
error = getaddrinfo(hptr, pptr, &hints, &res);
if (error) goto error_exit_addr;
sap = res->ai_addr;
diff --git a/ext/tcltklib/tcltklib.c b/ext/tcltklib/tcltklib.c
index b0a4880..cec025b 100644
--- a/ext/tcltklib/tcltklib.c
+++ b/ext/tcltklib/tcltklib.c
@@ -163,7 +163,7 @@ ip_ruby(clientData, interp, argc, argv)
Tcl_ResetResult(interp);
if (failed) {
VALUE eclass = CLASS_OF(failed);
- Tcl_AppendResult(interp, STR2CSTR(failed), (char*)NULL);
+ Tcl_AppendResult(interp, StringValuePtr(failed), (char*)NULL);
if (eclass == eTkCallbackBreak) {
return TCL_BREAK;
} else if (eclass == eTkCallbackContinue) {
@@ -180,9 +180,9 @@ ip_ruby(clientData, interp, argc, argv)
}
/* copy result to the tcl interpreter */
- DUMP2("(rb_eval_string result) %s", STR2CSTR(res));
+ DUMP2("(rb_eval_string result) %s", StringValuePtr(res));
DUMP1("Tcl_AppendResult");
- Tcl_AppendResult(interp, STR2CSTR(res), (char *)NULL);
+ Tcl_AppendResult(interp, StringValuePtr(res), (char *)NULL);
return TCL_OK;
}
@@ -254,7 +254,7 @@ ip_eval(self, str)
Data_Get_Struct(self, struct tcltkip, ptr);
/* call Tcl_Eval() */
- s = STR2CSTR(str);
+ s = StringValuePtr(str);
buf = ALLOCA_N(char, strlen(s)+1);
strcpy(buf, s);
DUMP2("Tcl_Eval(%s)", buf);
@@ -285,9 +285,11 @@ ip_toUTF8(self, str, encodename)
Data_Get_Struct(self,struct tcltkip, ptr);
interp = ptr->ip;
- encoding = Tcl_GetEncoding(interp,STR2CSTR(encodename));
- buf = ALLOCA_N(char,strlen(STR2CSTR(str))+1);
- strcpy(buf,STR2CSTR(str));
+ StringValue(encodename);
+ StringValue(str);
+ encoding = Tcl_GetEncoding(interp, RSTRING(encodename)->ptr);
+ buf = ALLOCA_N(char,strlen(RSTRING(str)->ptr)+1);
+ strcpy(buf, RSTRING(str)->ptr);
Tcl_DStringInit(&dstr);
Tcl_DStringFree(&dstr);
@@ -316,9 +318,11 @@ ip_fromUTF8(self, str, encodename)
Data_Get_Struct(self,struct tcltkip, ptr);
interp = ptr->ip;
- encoding = Tcl_GetEncoding(interp,STR2CSTR(encodename));
- buf = ALLOCA_N(char,strlen(STR2CSTR(str))+1);
- strcpy(buf,STR2CSTR(str));
+ StringValue(encodename);
+ StringValue(str);
+ encoding = Tcl_GetEncoding(interp,RSTRING(encodename)->ptr);
+ buf = ALLOCA_N(char,strlen(RSTRING(str)->ptr)+1);
+ strcpy(buf,RSTRING(str)->ptr);
Tcl_DStringInit(&dstr);
Tcl_DStringFree(&dstr);
@@ -339,10 +343,11 @@ ip_invoke_real(argc, argv, obj)
VALUE *argv;
VALUE obj;
{
+ VALUE v;
struct tcltkip *ptr; /* tcltkip data struct */
int i;
Tcl_CmdInfo info;
- char *cmd;
+ char *cmd, *s;
char **av = (char **)NULL;
#if TCL_MAJOR_VERSION >= 8
Tcl_Obj **ov = (Tcl_Obj **)NULL;
@@ -353,7 +358,8 @@ ip_invoke_real(argc, argv, obj)
Data_Get_Struct(obj, struct tcltkip, ptr);
/* get the command name string */
- cmd = STR2CSTR(argv[0]);
+ v = argv[0];
+ cmd = StringValuePtr(v);
/* map from the command name to a C procedure */
if (!Tcl_GetCommandInfo(ptr->ip, cmd, &info)) {
@@ -366,8 +372,9 @@ ip_invoke_real(argc, argv, obj)
/* object interface */
ov = (Tcl_Obj **)ALLOCA_N(Tcl_Obj *, argc+1);
for (i = 0; i < argc; ++i) {
- char *s = STR2CSTR(argv[i]);
- ov[i] = Tcl_NewStringObj(s, strlen(s));
+ VALUE v = argv[i];
+ s = StringValuePtr(v);
+ ov[i] = Tcl_NewStringObj(s, RSTRING(s)->len);
Tcl_IncrRefCount(ov[i]);
}
ov[argc] = (Tcl_Obj *)NULL;
@@ -378,8 +385,8 @@ ip_invoke_real(argc, argv, obj)
/* string interface */
av = (char **)ALLOCA_N(char *, argc+1);
for (i = 0; i < argc; ++i) {
- char *s = STR2CSTR(argv[i]);
-
+ v = argv[i];
+ s = StringValuePtr(v);
av[i] = ALLOCA_N(char, strlen(s)+1);
strcpy(av[i], s);
}
diff --git a/ext/tk/lib/tk.rb b/ext/tk/lib/tk.rb
index 873c823..47be8fd 100644
--- a/ext/tk/lib/tk.rb
+++ b/ext/tk/lib/tk.rb
@@ -1,7 +1,7 @@
#
-# tk.rb - Tk interface modue using tcltklib
+# tk.rb - Tk interface module using tcltklib
# $Date$
-# by Yukihiro Matsumoto <matz@netlab.co.jp>
+# by Yukihiro Matsumoto <matz@netlab.jp>
# use Shigehiro's tcltklib
require "tcltklib"
@@ -351,7 +351,7 @@ module TkComm
end
if context.kind_of? Array
context = context.collect{|ev|
- if context.kind_of? TkVirtualEvent
+ if ev.kind_of? TkVirtualEvent
ev.path
else
ev
@@ -397,8 +397,18 @@ module TkComm
end
}
else
- tk_split_list(tk_call(*what)).collect{|seq|
- seq[1..-2].gsub(/></,',')
+ tk_split_simplelist(tk_call(*what)).collect!{|seq|
+ l = seq.scan(/<*[^<>]+>*/).collect!{|subseq|
+ case (subseq)
+ when /^<<[^<>]+>>$/
+ TkVirtualEvent.getobj(subseq[1..-2])
+ when /^<[^<>]+>$/
+ subseq[1..-2]
+ else
+ subseq.split('')
+ end
+ }.flatten
+ (l.size == 1) ? l[0] : l
}
end
end
@@ -1046,6 +1056,12 @@ class TkBindTag
BTagID_TBL[id]? BTagID_TBL[id]: id
end
+ ALL = self.new
+ ALL.instance_eval {
+ @id = 'all'
+ BTagID_TBL[@id] = self
+ }
+
def initialize(*args)
@id = Tk_BINDTAG_ID[0]
Tk_BINDTAG_ID[0] = Tk_BINDTAG_ID[0].succ
@@ -1063,20 +1079,11 @@ class TkBindTag
end
class TkBindTagAll<TkBindTag
- BindTagALL = []
def TkBindTagAll.new(*args)
- if BindTagALL[0]
- BindTagALL[0].bind(*args) if args != []
- else
- new = super()
- BindTagALL[0] = new
- end
- BindTagALL[0]
- end
+ $stderr.puts "Warning: TkBindTagALL is obsolete. Use TkBindTag::ALL\n"
- def initialize(*args)
- @id = 'all'
- BindTagALL[0].bind(*args) if args != []
+ TkBindTag::ALL.bind(*args) if args != []
+ TkBindTag::ALL
end
end
@@ -2575,7 +2582,7 @@ class TkWindow<TkObject
def bindtags(taglist=nil)
if taglist
- fail unless taglist.kind_of? Array
+ fail ArgumentError unless taglist.kind_of? Array
tk_call('bindtags', path, taglist)
else
list(tk_call('bindtags', path)).collect{|tag|
diff --git a/ext/tk/lib/tkvirtevent.rb b/ext/tk/lib/tkvirtevent.rb
index b31b990..d3721e3 100644
--- a/ext/tk/lib/tkvirtevent.rb
+++ b/ext/tk/lib/tkvirtevent.rb
@@ -7,12 +7,27 @@ require 'tk'
class TkVirtualEvent<TkObject
extend Tk
- TkVirturlEventID = [0]
- TkVirturlEventTBL = {}
+ TkVirtualEventID = [0]
+ TkVirtualEventTBL = {}
+
+ class PreDefVirtEvent<self
+ def initialize(event)
+ @path = @id = event
+ TkVirtualEvent::TkVirtualEventTBL[@id] = self
+ end
+ end
def TkVirtualEvent.getobj(event)
- obj = TkVirturlEventTBL[event]
- obj ? obj : event
+ obj = TkVirtualEventTBL[event]
+ if obj
+ obj
+ else
+ if tk_call('event', 'info').index("<#{event}>")
+ PreDefVirtEvent.new(event)
+ else
+ fail ArgumentError, "undefined virtual event '<#{event}>'"
+ end
+ end
end
def TkVirtualEvent.info
@@ -22,8 +37,8 @@ class TkVirtualEvent<TkObject
end
def initialize(*sequences)
- @path = @id = format("<VirtEvent%.4d>", TkVirturlEventID[0])
- TkVirturlEventID[0] += 1
+ @path = @id = format("<VirtEvent%.4d>", TkVirtualEventID[0])
+ TkVirtualEventID[0] += 1
add(*sequences)
end
@@ -31,7 +46,7 @@ class TkVirtualEvent<TkObject
if sequences != []
tk_call('event', 'add', "<#{@id}>",
*(sequences.collect{|seq| "<#{tk_event_sequence(seq)}>"}) )
- TkVirturlEventTBL[@id] = self
+ TkVirtualEventTBL[@id] = self
end
self
end
@@ -39,11 +54,11 @@ class TkVirtualEvent<TkObject
def delete(*sequences)
if sequences == []
tk_call('event', 'delete', "<#{@id}>")
- TkVirturlEventTBL[@id] = nil
+ TkVirtualEventTBL[@id] = nil
else
tk_call('event', 'delete', "<#{@id}>",
*(sequences.collect{|seq| "<#{tk_event_sequence(seq)}>"}) )
- TkVirturlEventTBL[@id] = nil if info == []
+ TkVirtualEventTBL[@id] = nil if info == []
end
self
end
diff --git a/intern.h b/intern.h
index 7594b8a..f88a8bb 100644
--- a/intern.h
+++ b/intern.h
@@ -47,7 +47,7 @@ VALUE rb_ary_concat _((VALUE, VALUE));
VALUE rb_ary_assoc _((VALUE, VALUE));
VALUE rb_ary_rassoc _((VALUE, VALUE));
VALUE rb_ary_includes _((VALUE, VALUE));
-VALUE rb_protect_inspect _((VALUE(*)(VALUE,VALUE),VALUE,VALUE));
+VALUE rb_protect_inspect _((VALUE(*)(),VALUE,VALUE));
VALUE rb_inspecting_p _((VALUE));
/* bignum.c */
VALUE rb_big_clone _((VALUE));
@@ -144,7 +144,7 @@ void rb_obj_call_init _((VALUE, int, VALUE*));
VALUE rb_class_new_instance _((int, VALUE*, VALUE));
VALUE rb_f_lambda _((void));
VALUE rb_protect _((VALUE (*)(VALUE), VALUE, int*));
-void rb_set_end_proc _((void (*)(void), VALUE));
+void rb_set_end_proc _((void (*)(VALUE), VALUE));
void rb_mark_end_proc _((void));
void rb_exec_end_proc _((void));
void ruby_finalize _((void));
diff --git a/io.c b/io.c
index 08e8fd6..6570459 100644
--- a/io.c
+++ b/io.c
@@ -1531,6 +1531,8 @@ pipe_atexit _((void))
}
#endif
+static void pipe_finalize _((OpenFile *fptr));
+
static void
pipe_finalize(fptr)
OpenFile *fptr;
diff --git a/lib/cgi/session.rb b/lib/cgi/session.rb
index 1120fb5..1a3379b 100644
--- a/lib/cgi/session.rb
+++ b/lib/cgi/session.rb
@@ -96,10 +96,19 @@ class CGI
end
class FileStore
+ def check_id(id)
+ /[^0-9a-zA-Z]/ =~ id.to_s ? false : true
+ end
+ module_function :check_id
+
def initialize(session, option={})
dir = option['tmpdir'] || ENV['TMP'] || '/tmp'
prefix = option['prefix'] || ''
- path = dir+"/"+prefix+session.session_id
+ id = session.session_id
+ unless check_id(id)
+ raise ArgumentError, "session_id `%s' is invalid" % id
+ end
+ path = dir+"/"+prefix+id
path.untaint
unless File::exist? path
@hash = {}
@@ -149,9 +158,9 @@ class CGI
class MemoryStore
GLOBAL_HASH_TABLE = {}
- def initialize(session, option={})
+ def initialize(session, option=nil)
@session_id = session.session_id
- GLOBAL_HASH_TABLE[@session_id] = {}
+ GLOBAL_HASH_TABLE[@session_id] ||= {}
end
def restore
@@ -167,7 +176,7 @@ class CGI
end
def delete
- GLOBAL_HASH_TABLE[@session_id] = nil
+ GLOBAL_HASH_TABLE.delete(@session_id)
end
end
end
diff --git a/lib/date.rb b/lib/date.rb
index 3422121..cd0b997 100644
--- a/lib/date.rb
+++ b/lib/date.rb
@@ -202,7 +202,10 @@ class Date
alias_method :__#{id.to_i}__, :#{id.id2name}
private :__#{id.to_i}__
def #{id.id2name}(*args, &block)
- (@__#{id.to_i}__ ||= [__#{id.to_i}__(*args, &block)])[0]
+ unless defined? @__#{id.to_i}__
+ @__#{id.to_i}__ = __#{id.to_i}__(*args, &block)
+ end
+ @__#{id.to_i}__
end
end;
end
diff --git a/lib/e2mmap.rb b/lib/e2mmap.rb
index 2ae9345..6739c42 100644
--- a/lib/e2mmap.rb
+++ b/lib/e2mmap.rb
@@ -73,8 +73,7 @@ module Exception2MessageMapper
end
alias Fail Raise
- def self.append_features(mod)
- super
+ def self.included(mod)
mod.extend Exception2MessageMapper
end
]
diff --git a/lib/getopts.rb b/lib/getopts.rb
index 490523b..8a5917e 100644
--- a/lib/getopts.rb
+++ b/lib/getopts.rb
@@ -77,8 +77,8 @@ end
elsif boolopts.key? opt then # ruby --verbose
boolopts[ opt ] = true
else
- return nil
- end
+ return nil
+ end
c += 1
when /\A-(.+)/
diff --git a/lib/mathn.rb b/lib/mathn.rb
index 8d92272..f3f7a95 100644
--- a/lib/mathn.rb
+++ b/lib/mathn.rb
@@ -122,7 +122,11 @@ end
class Rational
Unify = true
-
+
+ def inspect
+ format "%s/%s", @numerator.inspect, @denominator.inspect
+ end
+
alias power! **
def ** (other)
diff --git a/lib/mutex_m.rb b/lib/mutex_m.rb
index e0fcf0f..1a3cd05 100644
--- a/lib/mutex_m.rb
+++ b/lib/mutex_m.rb
@@ -16,8 +16,7 @@
#
module Mutex_m
- def Mutex_m.append_features(cl)
- super
+ def Mutex_m.included(cl)
unless cl.instance_of?(Module)
cl.module_eval %q{
alias locked? mu_locked?
diff --git a/lib/pstore.rb b/lib/pstore.rb
index b3e1df8..d74d712 100644
--- a/lib/pstore.rb
+++ b/lib/pstore.rb
@@ -13,6 +13,7 @@
# end
require "ftools"
+require "md5"
class PStore
class Error < StandardError
@@ -41,11 +42,10 @@ class PStore
def [](name)
in_transaction
- value = @table[name]
- if value == nil
+ unless @table.key? name
raise PStore::Error, format("undefined root name `%s'", name)
end
- value
+ @table[name]
end
def []=(name, value)
in_transaction
@@ -69,10 +69,12 @@ class PStore
end
def commit
+ in_transaction
@abort = false
throw :pstore_abort_transaction
end
def abort
+ in_transaction
@abort = true
throw :pstore_abort_transaction
end
@@ -83,18 +85,21 @@ class PStore
@transaction = true
value = nil
backup = @filename+"~"
- if File::exist?(@filename)
+ begin
file = File::open(@filename, "r+")
orig = true
- else
- @table = {}
+ rescue Errno::ENOENT
file = File::open(@filename, "w+")
- Marshal::dump(@table, file)
end
file.flock(File::LOCK_EX)
if orig
- File::copy @filename, backup
- @table = Marshal::load(file)
+ content = file.read
+ @table = Marshal::load(content)
+ size = content.size
+ md5 = MD5.new(content).digest
+ content = nil # unreference huge data
+ else
+ @table = {}
end
begin
catch(:pstore_abort_transaction) do
@@ -105,13 +110,18 @@ class PStore
raise
ensure
unless @abort
- begin
- file.rewind
- Marshal::dump(@table, file)
- file.truncate(file.pos)
- rescue
- File::rename backup, @filename if File::exist?(backup)
- raise
+ file.rewind
+ content = Marshal::dump(@table)
+ if !md5 || size != content.size || md5 != MD5.new(content).digest
+ File::copy @filename, backup
+ begin
+ file.write(content)
+ file.truncate(file.pos)
+ content = nil # unreference huge data
+ rescue
+ File::rename backup, @filename if File::exist?(backup)
+ raise
+ end
end
end
@abort = false
@@ -139,4 +149,8 @@ if __FILE__ == $0
p db["root"][0]
end
end
+
+ db.transaction do
+ p db["root"]
+ end
end
diff --git a/lib/singleton.rb b/lib/singleton.rb
index aa245b3..f5c2d83 100644
--- a/lib/singleton.rb
+++ b/lib/singleton.rb
@@ -11,7 +11,7 @@
# a = SomeSingletonClass.new # error (`new' is private)
module Singleton
- def Singleton.append_features(klass)
+ def Singleton.included(klass)
klass.private_class_method(:new)
klass.instance_eval %{
@__instance__ = nil
diff --git a/lib/sync.rb b/lib/sync.rb
index f1410af..6ddd837 100644
--- a/lib/sync.rb
+++ b/lib/sync.rb
@@ -76,8 +76,7 @@ module Sync_m
end
end
- def Sync_m.append_features(cl)
- super
+ def Sync_m.included(cl)
unless cl.instance_of?(Module)
# do nothing for Modules
# make aliases and include the proper module.
diff --git a/lib/tempfile.rb b/lib/tempfile.rb
index 0b22de2..d4876f9 100644
--- a/lib/tempfile.rb
+++ b/lib/tempfile.rb
@@ -4,7 +4,7 @@
# The class for temporary files.
# o creates a temporary file, which name is "basename.pid.n" with mode "w+".
# o Tempfile objects can be used like IO object.
-# o with tmpfile.close(true) created temporary files are removed.
+# o with tempfile.close(true) created temporary files are removed.
# o created files are also removed on script termination.
# o with Tempfile#open, you can reopen the temporary file.
# o file mode of the temporary files are 0600.
@@ -35,36 +35,31 @@ class Tempfile < SimpleDelegator
if $SAFE > 0 and tmpdir.tainted?
tmpdir = '/tmp'
end
- umask = File.umask(0177)
- begin
- n = 0
- while true
- begin
- tmpname = sprintf('%s/%s%d.%d', tmpdir, basename, $$, n)
- lock = tmpname + '.lock'
- unless File.exist?(tmpname) or File.exist?(lock)
- Dir.mkdir(lock)
- break
- end
- rescue
- raise "cannot generate tmpfile `%s'" % tmpname if n >= Max_try
- #sleep(1)
+ n = 0
+ while true
+ begin
+ tmpname = sprintf('%s/%s%d.%d', tmpdir, basename, $$, n)
+ lock = tmpname + '.lock'
+ unless File.exist?(tmpname) or File.exist?(lock)
+ Dir.mkdir(lock)
+ break
end
- n += 1
+ rescue
+ raise "cannot generate tempfile `%s'" % tmpname if n >= Max_try
+ #sleep(1)
end
+ n += 1
+ end
- @protect = []
- @clean_files = Tempfile.callback(tmpname, @protect)
- ObjectSpace.define_finalizer(self, @clean_files)
+ @protect = []
+ @clean_files = Tempfile.callback(tmpname, @protect)
+ ObjectSpace.define_finalizer(self, @clean_files)
- @tmpfile = File.open(tmpname, File::RDWR|File::CREAT|File::EXCL)
- @protect[0] = @tmpfile
- @tmpname = tmpname
- super(@tmpfile)
- Dir.rmdir(lock)
- ensure
- File.umask(umask)
- end
+ @tmpfile = File.open(tmpname, File::RDWR|File::CREAT|File::EXCL)
+ @protect[0] = @tmpfile
+ @tmpname = tmpname
+ super(@tmpfile)
+ Dir.rmdir(lock)
end
def Tempfile.open(*args)
diff --git a/misc/ruby-mode.el b/misc/ruby-mode.el
index 7dd4708..a3cdff3 100644
--- a/misc/ruby-mode.el
+++ b/misc/ruby-mode.el
@@ -670,7 +670,7 @@ An end of a defun is found by moving forward from the beginning of one."
(setq font-lock-syntactic-keywords
'(("\\$\\([#\"'`$\\]\\)" 1 (1 . nil))
("\\(#\\)[{$@]" 1 (1 . nil))
- ("\\(/\\)\\([^/\n]\\|\\\\/\\)*\\(/\\)"
+ ("\\(/\\)\\([^/\n]\\|\\/\\)*\\(/\\)"
(1 (7 . ?'))
(3 (7 . ?')))))
(make-local-variable 'font-lock-defaults)
diff --git a/missing/alloca.c b/missing/alloca.c
index 6879618..39697f1 100644
--- a/missing/alloca.c
+++ b/missing/alloca.c
@@ -52,7 +52,12 @@ typedef char *pointer; /* generic pointer type */
#define NULL 0 /* null pointer constant */
-extern void free();
+#ifdef RUBY_LIB
+#define xmalloc ruby_xmalloc
+#define xfree ruby_xfree
+#endif
+
+extern void xfree();
extern pointer xmalloc();
/*
@@ -157,7 +162,7 @@ alloca (size) /* returns pointer to storage */
{
register header *np = hp->h.next;
- free ((pointer) hp); /* collect garbage */
+ xfree ((pointer) hp); /* collect garbage */
hp = np; /* -> next header */
}
diff --git a/rubytest.rb b/rubytest.rb
index e4b2ee6..05705da 100644
--- a/rubytest.rb
+++ b/rubytest.rb
@@ -6,7 +6,7 @@ include Config
unless File.exist? "./#{CONFIG['ruby_install_name']}#{CONFIG['EXEEXT']}"
print "./#{CONFIG['ruby_install_name']} is not found.\n"
print "Try `make' first, then `make test', please.\n"
- exit 0
+ exit 1
end
if File.exist? CONFIG['LIBRUBY_SO']
diff --git a/sample/test.rb b/sample/test.rb
index 3d8ce72..10ae5e5 100644
--- a/sample/test.rb
+++ b/sample/test.rb
@@ -644,6 +644,11 @@ test_ok(-7 == (-a).remainder(-b))
test_ok(10**40+10**20 == 10000000000000000000100000000000000000000)
test_ok(10**40/10**20 == 100000000000000000000)
+a = 677330545177305025495135714080
+b = 14269972710765292560
+test_ok(a % b == 0)
+test_ok(-a % b == 0)
+
test_check "string & char"
test_ok("abcd" == "abcd")
@@ -1053,7 +1058,7 @@ test_ok(foo.test == "test")
begin
foo.test2
test_ok false
-rescue NameError
+rescue NoMethodError
test_ok true
end
diff --git a/string.c b/string.c
index 0d54923..70e1886 100644
--- a/string.c
+++ b/string.c
@@ -950,7 +950,7 @@ rb_str_aref_m(argc, argv, str)
}
static void
-rb_str_replace(str, beg, len, val)
+rb_str_update(str, beg, len, val)
VALUE str;
long beg;
long len;
@@ -1018,7 +1018,7 @@ rb_str_aset(str, indx, val)
RSTRING(str)->ptr[idx] = NUM2INT(val) & 0xff;
}
else {
- rb_str_replace(str, idx, 1, val);
+ rb_str_update(str, idx, 1, val);
}
return val;
@@ -1034,7 +1034,7 @@ rb_str_aset(str, indx, val)
case T_STRING:
beg = rb_str_index(str, indx, 0);
if (beg != -1) {
- rb_str_replace(str, beg, RSTRING(indx)->len, val);
+ rb_str_update(str, beg, RSTRING(indx)->len, val);
}
return val;
@@ -1043,7 +1043,7 @@ rb_str_aset(str, indx, val)
{
long beg, len;
if (rb_range_beg_len(indx, &beg, &len, RSTRING(str)->len, 2)) {
- rb_str_replace(str, beg, len, val);
+ rb_str_update(str, beg, len, val);
return val;
}
}
@@ -1064,7 +1064,7 @@ rb_str_aset_m(argc, argv, str)
beg = NUM2INT(argv[0]);
len = NUM2INT(argv[1]);
- rb_str_replace(str, beg, len, argv[2]);
+ rb_str_update(str, beg, len, argv[2]);
return argv[2];
}
if (argc != 2) {
@@ -1077,7 +1077,15 @@ static VALUE
rb_str_insert(str, idx, str2)
VALUE str, idx, str2;
{
- rb_str_replace(str, NUM2LONG(idx), 0, str2);
+ long pos = NUM2LONG(idx);
+
+ if (pos == -1) {
+ pos = RSTRING(str)->len;
+ }
+ else if (pos < 0) {
+ pos++;
+ }
+ rb_str_update(str, pos, 0, str2);
return str;
}
@@ -1329,7 +1337,7 @@ rb_str_gsub(argc, argv, str)
}
static VALUE
-rb_str_replace_m(str, str2)
+rb_str_replace(str, str2)
VALUE str, str2;
{
if (str == str2) return str;
@@ -2789,7 +2797,7 @@ Init_String()
rb_include_module(rb_cString, rb_mComparable);
rb_include_module(rb_cString, rb_mEnumerable);
rb_define_singleton_method(rb_cString, "new", rb_str_s_new, -1);
- rb_define_method(rb_cString, "initialize", rb_str_replace_m, 1);
+ rb_define_method(rb_cString, "initialize", rb_str_replace, 1);
rb_define_method(rb_cString, "clone", rb_str_clone, 0);
rb_define_method(rb_cString, "dup", rb_str_dup, 0);
rb_define_method(rb_cString, "<=>", rb_str_cmp_m, 1);
@@ -2815,7 +2823,7 @@ Init_String()
rb_define_method(rb_cString, "upto", rb_str_upto_m, 1);
rb_define_method(rb_cString, "index", rb_str_index_m, -1);
rb_define_method(rb_cString, "rindex", rb_str_rindex, -1);
- rb_define_method(rb_cString, "replace", rb_str_replace_m, 1);
+ rb_define_method(rb_cString, "replace", rb_str_replace, 1);
rb_define_method(rb_cString, "to_i", rb_str_to_i, 0);
rb_define_method(rb_cString, "to_f", rb_str_to_f, 0);
diff --git a/win32/win32.c b/win32/win32.c
index a1f795d..15a9a2a 100644
--- a/win32/win32.c
+++ b/win32/win32.c
@@ -2825,7 +2825,7 @@ struct handler_arg_t {
static void win32_call_handler(struct handler_arg_t* h)
{
int status;
- RUBY_CRITICAL(rb_protect((VALUE (*)())h->handler, (VALUE)h->arg, &h->status);
+ RUBY_CRITICAL(rb_protect((VALUE (*)(VALUE))h->handler, (VALUE)h->arg, &h->status);
status = h->status;
SetEvent(h->handshake));
if (status) {