summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
authornagai <nagai@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2005-07-21 22:04:43 +0000
committernagai <nagai@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2005-07-21 22:04:43 +0000
commitecf2813198bb4e4d3eef9f2d48cfa69cb727d148 (patch)
tree41fe7f1a4b159b15c3171247c70c1f5f03d75d9b /ext
parent07f892fb3c5c928848ce7c74acd34e96ec364ce2 (diff)
* ext/tk/tkutil.c (tk_conv_args): forget to revert thread_critical
and gc_disable when raise ArgumentError. * ext/tk/lib/remote-tk.rb: RemoteTkIp doesn't need to include TkUtil. * ext/tcltklib/tcltklib.c: add TclTkIp#has_mainwindow? method. * ext/tk/lib/tk.rb: add Tk.has_mainwindow? method. * ext/tk/lib/multi-tk.rb: add MultiTkIp#has_mainwindow? method. * ext/tk/lib/remote-tk.rb: add RemoteTkIp#has_mainwindow? method. * ext/tk/lib/multi-tk.rb: slave IP fail to exit itself when $SAFE==4. * ext/tk/lib/multi-tk.rb: remove constants from MultiTkIp module to avoid access from external. * ext/tk/lib/multi-tk.rb: check_root flag is ignored on slave IPs' mainloop. * ext/tk/lib/multi-tk.rb: hang-up Tk.mainloop called on a slave IP with $SAFE==4. * ext/tk/lib/multi-tk.rb: MultiTkIp#bg_eval_proc doesn't work properly. * ext/tk/lib/multi-tk.rb: add MultiTkIp#set_cb_error(proc) and cb_error(exc) to log errors at callbacks on safe slave IPs. * ext/tk/lib/multi-tk.rb: fail to get an available slave IP object when call Tk.mainloop in the block which is given to new_* method, because cannot finish initialize while the root widget is alive. * ext/tk/lib/multi-tk.rb: fail to control a slave IP when Tk.mainloop runs on the IP. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8@8817 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'ext')
-rw-r--r--ext/tcltklib/MANUAL.eng5
-rw-r--r--ext/tcltklib/MANUAL.euc5
-rw-r--r--ext/tcltklib/tcltklib.c20
-rw-r--r--ext/tk/lib/multi-tk.rb160
-rw-r--r--ext/tk/lib/remote-tk.rb39
-rw-r--r--ext/tk/lib/tk.rb6
-rw-r--r--ext/tk/tkutil.c11
7 files changed, 183 insertions, 63 deletions
diff --git a/ext/tcltklib/MANUAL.eng b/ext/tcltklib/MANUAL.eng
index 9e7bd20d37..1db61f228e 100644
--- a/ext/tcltklib/MANUAL.eng
+++ b/ext/tcltklib/MANUAL.eng
@@ -310,6 +310,11 @@ class TclTkIp
: Check whether the interpreter is already deleted.
: If deleted, returns true.
+ has_mainwindow?
+ : Check whether the interpreter has a MainWindow (root widget).
+ : If has, returns true. If doesn't, returns false.
+ : If IP is already deleted, returns nil.
+
restart
: Restart Tk part of the interpreter.
: Use this when you need Tk functions after destroying the
diff --git a/ext/tcltklib/MANUAL.euc b/ext/tcltklib/MANUAL.euc
index f90dcff3e4..5dd36726ba 100644
--- a/ext/tcltklib/MANUAL.euc
+++ b/ext/tcltklib/MANUAL.euc
@@ -422,6 +422,11 @@ require "tcltklib" すると, 以下のモジュール, クラスが利用可能です.
: delete 済みでコマンドを受け付けない状態になっているならば
: true を返す.
+ has_mainwindow?
+ : Tcl/Tk インタープリタにメインウィンドウ (root widget) が
+ : 存在すれば true を,存在しなければ false を返す.
+ : インタープリタが既に delete 済みであれば nil を返す.
+
restart
: Tcl/Tk インタープリタの Tk 部分の初期化,再起動を行う.
: 一旦 root widget を破壊した後に再度 Tk の機能が必要と
diff --git a/ext/tcltklib/tcltklib.c b/ext/tcltklib/tcltklib.c
index b088ef7cf7..d1e5f9d0d0 100644
--- a/ext/tcltklib/tcltklib.c
+++ b/ext/tcltklib/tcltklib.c
@@ -4,7 +4,7 @@
* Oct. 24, 1997 Y. Matsumoto
*/
-#define TCLTKLIB_RELEASE_DATE "2005-07-19"
+#define TCLTKLIB_RELEASE_DATE "2005-07-22"
#include "ruby.h"
#include "rubysig.h"
@@ -511,6 +511,7 @@ get_ip(self)
}
if (ptr->ip == (Tcl_Interp*)NULL) {
/* rb_raise(rb_eRuntimeError, "deleted IP"); */
+ return((struct tcltkip *)NULL);
}
return ptr;
}
@@ -5293,6 +5294,22 @@ ip_is_deleted_p(self)
}
}
+static VALUE
+ip_has_mainwindow_p(self)
+ VALUE self;
+{
+ struct tcltkip *ptr = get_ip(self);
+
+ if (ptr == (struct tcltkip *)NULL || ptr->ip == (Tcl_Interp *)NULL
+ || Tcl_InterpDeleted(ptr->ip)) {
+ return Qnil;
+ } else if (Tk_MainWindow(ptr->ip) == (Tk_Window)NULL) {
+ return Qfalse;
+ } else {
+ return Qtrue;
+ }
+}
+
static VALUE
#ifdef HAVE_STDARG_PROTOTYPES
@@ -8557,6 +8574,7 @@ Init_tcltklib()
rb_define_method(ip, "allow_ruby_exit=", ip_allow_ruby_exit_set, 1);
rb_define_method(ip, "delete", ip_delete, 0);
rb_define_method(ip, "deleted?", ip_is_deleted_p, 0);
+ rb_define_method(ip, "has_mainwindow?", ip_has_mainwindow_p, 0);
rb_define_method(ip, "invalid_namespace?", ip_has_invalid_namespace_p, 0);
rb_define_method(ip, "_eval", ip_eval, 1);
rb_define_method(ip, "_toUTF8", ip_toUTF8, -1);
diff --git a/ext/tk/lib/multi-tk.rb b/ext/tk/lib/multi-tk.rb
index e8bbf67de1..3119080734 100644
--- a/ext/tk/lib/multi-tk.rb
+++ b/ext/tk/lib/multi-tk.rb
@@ -7,7 +7,7 @@ require 'tkutil'
require 'thread'
if defined? Tk
- fail RuntimeError, "'multi-tk' library must be required before requiring 'tk'"
+ fail RuntimeError,"'multi-tk' library must be required before requiring 'tk'"
end
################################################
@@ -54,7 +54,7 @@ MultiTkIp_OK.freeze
################################################
# methods for construction
class MultiTkIp
- SLAVE_IP_ID = ['slave'.freeze, '0'.taint].freeze
+ @@SLAVE_IP_ID = ['slave'.freeze, '0'.taint].freeze
@@IP_TABLE = {}.taint unless defined?(@@IP_TABLE)
@@ -86,9 +86,26 @@ class MultiTkIp
@ip.cb_eval(@cmd, *args)
rescue TkCallbackBreak, TkCallbackContinue => e
fail e
+ rescue SecurityError => e
+ # in 'exit', 'exit!', and 'abort' : security error --> delete IP
+ if e.backtrace[0] =~ /^(.+?):(\d+):in `(exit|exit!|abort)'/
+ @ip.delete
+ elsif @ip.safe?
+ if @ip.respond_to?(:cb_error)
+ @ip.cb_error(e)
+ else
+ nil # ignore
+ end
+ else
+ fail e
+ end
rescue Exception => e
if @ip.safe?
- nil # ignore
+ if @ip.respond_to?(:cb_error)
+ @ip.cb_error(e)
+ else
+ nil # ignore
+ end
else
fail e
end
@@ -161,6 +178,18 @@ class MultiTkIp
######################################
+ def set_cb_error(cmd = Proc.new)
+ @cb_error_proc[0] = cmd
+ end
+
+ def cb_error(e)
+ if @cb_error_proc[0].respond_to?(:call)
+ @cb_error_proc[0].call(e)
+ end
+ end
+
+ ######################################
+
def set_safe_level(safe)
if safe > @safe_level[0]
@safe_level[0] = safe
@@ -192,7 +221,7 @@ class MultiTkIp
end
def running_mainloop?
- @wait_on_mainloop[1]
+ @wait_on_mainloop[1] > 0
end
def _destroy_slaves_of_slaveIP(ip)
@@ -442,13 +471,21 @@ class MultiTkIp
private :_receiver_eval_proc, :_receiver_eval_proc_core
def _receiver_mainloop(check_root)
- Thread.new{
- while !@interp.deleted?
- inf = @interp._invoke_without_enc('info', 'command', '.')
- break if !inf.kind_of?(String) || inf != '.'
- sleep 0.5
- end
- }
+ if @evloop_thread[0] && @evloop_thread[0].alive?
+ @evloop_thread[0]
+ else
+ @evloop_thread[0] = Thread.new{
+ while !@interp.deleted?
+ #if check_root
+ # inf = @interp._invoke_without_enc('info', 'command', '.')
+ # break if !inf.kind_of?(String) || inf != '.'
+ #end
+ break if check_root && !@interp.has_mainwindow?
+ sleep 0.5
+ end
+ }
+ @evloop_thread[0]
+ end
end
def _create_receiver_and_watchdog(lvl = $SAFE)
@@ -456,7 +493,7 @@ class MultiTkIp
# command-procedures receiver
receiver = Thread.new(lvl){|safe_level|
- last_thread = nil
+ last_thread = {}
loop do
break if @interp.deleted?
@@ -479,8 +516,9 @@ class MultiTkIp
else
# procedure
- last_thread = _receiver_eval_proc(last_thread, safe_level,
- thread, cmd, *args)
+ last_thread[thread] = _receiver_eval_proc(last_thread[thread],
+ safe_level, thread,
+ cmd, *args)
end
end
}
@@ -539,6 +577,8 @@ class MultiTkIp
@slave_ip_top = {}.taint
+ @evloop_thread = [].taint
+
unless keys.kind_of? Hash
fail ArgumentError, "expecting a Hash object for the 2nd argument"
end
@@ -548,7 +588,7 @@ class MultiTkIp
@system = Object.new
- @wait_on_mainloop = [true, false]
+ @wait_on_mainloop = [true, 0].taint
@threadgroup = Thread.current.group
@@ -657,7 +697,7 @@ class MultiTkIp
######################################
- SAFE_OPT_LIST = [
+ @@SAFE_OPT_LIST = [
'accessPath'.freeze,
'statics'.freeze,
'nested'.freeze,
@@ -676,7 +716,7 @@ class MultiTkIp
name = v
elsif k_str == 'safe'
safe = v
- elsif SAFE_OPT_LIST.member?(k_str)
+ elsif @@SAFE_OPT_LIST.member?(k_str)
safe_opts[k_str] = v
else
tk_opts[k_str] = v
@@ -692,8 +732,8 @@ class MultiTkIp
private :_parse_slaveopts
def _create_slave_ip_name
- name = SLAVE_IP_ID.join('')
- SLAVE_IP_ID[1].succ!
+ name = @@SLAVE_IP_ID.join('')
+ @@SLAVE_IP_ID[1].succ!
name
end
private :_create_slave_ip_name
@@ -924,11 +964,15 @@ class MultiTkIp
@tk_table_list = []
@slave_ip_tbl = {}
@slave_ip_top = {}
+ @cb_error_proc = []
+ @evloop_thread = []
@tk_windows.taint unless @tk_windows.tainted?
@tk_table_list.taint unless @tk_table_list.tainted?
@slave_ip_tbl.taint unless @slave_ip_tbl.tainted?
@slave_ip_top.taint unless @slave_ip_top.tainted?
+ @cb_error_proc.taint unless @cb_error_proc.tainted?
+ @evloop_thread.taint unless @evloop_thread.tainted?
name, safe, safe_opts, tk_opts = _parse_slaveopts(keys)
@@ -975,7 +1019,8 @@ class MultiTkIp
@system = Object.new
- @wait_on_mainloop = [true, false]
+ @wait_on_mainloop = [true, 0].taint
+ # @wait_on_mainloop = [false, 0].taint
@threadgroup = ThreadGroup.new
@@ -1088,7 +1133,10 @@ class << MultiTkIp
end
ip = __new(__getip, nil, keys)
- ip.eval_proc(proc{$SAFE=ip.safe_level; Proc.new}.call) if block_given?
+ #ip.eval_proc(proc{$SAFE=ip.safe_level; Proc.new}.call) if block_given?
+ if block_given?
+ Thread.new{ip.eval_proc(proc{$SAFE=ip.safe_level; Proc.new}.call)}
+ end
ip
end
@@ -1109,7 +1157,10 @@ class << MultiTkIp
end
ip = __new(__getip, false, keys)
- ip.eval_proc(proc{$SAFE=ip.safe_level; Proc.new}.call) if block_given?
+ # ip.eval_proc(proc{$SAFE=ip.safe_level; Proc.new}.call) if block_given?
+ if block_given?
+ Thread.new{ip.eval_proc(proc{$SAFE=ip.safe_level; Proc.new}.call)}
+ end
ip
end
alias new_trusted_slave new_slave
@@ -1127,7 +1178,10 @@ class << MultiTkIp
end
ip = __new(__getip, true, keys)
- ip.eval_proc(proc{$SAFE=ip.safe_level; Proc.new}.call) if block_given?
+ # ip.eval_proc(proc{$SAFE=ip.safe_level; Proc.new}.call) if block_given?
+ if block_given?
+ Thread.new{ip.eval_proc(proc{$SAFE=ip.safe_level; Proc.new}.call)}
+ end
ip
end
alias new_safeTk new_safe_slave
@@ -1504,7 +1558,11 @@ class MultiTkIp
backup_ip = current['callback_ip']
current['callback_ip'] = self
begin
- eval_proc_core(false, cmd, safe_level, *args)
+ eval_proc_core(false,
+ proc{|safe, *params|
+ $SAFE=safe if $SAFE < safe
+ cmd.call(*params)
+ }, safe_level, *args)
ensure
current['callback_ip'] = backup_ip
end
@@ -1514,7 +1572,7 @@ class MultiTkIp
$SAFE=safe if $SAFE < safe
Thread.new(*params, &cmd).value
},
- *args)
+ safe_level, *args)
end
end
alias call eval_proc
@@ -1528,15 +1586,19 @@ class MultiTkIp
end
end
Thread.new{
+ eval_proc(cmd, *args)
+=begin
eval_proc_core(false,
proc{|safe, *params|
$SAFE=safe if $SAFE < safe
Thread.new(*params, &cmd).value
},
- *args)
+ safe_level, *args)
+=end
}
end
alias background_eval_proc bg_eval_proc
+ alias thread_eval_proc bg_eval_proc
alias bg_call bg_eval_proc
alias background_call bg_eval_proc
@@ -1550,7 +1612,7 @@ class MultiTkIp
proc{|safe|
$SAFE=safe if $SAFE < safe
Kernel.eval(cmd, *eval_args)
- })
+ }, safe_level)
end
alias eval_str eval_string
@@ -1564,7 +1626,7 @@ class MultiTkIp
proc{|safe|
$SAFE=safe if $SAFE < safe
Kernel.eval(cmd, *eval_args)
- })
+ }, safe_level)
}
end
alias background_eval_string bg_eval_string
@@ -1679,6 +1741,10 @@ class << MultiTkIp
__getip.deleted?
end
+ def has_mainwindow?
+ __getip.has_mainwindow?
+ end
+
def invalid_namespace?
__getip.invalid_namespace?
end
@@ -1860,22 +1926,24 @@ class MultiTkIp
if self != @@DEFAULT_MASTER
if @wait_on_mainloop[0]
begin
- @wait_on_mainloop[1] = true
- @cmd_queue.enq([@system, 'call_mainloop',
- Thread.current, check_root])
- Thread.stop
+ @wait_on_mainloop[1] += 1
+ if $SAFE >= 4
+ _receiver_mainloop(check_root).join
+ else
+ @cmd_queue.enq([@system, 'call_mainloop',
+ Thread.current, check_root])
+ Thread.stop
+ end
rescue MultiTkIp_OK => ret
# return value
- @wait_on_mainloop[1] = false
if ret.value.kind_of?(Thread)
return ret.value.value
else
return ret.value
end
- rescue SystemExit
+ rescue SystemExit => e
# exit IP
warn("Warning: " + $! + " on " + self.inspect) if $DEBUG
- @wait_on_mainloop[1] = false
begin
self._eval_without_enc('exit')
rescue Exception
@@ -1887,17 +1955,18 @@ class MultiTkIp
((e.message.length > 0)? ' "' + e.message + '"': '') +
" on " + self.inspect)
end
- @wait_on_mainloop[1] = false
return e
+ rescue Exception => e
+ return e
ensure
- @wait_on_mainloop[1] = false
+ @wait_on_mainloop[1] -= 1
end
end
return
end
unless restart_on_dead
- @wait_on_mainloop[1] = true
+ @wait_on_mainloop[1] += 1
=begin
begin
@interp.mainloop(check_root)
@@ -1909,11 +1978,13 @@ class MultiTkIp
end
end
=end
- @interp.mainloop(check_root)
- @wait_on_mainloop[1] = false
+ begin
+ @interp.mainloop(check_root)
+ ensure
+ @wait_on_mainloop[1] -= 1
+ end
else
loop do
- @wait_on_mainloop[1] = true
break unless self.alive?
if check_root
begin
@@ -1924,6 +1995,7 @@ class MultiTkIp
end
break if @interp.deleted?
begin
+ @wait_on_mainloop[1] += 1
@interp.mainloop(check_root)
rescue StandardError => e
if TclTkLib.mainloop_abort_on_exception != nil
@@ -1948,7 +2020,7 @@ class MultiTkIp
=end
raise e
ensure
- @wait_on_mainloop[1] = false
+ @wait_on_mainloop[1] -= 1
Thread.pass # avoid eventloop conflict
end
end
@@ -2040,6 +2112,10 @@ class MultiTkIp
@interp.deleted?
end
+ def has_mainwindow?
+ @interp.has_mainwindow?
+ end
+
def invalid_namespace?
@interp.invalid_namespace?
end
diff --git a/ext/tk/lib/remote-tk.rb b/ext/tk/lib/remote-tk.rb
index ed7f75b336..6e64a1ca2d 100644
--- a/ext/tk/lib/remote-tk.rb
+++ b/ext/tk/lib/remote-tk.rb
@@ -60,8 +60,6 @@ class << RemoteTkIp
end
class RemoteTkIp
- include TkUtil
-
def initialize(remote_ip, displayof=nil, timeout=5)
if $SAFE >= 4
fail SecurityError, "cannot access another interpreter at level #{$SAFE}"
@@ -96,7 +94,7 @@ class RemoteTkIp
@safe_level = [$SAFE]
- @wait_on_mainloop = [true, false]
+ @wait_on_mainloop = [true, 0]
@cmd_queue = Queue.new
@@ -179,7 +177,7 @@ class RemoteTkIp
fail SecurityError, "cannot send tainted commands at level #{$SAFE}"
end
- cmds = @interp._merge_tklist(*_conv_args([], enc_mode, *cmds))
+ cmds = @interp._merge_tklist(*TkUtil::_conv_args([], enc_mode, *cmds))
if @displayof
if async
@interp.__invoke('send', '-async', '-displayof', @displayof,
@@ -283,6 +281,19 @@ class RemoteTkIp
end
end
+ def has_mainwindow?
+ begin
+ inf = @interp._invoke_without_enc('info', 'command', '.')
+ rescue Exception
+ return nil
+ end
+ if !inf.kind_of?(String) || inf != '.'
+ false
+ else
+ true
+ end
+ end
+
def invalid_namespace?
false
end
@@ -343,25 +354,25 @@ class RemoteTkIp
def _get_variable(var_name, flag)
# ignore flag
- _appsend(false, 'set', _get_eval_string(var_name))
+ _appsend(false, 'set', TkComm::_get_eval_string(var_name))
end
def _get_variable2(var_name, index_name, flag)
# ignore flag
- _appsend(false, 'set', "#{_get_eval_string(var_name)}(#{_get_eval_string(index_name)})")
+ _appsend(false, 'set', "#{TkComm::_get_eval_string(var_name)}(#{TkComm::_get_eval_string(index_name)})")
end
def _set_variable(var_name, value, flag)
# ignore flag
- _appsend(false, 'set', _get_eval_string(var_name), _get_eval_string(value))
+ _appsend(false, 'set', TkComm::_get_eval_string(var_name), TkComm::_get_eval_string(value))
end
def _set_variable2(var_name, index_name, value, flag)
# ignore flag
- _appsend(false, 'set', "#{_get_eval_string(var_name)}(#{_get_eval_string(index_name)})", _get_eval_string(value))
+ _appsend(false, 'set', "#{TkComm::_get_eval_string(var_name)}(#{TkComm::_get_eval_string(index_name)})", TkComm::_get_eval_string(value))
end
def _unset_variable(var_name, flag)
# ignore flag
- _appsend(false, 'unset', _get_eval_string(var_name))
+ _appsend(false, 'unset', TkComm::_get_eval_string(var_name))
end
def _unset_variable2(var_name, index_name, flag)
# ignore flag
@@ -369,21 +380,21 @@ class RemoteTkIp
end
def _get_global_var(var_name)
- _appsend(false, 'set', _get_eval_string(var_name))
+ _appsend(false, 'set', TkComm::_get_eval_string(var_name))
end
def _get_global_var2(var_name, index_name)
- _appsend(false, 'set', "#{_get_eval_string(var_name)}(#{_get_eval_string(index_name)})")
+ _appsend(false, 'set', "#{TkComm::_get_eval_string(var_name)}(#{TkComm::_get_eval_string(index_name)})")
end
def _set_global_var(var_name, value)
- _appsend(false, 'set', _get_eval_string(var_name), _get_eval_string(value))
+ _appsend(false, 'set', TkComm::_get_eval_string(var_name), TkComm::_get_eval_string(value))
end
def _set_global_var2(var_name, index_name, value)
- _appsend(false, 'set', "#{_get_eval_string(var_name)}(#{_get_eval_string(index_name)})", _get_eval_string(value))
+ _appsend(false, 'set', "#{TkComm::_get_eval_string(var_name)}(#{TkComm::_get_eval_string(index_name)})", TkComm::_get_eval_string(value))
end
def _unset_global_var(var_name)
- _appsend(false, 'unset', _get_eval_string(var_name))
+ _appsend(false, 'unset', TkComm::_get_eval_string(var_name))
end
def _unset_global_var2(var_name, index_name)
_appsend(false, 'unset', "#{var_name}(#{index_name})")
diff --git a/ext/tk/lib/tk.rb b/ext/tk/lib/tk.rb
index 004e9e8f68..9f6290952e 100644
--- a/ext/tk/lib/tk.rb
+++ b/ext/tk/lib/tk.rb
@@ -1833,6 +1833,10 @@ module Tk
code
end
+ def Tk.has_mainwindow?
+ INTERP.has_mainwindow?
+ end
+
def root
TkRoot.new
end
@@ -4195,7 +4199,7 @@ end
#Tk.freeze
module Tk
- RELEASE_DATE = '2005-07-19'.freeze
+ RELEASE_DATE = '2005-07-22'.freeze
autoload :AUTO_PATH, 'tk/variable'
autoload :TCL_PACKAGE_PATH, 'tk/variable'
diff --git a/ext/tk/tkutil.c b/ext/tk/tkutil.c
index 464bbafa9c..496649f8c5 100644
--- a/ext/tk/tkutil.c
+++ b/ext/tk/tkutil.c
@@ -8,7 +8,7 @@
************************************************/
-#define TKUTIL_RELEASE_DATE "2005-07-05"
+#define TKUTIL_RELEASE_DATE "2005-07-22"
#include "ruby.h"
#include "rubysig.h"
@@ -892,14 +892,14 @@ tk_conv_args(argc, argv, self)
int thr_crit_bup;
VALUE old_gc;
+ if (argc < 2) {
+ rb_raise(rb_eArgError, "too few arguments");
+ }
+
thr_crit_bup = rb_thread_critical;
rb_thread_critical = Qtrue;
-
old_gc = rb_gc_disable();
- if (argc < 2) {
- rb_raise(rb_eArgError, "too few arguments");
- }
for(size = 0, idx = 2; idx < argc; idx++) {
if (TYPE(argv[idx]) == T_HASH) {
size += 2 * RHASH(argv[idx])->tbl->num_entries;
@@ -1605,6 +1605,7 @@ Init_tkutil()
tk_get_eval_string, -1);
rb_define_singleton_method(mTK, "_get_eval_enc_str",
tk_get_eval_enc_str, 1);
+ rb_define_singleton_method(mTK, "_conv_args", tk_conv_args, -1);
rb_define_singleton_method(mTK, "bool", tcl2rb_bool, 1);
rb_define_singleton_method(mTK, "number", tcl2rb_number, 1);