summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/English.rb28
-rw-r--r--lib/base64.rb47
-rw-r--r--lib/date.rb221
-rw-r--r--lib/debug.rb262
-rw-r--r--lib/e2mmap.rb94
-rw-r--r--lib/e2mmap1_0.rb71
-rw-r--r--lib/finalize.rb205
-rw-r--r--lib/ftplib.rb617
-rw-r--r--lib/jcode.rb35
-rw-r--r--lib/mathn.rb3
-rw-r--r--lib/matrix.rb777
-rw-r--r--lib/mutex_m.rb183
-rw-r--r--lib/observer.rb2
-rw-r--r--lib/parsedate.rb12
-rw-r--r--lib/ping.rb55
-rw-r--r--lib/safe.rb78
-rw-r--r--lib/sync.rb376
-rw-r--r--lib/thread.rb117
-rw-r--r--lib/thwait.rb128
-rw-r--r--lib/tk.rb128
-rw-r--r--lib/tkcanvas.rb21
-rw-r--r--lib/tkclass.rb2
-rw-r--r--lib/tkcore.rb40
-rw-r--r--lib/tkentry.rb15
-rw-r--r--lib/tkscrollbox.rb4
-rw-r--r--lib/tktext.rb46
-rw-r--r--lib/tkthcore.rb33
-rw-r--r--lib/tracer.rb75
28 files changed, 3376 insertions, 299 deletions
diff --git a/lib/English.rb b/lib/English.rb
new file mode 100644
index 0000000000..c7e13bebe6
--- /dev/null
+++ b/lib/English.rb
@@ -0,0 +1,28 @@
+
+alias $ERROR_INFO $!
+alias $ERROR_POSITION $@
+alias $LOADED_FEATURES $"
+alias $FS $;
+alias $FIELD_SEPARATOR $;
+alias $OFS $,
+alias $OUTPUT_FIELD_SEPARATOR $,
+alias $RS $/
+alias $INPUT_RECORD_SEPARATOR $/
+alias $ORS $\
+alias $OUPUT_RECORD_SEPARATOR $\
+alias $INPUT_LINE_NUMBER $.
+alias $NR $.
+alias $LAST_READ_LINE $_
+alias $DEFAULT_OUTPUT $>
+alias $DEFAULT_INPUT $<
+alias $PID $$
+alias $PROCESS_ID $$
+alias $CHILD_STATUS $?
+alias $LAST_MATCH_INFO $~
+alias $IGNORECASE $=
+alias $PROGRAM_NAME $0
+alias $ARGV $*
+alias $MATCH $&
+alias $PREMATCH $`
+alias $POSTMATCH $'
+alias $LAST_PAREN_MATCH $+
diff --git a/lib/base64.rb b/lib/base64.rb
index 9bb6487bee..96208a634d 100644
--- a/lib/base64.rb
+++ b/lib/base64.rb
@@ -1,29 +1,11 @@
def decode64(str)
- e = -1;
- c = ","
- string=''
+ string = ''
for line in str.split("\n")
- line.sub!(/=+$/, '')
- line.tr! 'A-Za-z0-9+/', "\000-\377"
- line.each_byte { |ch|
- n +=1
- e +=1
- if e==0
- c = ch << 2
- elsif e==1
- c |= ch >>4
- string += [c].pack('c')
- c = ch << 4
- elsif e == 2
- c |= ch >> 2
- string += [c].pack('c');
- c = ch << 6
- elsif e==3
- c |= ch
- string += [c].pack('c')
- e = -1
- end
- }
+ line.delete!('^A-Za-z0-9+/') # remove non-base64 chars
+ line.tr!('A-Za-z0-9+/', ' -_') # convert to uuencoded format
+ len = ["#{32 + line.length * 3 / 4}"].pack("c")
+ # compute length byte
+ string += "#{len}#{line}".unpack("u") # uudecode and concatenate
end
return string
end
@@ -53,3 +35,20 @@ def decode_b(str)
str.gsub!(/\0/, '')
j2e(str)
end
+
+def encode64(bin)
+ encode = ""
+ pad = 0
+ [bin].pack("u").each do |uu|
+ len = (2 + (uu[0] - 32)* 4) / 3
+ encode << uu[1, len].tr('` -_', 'AA-Za-z0-9+/')
+ pad += uu.length - 2 - len
+ end
+ encode + "=" * (pad % 3)
+end
+
+def b64encode(bin, len = 60)
+ encode64(bin).scan(/.{1,#{len}}/o) do
+ print $&, "\n"
+ end
+end
diff --git a/lib/date.rb b/lib/date.rb
new file mode 100644
index 0000000000..260f6e79ec
--- /dev/null
+++ b/lib/date.rb
@@ -0,0 +1,221 @@
+#
+# Date.rb -
+# $Release Version: $
+# $Revision: 1.2 $
+# $Date: 1997/02/14 11:05:29 $
+# by Yasuo OHBA(SHL Japan Inc. Technology Dept.)
+#
+# --
+#
+# September 1752
+# S M Tu W Th F S
+# 1 2 14 15 16
+# 17 18 19 20 21 22 23
+# 24 25 26 27 28 29 30
+#
+
+class Date
+ include Comparable
+
+ def initialize(y = 1, m = 1, d = 1)
+ if y.kind_of?(String) && y.size == 8
+ @year = y[0,4].to_i
+ @month = y[4,2].to_i
+ @day = y[6,2].to_i
+ else
+ if m.kind_of?(String)
+ ml = {"jan"=>1, "feb"=>2, "mar"=>3, "apr"=>4, "may"=>5, "jun"=>6, "jul"=>7, "aug"=>8, "sep"=>9, "oct"=>10, "nov"=>11, "dec"=>12}
+ m = ml[m.downcase]
+ if m.nil?
+ raise ArgumentError, "Wrong argument. (month)"
+ end
+ end
+ @year = y.to_i
+ @month = m.to_i
+ @day = d.to_i
+ end
+ _check_date
+ return self
+ end
+
+ def year
+ return @year
+ end
+
+ def month
+ return @month
+ end
+
+ def day
+ return @day
+ end
+
+ def period
+ return Date.period!(@year, @month, @day)
+ end
+
+ def day_of_week
+ dl = Date.daylist(@year)
+ d = Date.jan1!(@year)
+ for m in 1..(@month - 1)
+ d += dl[m]
+ end
+ d += @day - 1
+ if @year == 1752 && @month == 9 && @day >= 14
+ d -= (14 - 3)
+ end
+ return (d % 7)
+ end
+
+ Weektag = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
+ def name_of_week
+ return Weektag[self.day_of_week]
+ end
+
+ def +(o)
+ if o.kind_of?(Integer)
+ d = self.period + o
+ elsif o.kind_of?(Date)
+ d = self.period + o.period
+ else
+ raise TypeError, "Illegal type. (Integer or Date)"
+ end
+ return Date.at(d)
+ end
+
+ def -(o)
+ if o.kind_of?(Integer)
+ d = self.period - o
+ elsif o.kind_of?(Date)
+ d = self.period - o.period
+ else
+ raise TypeError, "Illegal type. (Integer or Date)"
+ end
+ if d <= 0
+ raise ArgumentError, "argument out of range. (self > other)"
+ end
+ return Date.at(d)
+ end
+
+ def <=>(o)
+ if o.kind_of?(Integer)
+ d = o
+ elsif o.kind_of?(Date)
+ d = o.period
+ else
+ raise TypeError, "Illegal type. (Integer or Date)"
+ end
+ return self.period <=> d
+ end
+
+ def eql?(o)
+ self == o
+ end
+
+ def hash
+ return @year ^ @month ^ @day
+ end
+
+ def leapyear?
+ if Date.leapyear(@year) == 1
+ return FALSE
+ else
+ return TRUE
+ end
+ end
+
+ def _check_date
+ m = Date.daylist(@year)
+ if @month < 1 || @month > 12
+ raise ArgumentError, "argument(month) out of range."
+ return nil
+ end
+ if @year == 1752 && @month == 9
+ if @day >= 3 && @day <= 13
+ raise ArgumentError, "argument(1752/09/3-13) out of range."
+ return nil
+ end
+ d = 30
+ else
+ d = m[@month]
+ end
+ if @day < 1 || @day > d
+ raise ArgumentError, "argument(day) out of range."
+ return nil
+ end
+ return self
+ end
+
+ private :_check_date
+end
+
+def Date.at(d)
+ mm = 1
+ yy = (d / 366.0).to_i
+ if yy != 0
+ dd = d - (Date.period!(yy, 1, 1) - 1)
+ else
+ dd = d
+ yy = 1
+ end
+ dl = Date.daylist(yy)
+ while dd > dl[mm]
+ if dd > dl[0]
+ dd -= dl[0]
+ yy += 1
+ dl = Date.daylist(yy)
+ else
+ dd -= dl[mm]
+ mm += 1
+ end
+ end
+ if yy == 1752 && mm == 9 && dd >= 3 && dd <= 19
+ dd += (14 - 3) # 1752/09/03-19 -> 1752/09/14-30
+ end
+
+ return Date.new(yy, mm, dd)
+end
+
+def Date.period!(y, m, d)
+ p = d
+ dl = Date.daylist(y)
+ for mm in 1..(m - 1)
+ p += dl[mm]
+ end
+ p += (y - 1) * 365 + ((y - 1) / 4.0).to_i
+ if (y - 1) > 1752
+ p -= ((y - 1 - 1752) / 100.0).to_i
+ p += ((y - 1 - 1752) / 400.0).to_i
+ p -= (14 - 3)
+ elsif y == 1752 && m == 9 && d >= 14 && d <= 30
+ p -= (14 - 3)
+ end
+ return p
+end
+
+def Date.leapyear(yy)
+ return ((Date.jan1!(yy + 1) + 7 - Date.jan1!(yy)) % 7)
+end
+
+def Date.daylist(yy)
+ case (Date.leapyear(yy))
+ when 1 # non-leapyear
+ return [365, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
+ when 2 # leapyear
+ return [366, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
+ else # 1752
+ return [355, 31, 29, 31, 30, 31, 30, 31, 31, 19, 31, 30, 31]
+ end
+end
+
+def Date.jan1!(y)
+ d = 4 + y + (y + 3) / 4
+ if y > 1800
+ d -= (y - 1701) / 100
+ d += (y - 1601) / 400
+ end
+ if y > 1752
+ d += 3
+ end
+ return (d % 7)
+end
diff --git a/lib/debug.rb b/lib/debug.rb
new file mode 100644
index 0000000000..432c7b4d19
--- /dev/null
+++ b/lib/debug.rb
@@ -0,0 +1,262 @@
+
+class DEBUGGER__
+ trap("INT") { DEBUGGER__::CONTEXT.interrupt }
+ $DEBUG = TRUE
+ def initialize
+ @break_points = []
+ @stop_next = 1
+ @frames = [nil]
+ @frame_pos = nil
+ @last_file = nil
+ @scripts = {}
+ end
+
+ def interrupt
+ @stop_next = 1
+ end
+
+ def debug_eval(str, binding)
+ begin
+ val = eval(str, binding)
+ val
+ rescue
+ at = caller(0)
+ printf "%s:%s\n", at.shift, $!
+ for i in at
+ break if i =~ /`debug_(eval|command)'$/ #`
+ printf "\tfrom %s\n", i
+ end
+ end
+ end
+
+ def debug_command(file, line, id, binding)
+ if (ENV['EMACS'] == 't')
+ printf "\032\032%s:%d:\n", file, line
+ else
+ printf "%s:%d:%s", file, line, line_at(file, line)
+ end
+ @frames[-1] = binding
+ STDOUT.print "(rdb:-) "
+ STDOUT.flush
+ while input = STDIN.gets
+ input.chop!
+ case input
+ when /^b(reak)?\s+(([^:\n]+:)?.+)/
+ pos = $2
+ if pos.index ":"
+ file, pos = pos.split(":")
+ end
+ file = File.basename(file)
+ if pos =~ /^\d+$/
+ pname = pos
+ pos = Integer(pos)
+ else
+ pname = pos = pos.intern.id2name
+ end
+ printf "Set breakpoint %d at %s:%s\n", @break_points.size, file, pname
+ @break_points.push [file, pos]
+ when /^b(reak)?$/, /^info b(reak)?$/
+ n = 0
+ for f, p in @break_points
+ printf "%d %s:%s\n", n, f, p
+ n += 1
+ end
+ when /^del(ete)?(\s+(\d+))?$/
+ pos = $3
+ unless pos
+ STDOUT.print "clear all breakpoints? (y/n) "
+ STDOUT.flush
+ input = STDIN.gets.chop!
+ if input == "y"
+ for n in @break_points.indexes
+ @break_points[n] = nil
+ end
+ end
+ else
+ pos = Integer(pos)
+ if @break_points[pos]
+ bp = @break_points[pos]
+ printf "Clear breakpoint %d at %s:%s\n", pos, bp[0], bp[1]
+ @break_points[pos] = nil
+ else
+ printf "Breakpoint %d is not defined\n", pos
+ end
+ end
+ when /^c(ont)?$/
+ return
+ when /^s(tep)?\s*(\d+)?$/
+ if $1
+ lev = Integer($1)
+ else
+ lev = 1
+ end
+ @stop_next = lev
+ return
+ when /^n(ext)?\s*(\d+)?$/
+ if $1
+ lev = Integer($1)
+ else
+ lev = 1
+ end
+ @stop_next = lev
+ @no_step = @frames.size
+ return
+ when /^up\s*(\d+)?$/
+ if $1
+ lev = Integer($1)
+ else
+ lev = 1
+ end
+ unless @frame_pos
+ @frame_pos = @frames.size - 1
+ end
+ @frame_pos -= lev
+ if @frame_pos < 0
+ STDOUT.print "at toplevel\n"
+ @frame_pos = 0
+ else
+ binding = @frames[@frame_pos]
+ end
+ when /^down\s*(\d+)??$/
+ if $1
+ lev = Integer($1)
+ else
+ lev = 1
+ end
+ if lev >= @frames.size or @frame_pos and @frame_pos+lev >= @frames.size
+ STDOUT.print "at stack bottom\n"
+ @frame_pos = nil
+ else
+ @frame_pos += lev
+ binding = @frames[@frame_pos]
+ end
+ when /^fin(ish)?$/
+ @finish_pos = @frames.size
+ return
+ when /^q(uit)?$/
+ STDOUT.print "really quit? (y/n) "
+ STDOUT.flush
+ input = STDIN.gets.chop!
+ exit if input == "y"
+ when /^where$/
+ at = caller(4)
+ for i in at
+ printf " %s\n", i
+ end
+ when /^l(ist)?(\s+(.*))?$/
+ if $3
+ b, e = $3.split(/[-,]/)
+ b = Integer(b)-1
+ if e
+ e = Integer(e)-1
+ else
+ e = b + 10
+ end
+ end
+ unless b
+ b = line - 1
+ e = line + 9
+ end
+ p [b,e]
+ line_at(file, line)
+ if lines = @scripts[file] and lines != TRUE
+ n = b+1
+ for l in lines[b..e]
+ printf "%4d %s", n, l
+ n += 1
+ end
+ else
+ printf "no sourcefile available for %s\n", file
+ end
+ when /^p\s+/
+ p debug_eval($', binding)
+ else
+ v = debug_eval(input, binding)
+ p v unless v == nil
+ end
+ STDOUT.print "(rdb:-) "
+ STDOUT.flush
+ end
+ end
+
+ def line_at(file, line)
+ lines = @scripts[file]
+ if lines
+ return "\n" if lines == TRUE
+ line = lines[line-1]
+ return "\n" unless line
+ return line
+ end
+ begin
+ f = open(file)
+ lines = @scripts[file] = f.readlines
+ rescue
+ @scripts[file] = TRUE
+ return "\n"
+ end
+ line = lines[line-1]
+ return "\n" unless line
+ return line
+ end
+
+ def debug_funcname(id)
+ if id == 0
+ "toplevel"
+ else
+ id.id2name
+ end
+ end
+
+ def check_break_points(file, pos, binding, id)
+ file = File.basename(file)
+ if @break_points.include? [file, pos]
+ index = @break_points.index([file, pos])
+ printf "Breakpoint %d, %s at %s:%s\n",
+ index, debug_funcname(id), file, pos
+ return TRUE
+ end
+ return FALSE
+ end
+
+ def trace_func(event, file, line, id, binding)
+ if event == 'line'
+ if @no_step == nil or @no_step >= @frames.size
+ @stop_next -= 1
+ end
+ if @stop_next == 0
+ if [file, line] == @last
+ @stop_next = 1
+ else
+ @no_step = nil
+ debug_command(file, line, id, binding)
+ @last = [file, line]
+ end
+ end
+ if check_break_points(file, line, binding, id)
+ debug_command(file, line, id, binding)
+ end
+ end
+ if event == 'call'
+ @frames.push binding
+ if check_break_points(file, id.id2name, binding, id)
+ debug_command(file, line, id, binding)
+ end
+ end
+ if event == 'class'
+ @frames.push binding
+ end
+ if event == 'return' or event == 'end'
+ if @finish_pos == @frames.size
+ @stop_next = 1
+ end
+ @frames.pop
+ end
+ @last_file = file
+ end
+
+ CONTEXT = new
+end
+
+set_trace_func proc{|event, file, line, id, binding|
+ DEBUGGER__::CONTEXT.trace_func event, file, line, id, binding
+}
diff --git a/lib/e2mmap.rb b/lib/e2mmap.rb
new file mode 100644
index 0000000000..d10657bbad
--- /dev/null
+++ b/lib/e2mmap.rb
@@ -0,0 +1,94 @@
+#
+# e2mmap.rb - for ruby 1.1
+# $Release Version: 1.1$
+# $Revision: 1.4 $
+# $Date: 1997/08/18 07:12:12 $
+# by Keiju ISHITSUKA
+#
+# --
+#
+#
+if VERSION < "1.1"
+ require "e2mmap1_0.rb"
+else
+
+ module Exception2MessageMapper
+ RCS_ID='-$Header: /home/keiju/var/src/var.lib/ruby/RCS/e2mmap.rb,v 1.4 1997/08/18 07:12:12 keiju Exp keiju $-'
+
+ E2MM = Exception2MessageMapper
+
+ def E2MM.extend_object(cl)
+ super
+ cl.bind(self)
+ end
+
+ # 以前との互換性のために残してある.
+ def E2MM.extend_to(b)
+ c = eval("self", b)
+ c.extend(self)
+ end
+
+# public :fail
+ # alias e2mm_fail fail
+
+ def fail(err = nil, *rest)
+ Exception2MessageMapper.fail Exception2MessageMapper::ErrNotRegisteredException, err.to_s
+ end
+
+ def bind(cl)
+ self.module_eval %q^
+ E2MM_ErrorMSG = {}
+ # fail(err, *rest)
+ # err: 例外
+ # rest: メッセージに渡すパラメータ
+ #
+ def self.fail(err = nil, *rest)
+ $@ = caller(0) if $@.nil?
+ $@.shift
+ if form = E2MM_ErrorMSG[err]
+ $! = err.new(sprintf(form, *rest))
+ # e2mm_fail()
+ raise()
+# elsif self == Exception2MessageMapper
+# fail Exception2MessageMapper::ErrNotRegisteredException, err.to_s
+ else
+# print "super\n"
+ super
+ end
+ end
+ class << self
+ public :fail
+ end
+
+ # def_exception(c, m)
+ # c: exception
+ # m: message_form
+ # 例外cのメッセージをmとする.
+ #
+ def self.def_e2message(c, m)
+ E2MM_ErrorMSG[c] = m
+ end
+
+ # def_exception(c, m)
+ # n: exception_name
+ # m: message_form
+ # s: 例外スーパークラス(デフォルト: Exception)
+ # 例外名``c''をもつ例外を定義し, そのメッセージをmとする.
+ #
+ #def def_exception(n, m)
+ def self.def_exception(n, m, s = Exception)
+ n = n.id2name if n.kind_of?(Fixnum)
+ e = Class.new(s)
+ const_set(n, e)
+ E2MM_ErrorMSG[e] = m
+ # const_get(:E2MM_ErrorMSG)[e] = m
+ end
+ ^
+ end
+
+ extend E2MM
+ def_exception(:ErrNotClassOrModule, "Not Class or Module")
+ def_exception(:ErrNotRegisteredException, "not registerd exception(%s)")
+ end
+end
+
diff --git a/lib/e2mmap1_0.rb b/lib/e2mmap1_0.rb
new file mode 100644
index 0000000000..c5797fd573
--- /dev/null
+++ b/lib/e2mmap1_0.rb
@@ -0,0 +1,71 @@
+#
+# e2mmap.rb -
+# $Release Version: 1.0$
+# $Revision: 1.4 $
+# $Date: 1997/08/18 07:12:12 $
+# by Keiju ISHITSUKA
+#
+# --
+#
+#
+
+module Exception2MessageMapper
+ RCS_ID='-$Header: /home/keiju/var/src/var.lib/ruby/RCS/e2mmap.rb,v 1.4 1997/08/18 07:12:12 keiju Exp keiju $-'
+ E2MM = Exception2MessageMapper
+
+ def E2MM.extend_to(b)
+ c = eval("self", b)
+ c.extend(self)
+ c.bind(b)
+ end
+
+ def bind(b)
+ eval "
+ @binding = binding
+ E2MM_ErrorMSG = Hash.new
+
+ # fail(err, *rest)
+ # err: 例外
+ # rest: メッセージに渡すパラメータ
+ #
+ def fail!(*rest)
+ super
+ end
+
+ def fail(err, *rest)
+ $! = err.new(sprintf(E2MM_ErrorMSG[err], *rest))
+ super()
+ end
+
+ public :fail
+ # def_exception(c, m)
+ # c: exception
+ # m: message_form
+ # 例外cのメッセージをmとする.
+ #
+ def def_e2message(c, m)
+ E2MM_ErrorMSG[c] = m
+ end
+
+ # def_exception(c, m)
+ # c: exception_name
+ # m: message_form
+ # s: 例外スーパークラス(デフォルト: Exception)
+ # 例外名``c''をもつ例外を定義し, そのメッセージをmとする.
+ #
+ def def_exception(c, m)
+
+ c = c.id2name if c.kind_of?(Fixnum)
+ eval \"class \#{c} < Exception
+ end
+ E2MM_ErrorMSG[\#{c}] = '\#{m}'
+ \", @binding
+ end
+", b
+
+ end
+
+ E2MM.extend_to(binding)
+ def_exception("ErrNotClassOrModule", "Not Class or Module")
+end
+
diff --git a/lib/finalize.rb b/lib/finalize.rb
new file mode 100644
index 0000000000..e934753e19
--- /dev/null
+++ b/lib/finalize.rb
@@ -0,0 +1,205 @@
+#
+# finalize.rb -
+# $Release Version: $
+# $Revision: 1.2 $
+# $Date: 1997/07/25 02:43:00 $
+# by Keiju ISHITSUKA(SHL Japan Inc.)
+#
+# --
+#
+# Usage:
+#
+# add(obj, dependant, method = :finalize, *opt)
+# add_dependency(obj, dependant, method = :finalize, *opt)
+# 依存関係 R_method(obj, dependant) の追加
+#
+# delete(obj_or_id, dependant, method = :finalize)
+# delete_dependency(obj_or_id, dependant, method = :finalize)
+# 依存関係 R_method(obj, dependant) の削除
+# delete_all_dependency(obj_or_id, dependant)
+# 依存関係 R_*(obj, dependant) の削除
+# delete_by_dependant(dependant, method = :finalize)
+# 依存関係 R_method(*, dependant) の削除
+# delete_all_by_dependant(dependant)
+# 依存関係 R_*(*, dependant) の削除
+# delete_all
+# 全ての依存関係の削除.
+#
+# finalize(obj_or_id, dependant, method = :finalize)
+# finalize_dependency(obj_or_id, dependant, method = :finalize)
+# 依存関連 R_method(obj, dependtant) で結ばれるdependantを
+# finalizeする.
+# finalize_all_dependency(obj_or_id, dependant)
+# 依存関連 R_*(obj, dependtant) で結ばれるdependantをfinalizeする.
+# finalize_by_dependant(dependant, method = :finalize)
+# 依存関連 R_method(*, dependtant) で結ばれるdependantをfinalizeする.
+# fainalize_all_by_dependant(dependant)
+# 依存関連 R_*(*, dependtant) で結ばれるdependantをfinalizeする.
+# finalize_all
+# Finalizerに登録される全てのdependantをfinalizeする
+#
+# safe{..}
+# gc時にFinalizerが起動するのを止める.
+#
+#
+
+module Finalizer
+ RCS_ID='-$Header: /home/keiju/var/src/var.lib/ruby/RCS/finalize.rb,v 1.2 1997/07/25 02:43:00 keiju Exp keiju $-'
+
+ # @dependency: {id => [[dependant, method, *opt], ...], ...}
+
+ # 依存関係 R_method(obj, dependant) の追加
+ def add_dependency(obj, dependant, method = :finalize, *opt)
+ ObjectSpace.call_finalizer(obj)
+ method = method.id unless method.kind_of?(Fixnum)
+ assoc = [dependant, method].concat(opt)
+ if dep = @dependency[obj.id]
+ dep.push assoc
+ else
+ @dependency[obj.id] = [assoc]
+ end
+ end
+ alias add add_dependency
+
+ # 依存関係 R_method(obj, dependant) の削除
+ def delete_dependency(id, dependant, method = :finalize)
+ id = id.id unless id.kind_of?(Fixnum)
+ method = method.id unless method.kind_of?(Fixnum)
+ for assoc in @dependency[id]
+ assoc.delete_if do
+ |d, m, *o|
+ d == dependant && m == method
+ end
+ @dependency.delete(id) if assoc.empty?
+ end
+ end
+ alias delete delete_dependency
+
+ # 依存関係 R_*(obj, dependant) の削除
+ def delete_all_dependency(id, dependant)
+ id = id.id unless id.kind_of?(Fixnum)
+ method = method.id unless method.kind_of?(Fixnum)
+ for assoc in @dependency[id]
+ assoc.delete_if do
+ |d, m, *o|
+ d == dependant
+ end
+ @dependency.delete(id) if assoc.empty?
+ end
+ end
+
+ # 依存関係 R_method(*, dependant) の削除
+ def delete_by_dependant(dependant, method = :finalize)
+ method = method.id unless method.kind_of?(Fixnum)
+ for id in @dependency.keys
+ delete(id, dependant, method)
+ end
+ end
+
+ # 依存関係 R_*(*, dependant) の削除
+ def delete_all_by_dependant(dependant)
+ for id in @dependency.keys
+ delete_all_dependency(id, dependant)
+ end
+ end
+
+ # 依存関連 R_method(obj, dependtant) で結ばれるdependantをfinalizeす
+ # る.
+ def finalize_dependency(id, dependant, method = :finalize)
+ id = id.id unless id.kind_of?(Fixnum)
+ method = method.id unless method.kind_of?(Fixnum)
+ for assocs in @dependency[id]
+ assocs.delete_if do
+ |d, m, *o|
+ d.send(m, *o) if ret = d == dependant && m == method
+ ret
+ end
+ @dependency.delete(id) if assoc.empty?
+ end
+ end
+ alias finalize finalize_dependency
+
+ # 依存関連 R_*(obj, dependtant) で結ばれるdependantをfinalizeする.
+ def finalize_all_dependency(id, dependant)
+ id = id.id unless id.kind_of?(Fixnum)
+ method = method.id unless method.kind_of?(Fixnum)
+ for assoc in @dependency[id]
+ assoc.delete_if do
+ |d, m, *o|
+ d.send(m, *o) if ret = d == dependant
+ end
+ @dependency.delete(id) if assoc.empty?
+ end
+ end
+
+ # 依存関連 R_method(*, dependtant) で結ばれるdependantをfinalizeする.
+ def finalize_by_dependant(dependant, method = :finalize)
+ method = method.id unless method.kind_of?(Fixnum)
+ for id in @dependency.keys
+ finalize(id, dependant, method)
+ end
+ end
+
+ # 依存関連 R_*(*, dependtant) で結ばれるdependantをfinalizeする.
+ def fainalize_all_by_dependant(dependant)
+ for id in @dependency.keys
+ finalize_all_dependency(id, dependant)
+ end
+ end
+
+ # Finalizerに登録されている全てのdependantをfinalizeする
+ def finalize_all
+ for id, assocs in @dependency
+ for dependant, method, *opt in assocs
+ dependant.send(method, id, *opt)
+ end
+ assocs.clear
+ end
+ end
+
+ # finalize_* を安全に呼び出すためのイテレータ
+ def safe
+ old_status = Thread.critical
+ Thread.critical = TRUE
+ ObjectSpace.remove_finalizer(@proc)
+ yield
+ ObjectSpace.add_finalizer(@proc)
+ Thread.critical = old_status
+ end
+
+ # ObjectSpace#add_finalizerへの登録関数
+ def final_of(id)
+ if assocs = @dependency.delete(id)
+ for dependant, method, *opt in assocs
+ dependant.send(method, id, *opt)
+ end
+ end
+ end
+
+ @dependency = Hash.new
+ @proc = proc{|id| final_of(id)}
+ ObjectSpace.add_finalizer(@proc)
+
+ module_function :add
+ module_function :add_dependency
+
+ module_function :delete
+ module_function :delete_dependency
+ module_function :delete_all_dependency
+ module_function :delete_by_dependant
+ module_function :delete_all_by_dependant
+
+ module_function :finalize
+ module_function :finalize_dependency
+ module_function :finalize_all_dependency
+ module_function :finalize_by_dependant
+ module_function :fainalize_all_by_dependant
+ module_function :finalize_all
+
+ module_function :safe
+
+ module_function :final_of
+ private_class_method :final_of
+
+end
+
diff --git a/lib/ftplib.rb b/lib/ftplib.rb
new file mode 100644
index 0000000000..34ee2f8d62
--- /dev/null
+++ b/lib/ftplib.rb
@@ -0,0 +1,617 @@
+### ftplib.rb -*- Mode: ruby; tab-width: 8; -*-
+
+## $Revision: 1.5 $
+## $Date: 1997/09/16 08:03:31 $
+## by maeda shugo <shugo@po.aianet.ne.jp>
+
+### Code:
+
+require "socket"
+require "sync" if defined? Thread
+
+class FTPError < Exception; end
+class FTPReplyError < FTPError; end
+class FTPTempError < FTPError; end
+class FTPPermError < FTPError; end
+class FTPProtoError < FTPError; end
+
+class FTP
+
+ RCS_ID = '$Id: ftplib.rb,v 1.5 1997/09/16 08:03:31 shugo Exp $'
+
+ FTP_PORT = 21
+ CRLF = "\r\n"
+
+ attr :passive, TRUE
+ attr :return_code, TRUE
+ attr :debug_mode, TRUE
+ attr :welcome
+ attr :lastresp
+
+ THREAD_SAFE = defined?(Thread) != FALSE
+
+ if THREAD_SAFE
+ def synchronize(mode = :EX)
+ if @sync
+ @sync.synchronize(mode) do
+ yield
+ end
+ end
+ end
+
+ def sock_synchronize(mode = :EX)
+ if @sock
+ @sock.synchronize(mode) do
+ yield
+ end
+ end
+ end
+ else
+ def synchronize(mode = :EX)
+ yield
+ end
+
+ def sock_synchronize(mode = :EX)
+ yield
+ end
+ end
+ private :sock_synchronize
+
+ def FTP.open(host, user = nil, passwd = nil, acct = nil)
+ new(host, user, passwd, acct)
+ end
+
+ def initialize(host = nil, user = nil,
+ passwd = nil, acct = nil)
+ if THREAD_SAFE
+ @sync = Sync.new
+ end
+ @passive = FALSE
+ @return_code = "\n"
+ @debug_mode = FALSE
+ if host
+ connect(host)
+ if user
+ login(user, passwd, acct)
+ end
+ end
+ end
+
+ def open_socket(host, port)
+ if defined? SOCKSsocket and ENV["SOCKS_SERVER"]
+ @passive = TRUE
+ SOCKSsocket.open(host, port)
+ else
+ TCPsocket.open(host, port)
+ end
+ end
+ private :open_socket
+
+ def connect(host, port = FTP_PORT)
+ if @debug_mode
+ print "connect: ", host, ", ", port, "\n"
+ end
+ synchronize do
+ @sock = open_socket(host, port)
+ if THREAD_SAFE
+ @sock.extend Sync_m
+ end
+ voidresp
+ end
+ end
+
+ def sanitize(s)
+ if s =~ /^PASS /i
+ s[0, 5] + "*" * (s.length - 5)
+ else
+ s
+ end
+ end
+ private :sanitize
+
+ def putline(line)
+ if @debug_mode
+ print "put: ", sanitize(line), "\n"
+ end
+ line = line + CRLF
+ @sock.write(line)
+ end
+ private :putline
+
+ def getline
+ line = @sock.readline # if get EOF, raise EOFError
+ if line[-2, 2] == CRLF
+ line = line[0 .. -3]
+ elsif line[-1] == ?\r or
+ line[-1] == ?\n
+ line = line[0 .. -2]
+ end
+ if @debug_mode
+ print "get: ", sanitize(line), "\n"
+ end
+ line
+ end
+ private :getline
+
+ def getmultiline
+ line = getline
+ buff = line
+ if line[3] == ?-
+ code = line[0, 3]
+ begin
+ line = getline
+ buff << "\n" << line
+ end until line[0, 3] == code and line[3] != ?-
+ end
+ buff << "\n"
+ end
+ private :getmultiline
+
+ def getresp
+ resp = getmultiline
+ @lastresp = resp[0, 3]
+ c = resp[0]
+ case c
+ when ?1, ?2, ?3
+ return resp
+ when ?4
+ raise FTPTempError, resp
+ when ?5
+ raise FTPPermError, resp
+ else
+ raise FTPProtoError, resp
+ end
+ end
+ private :getresp
+
+ def voidresp
+ resp = getresp
+ if resp[0] != ?2
+ raise FTPReplyError, resp
+ end
+ end
+ private :voidresp
+
+ def sendcmd(cmd)
+ synchronize do
+ sock_synchronize do
+ putline(cmd)
+ getresp
+ end
+ end
+ end
+
+ def voidcmd(cmd)
+ synchronize do
+ sock_synchronize do
+ putline(cmd)
+ voidresp
+ end
+ end
+ nil
+ end
+
+ def sendport(host, port)
+ hbytes = host.split(".")
+ pbytes = [port / 256, port % 256]
+ bytes = hbytes + pbytes
+ cmd = "PORT " + bytes.join(",")
+ voidcmd(cmd)
+ end
+ private :sendport
+
+ def makeport
+ sock = TCPserver.open(0)
+ port = sock.addr[1]
+ host = TCPsocket.getaddress(@sock.addr[2])
+ resp = sendport(host, port)
+ sock
+ end
+ private :makeport
+
+ def transfercmd(cmd)
+ if @passive
+ host, port = parse227(sendcmd("PASV"))
+ conn = open_socket(host, port)
+ resp = sendcmd(cmd)
+ if resp[0] != ?1
+ raise FTPReplyError, resp
+ end
+ else
+ sock = makeport
+ resp = sendcmd(cmd)
+ if resp[0] != ?1
+ raise FTPReplyError, resp
+ end
+ conn = sock.accept
+ end
+ conn
+ end
+ private :transfercmd
+
+ def getaddress
+ thishost = Socket.gethostname
+ if not thishost.index(".")
+ thishost = Socket.gethostbyname(thishost)[0]
+ end
+ if ENV.has_key?("LOGNAME")
+ realuser = ENV["LOGNAME"]
+ elsif ENV.has_key?("USER")
+ realuser = ENV["USER"]
+ else
+ realuser = "anonymous"
+ end
+ realuser + "@" + thishost
+ end
+ private :getaddress
+
+ def login(user = "anonymous", passwd = nil, acct = nil)
+ if user == "anonymous" and passwd == nil
+ passwd = getaddress
+ end
+
+ resp = ""
+ synchronize do
+ resp = sendcmd('USER ' + user)
+ if resp[0] == ?3
+ resp = sendcmd('PASS ' + passwd)
+ end
+ if resp[0] == ?3
+ resp = sendcmd('ACCT ' + acct)
+ end
+ end
+ if resp[0] != ?2
+ raise FTPReplyError, resp
+ end
+ @welcome = resp
+ end
+
+ def retrbinary(cmd, blocksize, callback = Proc.new)
+ synchronize do
+ voidcmd("TYPE I")
+ conn = transfercmd(cmd)
+ while TRUE
+ data = conn.read(blocksize)
+ break if data == nil
+ callback.call(data)
+ end
+ conn.close
+ voidresp
+ end
+ end
+
+ def retrlines(cmd, callback = nil)
+ if iterator?
+ callback = Proc.new
+ elsif not callback.is_a?(Proc)
+ callback = Proc.new {|line| print line, "\n"}
+ end
+ synchronize do
+ voidcmd("TYPE A")
+ conn = transfercmd(cmd)
+ while TRUE
+ line = conn.gets
+ break if line == nil
+ if line[-2, 2] == CRLF
+ line = line[0 .. -3]
+ elsif line[-1] == ?\n
+ line = line[0 .. -2]
+ end
+ callback.call(line)
+ end
+ conn.close
+ voidresp
+ end
+ end
+
+ def storbinary(cmd, file, blocksize, callback = nil)
+ if iterator?
+ callback = Proc.new
+ end
+ use_callback = callback.is_a?(Proc)
+ synchronize do
+ voidcmd("TYPE I")
+ conn = transfercmd(cmd)
+ while TRUE
+ buf = file.read(blocksize)
+ break if buf == nil
+ conn.write(buf)
+ if use_callback
+ callback.call(buf)
+ end
+ end
+ conn.close
+ voidresp
+ end
+ end
+
+ def storlines(cmd, file, callback = nil)
+ if iterator?
+ callback = Proc.new
+ end
+ use_callback = callback.is_a?(Proc)
+ synchronize do
+ voidcmd("TYPE A")
+ conn = transfercmd(cmd)
+ while TRUE
+ buf = file.gets
+ break if buf == nil
+ if buf[-2, 2] != CRLF
+ if buf[-1] == ?\r or
+ buf[-1] == ?\n
+ buf = buf[0 .. -2]
+ end
+ buf = buf + CRLF
+ end
+ conn.write(buf)
+ if use_callback
+ callback.call(buf)
+ end
+ end
+ conn.close
+ voidresp
+ end
+ end
+
+ def getbinaryfile(remotefile, localfile,
+ blocksize, callback = nil)
+ if iterator?
+ callback = Proc.new
+ end
+ use_callback = callback.is_a?(Proc)
+ f = open(localfile, "w")
+ begin
+ f.binmode
+ retrbinary("RETR " + remotefile, blocksize) do |data|
+ f.write(data)
+ if use_callback
+ callback.call(data)
+ end
+ end
+ ensure
+ f.close
+ end
+ end
+
+ def gettextfile(remotefile, localfile, callback = nil)
+ if iterator?
+ callback = Proc.new
+ end
+ use_callback = callback.is_a?(Proc)
+ f = open(localfile, "w")
+ begin
+ retrlines("RETR " + remotefile) do |line|
+ line = line + @return_code
+ f.write(line)
+ if use_callback
+ callback.call(line)
+ end
+ end
+ ensure
+ f.close
+ end
+ end
+
+ def putbinaryfile(localfile, remotefile,
+ blocksize, callback = nil)
+ if iterator?
+ callback = Proc.new
+ end
+ use_callback = callback.is_a?(Proc)
+ f = open(localfile)
+ begin
+ f.binmode
+ storbinary("STOR " + remotefile, f, blocksize) do |data|
+ if use_callback
+ callback.call(data)
+ end
+ end
+ ensure
+ f.close
+ end
+ end
+
+ def puttextfile(localfile, remotefile, callback = nil)
+ if iterator?
+ callback = Proc.new
+ end
+ use_callback = callback.is_a?(Proc)
+ f = open(localfile)
+ begin
+ storlines("STOR " + remotefile, f) do |line|
+ if use_callback
+ callback.call(line)
+ end
+ end
+ ensure
+ f.close
+ end
+ end
+
+ def acct(account)
+ cmd = "ACCT " + account
+ voidcmd(cmd)
+ end
+
+ def nlst(dir = nil)
+ cmd = "NLST"
+ if dir
+ cmd = cmd + " " + dir
+ end
+ files = []
+ retrlines(cmd) do |line|
+ files.push(line)
+ end
+ files
+ end
+
+ def list(*args)
+ cmd = "LIST"
+ if iterator?
+ callback = Proc.new
+ elsif args[-1].is_a?(Proc)
+ callback = args.pop
+ else
+ callback = nil
+ end
+ args.each do |arg|
+ cmd = cmd + " " + arg
+ end
+ retrlines(cmd, callback)
+ end
+ alias ls list
+ alias dir list
+
+ def rename(fromname, toname)
+ resp = sendcmd("RNFR " + fromname)
+ if resp[0] != ?3
+ raise FTPReplyError, resp
+ end
+ voidcmd("RNTO " + toname)
+ end
+
+ def delete(filename)
+ resp = sendcmd("DELE " + filename)
+ if resp[0, 3] == "250"
+ return
+ elsif resp[0] == ?5
+ raise FTPPermError, resp
+ else
+ raise FTPReplyError, resp
+ end
+ end
+
+ def chdir(dirname)
+ if dirname == ".."
+ begin
+ voidcmd("CDUP")
+ return
+ rescue FTPPermError
+ if $![0, 3] != "500"
+ raise FTPPermError, $!
+ end
+ end
+ end
+ cmd = "CWD " + dirname
+ voidcmd(cmd)
+ end
+
+ def size(filename)
+ resp = sendcmd("SIZE " + filename)
+ if resp[0, 3] == "213"
+ return Integer(resp[3 .. -1].strip)
+ end
+ end
+
+ def mkdir(dirname)
+ resp = sendcmd("MKD " + dirname)
+ return parse257(resp)
+ end
+
+ def rmdir(dirname)
+ voidcmd("RMD " + dirname)
+ end
+
+ def pwd
+ resp = sendcmd("PWD")
+ return parse257(resp)
+ end
+ alias getdir pwd
+
+ def system
+ resp = sendcmd("SYST")
+ if resp[0, 3] != "215"
+ raise FTPReplyError, resp
+ end
+ return resp[4 .. -1]
+ end
+
+ def abort
+ line = "ABOR" + CRLF
+ resp = ""
+ sock_synchronize do
+ print "put: ABOR\n" if @debug_mode
+ @sock.send(line, Socket::MSG_OOB)
+ resp = getmultiline
+ end
+ unless ["426", "226", "225"].include?(resp[0, 3])
+ raise FTPProtoError, resp
+ end
+ resp
+ end
+
+ def status
+ line = "STAT" + CRLF
+ resp = ""
+ sock_synchronize do
+ print "put: STAT\n" if @debug_mode
+ @sock.send(line, Socket::MSG_OOB)
+ resp = getresp
+ end
+ resp
+ end
+
+ def help(arg = nil)
+ cmd = "HELP"
+ if arg
+ cmd = cmd + " " + arg
+ end
+ sendcmd(cmd)
+ end
+
+ def quit
+ voidcmd("QUIT")
+ end
+
+ def close
+ @sock.close if @sock and not @sock.closed?
+ end
+
+ def closed?
+ @sock == nil or @sock.closed?
+ end
+
+ def parse227(resp)
+ if resp[0, 3] != "227"
+ raise FTPReplyError, resp
+ end
+ left = resp.index("(")
+ right = resp.index(")")
+ if left == nil or right == nil
+ raise FTPProtoError, resp
+ end
+ numbers = resp[left + 1 .. right - 1].split(",")
+ if numbers.length != 6
+ raise FTPProtoError, resp
+ end
+ host = numbers[0, 4].join(".")
+ port = (Integer(numbers[4]) << 8) + Integer(numbers[5])
+ return host, port
+ end
+ private :parse227
+
+ def parse257(resp)
+ if resp[0, 3] != "257"
+ raise FTPReplyError, resp
+ end
+ if resp[3, 2] != ' "'
+ return ""
+ end
+ dirname = ""
+ i = 5
+ n = resp.length
+ while i < n
+ c = resp[i, 1]
+ i = i + 1
+ if c == '"'
+ if i > n or resp[i, 1] != '"'
+ break
+ end
+ i = i + 1
+ end
+ dirname = dirname + c
+ end
+ return dirname
+ end
+ private :parse257
+end
diff --git a/lib/jcode.rb b/lib/jcode.rb
index 5b2289932f..40ab48ddac 100644
--- a/lib/jcode.rb
+++ b/lib/jcode.rb
@@ -1,15 +1,31 @@
# jcode.rb - ruby code to handle japanese (EUC/SJIS) string
+$vsave, $VERBOSE = $VERBOSE, FALSE
class String
printf STDERR, "feel free for some warnings:\n" if $VERBOSE
+ def jlength
+ self.split(//).length
+ end
+
alias original_succ succ
private :original_succ
+ def mbchar?(c)
+ if $KCODE =~ /^s/i
+ c =~ /[\x81-\x9f\xe0-\xef][\x40-\x7e\x80-\xfc]/n
+ elsif $KCODE =~ /^e/i
+ c =~ /[\xa1-\xfe][\xa1-\xfe]/n
+ else
+ FALSE
+ end
+ end
+
def succ
if self[-2] && self[-2] & 0x80 != 0
s = self.dup
s[-1] += 1
+ s[-1] += 1 if !mbchar?(s)
return s
else
original_succ
@@ -23,8 +39,11 @@ class String
tail = self[-2..-1]
if tail.length == 2 and tail =~ /^.$/ then
if self[0..-2] == to[0..-2]
+ first = self[-2].chr
for c in self[-1] .. to[-1]
- yield self[0..-2]+c.chr
+ if mbchar?(first+c.chr)
+ yield self[0..-2]+c.chr
+ end
end
end
else
@@ -171,4 +190,18 @@ class String
self.dup.tr_s!(from,to)
end
+ alias original_chop! chop!
+ private :original_chop!
+
+ def chop!
+ if self =~ /(.)$/ and $1.size == 2
+ original_chop!
+ end
+ original_chop!
+ end
+
+ def chop
+ self.dup.chop!
+ end
end
+$VERBOSE = $vsave
diff --git a/lib/mathn.rb b/lib/mathn.rb
index 359cb45769..fdf27f6771 100644
--- a/lib/mathn.rb
+++ b/lib/mathn.rb
@@ -2,7 +2,7 @@
# mathn.rb -
# $Release Version: 0.5 $
# $Revision: 1.1 $
-# $Date: 1996/11/11 04:25:24 $
+# $Date: 1997/07/03 04:43:47 $
# by Keiju ISHITSUKA(SHL Japan Inc.)
#
# --
@@ -12,6 +12,7 @@
require "rational.rb"
require "complex.rb"
+require "matrix.rb"
class Integer
diff --git a/lib/matrix.rb b/lib/matrix.rb
new file mode 100644
index 0000000000..394c66f098
--- /dev/null
+++ b/lib/matrix.rb
@@ -0,0 +1,777 @@
+#!/usr/local/bin/ruby
+#
+# matrix.rb -
+# $Release Version: 1.0$
+# $Revision: 1.0 $
+# $Date: 97/05/23 11:35:28 $
+# Original Version from Smalltalk-80 version
+# on July 23, 1985 at 8:37:17 am
+# by Keiju ISHITSUKA
+#
+# --
+#
+# Matrix[[1,2,3],
+# :
+# [3,4,5]]
+# Matrix[row0,
+# row1,
+# :
+# rown]
+#
+# column: 列
+# row: 行
+#
+
+require "e2mmap.rb"
+
+module ExceptionForMatrix
+ Exception2MessageMapper.extend_to(binding)
+
+ def_e2message(TypeError, "wrong argument type %s (expected %s)")
+ def_e2message(ArgumentError, "Wrong # of arguments(%d for %d)")
+
+ def_exception("ErrDimensionMismatch", "\#{self.type} dimemsion mismatch")
+ def_exception("ErrNotRegular", "Not Regular Matrix")
+ def_exception("ErrOperationNotDefined", "This operation(%s) can\\'t defined")
+end
+
+class Matrix
+ RCS_ID='-$Header: ruby-mode,v 1.2 91/04/20 17:24:57 keiju Locked $-'
+
+ include ExceptionForMatrix
+
+ # instance creations
+ private_class_method :new
+
+ def Matrix.[](*rows)
+ new(:init_rows, rows, FALSE)
+ end
+
+ def Matrix.rows(rows, copy = TRUE)
+ new(:init_rows, rows, copy)
+ end
+
+ def Matrix.columns(columns)
+ rows = (0 .. columns[0].size - 1).collect {
+ |i|
+ (0 .. columns.size - 1).collect {
+ |j|
+ columns[j][i]
+ }
+ }
+ Matrix.rows(rows, FALSE)
+ end
+
+ def Matrix.diagonal(*values)
+ size = values.size
+ rows = (0 .. size - 1).collect {
+ |j|
+ row = Array.new(size).fill(0, 0, size)
+ row[j] = values[j]
+ row
+ }
+ self
+ rows(rows, FALSE)
+ end
+
+ def Matrix.scalar(n, value)
+ Matrix.diagonal(*Array.new(n).fill(value, 0, n))
+ end
+
+ def Matrix.identity(n)
+ Matrix.scalar(n, 1)
+ end
+ class << Matrix
+ alias unit identity
+ alias I identity
+ end
+
+ def Matrix.zero(n)
+ Matrix.scalar(n, 0)
+ end
+
+ def Matrix.row_vector(row)
+ case row
+ when Vector
+ Matrix.rows([row.to_a], FALSE)
+ when Array
+ Matrix.rows([row.dup], FALSE)
+ else
+ Matrix.row([[row]], FALSE)
+ end
+ end
+
+ def Matrix.column_vector(column)
+ case column
+ when Vector
+ Matrix.columns([column.to_a])
+ when Array
+ Matrix.columns([column])
+ else
+ Matrix.columns([[column]])
+ end
+ end
+
+ # initializing
+ def initialize(init_method, *argv)
+ self.send(init_method, *argv)
+ end
+
+ def init_rows(rows, copy)
+ if copy
+ @rows = rows.collect{|row| row.dup}
+ else
+ @rows = rows
+ end
+ self
+ end
+ private :init_rows
+
+ #accessing
+ def [](i, j)
+ @rows[i][j]
+ end
+
+ def row_size
+ @rows.size
+ end
+
+ def column_size
+ @rows[0].size
+ end
+
+ def row(i)
+ if iterator?
+ for e in @rows[i]
+ yield e
+ end
+ else
+ Vector.elements(@rows[i])
+ end
+ end
+
+ def column(j)
+ if iterator?
+ 0.upto(row_size - 1) do
+ |i|
+ yield @rows[i][j]
+ end
+ else
+ col = (0 .. row_size - 1).collect {
+ |i|
+ @rows[i][j]
+ }
+ Vector.elements(col, FALSE)
+ end
+ end
+
+ def collect
+ rows = @rows.collect{|row| row.collect{|e| yield e}}
+ Matrix.rows(rows, FALSE)
+ end
+ alias map collect
+
+ #
+ # param: (from_row, row_size, from_col, size_col)
+ # (from_row..to_row, from_col..to_col)
+ #
+ def minor(*param)
+ case param.size
+ when 2
+ from_row = param[0].first
+ size_row = param[0].size
+ from_col = param[1].first
+ size_col = param[1].size
+ when 4
+ from_row = param[0]
+ size_row = param[1]
+ from_col = param[2]
+ size_col = param[3]
+ else
+ Matrix.fail ArgumentError, param.inspect
+ end
+
+ rows = @rows[from_row, size_row].collect{
+ |row|
+ row[from_col, size_col]
+ }
+ Matrix.rows(rows, FALSE)
+ end
+
+ # TESTING
+ def regular?
+ square? and rank == column_size
+ end
+
+ def singular?
+ not regular?
+ end
+
+ def square?
+ column_size == row_size
+ end
+
+ # ARITHMETIC
+
+ def *(m) #is matrix or vector or number"
+ case(m)
+ when Numeric
+ rows = @rows.collect {
+ |row|
+ row.collect {
+ |e|
+ e * m
+ }
+ }
+ return Matrix.rows(rows, FALSE)
+ when Vector
+ m = Matrix.column_vector(m)
+ r = self * m
+ return r.column(0)
+ when Matrix
+ Matrix.fail ErrDimensionMismatch if column_size != m.row_size
+
+ rows = (0 .. row_size - 1).collect {
+ |i|
+ (0 .. m.column_size - 1).collect {
+ |j|
+ vij = 0
+ 0.upto(column_size - 1) do
+ |k|
+ vij += self[i, k] * m[k, j]
+ end
+ vij
+ }
+ }
+ return Matrix.rows(rows, FALSE)
+ else
+ x, y = m.coerce(self)
+ return x * y
+ end
+ end
+
+ def +(m)
+ case m
+ when Numeric
+ Matrix.fail ErrOperationNotDefined, "+"
+ when Vector
+ m = Matrix.column_vector(m)
+ when Matrix
+ else
+ x, y = m.coerce(self)
+ return x + y
+ end
+
+ Matrix.fail ErrDimensionMismatch unless row_size == m.row_size and column_size == m.column_size
+
+ rows = (0 .. row_size - 1).collect {
+ |i|
+ (0 .. column_size - 1).collect {
+ |j|
+ self[i, j] + m[i, j]
+ }
+ }
+ Matrix.rows(rows, FALSE)
+ end
+
+ def -(m)
+ case m
+ when Numeric
+ Matrix.fail ErrOperationNotDefined, "-"
+ when Vector
+ m = Matrix.column_vector(m)
+ when Matrix
+ else
+ x, y = m.coerce(self)
+ return x - y
+ end
+
+ Matrix.fail ErrDimensionMismatch unless row_size == m.row_size and column_size == m.column_size
+
+ rows = (0 .. row_size - 1).collect {
+ |i|
+ (0 .. column_size - 1).collect {
+ |j|
+ self[i, j] - m[i, j]
+ }
+ }
+ Matrix.rows(rows, FALSE)
+ end
+
+ def inverse
+ Matrix.fail ErrDimensionMismatch unless square?
+ Matrix.I(row_size).inverse_from(self)
+ end
+ alias inv inverse
+
+ def inverse_from(src)
+ size = row_size - 1
+ a = src.to_a
+
+ for k in 0..size
+ if (akk = a[k][k]) == 0
+ i = k
+ begin
+ fail ErrNotRegular if (i += 1) > size
+ end while a[i][k] == 0
+ a[i], a[k] = a[k], a[i]
+ @rows[i], @rows[k] = @rows[k], @rows[i]
+ akk = a[k][k]
+ end
+
+ for i in 0 .. size
+ next if i == k
+ q = a[i][k] / akk
+ a[i][k] = 0
+
+ (k + 1).upto(size) do
+ |j|
+ a[i][j] -= a[k][j] * q
+ end
+ 0.upto(size) do
+ |j|
+ @rows[i][j] -= @rows[k][j] * q
+ end
+ end
+
+ (k + 1).upto(size) do
+ |j|
+ a[k][j] /= akk
+ end
+ 0.upto(size) do
+ |j|
+ @rows[k][j] /= akk
+ end
+ end
+ self
+ end
+ #alias reciprocal inverse
+
+ def ** (other)
+ if other.kind_of?(Integer)
+ x = self
+ if other <= 0
+ x = self.inverse
+ return Matrix.identity(self.column_size) if other == 0
+ other = -other
+ end
+ z = x
+ n = other - 1
+ while n != 0
+ while (div, mod = n.divmod(2)
+ mod == 0)
+ x = x * x
+ n = div
+ end
+ z *= x
+ n -= 1
+ end
+ z
+ elsif other.kind_of?(Float) || defined?(Rational) && other.kind_of?(Rational)
+ fail ErrOperationNotDefined, "**"
+ else
+ fail ErrOperationNotDefined, "**"
+ end
+ end
+
+ # Matrix functions
+
+ def determinant
+ return 0 unless square?
+
+ size = row_size - 1
+ a = to_a
+
+ det = 1
+ k = 0
+ begin
+ if (akk = a[k][k]) == 0
+ i = k
+ begin
+ return 0 if (i += 1) > size
+ end while a[i][k] == 0
+ a[i], a[k] = a[k], a[i]
+ akk = a[k][k]
+ end
+ (k + 1).upto(size) do
+ |i|
+ q = a[i][k] / akk
+ (k + 1).upto(size) do
+ |j|
+ a[i][j] -= a[k][j] * q
+ end
+ end
+ det *= akk
+ end while (k += 1) <= size
+ det
+ end
+ alias det determinant
+
+ def rank
+ if column_size > row_size
+ a = transpose.to_a
+ else
+ a = to_a
+ end
+ rank = 0
+ k = 0
+ begin
+ if (akk = a[k][k]) == 0
+ i = -1
+ nothing = FALSE
+ begin
+ if (i += 1) > column_size - 1
+ nothing = TRUE
+ break
+ end
+ end while a[i][k] == 0
+ next if nothing
+ a[i], a[k] = a[k], a[i]
+ akk = a[k][k]
+ end
+ (k + 1).upto(row_size - 1) do
+ |i|
+ q = a[i][k] / akk
+ (k + 1).upto(column_size - 1) do
+ |j|
+ a[i][j] -= a[k][j] * q
+ end
+ end
+ rank += 1
+ end while (k += 1) <= column_size - 1
+ return rank
+ end
+
+ def trace
+ tr = 0
+ 0.upto(column_size - 1) do
+ |i|
+ tr += @rows[i][i]
+ end
+ tr
+ end
+ alias tr trace
+
+ def transpose
+ Matrix.columns(@rows)
+ end
+ alias t transpose
+
+ # CONVERTING
+
+ def coerce(other)
+ case other
+ when Numeric
+ return Scalar.new(other), self
+ end
+ end
+
+ def row_vectors
+ rows = (0 .. column_size - 1).collect {
+ |i|
+ row(i)
+ }
+ rows
+ end
+
+ def column_vectors
+ columns = (0 .. row_size - 1).collect {
+ |i|
+ column(i)
+ }
+ columns
+ end
+
+ def to_a
+ @rows.collect{|row| row.collect{|e| e}}
+ end
+
+ def to_f
+ collect{|e| e.to_f}
+ end
+
+ def to_i
+ collect{|e| e.to_i}
+ end
+
+ def to_r
+ collect{|e| e.to_r}
+ end
+
+ # PRINTING
+ def to_s
+ "Matrix[" + @rows.collect{
+ |row|
+ "[" + row.collect{|e| e.to_s}.join(", ") + "]"
+ }.join(", ")+"]"
+ end
+
+ def inspect
+ "Matrix"+@rows.inspect
+ end
+
+ # Private CLASS
+
+ class Scalar < Numeric
+ include ExceptionForMatrix
+
+ def initialize(value)
+ @value = value
+ end
+
+ # ARITHMETIC
+ def +(other)
+ case other
+ when Numeric
+ Scalar.new(@value + other)
+ when Vector, Matrix
+ Scalar.fail WrongArgType, other.type, "Numeric or Scalar"
+ when Scalar
+ Scalar.new(@value + other.value)
+ else
+ x, y = other.coerce(self)
+ x + y
+ end
+ end
+
+ def -(other)
+ case other
+ when Numeric
+ Scalar.new(@value - other)
+ when Vector, Matrix
+ Scalar.fail WrongArgType, other.type, "Numeric or Scalar"
+ when Scalar
+ Scalar.new(@value - other.value)
+ else
+ x, y = other.coerce(self)
+ x - y
+ end
+ end
+
+ def *(other)
+ case other
+ when Numeric
+ Scalar.new(@value * other)
+ when Vector, Matrix
+ other.collect{|e| @value * e}
+ else
+ x, y = other.coerce(self)
+ x * y
+ end
+ end
+
+ def / (other)
+ case other
+ when Numeric
+ Scalar.new(@value / other)
+ when Vector
+ Scalar.fail WrongArgType, other.type, "Numeric or Scalar or Matrix"
+ when Matrix
+ self * _M.inverse
+ else
+ x, y = other.coerce(self)
+ x / y
+ end
+ end
+
+ def ** (other)
+ case other
+ when Numeric
+ Scalar.new(@value ** other)
+ when Vector
+ Scalar.fail WrongArgType, other.type, "Numeric or Scalar or Matrix"
+ when Matrix
+ other.powered_by(self)
+ else
+ x, y = other.coerce(self)
+ x ** y
+ end
+ end
+ end
+end
+
+#----------------------------------------------------------------------
+#
+# -
+#
+#----------------------------------------------------------------------
+class Vector
+ include ExceptionForMatrix
+
+
+ #INSTANCE CREATION
+
+ private_class_method :new
+ def Vector.[](*array)
+ new(:init_elements, array, copy = FALSE)
+ end
+
+ def Vector.elements(array, copy = TRUE)
+ new(:init_elements, array, copy)
+ end
+
+ def initialize(method, array, copy)
+ self.send(method, array, copy)
+ end
+
+ def init_elements(array, copy)
+ if copy
+ @elements = array.dup
+ else
+ @elements = array
+ end
+ end
+
+ # ACCSESSING
+
+ def [](i)
+ @elements[i]
+ end
+
+ def size
+ @elements.size
+ end
+
+ # ENUMRATIONS
+ def each2(v)
+ Vector.fail ErrDimensionMismatch if size != v.size
+ 0.upto(size - 1) do
+ |i|
+ yield @elements[i], v[i]
+ end
+ end
+
+ def collect2(v)
+ Vector.fail ErrDimensionMismatch if size != v.size
+ (0 .. size - 1).collect do
+ |i|
+ yield @elements[i], v[i]
+ end
+ end
+
+ # ARITHMETIC
+
+ def *(x) "is matrix or number"
+ case x
+ when Numeric
+ els = @elements.collect{|e| e * x}
+ Vector.elements(els, FALSE)
+ when Matrix
+ self.covector * x
+ else
+ s, x = X.corece(self)
+ s * x
+ end
+ end
+
+ def +(v)
+ case v
+ when Vector
+ Vector.fail ErrDimensionMismatch if size != v.size
+ els = collect2(v) {
+ |v1, v2|
+ v1 + v2
+ }
+ Vector.elements(els, FALSE)
+ when Matrix
+ Matrix.column_vector(self) + v
+ else
+ s, x = v.corece(self)
+ s + x
+ end
+ end
+
+ def -(v)
+ case v
+ when Vector
+ Vector.fail ErrDimensionMismatch if size != v.size
+ els = collect2(v) {
+ |v1, v2|
+ v1 - v2
+ }
+ Vector.elements(els, FALSE)
+ when Matrix
+ Matrix.column_vector(self) - v
+ else
+ s, x = v.corece(self)
+ s - x
+ end
+ end
+
+ # VECTOR FUNCTIONS
+
+ def inner_product(v)
+ Vector.fail ErrDimensionMismatch if size != v.size
+
+ p = 0
+ each2(v) {
+ |v1, v2|
+ p += v1 * v2
+ }
+ p
+ end
+
+ def collect
+ els = @elements.collect {
+ |v|
+ yield v
+ }
+ Vector.elements(els, FALSE)
+ end
+ alias map collect
+
+ def map2(v)
+ els = collect2(v) {
+ |v1, v2|
+ yield v1, v2
+ }
+ Vector.elements(els, FALSE)
+ end
+
+ def r
+ v = 0
+ for e in @elements
+ v += e*e
+ end
+ return v.sqrt
+ end
+
+ # CONVERTING
+ def covector
+ Matrix.row_vector(self)
+ end
+
+ def to_a
+ @elements.dup
+ end
+
+ def to_f
+ collect{|e| e.to_f}
+ end
+
+ def to_i
+ collect{|e| e.to_i}
+ end
+
+ def to_r
+ collect{|e| e.to_r}
+ end
+
+ def coerce(other)
+ case other
+ when Numeric
+ return Scalar.new(other), self
+ end
+ end
+
+ # PRINTING
+
+ def to_s
+ "Vector[" + @elements.join(", ") + "]"
+ end
+
+ def inspect
+ str = "Vector"+@elements.inspect
+ end
+end
+
diff --git a/lib/mutex_m.rb b/lib/mutex_m.rb
new file mode 100644
index 0000000000..823888e72f
--- /dev/null
+++ b/lib/mutex_m.rb
@@ -0,0 +1,183 @@
+#
+# mutex_m.rb -
+# $Release Version: 2.0$
+# $Revision: 1.2 $
+# $Date: 1997/07/25 02:43:21 $
+# Original from mutex.rb
+# by Keiju ISHITSUKA(SHL Japan Inc.)
+#
+# --
+# Usage:
+# require "mutex_m.rb"
+# obj = Object.new
+# obj.extend Mutex_m
+# ...
+# 後はMutexと同じ使い方
+#
+
+require "finalize"
+
+module Mutex_m
+ def Mutex_m.extend_object(obj)
+ if Fixnum === obj or TRUE === obj or FALSE === obj or nil == obj
+ raise TypeError, "Mutex_m can't extend to this class(#{obj.type})"
+ else
+ begin
+ eval "class << obj
+ @mu_locked
+ end"
+ obj.extend(For_primitive_object)
+ rescue TypeError
+ obj.extend(For_general_object)
+ end
+ end
+ end
+
+ def mu_extended
+ unless (defined? locked? and
+ defined? lock and
+ defined? unlock and
+ defined? try_lock and
+ defined? synchronize)
+ eval "class << self
+ alias locked mu_locked?
+ alias lock mu_lock
+ alias unlock mu_unlock
+ alias try_lock mu_try_lock
+ alias synchronize mu_synchronize
+ end"
+ end
+ end
+
+ def mu_synchronize
+ begin
+ mu_lock
+ yield
+ ensure
+ mu_unlock
+ end
+ end
+
+ module For_general_object
+ include Mutex_m
+
+ def For_general_object.extend_object(obj)
+ super
+ obj.mu_extended
+ end
+
+ def mu_extended
+ super
+ @mu_waiting = []
+ @mu_locked = FALSE;
+ end
+
+ def mu_locked?
+ @mu_locked
+ end
+
+ def mu_try_lock
+ result = FALSE
+ Thread.critical = TRUE
+ unless @mu_locked
+ @mu_locked = TRUE
+ result = TRUE
+ end
+ Thread.critical = FALSE
+ result
+ end
+
+ def mu_lock
+ while (Thread.critical = TRUE; @mu_locked)
+ @mu_waiting.push Thread.current
+ Thread.stop
+ end
+ @mu_locked = TRUE
+ Thread.critical = FALSE
+ self
+ end
+
+ def mu_unlock
+ return unless @mu_locked
+ Thread.critical = TRUE
+ wait = @mu_waiting
+ @mu_waiting = []
+ @mu_locked = FALSE
+ Thread.critical = FALSE
+ for w in wait
+ w.run
+ end
+ self
+ end
+
+ end
+
+ module For_primitive_object
+ include Mutex_m
+ Mu_Locked = Hash.new
+
+ def For_primitive_object.extend_object(obj)
+ super
+ obj.mu_extended
+ Finalizer.add(obj, For_primitive_object, :mu_finalize)
+ end
+
+ def For_primitive_object.mu_finalize(id)
+ Thread.critical = TRUE
+ if wait = Mu_Locked.delete(id)
+ # wait == [] ときだけ GCされるので, for w in wait は意味なし.
+ Thread.critical = FALSE
+ for w in wait
+ w.run
+ end
+ else
+ Thread.critical = FALSE
+ end
+ self
+ end
+
+ def mu_locked?
+ Mu_Locked.key?(self.id)
+ end
+
+ def mu_try_lock
+ Thread.critical = TRUE
+ if Mu_Locked.key?(self.id)
+ ret = FALSE
+ else
+ Mu_Locked[self.id] = []
+ Finalizer.set(self, For_primitive_object, :mu_delete_Locked)
+ ret = TRUE
+ end
+ Thread.critical = FALSE
+ ret
+ end
+
+ def mu_lock
+ while (Thread.critical = TRUE; w = Mu_Locked[self.id])
+ w.push Thread.current
+ Thread.stop
+ end
+ Mu_Locked[self.id] = []
+ Finalizer.add(self, For_primitive_object, :mu_delete_Locked)
+ Thread.critical = FALSE
+ self
+ end
+
+ def mu_unlock
+ Thread.critical = TRUE
+ if wait = Mu_Locked.delete(self.id)
+ Finalizer.delete(self, For_primitive_object, :mu_finalize)
+ Thread.critical = FALSE
+ for w in wait
+ w.run
+ end
+ else
+ Thread.critical = FALSE
+ end
+ self
+ end
+ end
+end
+
+
diff --git a/lib/observer.rb b/lib/observer.rb
index 9a753939a2..b802dac633 100644
--- a/lib/observer.rb
+++ b/lib/observer.rb
@@ -30,7 +30,7 @@ module Observable
@observer_state
end
def notify_observers(*arg)
- if @observer_state
+ if @observer_peers and @observer_state
for i in @observer_peers
i.update(*arg)
end
diff --git a/lib/parsedate.rb b/lib/parsedate.rb
index 3f4612ebe5..1c1dda76bc 100644
--- a/lib/parsedate.rb
+++ b/lib/parsedate.rb
@@ -14,26 +14,26 @@ module ParseDate
time = $1
end
if date =~ /19(\d\d)/
- year = $1
+ year = Integer($1)
end
if date.sub!(/\s*(\d+)\s+(#{MONTHPAT})\S*\s+/i, ' ')
- dayofmonth = $1
+ dayofmonth = $1.to_i
monthname = $2
elsif date.sub!(/\s*(#{MONTHPAT})\S*\s+(\d+)\s+/i, ' ')
monthname = $1
- dayofmonth = $2
+ dayofmonth = $2.to_i
elsif date.sub!(/\s*(#{MONTHPAT})\S*\s+(\d+)\D+/i, ' ')
monthname = $1
- dayofmonth = $2
+ dayofmonth = $2.to_i
elsif date.sub!(/\s*(\d\d?)\/(\d\d?)/, ' ')
month = $1
- dayofmonth = $2
+ dayofmonth = $2.to_i
end
if monthname
month = MONTHS[monthname.downcase]
end
if ! year && date =~ /\d\d/
- year = $&
+ year = Integer($&)
end
return year, month, dayofmonth
end
diff --git a/lib/ping.rb b/lib/ping.rb
new file mode 100644
index 0000000000..d742a50f99
--- /dev/null
+++ b/lib/ping.rb
@@ -0,0 +1,55 @@
+#
+# ping.rb -- check a host for upness
+#
+#= SYNOPSIS
+#
+# require 'ping'
+# print "'jimmy' is alive and kicking\n" if Ping.pingecho('jimmy', 10) ;
+#
+#= DESCRIPTION
+#
+# This module contains routines to test for the reachability of remote hosts.
+# Currently the only routine implemented is pingecho().
+#
+# pingecho() uses a TCP echo (I<not> an ICMP one) to determine if the
+# remote host is reachable. This is usually adequate to tell that a remote
+# host is available to rsh(1), ftp(1), or telnet(1) onto.
+#
+#== Parameters
+#
+# : hostname
+#
+# The remote host to check, specified either as a hostname or as an
+# IP address.
+#
+# : timeout
+#
+# The timeout in seconds. If not specified it will default to 5 seconds.
+#
+#= WARNING
+#
+# pingecho() uses user-level thread to implement the timeout, so it may block
+# for long period if named does not respond for some reason.
+#
+#=end
+
+module Ping
+ require "socket"
+ def pingecho(host, timeout=5)
+ begin
+ x = Thread.current
+ y = Thread.start {
+ sleep timeout
+ x.raise RuntimeError if x.status
+ }
+ s = TCPsocket.new(host, "echo")
+ s.close
+ return TRUE
+ rescue
+ return FALSE;
+ ensure
+ Thread.kill y if y.status
+ end
+ end
+ module_function "pingecho"
+end
diff --git a/lib/safe.rb b/lib/safe.rb
deleted file mode 100644
index 7c95555495..0000000000
--- a/lib/safe.rb
+++ /dev/null
@@ -1,78 +0,0 @@
-# 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/sync.rb b/lib/sync.rb
new file mode 100644
index 0000000000..fd18291ca9
--- /dev/null
+++ b/lib/sync.rb
@@ -0,0 +1,376 @@
+#
+# sync.rb - カウント付2-フェーズロッククラス
+# $Release Version: 0.1$
+# $Revision: 1.3 $
+# $Date: 1997/08/18 07:17:08 $
+# by Keiju ISHITSUKA
+#
+# --
+# Usage:
+# Sync_m, Synchronizer_m
+#
+# Sync_m#sync_mode
+# Sync_m#sync_locked?, locked?
+# Sync_m#sync_shared?, shared?
+# Sync_m#sync_exclusive?, sync_exclusive?
+# Sync_m#sync_try_lock, try_lock
+# Sync_m#sync_lock, lock
+# Sync_m#sync_unlock, unlock
+#
+# Sync, Synchronicer:
+# include Sync_m
+#
+# sync = Sync.new
+# Sync#mode
+# Sync#locked?
+# Sync#shared?
+# Sync#exclusive?
+# Sync#try_lock(mode) -- mode = :EX, :SH, :UN
+# Sync#lock(mode) -- mode = :EX, :SH, :UN
+# Sync#unlock
+# Sync#synchronize(mode) {...}
+#
+#
+
+unless defined? Thread
+ fail "Thread not available for this ruby interpreter"
+end
+
+require "finalize.rb"
+
+module Sync_m
+ RCS_ID='-$Header: /home/keiju/var/src/var.lib/ruby/RCS/sync.rb,v 1.3 1997/08/18 07:17:08 keiju Exp keiju $-'
+
+ UN = :UN
+ SH = :SH
+ EX = :EX
+
+ class Err < Exception
+ def Err.Fail(*opt)
+ fail self, sprintf(self::Message, *opt)
+ end
+
+ class UnknownLocker < Err
+ Message = "Thread(%s) not locked."
+ def UnknownLocker.Fail(th)
+ super(th.inspect)
+ end
+ end
+
+ class LockModeFailer < Err
+ Message = "Unknown lock mode(%s)"
+ def LockModeFailer.Fail(mode)
+ if mode.id2name
+ mode = id2name
+ end
+ super(mode)
+ end
+ end
+ end
+
+ def Sync_m.extend_object(obj)
+ if Fixnum === obj or TRUE === obj or FALSE === obj or nil == obj
+ raise TypeError, "Sync_m can't extend to this class(#{obj.type})"
+ else
+ begin
+ eval "class << obj
+ @sync_locked
+ end"
+ obj.extend(For_primitive_object)
+ rescue TypeError
+ obj.extend(For_general_object)
+ end
+ end
+ end
+
+ def sync_extended
+ unless (defined? locked? and
+ defined? shared? and
+ defined? exclusive? and
+ defined? lock and
+ defined? unlock and
+ defined? try_lock and
+ defined? synchronize)
+ eval "class << self
+ alias locked? sync_locked?
+ alias shared? sync_shared?
+ alias excluive? sync_exclusive?
+ alias lock sync_lock
+ alias unlock sync_unlock
+ alias try_lock sync_try_lock
+ alias synchronize sync_synchronize
+ end"
+ end
+ end
+
+ def sync_locked?
+ sync_mode != UN
+ end
+
+ def sync_shared?
+ sync_mode == SH
+ end
+
+ def sync_exclusive?
+ sync_mode == EX
+ end
+
+ def sync_try_lock(mode = EX)
+ return unlock if sync_mode == UN
+
+ Thread.critical = TRUE
+ ret = sync_try_lock_sub(sync_mode)
+ Thread.critical = FALSE
+ ret
+ end
+
+ def sync_lock(m = EX)
+ return unlock if m == UN
+
+ until (Thread.critical = TRUE; sync_try_lock_sub(m))
+ if sync_sh_locker[Thread.current]
+ sync_upgrade_waiting.push [Thread.current, sync_sh_locker[Thread.current]]
+ sync_sh_locker.delete(Thread.current)
+ else
+ sync_waiting.push Thread.current
+ end
+ Thread.stop
+ end
+ Thread.critical = FALSE
+ self
+ end
+
+ def sync_unlock(m = EX)
+ Thread.critical = TRUE
+ if sync_mode == UN
+ Thread.critical = FALSE
+ Err::UnknownLocker.Fail(Thread.current)
+ end
+
+ m = sync_mode if m == EX and sync_mode == SH
+
+ runnable = FALSE
+ case m
+ when UN
+ Thread.critical = FALSE
+ Err::UnknownLocker.Fail(Thread.current)
+
+ when EX
+ if sync_ex_locker == Thread.current
+ if (self.sync_ex_count = sync_ex_count - 1) == 0
+ self.sync_ex_locker = nil
+ if sync_sh_locker.include?(Thread.current)
+ self.sync_mode = SH
+ else
+ self.sync_mode = UN
+ end
+ runnable = TRUE
+ end
+ else
+ Err::UnknownLocker.Fail(Thread.current)
+ end
+
+ when SH
+ if (count = sync_sh_locker[Thread.current]).nil?
+ Err::UnknownLocker.Fail(Thread.current)
+ else
+ if (sync_sh_locker[Thread.current] = count - 1) == 0
+ sync_sh_locker.delete(Thread.current)
+ if sync_sh_locker.empty? and sync_ex_count == 0
+ self.sync_mode = UN
+ runnable = TRUE
+ end
+ end
+ end
+ end
+
+ if runnable
+ if sync_upgrade_waiting.size > 0
+ for k, v in sync_upgrade_waiting
+ sync_sh_locker[k] = v
+ end
+ wait = sync_upgrade_waiting
+ self.sync_upgrade_waiting = []
+ Thread.critical = FALSE
+
+ for w, v in wait
+ w.run
+ end
+ else
+ wait = sync_waiting
+ self.sync_waiting = []
+ Thread.critical = FALSE
+ for w in wait
+ w.run
+ end
+ end
+ end
+
+ Thread.critical = FALSE
+ self
+ end
+
+ def sync_try_lock_sub(m)
+ case m
+ when SH
+ case sync_mode
+ when UN
+ self.sync_mode = m
+ sync_sh_locker[Thread.current] = 1
+ ret = TRUE
+ when SH
+ count = 0 unless count = sync_sh_locker[Thread.current]
+ sync_sh_locker[Thread.current] = count + 1
+ ret = TRUE
+ when EX
+ # 既に, モードがEXである時は, 必ずEXロックとなる.
+ if sync_ex_locker == Thread.current
+ self.sync_ex_count = sync_ex_count + 1
+ ret = TRUE
+ else
+ ret = FALSE
+ end
+ end
+ when EX
+ if sync_mode == UN or
+ sync_mode == SH && sync_sh_locker.size == 1 && sync_sh_locker.include?(Thread.current)
+ self.sync_mode = m
+ self.sync_ex_locker = Thread.current
+ self.sync_ex_count = 1
+ ret = TRUE
+
+ elsif sync_mode == EX && sync_ex_locker == Thread.current
+ self.sync_ex_count = sync_ex_count + 1
+ ret = TRUE
+ else
+ ret = FALSE
+ end
+ else
+ Thread.critical = FALSE
+ Err::LockModeFailer.Fail mode
+ end
+ return ret
+ end
+ private :sync_try_lock_sub
+
+ def sync_synchronize(mode = EX)
+ begin
+ sync_lock(mode)
+ yield
+ ensure
+ sync_unlock
+ end
+ end
+
+ module For_primitive_object
+ include Sync_m
+
+ LockState = Struct.new("LockState",
+ :mode,
+ :waiting,
+ :upgrade_waiting,
+ :sh_locker,
+ :ex_locker,
+ :ex_count)
+
+ Sync_Locked = Hash.new
+
+ def For_primitive_object.extend_object(obj)
+ super
+ obj.sync_extended
+ Finalizer.add(obj, For_primitive_object, :sync_finalize)
+ end
+
+ def sync_extended
+ super
+ Sync_Locked[id] = LockState.new(UN, [], [], Hash.new, nil, 0 )
+ end
+
+ def sync_finalize
+ wait = Sync_Locked.delete(id)
+ # waiting == [] ときだけ GCされるので, 待ち行列の解放は意味がない.
+ end
+
+ def sync_mode
+ Sync_Locked[id].mode
+ end
+ def sync_mode=(value)
+ Sync_Locked[id].mode = value
+ end
+
+ def sync_waiting
+ Sync_Locked[id].waiting
+ end
+ def sync_waiting=(v)
+ Sync_Locked[id].waiting = v
+ end
+
+ def sync_upgrade_waiting
+ Sync_Locked[id].upgrade_waiting
+ end
+ def sync_upgrade_waiting=(v)
+ Sync_Locked[id].upgrade_waiting = v
+ end
+
+ def sync_sh_locker
+ Sync_Locked[id].sh_locker
+ end
+ def sync_sh_locker=(v)
+ Sync_Locked[id].sh_locker = v
+ end
+
+ def sync_ex_locker
+ Sync_Locked[id].ex_locker
+ end
+ def sync_ex_locker=(value)
+ Sync_Locked[id].ex_locker = value
+ end
+
+ def sync_ex_count
+ Sync_Locked[id].ex_count
+ end
+ def sync_ex_count=(value)
+ Sync_Locked[id].ex_count = value
+ end
+
+ end
+
+ module For_general_object
+ include Sync_m
+
+ def For_general_object.extend_object(obj)
+ super
+ obj.sync_extended
+ end
+
+ def sync_extended
+ super
+ @sync_mode = UN
+ @sync_waiting = []
+ @sync_upgrade_waiting = []
+ @sync_sh_locker = Hash.new
+ @sync_ex_locker = nil
+ @sync_ex_count = 0
+ end
+
+ attr :sync_mode, TRUE
+
+ attr :sync_waiting, TRUE
+ attr :sync_upgrade_waiting, TRUE
+ attr :sync_sh_locker, TRUE
+ attr :sync_ex_locker, TRUE
+ attr :sync_ex_count, TRUE
+
+ end
+end
+Synchronizer_m = Sync_m
+
+class Sync
+ include Sync_m::For_general_object
+
+ def initialize
+ sync_extended
+ end
+
+end
+Synchronizer = Sync
diff --git a/lib/thread.rb b/lib/thread.rb
index c3347b60b4..30f77ddbeb 100644
--- a/lib/thread.rb
+++ b/lib/thread.rb
@@ -24,27 +24,37 @@ class Mutex
end
def try_lock
- Thread.exclusive do
- if not @locked
- @locked=TRUE
- return TRUE
- end
+ result = FALSE
+ Thread.critical = TRUE
+ unless @locked
+ @locked = TRUE
+ result = TRUE
end
- FALSE
+ Thread.critical = FALSE
+ result
end
def lock
- while not try_lock
+ while (Thread.critical = TRUE; @locked)
@waiting.push Thread.current
Thread.stop
end
+ @locked = TRUE
+ Thread.critical = FALSE
+ self
end
def unlock
+ return unless @locked
+ Thread.critical = TRUE
+ wait = @waiting
+ @waiting = []
@locked = FALSE
- if w = @waiting.shift
+ Thread.critical = FALSE
+ for w in wait
w.run
end
+ self
end
def synchronize
@@ -57,37 +67,6 @@ class Mutex
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 = []
@@ -95,19 +74,30 @@ class Queue
end
def push(obj)
+ Thread.critical = TRUE
@que.push obj
- if t = @waiting.shift
- t.run
- end
+ t = @waiting.shift
+ Thread.critical = FALSE
+ t.run if t
end
def pop non_block=FALSE
- if @que.length == 0
- raise ThreadError, "queue empty" if non_block
- @waiting.push Thread.current
- Thread.stop
+ item = nil
+ until item
+ Thread.critical = TRUE
+ if @que.length == 0
+ if non_block
+ Thread.critical = FALSE
+ raise ThreadError, "queue empty"
+ end
+ @waiting.push Thread.current
+ Thread.stop
+ else
+ item = @que.shift
+ end
end
- @que.shift
+ Thread.critical = FALSE
+ item
end
def empty?
@@ -118,36 +108,3 @@ class Queue
@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/thwait.rb b/lib/thwait.rb
new file mode 100644
index 0000000000..c638335f5d
--- /dev/null
+++ b/lib/thwait.rb
@@ -0,0 +1,128 @@
+#
+# thwait.rb -
+# $Release Version: $
+# $Revision: 1.1 $
+# $Date: 1997/08/18 03:13:14 $
+# by Keiju ISHITSUKA(Nippon Rational Inc.)
+#
+# --
+#
+#
+#
+
+require "thread.rb"
+require "e2mmap.rb"
+
+class ThreadsWait
+ RCS_ID='-$Header: /home/keiju/var/src/var.lib/ruby/RCS/thwait.rb,v 1.1 1997/08/18 03:13:14 keiju Exp keiju $-'
+
+ Exception2MessageMapper.extend_to(binding)
+ def_exception("ErrWaitThreadsNothing", "Wait threads nothing.")
+ def_exception("FinshedThreadsNothing", "finished thread nothing.")
+
+ # class mthods
+ # all_waits
+
+ #
+ # 指定したスレッドが全て終了するまで待つ. イテレータとして呼ばれると
+ # 指定したスレッドが終了するとイテレータを呼び出す.
+ #
+ def ThreadsWait.all_waits(*threads)
+ tw = ThreadsWait.new(th1, th2, th3, th4, th5)
+ if iterator?
+ tw.all_waits do
+ |th|
+ yield th
+ end
+ else
+ tw.all_waits
+ end
+ end
+
+ # initialize and terminating:
+ # initialize
+
+ #
+ # 初期化. 待つスレッドの指定ができる.
+ #
+ def initialize(*threads)
+ @threads = []
+ @wait_queue = Queue.new
+ join_nowait(*threads) unless threads.empty?
+ end
+
+ # accessing
+ # threads
+
+ # 待ちスレッドの一覧を返す.
+ attr :threads
+
+ # testing
+ # empty?
+ # finished?
+ #
+
+ #
+ # 待ちスレッドが存在するかどうかを返す.
+ def empty?
+ @threads.empty?
+ end
+
+ #
+ # すでに終了したスレッドがあるかどうか返す
+ def finished?
+ !@wait_queue.empty?
+ end
+
+ # main process:
+ # join
+ # join_nowait
+ # next_wait
+ # all_wait
+
+ #
+ # 待っているスレッドを追加し待ちにはいる.
+ #
+ def join(*threads)
+ join_nowait(*threads)
+ next_wait
+ end
+
+ #
+ # 待っているスレッドを追加する. 待ちには入らない.
+ #
+ def join_nowait(*threads)
+ @threads.concat threads
+ for th in threads
+ Thread.start do
+ th = Thread.join(th)
+ @wait_queue.push th
+ end
+ end
+ end
+
+ #
+ # 次の待ちにはいる.
+ # 待つべきスレッドがなければ, 例外ErrWaitThreadsNothing を返す.
+ # nonnlockが真の時には, nonblockingで調べる. 存在しなければ, 例外
+ # FinishedThreadNothingを返す.
+ #
+ def next_wait(nonblock = nil)
+ Threads.Wait.fail ErrWaitThreadsNothing if @threads.empty?
+
+ th = @wait_queue.pop(nonblock)
+ @threads.delete th
+ th
+ end
+
+ #
+ # 全てのスレッドが終了するまで待つ. イテレータとして呼ばれた時は, ス
+ # レッドが終了する度に, イテレータを呼び出す.
+ #
+ def all_waits
+ until @threads.empty?
+ th = next_wait
+ yield th if iterator?
+ end
+ end
+end
diff --git a/lib/tk.rb b/lib/tk.rb
index 237408a77a..48a3940fcc 100644
--- a/lib/tk.rb
+++ b/lib/tk.rb
@@ -345,7 +345,7 @@ class TkObject<TkKernel
def configure(slot, value)
if value == FALSE
value = "0"
- elsif value.type == Proc
+ elsif value.kind_of? Proc
value = install_cmd(value)
end
tk_call path, 'configure', "-#{slot}", value
@@ -358,6 +358,61 @@ class TkObject<TkKernel
def bind(context, cmd=Proc.new, args=nil)
_bind path, context, cmd, args
end
+
+ def tk_trace_variable(v)
+ unless v.kind_of?(TkVariable)
+ fail ArgumentError, format("requires TkVariable given %s", v.type)
+ end
+ v
+ end
+ private :tk_trace_variable
+
+ def destroy
+ tk_call 'trace', 'vdelete', @tk_vn, 'w', @var_id if @var_id
+ end
+end
+
+
+class TkVariable
+ include Tk
+ $tk_variable_id = "v00000"
+ def initialize(val="")
+ @id = $tk_variable_id
+ $tk_variable_id = $tk_variable_id.succ
+ tk_call(format('global %s; set %s', @id, @id), val)
+ end
+
+ def id
+ @id
+ end
+
+ def value
+ tk_call(format('global %s; set', @id), @id)
+ end
+
+ def value=(val)
+ tk_call(format('global %s; set %s', @id, @id), val)
+ end
+
+ def to_i
+ Integer(number(value))
+ end
+
+ def to_f
+ Float(number(value))
+ end
+
+ def to_s
+ String(string(value))
+ end
+
+ def inspect
+ format "<TkVariable: %s>", @id
+ end
+
+ def to_a
+ list(value)
+ end
end
class TkWindow<TkObject
@@ -391,6 +446,36 @@ class TkWindow<TkObject
self
end
+ def place(keys = nil)
+ tk_call 'place', epath, *hash_kv(keys)
+ self
+ end
+
+ def unplace(keys = nil)
+ tk_call 'place', 'forget', epath, *hash_kv(keys)
+ self
+ end
+ alias place_forget unplace
+
+ def place_config(keys)
+ tk_call "place", 'configure', epath, *hash_kv(keys)
+ end
+
+ def place_info()
+ ilist = list(tk_call('place', 'info', epath))
+ info = {}
+ while key = ilist.shift
+ info[key[1,-1]] = ilist.shift
+ end
+ return info
+ end
+
+ def place_slaves()
+ list(tk_call('place', 'slaves', epath)).collect { |w|
+ window(w)
+ }
+ end
+
def focus
tk_call 'focus', path
self
@@ -426,7 +511,7 @@ class TkWindow<TkObject
self
end
- def command(cmd)
+ def command(cmd=Proc.new)
configure_cmd 'command', cmd
end
@@ -443,6 +528,7 @@ class TkWindow<TkObject
end
end
$tk_window_list[path] = nil
+ super
end
end
@@ -486,14 +572,7 @@ class TkLabel<TkWindow
tk_call 'label', @path
end
def textvariable(v)
- v = v.id2name unless v.kind_of? String
- vn = @path + v
- vset = format("global {%s}; set {%s} %%s", vn, vn)
- tk_write vset, eval(v).inspect
- trace_var v, proc{|val|
- tk_write vset, val.inspect
- }
- configure 'textvariable', vn
+ configure 'textvariable', tk_trace_variable(v)
end
end
@@ -520,26 +599,7 @@ class TkRadioButton<TkButton
tk_send 'select'
end
def variable(v)
- 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_write 'global %s; set %s %s', vn, val
- }
- @var_id = install_cmd(proc{|name1,|
- val = tk_call(format('global %s; set', name1), name1)
- eval(format("%s = '%s'", v.id2name, val))
- })
- tk_call 'trace', 'variable', vn, 'w', @var_id
- configure 'variable', vn
- end
- def destroy
- tk_call 'trace vdelete', vn, 'w', @var_id
- super
+ configure 'variable', tk_trace_variable(v)
end
end
@@ -678,7 +738,7 @@ class TkMenu<TkWindow
tk_send 'activate', index
end
def add(type, keys=nil)
- tk_send 'add', type, *kv_hash(keys)
+ tk_send 'add', type, *hash_kv(keys)
end
def index(index)
tk_send 'index', index
@@ -686,8 +746,8 @@ class TkMenu<TkWindow
def invoke
tk_send 'invoke'
end
- def insert(index, type, keys=nil)
- tk_send 'add', index, type, *kv_hash(keys)
+ def insert(index, type, *keys)
+ tk_send 'add', index, type, *hash_kv(keys)
end
def post(x, y)
tk_send 'post', x, y
@@ -695,7 +755,7 @@ class TkMenu<TkWindow
def postcascade(index)
tk_send 'postcascade', index
end
- def postcommand(cmd)
+ def postcommand(cmd=Proc.new)
configure_cmd 'postcommand', cmd
end
def menutype(index)
diff --git a/lib/tkcanvas.rb b/lib/tkcanvas.rb
index b0ae8b1daa..46acd8c9d7 100644
--- a/lib/tkcanvas.rb
+++ b/lib/tkcanvas.rb
@@ -110,11 +110,11 @@ class TkCanvas<TkWindow
def select(*args)
tk_send 'select', *args
end
- def xview(index)
- tk_send 'xview', index
+ def xview(*index)
+ tk_send 'xview', *index
end
- def yview(index)
- tk_send 'yview', index
+ def yview(*index)
+ tk_send 'yview', *index
end
end
@@ -125,12 +125,12 @@ class TkcItem<TkObject
end
@c = parent
@path = parent.path
- if args[-1].type == Hash
+ if args[-1].kind_of? Hash
keys = args.pop
end
@id = create_self(*args)
if keys
- tk_call @path, 'itemconfigure', *hash_kv(keys)
+ tk_call @path, 'itemconfigure', @id, *hash_kv(keys)
end
end
def create_self(*args) end
@@ -226,6 +226,11 @@ class TkcPolygon<TkcItem
tk_call(@path, 'create', 'polygon', *args)
end
end
+class TkcRectangle<TkcItem
+ def create_self(*args)
+ tk_call(@path, 'create', 'rectangle', *args)
+ end
+end
class TkcText<TkcItem
def create_self(*args)
tk_call(@path, 'create', 'text', *args)
@@ -272,7 +277,7 @@ class TkImage<TkObject
def initialize(keys=nil)
@path = $tk_image_id
$tk_image_id = $tk_image_id.succ
- tk_call 'image', @type, @path, *hash_kv(keys)
+ tk_call 'image', 'create', @type, @path, *hash_kv(keys)
end
def height
@@ -302,7 +307,7 @@ end
class TkPhotoImage<TkImage
def initialize(*args)
- @type = 'bitmap'
+ @type = 'photo'
super
end
diff --git a/lib/tkclass.rb b/lib/tkclass.rb
index 10ecc80b20..17f57f581d 100644
--- a/lib/tkclass.rb
+++ b/lib/tkclass.rb
@@ -25,11 +25,13 @@ Bitmap = TkcBitmap
Line = TkcLine
Oval = TkcOval
Polygon = TkcPolygon
+Rectangle = TkcRectangle
TextItem = TkcText
WindowItem = TkcWindow
Selection = TkSelection
Winfo = TkWinfo
Pack = TkPack
+Variable = TkVariable
def Mainloop
Tk.mainloop
diff --git a/lib/tkcore.rb b/lib/tkcore.rb
index 018e140ef0..9fd2c88efc 100644
--- a/lib/tkcore.rb
+++ b/lib/tkcore.rb
@@ -22,7 +22,7 @@ module Tk
break if wish_path
end
}
- fail 'can\'t find wish' if not wish_path
+ fail 'can\'t find wish' if not wish_path #'
def Tk.tk_exit
if not PORT.closed?
@@ -31,7 +31,8 @@ module Tk
end
end
- PORT = open(format("|%s -n %s", wish_path, File.basename($0)), "w+");
+# PORT = open(format("|%s -n %s", wish_path, File.basename($0)), "w+");
+ PORT = open(format("|%s", wish_path), "w+");
trap "EXIT", proc{Tk.tk_exit}
trap "PIPE", ""
@@ -46,8 +47,8 @@ proc rb_out args {
puts [format %%s $args]
flush stdout
}
-proc rb_ans args {
- if [catch "$args" var] {puts "!$var"} {puts "=$var@@"}
+proc rb_ans arg {
+ if [catch $arg var] {puts "!$var"} {puts "=$var@@"}
flush stdout
}
proc tkerror args { exit }
@@ -85,12 +86,11 @@ after 120000 keepalive'
}
def error_at
- n = 1
- while c = caller(n)
- break if c !~ /tk\.rb:/
- n+=1
+ frames = caller(1)
+ frames.delete_if do |c|
+ c =~ %r!/tk(|core|thcore|canvas|text|entry|scrollbox)\.rb:\d+!
end
- c
+ frames
end
def tk_tcl2ruby(val)
@@ -197,17 +197,21 @@ after 120000 keepalive'
s = "1"
elsif s.kind_of?(TkObject)
s = s.path
+ elsif s.kind_of?(TkVariable)
+ s = s.id
else
s = s.to_s
- s.gsub!(/[{}]/, '\\\\\0')
+ s.gsub!(/["\\\$\[\]]/, '\\\\\0') #"
+ s.gsub!(/\{/, '\\\\173')
+ s.gsub!(/\}/, '\\\\175')
end
- "{#{s}}"
+ "\"#{s}\""
end
}
str += " "
str += args.join(" ")
print str, "\n" if $DEBUG
- tk_write 'rb_ans %s', str
+ tk_write 'rb_ans {%s}', str
while PORT.gets
print $_ if $DEBUG
$_.chop!
@@ -229,10 +233,12 @@ after 120000 keepalive'
$@ = error_at
msg = $'
if msg =~ /unknown option "-(.*)"/
- fail NameError, format("undefined method `%s' for %s(%s)", $1, self, self.type) #`'
+ $! = NameError.new(format("undefined method `%s' for %s(%s)",
+ $1, self, self.type)) #`'
else
- fail format("%s - %s", self.type, msg)
+ $! = RuntimeError.new(format("%s - %s", self.type, msg))
end
+ fail
end
$tk_event_queue.push $_
end
@@ -250,7 +256,7 @@ after 120000 keepalive'
if keys
for k, v in keys
conf.push("-#{k}")
- v = install_cmd(v) if v.type == Proc
+ v = install_cmd(v) if v.kind_of? Proc
conf.push(v)
end
end
@@ -415,10 +421,10 @@ after 120000 keepalive'
module_function :after, :update, :dispatch, :mainloop, :root, :bell
module Scrollable
- def xscrollcommand(cmd)
+ def xscrollcommand(cmd=Proc.new)
configure_cmd 'xscrollcommand', cmd
end
- def yscrollcommand(cmd)
+ def yscrollcommand(cmd=Proc.new)
configure_cmd 'yscrollcommand', cmd
end
end
diff --git a/lib/tkentry.rb b/lib/tkentry.rb
index 9a03c34058..7c13e3bdb1 100644
--- a/lib/tkentry.rb
+++ b/lib/tkentry.rb
@@ -14,11 +14,7 @@ class TkEntry<TkLabel
end
def delete(s, e=None)
- if e
- tk_send 'delete', s
- else
- tk_send 'delete', s, e
- end
+ tk_send 'delete', s, e
end
def cursor
@@ -28,13 +24,10 @@ class TkEntry<TkLabel
tk_send 'icursor', index
end
def index(index)
- tk_send 'index', index
+ number(tk_send('index', index))
end
- def insert(text, pos=None)
- if pos
- tk_send 'icursor', pos
- end
- tk_send 'insert', 'insert', text
+ def insert(pos,text)
+ tk_send 'insert', pos, text
end
def mark(pos)
tk_send 'scan', 'mark', pos
diff --git a/lib/tkscrollbox.rb b/lib/tkscrollbox.rb
index b8dbe9b236..76844ed90a 100644
--- a/lib/tkscrollbox.rb
+++ b/lib/tkscrollbox.rb
@@ -18,8 +18,8 @@ class TkScrollbox<TkListbox
scroll.configure 'command', list.path+" yview"
scroll.pack 'side'=>'right','fill'=>'y'
- delegate('DEFALUT', list)
- delegate('foreground', list, scroll)
+ delegate('DEFAULT', list)
+ delegate('foreground', list)
delegate('background', list, scroll)
delegate('borderwidth', @frame)
delegate('relief', @frame)
diff --git a/lib/tktext.rb b/lib/tktext.rb
index 55e396c497..91a60529d1 100644
--- a/lib/tktext.rb
+++ b/lib/tktext.rb
@@ -24,10 +24,9 @@ class TkText<TkTextWin
def _addcmd(cmd)
@cmdtbl.push id
end
- def _addtag(cmd)
- @cmdtbl.push id
+ def _addtag(name, obj)
+ @tags[name] = obj
end
- private :_addcmd, :_addtag
def tag_names
tk_send('tag', 'names').collect{|elt|
if not @tags[elt]
@@ -75,18 +74,25 @@ class TkText<TkTextWin
def yview_pickplace(*what)
tk_send 'yview', '-pickplace', *what
end
+
+ def xview(*what)
+ tk_send 'xview', *what
+ end
+ def xview_pickplace(*what)
+ tk_send 'xview', '-pickplace', *what
+ end
end
class TkTextTag<TkObject
$tk_text_tag = 'tag0000'
- def initialize(parent)
+ def initialize(parent, keys=nil)
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
+ @path = @id = $tk_text_tag
$tk_text_tag = $tk_text_tag.succ
+ tk_call @t.path, "tag", "configure", @id, *hash_kv(keys)
@t._addtag id, self
end
def id
@@ -94,25 +100,25 @@ class TkTextTag<TkObject
end
def add(*index)
- tk_call path, 'tag', 'add', @id, *index
+ tk_call @t.path, 'tag', 'add', @id, *index
end
- def configure(slot, value)
- tk_call path, 'tag', 'configure', id, "-#{slot}", value
+ def configure(keys)
+ tk_call @t.path, 'tag', 'configure', @id, *hash_kv(keys)
end
def bind(seq, cmd=Proc.new)
id = install_cmd(cmd)
- tk_call path, 'tag', 'bind', tag, "<#{seq}>", id
+ tk_call @t, 'tag', 'bind', tag, "<#{seq}>", id
@t._addcmd cmd
end
def lower(below=None)
- tk_call path, 'tag', 'lower', below
+ tk_call @t.path, 'tag', 'lower', below
end
def destroy
- tk_call path, 'tag', 'delete', @id
+ tk_call @t.path, 'tag', 'delete', @id
end
end
@@ -123,10 +129,9 @@ class TkTextMark<TkObject
fail format("%s need to be TkText", parent.inspect)
end
@t = parent
- @path = parent.path
- @id = $tk_text_mark
+ @path = @id = $tk_text_mark
$tk_text_mark = $tk_text_mark.succ
- tk_call @t, 'set', @id, index
+ tk_call @t.path, 'set', @id, index
@t._addtag id, self
end
def id
@@ -134,11 +139,11 @@ class TkTextMark<TkObject
end
def set(where)
- tk_call path, 'mark', 'unset', @id, where
+ tk_call @t.path, 'mark', 'unset', @id, where
end
def unset
- tk_call path, 'mark', 'unset', @id
+ tk_call @t.path, 'mark', 'unset', @id
end
alias destroy unset
end
@@ -149,12 +154,11 @@ class TkTextWindow<TkObject
fail format("%s need to be TkText", parent.inspect)
end
@t = parent
- @path = parent.path
- @index = index
- tk_call @path, 'window', 'create', index, *args
+ @path = @index = index
+ tk_call @t.path, 'window', 'create', index, *args
end
def configure(slot, value)
- tk_call path, 'window', 'configure', @index, "-#{slot}", value
+ tk_call @t.path, 'window', 'configure', @index, "-#{slot}", value
end
end
diff --git a/lib/tkthcore.rb b/lib/tkthcore.rb
index 5e0abd72c5..b89850cb73 100644
--- a/lib/tkthcore.rb
+++ b/lib/tkthcore.rb
@@ -30,7 +30,7 @@ module Tk
break if wish_path
end
}
- fail 'can\'t find wish' if not wish_path
+ fail 'can\'t find wish' if not wish_path #'
# mark for non-given arguments
None = Object.new
@@ -66,9 +66,10 @@ module Tk
ary = [PORT]
loop do
str = Qin.pop
- print str, "\n" if $DEBUG
+ print "Qin: ", str, "\n" if $DEBUG
tk_write 'if [catch {%s} var] {puts "!$var"} {puts "=$var@@"};flush stdout', str
- Qout.push(tk_recv)
+ line = tk_recv
+ Qout.push(line)
end
end
end
@@ -89,7 +90,7 @@ module Tk
val += $'
return val
else
- v>al += $_
+ val += $_
end
end
elsif /^!/
@@ -101,7 +102,6 @@ module Tk
fail format("%s - %s", self.type, msg)
end
end
- Qcmd.push line
end
fail 'wish closed' if PORT.closed?
@@ -122,11 +122,15 @@ module Tk
s = "1"
elsif s.kind_of?(TkObject)
s = s.path
+ elsif s.kind_of?(TkVariable)
+ s = s.id
else
s = s.to_s
- s.gsub!(/[{}]/, '\\\\\0')
+ s.gsub!(/["\\\$\[\]]/, '\\\\\0') #"
+ s.gsub!(/\{/, '\\\\173')
+ s.gsub!(/\}/, '\\\\175')
end
- "{#{s}}"
+ "\"#{s}\""
end
}
str += " "
@@ -240,12 +244,11 @@ after 120000 keepalive'
module_function :dispatch
def error_at
- n = 1
- while c = caller(n)
- break if c !~ /tk\.rb:/
- n+=1
+ frames = caller(1)
+ frames.delete_if do |c|
+ c =~ %r!/tk(|core|thcore|canvas|text|entry|scrollbox)\.rb:\d+!
end
- c
+ frames
end
def bool(val)
@@ -295,7 +298,7 @@ after 120000 keepalive'
if keys
for k, v in keys
conf.push("-#{k}")
- v = install_cmd(v) if v.type == Proc
+ v = install_cmd(v) if v.kind_of? Proc
conf.push(v)
end
end
@@ -440,10 +443,10 @@ after 120000 keepalive'
module_function :after, :update, :dispatch, :mainloop, :root, :bell
module Scrollable
- def xscrollcommand(cmd)
+ def xscrollcommand(cmd=Proc.new)
configure_cmd 'xscrollcommand', cmd
end
- def yscrollcommand(cmd)
+ def yscrollcommand(cmd=Proc.new)
configure_cmd 'yscrollcommand', cmd
end
end
diff --git a/lib/tracer.rb b/lib/tracer.rb
new file mode 100644
index 0000000000..d37339fd62
--- /dev/null
+++ b/lib/tracer.rb
@@ -0,0 +1,75 @@
+class Tracer
+ MY_FILE_NAME_PATTERN = /^tracer\.(rb)?/
+ Threads = Hash.new
+ Sources = Hash.new
+
+ EVENT_SYMBOL = {
+ "line" => "-",
+ "call" => ">",
+ "return" => "<",
+ "class" => "C",
+ "end" => "E"}
+
+ def on
+ set_trace_func proc{|event, file, line, id, binding|
+ trace_func event, file, line, id, binding
+ }
+ print "Trace on\n"
+ end
+
+ def off
+ set_trace_func nil
+ print "Trace off\n"
+ end
+
+ def get_thread_no
+ unless no = Threads[Thread.current.id]
+ Threads[Thread.current.id] = no = Threads.size
+ end
+ no
+ end
+
+ def get_line(file, line)
+ unless list = Sources[file]
+ f =open(file)
+ begin
+ Sources[file] = list = f.readlines
+ ensure
+ f.close
+ end
+ end
+ list[line - 1]
+ end
+
+ def trace_func(event, file, line, id, binding)
+ return if File.basename(file) =~ MY_FILE_NAME_PATTERN
+
+ Thread.critical = TRUE
+ printf("#%d:%s:%d:%s: %s",
+ get_thread_no,
+ file,
+ line,
+ EVENT_SYMBOL[event],
+ get_line(file, line))
+ Thread.critical = FALSE
+ end
+
+ Single = new
+ def Tracer.on
+ Single.on
+ end
+
+ def Tracer.off
+ Single.off
+ end
+
+end
+
+if File.basename($0) =~ Tracer::MY_FILE_NAME_PATTERN
+ $0 = ARGV.shift
+
+ Tracer.on
+ load $0
+else
+ Tracer.on
+end