diff options
-rw-r--r-- | ToDo | 1 | ||||
-rw-r--r-- | array.c | 65 | ||||
-rw-r--r-- | bignum.c | 2 | ||||
-rw-r--r-- | dir.c | 6 | ||||
-rw-r--r-- | eval.c | 10 | ||||
-rw-r--r-- | ext/dbm/testdbm.rb | 570 | ||||
-rw-r--r-- | ext/gdbm/gdbm.c | 84 | ||||
-rw-r--r-- | ext/gdbm/testgdbm.rb | 643 | ||||
-rw-r--r-- | ext/nkf/nkf.c | 18 | ||||
-rw-r--r-- | ext/pty/pty.c | 2 | ||||
-rw-r--r-- | ext/readline/extconf.rb | 3 | ||||
-rw-r--r-- | ext/readline/readline.c | 24 | ||||
-rw-r--r-- | ext/sdbm/init.c | 115 | ||||
-rw-r--r-- | ext/sdbm/testsdbm.rb | 536 | ||||
-rw-r--r-- | ext/socket/socket.c | 100 | ||||
-rw-r--r-- | ext/tcltklib/tcltklib.c | 39 | ||||
-rw-r--r-- | ext/tk/lib/tk.rb | 43 | ||||
-rw-r--r-- | ext/tk/lib/tkvirtevent.rb | 33 | ||||
-rw-r--r-- | intern.h | 4 | ||||
-rw-r--r-- | io.c | 2 | ||||
-rw-r--r-- | lib/cgi/session.rb | 17 | ||||
-rw-r--r-- | lib/date.rb | 5 | ||||
-rw-r--r-- | lib/e2mmap.rb | 3 | ||||
-rw-r--r-- | lib/getopts.rb | 4 | ||||
-rw-r--r-- | lib/mathn.rb | 6 | ||||
-rw-r--r-- | lib/mutex_m.rb | 3 | ||||
-rw-r--r-- | lib/pstore.rb | 46 | ||||
-rw-r--r-- | lib/singleton.rb | 2 | ||||
-rw-r--r-- | lib/sync.rb | 3 | ||||
-rw-r--r-- | lib/tempfile.rb | 49 | ||||
-rw-r--r-- | misc/ruby-mode.el | 2 | ||||
-rw-r--r-- | missing/alloca.c | 9 | ||||
-rw-r--r-- | rubytest.rb | 2 | ||||
-rw-r--r-- | sample/test.rb | 7 | ||||
-rw-r--r-- | string.c | 26 | ||||
-rw-r--r-- | win32/win32.c | 2 |
36 files changed, 2190 insertions, 296 deletions
@@ -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 @@ -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); @@ -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; @@ -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); @@ -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 0000000000..c6b26e0cdf --- /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 ccfaeade6d..f20286a37c 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 0000000000..06f598cdaf --- /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 b59688cb03..58daad11ab 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 66907416eb..12063f958d 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 7db62745f3..431ed213bb 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 02b29796af..765a00280c 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 d6cda918e4..507fae69c1 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 0000000000..2cea1e4144 --- /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 668b332054..13a94ae297 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 b0a4880bfd..cec025bb71 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 873c823910..47be8fd974 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 b31b99062f..d3721e362e 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 @@ -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)); @@ -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 1120fb50f0..1a3379b88a 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 3422121298..cd0b997179 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 2ae934578d..6739c42518 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 490523b878..8a5917e794 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 8d92272159..f3f7a95a48 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 e0fcf0f209..1a3cd05856 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 b3e1df8284..d74d712a56 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 aa245b32b2..f5c2d8346b 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 f1410af1a9..6ddd837dad 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 0b22de260a..d4876f9c61 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 7dd4708176..a3cdff3c7a 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 6879618c8a..39697f114a 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 e4b2ee636c..05705dacf5 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 3d8ce723cc..10ae5e5301 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 @@ -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 a1f795d97e..15a9a2a673 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) { |