From 3db12e8b236ac8f88db8eb4690d10e4a3b8dbcd4 Mon Sep 17 00:00:00 2001 From: matz Date: Fri, 16 Jan 1998 12:13:05 +0000 Subject: Initial revision git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@2 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- lib/English.rb | 28 ++ lib/base64.rb | 54 ++++ lib/cgi-lib.rb | 56 ++++ lib/complex.rb | 490 +++++++++++++++++++++++++++++++ lib/date.rb | 227 +++++++++++++++ lib/debug.rb | 262 +++++++++++++++++ lib/e2mmap.rb | 94 ++++++ lib/e2mmap1_0.rb | 71 +++++ lib/finalize.rb | 205 +++++++++++++ lib/find.rb | 39 +++ lib/ftplib.rb | 617 +++++++++++++++++++++++++++++++++++++++ lib/getopts.rb | 142 +++++++++ lib/jcode.rb | 207 +++++++++++++ lib/mailread.rb | 48 ++++ lib/mathn.rb | 308 ++++++++++++++++++++ lib/matrix.rb | 777 +++++++++++++++++++++++++++++++++++++++++++++++++ lib/mutex_m.rb | 183 ++++++++++++ lib/observer.rb | 40 +++ lib/parsearg.rb | 84 ++++++ lib/parsedate.rb | 42 +++ lib/ping.rb | 55 ++++ lib/rational.rb | 361 +++++++++++++++++++++++ lib/sync.rb | 376 ++++++++++++++++++++++++ lib/thread.rb | 110 +++++++ lib/thwait.rb | 128 +++++++++ lib/tk.rb | 829 +++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/tkcanvas.rb | 326 +++++++++++++++++++++ lib/tkclass.rb | 38 +++ lib/tkcore.rb | 528 ++++++++++++++++++++++++++++++++++ lib/tkentry.rb | 67 +++++ lib/tkscrollbox.rb | 27 ++ lib/tktext.rb | 164 +++++++++++ lib/tkthcore.rb | 550 +++++++++++++++++++++++++++++++++++ lib/tracer.rb | 75 +++++ 34 files changed, 7608 insertions(+) create mode 100644 lib/English.rb create mode 100644 lib/base64.rb create mode 100644 lib/cgi-lib.rb create mode 100644 lib/complex.rb create mode 100644 lib/date.rb create mode 100644 lib/debug.rb create mode 100644 lib/e2mmap.rb create mode 100644 lib/e2mmap1_0.rb create mode 100644 lib/finalize.rb create mode 100644 lib/find.rb create mode 100644 lib/ftplib.rb create mode 100644 lib/getopts.rb create mode 100644 lib/jcode.rb create mode 100644 lib/mailread.rb create mode 100644 lib/mathn.rb create mode 100644 lib/matrix.rb create mode 100644 lib/mutex_m.rb create mode 100644 lib/observer.rb create mode 100644 lib/parsearg.rb create mode 100644 lib/parsedate.rb create mode 100644 lib/ping.rb create mode 100644 lib/rational.rb create mode 100644 lib/sync.rb create mode 100644 lib/thread.rb create mode 100644 lib/thwait.rb create mode 100644 lib/tk.rb create mode 100644 lib/tkcanvas.rb create mode 100644 lib/tkclass.rb create mode 100644 lib/tkcore.rb create mode 100644 lib/tkentry.rb create mode 100644 lib/tkscrollbox.rb create mode 100644 lib/tktext.rb create mode 100644 lib/tkthcore.rb create mode 100644 lib/tracer.rb (limited to 'lib') 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 new file mode 100644 index 0000000000..96208a634d --- /dev/null +++ b/lib/base64.rb @@ -0,0 +1,54 @@ +def decode64(str) + string = '' + for line in str.split("\n") + 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 + +def j2e(str) + while str =~ /\033\$B([^\033]*)\033\(B/ + s = $1 + pre, post = $`, $' + s.gsub!(/./) { |ch| + (ch[0]|0x80).chr + } + str = pre + s + post + end +# str.gsub!(/\033\$B([^\033]*)\033\(B/) { +# $1.gsub!(/./) { |ch| +# (ch[0]|0x80).chr +# } +# } + str +end + +def decode_b(str) + str.gsub!(/=\?ISO-2022-JP\?B\?([!->@-~]+)\?=/i) { + decode64($1) + } + str.gsub!(/\n/, ' ') + 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/cgi-lib.rb b/lib/cgi-lib.rb new file mode 100644 index 0000000000..afadbff3b6 --- /dev/null +++ b/lib/cgi-lib.rb @@ -0,0 +1,56 @@ +#!/usr/local/bin/ruby +# +# Get CGI String +# +# EXAMPLE: +# require "cgi-lib.rb" +# foo = CGI.new +# foo['field'] <== value of 'field' +# foo.keys <== array of fields +# foo.inputs <== hash of { => } + +class CGI + attr("inputs") + + def initialize + str = if ENV['REQUEST_METHOD'] == "GET" + ENV['QUERY_STRING'] + elsif ENV['REQUEST_METHOD'] == "POST" + $stdin.read ENV['CONTENT_LENGTH'].to_i + else + "" + end + arr = str.split(/&/) + @inputs = {} + arr.each do |x| + x.gsub!(/\+/, ' ') + key, val = x.split(/=/, 2) + val = "" unless val + + key.gsub!(/%(..)/) { [$1.hex].pack("c") } + val.gsub!(/%(..)/) { [$1.hex].pack("c") } + + @inputs[key] += "\0" if @inputs[key] + @inputs[key] += val + end + end + + def keys + @inputs.keys + end + + def [](key) + @inputs[key] + end + + def CGI.message(msg, title = "") + print "Content-type: text/html\n\n" + print "" + print title + print "\n" + print msg + print "\n" + TRUE + end + +end diff --git a/lib/complex.rb b/lib/complex.rb new file mode 100644 index 0000000000..aa5d219d2f --- /dev/null +++ b/lib/complex.rb @@ -0,0 +1,490 @@ +# +# complex.rb - +# $Release Version: 0.5 $ +# $Revision: 1.1 $ +# $Date: 1996/11/11 04:25:19 $ +# by Keiju ISHITSUKA(SHL Japan Inc.) +# +# -- +# Usage: +# class Complex < Numeric +# +# Complex(x, y) --> x + yi +# y.im --> 0 + yi +# +# Complex::polar +# +# Complex::+ +# Complex::- +# Complex::* +# Complex::/ +# Complex::** +# Complex::% +# Complex::divmod +# Complex::abs +# Complex::abs2 +# Complex::arg +# Complex::polar +# Complex::conjugate +# Complex::<=> +# Complex::== +# Complex::to_i +# Complex::to_f +# Complex::to_r +# Complex::to_s +# +# Complex::I +# +# Numeric::im +# +# Math.sqrt +# Math.exp +# Math.cos +# Math.sin +# Math.tan +# Math.log +# Math.log10 +# Math.atan2 +# +# + +def Complex(a, b = 0) + if a.kind_of?(Complex) and b == 0 + a + elsif b == 0 and defined? Complex::Unify + a + else + Complex.new(a, b) + end +end + +class Complex < Numeric + + def Complex.generic?(other) + other.kind_of?(Integer) or + other.kind_of?(Float) or + (defined?(Rational) and other.kind_of?(Rational)) + end + + def Complex.polar(r, theta) + Complex(r*Math.cos(theta), r*Math.sin(theta)) + end + + def initialize(a, b = 0) + @real = a + @image = b + end + + def + (other) + if other.kind_of?(Complex) + re = @real + other.real + im = @image + other.image + Complex(re, im) + elsif Complex.generic?(other) + Complex(@real + other, @image) + else + x , y = a.coerce(self) + x + y + end + end + + def - (other) + if other.kind_of?(Complex) + re = @real - other.real + im = @image - other.image + Complex(re, im) + elsif Complex.generic?(other) + Complex(@real - other, @image) + else + x , y = a.coerce(self) + x - y + end + end + + def * (other) + if other.kind_of?(Complex) + re = @real*other.real - @image*other.image + im = @real*other.image + @image*other.real + Complex(re, im) + elsif Complex.generic?(other) + Complex(@real * other, @image * other) + else + x , y = a.coerce(self) + x * y + end + end + + def / (other) + if other.kind_of?(Complex) + self * other.conjugate / other.abs2 + elsif Complex.generic?(other) + Complex(@real / other, @image / other) + else + x , y = a.coerce(self) + x / y + end + end + + def ** (other) + if other == 0 + return Complex(1) + end + if other.kind_of?(Complex) + r, theta = polar + ore = other.real + oim = other.image + nr = Math.exp!(ore*Math.log!(r) - oim * theta) + ntheta = theta*ore + oim*Math.log!(r) + Complex.polar(nr, ntheta) + elsif other.kind_of?(Integer) + if other > 0 + x = self + z = x + n = other - 1 + while n != 0 + while (div, mod = n.divmod(2) + mod == 0) + x = Complex(x.real*x.real - x.image*x.image, 2*x.real*x.image) + n = div + end + z *= x + n -= 1 + end + z + else + if defined? Rational + (Rational(1) / self) ** -other + else + self ** Float(other) + end + end + elsif Complex.generic?(other) + r, theta = polar + Complex.polar(r.power!(other), theta * other) + else + x , y = a.coerce(self) + x / y + end + end + + def % (other) + if other.kind_of?(Complex) + Complex(@real % other.real, @image % other.image) + elsif Complex.generic?(other) + Complex(@real % other, @image % other) + else + x , y = a.coerce(self) + x % y + end + end + + def divmod(other) + if other.kind_of?(Complex) + rdiv, rmod = @real.divmod(other.real) + idiv, imod = @image.divmod(other.image) + return Complex(rdiv, idiv), Complex(rmod, rdiv) + elsif Complex.generic?(other) + Complex(@real.divmod(other), @image.divmod(other)) + else + x , y = a.coerce(self) + x.divmod(y) + end + end + + def abs + Math.sqrt!((@real*@real + @image*@image).to_f) + end + + def abs2 + @real*@real + @image*@image + end + + def arg + Math.atan2(@image.to_f, @real.to_f) + end + + def polar + return abs, arg + end + + def conjugate + Complex(@real, -@image) + end + + def <=> (other) + self.abs <=> other.abs + end + + def == (other) + if other.kind_of?(Complex) + @real == other.real and @image == other.image + elsif Complex.generic?(other) + @real == other and @image == 0 + else + x , y = a.coerce(self) + x == y + end + end + + def coerce(other) + if Complex.generic?(other) + return Complex.new(other), self + else + super + end + end + + def to_i + Complex(@real.to_i, @image.to_i) + end + + def to_f + Complex(@real.to_f, @image.to_f) + end + + def to_r + Complex(@real.to_r, @image.to_r) + end + + def denominator + @real.denominator.lcm(@image.denominator) + end + + def numerator + cd = denominator + Complex(@real.numerator*(cd/@real.denominator), + @image.numerator*(cd/@image.denominator)) + end + + def to_s + if @real != 0 + if defined?(Rational) and @image.kind_of?(Rational) and @image.denominator != 1 + if @image >= 0 + @real.to_s+"+("+@image.to_s+")i" + else + @real.to_s+"-("+(-@image).to_s+")i" + end + else + if @image >= 0 + @real.to_s+"+"+@image.to_s+"i" + else + @real.to_s+"-"+(-@image).to_s+"i" + end + end + else + if defined?(Rational) and @image.kind_of?(Rational) and @image.denominator != 1 + "("+@image.to_s+")i" + else + @image.to_s+"i" + end + end + end + + def hash + @real ^ @image + end + + I = Complex(0,1) + + attr :real + attr :image + +end + +class Numeric + def im + Complex(0, self) + end + + def real + self + end + + def image + 0 + end + + def arg + if self >= 0 + return 0 + else + return Math.atan2(1,1)*4 + end + end + + def polar + return abs, arg + end + + def conjugate + self + end +end + +class Fixnum + if not defined? Rational + alias power! ** + end + + def ** (other) + if self < 0 + Complex.new(self) ** other + else + if defined? Rational + if other >= 0 + self.power!(other) + else + Rational.new!(self,1)**other + end + else + self.power!(other) + end + end + end +end + +class Bignum + if not defined? Rational + alias power! ** + end +end + +class Float + alias power! ** +end + +module Math + alias sqrt! sqrt + alias exp! exp + alias cos! cos + alias sin! sin + alias tan! tan + alias log! log + alias log10! log10 + alias atan2! atan2 + + def sqrt(z) + if Complex.generic?(z) + if z >= 0 + sqrt!(z) + else + Complex(0,sqrt!(-z)) + end + else + z**Rational(1,2) + end + end + + def exp(z) + if Complex.generic?(z) + exp!(z) + else + Complex(exp!(z.real) * cos!(z.image), exp!(z.real) * sin!(z.image)) + end + end + + def cosh!(x) + (exp!(x) + exp!(-x))/2.0 + end + + def sinh!(x) + (exp!(x) - exp!(-x))/2.0 + end + + def cos(z) + if Complex.generic?(z) + cos!(z) + else + Complex(cos!(z.real)*cosh!(z.image), + sin!(z.real)*sinh!(z.image)) + end + end + + def sin(z) + if Complex.generic?(z) + sin!(z) + else + Complex(sin!(z.real)*cosh!(z.image), + -cos!(z.real)*sinh!(z.image)) + end + end + + def tan(z) + if Complex.generic?(z) + tan!(z) + else + sin(z)/cos(z) + end + end + + def log(z) + if Complex.generic?(z) and z >= 0 + log!(z) + else + r, theta = z.polar + Complex(log!(r.abs), theta) + end + end + + def log10(z) + if Complex.generic?(z) + log10!(z) + else + log(z)/log!(10) + end + end + + def atan2(x, y) + if Complex.generic?(x) and Complex.generic?(y) + atan2!(x, y) + else + fail "Not yet implemented." + end + end + + def atanh!(x) + log((1.0 + x.to_f) / ( 1.0 - x.to_f)) / 2.0 + end + + def atan(z) + if Complex.generic?(z) + atan2!(z, 1) + elsif z.image == 0 + atan2(z.real,1) + else + a = z.real + b = z.image + + c = (a*a + b*b - 1.0) + d = (a*a + b*b + 1.0) + + Complex(atan2!((c + sqrt(c*c + 4.0*a*a)), 2.0*a), + atanh!((-d + sqrt(d*d - 4.0*b*b))/(2.0*b))) + end + end + + module_function :sqrt + module_function :sqrt! + module_function :exp! + module_function :exp + module_function :cosh! + module_function :cos! + module_function :cos + module_function :sinh! + module_function :sin! + module_function :sin + module_function :tan! + module_function :tan + module_function :log! + module_function :log + module_function :log10! + module_function :log + module_function :atan2! + module_function :atan2 +# module_function :atan! + module_function :atan + module_function :atanh! + +end + + diff --git a/lib/date.rb b/lib/date.rb new file mode 100644 index 0000000000..998c2e8152 --- /dev/null +++ b/lib/date.rb @@ -0,0 +1,227 @@ +# +# 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?(Numeric) + d = Integer(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?(Numeric) + d = Integer(self.period - o) + elsif o.kind_of?(Date) + return Integer(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) + if d.kind_of? Time + return Date.new(1900+d.year, d.mon+1, d.mday) + end + if d.kind_of? Date + return Date.at(d.period) + end + 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..d245dec975 --- /dev/null +++ b/lib/e2mmap1_0.rb @@ -0,0 +1,71 @@ +# +# e2mmap.rb - +# $Release Version: 1.0$ +# $Revision$ +# $Date$ +# by Keiju ISHITSUKA +# +# -- +# +# + +module Exception2MessageMapper + RCS_ID='-$Header$-' + 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/find.rb b/lib/find.rb new file mode 100644 index 0000000000..5ecc54329c --- /dev/null +++ b/lib/find.rb @@ -0,0 +1,39 @@ +# Usage: +# require "find.rb" +# +# Find.find('/foo','/bar') {|f| ...} +# or +# include Find +# find('/foo','/bar') {|f| ...} +# + +module Find + def find(*path) + while file = path.shift + catch(:prune) { + yield file + if File.directory? file and not File.symlink? file then + d = Dir.open(file) + begin + for f in d + next if f =~ /^\.\.?$/ + if file == "/" then + f = "/" + f + else + f = file + "/" + f + end + path.unshift f + end + ensure + d.close + end + end + } + end + end + + def prune + throw :prune + end + module_function :find, :prune +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 + +### 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/getopts.rb b/lib/getopts.rb new file mode 100644 index 0000000000..6929f7e4fd --- /dev/null +++ b/lib/getopts.rb @@ -0,0 +1,142 @@ +#!/usr/local/bin/ruby +# +# getopts.rb - +# $Release Version: $ +# $Revision$ +# $Date$ +# by Yasuo OHBA(SHL Japan Inc. Technology Dept.) +# +# -- +# +# +# + +$RCS_ID="$Header$" + +def isSingle(lopt) + if lopt.index(":") + if lopt.split(":")[0].length == 1 + return TRUE + end + end + return nil +end + +def getOptionName(lopt) + return lopt.split(":")[0] +end + +def getDefaultOption(lopt) + od = lopt.split(":")[1] + if od + return od + end + return nil +end + +def setOption(name, value) + eval("$OPT_" + name + " = " + 'value') +end + +def setDefaultOption(lopt) + d = getDefaultOption(lopt) + if d + setOption(getOptionName(lopt), d) + end +end + +def setNewArgv(newargv) + ARGV.clear + for na in newargv + ARGV << na + end +end + + +def getopts(single_opts, *options) + if options + single_colon = "" + long_opts = [] + sc = 0 + for o in options + setDefaultOption(o) + if isSingle(o) + single_colon[sc, 0] = getOptionName(o) + sc += 1 + else + long_opts.push(o) + end + end + end + + opts = {} + count = 0 + newargv = [] + while ARGV.length != 0 + compare = nil + case ARGV[0] + when /^--?$/ + ARGV.shift + newargv += ARGV + break + when /^--.*/ + compare = ARGV[0][2, (ARGV[0].length - 2)] + if long_opts != "" + for lo in long_opts + if lo.index(":") && getOptionName(lo) == compare + if ARGV.length <= 1 + return nil + end + setOption(compare, ARGV[1]) + opts[compare] = TRUE + ARGV.shift + count += 1 + break + elsif lo == compare + setOption(compare, TRUE) + opts[compare] = TRUE + count += 1 + break + end + end + end + if compare.length <= 1 + return nil + end + when /^-.*/ + for idx in 1..(ARGV[0].length - 1) + compare = ARGV[0][idx, 1] + if single_opts && compare =~ "[" + single_opts + "]" + setOption(compare, TRUE) + opts[compare] = TRUE + count += 1 + elsif single_colon != "" && compare =~ "[" + single_colon + "]" + if ARGV[0][idx..-1].length > 1 + setOption(compare, ARGV[0][(idx + 1)..-1]) + opts[compare] = TRUE + count += 1 + elsif ARGV.length <= 1 + return nil + else + setOption(compare, ARGV[1]) + opts[compare] = TRUE + ARGV.shift + count += 1 + end + break + end + end + else + compare = ARGV[0] + opts[compare] = TRUE + newargv << ARGV[0] + end + + ARGV.shift + if !opts.has_key?(compare) + return nil + end + end + setNewArgv(newargv) + return count +end diff --git a/lib/jcode.rb b/lib/jcode.rb new file mode 100644 index 0000000000..40ab48ddac --- /dev/null +++ b/lib/jcode.rb @@ -0,0 +1,207 @@ +# 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 + end + end + + def upto(to) + return if self > to + + curr = self + tail = self[-2..-1] + if tail.length == 2 and tail =~ /^.$/ then + if self[0..-2] == to[0..-2] + first = self[-2].chr + for c in self[-1] .. to[-1] + if mbchar?(first+c.chr) + yield self[0..-2]+c.chr + end + end + end + else + loop do + yield curr + return if curr == to + curr = curr.succ + return if curr.length > to.length + end + end + return nil + end + + def _expand_ch + a = [] + self.scan(/(.|\n)-(.|\n)|(.|\n)/) do |r| + if $3 + a.push $3 + elsif $1.length != $2.length + next + elsif $1.length == 1 + $1[0].upto($2[0]) { |c| a.push c.chr } + else + $1.upto($2) { |c| a.push c } + end + end + a + end + + def tr!(from, to) + return self.delete!(from) if to.length == 0 + + if from =~ /^\^/ + comp=TRUE + from = $' + end + afrom = from._expand_ch + ato = to._expand_ch + i = 0 + if comp + self.gsub!(/(.|\n)/) do |c| + unless afrom.include?(c) + ato[-1] + else + c + end + end + else + self.gsub!(/(.|\n)/) do |c| + if i = afrom.index(c) + if i < ato.size then ato[i] else ato[-1] end + else + c + end + end + end + end + + def tr(from, to) + self.dup.tr!(from, to) + end + + def delete!(del) + if del =~ /^\^/ + comp=TRUE + del = $' + end + adel = del._expand_ch + if comp + self.gsub!(/(.|\n)/) do |c| + next unless adel.include?(c) + c + end + else + self.gsub!(/(.|\n)/) do |c| + next if adel.include?(c) + c + end + end + end + + def delete(del) + self.dup.delete!(del) + end + + def squeeze!(del=nil) + if del + if del =~ /^\^/ + comp=TRUE + del = $' + end + adel = del._expand_ch + if comp + self.gsub!(/(.|\n)\1+/) do + next unless adel.include?($1) + $& + end + else + for c in adel + cq = Regexp.quote(c) + self.gsub!(/#{cq}(#{cq})+/, cq) + end + end + self + else + self.gsub!(/(.|\n)\1+/, '\1') + end + end + + def squeeze(del=nil) + self.dup.squeeze!(del) + end + + def tr_s!(from, to) + return self.delete!(from) if to.length == 0 + if from =~ /^\^/ + comp=TRUE + from = $' + end + afrom = from._expand_ch + ato = to._expand_ch + i = 0 + c = nil + last = nil + self.gsub!(/(.|\n)/) do |c| + if comp + unless afrom.include?(c) + ato[-1] + else + c + end + elsif i = afrom.index(c) + c = if i < ato.size then ato[i] else ato[-1] end + next if c == last + last = c + else + last = nil + c + end + end + end + + def tr_s(from, to) + self.dup.tr_s!(from,to) + end + + 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/mailread.rb b/lib/mailread.rb new file mode 100644 index 0000000000..d9feffbb7a --- /dev/null +++ b/lib/mailread.rb @@ -0,0 +1,48 @@ +class Mail + def Mail.new(f) + unless f.kind_of?(IO) + f = open(f, "r") + me = super(f) + f.close + else + me = super + end + return me + end + + def initialize(f) + @header = {} + @body = [] + while f.gets() + $_.chop! + next if /^From / # skip From-line + break if /^$/ # end of header + + if /^(\S+):\s*(.*)/ + @header[attr = $1.capitalize!] = $2 + elsif attr + sub!(/^\s*/, '') + @header[attr] += "\n" + $_ + end + end + + return unless $_ + + while f.gets() + break if /^From / + @body.push($_) + end + end + + def header + return @header + end + + def body + return @body + end + + def [](field) + @header[field] + end +end diff --git a/lib/mathn.rb b/lib/mathn.rb new file mode 100644 index 0000000000..fdf27f6771 --- /dev/null +++ b/lib/mathn.rb @@ -0,0 +1,308 @@ +# +# mathn.rb - +# $Release Version: 0.5 $ +# $Revision: 1.1 $ +# $Date: 1997/07/03 04:43:47 $ +# by Keiju ISHITSUKA(SHL Japan Inc.) +# +# -- +# +# +# + +require "rational.rb" +require "complex.rb" +require "matrix.rb" + +class Integer + + def gcd2(int) + a = self.abs + b = int.abs + a, b = b, a if a < b + + pd_a = a.prime_division + pd_b = b.prime_division + + gcd = 1 + for pair in pd_a + as = pd_b.assoc(pair[0]) + if as + gcd *= as[0] ** [as[1], pair[1]].min + end + end + return gcd + end + + def Integer.from_prime_division(pd) + value = 1 + for prime, index in pd + value *= prime**index + end + value + end + + def prime_division + ps = Prime.new + value = self + pv = [] + for prime in ps + count = 0 + while (value1, mod = value.divmod(prime) + mod) == 0 + value = value1 + count += 1 + end + if count != 0 + pv.push [prime, count] + end + break if prime * prime >= value + end + if value > 1 + pv.push [value, 1] + end + return pv + end +end + +class Prime + include Enumerable + + def initialize + @seed = 1 + @primes = [] + @counts = [] + end + + def succ + i = -1 + size = @primes.size + while i < size + if i == -1 + @seed += 1 + i += 1 + else + while @seed > @counts[i] + @counts[i] += @primes[i] + end + if @seed != @counts[i] + i += 1 + else + i = -1 + end + end + end + @primes.push @seed + @counts.push @seed + @seed + return @seed + end + + def each + loop do + yield succ + end + end +end + +class Fixnum + alias divmod! divmod + alias / rdiv + def divmod(other) + a = self.div(other) + b = self % other + return a,b + end +end + +class Bignum + alias divmod! divmod + alias / rdiv +end + +class Rational + Unify = TRUE + + alias power! ** + + def ** (other) + if other.kind_of?(Rational) + if self < 0 + return Complex(self, 0) ** other + elsif other == 0 + return Rational(1,1) + elsif self == 0 + return Rational(0,1) + elsif self == 1 + return Rational(1,1) + end + + npd = @numerator.prime_division + dpd = @denominator.prime_division + if other < 0 + other = -other + npd, dpd = dpd, npd + end + + for elm in npd + elm[1] = elm[1] * other + if !elm[1].kind_of?(Integer) and elm[1].denominator != 1 + return Float(self) ** other + end + elm[1] = elm[1].to_i + end + + for elm in dpd + elm[1] = elm[1] * other + if !elm[1].kind_of?(Integer) and elm[1].denominator != 1 + return Float(self) ** other + end + elm[1] = elm[1].to_i + end + + num = Integer.from_prime_division(npd) + den = Integer.from_prime_division(dpd) + + Rational(num,den) + + elsif other.kind_of?(Integer) + if other > 0 + num = @numerator ** other + den = @denominator ** other + elsif other < 0 + num = @denominator ** -other + den = @numerator ** -other + elsif other == 0 + num = 1 + den = 1 + end + Rational.new!(num, den) + elsif other.kind_of?(Float) + Float(self) ** other + else + x , y = other.coerce(self) + x ** y + end + end + + def power2(other) + if other.kind_of?(Rational) + if self < 0 + return Complex(self, 0) ** other + elsif other == 0 + return Rational(1,1) + elsif self == 0 + return Rational(0,1) + elsif self == 1 + return Rational(1,1) + end + + dem = nil + x = self.denominator.to_f.to_i + neard = self.denominator.to_f ** (1.0/other.denominator.to_f) + loop do + if (neard**other.denominator == self.denominator) + dem = neaed + break + end + end + nearn = self.numerator.to_f ** (1.0/other.denominator.to_f) + Rational(num,den) + + elsif other.kind_of?(Integer) + if other > 0 + num = @numerator ** other + den = @denominator ** other + elsif other < 0 + num = @denominator ** -other + den = @numerator ** -other + elsif other == 0 + num = 1 + den = 1 + end + Rational.new!(num, den) + elsif other.kind_of?(Float) + Float(self) ** other + else + x , y = other.coerce(self) + x ** y + end + end +end + +module Math + def sqrt(a) + if a.kind_of?(Complex) + abs = sqrt(a.real*a.real + a.image*a.image) +# if not abs.kind_of?(Rational) +# return a**Rational(1,2) +# end + x = sqrt((a.real + abs)/Rational(2)) + y = sqrt((-a.real + abs)/Rational(2)) +# if !(x.kind_of?(Rational) and y.kind_of?(Rational)) +# return a**Rational(1,2) +# end + if a.image >= 0 + Complex(x, y) + else + Complex(x, -y) + end + elsif a >= 0 + rsqrt(a) + else + Complex(0,rsqrt(-a)) + end + end + + def rsqrt(a) + if a.kind_of?(Float) + sqrt!(a) + elsif a.kind_of?(Rational) + rsqrt(a.numerator)/rsqrt(a.denominator) + else + src = a + max = 2 ** 32 + byte_a = [src & 0xffffffff] + # ruby's bug + while (src >= max) and (src >>= 32) + byte_a.unshift src & 0xffffffff + end + + answer = 0 + main = 0 + side = 0 + for elm in byte_a + main = (main << 32) + elm + side <<= 16 + if answer != 0 + if main * 4 < side * side + applo = main.div(side) + else + applo = ((sqrt!(side * side + 4 * main) - side)/2.0).to_i + 1 + end + else + applo = sqrt!(main).to_i + 1 + end + + while (x = (side + applo) * applo) > main + applo -= 1 + end + main -= x + answer = (answer << 16) + applo + side += applo * 2 + end + if main == 0 + answer + else + sqrt!(a) + end + end + end + + module_function :sqrt + module_function :rsqrt +end + +class Complex + Unify = TRUE +end + diff --git a/lib/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 new file mode 100644 index 0000000000..b802dac633 --- /dev/null +++ b/lib/observer.rb @@ -0,0 +1,40 @@ +# Observable Mixin +# +# Observers must respond to update + +module Observable + def add_observer(observer) + @observer_peers = [] unless @observer_peers + unless defined? observer.update + raise NameError, "observer needs to respond to `update'" + end + @observer_peers.push observer + end + def delete_observer(observer) + @observer_peers.delete observer if @observer_peers + end + def delete_observers + @observer_peers.clear if @observer_peers + end + def count_observers + if @observer_peers + @observer_peers.size + else + 0 + end + end + def changed(state=TRUE) + @observer_state = state + end + def changed? + @observer_state + end + def notify_observers(*arg) + if @observer_peers and @observer_state + for i in @observer_peers + i.update(*arg) + end + @observer_state = FALSE + end + end +end diff --git a/lib/parsearg.rb b/lib/parsearg.rb new file mode 100644 index 0000000000..a0ef90f018 --- /dev/null +++ b/lib/parsearg.rb @@ -0,0 +1,84 @@ +#!/usr/local/bin/ruby +# +# parsearg.rb - parse arguments +# $Release Version: $ +# $Revision$ +# $Date$ +# by Yasuo OHBA(SHL Japan Inc. Technology Dept.) +# +# -- +# +# +# + +$RCS_ID="$Header$" + +load("getopts.rb") + +def printUsageAndExit() + if $USAGE + eval($USAGE) + end + exit() +end + +def setParenthesis(ex, opt, c) + if opt != "" + ex = sprintf("%s$OPT_%s%s", ex, opt, c) + else + ex = sprintf("%s%s", ex, c) + end + return ex +end + +def setOrAnd(ex, opt, c) + if opt != "" + ex = sprintf("%s$OPT_%s %s%s ", ex, opt, c, c) + else + ex = sprintf("%s %s%s ", ex, c, c) + end + return ex +end + +def setExpression(ex, opt, op) + if !op + ex = sprintf("%s$OPT_%s", ex, opt) + return ex + end + case op.chr + when "(", ")" + ex = setParenthesis(ex, opt, op.chr) + when "|", "&" + ex = setOrAnd(ex, opt, op.chr) + else + return nil + end + return ex +end + +def parseArgs(argc, nopt, single_opts, *opts) + if (noOptions = getopts(single_opts, *opts)) == nil + printUsageAndExit() + end + if nopt + ex = nil + pos = 0 + for o in nopt.split(/[()|&]/) + pos += o.length + ex = setExpression(ex, o, nopt[pos]) + pos += 1 + end + begin + if !eval(ex) + printUsageAndExit() + end + rescue + print "Format Error!! : \"" + nopt + "\"\t[parseArgs]\n" + exit! -1 + end + end + if ARGV.length < argc + printUsageAndExit() + end + return noOptions +end diff --git a/lib/parsedate.rb b/lib/parsedate.rb new file mode 100644 index 0000000000..1c1dda76bc --- /dev/null +++ b/lib/parsedate.rb @@ -0,0 +1,42 @@ +module ParseDate + MONTHS = { + 'jan' => 1, 'feb' => 2, 'mar' => 3, 'apr' => 4, + 'may' => 5, 'jun' => 6, 'jul' => 7, 'aug' => 8, + 'sep' => 9, 'oct' =>10, 'nov' =>11, 'dec' =>12 } + MONTHPAT = MONTHS.keys.join('|') + DAYPAT = 'mon|tue|wed|thu|fri|sat|sun' + + def parsedate(date) + if date.sub!(/(#{DAYPAT})/i, ' ') + dayofweek = $1 + end + if date.sub!(/\s+(\d+:\d+(:\d+)?)/, ' ') + time = $1 + end + if date =~ /19(\d\d)/ + year = Integer($1) + end + if date.sub!(/\s*(\d+)\s+(#{MONTHPAT})\S*\s+/i, ' ') + dayofmonth = $1.to_i + monthname = $2 + elsif date.sub!(/\s*(#{MONTHPAT})\S*\s+(\d+)\s+/i, ' ') + monthname = $1 + dayofmonth = $2.to_i + elsif date.sub!(/\s*(#{MONTHPAT})\S*\s+(\d+)\D+/i, ' ') + monthname = $1 + dayofmonth = $2.to_i + elsif date.sub!(/\s*(\d\d?)\/(\d\d?)/, ' ') + month = $1 + dayofmonth = $2.to_i + end + if monthname + month = MONTHS[monthname.downcase] + end + if ! year && date =~ /\d\d/ + year = Integer($&) + end + return year, month, dayofmonth + end + + module_function :parsedate +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 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/rational.rb b/lib/rational.rb new file mode 100644 index 0000000000..d4112c2956 --- /dev/null +++ b/lib/rational.rb @@ -0,0 +1,361 @@ +# +# rational.rb - +# $Release Version: 0.5 $ +# $Revision: 1.1 $ +# $Date: 1996/11/11 04:25:14 $ +# by Keiju ISHITSUKA(SHL Japan Inc.) +# +# -- +# Usage: +# class Rational < Numeric +# (include Compareable) +# +# Rational(a, b) --> a/b +# +# Rational::+ +# Rational::- +# Rational::* +# Rational::/ +# Rational::** +# Rational::% +# Rational::divmod +# Rational::abs +# Rational::<=> +# Rational::to_i +# Rational::to_f +# Rational::to_s +# +# Integer::gcd +# Integer::lcm +# Integer::gcdlcm +# Integer::to_r +# +# Fixnum::** +# Bignum::** +# +# + +def Rational(a, b = 1) + if a.kind_of?(Rational) && b == 1 + a + else + Rational.reduce(a, b) + end +end + +class Rational < Numeric + def Rational.reduce(num, den = 1) + if den < 0 + num = -num + den = -den + end + gcd = num.gcd(den) + num = num.div(gcd) + den = den.div(gcd) + if den == 1 && defined?(Unify) + num + else + new!(num, den) + end + end + + def Rational.new!(num, den = 1) + new(num, den) + end + + def initialize(num, den) + if den < 0 + num = -num + den = -den + end + if num.kind_of?(Integer) and den.kind_of?(Integer) + @numerator = num + @denominator = den + else + @numerator = num.to_i + @denoninator = den.to_i + end + end + + def + (a) + if a.kind_of?(Rational) + num = @numerator * a.denominator + num_a = a.numerator * @denominator + Rational(num + num_a, @denominator * a.denominator) + elsif a.kind_of?(Integer) + self + Rational.new!(a, 1) + elsif a.kind_of?(Float) + Float(self) + a + else + x , y = a.coerce(self) + x + y + end + end + + def - (a) + if a.kind_of?(Rational) + num = @numerator * a.denominator + num_a = a.numerator * @denominator + Rational(num - num_a, @denominator*a.denominator) + elsif a.kind_of?(Integer) + self - Rational.new!(a, 1) + elsif a.kind_of?(Float) + Float(self) - a + else + x , y = a.coerce(self) + x - y + end + end + + def * (a) + if a.kind_of?(Rational) + num = @numerator * a.numerator + den = @denominator * a.denominator + Rational(num, den) + elsif a.kind_of?(Integer) + self * Rational.new!(a, 1) + elsif a.kind_of?(Float) + Float(self) * a + else + x , y = a.coerce(self) + x * y + end + end + + def / (a) + if a.kind_of?(Rational) + num = @numerator * a.denominator + den = @denominator * a.numerator + Rational(num, den) + elsif a.kind_of?(Integer) + self / Rational.new!(a, 1) + elsif a.kind_of?(Float) + Float(self) / a + else + x , y = a.coerce(self) + x / y + end + end + + def ** (other) + if other.kind_of?(Rational) + Float(self) ** other + elsif other.kind_of?(Integer) + if other > 0 + num = @numerator ** other + den = @denominator ** other + elsif other < 0 + num = @denominator ** -other + den = @numerator ** -other + elsif other == 0 + num = 1 + den = 1 + end + Rational.new!(num, den) + elsif other.kind_of?(Float) + Float(self) ** other + else + x , y = other.coerce(self) + x ** y + end + end + + def % (other) + value = (self / other).to_i + return self - other * value + end + + def divmod(other) + value = (self / other).to_i + return value, self - other * value + end + + def abs + if @numerator > 0 + Rational.new!(@numerator, @denominator) + else + Rational.new!(-@numerator, @denominator) + end + end + + def <=> (other) + if other.kind_of?(Rational) + num = @numerator * other.denominator + num_a = other.numerator * @denominator + v = num - num_a + if v > 0 + return 1 + elsif v < 0 + return -1 + else + return 0 + end + elsif other.kind_of?(Integer) + return self <=> Rational.new!(other, 1) + elsif other.kind_of?(Float) + return Float(self) <=> other + else + x , y = other.coerce(self) + return x <=> y + end + end + + def coerce(other) + if other.kind_of?(Float) + return other, self.to_f + elsif other.kind_of?(Integer) + return Rational.new!(other, 1), self + else + super + end + end + + def to_i + Integer(@numerator.div(@denominator)) + end + + def to_f + @numerator.to_f/@denominator.to_f + end + + def to_s + if @denominator == 1 + @numerator.to_s + else + @numerator.to_s+"/"+@denominator.to_s + end + end + + def to_r + self + end + + def hash + @numerator ^ @denominator + end + + attr :numerator + attr :denominator + + private :initialize +end + +class Integer + def numerator + self + end + + def denomerator + 1 + end + + def to_r + Rational(self, 1) + end + + def gcd(int) + a = self.abs + b = int.abs + + a, b = b, a if a < b + + while b != 0 + void, a = a.divmod(b) + a, b = b, a + end + return a + end + + def lcm(int) + a = self.abs + b = int.abs + gcd = a.gcd(b) + (a.div(gcd)) * b + end + + def gcdlcm(int) + a = self.abs + b = int.abs + gcd = a.gcd(b) + return gcd, (a.div(gcd)) * b + end + +end + +class Fixnum + alias div! /; + def div(other) + if other.kind_of?(Fixnum) + self.div!(other) + elsif other.kind_of?(Bignum) + x, y = other.coerce(self) + x.div!(y) + else + x, y = other.coerce(self) + x / y + end + end + +# alias divmod! divmod + + if not defined? Complex + alias power! **; + end + +# def rdiv(other) +# if other.kind_of?(Fixnum) +# Rational(self, other) +# elsif +# x, y = other.coerce(self) +# if defined?(x.div()) +# x.div(y) +# else +# x / y +# end +# end + # end + + def rdiv(other) + Rational.new!(self,1) / other + end + + def rpower (other) + if other >= 0 + self.power!(other) + else + Rational.new!(self,1)**other + end + end + + if not defined? Complex + alias ** rpower + end +end + +class Bignum + alias div! /; + alias div /; + alias divmod! divmod + + if not defined? power! + alias power! ** + end + + def rdiv(other) + Rational.new!(self,1) / other + end + + def rpower (other) + if other >= 0 + self.power!(other) + else + Rational.new!(self, 1)**other + end + end + + if not defined? Complex + alias ** rpower + end + +end + diff --git a/lib/sync.rb b/lib/sync.rb new file mode 100644 index 0000000000..3e57ed0e57 --- /dev/null +++ b/lib/sync.rb @@ -0,0 +1,376 @@ +# +# sync.rb - カウント付2-フェーズロッククラス +# $Release Version: 0.1$ +# $Revision$ +# $Date$ +# 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$-' + + 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 new file mode 100644 index 0000000000..4f294cc9a3 --- /dev/null +++ b/lib/thread.rb @@ -0,0 +1,110 @@ +# +# thread.rb - thread support classes +# $Date$ +# by Yukihiro Matsumoto +# + +unless defined? Thread + fail "Thread not available for this ruby interpreter" +end + +unless defined? ThreadError + class ThreadError + +if defined? Thread and $tk_thread_safe + require "tkthcore" +else + require "tkcore" +end + +module TkSelection + include Tk + extend Tk + def clear(win=Tk.root) + tk_call 'selection', 'clear', win.path + end + def get(type=None) + tk_call 'selection', 'get', type + end + def TkSelection.handle(win, func, type=None, format=None) + id = install_cmd(func) + tk_call 'selection', 'handle', win.path, id, type, format + end + def handle(func, type=None, format=None) + TkSelection.handle self, func, type, format + end + def TkSelection.own(win, func=None) + id = install_cmd(func) + tk_call 'selection', 'own', win.path, id + end + def own(func=None) + TkSelection.own self, func + end + + module_function :clear, :get +end + +module TkWinfo + include Tk + extend Tk + def TkWinfo.atom(name) + tk_call 'winfo', name + end + def winfo_atom(name) + TkWinfo.atom name + end + def TkWinfo.atomname(id) + tk_call 'winfo', id + end + def winfo_atomname(id) + TkWinfo.atomname id + end + def TkWinfo.cells(window) + number(tk_call('winfo', window.path)) + end + def winfo_cells + TkWinfo.cells self + end + def TkWinfo.children(window) + c = tk_call('winfo', 'children', window.path) + list(c) + end + def winfo_children + TkWinfo.children self + end + def TkWinfo.classname(window) + tk_call 'winfo', 'class', window.path + end + def winfo_classname + TkWinfo.classname self + end + def TkWinfo.containing(rootX, rootY) + path = tk_call('winfo', 'class', window.path) + window(path) + end + def winfo_containing(x, y) + TkWinfo.containing x, y + end + def TkWinfo.depth(window) + number(tk_call('winfo', 'depth', window.path)) + end + def winfo_depth(window) + TkWinfo.depth self + end + def TkWinfo.exist?(window) + bool(tk_call('winfo', 'exists', window.path)) + end + def winfo_exist?(window) + TkWinfo.exist? self + end + def TkWinfo.fpixels(window, number) + number(tk_call('winfo', 'fpixels', window.path, number)) + end + def winfo_fpixels(window, number) + TkWinfo.fpixels self + end + def TkWinfo.geometry(window) + list(tk_call('winfo', 'geometry', window.path)) + end + def winfo_geometry(window) + TkWinfo.geometry self + end + def TkWinfo.height(window) + number(tk_call('winfo', 'height', window.path)) + end + def winfo_height(window) + TkWinfo.height self + end + def TkWinfo.id(window) + number(tk_call('winfo', 'id', window.path)) + end + def winfo_id(window) + TkWinfo.id self + end + def TkWinfo.mapped?(window) + bool(tk_call('winfo', 'ismapped', window.path)) + end + def winfo_mapped?(window) + TkWinfo.mapped? self + end + def TkWinfo.parent(window) + window(tk_call('winfo', 'parent', window.path)) + end + def winfo_parent(window) + TkWinfo.parent self + end + def TkWinfo.widget(id) + window(tk_call('winfo', 'pathname', id)) + end + def winfo_widget(id) + TkWinfo.widget id + end + def TkWinfo.pixels(window, number) + number(tk_call('winfo', 'pixels', window.path, number)) + end + def winfo_pixels(window, number) + TkWinfo.pixels self, number + end + def TkWinfo.reqheight(window) + number(tk_call('winfo', 'reqheight', window.path)) + end + def winfo_reqheight(window) + TkWinfo.reqheight self + end + def TkWinfo.reqwidth(window) + number(tk_call('winfo', 'reqwidth', window.path)) + end + def winfo_reqwidth(window) + TkWinfo.reqwidth self + end + def TkWinfo.rgb(window, color) + list(tk_call('winfo', 'rgb', window.path, color)) + end + def winfo_rgb(window, color) + TkWinfo.rgb self, color + end + def TkWinfo.rootx(window) + number(tk_call('winfo', 'rootx', window.path)) + end + def winfo_rootx(window) + TkWinfo.rootx self + end + def TkWinfo.rooty(window) + number(tk_call('winfo', 'rooty', window.path)) + end + def winfo_rooty(window) + TkWinfo.rooty self + end + def TkWinfo.screen(window) + tk_call 'winfo', 'screen', window.path + end + def winfo_screen(window) + TkWinfo.screen self + end + def TkWinfo.screencells(window) + number(tk_call('winfo', 'screencells', window.path)) + end + def winfo_screencells(window) + TkWinfo.screencells self + end + def TkWinfo.screendepth(window) + number(tk_call('winfo', 'screendepth', window.path)) + end + def winfo_screendepth(window) + TkWinfo.screendepth self + end + def TkWinfo.screenheight (window) + number(tk_call('winfo', 'screenheight', window.path)) + end + def winfo_screenheight(window) + TkWinfo.screenheight self + end + def TkWinfo.screenmmheight(window) + number(tk_call('winfo', 'screenmmheight', window.path)) + end + def winfo_screenmmheight(window) + TkWinfo.screenmmheight self + end + def TkWinfo.screenmmwidth(window) + number(tk_call('winfo', 'screenmmwidth', window.path)) + end + def winfo_screenmmwidth(window) + TkWinfo.screenmmwidth self + end + def TkWinfo.screenvisual(window) + tk_call 'winfo', 'screenvisual', window.path + end + def winfo_screenvisual(window) + TkWinfo.screenvisual self + end + def TkWinfo.screenwidth(window) + number(tk_call('winfo', 'screenwidth', window.path)) + end + def winfo_screenwidth(window) + TkWinfo.screenwidth self + end + def TkWinfo.toplevel(window) + window(tk_call('winfo', 'toplevel', window.path)) + end + def winfo_toplevel(window) + TkWinfo.toplevel self + end + def TkWinfo.visual(window) + tk_call 'winfo', 'visual', window.path + end + def winfo_visual(window) + TkWinfo.visual self + end + def TkWinfo.vrootheigh(window) + number(tk_call('winfo', 'vrootheight', window.path)) + end + def winfo_vrootheight(window) + TkWinfo.vrootheight self + end + def TkWinfo.vrootwidth(window) + number(tk_call('winfo', 'vrootwidth', window.path)) + end + def winfo_vrootwidth(window) + TkWinfo.vrootwidth self + end + def TkWinfo.vrootx(window) + number(tk_call('winfo', 'vrootx', window.path)) + end + def winfo_vrootx(window) + TkWinfo.vrootx self + end + def TkWinfo.vrooty(window) + number(tk_call('winfo', 'vrooty', window.path)) + end + def winfo_vrooty(window) + TkWinfo.vrooty self + end + def TkWinfo.width(window) + number(tk_call('winfo', 'width', window.path)) + end + def winfo_width(window) + TkWinfo.width self + end + def TkWinfo.x(window) + number(tk_call('winfo', 'x', window.path)) + end + def winfo_x(window) + TkWinfo.x self + end + def TkWinfo.y(window) + number(tk_call('winfo', 'y', window.path)) + end + def winfo_y(window) + TkWinfo.y self + end +end + +module TkPack + include Tk + extend Tk + def configure(win, *args) + if args[-1].kind_of?(Hash) + keys = args.pop + end + wins = [win.epath] + for i in args + wins.push i.epath + end + tk_call "pack", 'configure', *(wins+hash_kv(keys)) + end + + def forget(*args) + tk_call 'pack', 'forget' *args + end + + def propagate(master, bool=None) + bool(tk_call('pack', 'propagate', mastaer.epath, bool)) + end + module_function :configure, :forget, :propagate +end + +module TkOption + include Tk + extend Tk + def add pat, value, pri=None + tk_call 'option', 'add', pat, value, pri + end + def clear + tk_call 'option', 'clear' + end + def get win, classname, name + tk_call 'option', 'get', classname, name + end + def readfile file, pri=None + tk_call 'option', 'readfile', file, pri + end + module_function :add, :clear, :get, :readfile +end + +class TkObject", @id + end + + def to_a + list(value) + end +end + +class TkWindow + +require "tk" + +class TkCanvas", id + @cmdtbl.push id + end + def canvasx(x, *args) + tk_send 'canvasx', x, *args + end + def canvasy(y, *args) + tk_send 'canvasy', y, *args + end + def coords(tag, *args) + tk_send 'coords', tagid(tag), *args + end + def dchars(tag, first, last=None) + tk_send 'dchars', tagid(tag), first, last + end + def delete(*args) + tk_send 'delete', *args + end + alias remove delete + def dtag(tag, tag_to_del=None) + tk_send 'dtag', tagid(tag), tag_to_del + end + def find(*args) + tk_send 'find', *args + end + def itemfocus(tag) + tk_send 'find', tagid(tag) + end + def gettags(tag) + tk_send 'gettags', tagid(tag) + end + def icursor(tag, index) + tk_send 'icursor', tagid(tag), index + end + def index(tag) + tk_send 'index', tagid(tag), index + end + def lower(tag, below=None) + tk_send 'lower', tagid(tag), below + end + def move(tag, x, y) + tk_send 'move', tagid(tag), x, y + end + def itemtype(tag) + tk_send 'type', tagid(tag) + end + def postscript(keys) + tk_send "postscript", *hash_kv(keys) + end + def raise(tag, above=None) + tk_send 'raise', tagid(tag), above + end + def scale(tag, x, y, xs, ys) + tk_send 'scale', tagid(tag), x, y, xs, ys + end + def scan_mark(x, y) + tk_send 'scan', 'mark', x, y + end + def scan_dragto(x, y) + tk_send 'scan', 'dragto', x, y + end + def select(*args) + tk_send 'select', *args + end + def xview(*index) + tk_send 'xview', *index + end + def yview(*index) + tk_send 'yview', *index + end +end + +class TkcItem + +require "tk" + +TopLevel = TkToplevel +Frame = TkFrame +Label = TkLabel +Button = TkButton +Radiobutton = TkRadioButton +Checkbutton = TkCheckButton +Message = TkMessage +Entry = TkEntry +Text = TkText +Scale = TkScale +Scrollbar = TkScrollbar +Listbox = TkListbox +Menu = TkMenu +Menubutton = TkMenubutton +Canvas = TkCanvas +Arc = TkcArc +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 +end diff --git a/lib/tkcore.rb b/lib/tkcore.rb new file mode 100644 index 0000000000..c151b0af9e --- /dev/null +++ b/lib/tkcore.rb @@ -0,0 +1,528 @@ +# +# tkcore.rb - Tk interface modue without thread +# $Date$ +# by Yukihiro Matsumoto + +require "tkutil" +if defined? Thread + require "thread" +end + +module Tk + include TkUtil + extend Tk + + wish_path = nil + ENV['PATH'].split(":").each {|path| + for wish in ['wish4.2', 'wish4.1', 'wish4.0', 'wish'] + if File.exist? path+'/'+wish + wish_path = path+'/'+wish + break + end + break if wish_path + end + } + fail 'can\'t find wish' if not wish_path #' + + def Tk.tk_exit + if not PORT.closed? + PORT.print "exit\n" + PORT.close + end + end + +# PORT = open(format("|%s -n %s", wish_path, File.basename($0)), "w+"); + PORT = open(format("|%s", wish_path), "w+"); + trap "EXIT", proc{Tk.tk_exit} + trap "PIPE", "" + + def tk_write(*args) + printf PORT, *args; + PORT.print "\n" + PORT.flush + end + tk_write '\ +wm withdraw . +proc rb_out args { + puts [format %%s $args] + flush stdout +} +proc rb_ans arg { + if [catch $arg var] {puts "!$var"} {puts "=$var@@"} + flush stdout +} +proc tkerror args { exit } +proc keepalive {} { rb_out alive; after 120000 keepalive} +after 120000 keepalive' + + READABLE = [] + READ_CMD = {} + + def file_readable(port, cmd) + if cmd == nil + READABLE.delete port + else + READABLE.push port + end + READ_CMD[port] = cmd + end + + WRITABLE = [] + WRITE_CMD = {} + def file_writable(port, cmd) + if cmd == nil + WRITABLE.delete port + else + WRITABLE.push port + end + WRITE_CMD[port] = cmd + end + module_function :file_readable, :file_writable + + file_readable PORT, proc { + line = PORT.gets + exit if not line + Tk.dispatch(line.chop!) + } + + def error_at + frames = caller(1) + frames.delete_if do |c| + c =~ %r!/tk(|core|thcore|canvas|text|entry|scrollbox)\.rb:\d+! + end + frames + end + + def tk_tcl2ruby(val) + case val + when /^-?\d+$/ + val.to_i + when /^\./ + $tk_window_list[val] + when /^rb_out (c\d+)/ + $tk_cmdtbl[$1] + when / / + val.split.collect{|elt| + tk_tcl2ruby(elt) + } + when /^-?\d+\.\d*$/ + val.to_f + else + val + end + end + + def tk_split_list(str) + idx = str.index('{') + return tk_tcl2ruby(str) if not idx + + list = tk_tcl2ruby(str[0,idx]) + str = str[idx+1..-1] + i = -1 + brace = 1 + str.each_byte {|c| + i += 1 + brace += 1 if c == ?{ + brace -= 1 if c == ?} + break if brace == 0 + } + if str[0, i] == ' ' + list.push ' ' + else + list.push tk_split_list(str[0, i]) + end + list += tk_split_list(str[i+1..-1]) + list + end + private :tk_tcl2ruby, :tk_split_list + + def bool(val) + case bool + when "1", 1, 'yes', 'true' + TRUE + else + FALSE + end + end + def number(val) + case val + when /^-?\d+$/ + val.to_i + when /^-?\d+\.\d*$/ + val.to_f + else + val + end + end + def string(val) + if val == "{}" + '' + elsif val[0] == ?{ + val[1..-2] + else + val + end + end + def list(val) + tk_split_list(val) + end + def window(val) + $tk_window_list[val] + end + def procedure(val) + if val =~ /^rb_out (c\d+)/ + $tk_cmdtbl[$1] + else + nil + end + end + private :bool, :number, :string, :list, :window, :procedure + + # mark for non-given arguments + None = Object.new + def None.to_s + 'None' + end + + $tk_event_queue = [] + def tk_call(str, *args) + args = args.collect{|s| + next if s == None + if s.kind_of?(Hash) + s = hash_kv(s).join(" ") + else + if not s + s = "0" + elsif s == TRUE + s = "1" + elsif s.kind_of?(TkObject) + s = s.path + elsif s.kind_of?(TkVariable) + s = s.id + else + s = s.to_s + s.gsub!(/["\\\$\[\]]/, '\\\\\0') #" + s.gsub!(/\{/, '\\\\173') + s.gsub!(/\}/, '\\\\175') + end + "\"#{s}\"" + end + } + str += " " + str += args.join(" ") + print str, "\n" if $DEBUG + tk_write 'rb_ans {%s}', str + while PORT.gets + print $_ if $DEBUG + $_.chop! + if /^=(.*)@@$/ + val = $1 + break + elsif /^=/ + val = $' + "\n" + while TRUE + PORT.readline + if ~/@@$/ + val += $' + return val + else + val += $_ + end + end + elsif /^!/ + $@ = error_at + msg = $' + if msg =~ /unknown option "-(.*)"/ + $! = NameError.new(format("undefined method `%s' for %s(%s)", + $1, self, self.type)) #`' + else + $! = RuntimeError.new(format("%s - %s", self.type, msg)) + end + fail + end + $tk_event_queue.push $_ + end + + while ev = $tk_event_queue.shift + Tk.dispatch ev + end + fail 'wish closed' if PORT.closed? +# tk_split_list(val) + val + end + + def hash_kv(keys) + conf = [] + if keys + for k, v in keys + conf.push("-#{k}") + v = install_cmd(v) if v.kind_of? Proc + conf.push(v) + end + end + conf + end + private :tk_call, :error_at, :hash_kv + + $tk_cmdid = 0 + def install_cmd(cmd) + return '' if cmd == '' # uninstall cmd + id = format("c%.4d", $tk_cmdid) + $tk_cmdid += 1 + $tk_cmdtbl[id] = cmd + @cmdtbl = [] if not @cmdtbl + @cmdtbl.push id + return format('rb_out %s', id) + end + def uninstall_cmd(id) + $tk_cmdtbl[id] = nil + end + private :install_cmd, :uninstall_cmd + + $tk_window_list = {} + class Event + def initialize(seq,b,f,h,k,s,t,w,x,y,aa,ee,kk,nn,ww,tt,xx,yy) + @serial = seq + @num = b + @focus = (f == 1) + @height = h + @keycode = k + @state = s + @time = t + @width = w + @x = x + @y = y + @char = aa + @send_event = (ee == 1) + @keysym = kk + @keysym_num = nn + @type = tt + @widget = ww + @x_root = xx + @y_root = yy + end + attr :serial + attr :num + attr :focus + attr :height + attr :keycode + attr :state + attr :time + attr :width + attr :x + attr :y + attr :char + attr :send_event + attr :keysym + attr :keysym_num + attr :type + attr :widget + attr :x_root + attr :y_root + end + + def install_bind(cmd, args=nil) + if args + id = install_cmd(proc{|arg| + TkUtil.eval_cmd cmd, *arg + }) + id + " " + args + else + id = install_cmd(proc{|arg| + TkUtil.eval_cmd cmd, Event.new(*arg) + }) + id + " %# %b %f %h %k %s %t %w %x %y %A %E %K %N %W %T %X %Y" + end + end + + def _bind(path, context, cmd, args=nil) + begin + id = install_bind(cmd, args) + tk_call 'bind', path, "<#{context}>", id + rescue + $tk_cmdtbl[id] = nil + fail + end + end + private :install_bind, :_bind + + def bind_all(context, cmd=Proc.new, args=nil) + _bind 'all', context, cmd, args + end + + def pack(*args) + TkPack.configure *args + end + + $tk_cmdtbl = {} + + def after(ms, cmd=Proc.new) + myid = format("c%.4d", $tk_cmdid) + tk_call 'after', ms, + install_cmd(proc{ + TkUtil.eval_cmd cmd + uninstall_cmd myid + }) + end + + def update(idle=nil) + if idle + tk_call 'update', 'idletasks' + else + tk_call 'update' + end + end + + def dispatch(line) + if line =~ /^c\d+/ + cmd = $& + fail "no command `#{cmd}'" if not $tk_cmdtbl[cmd] + args = tk_split_list($') + TkUtil.eval_cmd $tk_cmdtbl[cmd], *args + elsif line =~ /^alive$/ + # keep alive, do nothing + else + fail "malformed line <#{line}>" + end + end + + def mainloop + begin + tk_write 'after idle {wm deiconify .}' + while TRUE + rf, wf = select(READABLE, WRITABLE) + for f in rf + READ_CMD[f].call(f) if READ_CMD[f] + if f.closed? + READABLE.delete f + READ_CMD[f] = nil + end + end + for f in wf + WRITE_CMD[f].call(f) if WRITE_CMD[f] + if f.closed? + WRITABLE.delete f + WRITE_CMD[f] = nil + end + end + end + ensure + Tk.tk_exit + end + end + + def root + $tk_root + end + + def bell + tk_call 'bell' + end + module_function :after, :update, :dispatch, :mainloop, :root, :bell + + module Scrollable + def xscrollcommand(cmd=Proc.new) + configure_cmd 'xscrollcommand', cmd + end + def yscrollcommand(cmd=Proc.new) + configure_cmd 'yscrollcommand', cmd + end + end + + module Wm + def aspect(*args) + w = window(tk_call('wm', 'grid', path, *args)) + w.split.collect{|s|s.to_i} if args.length == 0 + end + def client(name=None) + tk_call 'wm', 'client', path, name + end + def colormapwindows(*args) + list(tk_call('wm', 'colormapwindows', path, *args)) + end + def wm_command(value=None) + string(tk_call('wm', 'command', path, value)) + end + def deiconify + tk_call 'wm', 'deiconify', path + end + def focusmodel(*args) + tk_call 'wm', 'focusmodel', path, *args + end + def frame + tk_call 'wm', 'frame', path + end + def geometry(*args) + list(tk_call('wm', 'geometry', path, *args)) + end + def grid(*args) + w = tk_call('wm', 'grid', path, *args) + list(w) if args.size == 0 + end + def group(*args) + tk_call 'wm', 'path', path, *args + end + def iconbitmap(*args) + tk_call 'wm', 'bitmap', path, *args + end + def iconify + tk_call 'wm', 'iconify' + end + def iconmask(*args) + tk_call 'wm', 'iconmask', path, *args + end + def iconname(*args) + tk_call 'wm', 'iconname', path, *args + end + def iconposition(*args) + w = tk_call('wm', 'iconposition', path, *args) + list(w) if args.size == 0 + end + def iconwindow(*args) + tk_call 'wm', 'iconwindow', path, *args + end + def maxsize(*args) + w = tk_call('wm', 'maxsize', path, *args) + list(w) if not args.size == 0 + end + def minsize(*args) + w = tk_call('wm', 'minsize', path, *args) + list(w) if args.size == 0 + end + def overrideredirect(bool=None) + if bool == None + bool(tk_call('wm', 'overrideredirect', path)) + else + tk_call 'wm', 'overrideredirect', path, bool + end + end + def positionfrom(*args) + tk_call 'wm', 'positionfrom', path, *args + end + def protocol(name, func=None) + func = install_cmd(func) if not func == None + tk_call 'wm', 'command', path, name, func + end + def resizable(*args) + w = tk_call('wm', 'resizable', path, *args) + if args.length == 0 + list(w).collect{|e| bool(e)} + end + end + def sizefrom(*args) + list(tk_call('wm', 'sizefrom', path, *args)) + end + def state + tk_call 'wm', 'state', path + end + def title(*args) + tk_call 'wm', 'title', path, *args + end + def transient(*args) + tk_call 'wm', 'transient', path, *args + end + def withdraw + tk_call 'wm', 'withdraw', path + end + end +end diff --git a/lib/tkentry.rb b/lib/tkentry.rb new file mode 100644 index 0000000000..bcf092a15c --- /dev/null +++ b/lib/tkentry.rb @@ -0,0 +1,67 @@ +# +# tkentry.rb - Tk entry classes +# $Date$ +# by Yukihiro Matsumoto + +require 'tk.rb' + +class TkEntry + +require 'tk.rb' + +class TkScrollbox'left','fill'=>'both','expand'=>'yes' + scroll.configure 'command', list.path+" yview" + scroll.pack 'side'=>'right','fill'=>'y' + + delegate('DEFAULT', list) + delegate('foreground', list) + delegate('background', list, scroll) + delegate('borderwidth', @frame) + delegate('relief', @frame) + end +end diff --git a/lib/tktext.rb b/lib/tktext.rb new file mode 100644 index 0000000000..2488f77793 --- /dev/null +++ b/lib/tktext.rb @@ -0,0 +1,164 @@ +# +# tktext.rb - Tk text classes +# $Date$ +# by Yukihiro Matsumoto + +require 'tk.rb' + +class TkText", id + @t._addcmd cmd + end + + def lower(below=None) + tk_call @t.path, 'tag', 'lower', below + end + + def destroy + tk_call @t.path, 'tag', 'delete', @id + end +end + +class TkTextMark + +require "tkutil" +require "thread" + +module Tk + include TkUtil + extend Tk + + def Tk.tk_exit + if not PORT.closed? + tk_write "exit" + PORT.close + end + end + + trap "EXIT", proc{Tk.tk_exit} + trap "PIPE", '' + + wish_path = nil + ENV['PATH'].split(":").each {|path| + for wish in ['wish4.2', 'wish4.1', 'wish4.0', 'wish'] + if File.exist? path+'/'+wish + wish_path = path+'/'+wish + break + end + break if wish_path + end + } + fail 'can\'t find wish' if not wish_path #' + + # mark for non-given arguments + None = Object.new + def None.to_s + 'None' + end + + Qin = Queue.new + Qout = Queue.new + Qwish = Queue.new + Qcmd = Queue.new + PORT = open(format("|%s -n %s", wish_path, File.basename($0)), "w+"); + + $tk_not_init = TRUE + + def Tk.init + $tk_not_init = FALSE + Thread.start do + loop do + while line = PORT.gets + line.chop! + if line =~ /^[=!]/ + Qwish.push line + else + Qcmd.push line + end + end + exit + end + end + + Thread.start do + ary = [PORT] + loop do + str = Qin.pop + print "Qin: ", str, "\n" if $DEBUG + tk_write 'if [catch {%s} var] {puts "!$var"} {puts "=$var@@"};flush stdout', str + line = tk_recv + Qout.push(line) + end + end + end + + $tk_event_queue = [] + def tk_recv() + val = nil + $_ = Qwish.pop + loop do + if /^=(.*)@@$/ + val = $1 + break + elsif /^=/ + val = $' + "\n" + while TRUE + PORT.readline + if ~/@@$/ + val += $' + return val + else + val += $_ + end + end + elsif /^!/ + $@ = error_at + msg = $' + if msg =~ /unknown option "-(.*)"/ + fail NameError, format("undefined method `%s' for %s(%s)", $1, self, self.type) #`' + else + fail format("%s - %s", self.type, msg) + end + end + end + + fail 'wish closed' if PORT.closed? +# tk_split_list(val) + val + end + + def tk_call(str, *args) + Tk.init if $tk_not_init + args = args.collect{|s| + next if s == None + if s.kind_of?(Hash) + s = hash_kv(s).join(" ") + else + if not s + s = "0" + elsif s == TRUE + s = "1" + elsif s.kind_of?(TkObject) + s = s.path + elsif s.kind_of?(TkVariable) + s = s.id + else + s = s.to_s + s.gsub!(/["\\\$\[\]]/, '\\\\\0') #" + s.gsub!(/\{/, '\\\\173') + s.gsub!(/\}/, '\\\\175') + end + "\"#{s}\"" + end + } + str += " " + str += args.join(" ") + Qin.push str + return Qout.pop + end + + def tk_write(*args) + PORT.printf *args; PORT.print "\n" + PORT.flush + end + module_function :tk_write, :tk_recv + tk_write '\ +wm withdraw . +proc rb_out args { + puts [format %%s $args] + flush stdout +} +proc tkerror args { exit } +proc keepalive {} { rb_out alive; after 120000 keepalive} +after 120000 keepalive' + + READ_TH = {} + def file_readable(port, cmd) + if cmd == nil + if READ_TH[port].has_key? + READ_TH[port].exit + READ_TH[port] = nil + end + else + READ_TH[port] = Thread.start{ + loop do + TkUtil.eval_cmd cmd + end + } + end + end + + WRITE_TH = {} + def file_writable(port, cmd) + if cmd == nil + if WRITE_TH[port].has_key? + WRITE_TH[port].exit + end + else + WRITE_TH[port] = Thread.start{ + loop do + TkUtil.eval_cmd cmd + end + } + end + end + module_function :file_readable, :file_writable + + def tk_tcl2ruby(val) + case val + when /^-?\d+$/ + val.to_i + when /^\./ + $tk_window_list[val] + when /^rb_out (c\d+)/ + $tk_cmdtbl[$1] + when / / + val.split.collect{|elt| + tk_tcl2ruby(elt) + } + when /^-?\d+\.\d*$/ + val.to_f + else + val + end + end + + def tk_split_list(str) + idx = str.index('{') + return tk_tcl2ruby(str) if not idx + + list = tk_tcl2ruby(str[0,idx]) + str = str[idx+1..-1] + i = -1 + brace = 1 + str.each_byte {|c| + i += 1 + brace += 1 if c == ?{ + brace -= 1 if c == ?} + break if brace == 0 + } + if str[0, i] == ' ' + list.push ' ' + else + list.push tk_split_list(str[0, i]) + end + list += tk_split_list(str[i+1..-1]) + list + end + private :tk_tcl2ruby, :tk_split_list + + def dispatch(line) + if line =~ /^c\d+/ + cmd = $& + fail "no command `#{cmd}'" if not $tk_cmdtbl[cmd] + args = tk_split_list($') + TkUtil.eval_cmd $tk_cmdtbl[cmd], *args + elsif line =~ /^alive$/ + # keep alive, do nothing + else + fail "malformed line <#{line}>" + end + end + module_function :dispatch + + def error_at + frames = caller(1) + frames.delete_if do |c| + c =~ %r!/tk(|core|thcore|canvas|text|entry|scrollbox)\.rb:\d+! + end + frames + end + + def bool(val) + case bool + when "1", 1, 'yes', 'true' + TRUE + else + FALSE + end + end + def number(val) + case val + when /^-?\d+$/ + val.to_i + when /^-?\d+\.\d*$/ + val.to_f + else + val + end + end + def string(val) + if val == "{}" + '' + elsif val[0] == ?{ + val[1..-2] + else + val + end + end + def list(val) + tk_split_list(val) + end + def window(val) + $tk_window_list[val] + end + def procedure(val) + if val =~ /^rb_out (c\d+)/ + $tk_cmdtbl[$1] + else + nil + end + end + private :bool, :number, :string, :list, :window, :procedure + + def hash_kv(keys) + conf = [] + if keys + for k, v in keys + conf.push("-#{k}") + v = install_cmd(v) if v.kind_of? Proc + conf.push(v) + end + end + conf + end + private :tk_call, :error_at, :hash_kv + + $tk_cmdid = 0 + def install_cmd(cmd) + return '' if cmd == '' # uninstall cmd + id = format("c%.4d", $tk_cmdid) + $tk_cmdid += 1 + $tk_cmdtbl[id] = cmd + @cmdtbl = [] if not @cmdtbl + @cmdtbl.push id + return format('rb_out %s', id) + end + def uninstall_cmd(id) + $tk_cmdtbl[id] = nil + end + private :install_cmd, :uninstall_cmd + + $tk_window_list = {} + class Event + def initialize(seq,b,f,h,k,s,t,w,x,y,aa,ee,kk,nn,ww,tt,xx,yy) + @serial = seq + @num = b + @focus = (f == 1) + @height = h + @keycode = k + @state = s + @time = t + @width = w + @x = x + @y = y + @char = aa + @send_event = (ee == 1) + @keysym = kk + @keysym_num = nn + @type = tt + @widget = ww + @x_root = xx + @y_root = yy + end + attr :serial + attr :num + attr :focus + attr :height + attr :keycode + attr :state + attr :time + attr :width + attr :x + attr :y + attr :char + attr :send_event + attr :keysym + attr :keysym_num + attr :type + attr :widget + attr :x_root + attr :y_root + end + + def install_bind(cmd, args=nil) + if args + id = install_cmd(proc{|arg| + TkUtil.eval_cmd cmd, *arg + }) + id + " " + args + else + id = install_cmd(proc{|arg| + TkUtil.eval_cmd cmd, Event.new(*arg) + }) + id + " %# %b %f %h %k %s %t %w %x %y %A %E %K %N %W %T %X %Y" + end + end + + def _bind(path, context, cmd, args=nil) + begin + id = install_bind(cmd, args) + tk_call 'bind', path, "<#{context}>", id + rescue + $tk_cmdtbl[id] = nil + fail + end + end + private :install_bind, :_bind + + def bind_all(context, cmd=Proc.new, args=nil) + _bind 'all', context, cmd, args + end + + def pack(*args) + TkPack.configure *args + end + + $tk_cmdtbl = {} + + Qafter = Queue.new + def after(ms, cmd=Proc.new) + unless $tk_after_thread + $tk_after_thread = Thread.start{ + loop do + cmd = Qafter.pop + TkUtil.eval_cmd cmd + end + } + end + Thread.start do + sleep Float(ms)/1000 + Qafter.push cmd + end + end + + def update(idle=nil) + if idle + tk_call 'update', 'idletasks' + else + tk_call 'update' + end + end + + def root + $tk_root + end + + def bell + tk_call 'bell' + end + + def mainloop + begin + tk_call 'after', 'idle', 'wm deiconify .' + loop do + dispatch Qcmd.pop + end + ensure + Tk.tk_exit + end + end + module_function :after, :update, :dispatch, :mainloop, :root, :bell + + module Scrollable + def xscrollcommand(cmd=Proc.new) + configure_cmd 'xscrollcommand', cmd + end + def yscrollcommand(cmd=Proc.new) + configure_cmd 'yscrollcommand', cmd + end + end + + module Wm + def aspect(*args) + w = window(tk_call('wm', 'grid', path, *args)) + w.split.collect{|s|s.to_i} if args.length == 0 + end + def client(name=None) + tk_call 'wm', 'client', path, name + end + def colormapwindows(*args) + list(tk_call('wm', 'colormapwindows', path, *args)) + end + def wm_command(value=None) + string(tk_call('wm', 'command', path, value)) + end + def deiconify + tk_call 'wm', 'deiconify', path + end + def focusmodel(*args) + tk_call 'wm', 'focusmodel', path, *args + end + def frame + tk_call 'wm', 'frame', path + end + def geometry(*args) + list(tk_call('wm', 'geometry', path, *args)) + end + def grid(*args) + w = tk_call('wm', 'grid', path, *args) + list(w) if args.size == 0 + end + def group(*args) + tk_call 'wm', 'path', path, *args + end + def iconbitmap(*args) + tk_call 'wm', 'bitmap', path, *args + end + def iconify + tk_call 'wm', 'iconify' + end + def iconmask(*args) + tk_call 'wm', 'iconmask', path, *args + end + def iconname(*args) + tk_call 'wm', 'iconname', path, *args + end + def iconposition(*args) + w = tk_call('wm', 'iconposition', path, *args) + list(w) if args.size == 0 + end + def iconwindow(*args) + tk_call 'wm', 'iconwindow', path, *args + end + def maxsize(*args) + w = tk_call('wm', 'maxsize', path, *args) + list(w) if not args.size == 0 + end + def minsize(*args) + w = tk_call('wm', 'minsize', path, *args) + list(w) if args.size == 0 + end + def overrideredirect(bool=None) + if bool == None + bool(tk_call('wm', 'overrideredirect', path)) + else + tk_call 'wm', 'overrideredirect', path, bool + end + end + def positionfrom(*args) + tk_call 'wm', 'positionfrom', path, *args + end + def protocol(name, func=None) + func = install_cmd(func) if not func == None + tk_call 'wm', 'command', path, name, func + end + def resizable(*args) + w = tk_call('wm', 'resizable', path, *args) + if args.length == 0 + list(w).collect{|e| bool(e)} + end + end + def sizefrom(*args) + list(tk_call('wm', 'sizefrom', path, *args)) + end + def state + tk_call 'wm', 'state', path + end + def title(*args) + tk_call 'wm', 'title', path, *args + end + def transient(*args) + tk_call 'wm', 'transient', path, *args + end + def withdraw + tk_call 'wm', 'withdraw', path + end + end +end diff --git a/lib/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 -- cgit v1.2.3