From 1d3d27b42d1371ba6242ec217ca803f107ceb9eb Mon Sep 17 00:00:00 2001 From: matz Date: Sun, 6 May 2001 15:06:00 +0000 Subject: forgot some checkins. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@1363 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ext/dbm/testdbm.rb | 570 ++++++++++++++++++++++++++++++++++++++++ ext/gdbm/gdbm.c | 84 +++--- ext/gdbm/testgdbm.rb | 643 ++++++++++++++++++++++++++++++++++++++++++++++ ext/nkf/nkf.c | 18 +- ext/pty/pty.c | 2 +- ext/readline/extconf.rb | 3 + ext/readline/readline.c | 24 +- ext/sdbm/init.c | 115 ++++++--- ext/sdbm/testsdbm.rb | 536 ++++++++++++++++++++++++++++++++++++++ ext/socket/socket.c | 100 ++++--- ext/tcltklib/tcltklib.c | 39 +-- ext/tk/lib/tk.rb | 43 ++-- ext/tk/lib/tkvirtevent.rb | 33 ++- 13 files changed, 2027 insertions(+), 183 deletions(-) create mode 100644 ext/dbm/testdbm.rb create mode 100644 ext/gdbm/testgdbm.rb create mode 100644 ext/sdbm/testsdbm.rb (limited to 'ext') 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 #include -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; @@ -184,6 +190,18 @@ rb_gdbm_fetch2(dbm, keystr) return rb_gdbm_fetch(dbm, key); } +static VALUE +rb_gdbm_fetch3(obj, keystr) + VALUE obj, keystr; +{ + struct dbmdata *dbmp; + GDBM_FILE dbm; + + GetDBM(obj, dbmp); + dbm = dbmp->di_dbm; + return rb_gdbm_fetch2(dbm, keystr); +} + static VALUE rb_gdbm_firstkey(dbm) GDBM_FILE dbm; @@ -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; iptr; - 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 #include @@ -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 #include -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 +# by Yukihiro Matsumoto # 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(/>]+>*/).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") + PreDefVirtEvent.new(event) + else + fail ArgumentError, "undefined virtual event '<#{event}>'" + end + end end def TkVirtualEvent.info @@ -22,8 +37,8 @@ class TkVirtualEvent", TkVirturlEventID[0]) - TkVirturlEventID[0] += 1 + @path = @id = format("", TkVirtualEventID[0]) + TkVirtualEventID[0] += 1 add(*sequences) end @@ -31,7 +46,7 @@ class TkVirtualEvent", *(sequences.collect{|seq| "<#{tk_event_sequence(seq)}>"}) ) - TkVirturlEventTBL[@id] = self + TkVirtualEventTBL[@id] = self end self end @@ -39,11 +54,11 @@ class TkVirtualEvent") - 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 -- cgit v1.2.3