ruby-changes:20429
From: yugui <ko1@a...>
Date: Sat, 9 Jul 2011 20:12:49 +0900 (JST)
Subject: [ruby-changes:20429] yugui:r32477 (ruby_1_9_2): * ext/tk/extconf.rb: I gave up to fix the build issue of ext/tk with Windows
yugui 2011-07-09 20:12:34 +0900 (Sat, 09 Jul 2011) New Revision: 32477 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=32477 Log: * ext/tk/extconf.rb: I gave up to fix the build issue of ext/tk with Windows installer (mingw32). Ported whole ext/tk/extconf.rb from trunk. Modified files: branches/ruby_1_9_2/ChangeLog branches/ruby_1_9_2/ext/tk/extconf.rb branches/ruby_1_9_2/version.h Index: ruby_1_9_2/ChangeLog =================================================================== --- ruby_1_9_2/ChangeLog (revision 32476) +++ ruby_1_9_2/ChangeLog (revision 32477) @@ -1,3 +1,8 @@ +Sat Jul 9 19:25:02 2011 Yuki Sonoda (Yugui) <yugui@y...> + + * ext/tk/extconf.rb: I gave up to fix the build issue of ext/tk with Windows + installer (mingw32). Ported whole ext/tk/extconf.rb from trunk. + Mon Jul 4 00:28:05 2011 Yuki Sonoda (Yugui) <yugui@y...> * ext/tk/extconf.rb (find_tcl): fixed a TypeError on --with-opt-dir. Index: ruby_1_9_2/ext/tk/extconf.rb =================================================================== --- ruby_1_9_2/ext/tk/extconf.rb (revision 32476) +++ ruby_1_9_2/ext/tk/extconf.rb (revision 32477) @@ -5,12 +5,14 @@ require 'mkmf' TkLib_Config = {} -TkLib_Config['search_versions'] = +TkLib_Config['search_versions'] = # %w[8.9 8.8 8.7 8.6 8.5 8.4 8.3 8.2 8.1 8.0 7.6 4.2] # %w[8.7 8.6 8.5 8.4 8.3 8.2 8.1 8.0] %w[8.7 8.6 8.5 8.4 8.0] # to shorten search steps +TkLib_Config['major_nums'] = '87' + ############################################################## # use old extconf.rb ? ############################################################## @@ -26,7 +28,7 @@ ($cleanfiles ||= "") << 'config_list' config_list_file = 'config_list' config_list_file_source = File.join(File.dirname(__FILE__),'config_list.in') -if !File.exist?(config_list_file) || +if !File.exist?(config_list_file) || File.ctime(config_list_file_source) > File.ctime(config_list_file) old_config_list_file = config_list_file_source else @@ -92,7 +94,7 @@ else makefile = 'Makefile' - if File.exist?(makefile) && + if File.exist?(makefile) && File.ctime(config_list_file) > File.ctime(makefile) # no need to update Makefile exit @@ -118,20 +120,18 @@ def check_tcltk_version(version) return [nil, nil] unless version.kind_of? String - version = version.strip + tclver, tkver = version.split(',') + tclver = tclver.strip + return [tclver, tkver.strip] if tkver - tclver = version.dup - tkver = version.dup - dot = major = minor_dot = minor = plvl_dot = plvl = ext = nil - - if version =~ /^(\d)(\.?)(\d)(\.?)(\d*)(.*)$/ + if tclver =~ /^(\d)(\.?)(\d)(\.?)(\d*)(.*)$/ major = $1; minor_dot = $2; minor = $3; plvl_dot = $4; plvl = $5; ext = $6 dot = ! minor_dot.empty? if plvl_dot.empty? && ! plvl.empty? minor << plvl end - elsif version =~ /^(\d)(\.?)(\d?)(.*)$/ + elsif tclver =~ /^(\d)(\.?)(\d?)(.*)$/ major = $1; minor_dot = $2; minor = $3; ext = $4 dot = ! minor_dot.empty? else # unknown -> believe user @@ -144,9 +144,12 @@ tkver = "4" + ((dot)? ".": "") + ((minor.empty)? "": "2") + ext elsif major == "4" # Tk4.2 ( not support Tkversion < 4.2 ) # Tcl7.6 + tkver = tclver tclver = "7" + ((dot)? ".": "") + ((minor.empty)? "": "6") + ext end + tkver = tclver unless tkver + [tclver, tkver] end @@ -198,11 +201,13 @@ "c:/Tcl", "c:/Program Files/Tcl", "c:/Program Files (x86)/Tcl", "/Tcl", "/Program Files/Tcl", "/Program Files (x86)/Tcl" ] - path_head.each{|dir| path_dirs << File.expand_path(dir) if File.directory? dir } + path_head.uniq! + #path_head.each{|dir| path_dirs << dir.dup if File.directory? dir} + path_head.each{|dir| path_dirs << File.expand_path(dir) if File.directory? dir} # for MinGW ["/usr/local/lib64", "/usr/lib64", "/usr/local/lib", "/usr/lib"].each{|dir| - path_dirs << dir if File.directory? dir + #path_dirs << dir if File.directory? dir path_dirs << File.expand_path(dir) if File.directory? dir } path_dirs |= ENV['LIBRARY_PATH'].split(';').find_all{|dir| File.directory? dir}.map{|dir| File.expand_path(dir)} if ENV['LIBRARY_PATH'] @@ -210,13 +215,13 @@ else [ - '/opt', '/pkg', '/share', + '/opt', '/pkg', '/share', '/usr/local/opt', '/usr/local/pkg', '/usr/local/share', '/usr/local', '/usr/opt', '/usr/pkg', '/usr/share', '/usr/contrib', '/usr' ].each{|dir| next unless File.directory?(dir) - path_dirs << "#{dir}/lib64" + path_dirs << "#{dir}/lib64" if maybe_64bit? path_dirs << "#{dir}/lib" path_dirs << "#{dir}" unless Dir.glob("#{dir}/lib*.*", File::FNM_CASEFOLD).empty? @@ -282,7 +287,7 @@ end # framework is disabled? - if with_config("tcltk-framework") == false || + if with_config("tcltk-framework") == false || enable_config("tcltk-framework") == false return false end @@ -290,7 +295,7 @@ use_framework ||= (framework_dir = with_config("tcltk-framework")) if framework_dir.kind_of? String TkLib_Config["tcltk-framework"] = framework_dir.strip.chomp('/') - return [File.join(TkLib_Config["tcltk-framework"], 'Tcl.framework'), + return [File.join(TkLib_Config["tcltk-framework"], 'Tcl.framework'), File.join(TkLib_Config["tcltk-framework"], 'Tk.framework')] end @@ -301,7 +306,7 @@ end paths = [ - #"~/Library/Frameworks", + #"~/Library/Frameworks", "/Library/Frameworks", "/Network/Library/Frameworks", "/System/Library/Frameworks" ] @@ -319,7 +324,7 @@ def collect_tcltk_defs(tcl_defs_str, tk_defs_str) conflicts = [ - 'PACKAGE_NAME', 'PACKAGE_TARNAME', 'PACKAGE_VERSION', + 'PACKAGE_NAME', 'PACKAGE_TARNAME', 'PACKAGE_VERSION', 'PACKAGE_STRING', 'PACKAGE_BUGREPORT' ] @@ -361,7 +366,7 @@ defs.delete_if{|name,value| conflicts.include?(name) || - ( (vtcl = tcl_defs.assoc(name)) && (vtk = tk_defs.assoc(name)) && + ( (vtcl = tcl_defs.assoc(name)) && (vtk = tk_defs.assoc(name)) && vtcl != vtk ) } @@ -385,8 +390,8 @@ end def get_libpath(lib_flag, lib_spec) - # get libpath fro {TCL,Tk}_LIB_FLAG and {TCL,Tk}_LIB_SPEC - libpath = lib_spec.gsub(/(#{lib_flag}|-L)/, "").strip + # get libpath from {TCL,Tk}_LIB_FLAG and {TCL,Tk}_LIB_SPEC + lib_spec.gsub(/(#{lib_flag}|-L)/, "").strip end def get_tclConfig_dirs @@ -411,8 +416,8 @@ "/Tcl*/lib", "/Program Files*/Tcl*/lib" ] end - dirs.collect{|d| Dir.glob(d, File::FNM_CASEFOLD)}.flatten! - dirs |= dirs + dirs = dirs.collect{|d| Dir.glob(d, File::FNM_CASEFOLD)}.flatten.uniq + dirs |= ENV['LIBRARY_PATH'].split(';') if ENV['LIBRARY_PATH'] dirs |= ENV['PATH'].split(';') if ENV['PATH'] @@ -449,7 +454,7 @@ File.join(base, 'Tk.framework', 'Versions', 'Current') ] - Dir.glob(File.join(base, 'Tcl.framework', + Dir.glob(File.join(base, 'Tcl.framework', 'Versions', '*')).sort.reverse.each{|dir| next if dir =~ /Current/ config_dir << [dir, dir.gsub(/Tcl/, 'Tk')] @@ -460,23 +465,27 @@ end config_dir << RbConfig::CONFIG['libdir'] + ((maybe_64bit?)? ['lib64', 'lib']: ['lib']).each{|dir| config_dir.concat [ File.join(RbConfig::CONFIG['exec_prefix'], dir), - File.join(RbConfig::CONFIG['prefix'], dir), - "/usr/local/opt/#{dir}", "/usr/local/pkg/#{dir}", "/usr/local/share/#{dir}", - "/usr/local/#{dir}", "/usr/opt/#{dir}", "/usr/pkg/#{dir}", - "/usr/share/#{dir}", "/usr/contrib/#{dir}", "/usr/#{dir}" + File.join(RbConfig::CONFIG['prefix'], dir), + "/usr/local/opt/#{dir}", "/usr/local/pkg/#{dir}", + "/usr/local/share/#{dir}", "/usr/local/#{dir}", + "/usr/opt/#{dir}", "/usr/pkg/#{dir}", "/usr/share/#{dir}", + "/usr/contrib/#{dir}", "/usr/#{dir}" ] } config_dir.concat [ - '/opt', '/pkg', '/share', + '/opt', '/pkg', '/share', '/usr/local/opt', '/usr/local/pkg', '/usr/local/share', '/usr/local', '/usr/opt', '/usr/pkg', '/usr/share', '/usr/contrib', '/usr' ].map{|dir| - Dir.glob(dir + '/{tcltk,tcl,tk}[87]*/lib', File::FNM_CASEFOLD) - Dir.glob(dir + '/{tcltk,tcl,tk}[87]*', File::FNM_CASEFOLD) + Dir.glob(dir + "/{tcltk,tcl,tk}[#{TkLib_Config['major_nums']}*/lib", + File::FNM_CASEFOLD) + Dir.glob(dir + "/{tcltk,tcl,tk}[#{TkLib_Config['major_nums']}*", + File::FNM_CASEFOLD) Dir.glob(dir + '/{tcltk,tcl,tk}/lib', File::FNM_CASEFOLD) Dir.glob(dir + '/{tcltk,tcl,tk}', File::FNM_CASEFOLD) }.flatten! @@ -501,14 +510,14 @@ } paths = [ - #"~/Library/Frameworks", + #"~/Library/Frameworks", "/Library/Frameworks", "/Network/Library/Frameworks", "/System/Library/Frameworks" ] paths.reverse! unless TkLib_Config["ActiveTcl"] - paths.each{|framework| - base = File.expand_path(framework) + paths.each{|frmwk| + base = File.expand_path(frmwk) config_dir << [ File.join(base, 'Tcl.framework'), File.join(base, 'Tk.framework') ] @@ -518,7 +527,7 @@ File.join(base, 'Tk.framework', 'Versions', 'Current') ] - Dir.glob(File.join(base, 'Tcl.framework', + Dir.glob(File.join(base, 'Tcl.framework', 'Versions', '*')).sort.reverse.each{|dir| next if dir =~ /Current/ config_dir << [dir, dir.gsub(/Tcl/, 'Tk')] @@ -529,7 +538,25 @@ config_dir end -def libcheck_for_tclConfig(dir, tclconf, tkconf) +def get_ext_list() + exts = [CONFIG['DLEXT']] + exts.concat %w(dll lib) if is_win32? + exts.concat %w(bundle dylib) if is_macosx? || /nextstep|openstep|rhapsody/ =~ RUBY_PLATFORM + + if enable_config("shared") == false + [CONFIG['LIBEXT'], "a"].concat exts + else + exts.concat [CONFIG['LIBEXT'], "a"] + end + + if is_win32? + exts.map!{|ext| [ext.downcase, ext.upcase]}.flatten! + end + + exts +end + +def libcheck_for_tclConfig(tcldir, tkdir, tclconf, tkconf) tcllib_ok = tklib_ok = false if TkLib_Config["tcltk-stubs"] @@ -545,20 +572,39 @@ incflags = ($INCFLAGS ||= "").dup libpath = ($LIBPATH ||= []).dup libs_param = ($libs ||= "").dup - defs = ($defs ||= []).dup tcllibs = nil mkmf_param = nil - tcllib_ok ||= Dir.glob(File.join(dir, "*tcl#{stub}#{tclconf['TCL_MAJOR_VERSION']}{.,}#{tclconf['TCL_MINOR_VERSION']}*.*"), File::FNM_CASEFOLD).find{|file| - if file =~ /^.*(tcl#{stub}#{tclconf['TCL_MAJOR_VERSION']}(\.|)#{tclconf['TCL_MINOR_VERSION']}.*)\.([^.]*)$/ - libname, ext = $1, $2 + tclver, tkver = TkLib_Config["tcltkversion"] + exts = "(" + get_ext_list.join('|') + ")" + + if tclver + tcl_glob = "*tcl#{stub}#{tclver}.*" + tcl_regexp = /^.*(tcl#{stub}#{tclver}.*)\.(#{exts}).*$/ + elsif tclconf + tcl_glob = "*tcl#{stub}#{tclconf['TCL_MAJOR_VERSION']}{.,}#{tclconf['TCL_MINOR_VERSION']}*.*" + tcl_regexp = /^.*(tcl#{stub}#{tclconf['TCL_MAJOR_VERSION']}(?:\.|)#{tclconf['TCL_MINOR_VERSION']}.*)\.(#{exts}).*$/ + end + if tkver + tk_glob = "*tk#{stub}#{tkver}.*" + tk_regexp = /^.*(tk#{stub}#{tkver}.*)\.(#{exts}).*$/ + elsif tkconf + tk_glob = "*tk#{stub}#{tkconf['TK_MAJOR_VERSION']}{.,}#{tkconf['TK_MINOR_VERSION']}*.*" + tk_regexp = /^.*(tk#{stub}#{tkconf['TK_MAJOR_VERSION']}(?:\.|)#{tkconf['TK_MINOR_VERSION']}.*)\.#{exts}.*$/ + end + + tcllib_ok ||= !tclconf || Dir.glob(File.join(tcldir, tcl_glob), File::FNM_CASEFOLD).find{|file| + if file =~ tcl_regexp + libname = $1 + ext = $2.downcase begin $INCFLAGS = incflags.dup << " " << tclconf["TCL_INCLUDE_SPEC"] + #puts "check #{file} #{$1} #{tclfunc} #{tcldir}" + #find_library($1, tclfunc, tcldir) if (tclconf && tclconf["TCL_SHARED_BUILD"] == "0") || - (ext != CONFIG['DLEXT'] && ext == CONFIG['LIBEXT']) || ext == "a" + (ext != CONFIG['DLEXT'] && ext == CONFIG['LIBEXT']) || ext == "a" # static link - $defs << '-DSTATIC_BUILD' - tcllibs = $libs + " " + file.quote + tcllibs = $libs + " -DSTATIC_BUILD " + file.quote # FIX ME: avoid pathname trouble (fail to find) on MinGW. # e.g. TCL_INCLUDE_SPEC describes "-I/usr/local/include", @@ -566,14 +612,16 @@ $INCFLAGS << " -I" << File.join(File.dirname(File.dirname(file)),"include") if is_win32? else tcllibs = append_library($libs, libname) + tcllibs = "-L#{tcldir.quote} -Wl,-R#{tcldir.quote} " + tcllibs # FIX ME: avoid pathname trouble (fail to find) on MinGW. - $INCFLAGS << " -I" << File.join(File.dirname(dir),"include") if is_win32? + $INCFLAGS << " -I" << File.join(File.dirname(tcldir),"include") if is_win32? end - $LIBPATH = libpath | [dir] - try_func(tclfunc, tcllibs) + + $LIBPATH = libpath | [tcldir] try_func(tclfunc, tcllibs, ["tcl.h"]) || ( try_func(tclfunc, tcllibs << " " << tclconf['TCL_LIBS'], ["tcl.h"]) if tclconf['TCL_LIBS'] ) + ensure mkmf_param = { 'PATH' => file, @@ -584,38 +632,42 @@ } $LIBPATH = libpath.dup $libs = libs_param.dup - $defs = defs.dup end end } tclconf['MKMF_PARAMS'] = mkmf_param if tclconf && tcllib_ok - tklib_ok ||= Dir.glob(File.join(dir, "*tk#{stub}#{tkconf['TK_MAJOR_VERSION']}{.,}#{tkconf['TK_MINOR_VERSION']}*.*"), File::FNM_CASEFOLD).find{|file| - if file =~ /^.*(tk#{stub}#{tkconf['TK_MAJOR_VERSION']}(\.|)#{tkconf['TK_MINOR_VERSION']}.*)\.([^.]*)$/ - libname, ext = $1, $2 + tklib_ok ||= !tkconf || Dir.glob(File.join(tkdir, tk_glob), File::FNM_CASEFOLD).find{|file| + if file =~ tk_regexp + libname = $1 + ext = $2.downcase begin + #puts "check #{file} #{$1} #{tkfunc} #{tkdir}" + # find_library($1, tkfunc, tkdir) if (tkconf && tkconf["TCL_SHARED_BUILD"] == "0") || (ext != CONFIG['DLEXT'] && ext == CONFIG['LIBEXT']) || ext == "a" # static link - $defs << '-DSTATIC_BUILD' - tklibs = $libs + " " + file.quote + tklibs = " -DSTATIC_BUILD " + file.quote # FIX ME: avoid pathname trouble (fail to find) on MinGW. $INCFLAGS << " -I" << File.join(File.dirname(File.dirname(file)),"include") if is_win32? else tklibs = append_library("", libname) + #tklibs = append_library("", $1) + tklibs = "-L#{tkdir.quote} -Wl,-R#{tkdir.quote} " + tklibs # FIX ME: avoid pathname trouble (fail to find) on MinGW. - $INCFLAGS << " -I" << File.join(File.dirname(dir),"include") if is_win32? + $INCFLAGS << " -I" << File.join(File.dirname(tcldir),"include") if is_win32? end tklibs << " " << tcllibs if tcllibs tmp_tklibs = tklibs.dup - $LIBPATH = libpath | [dir] - try_func(tkfunc, tklibs) || + $LIBPATH = libpath | [tkdir] + try_func(tkfunc, tklibs, ["tcl.h", "tk.h"]) || ( try_func(tkfunc, tklibs << " " << tkconf['TK_LIBS'], ["tcl.h", "tk.h"]) if tkconf['TK_LIBS'] ) || ( try_func(tkfunc, (tklibs = tmp_tklibs.dup) << " " << tkconf['TK_XLIBSW'], ["tcl.h", "tk.h"]) if tkconf['TK_XLIBSW'] ) || ( try_func(tkfunc, tklibs << " " << tkconf['TK_LIBS'], ["tcl.h", "tk.h"]) if tkconf['TK_LIBS'] ) + ensure mkmf_param = { 'PATH' => file, @@ -626,7 +678,6 @@ } $LIBPATH = libpath.dup $libs = libs_param.dup - $defs = defs.dup end end } @@ -643,6 +694,16 @@ paths.compact! if paths.empty? config_dir = get_tclConfig_dirs + elsif paths.length == 1 && !paths[0][0] && !paths[0][1] + config_dir = get_tclConfig_dirs.map{|dir| + if dir.kind_of? Array + [ (paths[0][0] == false)? nil: dir[0], + (paths[0][1] == false)? nil: dir[1] ] + else + [ (paths[0][0] == false)? nil: dir, + (paths[0][1] == false)? nil: dir ] + end + } else # fixed tclConfig config_dir = [] @@ -657,12 +718,28 @@ end tclver, tkver = TkLib_Config['tcltkversion'] + if tclver && tclver =~ /^\D*(\d)\.?(\d)?/ # ignore PATCH_LEVEL + tclver_major = $1 + tclver_minor = $2 + else + tclver_major = nil + tclver_minor = nil + end + if tkver && tkver =~ /^\D*(\d)\.?(\d)?/ # ignore PATCH_LEVEL + tkver_major = $1 + tkver_minor = $2 + else + tkver_major = nil + tkver_minor = nil + end + conf = nil config_dir.uniq! config_dir.map{|dir| if dir.kind_of? Array - [dir[0].strip.chomp('/'), dir[1].strip.chomp('/')] + [ (dir[0])? dir[0].strip.chomp('/'): nil, + (dir[1])? dir[1].strip.chomp('/'): nil ] else dir.strip.chomp('/') end @@ -677,32 +754,51 @@ tails = ['Config-shared.sh', 'config-shared.sh', 'Config.sh', 'config.sh'] - if File.file?(tcldir) - tclcfg_files = [tcldir] * tails.length + if tcldir + if File.file?(tcldir) + tclcfg_files = [tcldir] * tails.length + else + tclcfg_files = tails.map{|f| File.join(tcldir, 'tcl' << f)} + end else - tclcfg_files = tails.map{|f| File.join(tcldir, 'tcl' << f)} + tclcfg_files = [nil] * tails.length end - if File.file?(tkdir) - tkcfg_files = [tkdir] * tails.length + if tkdir + if File.file?(tkdir) + tkcfg_files = [tkdir] * tails.length + else + tkcfg_files = tails.map{|f| File.join(tkdir, 'tk' << f)} + end else - tkcfg_files = tails.map{|f| File.join(tkdir, 'tk' << f)} + tkcfg_files = [nil] * tails.length end - tclcfg_files.zip(tkcfg_files).uniq.each{|tclpath, tkpath| - next if !File.exist?(tclpath) || !File.exist?(tkpath) + tclcfg_files.zip(tkcfg_files).map{|tclpath, tkpath| + [ (tclpath && File.exist?(tclpath))? File.expand_path(tclpath): tclpath, + (tkpath && File.exist?(tkpath))? File.expand_path(tkpath): tkpath ] + }.uniq.each{|tclpath, tkpath| + next if tclpath && !File.exist?(tclpath) + next if tkpath && !File.exist?(tkpath) # parse tclConfig.sh/tkConfig.sh - tclconf = parse_tclConfig(tclpath) - next if tclver && tclver !~ /^#{tclconf['TCL_MAJOR_VERSION']}(\.?)#{tclconf['TCL_MINOR_VERSION']}/ - tkconf = parse_tclConfig(tkpath) - next if tkver && tkver !~ /^#{tkconf['TK_MAJOR_VERSION']}(\.?)#{tkconf['TK_MINOR_VERSION']}/ + tclconf = (tclpath)? parse_tclConfig(tclpath): nil + next if tclconf && tclver && ((tclver_major && tclver_major != tclconf['TCL_MAJOR_VERSION']) || (tclver_minor && tclver_minor != tclconf['TCL_MINOR_VERSION'])) + tkconf = (tkpath)? parse_tclConfig(tkpath): nil + next if tkconf && tkver && ((tkver_major && tkver_major != tkconf['TK_MAJOR_VERSION']) || (tkver_minor && tkver_minor != tkconf['TK_MINOR_VERSION'])) + # nativethread check - if !TkLib_Config["ruby_with_thread"] && tclconf['TCL_THREADS'] == '1' - puts "\nWARNING: found #{tclpath.inspect}, but it WITH nativethread-support under ruby WITHOUT nativethread-support. So, ignore it." - TkLib_Config["tcltk-NG-path"] << File.dirname(tclpath) - next + if !TkLib_Config["ruby_with_thread"] + if tclconf + if tclconf['TCL_THREADS'] == '1' + puts "\nWARNING: found #{tclpath.inspect}, but it WITH nativethread-support under ruby WITHOUT nativethread-support. So, ignore it." + TkLib_Config["tcl-NG-path"] << File.dirname(tclpath) + next + end + else + puts "\nWARNING: When not refer tclConfig.sh, cannot check native-thread support on Tcl/Tk libraries. Ruby, which is used now, does NOT support native-thread. So, if Tcl/Tk libraries support native-thread, it will NOT work properly." + end end # find tclConfig.sh & tkConfig.sh @@ -713,51 +809,21 @@ # if use framework, not check (believe it is installed properly) tcllib_ok = tklib_ok = true else - tcllib_ok, tklib_ok = libcheck_for_tclConfig(File.dirname(tclpath), - tclconf, tkconf) -=begin - tclli (... truncated) -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/