summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/base64.rb2
-rw-r--r--lib/cgi-lib.rb56
-rw-r--r--lib/complex.rb490
-rw-r--r--lib/find.rb47
-rw-r--r--lib/getopts.rb173
-rw-r--r--lib/jcode.rb174
-rw-r--r--lib/mailread.rb19
-rw-r--r--lib/mathn.rb307
-rw-r--r--lib/observer.rb40
-rw-r--r--lib/parsearg.rb103
-rw-r--r--lib/rational.rb361
-rw-r--r--lib/safe.rb78
-rw-r--r--lib/thread.rb153
-rw-r--r--lib/tk.rb557
-rw-r--r--lib/tkcanvas.rb47
-rw-r--r--lib/tkcore.rb521
-rw-r--r--lib/tkentry.rb2
-rw-r--r--lib/tkscrollbox.rb27
-rw-r--r--lib/tktext.rb18
-rw-r--r--lib/tkthcore.rb546
20 files changed, 3036 insertions, 685 deletions
diff --git a/lib/base64.rb b/lib/base64.rb
index a6bf1adf92..9bb6487bee 100644
--- a/lib/base64.rb
+++ b/lib/base64.rb
@@ -46,7 +46,7 @@ def j2e(str)
end
def decode_b(str)
- str.gsub!(/=\?ISO-2022-JP\?B\?([!->@-~]+)\?=/) {
+ str.gsub!(/=\?ISO-2022-JP\?B\?([!->@-~]+)\?=/i) {
decode64($1)
}
str.gsub!(/\n/, ' ')
diff --git a/lib/cgi-lib.rb b/lib/cgi-lib.rb
new file mode 100644
index 0000000000..afadbff3b6
--- /dev/null
+++ b/lib/cgi-lib.rb
@@ -0,0 +1,56 @@
+#!/usr/local/bin/ruby
+#
+# Get CGI String
+#
+# EXAMPLE:
+# require "cgi-lib.rb"
+# foo = CGI.new
+# foo['field'] <== value of 'field'
+# foo.keys <== array of fields
+# foo.inputs <== hash of { <field> => <value> }
+
+class CGI
+ attr("inputs")
+
+ def initialize
+ str = if ENV['REQUEST_METHOD'] == "GET"
+ ENV['QUERY_STRING']
+ elsif ENV['REQUEST_METHOD'] == "POST"
+ $stdin.read ENV['CONTENT_LENGTH'].to_i
+ else
+ ""
+ end
+ arr = str.split(/&/)
+ @inputs = {}
+ arr.each do |x|
+ x.gsub!(/\+/, ' ')
+ key, val = x.split(/=/, 2)
+ val = "" unless val
+
+ key.gsub!(/%(..)/) { [$1.hex].pack("c") }
+ val.gsub!(/%(..)/) { [$1.hex].pack("c") }
+
+ @inputs[key] += "\0" if @inputs[key]
+ @inputs[key] += val
+ end
+ end
+
+ def keys
+ @inputs.keys
+ end
+
+ def [](key)
+ @inputs[key]
+ end
+
+ def CGI.message(msg, title = "")
+ print "Content-type: text/html\n\n"
+ print "<html><head><title>"
+ print title
+ print "</title></head><body>\n"
+ print msg
+ print "</body></html>\n"
+ TRUE
+ end
+
+end
diff --git a/lib/complex.rb b/lib/complex.rb
new file mode 100644
index 0000000000..aa5d219d2f
--- /dev/null
+++ b/lib/complex.rb
@@ -0,0 +1,490 @@
+#
+# complex.rb -
+# $Release Version: 0.5 $
+# $Revision: 1.1 $
+# $Date: 1996/11/11 04:25:19 $
+# by Keiju ISHITSUKA(SHL Japan Inc.)
+#
+# --
+# Usage:
+# class Complex < Numeric
+#
+# Complex(x, y) --> x + yi
+# y.im --> 0 + yi
+#
+# Complex::polar
+#
+# Complex::+
+# Complex::-
+# Complex::*
+# Complex::/
+# Complex::**
+# Complex::%
+# Complex::divmod
+# Complex::abs
+# Complex::abs2
+# Complex::arg
+# Complex::polar
+# Complex::conjugate
+# Complex::<=>
+# Complex::==
+# Complex::to_i
+# Complex::to_f
+# Complex::to_r
+# Complex::to_s
+#
+# Complex::I
+#
+# Numeric::im
+#
+# Math.sqrt
+# Math.exp
+# Math.cos
+# Math.sin
+# Math.tan
+# Math.log
+# Math.log10
+# Math.atan2
+#
+#
+
+def Complex(a, b = 0)
+ if a.kind_of?(Complex) and b == 0
+ a
+ elsif b == 0 and defined? Complex::Unify
+ a
+ else
+ Complex.new(a, b)
+ end
+end
+
+class Complex < Numeric
+
+ def Complex.generic?(other)
+ other.kind_of?(Integer) or
+ other.kind_of?(Float) or
+ (defined?(Rational) and other.kind_of?(Rational))
+ end
+
+ def Complex.polar(r, theta)
+ Complex(r*Math.cos(theta), r*Math.sin(theta))
+ end
+
+ def initialize(a, b = 0)
+ @real = a
+ @image = b
+ end
+
+ def + (other)
+ if other.kind_of?(Complex)
+ re = @real + other.real
+ im = @image + other.image
+ Complex(re, im)
+ elsif Complex.generic?(other)
+ Complex(@real + other, @image)
+ else
+ x , y = a.coerce(self)
+ x + y
+ end
+ end
+
+ def - (other)
+ if other.kind_of?(Complex)
+ re = @real - other.real
+ im = @image - other.image
+ Complex(re, im)
+ elsif Complex.generic?(other)
+ Complex(@real - other, @image)
+ else
+ x , y = a.coerce(self)
+ x - y
+ end
+ end
+
+ def * (other)
+ if other.kind_of?(Complex)
+ re = @real*other.real - @image*other.image
+ im = @real*other.image + @image*other.real
+ Complex(re, im)
+ elsif Complex.generic?(other)
+ Complex(@real * other, @image * other)
+ else
+ x , y = a.coerce(self)
+ x * y
+ end
+ end
+
+ def / (other)
+ if other.kind_of?(Complex)
+ self * other.conjugate / other.abs2
+ elsif Complex.generic?(other)
+ Complex(@real / other, @image / other)
+ else
+ x , y = a.coerce(self)
+ x / y
+ end
+ end
+
+ def ** (other)
+ if other == 0
+ return Complex(1)
+ end
+ if other.kind_of?(Complex)
+ r, theta = polar
+ ore = other.real
+ oim = other.image
+ nr = Math.exp!(ore*Math.log!(r) - oim * theta)
+ ntheta = theta*ore + oim*Math.log!(r)
+ Complex.polar(nr, ntheta)
+ elsif other.kind_of?(Integer)
+ if other > 0
+ x = self
+ z = x
+ n = other - 1
+ while n != 0
+ while (div, mod = n.divmod(2)
+ mod == 0)
+ x = Complex(x.real*x.real - x.image*x.image, 2*x.real*x.image)
+ n = div
+ end
+ z *= x
+ n -= 1
+ end
+ z
+ else
+ if defined? Rational
+ (Rational(1) / self) ** -other
+ else
+ self ** Float(other)
+ end
+ end
+ elsif Complex.generic?(other)
+ r, theta = polar
+ Complex.polar(r.power!(other), theta * other)
+ else
+ x , y = a.coerce(self)
+ x / y
+ end
+ end
+
+ def % (other)
+ if other.kind_of?(Complex)
+ Complex(@real % other.real, @image % other.image)
+ elsif Complex.generic?(other)
+ Complex(@real % other, @image % other)
+ else
+ x , y = a.coerce(self)
+ x % y
+ end
+ end
+
+ def divmod(other)
+ if other.kind_of?(Complex)
+ rdiv, rmod = @real.divmod(other.real)
+ idiv, imod = @image.divmod(other.image)
+ return Complex(rdiv, idiv), Complex(rmod, rdiv)
+ elsif Complex.generic?(other)
+ Complex(@real.divmod(other), @image.divmod(other))
+ else
+ x , y = a.coerce(self)
+ x.divmod(y)
+ end
+ end
+
+ def abs
+ Math.sqrt!((@real*@real + @image*@image).to_f)
+ end
+
+ def abs2
+ @real*@real + @image*@image
+ end
+
+ def arg
+ Math.atan2(@image.to_f, @real.to_f)
+ end
+
+ def polar
+ return abs, arg
+ end
+
+ def conjugate
+ Complex(@real, -@image)
+ end
+
+ def <=> (other)
+ self.abs <=> other.abs
+ end
+
+ def == (other)
+ if other.kind_of?(Complex)
+ @real == other.real and @image == other.image
+ elsif Complex.generic?(other)
+ @real == other and @image == 0
+ else
+ x , y = a.coerce(self)
+ x == y
+ end
+ end
+
+ def coerce(other)
+ if Complex.generic?(other)
+ return Complex.new(other), self
+ else
+ super
+ end
+ end
+
+ def to_i
+ Complex(@real.to_i, @image.to_i)
+ end
+
+ def to_f
+ Complex(@real.to_f, @image.to_f)
+ end
+
+ def to_r
+ Complex(@real.to_r, @image.to_r)
+ end
+
+ def denominator
+ @real.denominator.lcm(@image.denominator)
+ end
+
+ def numerator
+ cd = denominator
+ Complex(@real.numerator*(cd/@real.denominator),
+ @image.numerator*(cd/@image.denominator))
+ end
+
+ def to_s
+ if @real != 0
+ if defined?(Rational) and @image.kind_of?(Rational) and @image.denominator != 1
+ if @image >= 0
+ @real.to_s+"+("+@image.to_s+")i"
+ else
+ @real.to_s+"-("+(-@image).to_s+")i"
+ end
+ else
+ if @image >= 0
+ @real.to_s+"+"+@image.to_s+"i"
+ else
+ @real.to_s+"-"+(-@image).to_s+"i"
+ end
+ end
+ else
+ if defined?(Rational) and @image.kind_of?(Rational) and @image.denominator != 1
+ "("+@image.to_s+")i"
+ else
+ @image.to_s+"i"
+ end
+ end
+ end
+
+ def hash
+ @real ^ @image
+ end
+
+ I = Complex(0,1)
+
+ attr :real
+ attr :image
+
+end
+
+class Numeric
+ def im
+ Complex(0, self)
+ end
+
+ def real
+ self
+ end
+
+ def image
+ 0
+ end
+
+ def arg
+ if self >= 0
+ return 0
+ else
+ return Math.atan2(1,1)*4
+ end
+ end
+
+ def polar
+ return abs, arg
+ end
+
+ def conjugate
+ self
+ end
+end
+
+class Fixnum
+ if not defined? Rational
+ alias power! **
+ end
+
+ def ** (other)
+ if self < 0
+ Complex.new(self) ** other
+ else
+ if defined? Rational
+ if other >= 0
+ self.power!(other)
+ else
+ Rational.new!(self,1)**other
+ end
+ else
+ self.power!(other)
+ end
+ end
+ end
+end
+
+class Bignum
+ if not defined? Rational
+ alias power! **
+ end
+end
+
+class Float
+ alias power! **
+end
+
+module Math
+ alias sqrt! sqrt
+ alias exp! exp
+ alias cos! cos
+ alias sin! sin
+ alias tan! tan
+ alias log! log
+ alias log10! log10
+ alias atan2! atan2
+
+ def sqrt(z)
+ if Complex.generic?(z)
+ if z >= 0
+ sqrt!(z)
+ else
+ Complex(0,sqrt!(-z))
+ end
+ else
+ z**Rational(1,2)
+ end
+ end
+
+ def exp(z)
+ if Complex.generic?(z)
+ exp!(z)
+ else
+ Complex(exp!(z.real) * cos!(z.image), exp!(z.real) * sin!(z.image))
+ end
+ end
+
+ def cosh!(x)
+ (exp!(x) + exp!(-x))/2.0
+ end
+
+ def sinh!(x)
+ (exp!(x) - exp!(-x))/2.0
+ end
+
+ def cos(z)
+ if Complex.generic?(z)
+ cos!(z)
+ else
+ Complex(cos!(z.real)*cosh!(z.image),
+ sin!(z.real)*sinh!(z.image))
+ end
+ end
+
+ def sin(z)
+ if Complex.generic?(z)
+ sin!(z)
+ else
+ Complex(sin!(z.real)*cosh!(z.image),
+ -cos!(z.real)*sinh!(z.image))
+ end
+ end
+
+ def tan(z)
+ if Complex.generic?(z)
+ tan!(z)
+ else
+ sin(z)/cos(z)
+ end
+ end
+
+ def log(z)
+ if Complex.generic?(z) and z >= 0
+ log!(z)
+ else
+ r, theta = z.polar
+ Complex(log!(r.abs), theta)
+ end
+ end
+
+ def log10(z)
+ if Complex.generic?(z)
+ log10!(z)
+ else
+ log(z)/log!(10)
+ end
+ end
+
+ def atan2(x, y)
+ if Complex.generic?(x) and Complex.generic?(y)
+ atan2!(x, y)
+ else
+ fail "Not yet implemented."
+ end
+ end
+
+ def atanh!(x)
+ log((1.0 + x.to_f) / ( 1.0 - x.to_f)) / 2.0
+ end
+
+ def atan(z)
+ if Complex.generic?(z)
+ atan2!(z, 1)
+ elsif z.image == 0
+ atan2(z.real,1)
+ else
+ a = z.real
+ b = z.image
+
+ c = (a*a + b*b - 1.0)
+ d = (a*a + b*b + 1.0)
+
+ Complex(atan2!((c + sqrt(c*c + 4.0*a*a)), 2.0*a),
+ atanh!((-d + sqrt(d*d - 4.0*b*b))/(2.0*b)))
+ end
+ end
+
+ module_function :sqrt
+ module_function :sqrt!
+ module_function :exp!
+ module_function :exp
+ module_function :cosh!
+ module_function :cos!
+ module_function :cos
+ module_function :sinh!
+ module_function :sin!
+ module_function :sin
+ module_function :tan!
+ module_function :tan
+ module_function :log!
+ module_function :log
+ module_function :log10!
+ module_function :log
+ module_function :atan2!
+ module_function :atan2
+# module_function :atan!
+ module_function :atan
+ module_function :atanh!
+
+end
+
+
diff --git a/lib/find.rb b/lib/find.rb
index 340461c653..5ecc54329c 100644
--- a/lib/find.rb
+++ b/lib/find.rb
@@ -8,31 +8,32 @@
#
module Find
- extend Find
-
- def findpath(path, ary)
- ary.push(path)
- d = Dir.open(path)
- for f in d
- continue if f =~ /^\.\.?$/
- f = path + "/" + f
- if File.directory? f
- findpath(f, ary)
- else
- ary.push(f)
- end
+ def find(*path)
+ while file = path.shift
+ catch(:prune) {
+ yield file
+ if File.directory? file and not File.symlink? file then
+ d = Dir.open(file)
+ begin
+ for f in d
+ next if f =~ /^\.\.?$/
+ if file == "/" then
+ f = "/" + f
+ else
+ f = file + "/" + f
+ end
+ path.unshift f
+ end
+ ensure
+ d.close
+ end
+ end
+ }
end
end
- private :findpath
- def find(*path)
- ary = []
- for p in path
- findpath(p, ary)
- for f in ary
- yield f
- end
- end
+ def prune
+ throw :prune
end
- module_function :find
+ module_function :find, :prune
end
diff --git a/lib/getopts.rb b/lib/getopts.rb
index 37fd3dc69d..d25437515d 100644
--- a/lib/getopts.rb
+++ b/lib/getopts.rb
@@ -1,117 +1,142 @@
+#!/usr/local/bin/ruby
#
-# getopts.rb - get options
+# getopts.rb -
# $Release Version: $
-# $Revision: 1.2 $
-# $Date: 1994/02/15 05:17:15 $
-# by Yasuo OHBA(STAFS Development Room)
+# $Revision: 1.1 $
+# $Date: 1996/11/10 05:01:15 $
+# by Yasuo OHBA(SHL Japan Inc. Technology Dept.)
#
# --
-# オプションの解析をし, $OPT_?? に値をセットします.
-# 指定のないオプションが指定された時は nil を返します.
-# 正常終了した場合は, セットされたオプションの数を返します.
#
-# getopts(single_opts, *opts)
-#
-# ex. sample [options] filename
-# options ...
-# -f -x --version --geometry 100x200 -d unix:0.0
-# ↓
-# getopts("fx", "version", "geometry:", "d:")
-#
-# 第一引数:
-# -f や -x (= -fx) の様な一文字のオプションの指定をします.
-# ここで引数がないときは nil の指定が必要です.
-# 第二引数以降:
-# ロングネームのオプションや, 引数の伴うオプションの指定をします.
-# --version や, --geometry 300x400 や, -d host:0.0 等です.
-# 引数を伴う指定は ":" を必ず付けてください.
-#
-# オプションの指定があった場合, 変数 $OPT_?? に non-nil もしくは, そのオ
-# プションの引数がセットされます.
-# -f -> $OPT_f = TRUE
-# --geometry 300x400 -> $OPT_geometry = 300x400
-#
-# - もしくは -- は, それ以降, 全てオプションの解析をしません.
+#
#
-$RCS_ID="$Header: /var/ohba/RCS/getopts.rb,v 1.2 1994/02/15 05:17:15 ohba Exp ohba $"
+$RCS_ID="$Header: /home/jammy/current/ruby/RCS/getopts.rb,v 1.1 1996/11/10 05:01:15 jammy Exp $"
+
+def isSingle(lopt)
+ if lopt.index(":")
+ if lopt.split(":")[0].length == 1
+ return TRUE
+ end
+ end
+ return nil
+end
+
+def getOptionName(lopt)
+ return lopt.split(":")[0]
+end
+
+def getDefaultOption(lopt)
+ od = lopt.split(":")[1]
+ if od
+ return od
+ end
+ return nil
+end
+
+def setOption(name, value)
+ eval("$OPT_" + name + " = " + 'value')
+end
+
+def setDefaultOption(lopt)
+ d = getDefaultOption(lopt)
+ if d
+ setOption(getOptionName(lopt), d)
+ end
+end
+
+def setNewArgv(newargv)
+ ARGV.clear
+ for na in newargv
+ ARGV << na
+ end
+end
-def getopts(single_opts, *opts)
- if (opts)
+
+def getopts(single_opts, *options)
+ if options
single_colon = ""
long_opts = []
sc = 0
- for option in opts
- if (option.length <= 2)
- single_colon[sc, 0] = option[0, 1]
+ for o in options
+ setDefaultOption(o)
+ if isSingle(o)
+ single_colon[sc, 0] = getOptionName(o)
sc += 1
else
- long_opts.push(option)
+ long_opts.push(o)
end
end
end
-
+
opts = {}
count = 0
- while ($ARGV.length != 0)
+ newargv = []
+ while ARGV.length != 0
compare = nil
- case $ARGV[0]
+ case ARGV[0]
when /^--?$/
- $ARGV.shift
+ ARGV.shift
+ newargv += ARGV
break
when /^--.*/
- compare = $ARGV[0][2, ($ARGV[0].length - 2)]
- if (long_opts != "")
- for option in long_opts
- if (option[(option.length - 1), 1] == ":" &&
- option[0, (option.length - 1)] == compare)
- if ($ARGV.length <= 1)
+ compare = ARGV[0][2, (ARGV[0].length - 2)]
+ if long_opts != ""
+ for lo in long_opts
+ if lo.index(":") && getOptionName(lo) == compare
+ if ARGV.length <= 1
return nil
- end
- eval("$OPT_" + compare + " = " + '$ARGV[1]')
- opts[compare] = TRUE
- $ARGV.shift
+ end
+ setOption(compare, ARGV[1])
+ opts[compare] = TRUE
+ ARGV.shift
count += 1
break
- elsif (option == compare)
- eval("$OPT_" + compare + " = TRUE")
- opts[compare] = TRUE
+ elsif lo == compare
+ setOption(compare, TRUE)
+ opts[compare] = TRUE
count += 1
- break
- end
- end
+ break
+ end
+ end
+ end
+ if compare.length <= 1
+ return nil
end
when /^-.*/
- for index in 1..($ARGV[0].length - 1)
- compare = $ARGV[0][index, 1]
- if (single_opts && compare =~ "[" + single_opts + "]")
- eval("$OPT_" + compare + " = TRUE")
- opts[compare] = TRUE
+ for idx in 1..(ARGV[0].length - 1)
+ compare = ARGV[0][idx, 1]
+ if single_opts && compare =~ "[" + single_opts + "]"
+ setOption(compare, TRUE)
+ opts[compare] = TRUE
count += 1
- elsif (single_colon != "" && compare =~ "[" + single_colon + "]")
- if ($ARGV[0][index..-1].length > 1)
- eval("$OPT_" + compare + " = " + '$ARGV[0][(index + 1)..-1]')
- opts[compare] = TRUE
+ elsif single_colon != "" && compare =~ "[" + single_colon + "]"
+ if ARGV[0][idx..-1].length > 1
+ setOption(compare, ARGV[0][(idx + 1)..-1])
+ opts[compare] = TRUE
count += 1
- elsif ($ARGV.length <= 1)
+ elsif ARGV.length <= 1
return nil
else
- eval("$OPT_" + compare + " = " + '$ARGV[1]')
- opts[compare] = TRUE
- $ARGV.shift
- count = count + 1
+ setOption(compare, ARGV[1])
+ opts[compare] = TRUE
+ ARGV.shift
+ count += 1
end
break
end
end
else
- break
+ compare = ARGV[0]
+ opts[compare] = TRUE
+ newargv << ARGV[0]
end
-
- $ARGV.shift
- if (!opts.includes(compare))
+
+ ARGV.shift
+ if !opts.has_key?(compare)
return nil
end
end
+ setNewArgv(newargv)
return count
end
diff --git a/lib/jcode.rb b/lib/jcode.rb
new file mode 100644
index 0000000000..5b2289932f
--- /dev/null
+++ b/lib/jcode.rb
@@ -0,0 +1,174 @@
+# jcode.rb - ruby code to handle japanese (EUC/SJIS) string
+
+class String
+ printf STDERR, "feel free for some warnings:\n" if $VERBOSE
+
+ alias original_succ succ
+ private :original_succ
+
+ def succ
+ if self[-2] && self[-2] & 0x80 != 0
+ s = self.dup
+ s[-1] += 1
+ return s
+ else
+ original_succ
+ end
+ end
+
+ def upto(to)
+ return if self > to
+
+ curr = self
+ tail = self[-2..-1]
+ if tail.length == 2 and tail =~ /^.$/ then
+ if self[0..-2] == to[0..-2]
+ for c in self[-1] .. to[-1]
+ yield self[0..-2]+c.chr
+ end
+ end
+ else
+ loop do
+ yield curr
+ return if curr == to
+ curr = curr.succ
+ return if curr.length > to.length
+ end
+ end
+ return nil
+ end
+
+ def _expand_ch
+ a = []
+ self.scan(/(.|\n)-(.|\n)|(.|\n)/) do |r|
+ if $3
+ a.push $3
+ elsif $1.length != $2.length
+ next
+ elsif $1.length == 1
+ $1[0].upto($2[0]) { |c| a.push c.chr }
+ else
+ $1.upto($2) { |c| a.push c }
+ end
+ end
+ a
+ end
+
+ def tr!(from, to)
+ return self.delete!(from) if to.length == 0
+
+ if from =~ /^\^/
+ comp=TRUE
+ from = $'
+ end
+ afrom = from._expand_ch
+ ato = to._expand_ch
+ i = 0
+ if comp
+ self.gsub!(/(.|\n)/) do |c|
+ unless afrom.include?(c)
+ ato[-1]
+ else
+ c
+ end
+ end
+ else
+ self.gsub!(/(.|\n)/) do |c|
+ if i = afrom.index(c)
+ if i < ato.size then ato[i] else ato[-1] end
+ else
+ c
+ end
+ end
+ end
+ end
+
+ def tr(from, to)
+ self.dup.tr!(from, to)
+ end
+
+ def delete!(del)
+ if del =~ /^\^/
+ comp=TRUE
+ del = $'
+ end
+ adel = del._expand_ch
+ if comp
+ self.gsub!(/(.|\n)/) do |c|
+ next unless adel.include?(c)
+ c
+ end
+ else
+ self.gsub!(/(.|\n)/) do |c|
+ next if adel.include?(c)
+ c
+ end
+ end
+ end
+
+ def delete(del)
+ self.dup.delete!(del)
+ end
+
+ def squeeze!(del=nil)
+ if del
+ if del =~ /^\^/
+ comp=TRUE
+ del = $'
+ end
+ adel = del._expand_ch
+ if comp
+ self.gsub!(/(.|\n)\1+/) do
+ next unless adel.include?($1)
+ $&
+ end
+ else
+ for c in adel
+ cq = Regexp.quote(c)
+ self.gsub!(/#{cq}(#{cq})+/, cq)
+ end
+ end
+ self
+ else
+ self.gsub!(/(.|\n)\1+/, '\1')
+ end
+ end
+
+ def squeeze(del=nil)
+ self.dup.squeeze!(del)
+ end
+
+ def tr_s!(from, to)
+ return self.delete!(from) if to.length == 0
+ if from =~ /^\^/
+ comp=TRUE
+ from = $'
+ end
+ afrom = from._expand_ch
+ ato = to._expand_ch
+ i = 0
+ c = nil
+ last = nil
+ self.gsub!(/(.|\n)/) do |c|
+ if comp
+ unless afrom.include?(c)
+ ato[-1]
+ else
+ c
+ end
+ elsif i = afrom.index(c)
+ c = if i < ato.size then ato[i] else ato[-1] end
+ next if c == last
+ last = c
+ else
+ last = nil
+ c
+ end
+ end
+ end
+
+ def tr_s(from, to)
+ self.dup.tr_s!(from,to)
+ end
+
+end
diff --git a/lib/mailread.rb b/lib/mailread.rb
index 4b04445beb..d9feffbb7a 100644
--- a/lib/mailread.rb
+++ b/lib/mailread.rb
@@ -1,9 +1,8 @@
class Mail
-
def Mail.new(f)
- if !f.is_kind_of?(IO)
+ unless f.kind_of?(IO)
f = open(f, "r")
- me = super
+ me = super(f)
f.close
else
me = super
@@ -16,17 +15,18 @@ class Mail
@body = []
while f.gets()
$_.chop!
- continue if /^From / # skip From-line
+ next if /^From / # skip From-line
break if /^$/ # end of header
+
if /^(\S+):\s*(.*)/
- @header[attr = $1.capitalize] = $2
+ @header[attr = $1.capitalize!] = $2
elsif attr
- sub(/^\s*/, '')
+ sub!(/^\s*/, '')
@header[attr] += "\n" + $_
end
end
-
- return if ! $_
+
+ return unless $_
while f.gets()
break if /^From /
@@ -42,4 +42,7 @@ class Mail
return @body
end
+ def [](field)
+ @header[field]
+ end
end
diff --git a/lib/mathn.rb b/lib/mathn.rb
new file mode 100644
index 0000000000..359cb45769
--- /dev/null
+++ b/lib/mathn.rb
@@ -0,0 +1,307 @@
+#
+# mathn.rb -
+# $Release Version: 0.5 $
+# $Revision: 1.1 $
+# $Date: 1996/11/11 04:25:24 $
+# by Keiju ISHITSUKA(SHL Japan Inc.)
+#
+# --
+#
+#
+#
+
+require "rational.rb"
+require "complex.rb"
+
+class Integer
+
+ def gcd2(int)
+ a = self.abs
+ b = int.abs
+ a, b = b, a if a < b
+
+ pd_a = a.prime_division
+ pd_b = b.prime_division
+
+ gcd = 1
+ for pair in pd_a
+ as = pd_b.assoc(pair[0])
+ if as
+ gcd *= as[0] ** [as[1], pair[1]].min
+ end
+ end
+ return gcd
+ end
+
+ def Integer.from_prime_division(pd)
+ value = 1
+ for prime, index in pd
+ value *= prime**index
+ end
+ value
+ end
+
+ def prime_division
+ ps = Prime.new
+ value = self
+ pv = []
+ for prime in ps
+ count = 0
+ while (value1, mod = value.divmod(prime)
+ mod) == 0
+ value = value1
+ count += 1
+ end
+ if count != 0
+ pv.push [prime, count]
+ end
+ break if prime * prime >= value
+ end
+ if value > 1
+ pv.push [value, 1]
+ end
+ return pv
+ end
+end
+
+class Prime
+ include Enumerable
+
+ def initialize
+ @seed = 1
+ @primes = []
+ @counts = []
+ end
+
+ def succ
+ i = -1
+ size = @primes.size
+ while i < size
+ if i == -1
+ @seed += 1
+ i += 1
+ else
+ while @seed > @counts[i]
+ @counts[i] += @primes[i]
+ end
+ if @seed != @counts[i]
+ i += 1
+ else
+ i = -1
+ end
+ end
+ end
+ @primes.push @seed
+ @counts.push @seed + @seed
+ return @seed
+ end
+
+ def each
+ loop do
+ yield succ
+ end
+ end
+end
+
+class Fixnum
+ alias divmod! divmod
+ alias / rdiv
+ def divmod(other)
+ a = self.div(other)
+ b = self % other
+ return a,b
+ end
+end
+
+class Bignum
+ alias divmod! divmod
+ alias / rdiv
+end
+
+class Rational
+ Unify = TRUE
+
+ alias power! **
+
+ def ** (other)
+ if other.kind_of?(Rational)
+ if self < 0
+ return Complex(self, 0) ** other
+ elsif other == 0
+ return Rational(1,1)
+ elsif self == 0
+ return Rational(0,1)
+ elsif self == 1
+ return Rational(1,1)
+ end
+
+ npd = @numerator.prime_division
+ dpd = @denominator.prime_division
+ if other < 0
+ other = -other
+ npd, dpd = dpd, npd
+ end
+
+ for elm in npd
+ elm[1] = elm[1] * other
+ if !elm[1].kind_of?(Integer) and elm[1].denominator != 1
+ return Float(self) ** other
+ end
+ elm[1] = elm[1].to_i
+ end
+
+ for elm in dpd
+ elm[1] = elm[1] * other
+ if !elm[1].kind_of?(Integer) and elm[1].denominator != 1
+ return Float(self) ** other
+ end
+ elm[1] = elm[1].to_i
+ end
+
+ num = Integer.from_prime_division(npd)
+ den = Integer.from_prime_division(dpd)
+
+ Rational(num,den)
+
+ elsif other.kind_of?(Integer)
+ if other > 0
+ num = @numerator ** other
+ den = @denominator ** other
+ elsif other < 0
+ num = @denominator ** -other
+ den = @numerator ** -other
+ elsif other == 0
+ num = 1
+ den = 1
+ end
+ Rational.new!(num, den)
+ elsif other.kind_of?(Float)
+ Float(self) ** other
+ else
+ x , y = other.coerce(self)
+ x ** y
+ end
+ end
+
+ def power2(other)
+ if other.kind_of?(Rational)
+ if self < 0
+ return Complex(self, 0) ** other
+ elsif other == 0
+ return Rational(1,1)
+ elsif self == 0
+ return Rational(0,1)
+ elsif self == 1
+ return Rational(1,1)
+ end
+
+ dem = nil
+ x = self.denominator.to_f.to_i
+ neard = self.denominator.to_f ** (1.0/other.denominator.to_f)
+ loop do
+ if (neard**other.denominator == self.denominator)
+ dem = neaed
+ break
+ end
+ end
+ nearn = self.numerator.to_f ** (1.0/other.denominator.to_f)
+ Rational(num,den)
+
+ elsif other.kind_of?(Integer)
+ if other > 0
+ num = @numerator ** other
+ den = @denominator ** other
+ elsif other < 0
+ num = @denominator ** -other
+ den = @numerator ** -other
+ elsif other == 0
+ num = 1
+ den = 1
+ end
+ Rational.new!(num, den)
+ elsif other.kind_of?(Float)
+ Float(self) ** other
+ else
+ x , y = other.coerce(self)
+ x ** y
+ end
+ end
+end
+
+module Math
+ def sqrt(a)
+ if a.kind_of?(Complex)
+ abs = sqrt(a.real*a.real + a.image*a.image)
+# if not abs.kind_of?(Rational)
+# return a**Rational(1,2)
+# end
+ x = sqrt((a.real + abs)/Rational(2))
+ y = sqrt((-a.real + abs)/Rational(2))
+# if !(x.kind_of?(Rational) and y.kind_of?(Rational))
+# return a**Rational(1,2)
+# end
+ if a.image >= 0
+ Complex(x, y)
+ else
+ Complex(x, -y)
+ end
+ elsif a >= 0
+ rsqrt(a)
+ else
+ Complex(0,rsqrt(-a))
+ end
+ end
+
+ def rsqrt(a)
+ if a.kind_of?(Float)
+ sqrt!(a)
+ elsif a.kind_of?(Rational)
+ rsqrt(a.numerator)/rsqrt(a.denominator)
+ else
+ src = a
+ max = 2 ** 32
+ byte_a = [src & 0xffffffff]
+ # ruby's bug
+ while (src >= max) and (src >>= 32)
+ byte_a.unshift src & 0xffffffff
+ end
+
+ answer = 0
+ main = 0
+ side = 0
+ for elm in byte_a
+ main = (main << 32) + elm
+ side <<= 16
+ if answer != 0
+ if main * 4 < side * side
+ applo = main.div(side)
+ else
+ applo = ((sqrt!(side * side + 4 * main) - side)/2.0).to_i + 1
+ end
+ else
+ applo = sqrt!(main).to_i + 1
+ end
+
+ while (x = (side + applo) * applo) > main
+ applo -= 1
+ end
+ main -= x
+ answer = (answer << 16) + applo
+ side += applo * 2
+ end
+ if main == 0
+ answer
+ else
+ sqrt!(a)
+ end
+ end
+ end
+
+ module_function :sqrt
+ module_function :rsqrt
+end
+
+class Complex
+ Unify = TRUE
+end
+
diff --git a/lib/observer.rb b/lib/observer.rb
new file mode 100644
index 0000000000..9a753939a2
--- /dev/null
+++ b/lib/observer.rb
@@ -0,0 +1,40 @@
+# Observable Mixin
+#
+# Observers must respond to update
+
+module Observable
+ def add_observer(observer)
+ @observer_peers = [] unless @observer_peers
+ unless defined? observer.update
+ raise NameError, "observer needs to respond to `update'"
+ end
+ @observer_peers.push observer
+ end
+ def delete_observer(observer)
+ @observer_peers.delete observer if @observer_peers
+ end
+ def delete_observers
+ @observer_peers.clear if @observer_peers
+ end
+ def count_observers
+ if @observer_peers
+ @observer_peers.size
+ else
+ 0
+ end
+ end
+ def changed(state=TRUE)
+ @observer_state = state
+ end
+ def changed?
+ @observer_state
+ end
+ def notify_observers(*arg)
+ if @observer_state
+ for i in @observer_peers
+ i.update(*arg)
+ end
+ @observer_state = FALSE
+ end
+ end
+end
diff --git a/lib/parsearg.rb b/lib/parsearg.rb
index e7e2b7a7f3..569ed260f7 100644
--- a/lib/parsearg.rb
+++ b/lib/parsearg.rb
@@ -1,68 +1,83 @@
+#!/usr/local/bin/ruby
#
-# parseargs.rb - parse arguments
+# parsearg.rb - parse arguments
# $Release Version: $
# $Revision: 1.3 $
-# $Date: 1994/02/15 05:16:21 $
-# by Yasuo OHBA(STAFS Development Room)
+# $Date: 1996/11/12 06:48:51 $
+# by Yasuo OHBA(SHL Japan Inc. Technology Dept.)
#
# --
-# 引数の解析をし, $OPT_?? に値をセットします.
-# 正常終了した場合は, セットされたオプションの数を返します.
#
-# parseArgs(argc, single_opts, *opts)
-#
-# ex. sample [options] filename
-# options ...
-# -f -x --version --geometry 100x200 -d unix:0.0
-# ↓
-# parseArgs(1, nil, "fx", "version", "geometry:", "d:")
-#
-# 第一引数:
-# オプション以外の最低引数の数
-# 第二引数:
-# オプションの必要性…必ず必要なら %TRUE そうでなければ %FALSE.
-# 第三引数:
-# -f や -x (= -fx) の様な一文字のオプションの指定をします.
-# ここで引数がないときは nil の指定が必要です.
-# 第四引数以降:
-# ロングネームのオプションや, 引数の伴うオプションの指定をします.
-# --version や, --geometry 300x400 や, -d host:0.0 等です.
-# 引数を伴う指定は ":" を必ず付けてください.
-#
-# オプションの指定があった場合, 変数 $OPT_?? に non-nil もしくは, そのオ
-# プションの引数がセットされます.
-# -f -> $OPT_f = %TRUE
-# --geometry 300x400 -> $OPT_geometry = 300x400
-#
-# usage を使いたい場合は, $USAGE に usage() を指定します.
-# def usage()
-# …
-# end
-# $USAGE = 'usage'
-# usage は, --help が指定された時, 間違った指定をした時に表示します.
-#
-# - もしくは -- は, それ以降, 全てオプションの解析をしません.
+#
#
-$RCS_ID="$Header: /var/ohba/RCS/parseargs.rb,v 1.3 1994/02/15 05:16:21 ohba Exp ohba $"
+$RCS_ID="$Header: /home/jammy/current/ruby/RCS/parsearg.rb,v 1.3 1996/11/12 06:48:51 jammy Exp $"
load("getopts.rb")
def printUsageAndExit()
if $USAGE
- apply($USAGE)
+ eval($USAGE)
end
exit()
end
+def setParenthesis(ex, opt, c)
+ if opt != ""
+ ex = sprintf("%s$OPT_%s%s", ex, opt, c)
+ else
+ ex = sprintf("%s%s", ex, c)
+ end
+ return ex
+end
+
+def setOrAnd(ex, opt, c)
+ if opt != ""
+ ex = sprintf("%s$OPT_%s %s%s ", ex, opt, c, c)
+ else
+ ex = sprintf("%s %s%s ", ex, c, c)
+ end
+ return ex
+end
+
+def setExpression(ex, opt, op)
+ if !op
+ ex = sprintf("%s$OPT_%s", ex, opt)
+ return ex
+ end
+ case op.chr
+ when "(", ")"
+ ex = setParenthesis(ex, opt, op.chr)
+ when "|", "&"
+ ex = setOrAnd(ex, opt, op.chr)
+ else
+ return nil
+ end
+ return ex
+end
+
def parseArgs(argc, nopt, single_opts, *opts)
- if ((noOptions = getopts(single_opts, *opts)) == nil)
+ if (noOptions = getopts(single_opts, *opts)) == nil
printUsageAndExit()
end
- if (nopt && noOptions == 0)
- printUsageAndExit()
+ if nopt
+ ex = nil
+ pos = 0
+ for o in nopt.split(/[()|&]/)
+ pos += o.length
+ ex = setExpression(ex, o, nopt[pos])
+ pos += 1
+ end
+ begin
+ if !eval(ex)
+ printUsageAndExit()
+ end
+ rescue
+ print "Format Error!! : \"" + nopt + "\"\t[parseArgs]\n"
+ exit! -1
+ end
end
- if ($ARGV.length < argc)
+ if ARGV.length < argc
printUsageAndExit()
end
return noOptions
diff --git a/lib/rational.rb b/lib/rational.rb
new file mode 100644
index 0000000000..d4112c2956
--- /dev/null
+++ b/lib/rational.rb
@@ -0,0 +1,361 @@
+#
+# rational.rb -
+# $Release Version: 0.5 $
+# $Revision: 1.1 $
+# $Date: 1996/11/11 04:25:14 $
+# by Keiju ISHITSUKA(SHL Japan Inc.)
+#
+# --
+# Usage:
+# class Rational < Numeric
+# (include Compareable)
+#
+# Rational(a, b) --> a/b
+#
+# Rational::+
+# Rational::-
+# Rational::*
+# Rational::/
+# Rational::**
+# Rational::%
+# Rational::divmod
+# Rational::abs
+# Rational::<=>
+# Rational::to_i
+# Rational::to_f
+# Rational::to_s
+#
+# Integer::gcd
+# Integer::lcm
+# Integer::gcdlcm
+# Integer::to_r
+#
+# Fixnum::**
+# Bignum::**
+#
+#
+
+def Rational(a, b = 1)
+ if a.kind_of?(Rational) && b == 1
+ a
+ else
+ Rational.reduce(a, b)
+ end
+end
+
+class Rational < Numeric
+ def Rational.reduce(num, den = 1)
+ if den < 0
+ num = -num
+ den = -den
+ end
+ gcd = num.gcd(den)
+ num = num.div(gcd)
+ den = den.div(gcd)
+ if den == 1 && defined?(Unify)
+ num
+ else
+ new!(num, den)
+ end
+ end
+
+ def Rational.new!(num, den = 1)
+ new(num, den)
+ end
+
+ def initialize(num, den)
+ if den < 0
+ num = -num
+ den = -den
+ end
+ if num.kind_of?(Integer) and den.kind_of?(Integer)
+ @numerator = num
+ @denominator = den
+ else
+ @numerator = num.to_i
+ @denoninator = den.to_i
+ end
+ end
+
+ def + (a)
+ if a.kind_of?(Rational)
+ num = @numerator * a.denominator
+ num_a = a.numerator * @denominator
+ Rational(num + num_a, @denominator * a.denominator)
+ elsif a.kind_of?(Integer)
+ self + Rational.new!(a, 1)
+ elsif a.kind_of?(Float)
+ Float(self) + a
+ else
+ x , y = a.coerce(self)
+ x + y
+ end
+ end
+
+ def - (a)
+ if a.kind_of?(Rational)
+ num = @numerator * a.denominator
+ num_a = a.numerator * @denominator
+ Rational(num - num_a, @denominator*a.denominator)
+ elsif a.kind_of?(Integer)
+ self - Rational.new!(a, 1)
+ elsif a.kind_of?(Float)
+ Float(self) - a
+ else
+ x , y = a.coerce(self)
+ x - y
+ end
+ end
+
+ def * (a)
+ if a.kind_of?(Rational)
+ num = @numerator * a.numerator
+ den = @denominator * a.denominator
+ Rational(num, den)
+ elsif a.kind_of?(Integer)
+ self * Rational.new!(a, 1)
+ elsif a.kind_of?(Float)
+ Float(self) * a
+ else
+ x , y = a.coerce(self)
+ x * y
+ end
+ end
+
+ def / (a)
+ if a.kind_of?(Rational)
+ num = @numerator * a.denominator
+ den = @denominator * a.numerator
+ Rational(num, den)
+ elsif a.kind_of?(Integer)
+ self / Rational.new!(a, 1)
+ elsif a.kind_of?(Float)
+ Float(self) / a
+ else
+ x , y = a.coerce(self)
+ x / y
+ end
+ end
+
+ def ** (other)
+ if other.kind_of?(Rational)
+ Float(self) ** other
+ elsif other.kind_of?(Integer)
+ if other > 0
+ num = @numerator ** other
+ den = @denominator ** other
+ elsif other < 0
+ num = @denominator ** -other
+ den = @numerator ** -other
+ elsif other == 0
+ num = 1
+ den = 1
+ end
+ Rational.new!(num, den)
+ elsif other.kind_of?(Float)
+ Float(self) ** other
+ else
+ x , y = other.coerce(self)
+ x ** y
+ end
+ end
+
+ def % (other)
+ value = (self / other).to_i
+ return self - other * value
+ end
+
+ def divmod(other)
+ value = (self / other).to_i
+ return value, self - other * value
+ end
+
+ def abs
+ if @numerator > 0
+ Rational.new!(@numerator, @denominator)
+ else
+ Rational.new!(-@numerator, @denominator)
+ end
+ end
+
+ def <=> (other)
+ if other.kind_of?(Rational)
+ num = @numerator * other.denominator
+ num_a = other.numerator * @denominator
+ v = num - num_a
+ if v > 0
+ return 1
+ elsif v < 0
+ return -1
+ else
+ return 0
+ end
+ elsif other.kind_of?(Integer)
+ return self <=> Rational.new!(other, 1)
+ elsif other.kind_of?(Float)
+ return Float(self) <=> other
+ else
+ x , y = other.coerce(self)
+ return x <=> y
+ end
+ end
+
+ def coerce(other)
+ if other.kind_of?(Float)
+ return other, self.to_f
+ elsif other.kind_of?(Integer)
+ return Rational.new!(other, 1), self
+ else
+ super
+ end
+ end
+
+ def to_i
+ Integer(@numerator.div(@denominator))
+ end
+
+ def to_f
+ @numerator.to_f/@denominator.to_f
+ end
+
+ def to_s
+ if @denominator == 1
+ @numerator.to_s
+ else
+ @numerator.to_s+"/"+@denominator.to_s
+ end
+ end
+
+ def to_r
+ self
+ end
+
+ def hash
+ @numerator ^ @denominator
+ end
+
+ attr :numerator
+ attr :denominator
+
+ private :initialize
+end
+
+class Integer
+ def numerator
+ self
+ end
+
+ def denomerator
+ 1
+ end
+
+ def to_r
+ Rational(self, 1)
+ end
+
+ def gcd(int)
+ a = self.abs
+ b = int.abs
+
+ a, b = b, a if a < b
+
+ while b != 0
+ void, a = a.divmod(b)
+ a, b = b, a
+ end
+ return a
+ end
+
+ def lcm(int)
+ a = self.abs
+ b = int.abs
+ gcd = a.gcd(b)
+ (a.div(gcd)) * b
+ end
+
+ def gcdlcm(int)
+ a = self.abs
+ b = int.abs
+ gcd = a.gcd(b)
+ return gcd, (a.div(gcd)) * b
+ end
+
+end
+
+class Fixnum
+ alias div! /;
+ def div(other)
+ if other.kind_of?(Fixnum)
+ self.div!(other)
+ elsif other.kind_of?(Bignum)
+ x, y = other.coerce(self)
+ x.div!(y)
+ else
+ x, y = other.coerce(self)
+ x / y
+ end
+ end
+
+# alias divmod! divmod
+
+ if not defined? Complex
+ alias power! **;
+ end
+
+# def rdiv(other)
+# if other.kind_of?(Fixnum)
+# Rational(self, other)
+# elsif
+# x, y = other.coerce(self)
+# if defined?(x.div())
+# x.div(y)
+# else
+# x / y
+# end
+# end
+ # end
+
+ def rdiv(other)
+ Rational.new!(self,1) / other
+ end
+
+ def rpower (other)
+ if other >= 0
+ self.power!(other)
+ else
+ Rational.new!(self,1)**other
+ end
+ end
+
+ if not defined? Complex
+ alias ** rpower
+ end
+end
+
+class Bignum
+ alias div! /;
+ alias div /;
+ alias divmod! divmod
+
+ if not defined? power!
+ alias power! **
+ end
+
+ def rdiv(other)
+ Rational.new!(self,1) / other
+ end
+
+ def rpower (other)
+ if other >= 0
+ self.power!(other)
+ else
+ Rational.new!(self, 1)**other
+ end
+ end
+
+ if not defined? Complex
+ alias ** rpower
+ end
+
+end
+
diff --git a/lib/safe.rb b/lib/safe.rb
new file mode 100644
index 0000000000..7c95555495
--- /dev/null
+++ b/lib/safe.rb
@@ -0,0 +1,78 @@
+# this is a safe-mode for ruby, which is still incomplete.
+
+unless defined? SecurityError
+ class SecurityError<Exception
+ end
+end
+
+module Restricted
+
+ printf STDERR, "feel free for some warnings:\n" if $VERBOSE
+ module Bastion
+ include Restricted
+ extend Restricted
+ BINDING = binding
+ def Bastion.to_s; "main" end
+ end
+
+ class R_File<File
+ NG_FILE_OP = []
+ def R_File.open(*args)
+ raise SecurityError, "can't use File.open() in safe mode" #'
+ end
+ end
+
+ IO = nil
+ File = R_File
+ FileTest = nil
+ Dir = nil
+ ObjectSpace = nil
+
+ def eval(string)
+ begin
+ super(string, Bastion::BINDING)
+ rescue
+ $@ = caller
+ raise
+ end
+ end
+ module_function :eval
+
+ DEFAULT_SECURITY_MANAGER = Object.new
+
+ def Restricted.set_securuty_manager(sec_man)
+ if @sec_man
+ raise SecurityError, "cannot change security manager"
+ end
+ @sec_man = sec_man
+ end
+
+ def Restricted.securuty_manager
+ return @sec_man if @sec_man
+ return DEFAULT_SECURITY_MANAGER
+ end
+
+ for cmd in ["test", "require", "load", "open", "system"]
+ eval format("def DEFAULT_SECURITY_MANAGER.%s(*args)
+ raise SecurityError, \"can't use %s() in safe mode\"
+ end", cmd, cmd) #'
+ eval format("def %s(*args)
+ Restricted.securuty_manager.%s(*args)
+ end", cmd, cmd)
+ end
+
+ def `(arg) #`
+ Restricted.securuty_manager.send(:`, arg) #`)
+ end
+
+ def DEFAULT_SECURITY_MANAGER.`(arg) #`
+ raise SecurityError, "can't use backquote(``) in safe mode"
+ end
+end
+
+if $DEBUG
+ p eval("File.open('/dev/null')")
+ p Restricted.eval("self")
+ p Restricted.eval("open('/dev/null')")
+ p Restricted.eval("File.open('/dev/null')")
+end
diff --git a/lib/thread.rb b/lib/thread.rb
new file mode 100644
index 0000000000..c3347b60b4
--- /dev/null
+++ b/lib/thread.rb
@@ -0,0 +1,153 @@
+#
+# thread.rb - thread support classes
+# $Date: 1996/05/21 09:29:21 $
+# by Yukihiro Matsumoto <matz@caelum.co.jp>
+#
+
+unless defined? Thread
+ fail "Thread not available for this ruby interpreter"
+end
+
+unless defined? ThreadError
+ class ThreadError<Exception
+ end
+end
+
+class Mutex
+ def initialize
+ @waiting = []
+ @locked = FALSE;
+ end
+
+ def locked?
+ @locked
+ end
+
+ def try_lock
+ Thread.exclusive do
+ if not @locked
+ @locked=TRUE
+ return TRUE
+ end
+ end
+ FALSE
+ end
+
+ def lock
+ while not try_lock
+ @waiting.push Thread.current
+ Thread.stop
+ end
+ end
+
+ def unlock
+ @locked = FALSE
+ if w = @waiting.shift
+ w.run
+ end
+ end
+
+ def synchronize
+ begin
+ lock
+ yield
+ ensure
+ unlock
+ end
+ end
+end
+
+class SharedMutex<Mutex
+ def initialize
+ @locking = nil
+ @num_locks = 0;
+ super
+ end
+ def try_lock
+ if @locking == Thread.current
+ @num_locks += 1
+ return TRUE
+ end
+ if super
+ @num_locks = 1
+ @locking = Thread.current
+ TRUE
+ else
+ FALSE
+ end
+ end
+ def unlock
+ unless @locking == Thread.current
+ raise ThreadError, "cannot release shared mutex"
+ end
+ @num_locks -= 1
+ if @num_locks == 0
+ @locking = nil
+ super
+ end
+ end
+end
+
+class Queue
+ def initialize
+ @que = []
+ @waiting = []
+ end
+
+ def push(obj)
+ @que.push obj
+ if t = @waiting.shift
+ t.run
+ end
+ end
+
+ def pop non_block=FALSE
+ if @que.length == 0
+ raise ThreadError, "queue empty" if non_block
+ @waiting.push Thread.current
+ Thread.stop
+ end
+ @que.shift
+ end
+
+ def empty?
+ @que.length == 0
+ end
+
+ def length
+ @que.length
+ end
+end
+
+class Condition
+ def initialize
+ @waiting = []
+ end
+
+ def wait(mut)
+ Thread.exclusive do
+ mut.unlock
+ @waiting.push Thread.current
+ end
+ Thread.sleep
+ mut.lock
+ end
+
+ def signal
+ th = nil
+ Thread.exclusive do
+ th = @waiting.pop
+ end
+ th.run
+ end
+
+ def broadcast
+ w = @waiting
+ Thread.exclusive do
+ th = []
+ end
+ for th in w
+ th.run
+ end
+ end
+end
diff --git a/lib/tk.rb b/lib/tk.rb
index 9c61269881..5a725aac11 100644
--- a/lib/tk.rb
+++ b/lib/tk.rb
@@ -3,477 +3,10 @@
# $Date: 1995/11/03 08:17:15 $
# by Yukihiro Matsumoto <matz@caelum.co.jp>
-require "tkutil"
-
-trap "PIPE", proc{exit 0}
-trap "EXIT", proc{Tk.tk_exit}
-
-module Tk
- include TkUtil
- extend Tk
-
- $0 =~ /\/(.*$)/
-
- PORT = open(format("|%s -n %s", WISH_PATH, $1), "w+");
- def tk_write(*args)
- printf PORT, *args;
- PORT.print "\n"
- PORT.flush
- end
- tk_write '\
-wm withdraw .
-proc rb_out args {
- puts [format %%s $args]
- flush stdout
-}
-proc tkerror args { exit }
-proc keepalive {} { rb_out alive; after 120000 keepalive}
-after 120000 keepalive'
-
- READABLE = []
- READ_CMD = {}
-
- def file_readable(port, cmd)
- READABLE.push port
- READ_CMD[port] = cmd
- end
-
- WRITABLE = []
- WRITE_CMD = {}
- def file_writable
- WRITABLE.push port
- WRITE_CMD[port] = cmd
- end
- module_function :file_readable, :file_writable
-
- file_readable PORT, proc {
- exit if not PORT.gets
- Tk.dispatch($_.chop!)
- }
-
- def tk_exit
- PORT.print "exit\n"
- PORT.close
- end
-
- def error_at
- n = 1
- while c = caller(n)
- break if c !~ /tk\.rb:/
- n+=1
- end
- c
- end
-
- def tk_tcl2ruby(val)
- case val
- when /^-?\d+$/
- val.to_i
- when /^\./
- $tk_window_list[val]
- when /^rb_out (c\d+)/
- $tk_cmdtbl[$1]
- when / /
- val.split.collect{|elt|
- tk_tcl2ruby(elt)
- }
- when /^-?\d+\.\d*$/
- val.to_f
- else
- val
- end
- end
-
- def tk_split_list(str)
- idx = str.index('{')
- return tk_tcl2ruby(str) if not idx
-
- list = tk_tcl2ruby(str[0,idx])
- str = str[idx+1..-1]
- i = -1
- brace = 1
- str.each_byte {|c|
- i += 1
- brace += 1 if c == ?{
- brace -= 1 if c == ?}
- break if brace == 0
- }
- if str[0, i] == ' '
- list.push ' '
- else
- list.push tk_split_list(str[0, i])
- end
- list += tk_split_list(str[i+1..-1])
- list
- end
- private :tk_tcl2ruby, :tk_split_list
-
- def bool(val)
- case bool
- when "1", 1, 'yes', 'true'
- TRUE
- else
- FALSE
- end
- end
- def number(val)
- case val
- when /^-?\d+$/
- val.to_i
- when /^-?\d+\.\d*$/
- val.to_f
- else
- val
- end
- end
- def string(val)
- if val == "{}"
- ''
- elsif val[0] == ?{
- val[1..-2]
- else
- val
- end
- end
- def list(val)
- tk_split_list(val)
- end
- def window(val)
- $tk_window_list[val]
- end
- def procedure(val)
- if val =~ /^rb_out (c\d+)/
- $tk_cmdtbl[$1]
- else
- nil
- end
- end
- private :bool, :number, :string, :list, :window, :procedure
-
- # mark for non-given arguments
- None = Object.new
- def None.to_s
- 'None'
- end
-
- $tk_event_queue = []
- def tk_call(*args)
- args = args.collect{|s|
- continue if s == None
- if s == FALSE
- s = "0"
- elsif s == TRUE
- s = "1"
- elsif s.is_kind_of?(TkObject)
- s = s.path
- else
- s = s.to_s
- s.gsub!(/[{}]/, '\\\\\0')
- end
- "{#{s}}"
- }
- str = args.join(" ")
- tk_write 'if [catch {%s} var] {puts "!$var"} {puts "=$var@@"};flush stdout', str
- while PORT.gets
- $_.chop!
- if /^=(.*)@@$/
- val = $1
- break
- elsif /^=/
- val = $' + "\n"
- while TRUE
- PORT.gets
- fail 'wish closed' if not $_
- if ~/@@$/
- val += $'
- return val
- else
- val += $_
- end
- end
- elsif /^!/
- $@ = error_at
- msg = $'
- if msg =~ /unknown option "-(.*)"/
- fail format("undefined method `%s' for %s(%s)'", $1, self, self.type)
- else
- fail format("%s - %s", self.type, msg)
- end
- end
- $tk_event_queue.push $_
- end
-
- while ev = $tk_event_queue.shift
- Tk.dispatch ev
- end
- fail 'wish closed' if not $_
-# tk_split_list(val)
- val
- end
-
- def hash_kv(keys)
- conf = []
- if keys
- for k, v in keys
- conf.push("-#{k}")
- v = install_cmd(v) if v.type == Proc
- conf.push(v)
- end
- end
- conf
- end
- private :tk_call, :error_at, :hash_kv
-
- $tk_cmdid = "c00000"
- def install_cmd(cmd)
- return '' if cmd == '' # uninstall cmd
- id = $tk_cmdid
- $tk_cmdid = $tk_cmdid.next
- $tk_cmdtbl[id] = cmd
- @cmdtbl = [] if not @cmdtbl
- @cmdtbl.push id
- return format('rb_out %s', id)
- end
- def uninstall_cmd(id)
- $tk_cmdtbl[id] = nil
- end
- private :install_cmd, :uninstall_cmd
-
- $tk_window_list = {}
- class Event
- def initialize(seq,b,f,h,k,s,t,w,x,y,aa,ee,kk,nn,ww,tt,xx,yy)
- @serial = seq
- @num = b
- @focus = (f == 1)
- @height = h
- @keycode = k
- @state = s
- @time = t
- @width = w
- @x = x
- @y = y
- @char = aa
- @send_event = (ee == 1)
- @keysym = kk
- @keysym_num = nn
- @type = tt
- @widget = ww
- @x_root = xx
- @y_root = yy
- end
- attr :serial
- attr :num
- attr :focus
- attr :height
- attr :keycode
- attr :state
- attr :time
- attr :width
- attr :x
- attr :y
- attr :char
- attr :send_event
- attr :keysym
- attr :keysym_num
- attr :type
- attr :widget
- attr :x_root
- attr :y_root
- end
-
- def install_bind(cmd)
- id = install_cmd(proc{|args|
- TkUtil.eval_cmd cmd, Event.new(*args)
- })
- id + " %# %b %f %h %k %s %t %w %x %y %A %E %K %N %W %T %X %Y"
- end
-
- def _bind(path, context, cmd)
- begin
- id = install_bind(cmd)
- tk_call 'bind', path, "<#{context}>", id
- rescue
- $tk_cmdtbl[id] = nil
- fail
- end
- end
- private :install_bind, :_bind
-
- def bind_all(context, cmd=Proc.new)
- _bind 'all', context, cmd
- end
-
- $tk_cmdtbl = {}
-
- def after(ms, cmd=Proc.new)
- myid = $tk_cmdid
- tk_call 'after', ms,
- install_cmd(proc{
- TkUtil.eval_cmd cmd
- uninstall_cmd myid
- })
- end
-
- def update(idle=nil)
- if idle
- tk_call 'update', 'idletasks'
- else
- tk_call 'update'
- end
- end
-
- def dispatch(line)
- if line =~ /^c\d+/
- cmd = $&
- fail "no command `#{cmd}'" if not $tk_cmdtbl[cmd]
- args = tk_split_list($')
- TkUtil.eval_cmd $tk_cmdtbl[cmd], *args
- elsif line =~ /^alive$/
- # keep alive, do nothing
- else
- fail "malformed line <#{line}>"
- end
- end
-
- def mainloop
- begin
- tk_write 'after idle {wm deiconify .}'
- while TRUE
- rf, wf = select(READABLE, WRITABLE)
- for f in rf
- READ_CMD[f].call(f) if READ_CMD[f]
- if f.closed?
- READABLE.delete f
- READ_CMD[f] = nil
- end
- end
- for f in wf
- WRITE_CMD[f].call(f) if WRITE_CMD[f]
- if f.closed?
- WRITABLE.delete f
- WRITE_CMD[f] = nil
- end
- end
- end
- rescue
- exit if $! =~ /^Interrupt/
- fail
- ensure
- tk_exit
- end
- end
-
- def root
- $tk_root
- end
-
- module_function :after, :update, :dispatch, :mainloop, :root
-
- module Scrollable
- def xscrollcommand(cmd)
- configure_cmd 'xscrollcommand', cmd
- end
- def yscrollcommand(cmd)
- configure_cmd 'yscrollcommand', cmd
- end
- end
-
- module Wm
- def aspect(*args)
- w = window(tk_call('wm', 'grid', path, *args))
- w.split.collect{|s|s.to_i} if args.length == 0
- end
- def client(name=None)
- tk_call 'wm', 'client', path, name
- end
- def colormapwindows(*args)
- list(tk_call('wm', 'colormapwindows', path, *args))
- end
- def wm_command(value=None)
- string(tk_call('wm', 'command', path, value))
- end
- def deiconify
- tk_call 'wm', 'deiconify', path
- end
- def focusmodel(*args)
- tk_call 'wm', 'focusmodel', path, *args
- end
- def frame
- tk_call 'wm', 'frame', path
- end
- def geometry(*args)
- list(tk_call('wm', 'geometry', path, *args))
- end
- def grid(*args)
- w = tk_call('wm', 'grid', path, *args)
- list(w) if args.size == 0
- end
- def group(*args)
- tk_call 'wm', 'path', path, *args
- end
- def iconbitmap(*args)
- tk_call 'wm', 'bitmap', path, *args
- end
- def iconify
- tk_call 'wm', 'iconify'
- end
- def iconmask(*args)
- tk_call 'wm', 'iconmask', path, *args
- end
- def iconname(*args)
- tk_call 'wm', 'iconname', path, *args
- end
- def iconposition(*args)
- w = tk_call('wm', 'iconposition', path, *args)
- list(w) if args.size == 0
- end
- def iconwindow(*args)
- tk_call 'wm', 'iconwindow', path, *args
- end
- def maxsize(*args)
- w = tk_call('wm', 'maxsize', path, *args)
- list(w) if not args.size == 0
- end
- def minsize(*args)
- w = tk_call('wm', 'minsize', path, *args)
- list(w) if args.size == 0
- end
- def overrideredirect(bool=None)
- if bool == None
- bool(tk_call('wm', 'overrideredirect', path))
- else
- tk_call 'wm', 'overrideredirect', path, bool
- end
- end
- def positionfrom(*args)
- tk_call 'wm', 'positionfrom', path, *args
- end
- def protocol(name, func=None)
- func = install_cmd(func) if not func == None
- tk_call 'wm', 'command', path, name, func
- end
- def resizable(*args)
- w = tk_call('wm', 'resizable', path, *args)
- if args.length == 0
- list(w).collect{|e| bool(e)}
- end
- end
- def sizefrom(*args)
- list(tk_call('wm', 'sizefrom', path, *args))
- end
- def state
- tk_call 'wm', 'state', path
- end
- def title(*args)
- tk_call 'wm', 'title', path, *args
- end
- def transient(*args)
- tk_call 'wm', 'transient', path, *args
- end
- def withdraw
- tk_call 'wm', 'withdraw', path
- end
- end
+if defined? Thread and $tk_thread_safe
+ require "tkthcore"
+else
+ require "tkcore"
end
module TkSelection
@@ -550,11 +83,11 @@ module TkWinfo
def winfo_depth(window)
TkWinfo.depth self
end
- def TkWinfo.exists(window)
+ def TkWinfo.exist?(window)
bool(tk_call('winfo', 'exists', window.path))
end
- def winfo_exists(window)
- TkWinfo.exists self
+ def winfo_exist?(window)
+ TkWinfo.exist? self
end
def TkWinfo.fpixels(window, number)
number(tk_call('winfo', 'fpixels', window.path, number))
@@ -580,11 +113,11 @@ module TkWinfo
def winfo_id(window)
TkWinfo.id self
end
- def TkWinfo.ismapped(window)
+ def TkWinfo.mapped?(window)
bool(tk_call('winfo', 'ismapped', window.path))
end
- def winfo_ismapped(window)
- TkWinfo.ismapped self
+ def winfo_mapped?(window)
+ TkWinfo.mapped? self
end
def TkWinfo.parent(window)
window(tk_call('winfo', 'parent', window.path))
@@ -742,7 +275,7 @@ module TkPack
include Tk
extend Tk
def configure(win, *args)
- if args[-1].is_kind_of(Hash)
+ if args[-1].kind_of?(Hash)
keys = args.pop
end
wins = [win.epath]
@@ -780,7 +313,7 @@ module TkOption
module_function :add, :clear, :get, :readfile
end
-class TkObject:TkKernel
+class TkObject<TkKernel
include Tk
def path
@@ -822,16 +355,16 @@ class TkObject:TkKernel
configure slot, install_cmd(value)
end
- def bind(context, cmd=Proc.new)
- _bind path, context, cmd
+ def bind(context, cmd=Proc.new, args=nil)
+ _bind path, context, cmd, args
end
end
-class TkWindow:TkObject
+class TkWindow<TkObject
$tk_window_id = "w00000"
def initialize(parent=nil, keys=nil)
id = $tk_window_id
- $tk_window_id = $tk_window_id.next
+ $tk_window_id = $tk_window_id.succ
if !parent or parent == Tk.root
@path = format(".%s", id);
else
@@ -880,7 +413,7 @@ class TkWindow:TkObject
return val
end
else
- fail 'wrong # of args'
+ fail ArgumentError, 'wrong # of args'
end
end
@@ -913,7 +446,7 @@ class TkWindow:TkObject
end
end
-class TkRoot:TkWindow
+class TkRoot<TkWindow
include Wm
def TkRoot.new
return $tk_root if $tk_root
@@ -926,7 +459,7 @@ class TkRoot:TkWindow
$tk_window_list['.'] = $tk_root
end
-class TkToplevel:TkWindow
+class TkToplevel<TkWindow
include Wm
def initialize(parent=nil, screen=nil, classname=nil)
@screen = screen if screen
@@ -942,20 +475,21 @@ class TkToplevel:TkWindow
end
end
-class TkFrame:TkWindow
+class TkFrame<TkWindow
def create_self
tk_call 'frame', @path
end
end
-class TkLabel:TkWindow
+class TkLabel<TkWindow
def create_self
tk_call 'label', @path
end
def textvariable(v)
- vn = @path + v.id2name
+ v = v.id2name unless v.kind_of "String"
+ vn = @path + v
vset = format("global {%s}; set {%s}", vn, vn)
- tk_call vset, eval(v.id2name).inspect
+ tk_call vset, eval(v).inspect
trace_var v, proc{|val|
tk_call vset, val.inspect
}
@@ -963,7 +497,7 @@ class TkLabel:TkWindow
end
end
-class TkButton:TkLabel
+class TkButton<TkLabel
def create_self
tk_call 'button', @path
end
@@ -975,7 +509,7 @@ class TkButton:TkLabel
end
end
-class TkRadioButton:TkButton
+class TkRadioButton<TkButton
def create_self
tk_call 'radiobutton', @path
end
@@ -986,8 +520,13 @@ class TkRadioButton:TkButton
tk_send 'select'
end
def variable(v)
- vn = v.id2name; vn =~ /^./
- vn = 'btns_selected_' + $'
+ v = v.id2name unless v.kind_of "String"
+ if v =~ /^\$/
+ v = $'
+ else
+ fail ArgumentError, "variable must be global(%s)", v
+ end
+ vn = 'btns_selected_' + v
trace_var v, proc{|val|
tk_call 'set', vn, val
}
@@ -1004,7 +543,7 @@ class TkRadioButton:TkButton
end
end
-class TkCheckButton:TkRadioButton
+class TkCheckButton<TkRadioButton
def create_self
tk_call 'checkbutton', @path
end
@@ -1013,13 +552,13 @@ class TkCheckButton:TkRadioButton
end
end
-class TkMessage:TkLabel
+class TkMessage<TkLabel
def create_self
tk_call 'message', @path
end
end
-class TkScale:TkWindow
+class TkScale<TkWindow
def create_self
tk_call 'scale', path
end
@@ -1041,11 +580,23 @@ class TkScale:TkWindow
end
end
-class TkScrollbar:TkWindow
+class TkScrollbar<TkWindow
def create_self
tk_call 'scrollbar', path
end
+ def delta(deltax=None, deltay=None)
+ number(tk_send('delta', deltax, deltay))
+ end
+
+ def fraction(x=None, y=None)
+ number(tk_send('fraction', x, y))
+ end
+
+ def identify(x=None, y=None)
+ tk_send('fraction', x, y)
+ end
+
def get
ary1 = tk_send('get', path).split
ary2 = []
@@ -1061,7 +612,7 @@ class TkScrollbar:TkWindow
end
# abstract class for Text and Listbox
-class TkTextWin:TkWindow
+class TkTextWin<TkWindow
def bbox(index)
tk_send 'bbox', index
end
@@ -1091,7 +642,7 @@ class TkTextWin:TkWindow
end
end
-class TkListbox:TkTextWin
+class TkListbox<TkTextWin
def create_self
tk_call 'listbox', path
end
@@ -1119,7 +670,7 @@ class TkListbox:TkTextWin
end
end
-class TkMenu:TkWindow
+class TkMenu<TkWindow
def create_self
tk_call 'menu', path
end
@@ -1158,7 +709,7 @@ class TkMenu:TkWindow
end
end
-class TkMenubutton:TkLabel
+class TkMenubutton<TkLabel
def create_self
tk_call 'menubutton', path
end
@@ -1181,7 +732,7 @@ module TkComposite
def delegate(option, *wins)
@delegates = {} if not @delegates
@delegates['DEFAULT'] = @frame
- if option.is_kind_of? String
+ if option.kind_of? String
@delegates[option] = wins
else
for i in option
diff --git a/lib/tkcanvas.rb b/lib/tkcanvas.rb
index 33b28e3eff..b0ae8b1daa 100644
--- a/lib/tkcanvas.rb
+++ b/lib/tkcanvas.rb
@@ -5,12 +5,12 @@
require "tk"
-class TkCanvas:TkWindow
+class TkCanvas<TkWindow
def create_self
tk_call 'canvas', path
end
def tagid(tag)
- if tag.is_kind_of?(TkcItem)
+ if tag.kind_of?(TkcItem)
tag.id
else
tag
@@ -89,6 +89,9 @@ class TkCanvas:TkWindow
def move(tag, x, y)
tk_send 'move', tagid(tag), x, y
end
+ def itemtype(tag)
+ tk_send 'type', tagid(tag)
+ end
def postscript(keys=None)
tk_call "pack", *hash_kv(keys)
end
@@ -115,9 +118,9 @@ class TkCanvas:TkWindow
end
end
-class TkcItem:TkObject
+class TkcItem<TkObject
def initialize(parent, *args)
- if not parent.is_kind_of?(TkCanvas)
+ if not parent.kind_of?(TkCanvas)
fail format("%s need to be TkCanvas", parent.inspect)
end
@c = parent
@@ -137,7 +140,7 @@ class TkcItem:TkObject
end
def configure(slot, value)
- tk_call path, 'itemconfigure', id, "-#{slot}", value
+ tk_call path, 'itemconfigure', @id, "-#{slot}", value
end
def addtag(tag)
@@ -185,59 +188,59 @@ class TkcItem:TkObject
def scale(xorigin, yorigin, xscale, yscale)
@c.scale @id, xorigin, yorigin, xscale, yscale
end
- def type
- @c.type @id
+ def itemtype
+ @c.itemtype @id
end
def destroy
tk_call path, 'delete', @id
end
end
-class TkcArc:TkcItem
+class TkcArc<TkcItem
def create_self(*args)
tk_call(@path, 'create', 'arc', *args)
end
end
-class TkcBitmap:TkcItem
+class TkcBitmap<TkcItem
def create_self(*args)
tk_call(@path, 'create', 'bitmap', *args)
end
end
-class TkcImage:TkcItem
+class TkcImage<TkcItem
def create_self(*args)
tk_call(@path, 'create', 'image', *args)
end
end
-class TkcLine:TkcItem
+class TkcLine<TkcItem
def create_self(*args)
tk_call(@path, 'create', 'line', *args)
end
end
-class TkcOval:TkcItem
+class TkcOval<TkcItem
def create_self(*args)
tk_call(@path, 'create', 'oval', *args)
end
end
-class TkcPolygon:TkcItem
+class TkcPolygon<TkcItem
def create_self(*args)
tk_call(@path, 'create', 'polygon', *args)
end
end
-class TkcText:TkcItem
+class TkcText<TkcItem
def create_self(*args)
tk_call(@path, 'create', 'text', *args)
end
end
-class TkcWindow:TkcItem
+class TkcWindow<TkcItem
def create_self(*args)
tk_call(@path, 'create', 'window', *args)
end
end
-class TkcGroup:TkcItem
+class TkcGroup<TkcItem
$tk_group_id = 'tkg00000'
def create_self(*args)
@id = $tk_group_id
- $tk_group_id = $tk_group_id.next
+ $tk_group_id = $tk_group_id.succ
end
def add(*tags)
@@ -262,20 +265,20 @@ class TkcGroup:TkcItem
end
-class TkImage:TkObject
+class TkImage<TkObject
include Tk
$tk_image_id = 'i00000'
def initialize(keys=nil)
@path = $tk_image_id
- $tk_image_id = $tk_image_id.next
+ $tk_image_id = $tk_image_id.succ
tk_call 'image', @type, @path, *hash_kv(keys)
end
def height
number(tk_call('image', 'height', @path))
end
- def type
+ def itemtype
tk_call('image', 'type', @path)
end
def width
@@ -290,14 +293,14 @@ class TkImage:TkObject
end
end
-class TkBitmapImage:TkImage
+class TkBitmapImage<TkImage
def initialize(*args)
@type = 'bitmap'
super
end
end
-class TkPhotoImage:TkImage
+class TkPhotoImage<TkImage
def initialize(*args)
@type = 'bitmap'
super
diff --git a/lib/tkcore.rb b/lib/tkcore.rb
new file mode 100644
index 0000000000..df4af669ba
--- /dev/null
+++ b/lib/tkcore.rb
@@ -0,0 +1,521 @@
+#
+# tkcore.rb - Tk interface modue without thread
+# $Date: 1996/11/09 22:51:15 $
+# by Yukihiro Matsumoto <matz@caelum.co.jp>
+
+require "tkutil"
+if defined? Thread
+ require "thread"
+end
+
+module Tk
+ include TkUtil
+ extend Tk
+
+ wish_path = nil
+ ENV['PATH'].split(":").each {|path|
+ for wish in ['wish4.2', 'wish4.1', 'wish4.0', 'wish']
+ if File.exist? path+'/'+wish
+ wish_path = path+'/'+wish
+ break
+ end
+ break if wish_path
+ end
+ }
+ fail 'can\'t find wish' if not wish_path
+
+ def Tk.tk_exit
+ if not PORT.closed?
+ PORT.print "exit\n"
+ PORT.close
+ end
+ end
+
+ PORT = open(format("|%s -n %s", wish_path, File.basename($0)), "w+");
+ trap "EXIT", proc{Tk.tk_exit}
+ trap "PIPE", ""
+
+ def tk_write(*args)
+ printf PORT, *args;
+ PORT.print "\n"
+ PORT.flush
+ end
+ tk_write '\
+wm withdraw .
+proc rb_out args {
+ puts [format %%s $args]
+ flush stdout
+}
+proc rb_ans args {
+ if [catch "$args" var] {puts "!$var"} {puts "=$var@@"}
+ flush stdout
+}
+proc tkerror args { exit }
+proc keepalive {} { rb_out alive; after 120000 keepalive}
+after 120000 keepalive'
+
+ READABLE = []
+ READ_CMD = {}
+
+ def file_readable(port, cmd)
+ if cmd == nil
+ READABLE.delete port
+ else
+ READABLE.push port
+ end
+ READ_CMD[port] = cmd
+ end
+
+ WRITABLE = []
+ WRITE_CMD = {}
+ def file_writable(port, cmd)
+ if cmd == nil
+ WRITABLE.delete port
+ else
+ WRITABLE.push port
+ end
+ WRITE_CMD[port] = cmd
+ end
+ module_function :file_readable, :file_writable
+
+ file_readable PORT, proc {
+ line = PORT.gets
+ exit if not line
+ Tk.dispatch(line.chop!)
+ }
+
+ def error_at
+ n = 1
+ while c = caller(n)
+ break if c !~ /tk\.rb:/
+ n+=1
+ end
+ c
+ end
+
+ def tk_tcl2ruby(val)
+ case val
+ when /^-?\d+$/
+ val.to_i
+ when /^\./
+ $tk_window_list[val]
+ when /^rb_out (c\d+)/
+ $tk_cmdtbl[$1]
+ when / /
+ val.split.collect{|elt|
+ tk_tcl2ruby(elt)
+ }
+ when /^-?\d+\.\d*$/
+ val.to_f
+ else
+ val
+ end
+ end
+
+ def tk_split_list(str)
+ idx = str.index('{')
+ return tk_tcl2ruby(str) if not idx
+
+ list = tk_tcl2ruby(str[0,idx])
+ str = str[idx+1..-1]
+ i = -1
+ brace = 1
+ str.each_byte {|c|
+ i += 1
+ brace += 1 if c == ?{
+ brace -= 1 if c == ?}
+ break if brace == 0
+ }
+ if str[0, i] == ' '
+ list.push ' '
+ else
+ list.push tk_split_list(str[0, i])
+ end
+ list += tk_split_list(str[i+1..-1])
+ list
+ end
+ private :tk_tcl2ruby, :tk_split_list
+
+ def bool(val)
+ case bool
+ when "1", 1, 'yes', 'true'
+ TRUE
+ else
+ FALSE
+ end
+ end
+ def number(val)
+ case val
+ when /^-?\d+$/
+ val.to_i
+ when /^-?\d+\.\d*$/
+ val.to_f
+ else
+ val
+ end
+ end
+ def string(val)
+ if val == "{}"
+ ''
+ elsif val[0] == ?{
+ val[1..-2]
+ else
+ val
+ end
+ end
+ def list(val)
+ tk_split_list(val)
+ end
+ def window(val)
+ $tk_window_list[val]
+ end
+ def procedure(val)
+ if val =~ /^rb_out (c\d+)/
+ $tk_cmdtbl[$1]
+ else
+ nil
+ end
+ end
+ private :bool, :number, :string, :list, :window, :procedure
+
+ # mark for non-given arguments
+ None = Object.new
+ def None.to_s
+ 'None'
+ end
+
+ $tk_event_queue = []
+ def tk_call(*args)
+ args = args.collect{|s|
+ next if s == None
+ if s.kind_of?(Hash)
+ s = hash_kv(s).join(" ")
+ else
+ if not s
+ s = "0"
+ elsif s == TRUE
+ s = "1"
+ elsif s.kind_of?(TkObject)
+ s = s.path
+ else
+ s = s.to_s
+ s.gsub!(/[{}]/, '\\\\\0')
+ end
+ "{#{s}}"
+ end
+ }
+ str = args.join(" ")
+ print str, "\n" if $DEBUG
+ tk_write 'rb_ans %s', str
+ while PORT.gets
+ print $_ if $DEBUG
+ $_.chop!
+ if /^=(.*)@@$/
+ val = $1
+ break
+ elsif /^=/
+ val = $' + "\n"
+ while TRUE
+ PORT.readline
+ if ~/@@$/
+ val += $'
+ return val
+ else
+ val += $_
+ end
+ end
+ elsif /^!/
+ $@ = error_at
+ msg = $'
+ if msg =~ /unknown option "-(.*)"/
+ fail NameError, format("undefined method `%s' for %s(%s)", $1, self, self.type) #`'
+ else
+ fail format("%s - %s", self.type, msg)
+ end
+ end
+ $tk_event_queue.push $_
+ end
+
+ while ev = $tk_event_queue.shift
+ Tk.dispatch ev
+ end
+ fail 'wish closed' if PORT.closed?
+# tk_split_list(val)
+ val
+ end
+
+ def hash_kv(keys)
+ conf = []
+ if keys
+ for k, v in keys
+ conf.push("-#{k}")
+ v = install_cmd(v) if v.type == Proc
+ conf.push(v)
+ end
+ end
+ conf
+ end
+ private :tk_call, :error_at, :hash_kv
+
+ $tk_cmdid = 0
+ def install_cmd(cmd)
+ return '' if cmd == '' # uninstall cmd
+ id = format("c%.4d", $tk_cmdid)
+ $tk_cmdid += 1
+ $tk_cmdtbl[id] = cmd
+ @cmdtbl = [] if not @cmdtbl
+ @cmdtbl.push id
+ return format('rb_out %s', id)
+ end
+ def uninstall_cmd(id)
+ $tk_cmdtbl[id] = nil
+ end
+ private :install_cmd, :uninstall_cmd
+
+ $tk_window_list = {}
+ class Event
+ def initialize(seq,b,f,h,k,s,t,w,x,y,aa,ee,kk,nn,ww,tt,xx,yy)
+ @serial = seq
+ @num = b
+ @focus = (f == 1)
+ @height = h
+ @keycode = k
+ @state = s
+ @time = t
+ @width = w
+ @x = x
+ @y = y
+ @char = aa
+ @send_event = (ee == 1)
+ @keysym = kk
+ @keysym_num = nn
+ @type = tt
+ @widget = ww
+ @x_root = xx
+ @y_root = yy
+ end
+ attr :serial
+ attr :num
+ attr :focus
+ attr :height
+ attr :keycode
+ attr :state
+ attr :time
+ attr :width
+ attr :x
+ attr :y
+ attr :char
+ attr :send_event
+ attr :keysym
+ attr :keysym_num
+ attr :type
+ attr :widget
+ attr :x_root
+ attr :y_root
+ end
+
+ def install_bind(cmd, args=nil)
+ if args
+ id = install_cmd(proc{|arg|
+ TkUtil.eval_cmd cmd, *arg
+ })
+ id + " " + args
+ else
+ id = install_cmd(proc{|arg|
+ TkUtil.eval_cmd cmd, Event.new(*arg)
+ })
+ id + " %# %b %f %h %k %s %t %w %x %y %A %E %K %N %W %T %X %Y"
+ end
+ end
+
+ def _bind(path, context, cmd, args=nil)
+ begin
+ id = install_bind(cmd, args)
+ tk_call 'bind', path, "<#{context}>", id
+ rescue
+ $tk_cmdtbl[id] = nil
+ fail
+ end
+ end
+ private :install_bind, :_bind
+
+ def bind_all(context, cmd=Proc.new, args=nil)
+ _bind 'all', context, cmd, args
+ end
+
+ def pack(*args)
+ TkPack.configure *args
+ end
+
+ $tk_cmdtbl = {}
+
+ def after(ms, cmd=Proc.new)
+ myid = format("c%.4d", $tk_cmdid)
+ tk_call 'after', ms,
+ install_cmd(proc{
+ TkUtil.eval_cmd cmd
+ uninstall_cmd myid
+ })
+ end
+
+ def update(idle=nil)
+ if idle
+ tk_call 'update', 'idletasks'
+ else
+ tk_call 'update'
+ end
+ end
+
+ def dispatch(line)
+ if line =~ /^c\d+/
+ cmd = $&
+ fail "no command `#{cmd}'" if not $tk_cmdtbl[cmd]
+ args = tk_split_list($')
+ TkUtil.eval_cmd $tk_cmdtbl[cmd], *args
+ elsif line =~ /^alive$/
+ # keep alive, do nothing
+ else
+ fail "malformed line <#{line}>"
+ end
+ end
+
+ def mainloop
+ begin
+ tk_write 'after idle {wm deiconify .}'
+ while TRUE
+ rf, wf = select(READABLE, WRITABLE)
+ for f in rf
+ READ_CMD[f].call(f) if READ_CMD[f]
+ if f.closed?
+ READABLE.delete f
+ READ_CMD[f] = nil
+ end
+ end
+ for f in wf
+ WRITE_CMD[f].call(f) if WRITE_CMD[f]
+ if f.closed?
+ WRITABLE.delete f
+ WRITE_CMD[f] = nil
+ end
+ end
+ end
+ ensure
+ Tk.tk_exit
+ end
+ end
+
+ def root
+ $tk_root
+ end
+
+ def bell
+ tk_call 'bell'
+ end
+ module_function :after, :update, :dispatch, :mainloop, :root, :bell
+
+ module Scrollable
+ def xscrollcommand(cmd)
+ configure_cmd 'xscrollcommand', cmd
+ end
+ def yscrollcommand(cmd)
+ configure_cmd 'yscrollcommand', cmd
+ end
+ end
+
+ module Wm
+ def aspect(*args)
+ w = window(tk_call('wm', 'grid', path, *args))
+ w.split.collect{|s|s.to_i} if args.length == 0
+ end
+ def client(name=None)
+ tk_call 'wm', 'client', path, name
+ end
+ def colormapwindows(*args)
+ list(tk_call('wm', 'colormapwindows', path, *args))
+ end
+ def wm_command(value=None)
+ string(tk_call('wm', 'command', path, value))
+ end
+ def deiconify
+ tk_call 'wm', 'deiconify', path
+ end
+ def focusmodel(*args)
+ tk_call 'wm', 'focusmodel', path, *args
+ end
+ def frame
+ tk_call 'wm', 'frame', path
+ end
+ def geometry(*args)
+ list(tk_call('wm', 'geometry', path, *args))
+ end
+ def grid(*args)
+ w = tk_call('wm', 'grid', path, *args)
+ list(w) if args.size == 0
+ end
+ def group(*args)
+ tk_call 'wm', 'path', path, *args
+ end
+ def iconbitmap(*args)
+ tk_call 'wm', 'bitmap', path, *args
+ end
+ def iconify
+ tk_call 'wm', 'iconify'
+ end
+ def iconmask(*args)
+ tk_call 'wm', 'iconmask', path, *args
+ end
+ def iconname(*args)
+ tk_call 'wm', 'iconname', path, *args
+ end
+ def iconposition(*args)
+ w = tk_call('wm', 'iconposition', path, *args)
+ list(w) if args.size == 0
+ end
+ def iconwindow(*args)
+ tk_call 'wm', 'iconwindow', path, *args
+ end
+ def maxsize(*args)
+ w = tk_call('wm', 'maxsize', path, *args)
+ list(w) if not args.size == 0
+ end
+ def minsize(*args)
+ w = tk_call('wm', 'minsize', path, *args)
+ list(w) if args.size == 0
+ end
+ def overrideredirect(bool=None)
+ if bool == None
+ bool(tk_call('wm', 'overrideredirect', path))
+ else
+ tk_call 'wm', 'overrideredirect', path, bool
+ end
+ end
+ def positionfrom(*args)
+ tk_call 'wm', 'positionfrom', path, *args
+ end
+ def protocol(name, func=None)
+ func = install_cmd(func) if not func == None
+ tk_call 'wm', 'command', path, name, func
+ end
+ def resizable(*args)
+ w = tk_call('wm', 'resizable', path, *args)
+ if args.length == 0
+ list(w).collect{|e| bool(e)}
+ end
+ end
+ def sizefrom(*args)
+ list(tk_call('wm', 'sizefrom', path, *args))
+ end
+ def state
+ tk_call 'wm', 'state', path
+ end
+ def title(*args)
+ tk_call 'wm', 'title', path, *args
+ end
+ def transient(*args)
+ tk_call 'wm', 'transient', path, *args
+ end
+ def withdraw
+ tk_call 'wm', 'withdraw', path
+ end
+ end
+end
diff --git a/lib/tkentry.rb b/lib/tkentry.rb
index dbd848d0ca..9a03c34058 100644
--- a/lib/tkentry.rb
+++ b/lib/tkentry.rb
@@ -5,7 +5,7 @@
require 'tk.rb'
-class TkEntry:TkLabel
+class TkEntry<TkLabel
def create_self
tk_call 'entry', @path
end
diff --git a/lib/tkscrollbox.rb b/lib/tkscrollbox.rb
new file mode 100644
index 0000000000..b8dbe9b236
--- /dev/null
+++ b/lib/tkscrollbox.rb
@@ -0,0 +1,27 @@
+#
+# tkscrollbox.rb - Tk Listbox with Scrollbar
+# as an example of Composite Widget
+# $Date: 1995/12/12 18:21:01 $
+# by Yukihiro Matsumoto <matz@caelum.co.jp>
+
+require 'tk.rb'
+
+class TkScrollbox<TkListbox
+ include TkComposite
+ def initialize_composite
+ list = TkListbox.new(@frame)
+ scroll = TkScrollbar.new(@frame)
+ @path = list.path
+
+ list.configure 'yscroll', scroll.path+" set"
+ list.pack 'side'=>'left','fill'=>'both','expand'=>'yes'
+ scroll.configure 'command', list.path+" yview"
+ scroll.pack 'side'=>'right','fill'=>'y'
+
+ delegate('DEFALUT', list)
+ delegate('foreground', list, scroll)
+ delegate('background', list, scroll)
+ delegate('borderwidth', @frame)
+ delegate('relief', @frame)
+ end
+end
diff --git a/lib/tktext.rb b/lib/tktext.rb
index e7a2be950f..55e396c497 100644
--- a/lib/tktext.rb
+++ b/lib/tktext.rb
@@ -5,7 +5,7 @@
require 'tk.rb'
-class TkText:TkTextWin
+class TkText<TkTextWin
include Scrollable
def create_self
tk_call 'text', @path
@@ -77,16 +77,16 @@ class TkText:TkTextWin
end
end
-class TkTextTag:TkObject
+class TkTextTag<TkObject
$tk_text_tag = 'tag0000'
def initialize(parent)
- if not parent.is_kind_of?(TkText)
+ if not parent.kind_of?(TkText)
fail format("%s need to be TkText", parent.inspect)
end
@t = parent
@path = parent.path
@id = $tk_text_tag
- $tk_text_tag = $tk_text_tag.next
+ $tk_text_tag = $tk_text_tag.succ
@t._addtag id, self
end
def id
@@ -116,16 +116,16 @@ class TkTextTag:TkObject
end
end
-class TkTextMark:TkObject
+class TkTextMark<TkObject
$tk_text_mark = 'mark0000'
def initialize(parent, index)
- if not parent.is_kind_of?(TkText)
+ if not parent.kind_of?(TkText)
fail format("%s need to be TkText", parent.inspect)
end
@t = parent
@path = parent.path
@id = $tk_text_mark
- $tk_text_mark = $tk_text_mark.next
+ $tk_text_mark = $tk_text_mark.succ
tk_call @t, 'set', @id, index
@t._addtag id, self
end
@@ -143,9 +143,9 @@ class TkTextMark:TkObject
alias destroy unset
end
-class TkTextWindow:TkObject
+class TkTextWindow<TkObject
def initialize(parent, index, *args)
- if not parent.is_kind_of?(TkText)
+ if not parent.kind_of?(TkText)
fail format("%s need to be TkText", parent.inspect)
end
@t = parent
diff --git a/lib/tkthcore.rb b/lib/tkthcore.rb
new file mode 100644
index 0000000000..adbad775d0
--- /dev/null
+++ b/lib/tkthcore.rb
@@ -0,0 +1,546 @@
+#
+# tkthcore.rb - Tk interface modue using thread
+# $Date: 1996/11/09 22:49:15 $
+# by Yukihiro Matsumoto <matz@caelum.co.jp>
+
+require "tkutil"
+require "thread"
+
+module Tk
+ include TkUtil
+ extend Tk
+
+ def Tk.tk_exit
+ if not PORT.closed?
+ tk_write "exit"
+ PORT.close
+ end
+ end
+
+ trap "EXIT", proc{Tk.tk_exit}
+ trap "PIPE", ''
+
+ wish_path = nil
+ ENV['PATH'].split(":").each {|path|
+ for wish in ['wish4.2', 'wish4.1', 'wish4.0', 'wish']
+ if File.exist? path+'/'+wish
+ wish_path = path+'/'+wish
+ break
+ end
+ break if wish_path
+ end
+ }
+ fail 'can\'t find wish' if not wish_path
+
+ # mark for non-given arguments
+ None = Object.new
+ def None.to_s
+ 'None'
+ end
+
+ Qin = Queue.new
+ Qout = Queue.new
+ Qwish = Queue.new
+ Qcmd = Queue.new
+ PORT = open(format("|%s -n %s", wish_path, File.basename($0)), "w+");
+
+ $tk_not_init = TRUE
+
+ def Tk.init
+ $tk_not_init = FALSE
+ Thread.start do
+ loop do
+ while line = PORT.gets
+ line.chop!
+ if line =~ /^[=!]/
+ Qwish.push line
+ else
+ Qcmd.push line
+ end
+ end
+ exit
+ end
+ end
+
+ Thread.start do
+ ary = [PORT]
+ loop do
+ str = Qin.pop
+ print str, "\n" if $DEBUG
+ tk_write 'if [catch {%s} var] {puts "!$var"} {puts "=$var@@"};flush stdout', str
+ Qout.push(tk_recv)
+ end
+ end
+ end
+
+ $tk_event_queue = []
+ def tk_recv()
+ val = nil
+ $_ = Qwish.pop
+ loop do
+ if /^=(.*)@@$/
+ val = $1
+ break
+ elsif /^=/
+ val = $' + "\n"
+ while TRUE
+ PORT.readline
+ if ~/@@$/
+ val += $'
+ return val
+ else
+ v>al += $_
+ end
+ end
+ elsif /^!/
+ $@ = error_at
+ msg = $'
+ if msg =~ /unknown option "-(.*)"/
+ fail NameError, format("undefined method `%s' for %s(%s)", $1, self, self.type) #`'
+ else
+ fail format("%s - %s", self.type, msg)
+ end
+ end
+ Qcmd.push line
+ end
+
+ fail 'wish closed' if PORT.closed?
+# tk_split_list(val)
+ val
+ end
+
+ def tk_call(*args)
+ Tk.init if $tk_not_init
+ args = args.collect{|s|
+ next if s == None
+ if s.kind_of?(Hash)
+ s = hash_kv(s).join(" ")
+ else
+ if not s
+ s = "0"
+ elsif s == TRUE
+ s = "1"
+ elsif s.kind_of?(TkObject)
+ s = s.path
+ else
+ s = s.to_s
+ s.gsub!(/[{}]/, '\\\\\0')
+ end
+ "{#{s}}"
+ end
+ }
+ str = args.join(" ")
+ Qin.push str
+ return Qout.pop
+ end
+
+ def tk_write(*args)
+ PORT.printf *args; PORT.print "\n"
+ PORT.flush
+ end
+ module_function :tk_write, :tk_recv
+ tk_write '\
+wm withdraw .
+proc rb_out args {
+ puts [format %%s $args]
+ flush stdout
+}
+proc tkerror args { exit }
+proc keepalive {} { rb_out alive; after 120000 keepalive}
+after 120000 keepalive'
+
+ READ_TH = {}
+ def file_readable(port, cmd)
+ if cmd == nil
+ if READ_TH[port].has_key?
+ READ_TH[port].exit
+ READ_TH[port] = nil
+ end
+ else
+ READ_TH[port] = Thread.start{
+ loop do
+ TkUtil.eval_cmd cmd
+ end
+ }
+ end
+ end
+
+ WRITE_TH = {}
+ def file_writable(port, cmd)
+ if cmd == nil
+ if WRITE_TH[port].has_key?
+ WRITE_TH[port].exit
+ end
+ else
+ WRITE_TH[port] = Thread.start{
+ loop do
+ TkUtil.eval_cmd cmd
+ end
+ }
+ end
+ end
+ module_function :file_readable, :file_writable
+
+ def tk_tcl2ruby(val)
+ case val
+ when /^-?\d+$/
+ val.to_i
+ when /^\./
+ $tk_window_list[val]
+ when /^rb_out (c\d+)/
+ $tk_cmdtbl[$1]
+ when / /
+ val.split.collect{|elt|
+ tk_tcl2ruby(elt)
+ }
+ when /^-?\d+\.\d*$/
+ val.to_f
+ else
+ val
+ end
+ end
+
+ def tk_split_list(str)
+ idx = str.index('{')
+ return tk_tcl2ruby(str) if not idx
+
+ list = tk_tcl2ruby(str[0,idx])
+ str = str[idx+1..-1]
+ i = -1
+ brace = 1
+ str.each_byte {|c|
+ i += 1
+ brace += 1 if c == ?{
+ brace -= 1 if c == ?}
+ break if brace == 0
+ }
+ if str[0, i] == ' '
+ list.push ' '
+ else
+ list.push tk_split_list(str[0, i])
+ end
+ list += tk_split_list(str[i+1..-1])
+ list
+ end
+ private :tk_tcl2ruby, :tk_split_list
+
+ def dispatch(line)
+ if line =~ /^c\d+/
+ cmd = $&
+ fail "no command `#{cmd}'" if not $tk_cmdtbl[cmd]
+ args = tk_split_list($')
+ TkUtil.eval_cmd $tk_cmdtbl[cmd], *args
+ elsif line =~ /^alive$/
+ # keep alive, do nothing
+ else
+ fail "malformed line <#{line}>"
+ end
+ end
+ module_function :dispatch
+
+ def error_at
+ n = 1
+ while c = caller(n)
+ break if c !~ /tk\.rb:/
+ n+=1
+ end
+ c
+ end
+
+ def bool(val)
+ case bool
+ when "1", 1, 'yes', 'true'
+ TRUE
+ else
+ FALSE
+ end
+ end
+ def number(val)
+ case val
+ when /^-?\d+$/
+ val.to_i
+ when /^-?\d+\.\d*$/
+ val.to_f
+ else
+ val
+ end
+ end
+ def string(val)
+ if val == "{}"
+ ''
+ elsif val[0] == ?{
+ val[1..-2]
+ else
+ val
+ end
+ end
+ def list(val)
+ tk_split_list(val)
+ end
+ def window(val)
+ $tk_window_list[val]
+ end
+ def procedure(val)
+ if val =~ /^rb_out (c\d+)/
+ $tk_cmdtbl[$1]
+ else
+ nil
+ end
+ end
+ private :bool, :number, :string, :list, :window, :procedure
+
+ def hash_kv(keys)
+ conf = []
+ if keys
+ for k, v in keys
+ conf.push("-#{k}")
+ v = install_cmd(v) if v.type == Proc
+ conf.push(v)
+ end
+ end
+ conf
+ end
+ private :tk_call, :error_at, :hash_kv
+
+ $tk_cmdid = 0
+ def install_cmd(cmd)
+ return '' if cmd == '' # uninstall cmd
+ id = format("c%.4d", $tk_cmdid)
+ $tk_cmdid += 1
+ $tk_cmdtbl[id] = cmd
+ @cmdtbl = [] if not @cmdtbl
+ @cmdtbl.push id
+ return format('rb_out %s', id)
+ end
+ def uninstall_cmd(id)
+ $tk_cmdtbl[id] = nil
+ end
+ private :install_cmd, :uninstall_cmd
+
+ $tk_window_list = {}
+ class Event
+ def initialize(seq,b,f,h,k,s,t,w,x,y,aa,ee,kk,nn,ww,tt,xx,yy)
+ @serial = seq
+ @num = b
+ @focus = (f == 1)
+ @height = h
+ @keycode = k
+ @state = s
+ @time = t
+ @width = w
+ @x = x
+ @y = y
+ @char = aa
+ @send_event = (ee == 1)
+ @keysym = kk
+ @keysym_num = nn
+ @type = tt
+ @widget = ww
+ @x_root = xx
+ @y_root = yy
+ end
+ attr :serial
+ attr :num
+ attr :focus
+ attr :height
+ attr :keycode
+ attr :state
+ attr :time
+ attr :width
+ attr :x
+ attr :y
+ attr :char
+ attr :send_event
+ attr :keysym
+ attr :keysym_num
+ attr :type
+ attr :widget
+ attr :x_root
+ attr :y_root
+ end
+
+ def install_bind(cmd, args=nil)
+ if args
+ id = install_cmd(proc{|arg|
+ TkUtil.eval_cmd cmd, *arg
+ })
+ id + " " + args
+ else
+ id = install_cmd(proc{|arg|
+ TkUtil.eval_cmd cmd, Event.new(*arg)
+ })
+ id + " %# %b %f %h %k %s %t %w %x %y %A %E %K %N %W %T %X %Y"
+ end
+ end
+
+ def _bind(path, context, cmd, args=nil)
+ begin
+ id = install_bind(cmd, args)
+ tk_call 'bind', path, "<#{context}>", id
+ rescue
+ $tk_cmdtbl[id] = nil
+ fail
+ end
+ end
+ private :install_bind, :_bind
+
+ def bind_all(context, cmd=Proc.new, args=nil)
+ _bind 'all', context, cmd, args
+ end
+
+ def pack(*args)
+ TkPack.configure *args
+ end
+
+ $tk_cmdtbl = {}
+
+ Qafter = Queue.new
+ def after(ms, cmd=Proc.new)
+ unless $tk_after_thread
+ $tk_after_thread = Thread.start{
+ loop do
+ cmd = Qafter.pop
+ TkUtil.eval_cmd cmd
+ end
+ }
+ end
+ Thread.start do
+ sleep Float(ms)/1000
+ Qafter.push cmd
+ end
+ end
+
+ def update(idle=nil)
+ if idle
+ tk_call 'update', 'idletasks'
+ else
+ tk_call 'update'
+ end
+ end
+
+ def root
+ $tk_root
+ end
+
+ def bell
+ tk_call 'bell'
+ end
+
+ def mainloop
+ begin
+ tk_call 'after', 'idle', 'wm deiconify .'
+ loop do
+ dispatch Qcmd.pop
+ end
+ ensure
+ Tk.tk_exit
+ end
+ end
+ module_function :after, :update, :dispatch, :mainloop, :root, :bell
+
+ module Scrollable
+ def xscrollcommand(cmd)
+ configure_cmd 'xscrollcommand', cmd
+ end
+ def yscrollcommand(cmd)
+ configure_cmd 'yscrollcommand', cmd
+ end
+ end
+
+ module Wm
+ def aspect(*args)
+ w = window(tk_call('wm', 'grid', path, *args))
+ w.split.collect{|s|s.to_i} if args.length == 0
+ end
+ def client(name=None)
+ tk_call 'wm', 'client', path, name
+ end
+ def colormapwindows(*args)
+ list(tk_call('wm', 'colormapwindows', path, *args))
+ end
+ def wm_command(value=None)
+ string(tk_call('wm', 'command', path, value))
+ end
+ def deiconify
+ tk_call 'wm', 'deiconify', path
+ end
+ def focusmodel(*args)
+ tk_call 'wm', 'focusmodel', path, *args
+ end
+ def frame
+ tk_call 'wm', 'frame', path
+ end
+ def geometry(*args)
+ list(tk_call('wm', 'geometry', path, *args))
+ end
+ def grid(*args)
+ w = tk_call('wm', 'grid', path, *args)
+ list(w) if args.size == 0
+ end
+ def group(*args)
+ tk_call 'wm', 'path', path, *args
+ end
+ def iconbitmap(*args)
+ tk_call 'wm', 'bitmap', path, *args
+ end
+ def iconify
+ tk_call 'wm', 'iconify'
+ end
+ def iconmask(*args)
+ tk_call 'wm', 'iconmask', path, *args
+ end
+ def iconname(*args)
+ tk_call 'wm', 'iconname', path, *args
+ end
+ def iconposition(*args)
+ w = tk_call('wm', 'iconposition', path, *args)
+ list(w) if args.size == 0
+ end
+ def iconwindow(*args)
+ tk_call 'wm', 'iconwindow', path, *args
+ end
+ def maxsize(*args)
+ w = tk_call('wm', 'maxsize', path, *args)
+ list(w) if not args.size == 0
+ end
+ def minsize(*args)
+ w = tk_call('wm', 'minsize', path, *args)
+ list(w) if args.size == 0
+ end
+ def overrideredirect(bool=None)
+ if bool == None
+ bool(tk_call('wm', 'overrideredirect', path))
+ else
+ tk_call 'wm', 'overrideredirect', path, bool
+ end
+ end
+ def positionfrom(*args)
+ tk_call 'wm', 'positionfrom', path, *args
+ end
+ def protocol(name, func=None)
+ func = install_cmd(func) if not func == None
+ tk_call 'wm', 'command', path, name, func
+ end
+ def resizable(*args)
+ w = tk_call('wm', 'resizable', path, *args)
+ if args.length == 0
+ list(w).collect{|e| bool(e)}
+ end
+ end
+ def sizefrom(*args)
+ list(tk_call('wm', 'sizefrom', path, *args))
+ end
+ def state
+ tk_call 'wm', 'state', path
+ end
+ def title(*args)
+ tk_call 'wm', 'title', path, *args
+ end
+ def transient(*args)
+ tk_call 'wm', 'transient', path, *args
+ end
+ def withdraw
+ tk_call 'wm', 'withdraw', path
+ end
+ end
+end