diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/English.rb | 28 | ||||
-rw-r--r-- | lib/base64.rb | 47 | ||||
-rw-r--r-- | lib/date.rb | 221 | ||||
-rw-r--r-- | lib/debug.rb | 262 | ||||
-rw-r--r-- | lib/e2mmap.rb | 94 | ||||
-rw-r--r-- | lib/e2mmap1_0.rb | 71 | ||||
-rw-r--r-- | lib/finalize.rb | 205 | ||||
-rw-r--r-- | lib/ftplib.rb | 617 | ||||
-rw-r--r-- | lib/jcode.rb | 35 | ||||
-rw-r--r-- | lib/mathn.rb | 3 | ||||
-rw-r--r-- | lib/matrix.rb | 777 | ||||
-rw-r--r-- | lib/mutex_m.rb | 183 | ||||
-rw-r--r-- | lib/observer.rb | 2 | ||||
-rw-r--r-- | lib/parsedate.rb | 12 | ||||
-rw-r--r-- | lib/ping.rb | 55 | ||||
-rw-r--r-- | lib/safe.rb | 78 | ||||
-rw-r--r-- | lib/sync.rb | 376 | ||||
-rw-r--r-- | lib/thread.rb | 117 | ||||
-rw-r--r-- | lib/thwait.rb | 128 | ||||
-rw-r--r-- | lib/tk.rb | 128 | ||||
-rw-r--r-- | lib/tkcanvas.rb | 21 | ||||
-rw-r--r-- | lib/tkclass.rb | 2 | ||||
-rw-r--r-- | lib/tkcore.rb | 40 | ||||
-rw-r--r-- | lib/tkentry.rb | 15 | ||||
-rw-r--r-- | lib/tkscrollbox.rb | 4 | ||||
-rw-r--r-- | lib/tktext.rb | 46 | ||||
-rw-r--r-- | lib/tkthcore.rb | 33 | ||||
-rw-r--r-- | lib/tracer.rb | 75 |
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 [email protected]? + 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 <[email protected]> + +### 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"[email protected] + 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"[email protected] + 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 @@ -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 |