summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authormatz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>1999-08-13 05:45:20 +0000
committermatz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>1999-08-13 05:45:20 +0000
commit65a5162550f58047974793cdc8067a970b2435c0 (patch)
tree082bb7d5568f3b2e36e3fe166e9f3039394fcf44 /lib
parentfcd020c83028f5610d382e85a2df00223e12bd7e (diff)
1.4.0
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@520 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'lib')
-rw-r--r--lib/Env.rb31
-rw-r--r--lib/README48
-rw-r--r--lib/cgi-lib.rb277
-rw-r--r--lib/complex.rb18
-rw-r--r--lib/date2.rb267
-rw-r--r--lib/debug.rb387
-rw-r--r--lib/delegate.rb10
-rw-r--r--lib/e2mmap.rb269
-rw-r--r--lib/final.rb41
-rw-r--r--lib/finalize.rb2
-rw-r--r--lib/ftools.rb28
-rw-r--r--lib/ftplib.rb87
-rw-r--r--lib/getoptlong.rb473
-rw-r--r--lib/getopts.rb18
-rw-r--r--lib/jcode.rb149
-rw-r--r--lib/mailread.rb2
-rw-r--r--lib/mathn.rb4
-rw-r--r--lib/matrix.rb130
-rw-r--r--lib/mkmf.rb436
-rw-r--r--lib/monitor.rb229
-rw-r--r--lib/mutex_m.rb226
-rw-r--r--lib/observer.rb4
-rw-r--r--lib/open3.rb55
-rw-r--r--lib/parsedate.rb23
-rw-r--r--lib/profile.rb55
-rw-r--r--lib/rational.rb2
-rw-r--r--lib/readbytes.rb36
-rw-r--r--lib/shellwords.rb2
-rw-r--r--lib/singleton.rb37
-rw-r--r--lib/sync.rb272
-rw-r--r--lib/telnet.rb636
-rw-r--r--lib/tempfile.rb94
-rw-r--r--lib/thread.rb68
-rw-r--r--lib/timeout.rb42
-rw-r--r--lib/tracer.rb2
-rw-r--r--lib/weakref.rb34
36 files changed, 3461 insertions, 1033 deletions
diff --git a/lib/Env.rb b/lib/Env.rb
new file mode 100644
index 0000000..b3ee3ba
--- /dev/null
+++ b/lib/Env.rb
@@ -0,0 +1,31 @@
+# Env.rb -- imports environment variables as global variables
+#
+# Usage:
+#
+# require 'Env'
+# p $USER
+# $USER = "matz"
+# p ENV["USER"]
+
+for k,v in ENV
+ next unless /^[a-zA-Z][_a-zA-Z0-9]*/ =~ k
+ eval <<EOS
+ $#{k} = %q!#{v}!
+ trace_var "$#{k}", proc{|v|
+ ENV[%q!#{k}!] = v;
+ $#{k} = %q!#{v}!
+ if v == nil
+ untrace_var "$#{k}"
+ end
+ }
+EOS
+end
+
+if __FILE__ == $0
+ p $TERM
+ $TERM = nil
+ p $TERM
+ p ENV["TERM"]
+ $TERM = "foo"
+ p ENV["TERM"]
+end
diff --git a/lib/README b/lib/README
new file mode 100644
index 0000000..765c380
--- /dev/null
+++ b/lib/README
@@ -0,0 +1,48 @@
+English.rb access global variables by english names
+Env.rb access environment variables as globals
+README this file
+base64.rb encode/decode base64 (obsolete)
+cgi-lib.rb decode CGI data
+complex.rb complex number suppor
+date.rb date object (compatible)
+date2.rb yet another (better) date object
+debug.rb ruby debugger
+delegate.rb delegate messages to other object
+e2mmap.rb exception utilities
+eregex.rb extended regular expression (just a proof of concept)
+final.rb add finalizer to the object (simple)
+finalize.rb add finalizer to the object
+find.rb traverse directory tree
+ftools.rb file tools
+ftplib.rb ftp access library
+getoptlong.rb GNU getoptlong compatible
+getopts.rb parse command line options
+importenv.rb access environment variables as globals
+jcode.rb japanese text handling (replace String methods)
+mailread.rb read mail headers
+mathn.rb extended math operation
+matrix.rb matrix calculation library
+mkmf.rb Makefile maker
+monitor.rb exclusive region monitor for thread
+mutex_m.rb mutex mixin
+observer.rb observer desing pattern library (provides Observable)
+open3.rb open subprocess connection stdin/stdout/stderr
+ostruct.rb python style object
+parsearg.rb argument parser using getopts
+parsedate.rb parse date string
+ping.rb check whether host is up, using TCP echo.
+profile.rb ruby profiler
+pstore.rb persistent object strage using marshal
+rational.rb rational number support
+readbytes.rb define IO#readbytes
+shell.rb shell like operation under Ruby (imcomplete)
+shellwords.rb split into words like shell
+singleton.rb singleton design pattern library
+sync.rb 2 phase lock
+telnet.rb telnet library
+tempfile.rb temporary file that automatically removed
+thread.rb thread support
+thwait.rb thread syncronization class
+timeout.rb provids timeout
+tracer.rb execution tracer
+weakref.rb weak reference class
diff --git a/lib/cgi-lib.rb b/lib/cgi-lib.rb
index 7033f0f..f599f77 100644
--- a/lib/cgi-lib.rb
+++ b/lib/cgi-lib.rb
@@ -1,63 +1,163 @@
-#
-# Get CGI String
-#
-# EXAMPLE:
-# require "cgi-lib.rb"
-# foo = CGI.new
-# foo['field'] <== value of 'field'
-# foo.keys <== array of fields
-# and foo has Hash class methods
-
-# if running on Windows(IIS or PWS) then change cwd.
-if ENV['SERVER_SOFTWARE'] =~ /^Microsoft-/ then
- Dir.chdir ENV['PATH_TRANSLATED'].sub(/[^\\]+$/, '')
-end
+=begin
+
+= simple CGI support library
+
+= example
+
+== get form values
+
+ require "cgi-lib.rb"
+ query = CGI.new
+ query['field'] # <== value of 'field'
+ query.keys # <== array of fields
+
+and query has Hash class methods
+
+
+== get cookie values
+
+ require "cgi-lib.rb"
+ query = CGI.new
+ query.cookie['name'] # <== cookie value of 'name'
+ query.cookie.keys # <== all cookie names
+
+and query.cookie has Hash class methods
+
+
+== print HTTP header and HTML string to $>
+
+ require "cgi-lib.rb"
+ CGI::print{
+ CGI::tag("HTML"){
+ CGI::tag("HEAD"){ CGI::tag("TITLE"){"TITLE"} } +
+ CGI::tag("BODY"){
+ CGI::tag("FORM", {"ACTION"=>"test.rb", "METHOD"=>"POST"}){
+ CGI::tag("INPUT", {"TYPE"=>"submit", "VALUE"=>"submit"})
+ } +
+ CGI::tag("HR")
+ }
+ }
+ }
+
+
+== make raw cookie string
+
+ require "cgi-lib.rb"
+ cookie1 = CGI::cookie({'name' => 'name',
+ 'value' => 'value',
+ 'path' => 'path', # optional
+ 'domain' => 'domain', # optional
+ 'expires' => Time.now, # optional
+ 'secure' => true # optional
+ })
+
+ CGI::print("Content-Type: text/html", cookie1, cookie2){ "string" }
+
+
+== print HTTP header and string to $>
+
+ require "cgi-lib.rb"
+ CGI::print{ "string" }
+ # == CGI::print("Content-Type: text/html"){ "string" }
+ CGI::print("Content-Type: text/html", cookie1, cookie2){ "string" }
+
+
+=== NPH (no-parse-header) mode
+
+ require "cgi-lib.rb"
+ CGI::print("nph"){ "string" }
+ # == CGI::print("nph", "Content-Type: text/html"){ "string" }
+ CGI::print("nph", "Content-Type: text/html", cookie1, cookie2){ "string" }
+
+
+== make HTML tag string
+
+ require "cgi-lib.rb"
+ CGI::tag("element", {"attribute_name"=>"attribute_value"}){"content"}
+
+
+== make HTTP header string
+
+ require "cgi-lib.rb"
+ CGI::header # == CGI::header("Content-Type: text/html")
+ CGI::header("Content-Type: text/html", cookie1, cookie2)
+
+
+=== NPH (no-parse-header) mode
+
+ CGI::header("nph") # == CGI::header("nph", "Content-Type: text/html")
+ CGI::header("nph", "Content-Type: text/html", cookie1, cookie2)
+
+
+== escape url encode
+
+ require "cgi-lib.rb"
+ url_encoded_string = CGI::escape("string")
+
+
+== unescape url encoded
+
+ require "cgi-lib.rb"
+ string = CGI::unescape("url encoded string")
+
+
+== escape HTML &"<>
+
+ require "cgi-lib.rb"
+ CGI::escapeHTML("string")
+
+
+=end
require "delegate"
class CGI < SimpleDelegator
- attr("inputs")
+ CR = "\015"
+ LF = "\012"
+ EOL = CR + LF
- # original is CGI.pm
- def read_from_cmdline
- require "shellwords.rb"
- words = Shellwords.shellwords(if not ARGV.empty? then
- ARGV.join(' ')
- else
- STDERR.print "(offline mode: enter name=value pairs on standard input)\n" if STDIN.tty?
- readlines.join(' ').gsub(/\n/, '')
- end.gsub(/\\=/, '%3D').gsub(/\\&/, '%26'))
-
- if words.find{|x| x =~ /=/} then words.join('&') else words.join('+') end
- end
-
# escape url encode
def escape(str)
- str.gsub!(/[^a-zA-Z0-9_\-.]/n){ sprintf("%%%02X", $&.unpack("C")[0]) }
- str
+ str.gsub(/[^a-zA-Z0-9_\-.]/n){ sprintf("%%%02X", $&.unpack("C")[0]) }
end
# unescape url encoded
def unescape(str)
- str.gsub! /\+/, ' '
- str.gsub!(/%([0-9a-fA-F]{2})/){ [$1.hex].pack("c") }
- str
+ str.gsub(/\+/, ' ').gsub(/%([0-9a-fA-F]{2})/){ [$1.hex].pack("c") }
+ end
+
+ # escape HTML
+ def escapeHTML(str)
+ str.gsub(/&/, "&amp;").gsub(/\"/, "&quot;").gsub(/>/, "&gt;").gsub(/</, "&lt;")
+ end
+
+ module_function :escape, :unescape, :escapeHTML
+
+ # offline mode. read name=value pairs on standard input.
+ def read_from_cmdline
+ require "shellwords.rb"
+ words = Shellwords.shellwords(
+ if not ARGV.empty?
+ ARGV.join(' ')
+ else
+ STDERR.print "(offline mode: enter name=value pairs on standard input)\n" if STDIN.tty?
+ readlines.join(' ').gsub(/\n/, '')
+ end.gsub(/\\=/, '%3D').gsub(/\\&/, '%26'))
+
+ if words.find{|x| x =~ /=/} then words.join('&') else words.join('+') end
end
- module_function :escape, :unescape
def initialize(input = $stdin)
@inputs = {}
+ @cookie = {}
+
case ENV['REQUEST_METHOD']
when "GET"
- # exception messages should be printed to stdout.
- STDERR.reopen(STDOUT)
ENV['QUERY_STRING'] or ""
when "POST"
- # exception messages should be printed to stdout.
- STDERR.reopen(STDOUT)
- input.read Integer(ENV['CONTENT_LENGTH'])
+ input.read(Integer(ENV['CONTENT_LENGTH'])) or ""
else
read_from_cmdline
end.split(/&/).each do |x|
@@ -70,27 +170,92 @@ class CGI < SimpleDelegator
end
super(@inputs)
+
+ if ENV.has_key?('HTTP_COOKIE') or ENV.has_key?('COOKIE')
+ (ENV['HTTP_COOKIE'] or ENV['COOKIE']).split("; ").each do |x|
+ key, val = x.split(/=/,2)
+ key = unescape(key)
+ val = val.split(/&/).collect{|x|unescape(x)}.join("\0")
+ if @cookie.include?(key)
+ @cookie[key] += "\0" + val
+ else
+ @cookie[key] = val
+ end
+ end
+ end
end
- def CGI.message(msg, title = "")
- print "Content-type: text/html\n\n"
- print "<html><head><title>"
- print title
- print "</title></head><body>\n"
- print msg
- print "</body></html>\n"
- TRUE
+ attr("inputs")
+ attr("cookie")
+
+ # make HTML tag string
+ def CGI::tag(element, attributes = {})
+ "<" + escapeHTML(element) + attributes.collect{|name, value|
+ " " + escapeHTML(name) + '="' + escapeHTML(value) + '"'
+ }.to_s + ">" +
+ (iterator? ? yield.to_s + "</" + escapeHTML(element) + ">" : "")
+ end
+
+ # make raw cookie string
+ def CGI::cookie(options)
+ "Set-Cookie: " + options['name'] + '=' + escape(options['value']) +
+ (options['domain'] ? '; domain=' + options['domain'] : '') +
+ (options['path'] ? '; path=' + options['path'] : '') +
+ (options['expires'] ? '; expires=' + options['expires'].strftime("%a, %d %b %Y %X %Z") : '') +
+ (options['secure'] ? '; secure' : '')
+ end
+
+ # make HTTP header string
+ def CGI::header(*options)
+ if ENV['MOD_RUBY']
+ options.each{|option|
+ option.sub(/(.*?): (.*)/){
+ Apache::request[$1] = $2
+ }
+ }
+ Apache::request.send_http_header
+ ''
+ else
+ if options.delete("nph") or (ENV['SERVER_SOFTWARE'] =~ /IIS/)
+ [(ENV['SERVER_PROTOCOL'] or "HTTP/1.0") + " 200 OK",
+ "Date: " + Time.now.gmtime.strftime("%a, %d %b %Y %X %Z"),
+ "Server: " + (ENV['SERVER_SOFTWARE'] or ""),
+ "Connection: close"] +
+ (options.empty? ? ["Content-Type: text/html"] : options)
+ else
+ options.empty? ? ["Content-Type: text/html"] : options
+ end.join(EOL) + EOL + EOL
+ end
+ end
+
+ # print HTTP header and string to $>
+ def CGI::print(*options)
+ $>.print CGI::header(*options) + yield.to_s
+ end
+
+ # print message to $>
+ def CGI::message(message, title = "", header = ["Content-Type: text/html"])
+ if message.kind_of?(Hash)
+ title = message['title']
+ header = message['header']
+ message = message['body']
+ end
+ CGI::print(*header){
+ CGI::tag("HTML"){
+ CGI::tag("HEAD"){ CGI.tag("TITLE"){ title } } +
+ CGI::tag("BODY"){ message }
+ }
+ }
+ true
end
- def CGI.error
- m = $!.to_s.dup
- m.gsub!(/&/, '&amp;')
- m.gsub!(/</, '&lt;')
- m.gsub!(/>/, '&gt;')
- msgs = ["<pre>ERROR: <strong>#{m}</strong>"]
- msgs << $@
- msgs << "</pre>"
- CGI.message(msgs.join("\n"), "ERROR")
+ # print error message to $> and exit
+ def CGI::error
+ CGI::message({'title'=>'ERROR', 'body'=>
+ CGI::tag("PRE"){
+ "ERROR: " + CGI::tag("STRONG"){ escapeHTML($!.to_s) } + "\n" + escapeHTML($@.join("\n"))
+ }
+ })
exit
end
end
diff --git a/lib/complex.rb b/lib/complex.rb
index 59caad6..0af8c20 100644
--- a/lib/complex.rb
+++ b/lib/complex.rb
@@ -72,6 +72,8 @@ class Complex < Numeric
end
def initialize(a, b = 0)
+ raise "non numeric 1st arg `#{a.inspect}'" if !a.kind_of? Numeric
+ raise "non numeric 2nd arg `#{b.inspect}'" if !b.kind_of? Numeric
@real = a
@image = b
end
@@ -84,7 +86,7 @@ class Complex < Numeric
elsif Complex.generic?(other)
Complex(@real + other, @image)
else
- x , y = a.coerce(self)
+ x , y = other.coerce(self)
x + y
end
end
@@ -97,7 +99,7 @@ class Complex < Numeric
elsif Complex.generic?(other)
Complex(@real - other, @image)
else
- x , y = a.coerce(self)
+ x , y = other.coerce(self)
x - y
end
end
@@ -110,7 +112,7 @@ class Complex < Numeric
elsif Complex.generic?(other)
Complex(@real * other, @image * other)
else
- x , y = a.coerce(self)
+ x , y = other.coerce(self)
x * y
end
end
@@ -121,7 +123,7 @@ class Complex < Numeric
elsif Complex.generic?(other)
Complex(@real / other, @image / other)
else
- x , y = a.coerce(self)
+ x , y = other.coerce(self)
x / y
end
end
@@ -163,7 +165,7 @@ class Complex < Numeric
r, theta = polar
Complex.polar(r.power!(other), theta * other)
else
- x , y = a.coerce(self)
+ x , y = other.coerce(self)
x / y
end
end
@@ -174,7 +176,7 @@ class Complex < Numeric
elsif Complex.generic?(other)
Complex(@real % other, @image % other)
else
- x , y = a.coerce(self)
+ x , y = other.coerce(self)
x % y
end
end
@@ -187,7 +189,7 @@ class Complex < Numeric
elsif Complex.generic?(other)
Complex(@real.divmod(other), @image.divmod(other))
else
- x , y = a.coerce(self)
+ x , y = other.coerce(self)
x.divmod(y)
end
end
@@ -222,7 +224,7 @@ class Complex < Numeric
elsif Complex.generic?(other)
@real == other and @image == 0
else
- x , y = a.coerce(self)
+ x , y = other.coerce(self)
x == y
end
end
diff --git a/lib/date2.rb b/lib/date2.rb
new file mode 100644
index 0000000..58bfbe5
--- /dev/null
+++ b/lib/date2.rb
@@ -0,0 +1,267 @@
+# date2.rb: Written by Tadayoshi Funaba 1998, 1999
+# $Id: date2.rb,v 1.13 1999/08/11 01:10:02 tadf Exp $
+
+class Date
+
+ include Comparable
+
+ MONTHNAMES = [ nil, 'January', 'February', 'March',
+ 'April', 'May', 'June', 'July', 'August',
+ 'September', 'October', 'November', 'December' ]
+
+ DAYNAMES = [ 'Sunday', 'Monday', 'Tuesday',
+ 'Wednesday', 'Thursday', 'Friday', 'Saturday' ]
+
+ ITALY = 2299161 # Oct 15, 1582
+ ENGLAND = 2361222 # Sept 14, 1752
+
+ class << self
+
+ def os? (jd, sg)
+ case sg
+ when Numeric; jd < sg
+ else; not sg
+ end
+ end
+
+ def ns? (jd, sg) not os?(jd, sg) end
+
+ def civil_to_jd(y, m, d, sg=true)
+ if m <= 2
+ y -= 1
+ m += 12
+ end
+ a = (y / 100).to_i
+ b = 2 - a + (a / 4).to_i
+ jd = (365.25 * (y + 4716)).to_i +
+ (30.6001 * (m + 1)).to_i +
+ d + b - 1524
+ if os?(jd, sg)
+ jd -= b
+ end
+ jd
+ end
+
+ def jd_to_civil(jd, sg=true)
+ if os?(jd, sg)
+ a = jd
+ else
+ x = ((jd - 1867216.25) / 36524.25).to_i
+ a = jd + 1 + x - (x / 4).to_i
+ end
+ b = a + 1524
+ c = ((b - 122.1) / 365.25).to_i
+ d = (365.25 * c).to_i
+ e = ((b - d) / 30.6001).to_i
+ dom = b - d - (30.6001 * e).to_i
+ if e <= 13
+ m = e - 1
+ y = c - 4716
+ else
+ m = e - 13
+ y = c - 4715
+ end
+ return y, m, dom
+ end
+
+ def ordinal_to_jd(y, d, sg=true)
+ civil_to_jd(y, 1, d, sg)
+ end
+
+ def jd_to_ordinal(jd, sg=true)
+ y = jd_to_civil(jd, sg)[0]
+ pl = civil_to_jd(y - 1, 12, 31, ns?(jd, sg))
+ doy = jd - pl
+ return y, doy
+ end
+
+ def mjd_to_jd(mjd) mjd + 2400000.5 end
+ def jd_to_mjd(jd) jd - 2400000.5 end
+ def tjd_to_jd(tjd) tjd + 2440000.5 end
+ def jd_to_tjd(jd) jd - 2440000.5 end
+
+ def julian_leap? (y) y % 4 == 0 end
+ def gregorian_leap? (y) y % 4 == 0 and y % 100 != 0 or y % 400 == 0 end
+
+ alias_method :leap?, :gregorian_leap?
+
+ def exist3? (y, m, d, sg=ITALY)
+ if m < 0
+ m += 13
+ end
+ if d < 0
+ ljd = nil
+ 31.downto 1 do |ld|
+ break if ljd = exist3?(y, m, ld, sg)
+ end
+ x = y * 12 + m
+ ny = x / 12
+ nm = x % 12 + 1
+ d = jd_to_civil(civil_to_jd(ny, nm, 1, ns?(ljd, sg)) + d,
+ ns?(ljd, sg))[-1]
+ end
+ jd = civil_to_jd(y, m, d, sg)
+ if [y, m, d] == jd_to_civil(jd, sg)
+ jd
+ end
+ end
+
+ alias_method :exist?, :exist3?
+
+ def new3(y=-4712, m=1, d=1, sg=ITALY)
+ unless jd = exist3?(y, m, d, sg)
+ fail ArgumentError, 'invalid date'
+ end
+ new(jd, sg)
+ end
+
+ def exist2? (y, d, sg=ITALY)
+ if d < 0
+ ljd = nil
+ 366.downto 1 do |ld|
+ break if ljd = exist2?(y, ld, sg)
+ end
+ ny = y + 1
+ d = jd_to_ordinal(ordinal_to_jd(ny, 1, ns?(ljd, sg)) + d,
+ ns?(ljd, sg))[-1]
+ end
+ jd = ordinal_to_jd(y, d, sg)
+ if [y, d] == jd_to_ordinal(jd, sg)
+ jd
+ end
+ end
+
+ def new2(y=-4712, d=1, sg=ITALY)
+ unless jd = exist2?(y, d, sg)
+ fail ArgumentError, 'invalid date'
+ end
+ new(jd, sg)
+ end
+
+ def today(sg=ITALY)
+ new(civil_to_jd(*(Time.now.to_a[3..5].reverse << sg)), sg)
+ end
+
+ end
+
+ def initialize(jd=0, sg=ITALY) @jd, @sg = jd, sg end
+
+ def jd() @jd end
+
+ def mjd
+ def self.mjd() @mjd end
+ @mjd = Date.jd_to_mjd(@jd)
+ end
+
+ def tjd
+ def self.tjd() @tjd end
+ @tjd = Date.jd_to_tjd(@jd)
+ end
+
+ def civil
+ def self.year() @year end
+ def self.mon() @mon end
+ def self.month() @mon end
+ def self.mday() @mday end
+ def self.day() @mday end
+ @year, @mon, @mday = Date.jd_to_civil(@jd, @sg)
+ end
+
+ private :civil
+
+ def year
+ civil
+ @year
+ end
+
+ def yday
+ def self.yday() @yday end
+ @yday = Date.jd_to_ordinal(@jd, @sg)[-1]
+ @yday
+ end
+
+ def mon
+ civil
+ @mon
+ end
+
+ alias_method :month, :mon
+
+ def mday
+ civil
+ @mday
+ end
+
+ alias_method :day, :mday
+
+ def wday
+ def self.wday() @wday end
+ @wday = (@jd + 1) % 7
+ end
+
+ def os? () Date.os?(@jd, @sg) end
+ def ns? () Date.ns?(@jd, @sg) end
+
+ def leap?
+ def self.leap?() @leap_p end
+ @leap_p = Date.jd_to_civil(Date.civil_to_jd(year, 3, 1, ns?) - 1,
+ ns?)[-1] == 29
+ end
+
+ def + (other)
+ case other
+ when Numeric; return Date.new(@jd + other, @sg)
+ end
+ fail TypeError, 'expected numeric'
+ end
+
+ def - (other)
+ case other
+ when Numeric; return Date.new(@jd - other, @sg)
+ when Date; return @jd - other.jd
+ end
+ fail TypeError, 'expected numeric or date'
+ end
+
+ def <=> (other)
+ case other
+ when Numeric; return @jd <=> other
+ when Date; return @jd <=> other.jd
+ end
+ fail TypeError, 'expected numeric or date'
+ end
+
+ def downto(min)
+ @jd.downto(min.jd) do |jd|
+ yield Date.new(jd, @sg)
+ end
+ self
+ end
+
+ def upto(max)
+ @jd.upto(max.jd) do |jd|
+ yield Date.new(jd, @sg)
+ end
+ self
+ end
+
+ def step(limit, step)
+ @jd.step(limit.jd, step) do |jd|
+ yield Date.new(jd, @sg)
+ end
+ self
+ end
+
+ def succ() self + 1 end
+
+ alias_method :next, :succ
+
+ def eql? (other) self == other end
+ def hash() @jd end
+ def inspect() format('#<Date: %s,%s>', @jd, @sg) end
+ def to_s() format('%.4d-%02d-%02d', year, mon, mday) end
+
+ def _dump(limit) Marshal.dump([@jd, @sg], -1) end
+ def Date._load(str) Date.new(*Marshal.load(str)) end
+
+end
diff --git a/lib/debug.rb b/lib/debug.rb
index 90270a3..d2f1da8 100644
--- a/lib/debug.rb
+++ b/lib/debug.rb
@@ -1,13 +1,29 @@
-
class DEBUGGER__
+ begin
+ require 'readline'
+ def readline(prompt, hist)
+ Readline::readline(prompt, hist)
+ end
+ rescue LoadError
+ def readline(prompt, hist)
+ STDOUT.print prompt
+ STDOUT.flush
+ line = STDIN.gets
+ line.chomp!
+ line
+ end
+ USE_READLINE = false
+ end
+
trap("INT") { DEBUGGER__::CONTEXT.interrupt }
- $DEBUG = TRUE
+ $DEBUG = true
def initialize
@break_points = []
+ @display = []
@stop_next = 1
@frames = [nil]
- @frame_pos = nil
@last_file = nil
+ @last = [nil, nil]
@scripts = {}
end
@@ -23,185 +39,271 @@ class DEBUGGER__
val
rescue
at = caller(0)
- printf "%s:%s\n", at.shift, $!
+ STDOUT.printf "%s:%s\n", at.shift, $!
for i in at
break if i =~ /`debug_(eval|command)'$/ #`
- printf "\tfrom %s\n", i
+ STDOUT.printf "\tfrom %s\n", i
end
end
end
def debug_command(file, line, id, binding)
+ frame_pos = 0
+ binding_file = file
+ binding_line = line
+ previus_line = nil
if (ENV['EMACS'] == 't')
- printf "\032\032%s:%d:\n", file, line
+ STDOUT.printf "\032\032%s:%d:\n", binding_file, binding_line
else
- printf "%s:%d:%s", file, line, line_at(file, line)
+ STDOUT.printf "%s:%d:%s", binding_file, binding_line,
+ line_at(binding_file, binding_line)
end
- @frames[-1] = binding
- STDOUT.print "(rdb:-) "
- STDOUT.flush
- while input = STDIN.gets
- input.chop!
+ @frames[0] = binding
+ display_expressions(binding)
+ while input = readline("(rdb:-) ", true)
if input == ""
input = DEBUG_LAST_CMD[0]
else
DEBUG_LAST_CMD[0] = input
end
+
case input
- when /^b(reak)?\s+(([^:\n]+:)?.+)/
- pos = $2
- if pos.index ":"
+ when /^b(?:reak)?\s+((?:[^:\n]+:)?.+)$/
+ pos = $1
+ if pos.index(":")
file, pos = pos.split(":")
end
file = File.basename(file)
if pos =~ /^\d+$/
pname = pos
- pos = Integer(pos)
+ pos = pos.to_i
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
+ @break_points.push [true, 0, file, pos]
+ STDOUT.printf "Set breakpoint %d at %s:%s\n", @break_points.size, file,
+ pname
+
+ when /^wat(?:ch)?\s+(.+)$/
+ exp = $1
+ @break_points.push [true, 1, exp]
+ STDOUT.printf "Set watchpoint %d\n", @break_points.size, exp
+
+ when /^b(?:reak)?$/, /^info b(?:reak)?$/
+ n = 1
+ STDOUT.print "breakpoints:\n"
+ for b in @break_points
+ if b[0] and (b[1] == 0)
+ STDOUT.printf " %d %s:%s\n", n, b[2], b[3]
+ end
n += 1
end
- when /^del(ete)?(\s+(\d+))?$/
- pos = $3
+ n = 1
+ STDOUT.print "\n"
+ STDOUT.print "watchpoints:\n"
+ for b in @break_points
+ if b[0] and (b[1] == 1)
+ STDOUT.printf " %d %s\n", n, b[2]
+ end
+ n += 1
+ end
+ STDOUT.print "\n"
+
+ when /^del(?:ete)?(?:\s+(\d+))?$/
+ pos = $1
unless pos
- STDOUT.print "clear all breakpoints? (y/n) "
- STDOUT.flush
- input = STDIN.gets.chop!
+ input = readline("clear all breakpoints? (y/n) ", false)
if input == "y"
- for n in @break_points.indexes
- @break_points[n] = nil
+ for b in @break_points
+ b[0] = false
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
+ pos = pos.to_i
+ if @break_points[pos-1]
+ @break_points[pos-1][0] = false
else
- printf "Breakpoint %d is not defined\n", pos
+ STDOUT.printf "Breakpoint %d is not defined\n", pos
end
end
- when /^c(ont)?$/
- return
- when /^s(tep)?\s*(\d+)?$/
- if $1
- lev = Integer($1)
+
+ when /^disp(?:lay)?\s+(.+)$/
+ exp = $1
+ @display.push.push [true, exp]
+ STDOUT.printf " %d: %s = %s\n", @display.size, exp,
+ debug_eval(exp, binding).to_s
+
+ when /^disp(?:lay)?$/, /^info disp(?:lay)?$/
+ display_expressions(binding)
+
+ when /^undisp(?:lay)?(?:\s+(\d+))?$/
+ pos = $1
+ unless pos
+ input = readline("clear all expressions? (y/n) ", false)
+ if input == "y"
+ for d in @display
+ d[0] = false
+ end
+ end
else
- lev = 1
+ pos = pos.to_i
+ if @display[pos-1]
+ @display[pos-1][0] = false
+ else
+ STDOUT.printf "display expression %d is not defined\n", pos
+ end
end
- @stop_next = lev
+
+ when /^c(?:ont)?$/
return
- when /^n(ext)?\s*(\d+)?$/
+
+ when /^s(?:tep)?(?:\s+(\d+))?$/
if $1
- lev = Integer($1)
+ lev = $1.to_i
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+)??$/
+
+ when /^n(?:ext)?(?:\s+(\d+))?$/
if $1
- lev = Integer($1)
+ lev = $1.to_i
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
+ @stop_next = lev
+ @no_step = @frames.size - frame_pos
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
+
+ when /^w(?:here)?$/, /^f(?:rame)?$/
+ at = caller(0)
+ 0.upto(@frames.size - 1) do |n|
+ if frame_pos == n
+ STDOUT.printf "--> #%d %s\n", n, at[-(@frames.size - n)]
else
- e = b + 10
+ STDOUT.printf " #%d %s\n", n, at[-(@frames.size - n)]
end
end
- unless b
- b = line - 1
- e = line + 9
+
+ when /^l(?:ist)?(?:\s+(.+))?$/
+ if not $1
+ b = previus_line ? previus_line + 10 : binding_line - 5
+ e = b + 9
+ elsif $1 == '-'
+ b = previus_line ? previus_line - 10 : binding_line - 5
+ e = b + 9
+ else
+ b, e = $1.split(/[-,]/)
+ if e
+ b = b.to_i
+ e = e.to_i
+ else
+ b = b.to_i - 5
+ e = b + 9
+ end
+ end
+ previus_line = b
+ STDOUT.printf "[%d, %d] in %s\n", b, e, binding_file
+ line_at(binding_file, binding_line)
+ if lines = @scripts[binding_file] and lines != true
+ n = 0
+ b.upto(e) do |n|
+ if n > 0 && lines[n-1]
+ if n == binding_line
+ STDOUT.printf "=> %d %s\n", n, lines[n-1].chomp
+ else
+ STDOUT.printf " %d %s\n", n, lines[n-1].chomp
+ end
+ end
+ end
+ else
+ STDOUT.printf "no sourcefile available for %s\n", binding_file
+ end
+
+ when /^up(?:\s+(\d+))?$/
+ previus_line = nil
+ if $1
+ lev = $1.to_i
+ else
+ lev = 1
+ end
+ frame_pos += lev
+ if frame_pos >= @frames.size
+ frame_pos = @frames.size - 1
+ STDOUT.print "at toplevel\n"
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
+ binding = @frames[frame_pos]
+ info, binding_file, binding_line = frame_info(frame_pos)
+ STDOUT.printf "#%d %s\n", frame_pos, info
+
+ when /^down(?:\s+(\d+))?$/
+ previus_line = nil
+ if $1
+ lev = $1.to_i
+ else
+ lev = 1
+ end
+ frame_pos -= lev
+ if frame_pos < 0
+ frame_pos = 0
+ STDOUT.print "at stack bottom\n"
end
+ binding = @frames[frame_pos]
+ info, binding_file, binding_line = frame_info(frame_pos)
+ STDOUT.printf "#%d %s\n", frame_pos, info
+
+ when /^fi(?:nish)?$/
+ @finish_pos = @frames.size - frame_pos
+ frame_pos = 0
+ return
+
+ when /^q(?:uit)?$/
+ input = readline("really quit? (y/n) ", false)
+ exit if input == "y"
+
when /^p\s+/
- p debug_eval($', binding) #'
+ p debug_eval($', binding)
+
else
v = debug_eval(input, binding)
- p v unless v == nil
+ p v unless (v == nil)
end
- STDOUT.print "(rdb:-) "
- STDOUT.flush
end
end
+ def display_expressions(binding)
+ n = 1
+ for d in @display
+ if d[0]
+ STDOUT.printf "%d: %s = %s\n", n, d[1], debug_eval(d[1], binding).to_s
+ end
+ n += 1
+ end
+ end
+
+ def frame_info(pos = 0)
+ info = caller(0)[-(@frames.size - pos)]
+ info.sub(/:in `.*'$/, "") =~ /^(.*):(\d+)$/ #`
+ [info, $1, $2.to_i]
+ end
+
def line_at(file, line)
lines = @scripts[file]
if lines
- return "\n" if lines == TRUE
+ return "\n" if lines == true
line = lines[line-1]
return "\n" unless line
return line
end
save = $DEBUG
begin
- $DEBUG = FALSE
+ $DEBUG = false
f = open(file)
lines = @scripts[file] = f.readlines
rescue
$DEBUG = save
- @scripts[file] = TRUE
+ @scripts[file] = true
return "\n"
end
line = lines[line-1]
@@ -219,19 +321,44 @@ class DEBUGGER__
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
+ n = 1
+ for b in @break_points
+ if b[0]
+ if b[1] == 0 and b[2] == file and b[3] == pos
+ STDOUT.printf "breakpoint %d, %s at %s:%s\n", n, debug_funcname(id),
+ file, pos
+ return true
+ elsif b[1] == 1 and debug_eval(b[2], binding)
+ STDOUT.printf "watchpoint %d, %s at %s:%s\n", n, debug_funcname(id),
+ file, pos
+ return true
+ end
+ end
+ n += 1
+ end
+ return false
+ end
+
+ def excn_handle(file, line, id, binding)
+ fs = @frames.size
+ tb = caller(0)[-fs..-1]
+
+ STDOUT.printf "%s\n", $!
+ for i in tb
+ STDOUT.printf "\tfrom %s\n", i
end
- return FALSE
+ debug_command(file, line, id, binding)
end
def trace_func(event, file, line, id, binding)
- if event == 'line'
- if @no_step == nil or @no_step >= @frames.size
+ case event
+ when 'line'
+ if !@no_step or @frames.size == @no_step
@stop_next -= 1
+ elsif @frames.size < @no_step
+ @stop_next = 0 # break here before leaving...
+ else
+ # nothing to do. skipped.
end
if @stop_next == 0
if [file, line] == @last
@@ -245,21 +372,25 @@ class DEBUGGER__
if check_break_points(file, line, binding, id)
debug_command(file, line, id, binding)
end
- end
- if event == 'call'
- @frames.push binding
+
+ when 'call'
+ @frames.unshift 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
+
+ when 'class'
+ @frames.unshift binding
+
+ when 'return', 'end'
+ if @frames.size == @finish_pos
@stop_next = 1
end
- @frames.pop
+ @frames.shift
+
+ when 'raise'
+ excn_handle(file, line, id, binding)
+
end
@last_file = file
end
@@ -267,6 +398,6 @@ class DEBUGGER__
CONTEXT = new
end
-set_trace_func proc{|event, file, line, id, binding|
+set_trace_func proc{|event, file, line, id, binding,*rest|
DEBUGGER__::CONTEXT.trace_func event, file, line, id, binding
}
diff --git a/lib/delegate.rb b/lib/delegate.rb
index 0771f2f..29f2a5d 100644
--- a/lib/delegate.rb
+++ b/lib/delegate.rb
@@ -34,14 +34,8 @@ class Delegator
begin
__getobj__.__send__(:#{method}, *args, &block)
rescue Exception
- c = -caller(0).size
- if /:in `__getobj__'$/ =~ $@[c-1] #`
- n = 1
- else
- c -= 1
- n = 2
- end
- $@[c,n] = nil
+ $@.delete_if{|s| /:in `__getobj__'$/ =~ s} #`
+ $@.delete_if{|s| /^\\(eval\\):/ =~ s}
raise
end
end
diff --git a/lib/e2mmap.rb b/lib/e2mmap.rb
index bf860dc..e04ed4a 100644
--- a/lib/e2mmap.rb
+++ b/lib/e2mmap.rb
@@ -1,17 +1,46 @@
#
# e2mmap.rb - for ruby 1.1
-# $Release Version: 1.2$
-# $Revision: 1.8 $
-# $Date: 1998/08/19 15:22:22 $
+# $Release Version: 2.0$
+# $Revision: 1.10 $
+# $Date: 1999/02/17 12:33:17 $
# by Keiju ISHITSUKA
#
# --
# Usage:
#
+# U1)
# class Foo
# extend Exception2MassageMapper
+# def_e2message ExistingExceptionClass, "message..."
# def_exception :NewExceptionClass, "message..."[, superclass]
+# ...
+# end
+#
+# U2)
+# module Error
+# extend Exception2MassageMapper
# def_e2meggage ExistingExceptionClass, "message..."
+# def_exception :NewExceptionClass, "message..."[, superclass]
+# ...
+# end
+# class Foo
+# include Exp
+# ...
+# end
+#
+# foo = Foo.new
+# foo.Fail ....
+#
+# U3)
+# module Error
+# extend Exception2MassageMapper
+# def_e2message ExistingExceptionClass, "message..."
+# def_exception :NewExceptionClass, "message..."[, superclass]
+# ...
+# end
+# class Foo
+# extend Exception2MessageMapper
+# include Error
# ...
# end
#
@@ -19,113 +48,149 @@
# Foo.Fail ExistingExceptionClass, arg...
#
#
-if VERSION < "1.1"
- require "e2mmap1_0.rb"
-else
+fail "Use Ruby 1.1" if VERSION < "1.1"
+
+module Exception2MessageMapper
+ @RCS_ID='-$Id: e2mmap.rb,v 1.10 1999/02/17 12:33:17 keiju Exp keiju $-'
+
+ E2MM = Exception2MessageMapper
+
+ def E2MM.extend_object(cl)
+ super
+ cl.bind(self) unless cl == E2MM
+ end
- module Exception2MessageMapper
- @RCS_ID='-$Id: e2mmap.rb,v 1.8 1998/08/19 15:22:22 keiju Exp keiju $-'
-
- E2MM = Exception2MessageMapper
+ # 以前との互換性のために残してある.
+ def E2MM.extend_to(b)
+ c = eval("self", b)
+ c.extend(self)
+ end
- def E2MM.extend_object(cl)
+ def bind(cl)
+ self.module_eval %[
+ def Raise(err = nil, *rest)
+ Exception2MessageMapper.Raise(self.type, err, *rest)
+ end
+ alias Fail Raise
+
+ def self.append_features(mod)
+ super
+ mod.extend Exception2MessageMapper
+ end
+ ]
+ end
+
+ # Fail(err, *rest)
+ # err: 例外
+ # rest: メッセージに渡すパラメータ
+ #
+ def Raise(err = nil, *rest)
+ E2MM.Raise(self, err, *rest)
+ end
+ alias Fail Raise
+
+ # 過去の互換性のため
+ alias fail! fail
+ def fail(err = nil, *rest)
+ begin
+ E2MM.Fail(self, err, *rest)
+ rescue E2MM::ErrNotRegisteredException
super
- cl.bind(self)
end
-
- # backward compatibility
- def E2MM.extend_to(b)
- c = eval("self", b)
- c.extend(self)
- end
-
- # public :fail
- alias fail! fail
+ end
+ class << self
+ public :fail
+ end
- #def fail(err = nil, *rest)
- # super
- #end
+
+ # def_e2message(c, m)
+ # c: exception
+ # m: message_form
+ # 例外cのメッセージをmとする.
+ #
+ def def_e2message(c, m)
+ E2MM.def_e2message(self, c, m)
+ end
+
+ # def_exception(c, m)
+ # n: exception_name
+ # m: message_form
+ # s: 例外スーパークラス(デフォルト: StandardError)
+ # 例外名``c''をもつ例外を定義し, そのメッセージをmとする.
+ #
+ def def_exception(n, m, s = StandardError)
+ E2MM.def_exception(self, n, m, s)
+ end
- def Fail(err = nil, *rest)
- Exception2MessageMapper.Fail Exception2MessageMapper::ErrNotRegisteredException, err.inspect
- end
-
- def bind(cl)
- self.module_eval %q^
- E2MM_ErrorMSG = {} unless self.const_defined?(:E2MM_ErrorMSG)
- # fail(err, *rest)
- # err: Exception
- # rest: Parameter accompanied with the exception
- #
- def self.Fail(err = nil, *rest)
- if form = E2MM_ErrorMSG[err]
- $! = err.new(sprintf(form, *rest))
- $@ = caller(0) if $@.nil?
- $@.shift
- # e2mm_fail()
- raise()
-# elsif self == Exception2MessageMapper
-# fail Exception2MessageMapper::ErrNotRegisteredException, err.to_s
- else
-# print "super\n"
- super
- end
- end
+ #
+ # Private definitions.
+ #
+ # {[class, exp] => message, ...}
+ @MessageMap = {}
+
+ # E2MM.def_exception(k, e, m)
+ # k: 例外を定義するクラス
+ # e: exception
+ # m: message_form
+ # 例外cのメッセージをmとする.
+ #
+ def E2MM.def_e2message(k, c, m)
+ E2MM.instance_eval{@MessageMap[[k, c]] = m}
+ c
+ end
+
+ # E2MM.def_exception(k, c, m)
+ # k: 例外を定義するクラス
+ # n: exception_name
+ # m: message_form
+ # s: 例外スーパークラス(デフォルト: StandardError)
+ # 例外名``c''をもつ例外を定義し, そのメッセージをmとする.
+ #
+ def E2MM.def_exception(k, n, m, s = StandardError)
+ n = n.id2name if n.kind_of?(Fixnum)
+ e = Class.new(s)
+ E2MM.instance_eval{@MessageMap[[k, e]] = m}
+ k.const_set(n, e)
+ end
- # 過去の互換性のため
- def self.fail(err = nil, *rest)
- if form = E2MM_ErrorMSG[err]
- $! = err.new(sprintf(form, *rest))
- $@ = caller(0) if $@.nil?
- $@.shift
- # 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
- #
- def self.def_e2message(c, m)
- E2MM_ErrorMSG[c] = m
- end
-
- # def_exception(c, m)
- # n: exception_name
- # m: message_form
- # s: superclass_of_exception (default: Exception)
- # defines excaption named ``c'', whose message is ``m''.
- #
- #def def_exception(n, m)
- def self.def_exception(n, m, s = nil)
- n = n.id2name if n.kind_of?(Fixnum)
- unless s
- if defined?(StandardError)
- s = StandardError
- else
- s = Exception
- end
- end
- e = Class.new(s)
+ # Fail(klass, err, *rest)
+ # klass: 例外の定義されているクラス
+ # err: 例外
+ # rest: メッセージに渡すパラメータ
+ #
+ def E2MM.Raise(klass = E2MM, err = nil, *rest)
+ if form = e2mm_message(klass, err)
+ $! = err.new(sprintf(form, *rest))
+ $@ = caller(1) if $@.nil?
+ #p $@
+ #p __FILE__
+ $@.shift if $@[0] =~ /^#{Regexp.quote(__FILE__)}:/
+ raise
+ else
+ E2MM.Fail E2MM, ErrNotRegisteredException, err.inspect
+ end
+ end
+ class <<E2MM
+ alias Fail Raise
+ end
- const_set(n, e)
- E2MM_ErrorMSG[e] = m
- # const_get(:E2MM_ErrorMSG)[e] = m
- end
- ^
+ def E2MM.e2mm_message(klass, exp)
+ for c in klass.ancestors
+ if mes = @MessageMap[[c,exp]]
+ p mes
+ m = klass.instance_eval('"' + mes + '"')
+ return m
end
-
- extend E2MM
- def_exception(:ErrNotClassOrModule, "Not Class or Module")
- def_exception(:ErrNotRegisteredException, "not registerd exception(%s)")
end
+ nil
+ end
+ class <<self
+ alias message e2mm_message
+ end
+
+ E2MM.def_exception(E2MM,
+ :ErrNotRegisteredException,
+ "not registerd exception(%s)")
end
+
+
diff --git a/lib/final.rb b/lib/final.rb
new file mode 100644
index 0000000..cdffd94
--- /dev/null
+++ b/lib/final.rb
@@ -0,0 +1,41 @@
+#
+# $Id$
+# Copyright (C) 1998 Yukihiro Matsumoto. All rights reserved.
+
+# The ObjectSpace extension:
+#
+# ObjectSpace.define_finalizer(obj, proc=lambda())
+#
+# Defines the finalizer for the specified object.
+#
+# ObjectSpace.undefine_finalizer(obj)
+#
+# Removes the finalizers for the object. If multiple finalizers are
+# defined for the object, all finalizers will be removed.
+#
+
+module ObjectSpace
+ Finalizers = {}
+ def define_finalizer(obj, proc=lambda())
+ ObjectSpace.call_finalizer(obj)
+ if assoc = Finalizers[obj.id]
+ assoc.push(proc)
+ else
+ Finalizers[obj.id] = [proc]
+ end
+ end
+ def undefine_finalizer(obj)
+ Finalizers.delete(obj.id)
+ end
+ module_function :define_finalizer, :undefine_finalizer
+
+ Generic_Finalizer = proc {|id|
+ if Finalizers.key? id
+ for proc in Finalizers[id]
+ proc.call(id)
+ end
+ Finalizers.delete(id)
+ end
+ }
+ add_finalizer Generic_Finalizer
+end
diff --git a/lib/finalize.rb b/lib/finalize.rb
index a07e67d..3cf79ff 100644
--- a/lib/finalize.rb
+++ b/lib/finalize.rb
@@ -157,7 +157,7 @@ module Finalizer
# method to call finalize_* safely.
def safe
old_status = Thread.critical
- Thread.critical = TRUE
+ Thread.critical = true
ObjectSpace.remove_finalizer(@proc)
yield
ObjectSpace.add_finalizer(@proc)
diff --git a/lib/ftools.rb b/lib/ftools.rb
index 7ccc7a4..39d6ca9 100644
--- a/lib/ftools.rb
+++ b/lib/ftools.rb
@@ -24,6 +24,9 @@ class << File
fsize = 1024 if fsize < 512
fsize = TOO_BIG if fsize > TOO_BIG
+ fmode = stat(from).mode
+ tpath = to
+
from = open(from, "r")
from.binmode
to = open(to, "w")
@@ -47,6 +50,7 @@ class << File
to.close
from.close
end
+ chmod(fmode, tpath)
ret
end
@@ -63,13 +67,24 @@ class << File
to = catname(from, to)
$stderr.print from, " -> ", to, "\n" if verbose
- if PLATFORM =~ /djgpp|cygwin|mswin32/ and FileTest.file? to
+ if RUBY_PLATFORM =~ /djgpp|cygwin|mswin32/ and FileTest.file? to
unlink to
end
+ fstat = stat(from)
begin
rename from, to
rescue
- syscopy from, to and unlink from
+ begin
+ symlink File.readlink(from), to and unlink from
+ rescue
+ from_stat = stat(from)
+ syscopy from, to and unlink from
+ utime(from_stat.atime, from_stat.mtime, to)
+ begin
+ chown(fstat.uid, fstat.gid, tpath)
+ rescue
+ end
+ end
end
end
@@ -98,7 +113,8 @@ class << File
if fr = from.read(fsize)
tr = to.read(fr.size)
else
- ret = !to.read(fsize)
+ ret = to.read(fsize)
+ ret = !ret || ret.length == 0
break
end
end
@@ -137,7 +153,9 @@ class << File
parent = dirname(dir)
makedirs parent unless FileTest.directory? parent
$stderr.print "mkdir ", dir, "\n" if verbose
- Dir.mkdir dir, mode
+ if basename(dir) != ""
+ Dir.mkdir dir, mode
+ end
end
end
@@ -154,7 +172,7 @@ class << File
def install(from, to, mode = nil, verbose = false)
to = catname(from, to)
unless FileTest.exist? to and cmp from, to
- unlink to if FileTest.exist? to
+ safe_unlink to if FileTest.exist? to
cp from, to, verbose
chmod mode, to, verbose if mode
end
diff --git a/lib/ftplib.rb b/lib/ftplib.rb
index 617d858..9336e0a 100644
--- a/lib/ftplib.rb
+++ b/lib/ftplib.rb
@@ -150,16 +150,23 @@ class FTP
end
def sendport(host, port)
- hbytes = host.split(".")
- pbytes = [port / 256, port % 256]
- bytes = hbytes + pbytes
- cmd = "PORT " + bytes.join(",")
+ af = (@sock.peeraddr)[0]
+ if af == "AF_INET"
+ hbytes = host.split(".")
+ pbytes = [port / 256, port % 256]
+ bytes = hbytes + pbytes
+ cmd = "PORT " + bytes.join(",")
+ elsif af == "AF_INET6"
+ cmd = "EPRT |2|" + host + "|" + sprintf("%d", port) + "|"
+ else
+ raise FTPProtoError, host
+ end
voidcmd(cmd)
end
private :sendport
def makeport
- sock = TCPserver.open(0)
+ sock = TCPserver.open(@sock.addr[3], 0)
port = sock.addr[1]
host = TCPsocket.getaddress(@sock.addr[2])
resp = sendport(host, port)
@@ -167,9 +174,20 @@ class FTP
end
private :makeport
+ def makepasv
+ if @sock.peeraddr[0] == "AF_INET"
+ host, port = parse227(sendcmd("PASV"))
+ else
+ host, port = parse229(sendcmd("EPSV"))
+# host, port = parse228(sendcmd("LPSV"))
+ end
+ return host, port
+ end
+ private :makepasv
+
def transfercmd(cmd)
if @passive
- host, port = parse227(sendcmd("PASV"))
+ host, port = makepasv
conn = open_socket(host, port)
resp = sendcmd(cmd)
if resp[0] != ?1
@@ -293,11 +311,7 @@ class FTP
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
+ buf = buf.chop + CRLF
end
conn.write(buf)
callback.call(buf) if use_callback
@@ -545,6 +559,57 @@ class FTP
end
private :parse227
+ def parse228(resp)
+ if resp[0, 3] != "228"
+ 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[0] == "4"
+ if numbers.length != 9 || numbers[1] != "4" || numbers[2 + 4] != "2"
+ raise FTPProtoError, resp
+ end
+ host = numbers[2, 4].join(".")
+ port = (numbers[7].to_i << 8) + numbers[8].to_i
+ elsif numbers[0] == "6"
+ if numbers.length != 21 || numbers[1] != "16" || numbers[2 + 16] != "2"
+ raise FTPProtoError, resp
+ end
+ v6 = ["", "", "", "", "", "", "", ""]
+ for i in 0 .. 7
+ v6[i] = sprintf("%02x%02x", numbers[(i * 2) + 2].to_i,
+ numbers[(i * 2) + 3].to_i)
+ end
+ host = v6[0, 8].join(":")
+ port = (numbers[19].to_i << 8) + numbers[20].to_i
+ end
+ return host, port
+ end
+ private :parse228
+
+ def parse229(resp)
+ if resp[0, 3] != "229"
+ 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(resp[left + 1, 1])
+ if numbers.length != 4
+ raise FTPProtoError, resp
+ end
+ port = numbers[3].to_i
+ host = (@sock.peeraddr())[3]
+ return host, port
+ end
+ private :parse228
+
def parse257(resp)
if resp[0, 3] != "257"
raise FTPReplyError, resp
diff --git a/lib/getoptlong.rb b/lib/getoptlong.rb
new file mode 100644
index 0000000..a37714c
--- /dev/null
+++ b/lib/getoptlong.rb
@@ -0,0 +1,473 @@
+# -*- Ruby -*-
+# Copyright (C) 1998 Motoyuki Kasahara
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+
+#
+# Documents and latest version of `getoptlong.rb' are found at:
+# http://www.sra.co.jp/people/m-kasahr/ruby/getoptlong/
+#
+
+#
+# Parse command line options just like GNU getopt_long().
+#
+class GetoptLong
+ #
+ # Orderings.
+ #
+ ORDERINGS = [REQUIRE_ORDER = 0, PERMUTE = 1, RETURN_IN_ORDER = 2]
+
+ #
+ # Argument flags.
+ #
+ ARGUMENT_FLAGS = [NO_ARGUMENT = 0, REQUIRED_ARGUMENT = 1,
+ OPTIONAL_ARGUMENT = 2]
+
+ #
+ # Status codes.
+ #
+ STATUS_YET, STATUS_STARTED, STATUS_TERMINATED = 0..2
+
+ #
+ # Error types.
+ #
+ class AmbigousOption < StandardError; end
+ class NeedlessArgument < StandardError; end
+ class MissingArgument < StandardError; end
+ class InvalidOption < StandardError; end
+
+ #
+ # Initializer.
+ #
+ def initialize(*arguments)
+ #
+ # Current ordering.
+ #
+ if ENV.include?('POSIXLY_CORRECT')
+ @ordering = REQUIRE_ORDER
+ else
+ @ordering = PERMUTE
+ end
+
+ #
+ # Hash table of option names.
+ # Keyes of the table are option names, and their values are canonical
+ # names of the options.
+ #
+ @canonical_names = Hash.new
+
+ #
+ # Hash table of argument flags.
+ # Keyes of the table are option names, and their values are argument
+ # flags of the options.
+ #
+ @argument_flags = Hash.new
+
+ #
+ # Whether error messages are output to stderr.
+ #
+ @quiet = FALSE
+
+ #
+ # Status code.
+ #
+ @status = STATUS_YET
+
+ #
+ # Error code.
+ #
+ @error = nil
+
+ #
+ # Error message.
+ #
+ @error_message = nil
+
+ #
+ # Rest of catinated short options.
+ #
+ @rest_singles = ''
+
+ #
+ # List of non-option-arguments.
+ # Append them to ARGV when option processing is terminated.
+ #
+ @non_option_arguments = Array.new
+
+ if 0 < arguments.length
+ set_options(*arguments)
+ end
+ end
+
+ #
+ # Set ordering.
+ #
+ def ordering=(ordering)
+ #
+ # The method is failed if option processing has already started.
+ #
+ if @status != STATUS_YET
+ set_error(ArgumentError, "argument error")
+ raise RuntimeError,
+ "invoke ordering=, but option processing has already started"
+ end
+
+ #
+ # Check ordering.
+ #
+ if !ORDERINGS.include?(ordering)
+ raise ArgumentError, "invalid ordering `#{ordering}'"
+ end
+ if ordering == PERMUTE && ENV.include?('POSIXLY_CORRECT')
+ @ordering = REQUIRE_ORDER
+ else
+ @ordering = ordering
+ end
+ end
+
+ #
+ # Return ordering.
+ #
+ attr_reader :ordering
+
+ #
+ # Set options
+ #
+ def set_options(*arguments)
+ #
+ # The method is failed if option processing has already started.
+ #
+ if @status != STATUS_YET
+ raise RuntimeError,
+ "invoke set_options, but option processing has already started"
+ end
+
+ #
+ # Clear tables of option names and argument flags.
+ #
+ @canonical_names.clear
+ @argument_flags.clear
+
+ arguments.each do |arg|
+ #
+ # Each argument must be an Array.
+ #
+ if !arg.is_a?(Array)
+ raise ArgumentError, "the option list contains non-Array argument"
+ end
+
+ #
+ # Find an argument flag and it set to `argument_flag'.
+ #
+ argument_flag = nil
+ arg.each do |i|
+ if ARGUMENT_FLAGS.include?(i)
+ if argument_flag != nil
+ raise ArgumentError, "too many argument-flags"
+ end
+ argument_flag = i
+ end
+ end
+ raise ArgumentError, "no argument-flag" if argument_flag == nil
+
+ canonical_name = nil
+ arg.each do |i|
+ #
+ # Check an option name.
+ #
+ next if i == argument_flag
+ begin
+ if !i.is_a?(String) || i !~ /^-([^-]|-.+)$/
+ raise ArgumentError, "an invalid option `#{i}'"
+ end
+ if (@canonical_names.include?(i))
+ raise ArgumentError, "option redefined `#{i}'"
+ end
+ rescue
+ @canonical_names.clear
+ @argument_flags.clear
+ raise
+ end
+
+ #
+ # Register the option (`i') to the `@canonical_names' and
+ # `@canonical_names' Hashes.
+ #
+ if canonical_name == nil
+ canonical_name = i
+ end
+ @canonical_names[i] = canonical_name
+ @argument_flags[i] = argument_flag
+ end
+ raise ArgumentError, "no option name" if canonical_name == nil
+ end
+ return self
+ end
+
+ #
+ # Set/Unset `quit' mode.
+ #
+ attr_writer :quiet
+
+ #
+ # Return the flag of `quiet' mode.
+ #
+ attr_reader :quiet
+
+ #
+ # `quiet?' is an alias of `quiet'.
+ #
+ alias quiet? quiet
+
+ #
+ # Termintate option processing.
+ #
+ def terminate
+ return if @status == STATUS_TERMINATED
+ raise RuntimeError, "an error has occured" if @error != nil
+
+ @status = STATUS_TERMINATED
+ @non_option_arguments.reverse_each do |argument|
+ ARGV.unshift(argument)
+ end
+
+ @canonical_names = nil
+ @argument_flags = nil
+ @rest_singles = nil
+ @non_option_arguments = nil
+
+ return self
+ end
+
+ #
+ # Examine whether option processing is termintated or not.
+ #
+ def terminated?
+ return @status == STATUS_TERMINATED
+ end
+
+ #
+ # Set an error (protected).
+ #
+ def set_error(type, message)
+ $stderr.print("#{$0}: #{message}\n") if !@quiet
+
+ @error = type
+ @error_message = message
+ @canonical_names = nil
+ @argument_flags = nil
+ @rest_singles = nil
+ @non_option_arguments = nil
+
+ raise type, message
+ end
+ protected :set_error
+
+ #
+ # Examine whether an option processing is failed.
+ #
+ attr_reader :error
+
+ #
+ # `error?' is an alias of `error'.
+ #
+ alias error? error
+
+ #
+ # Return an error message.
+ #
+ def error_message
+ return @error_message
+ end
+
+ #
+ # Get next option name and its argument as an array.
+ #
+ def get
+ name, argument = nil, ''
+
+ #
+ # Check status.
+ #
+ return if @error != nil
+ case @status
+ when STATUS_YET
+ @status = STATUS_STARTED
+ when STATUS_TERMINATED
+ return
+ end
+
+ #
+ # Get next option argument.
+ #
+ if 0 < @rest_singles.length
+ $_ = '-' + @rest_singles
+ elsif (ARGV.length == 0)
+ terminate
+ return nil
+ elsif @ordering == PERMUTE
+ while 0 < ARGV.length && ARGV[0] !~ /^-./
+ @non_option_arguments.push(ARGV.shift)
+ end
+ if ARGV.length == 0
+ terminate
+ return
+ end
+ $_ = ARGV.shift
+ elsif @ordering == REQUIRE_ORDER
+ if (ARGV[0] !~ /^-./)
+ terminate
+ return nil
+ end
+ $_ = ARGV.shift
+ else
+ $_ = ARGV.shift
+ end
+
+ #
+ # Check the special argument `--'.
+ # `--' indicates the end of the option list.
+ #
+ if $_ == '--' && @rest_singles.length == 0
+ terminate
+ return nil
+ end
+
+ #
+ # Check for long and short options.
+ #
+ if /^(--[^=]+)/ && @rest_singles.length == 0
+ #
+ # This is a long style option, which start with `--'.
+ #
+ pattern = $1
+ if @canonical_names.include?(pattern)
+ name = pattern
+ else
+ #
+ # The option `name' is not registered in `@canonical_names'.
+ # It may be an abbreviated.
+ #
+ match_count = 0
+ @canonical_names.each_key do |key|
+ if key.index(pattern) == 0
+ name = key
+ match_count += 1
+ end
+ end
+ if 2 <= match_count
+ set_error(AmbigousOption, "option `#{$_}' is ambiguous")
+ elsif match_count == 0
+ set_error(InvalidOption, "unrecognized option `#{$_}'")
+ end
+ end
+
+ #
+ # Check an argument to the option.
+ #
+ if @argument_flags[name] == REQUIRED_ARGUMENT
+ if /=(.*)$/
+ argument = $1
+ elsif 0 < ARGV.length
+ argument = ARGV.shift
+ else
+ set_error(MissingArgument, "option `#{$_}' requires an argument")
+ end
+ elsif @argument_flags[name] == OPTIONAL_ARGUMENT
+ if /=(.*)$/
+ argument = $1
+ elsif 0 < ARGV.length && ARGV[0] !~ /^-./
+ argument = ARGV.shift
+ else
+ argument = ''
+ end
+ elsif /=(.*)$/
+ set_error(NeedlessArgument,
+ "option `#{name}' doesn't allow an argument")
+ end
+
+ elsif /^(-(.))(.*)/
+ #
+ # This is a short style option, which start with `-' (not `--').
+ # Short options may be catinated (e.g. `-l -g' is equivalent to
+ # `-lg').
+ #
+ name, ch, @rest_singles = $1, $2, $3
+
+ if @canonical_names.include?(name)
+ #
+ # The option `name' is found in `@canonical_names'.
+ # Check its argument.
+ #
+ if @argument_flags[name] == REQUIRED_ARGUMENT
+ if 0 < @rest_singles.length
+ argument = @rest_singles
+ @rest_singles = ''
+ elsif 0 < ARGV.length
+ argument = ARGV.shift
+ else
+ # 1003.2 specifies the format of this message.
+ set_error(MissingArgument, "option requires an argument -- #{ch}")
+ end
+ elsif @argument_flags[name] == OPTIONAL_ARGUMENT
+ if 0 < @rest_singles.length
+ argument = @rest_singles
+ @rest_singles = ''
+ elsif 0 < ARGV.length && ARGV[0] !~ /^-./
+ argument = ARGV.shift
+ else
+ argument = ''
+ end
+ end
+ else
+ #
+ # This is an invalid option.
+ # 1003.2 specifies the format of this message.
+ #
+ if ENV.include?('POSIXLY_CORRECT')
+ set_error(InvalidOption, "illegal option -- #{ch}")
+ else
+ set_error(InvalidOption, "invalid option -- #{ch}")
+ end
+ end
+ else
+ #
+ # This is a non-option argument.
+ # Only RETURN_IN_ORDER falled into here.
+ #
+ return '', $_
+ end
+
+ return @canonical_names[name], argument
+ end
+
+ #
+ # `get_option' is an alias of `get'.
+ #
+ alias get_option get
+
+ #
+ # Iterator version of `get'.
+ #
+ def each
+ loop do
+ name, argument = get_option
+ break if name == nil
+ yield name, argument
+ end
+ end
+
+ #
+ # `each_option' is an alias of `each'.
+ #
+ alias each_option each
+end
diff --git a/lib/getopts.rb b/lib/getopts.rb
index 9e1e8a2..5b9562d 100644
--- a/lib/getopts.rb
+++ b/lib/getopts.rb
@@ -15,7 +15,7 @@ $RCS_ID=%q$Header$
def isSingle(lopt)
if lopt.index(":")
if lopt.split(":")[0].length == 1
- return TRUE
+ return true
end
end
return nil
@@ -87,13 +87,13 @@ def getopts(single_opts, *options)
return nil
end
setOption(compare, ARGV[1])
- opts[compare] = TRUE
+ opts[compare] = true
ARGV.shift
count += 1
break
elsif lo == compare
- setOption(compare, TRUE)
- opts[compare] = TRUE
+ setOption(compare, true)
+ opts[compare] = true
count += 1
break
end
@@ -106,19 +106,19 @@ def getopts(single_opts, *options)
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
+ 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
+ opts[compare] = true
count += 1
elsif ARGV.length <= 1
return nil
else
setOption(compare, ARGV[1])
- opts[compare] = TRUE
+ opts[compare] = true
ARGV.shift
count += 1
end
@@ -127,7 +127,7 @@ def getopts(single_opts, *options)
end
else
compare = ARGV[0]
- opts[compare] = TRUE
+ opts[compare] = true
newargv << ARGV[0]
end
diff --git a/lib/jcode.rb b/lib/jcode.rb
index 50b7bee..92b9284 100644
--- a/lib/jcode.rb
+++ b/lib/jcode.rb
@@ -12,9 +12,10 @@ class String
private :original_succ
def mbchar?
- if $KCODE =~ /^s/i
+ case $KCODE[0]
+ when ?s, ?S
self =~ /[\x81-\x9f\xe0-\xef][\x40-\x7e\x80-\xfc]/n
- elsif $KCODE =~ /^e/i
+ when ?e, ?E
self =~ /[\xa1-\xfe][\xa1-\xfe]/n
else
false
@@ -22,16 +23,15 @@ class String
end
def succ
- if self[-2] && self[-2] & 0x80 != 0
+ if self[-2] and self[-2, 2].mbchar?
s = self.dup
s[-1] += 1
- s[-1] += 1 if !s.mbchar?
+ s[-1] += 1 unless s[-2, 2].mbchar?
return s
else
original_succ
end
end
- alias next succ
def upto(to)
return if self > to
@@ -58,9 +58,11 @@ class String
return nil
end
- def _expand_ch
+ private
+
+ def _expand_ch str
a = []
- self.scan(/(.|\n)-(.|\n)|(.|\n)/) do |r|
+ str.scan(/(.|\n)-(.|\n)|(.|\n)/) do |r|
if $3
a.push $3
elsif $1.length != $2.length
@@ -74,32 +76,35 @@ class String
a
end
+ def expand_ch_hash from, to
+ h = {}
+ afrom = _expand_ch(from)
+ ato = _expand_ch(to)
+ afrom.each_with_index do |x,i| h[x] = ato[i] || ato[-1] end
+ h
+ end
+
+ def bsquote(str)
+ str.gsub(/\\/, '\\\\\\\\')
+ end
+
+ HashCache = {}
+ TrPatternCache = {}
+ DeletePatternCache = {}
+ SqueezePatternCache = {}
+
+ public
+
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
+ pattern = TrPatternCache[from] ||= /[#{bsquote(from)}]/
+ if from[0] == ?^
+ last = /.$/.match(to)[0]
+ self.gsub!(pattern, last)
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
+ h = HashCache[from + "::" + to] ||= expand_ch_hash(from, to)
+ self.gsub!(pattern) do |c| h[c] end
end
end
@@ -108,22 +113,7 @@ class String
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
+ self.gsub!(DeletePatternCache[del] ||= /[#{bsquote(del)}]+/, '')
end
def delete(del)
@@ -131,27 +121,13 @@ class String
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
+ pattern =
+ if del
+ SqueezePatternCache[del] ||= /([#{bsquote(del)}])\1+/
else
- for c in adel
- cq = Regexp.quote(c)
- self.gsub!(/#{cq}(#{cq})+/, cq)
- end
+ /(.|\n)\1+/
end
- self
- else
- self.gsub!(/(.|\n)\1+/, '\1')
- end
+ self.gsub!(pattern, '\1')
end
def squeeze(del=nil)
@@ -160,30 +136,14 @@ class String
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
+
+ pattern = SqueezePatternCache[from] ||= /([#{bsquote(from)}])\1+"/
+ if from[0] == ?^
+ last = /.$/.match(to)[0]
+ self.gsub!(pattern, last)
+ else
+ h = HashCache[from + "::" + to] ||= expand_ch_hash(from, to)
+ self.gsub!(pattern) do h[$1] end
end
end
@@ -191,18 +151,17 @@ class String
(str = self.dup).tr_s!(from,to) or str
end
- alias original_chop! chop!
- private :original_chop!
-
def chop!
- if self =~ /(.)$/ and $1.size == 2
- original_chop!
- end
- original_chop!
+ self.gsub!(/(?:.|\r?\n)\z/, '')
end
def chop
(str = self.dup).chop! or str
end
+
+ def jcount(str)
+ self.delete("^#{str}").jlength
+ end
+
end
$VERBOSE = $vsave
diff --git a/lib/mailread.rb b/lib/mailread.rb
index 5e46606..2edcca0 100644
--- a/lib/mailread.rb
+++ b/lib/mailread.rb
@@ -43,6 +43,6 @@ class Mail
end
def [](field)
- @header[field]
+ @header[field.capitalize]
end
end
diff --git a/lib/mathn.rb b/lib/mathn.rb
index 265ef13..8d92272 100644
--- a/lib/mathn.rb
+++ b/lib/mathn.rb
@@ -121,7 +121,7 @@ class Bignum
end
class Rational
- Unify = TRUE
+ Unify = true
alias power! **
@@ -304,6 +304,6 @@ module Math
end
class Complex
- Unify = TRUE
+ Unify = true
end
diff --git a/lib/matrix.rb b/lib/matrix.rb
index 64b0738..f5c8491 100644
--- a/lib/matrix.rb
+++ b/lib/matrix.rb
@@ -1,8 +1,9 @@
+#!/usr/local/bin/ruby
#
# matrix.rb -
# $Release Version: 1.0$
-# $Revision: 1.6 $
-# $Date: 1998/07/31 03:39:49 $
+# $Revision: 1.8 $
+# $Date: 1999/02/17 12:34:19 $
# Original Version from Smalltalk-80 version
# on July 23, 1985 at 8:37:17 am
# by Keiju ISHITSUKA
@@ -17,6 +18,8 @@
# :
# rown]
#
+# column: 列
+# row: 行
#
# module ExceptionForMatrix::
# Exceptions:
@@ -36,7 +39,7 @@
# creates a matrix where `rows' indicates rows.
# `rows' is an array of arrays,
# e.g, Matrix[[11, 12], [21, 22]]
-# Matrix.rows(rows, copy = TRUE)
+# Matrix.rows(rows, copy = true)
# creates a matrix where `rows' indicates rows.
# if optional argument `copy' is false, use the array as
# internal structure of the metrix without copying.
@@ -142,7 +145,7 @@
#
# INSTANCE CREATION:
# Vector.[](*array)
-# Vector.elements(array, copy = TRUE)
+# Vector.elements(array, copy = true)
# ACCSESSING:
# [](i)
# size
@@ -173,29 +176,29 @@
require "e2mmap.rb"
module ExceptionForMatrix
- Exception2MessageMapper.extend_to(binding)
-
+ extend Exception2MessageMapper
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("ErrDimensionMismatch", "\#{self.name} dimension mismatch")
def_exception("ErrNotRegular", "Not Regular Matrix")
def_exception("ErrOperationNotDefined", "This operation(%s) can\\'t defined")
end
class Matrix
- @RCS_ID='-$Id: matrix.rb,v 1.6 1998/07/31 03:39:49 keiju Exp keiju $-'
-
+ @RCS_ID='-$Id: matrix.rb,v 1.8 1999/02/17 12:34:19 keiju Exp keiju $-'
+
+# extend Exception2MessageMapper
include ExceptionForMatrix
# instance creations
private_class_method :new
def Matrix.[](*rows)
- new(:init_rows, rows, FALSE)
+ new(:init_rows, rows, false)
end
- def Matrix.rows(rows, copy = TRUE)
+ def Matrix.rows(rows, copy = true)
new(:init_rows, rows, copy)
end
@@ -207,7 +210,7 @@ class Matrix
columns[j][i]
}
}
- Matrix.rows(rows, FALSE)
+ Matrix.rows(rows, false)
end
def Matrix.diagonal(*values)
@@ -218,8 +221,7 @@ class Matrix
row[j] = values[j]
row
}
- self
- rows(rows, FALSE)
+ rows(rows, false)
end
def Matrix.scalar(n, value)
@@ -241,11 +243,11 @@ class Matrix
def Matrix.row_vector(row)
case row
when Vector
- Matrix.rows([row.to_a], FALSE)
+ Matrix.rows([row.to_a], false)
when Array
- Matrix.rows([row.dup], FALSE)
+ Matrix.rows([row.dup], false)
else
- Matrix.row([[row]], FALSE)
+ Matrix.row([[row]], false)
end
end
@@ -310,13 +312,13 @@ class Matrix
|i|
@rows[i][j]
}
- Vector.elements(col, FALSE)
+ Vector.elements(col, false)
end
end
def collect
rows = @rows.collect{|row| row.collect{|e| yield e}}
- Matrix.rows(rows, FALSE)
+ Matrix.rows(rows, false)
end
alias map collect
@@ -337,14 +339,14 @@ class Matrix
from_col = param[2]
size_col = param[3]
else
- Matrix.fail ArgumentError, param.inspect
+ Matrix.Raise ArgumentError, param.inspect
end
rows = @rows[from_row, size_row].collect{
|row|
row[from_col, size_col]
}
- Matrix.rows(rows, FALSE)
+ Matrix.rows(rows, false)
end
# TESTING
@@ -362,20 +364,20 @@ class Matrix
# COMPARING
def ==(other)
- return FALSE unless Matrix === other
+ return false unless Matrix === other
other.compare_by_row_vectors(@rows)
end
alias eql? ==
def compare_by_row_vectors(rows)
- return FALSE unless @rows.size == rows.size
+ return false unless @rows.size == rows.size
0.upto(@rows.size - 1) do
|i|
- return FALSE unless @rows[i] == rows[i]
+ return false unless @rows[i] == rows[i]
end
- TRUE
+ true
end
def clone
@@ -404,13 +406,13 @@ class Matrix
e * m
}
}
- return Matrix.rows(rows, FALSE)
+ 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
+ Matrix.Raise ErrDimensionMismatch if column_size != m.row_size
rows = (0 .. row_size - 1).collect {
|i|
@@ -424,7 +426,7 @@ class Matrix
vij
}
}
- return Matrix.rows(rows, FALSE)
+ return Matrix.rows(rows, false)
else
x, y = m.coerce(self)
return x * y
@@ -434,7 +436,7 @@ class Matrix
def +(m)
case m
when Numeric
- Matrix.fail ErrOperationNotDefined, "+"
+ Matrix.Raise ErrOperationNotDefined, "+"
when Vector
m = Matrix.column_vector(m)
when Matrix
@@ -443,7 +445,7 @@ class Matrix
return x + y
end
- Matrix.fail ErrDimensionMismatch unless row_size == m.row_size and column_size == m.column_size
+ Matrix.Raise ErrDimensionMismatch unless row_size == m.row_size and column_size == m.column_size
rows = (0 .. row_size - 1).collect {
|i|
@@ -452,13 +454,13 @@ class Matrix
self[i, j] + m[i, j]
}
}
- Matrix.rows(rows, FALSE)
+ Matrix.rows(rows, false)
end
def -(m)
case m
when Numeric
- Matrix.fail ErrOperationNotDefined, "-"
+ Matrix.Raise ErrOperationNotDefined, "-"
when Vector
m = Matrix.column_vector(m)
when Matrix
@@ -467,7 +469,7 @@ class Matrix
return x - y
end
- Matrix.fail ErrDimensionMismatch unless row_size == m.row_size and column_size == m.column_size
+ Matrix.Raise ErrDimensionMismatch unless row_size == m.row_size and column_size == m.column_size
rows = (0 .. row_size - 1).collect {
|i|
@@ -476,7 +478,7 @@ class Matrix
self[i, j] - m[i, j]
}
}
- Matrix.rows(rows, FALSE)
+ Matrix.rows(rows, false)
end
def /(other)
@@ -489,7 +491,7 @@ class Matrix
e / other
}
}
- return Matrix.rows(rows, FALSE)
+ return Matrix.rows(rows, false)
when Matrix
return self * other.inverse
else
@@ -499,7 +501,7 @@ class Matrix
end
def inverse
- Matrix.fail ErrDimensionMismatch unless square?
+ Matrix.Raise ErrDimensionMismatch unless square?
Matrix.I(row_size).inverse_from(self)
end
alias inv inverse
@@ -512,7 +514,7 @@ class Matrix
if (akk = a[k][k]) == 0
i = k
begin
- fail ErrNotRegular if (i += 1) > size
+ Matrix.Raise 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]
@@ -568,9 +570,9 @@ class Matrix
end
z
elsif other.kind_of?(Float) || defined?(Rational) && other.kind_of?(Rational)
- fail ErrOperationNotDefined, "**"
+ Matrix.Raise ErrOperationNotDefined, "**"
else
- fail ErrOperationNotDefined, "**"
+ Matrix.Raise ErrOperationNotDefined, "**"
end
end
@@ -618,10 +620,10 @@ class Matrix
begin
if (akk = a[k][k]) == 0
i = -1
- nothing = FALSE
+ nothing = false
begin
if (i += 1) > column_size - 1
- nothing = TRUE
+ nothing = true
break
end
end while a[i][k] == 0
@@ -663,6 +665,8 @@ class Matrix
case other
when Numeric
return Scalar.new(other), self
+ else
+ raise TypeError, "#{type} can't be coerced into #{other.type}"
end
end
@@ -725,7 +729,7 @@ class Matrix
when Numeric
Scalar.new(@value + other)
when Vector, Matrix
- Scalar.fail WrongArgType, other.type, "Numeric or Scalar"
+ Scalar.Raise WrongArgType, other.type, "Numeric or Scalar"
when Scalar
Scalar.new(@value + other.value)
else
@@ -739,7 +743,7 @@ class Matrix
when Numeric
Scalar.new(@value - other)
when Vector, Matrix
- Scalar.fail WrongArgType, other.type, "Numeric or Scalar"
+ Scalar.Raise WrongArgType, other.type, "Numeric or Scalar"
when Scalar
Scalar.new(@value - other.value)
else
@@ -765,7 +769,7 @@ class Matrix
when Numeric
Scalar.new(@value / other)
when Vector
- Scalar.fail WrongArgType, other.type, "Numeric or Scalar or Matrix"
+ Scalar.Raise WrongArgType, other.type, "Numeric or Scalar or Matrix"
when Matrix
self * _M.inverse
else
@@ -779,7 +783,7 @@ class Matrix
when Numeric
Scalar.new(@value ** other)
when Vector
- Scalar.fail WrongArgType, other.type, "Numeric or Scalar or Matrix"
+ Scalar.Raise WrongArgType, other.type, "Numeric or Scalar or Matrix"
when Matrix
other.powered_by(self)
else
@@ -802,10 +806,10 @@ class Vector
private_class_method :new
def Vector.[](*array)
- new(:init_elements, array, FALSE)
+ new(:init_elements, array, copy = false)
end
- def Vector.elements(array, copy = TRUE)
+ def Vector.elements(array, copy = true)
new(:init_elements, array, copy)
end
@@ -833,7 +837,7 @@ class Vector
# ENUMRATIONS
def each2(v)
- Vector.fail ErrDimensionMismatch if size != v.size
+ Vector.Raise ErrDimensionMismatch if size != v.size
0.upto(size - 1) do
|i|
yield @elements[i], v[i]
@@ -841,7 +845,7 @@ class Vector
end
def collect2(v)
- Vector.fail ErrDimensionMismatch if size != v.size
+ Vector.Raise ErrDimensionMismatch if size != v.size
(0 .. size - 1).collect do
|i|
yield @elements[i], v[i]
@@ -850,7 +854,7 @@ class Vector
# COMPARING
def ==(other)
- return FALSE unless Vector === other
+ return false unless Vector === other
other.compare_by(@elements)
end
@@ -870,15 +874,15 @@ class Vector
# ARITHMETIC
- def *(x) "is matrix or number"
+ def *(x) # is matrix or number
case x
when Numeric
els = @elements.collect{|e| e * x}
- Vector.elements(els, FALSE)
+ Vector.elements(els, false)
when Matrix
self.covector * x
else
- s, x = X.corece(self)
+ s, x = X.coerce(self)
s * x
end
end
@@ -886,16 +890,16 @@ class Vector
def +(v)
case v
when Vector
- Vector.fail ErrDimensionMismatch if size != v.size
+ Vector.Raise ErrDimensionMismatch if size != v.size
els = collect2(v) {
|v1, v2|
v1 + v2
}
- Vector.elements(els, FALSE)
+ Vector.elements(els, false)
when Matrix
Matrix.column_vector(self) + v
else
- s, x = v.corece(self)
+ s, x = v.coerce(self)
s + x
end
end
@@ -903,16 +907,16 @@ class Vector
def -(v)
case v
when Vector
- Vector.fail ErrDimensionMismatch if size != v.size
+ Vector.Raise ErrDimensionMismatch if size != v.size
els = collect2(v) {
|v1, v2|
v1 - v2
}
- Vector.elements(els, FALSE)
+ Vector.elements(els, false)
when Matrix
Matrix.column_vector(self) - v
else
- s, x = v.corece(self)
+ s, x = v.coerce(self)
s - x
end
end
@@ -920,7 +924,7 @@ class Vector
# VECTOR FUNCTIONS
def inner_product(v)
- Vector.fail ErrDimensionMismatch if size != v.size
+ Vector.Raise ErrDimensionMismatch if size != v.size
p = 0
each2(v) {
@@ -935,7 +939,7 @@ class Vector
|v|
yield v
}
- Vector.elements(els, FALSE)
+ Vector.elements(els, false)
end
alias map collect
@@ -944,7 +948,7 @@ class Vector
|v1, v2|
yield v1, v2
}
- Vector.elements(els, FALSE)
+ Vector.elements(els, false)
end
def r
@@ -980,6 +984,8 @@ class Vector
case other
when Numeric
return Scalar.new(other), self
+ else
+ raise TypeError, "#{type} can't be coerced into #{other.type}"
end
end
diff --git a/lib/mkmf.rb b/lib/mkmf.rb
index 7e131fe..50920a0 100644
--- a/lib/mkmf.rb
+++ b/lib/mkmf.rb
@@ -6,7 +6,9 @@ require 'find'
include Config
-$found = false;
+SRC_EXT = ["c", "cc", "m", "cxx", "cpp", "C"]
+
+$cache_mod = false
$lib_cache = {}
$lib_found = {}
$func_cache = {}
@@ -31,14 +33,8 @@ if File.exist?($config_cache) then
end
$srcdir = CONFIG["srcdir"]
-$libdir = CONFIG["libdir"]+"/"+CONFIG["ruby_install_name"]
+$libdir = CONFIG["libdir"]+"/ruby/"+CONFIG["MAJOR"]+"."+CONFIG["MINOR"]
$archdir = $libdir+"/"+CONFIG["arch"]
-$install = CONFIG["INSTALL_PROGRAM"]
-$install_data = CONFIG["INSTALL_DATA"]
-if $install !~ /^\// then
- $install = CONFIG["srcdir"]+"/"+$install
- $install_data = CONFIG["srcdir"]+"/"+$install_data
-end
if File.exist? $archdir + "/ruby.h"
$hdrdir = $archdir
@@ -48,18 +44,22 @@ else
STDERR.print "can't find header files for ruby.\n"
exit 1
end
+$topdir = $hdrdir
+$hdrdir.gsub!('/', '\\') if RUBY_PLATFORM =~ /mswin32/
CFLAGS = CONFIG["CFLAGS"]
-if PLATFORM == "m68k-human"
+if RUBY_PLATFORM == "m68k-human"
CFLAGS.gsub!(/-c..-stack=[0-9]+ */, '')
+elsif RUBY_PLATFORM =~ /-nextstep|-rhapsody/
+ CFLAGS.gsub!( /-arch\s\w*/, '' )
end
-if /win32|djgpp|mingw32|m68k-human/i =~ PLATFORM
+if /win32|djgpp|mingw32|m68k-human|i386-os2_emx/i =~ RUBY_PLATFORM
$null = open("nul", "w")
else
$null = open("/dev/null", "w")
end
-LINK = "#{CONFIG['CC']} -o conftest -I#{$srcdir} -I#{CONFIG['includedir']} #{CFLAGS} %s #{CONFIG['LDFLAGS']} %s conftest.c #{CONFIG['LIBS']} %s"
-CPP = "#{CONFIG['CPP']} -E -I#{$srcdir} -I#{CONFIG['includedir']} #{CFLAGS} %s conftest.c"
+LINK = "#{CONFIG['CC']} -o conftest -I#{$hdrdir} #{CFLAGS} -I#{CONFIG['includedir']} %s #{CONFIG['LDFLAGS']} %s conftest.c %s %s #{CONFIG['LIBS']}"
+CPP = "#{CONFIG['CPP']} -E -I#{$hdrdir} #{CFLAGS} -I#{CONFIG['includedir']} %s %s conftest.c"
$orgerr = $stderr.dup
$orgout = $stdout.dup
@@ -76,29 +76,84 @@ def xsystem command
return r
end
-def try_link(libs)
- xsystem(format(LINK, $CFLAGS, $LDFLAGS, libs))
+def try_link0(src, opt="")
+ cfile = open("conftest.c", "w")
+ cfile.print src
+ cfile.close
+ xsystem(format(LINK, $CFLAGS, $LDFLAGS, opt, $LOCAL_LIBS))
end
-def try_cpp
- xsystem(format(CPP, $CFLAGS))
+def try_link(src, opt="")
+ begin
+ try_link0(src, opt)
+ ensure
+ system "rm -f conftest*"
+ end
end
-def install_rb(mfile)
+def try_cpp(src, opt="")
+ cfile = open("conftest.c", "w")
+ cfile.print src
+ cfile.close
+ begin
+ xsystem(format(CPP, $CFLAGS, opt))
+ ensure
+ system "rm -f conftest*"
+ end
+end
+
+def egrep_cpp(pat, src, opt="")
+ cfile = open("conftest.c", "w")
+ cfile.print src
+ cfile.close
+ begin
+ xsystem(format(CPP+"|egrep #{pat}", $CFLAGS, opt))
+ ensure
+ system "rm -f conftest*"
+ end
+end
+
+def try_run(src, opt="")
+ begin
+ if try_link0(src, opt)
+ if xsystem("./conftest")
+ true
+ else
+ false
+ end
+ else
+ nil
+ end
+ ensure
+ system "rm -f conftest*"
+ end
+end
+
+def install_rb(mfile, srcdir = nil)
+ libdir = "lib"
+ libdir = srcdir + "/" + libdir if srcdir
path = []
dir = []
- Find.find("lib") do |f|
+ Find.find(libdir) do |f|
next unless /\.rb$/ =~ f
- f = f[4..-1]
+ f = f[libdir.length+1..-1]
path.push f
dir |= File.dirname(f)
end
for f in dir
next if f == "."
- mfile.printf "\t@test -d $(libdir)/%s || mkdir $(libdir)/%s\n", f, f
+ mfile.printf "\t@$(RUBY) -r ftools -e 'File::makedirs(*ARGV)' $(libdir)/%s\n", f
end
for f in path
- mfile.printf "\t$(INSTALL_DATA) lib/%s $(libdir)/%s\n", f, f
+ mfile.printf "\t@$(RUBY) -r ftools -e 'File::install(ARGV[0], ARGV[1], 0644, true)' lib/%s $(libdir)/%s\n", f, f
+ end
+end
+
+def append_library(libs, lib)
+ if /mswin32/ =~ RUBY_PLATFORM
+ lib + ".lib " + libs
+ else
+ "-l" + lib + " " + libs
end
end
@@ -107,55 +162,75 @@ def have_library(lib, func="main")
STDOUT.flush
if $lib_cache[lib]
if $lib_cache[lib] == "yes"
- if $libs
- $libs = "-l" + lib + " " + $libs
- else
- $libs = "-l" + lib
- end
+ $libs = append_library($libs, lib)
print "(cached) yes\n"
- return TRUE
+ return true
else
print "(cached) no\n"
- return FALSE
+ return false
end
end
if func && func != ""
- cfile = open("conftest.c", "w")
- cfile.printf "\
+ libs = append_library($libs, lib)
+ if /mswin32/ =~ RUBY_PLATFORM
+ r = try_link(<<"SRC", libs)
+#include <windows.h>
+#include <winsock.h>
int main() { return 0; }
-int t() { %s(); return 0; }
-", func
- cfile.close
-
- begin
- if $libs
- libs = "-l" + lib + " " + $libs
- else
- libs = "-l" + lib
- end
- unless try_link(libs)
- $lib_cache[lib] = 'no'
- $cache_mod = TRUE
- print "no\n"
- return FALSE
+int t() { #{func}(); return 0; }
+SRC
+ unless r
+ r = try_link(<<"SRC", libs)
+#include <windows.h>
+#include <winsock.h>
+int main() { return 0; }
+int t() { void ((*p)()); p = (void ((*)()))#{func}; return 0; }
+SRC
end
- ensure
- system "rm -f conftest*"
- end
- else
- if $libs
- libs = "-l" + lib + " " + $libs
else
- libs = "-l" + lib
+ r = try_link(<<"SRC", libs)
+int main() { return 0; }
+int t() { #{func}(); return 0; }
+SRC
+ end
+ unless r
+ $lib_cache[lib] = 'no'
+ $cache_mod = true
+ print "no\n"
+ return false
end
+ else
+ libs = append_library($libs, lib)
end
$libs = libs
$lib_cache[lib] = 'yes'
- $cache_mod = TRUE
+ $cache_mod = true
+ print "yes\n"
+ return true
+end
+
+def find_library(lib, func, *paths)
+ printf "checking for %s() in -l%s... ", func, lib
+ STDOUT.flush
+
+ ldflags = $LDFLAGS
+ libs = append_library($libs, lib)
+ until try_link(<<"SRC", libs)
+int main() { return 0; }
+int t() { #{func}(); return 0; }
+SRC
+ if paths.size == 0
+ $LDFLAGS = ldflags
+ print "no\n"
+ return false
+ end
+ $LDFLAGS = ldflags + " -L"+paths.shift
+ end
+ $libs = libs
print "yes\n"
- return TRUE
+ return true
end
def have_func(func)
@@ -165,39 +240,47 @@ def have_func(func)
if $func_cache[func] == "yes"
$defs.push(format("-DHAVE_%s", func.upcase))
print "(cached) yes\n"
- return TRUE
+ return true
else
print "(cached) no\n"
- return FALSE
+ return false
end
end
- cfile = open("conftest.c", "w")
- cfile.printf "\
-char %s();
-int main() { return 0; }
-int t() { %s(); return 0; }
-", func, func
- cfile.close
-
libs = $libs
- libs = "" if libs == nil
- begin
- unless try_link(libs)
- $func_found[func] = 'no'
- $found = TRUE
- print "no\n"
- return FALSE
+ if /mswin32/ =~ RUBY_PLATFORM
+ r = try_link(<<"SRC", libs)
+#include <windows.h>
+#include <winsock.h>
+int main() { return 0; }
+int t() { #{func}(); return 0; }
+SRC
+ unless r
+ r = try_link(<<"SRC", libs)
+#include <windows.h>
+#include <winsock.h>
+int main() { return 0; }
+int t() { void ((*p)()); p = (void ((*)()))#{func}; return 0; }
+SRC
end
- ensure
- system "rm -f conftest*"
+ else
+ r = try_link(<<"SRC", libs)
+int main() { return 0; }
+int t() { #{func}(); return 0; }
+SRC
+ end
+ unless r
+ $func_found[func] = 'no'
+ $cache_mod = true
+ print "no\n"
+ return false
end
$defs.push(format("-DHAVE_%s", func.upcase))
$func_found[func] = 'yes'
- $found = TRUE
+ $cache_mod = true
print "yes\n"
- return TRUE
+ return true
end
def have_header(header)
@@ -208,35 +291,59 @@ def have_header(header)
header.tr!("a-z./\055", "A-Z___")
$defs.push(format("-DHAVE_%s", header))
print "(cached) yes\n"
- return TRUE
+ return true
else
print "(cached) no\n"
- return FALSE
+ return false
end
end
- cfile = open("conftest.c", "w")
- cfile.printf "\
-#include <%s>
-", header
- cfile.close
-
- begin
- unless try_cpp
- $hdr_found[header] = 'no'
- $found = TRUE
- print "no\n"
- return FALSE
- end
- ensure
- system "rm -f conftest*"
+ unless try_cpp(<<"SRC")
+#include <#{header}>
+SRC
+ $hdr_found[header] = 'no'
+ $cache_mod = true
+ print "no\n"
+ return false
end
$hdr_found[header] = 'yes'
header.tr!("a-z./\055", "A-Z___")
$defs.push(format("-DHAVE_%s", header))
- $found = TRUE
+ $cache_mod = true
print "yes\n"
- return TRUE
+ return true
+end
+
+def arg_config(config, default=nil)
+ unless defined? $configure_args
+ $configure_args = {}
+ for arg in CONFIG["configure_args"].split + ARGV
+ next unless /^--/ =~ arg
+ if /=/ =~ arg
+ $configure_args[$`] = $'
+ else
+ $configure_args[arg] = true
+ end
+ end
+ end
+ $configure_args.fetch(config, default)
+end
+
+def with_config(config, default=nil)
+ unless /^--with-/ =~ config
+ config = '--with-' + config
+ end
+ arg_config(config, default)
+end
+
+def enable_config(config, default=nil)
+ if arg_config("--enable-"+config, default)
+ true
+ elsif arg_config("--disable-"+config, false)
+ false
+ else
+ default
+ end
end
def create_header()
@@ -252,28 +359,58 @@ def create_header()
end
end
+def dir_config(target)
+ dir = with_config("%s-dir"%target)
+ if dir
+ idir = " -I"+dir+"/include"
+ ldir = " -L"+dir+"/lib"
+ end
+ unless idir
+ dir = with_config("%s-include"%target)
+ idir = " -I"+dir if dir
+ end
+ unless ldir
+ dir = with_config("%s-lib"%target)
+ ldir = " -L"+dir if dir
+ end
+
+ $CFLAGS += idir if idir
+ $LDFLAGS += ldir if ldir
+end
+
def create_makefile(target)
print "creating Makefile\n"
+ system "rm -f conftest*"
STDOUT.flush
- if $libs and CONFIG["DLEXT"] == "o"
+ if CONFIG["DLEXT"] == $OBJEXT
libs = $libs.split
for lib in libs
lib.sub!(/-l(.*)/, '"lib\1.a"')
end
$defs.push(format("-DEXTLIB='%s'", libs.join(",")))
end
- $libs = "" unless $libs
$DLDFLAGS = CONFIG["DLDFLAGS"]
- if PLATFORM =~ /beos/
+ if RUBY_PLATFORM =~ /beos/
$libs = $libs + " -lruby"
$DLDFLAGS = $DLDFLAGS + " -L" + CONFIG["prefix"] + "/lib"
end
+ defflag = ''
+ if RUBY_PLATFORM =~ /cygwin/
+ if File.exist? target + ".def"
+ defflag = "--def=" + target + ".def"
+ end
+ $libs = $libs + " " + CONFIG["LIBRUBYARG"]
+ $DLDFLAGS = $DLDFLAGS + " -L$(topdir)"
+ end
+
unless $objs then
- $objs = Dir["*.{c,cc}"]
- for f in $objs
- f.sub!(/\.(c|cc)$/, ".o")
+ $objs = []
+ for f in Dir["*.{#{SRC_EXT.join(%q{,})}}"]
+ f = File.basename(f)
+ f.sub!(/(#{SRC_EXT.join(%q{|})})$/, $OBJEXT)
+ $objs.push f
end
end
$objs = $objs.join(" ")
@@ -285,15 +422,15 @@ SHELL = /bin/sh
#### Start of system configuration section. ####
srcdir = #{$srcdir}
+topdir = #{$topdir}
hdrdir = #{$hdrdir}
CC = #{CONFIG["CC"]}
-prefix = #{CONFIG["prefix"]}
-CFLAGS = #{CONFIG["CCDLFLAGS"]} -I$(hdrdir) -I#{CONFIG["includedir"]} #{CFLAGS} #{$CFLAGS} #{$defs.join(" ")}
+CFLAGS = #{CONFIG["CCDLFLAGS"]} -I$(hdrdir) #{CFLAGS} #{$CFLAGS} -I#{CONFIG["includedir"]} #{$defs.join(" ")}
CXXFLAGS = $(CFLAGS)
DLDFLAGS = #{$DLDFLAGS} #{$LDFLAGS}
-LDSHARED = #{CONFIG["LDSHARED"]}
+LDSHARED = #{CONFIG["LDSHARED"]} #{defflag}
prefix = #{CONFIG["prefix"]}
exec_prefix = #{CONFIG["exec_prefix"]}
@@ -302,49 +439,47 @@ archdir = #{$archdir}
#### End of system configuration section. ####
-LOCAL_LIBS = #{$local_libs}
+LOCAL_LIBS = #{$LOCAL_LIBS} #{$local_flags}
LIBS = #{$libs}
OBJS = #{$objs}
-TARGET = #{target}.#{CONFIG["DLEXT"]}
+TARGET = #{target}
+DLLIB = $(TARGET).#{CONFIG["DLEXT"]}
-INSTALL = #{$install}
-INSTALL_DATA = #{$install_data}
+RUBY = #{CONFIG["ruby_install_name"]}
-binsuffix = #{CONFIG["binsuffix"]}
+EXEEXT = #{CONFIG["EXEEXT"]}
-all: $(TARGET)
+all: $(DLLIB)
-clean:; @rm -f *.o *.so *.sl
+clean:; @rm -f *.#{$OBJEXT} *.so *.sl *.a $(DLLIB)
+ @rm -f $(TARGET).lib $(TARGET).exp
@rm -f Makefile extconf.h conftest.*
- @rm -f core ruby$(binsuffix) *~
+ @rm -f core ruby$(EXEEXT) *~
realclean: clean
-install: $(archdir)/$(TARGET)
+install: $(archdir)/$(DLLIB)
-$(archdir)/$(TARGET): $(TARGET)
- @test -d $(libdir) || mkdir $(libdir)
- @test -d $(archdir) || mkdir $(archdir)
- $(INSTALL) $(TARGET) $(archdir)/$(TARGET)
+$(archdir)/$(DLLIB): $(DLLIB)
+ @$(RUBY) -r ftools -e 'File::makedirs(*ARGV)' $(libdir) $(archdir)
+ @$(RUBY) -r ftools -e 'File::install(ARGV[0], ARGV[1], 0555, true)' $(DLLIB) $(archdir)/$(DLLIB)
EOMF
install_rb(mfile)
mfile.printf "\n"
- if CONFIG["DLEXT"] != "o"
+ if CONFIG["DLEXT"] != $OBJEXT
mfile.printf <<EOMF
-$(TARGET): $(OBJS)
- $(LDSHARED) $(DLDFLAGS) -o $(TARGET) $(OBJS) $(LIBS) $(LOCAL_LIBS)
+$(DLLIB): $(OBJS)
+ $(LDSHARED) $(DLDFLAGS) -o $(DLLIB) $(OBJS) $(LIBS) $(LOCAL_LIBS)
EOMF
- elsif not File.exist?(target + ".c") and not File.exist?(target + ".cc") or
- mfile.print "$(TARGET): $(OBJS)\n"
- case PLATFORM
+ elsif not File.exist?(target + ".c") and not File.exist?(target + ".cc")
+ mfile.print "$(DLLIB): $(OBJS)\n"
+ case RUBY_PLATFORM
when "m68k-human"
- mfile.printf "ar cru $(TARGET) $(OBJS)\n"
- when /-nextstep/
- mfile.printf "cc -r $(CFLAGS) -o $(TARGET) $(OBJS)\n"
+ mfile.printf "ar cru $(DLLIB) $(OBJS)\n"
else
- mfile.printf "ld $(DLDFLAGS) -r -o $(TARGET) $(OBJS)\n"
+ mfile.printf "ld $(DLDFLAGS) -r -o $(DLLIB) $(OBJS)\n"
end
end
@@ -352,13 +487,13 @@ EOMF
dfile = open("depend", "r")
mfile.printf "###\n"
while line = dfile.gets()
- mfile.print line
+ mfile.printf "%s", line.gsub(/\.o/, ".#{$OBJEXT}")
end
dfile.close
end
mfile.close
- if $found
+ if $cache_mod
begin
f = open($config_cache, "w")
for k,v in $lib_cache
@@ -384,18 +519,47 @@ EOMF
end
end
- if PLATFORM =~ /beos/
- print "creating ruby.def\n"
- open("ruby.def", "w") do |file|
- file.print("EXPORTS\n") if PLATFORM =~ /^i/
+ if RUBY_PLATFORM =~ /beos/
+ if RUBY_PLATFORM =~ /^powerpc/ then
+ deffilename = "ruby.exp"
+ else
+ deffilename = "ruby.def"
+ end
+ print "creating #{deffilename}\n"
+ open(deffilename, "w") do |file|
+ file.print("EXPORTS\n") if RUBY_PLATFORM =~ /^i/
file.print("Init_#{target}\n")
end
end
end
-$libs = PLATFORM =~ /cygwin32|beos/ ? nil : "-lc"
+$OBJEXT = CONFIG["OBJEXT"]
$objs = nil
-$local_libs = ""
-$CFLAGS = ""
-$LDFLAGS = ""
+$libs = "-lc"
+$local_flags = ""
+case RUBY_PLATFORM
+when /cygwin|beos|openstep|nextstep|rhapsody/
+ $libs = ""
+when /mswin32/
+ $libs = ""
+ $local_flags = "rubymw.lib -link /LIBPATH:$(topdir) /EXPORT:Init_$(TARGET)"
+end
+$LOCAL_LIBS = ""
$defs = []
+
+dir = with_config("opt-dir")
+if dir
+ idir = "-I"+dir+"/include"
+ ldir = "-L"+dir+"/lib"
+end
+unless idir
+ dir = with_config("opt-include")
+ idir = "-I"+dir if dir
+end
+unless ldir
+ dir = with_config("opt-lib")
+ ldir = "-L"+dir if dir
+end
+
+$CFLAGS = idir || ""
+$LDFLAGS = ldir || ""
diff --git a/lib/monitor.rb b/lib/monitor.rb
new file mode 100644
index 0000000..75d9c35
--- /dev/null
+++ b/lib/monitor.rb
@@ -0,0 +1,229 @@
+=begin
+
+monitor.rb
+Author: Shugo Maeda <shugo@netlab.co.jp>
+Version: 1.2.1
+
+USAGE:
+
+ foo = Foo.new
+ foo.extend(MonitorMixin)
+ cond = foo.new_cond
+
+ thread1:
+ foo.synchronize {
+ ...
+ cond.wait_until { foo.done? }
+ ...
+ }
+
+ thread2:
+ foo.synchronize {
+ foo.do_something
+ cond.signal
+ }
+
+=end
+
+module MonitorMixin
+ module Accessible
+ protected
+ attr_accessor :mon_owner, :mon_count
+ attr_reader :mon_entering_queue, :mon_waiting_queue
+ end
+
+ module Initializable
+ protected
+ def mon_initialize
+ @mon_owner = nil
+ @mon_count = 0
+ @mon_entering_queue = []
+ @mon_waiting_queue = []
+ end
+ end
+
+ class ConditionVariable
+ class Timeout < Exception; end
+
+ include Accessible
+
+ def wait(timeout = nil)
+ if @monitor.mon_owner != Thread.current
+ raise ThreadError, "current thread not owner"
+ end
+
+ Thread.critical = true
+ count = @monitor.mon_count
+ @monitor.mon_count = 0
+ @monitor.mon_owner = nil
+ if @monitor.mon_waiting_queue.empty?
+ t = @monitor.mon_entering_queue.shift
+ else
+ t = @monitor.mon_waiting_queue.shift
+ end
+ t.wakeup if t
+ @waiters.push(Thread.current)
+
+ if timeout
+ t = Thread.current
+ timeout_thread = Thread.start {
+ sleep(timeout)
+ t.raise(Timeout.new)
+ }
+ end
+ begin
+ Thread.stop
+ rescue Timeout
+ @waiters.delete(Thread.current)
+ ensure
+ if timeout && timeout_thread.alive?
+ Thread.kill(timeout_thread)
+ end
+ end
+
+ Thread.critical = true
+ while @monitor.mon_owner &&
+ @monitor.mon_owner != Thread.current
+ @monitor.mon_waiting_queue.push(Thread.current)
+ Thread.stop
+ Thread.critical = true
+ end
+ @monitor.mon_owner = Thread.current
+ @monitor.mon_count = count
+ Thread.critical = false
+ end
+
+ def wait_while
+ while yield
+ wait
+ end
+ end
+
+ def wait_until
+ until yield
+ wait
+ end
+ end
+
+ def signal
+ if @monitor.mon_owner != Thread.current
+ raise ThreadError, "current thread not owner"
+ end
+ Thread.critical = true
+ t = @waiters.shift
+ t.wakeup if t
+ Thread.critical = false
+ Thread.pass
+ end
+
+ def broadcast
+ if @monitor.mon_owner != Thread.current
+ raise ThreadError, "current thread not owner"
+ end
+ Thread.critical = true
+ for t in @waiters
+ t.wakeup
+ end
+ @waiters.clear
+ Thread.critical = false
+ Thread.pass
+ end
+
+ def count_waiters
+ return @waiters.length
+ end
+
+ private
+ def initialize(monitor)
+ @monitor = monitor
+ @waiters = []
+ end
+ end
+
+ include Accessible
+ include Initializable
+ extend Initializable
+
+ def self.extend_object(obj)
+ super(obj)
+ obj.mon_initialize
+ end
+
+ def try_mon_enter
+ result = false
+ Thread.critical = true
+ if mon_owner.nil?
+ self.mon_owner = Thread.current
+ end
+ if mon_owner == Thread.current
+ self.mon_count += 1
+ result = true
+ end
+ Thread.critical = false
+ return result
+ end
+
+ def mon_enter
+ Thread.critical = true
+ while mon_owner != nil && mon_owner != Thread.current
+ mon_entering_queue.push(Thread.current)
+ Thread.stop
+ Thread.critical = true
+ end
+ self.mon_owner = Thread.current
+ self.mon_count += 1
+ Thread.critical = false
+ end
+
+ def mon_exit
+ if mon_owner != Thread.current
+ raise ThreadError, "current thread not owner"
+ end
+ Thread.critical = true
+ self.mon_count -= 1
+ if mon_count == 0
+ self.mon_owner = nil
+ if mon_waiting_queue.empty?
+ t = mon_entering_queue.shift
+ else
+ t = mon_waiting_queue.shift
+ end
+ end
+ t.wakeup if t
+ Thread.critical = false
+ Thread.pass
+ end
+
+ def mon_synchronize
+ mon_enter
+ begin
+ yield
+ ensure
+ mon_exit
+ end
+ end
+ alias synchronize mon_synchronize
+
+ def new_cond
+ return ConditionVariable.new(self)
+ end
+
+private
+ def initialize(*args)
+ super
+ mon_initialize
+ end
+end
+
+class Monitor
+ include MonitorMixin
+ alias try_enter try_mon_enter
+ alias enter mon_enter
+ alias exit mon_exit
+ alias owner mon_owner
+end
+
+# Local variables:
+# mode: Ruby
+# tab-width: 8
+# End:
diff --git a/lib/mutex_m.rb b/lib/mutex_m.rb
index 4b8d644..e0fcf0f 100644
--- a/lib/mutex_m.rb
+++ b/lib/mutex_m.rb
@@ -12,54 +12,27 @@
# obj = Object.new
# obj.extend Mutex_m
# ...
-# 後はMutexと同じ使い方
+# extended object can be handled like Mutex
#
-require "finalize"
-
module Mutex_m
- def Mutex_m.extendable_module(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
- obj.instance_eval "@mu_locked"
- For_general_object
- rescue TypeError
- For_primitive_object
- end
+ def Mutex_m.append_features(cl)
+ super
+ unless cl.instance_of?(Module)
+ cl.module_eval %q{
+ alias locked? mu_locked?
+ alias lock mu_lock
+ alias unlock mu_unlock
+ alias try_lock mu_try_lock
+ alias synchronize mu_synchronize
+ }
end
- end
-
- def Mutex_m.includable_module(cl)
- begin
- dummy = cl.new
- Mutex_m.extendable_module(dummy)
- rescue NameError
- # newが定義されていない時は, DATAとみなす.
- For_primitive_object
- end
- end
-
- def Mutex_m.extend_class(cl)
- return super if cl.instance_of?(Module)
-
- # モジュールの時は何もしない. クラスの場合, 適切なモジュールの決定
- # とaliasを行う.
- real = includable_module(cl)
- cl.module_eval %q{
- include real
-
- alias locked? mu_locked?
- alias lock mu_lock
- alias unlock mu_unlock
- alias try_lock mu_try_lock
- alias synchronize mu_synchronize
- }
+ return self
end
def Mutex_m.extend_object(obj)
- obj.extend(Mutex_m.extendable_module(obj))
+ super
+ obj.mu_extended
end
def mu_extended
@@ -76,6 +49,7 @@ module Mutex_m
alias synchronize mu_synchronize
end"
end
+ initialize
end
# locking
@@ -88,132 +62,50 @@ module Mutex_m
end
end
- # internal class
- 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
-
+ def mu_locked?
+ @mu_locked
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 mu_extended
- super
- initialize
- 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.add(self, For_primitive_object, :mu_finalize)
- 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_finalize)
- 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
+
+ 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
+
+ private
+
+ def initialize(*args)
+ ret = super
+ @mu_waiting = []
+ @mu_locked = false;
+ return ret
end
end
-
diff --git a/lib/observer.rb b/lib/observer.rb
index 5928367..0c74b49 100644
--- a/lib/observer.rb
+++ b/lib/observer.rb
@@ -23,7 +23,7 @@ module Observable
0
end
end
- def changed(state=TRUE)
+ def changed(state=true)
@observer_state = state
end
def changed?
@@ -36,7 +36,7 @@ module Observable
i.update(*arg)
end
end
- @observer_state = FALSE
+ @observer_state = false
end
end
end
diff --git a/lib/open3.rb b/lib/open3.rb
new file mode 100644
index 0000000..9e34acf
--- /dev/null
+++ b/lib/open3.rb
@@ -0,0 +1,55 @@
+# Usage:
+# require "open3"
+#
+# in, out, err = Open3.popen3('nroff -man')
+# or
+# include Open3
+# in, out, err = popen3('nroff -man')
+#
+
+module Open3
+ #[stdin, stdout, stderr] = popen3(command);
+ def popen3(cmd)
+ pw = IO::pipe # pipe[0] for read, pipe[1] for write
+ pr = IO::pipe
+ pe = IO::pipe
+
+ pid = fork
+ if pid == nil then # child
+ pw[1].close
+ STDIN.reopen(pw[0])
+ pw[0].close
+
+ pr[0].close
+ STDOUT.reopen(pr[1])
+ pr[1].close
+
+ pe[0].close
+ STDERR.reopen(pe[1])
+ pe[1].close
+
+ exec(cmd)
+ exit
+ else
+ pw[0].close
+ pr[1].close
+ pe[1].close
+ pi = [ pw[1], pr[0], pe[0] ]
+ end
+ end
+ module_function :popen3
+end
+
+if $0 == __FILE__
+ a = Open3.popen3("nroff -man")
+ Thread.start do
+ while gets
+ a[0].print $_
+ end
+ a[0].close
+ end
+ while a[1].gets
+ print ":", $_
+ end
+end
+
diff --git a/lib/parsedate.rb b/lib/parsedate.rb
index 68550c6..6afec0f 100644
--- a/lib/parsedate.rb
+++ b/lib/parsedate.rb
@@ -8,8 +8,8 @@ module ParseDate
'sun' => 0, 'mon' => 1, 'tue' => 2, 'wed' => 3,
'thu' => 4, 'fri' => 5, 'sat' => 6 }
DAYPAT = DAYS.keys.join('|')
-
- def parsedate(date)
+
+ def parsedate(date, guess=false)
# part of ISO 8601
# yyyy-mm-dd | yyyy-mm | yyyy
# date hh:mm:ss | date Thh:mm:ss
@@ -46,7 +46,7 @@ module ParseDate
if $3
year = $3.to_i
end
- elsif date.sub!(/(#{MONTHPAT})\S*\s+(\d+)\S*\s*,?(?:\s+(\d+))?/i, ' ')
+ elsif date.sub!(/(#{MONTHPAT})\S*\s+(\d+)\S*,?(?:\s+(\d+))?/i, ' ')
mon = MONTHS[$1.downcase]
mday = $2.to_i
if $3
@@ -58,6 +58,23 @@ module ParseDate
if $3
year = $3.to_i
end
+ elsif date.sub!(/(\d+)-(#{MONTHPAT})-(\d+)/i, ' ')
+ mday = $1.to_i
+ mon = MONTHS[$2.downcase]
+ year = $3.to_i
+ end
+ if guess
+ if year < 100
+ if year >= 69
+ year += 1900
+ else
+ year += 2000
+ end
+ end
+ elsif date.sub!(/(\d+)-(#{MONTHPAT})-(\d+)/i, ' ')
+ mday = $1.to_i
+ mon = MONTHS[$2.downcase]
+ year = $3.to_i
end
return year, mon, mday, hour, min, sec, zone, wday
end
diff --git a/lib/profile.rb b/lib/profile.rb
new file mode 100644
index 0000000..e4b1b4b
--- /dev/null
+++ b/lib/profile.rb
@@ -0,0 +1,55 @@
+
+module Profiler__
+ Start = Float(Time.times[0])
+ top = "toplevel".intern
+ Stack = [[0, 0, top]]
+ MAP = {top => [1, 0, 0, "#toplevel"]}
+
+ p = proc{|event, file, line, id, binding, klass|
+ case event
+ when "call", "c-call"
+ now = Float(Time.times[0])
+ Stack.push [now, 0.0, id]
+ when "return", "c-return"
+ now = Float(Time.times[0])
+ tick = Stack.pop
+ data = MAP[id]
+ unless data
+ name = klass.to_s
+ if name.nil? then name = '' end
+ if klass.kind_of? Class
+ name += "#"
+ else
+ name += "."
+ end
+ data = [0.0, 0.0, 0.0, name+id.id2name]
+ MAP[id] = data
+ end
+ data[0] += 1
+ cost = now - tick[0]
+ data[1] += cost
+ data[2] += cost - tick[1]
+ Stack[-1][1] += cost
+ end
+ }
+ END {
+ set_trace_func nil
+ total = Float(Time.times[0]) - Start
+ if total == 0 then total = 0.01 end
+ MAP[:toplevel][1] = total
+# f = open("./rmon.out", "w")
+ f = STDERR
+ data = MAP.values.sort!{|a,b| b[2] <=> a[2]}
+ sum = 0
+ f.printf " %% cumulative self self total\n"
+ f.printf " time seconds seconds calls ms/call ms/call name\n"
+ for d in data
+ sum += d[2]
+ f.printf "%6.2f %8.2f %8.2f %8d ", d[2]/total*100, sum, d[2], d[0]
+ f.printf "%8.2f %8.2f %s\n", d[2]*1000/d[0], d[1]*1000/d[0], d[3]
+ end
+ p total
+ f.close
+ }
+ set_trace_func p
+end
diff --git a/lib/rational.rb b/lib/rational.rb
index 1282f56..f976cf0 100644
--- a/lib/rational.rb
+++ b/lib/rational.rb
@@ -77,7 +77,7 @@ class Rational < Numeric
@denominator = den
else
@numerator = num.to_i
- @denoninator = den.to_i
+ @denominator = den.to_i
end
end
diff --git a/lib/readbytes.rb b/lib/readbytes.rb
new file mode 100644
index 0000000..d6a3b10
--- /dev/null
+++ b/lib/readbytes.rb
@@ -0,0 +1,36 @@
+# readbytes.rb
+#
+# add IO#readbytes, which reads fixed sized data.
+# it guarantees read data size.
+
+class TruncatedDataError<IOError
+ def initialize(mesg, data)
+ @data = data
+ super(mesg)
+ end
+ attr_reader :data
+end
+
+class IO
+ def readbytes(n)
+ str = read(n)
+ if str == nil
+ raise EOFError, "End of file reached"
+ end
+ if str.size < n
+ raise TruncatedDataError.new("data truncated", str)
+ end
+ str
+ end
+end
+
+if __FILE__ == $0
+ begin
+ loop do
+ print STDIN.readbytes(6)
+ end
+ rescue TruncatedDataError
+ p $!.data
+ raise
+ end
+end
diff --git a/lib/shellwords.rb b/lib/shellwords.rb
index 9154cd8..60996be 100644
--- a/lib/shellwords.rb
+++ b/lib/shellwords.rb
@@ -17,7 +17,7 @@ module Shellwords
words = []
while line != ''
field = ''
- while TRUE
+ while true
if line.sub! /^"(([^"\\]|\\.)*)"/, '' then #"
snippet = $1
snippet.gsub! /\\(.)/, '\1'
diff --git a/lib/singleton.rb b/lib/singleton.rb
new file mode 100644
index 0000000..8167a01
--- /dev/null
+++ b/lib/singleton.rb
@@ -0,0 +1,37 @@
+# Singleton module that ensures only one object to be allocated.
+#
+# Usage:
+# class SomeSingletonClass
+# include Singleton
+# #....
+# end
+# a = SomeSingletonClass.instance
+# b = SomeSingletonClass.instance # a and b are same object
+# p [a,b]
+# a = SomeSingletonClass.new # error (`new' is private)
+
+module Singleton
+ def Singleton.append_features(klass)
+ klass.private_class_method(:new)
+ klass.instance_eval %{
+ def instance
+ unless @__instance__
+ @__instance__ = new
+ end
+ return @__instance__
+ end
+ }
+ end
+end
+
+if __FILE__ == $0
+ class SomeSingletonClass
+ include Singleton
+ #....
+ end
+
+ a = SomeSingletonClass.instance
+ b = SomeSingletonClass.instance # a and b are same object
+ p [a,b]
+ a = SomeSingletonClass.new # error (`new' is private)
+end
diff --git a/lib/sync.rb b/lib/sync.rb
index 9f9706d..f1410af 100644
--- a/lib/sync.rb
+++ b/lib/sync.rb
@@ -1,5 +1,5 @@
#
-# sync.rb - カウント付2-フェーズロッククラス
+# sync.rb - 2 phase lock with counter
# $Release Version: 0.2$
# $Revision$
# $Date$
@@ -44,8 +44,6 @@ unless defined? Thread
fail "Thread not available for this ruby interpreter"
end
-require "final"
-
module Sync_m
RCS_ID='-$Header$-'
@@ -54,7 +52,7 @@ module Sync_m
SH = :SH
EX = :EX
- # 例外定義
+ # exceptions
class Err < StandardError
def Err.Fail(*opt)
fail self, sprintf(self::Message, *opt)
@@ -78,51 +76,27 @@ module Sync_m
end
end
- # include and extend initialize methods.
- def Sync_m.extendable_module(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
- obj.instance_eval "@sync_locked"
- For_general_object
- rescue TypeError
- For_primitive_object
- end
- end
- end
-
- def Sync_m.includable_module(cl)
- begin
- dummy = cl.new
- Sync_m.extendable_module(dummy)
- rescue NameError
- # newが定義されていない時は, DATAとみなす.
- For_primitive_object
+ def Sync_m.append_features(cl)
+ super
+ unless cl.instance_of?(Module)
+ # do nothing for Modules
+ # make aliases and include the proper module.
+ cl.module_eval %q{
+ alias locked? sync_locked?
+ alias shared? sync_shared?
+ alias exclusive? sync_exclusive?
+ alias lock sync_lock
+ alias unlock sync_unlock
+ alias try_lock sync_try_lock
+ alias synchronize sync_synchronize
+ }
end
- end
-
- def Sync_m.extend_class(cl)
- return super if cl.instance_of?(Module)
-
- # モジュールの時は何もしない. クラスの場合, 適切なモジュールの決定
- # とaliasを行う.
- real = includable_module(cl)
- cl.module_eval %q{
- include real
-
- alias locked? sync_locked?
- alias shared? sync_shared?
- alias exclusive? sync_exclusive?
- alias lock sync_lock
- alias unlock sync_unlock
- alias try_lock sync_try_lock
- alias synchronize sync_synchronize
- }
+ return self
end
def Sync_m.extend_object(obj)
- obj.extend(Sync_m.extendable_module(obj))
+ super
+ obj.sync_extended
end
def sync_extended
@@ -143,6 +117,7 @@ module Sync_m
alias synchronize sync_synchronize
end"
end
+ initialize
end
# accessing
@@ -162,16 +137,16 @@ module Sync_m
def sync_try_lock(mode = EX)
return unlock if sync_mode == UN
- Thread.critical = TRUE
+ Thread.critical = true
ret = sync_try_lock_sub(sync_mode)
- Thread.critical = FALSE
+ Thread.critical = false
ret
end
def sync_lock(m = EX)
return unlock if m == UN
- until (Thread.critical = TRUE; sync_try_lock_sub(m))
+ 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)
@@ -180,23 +155,23 @@ module Sync_m
end
Thread.stop
end
- Thread.critical = FALSE
+ Thread.critical = false
self
end
def sync_unlock(m = EX)
- Thread.critical = TRUE
+ Thread.critical = true
if sync_mode == UN
- Thread.critical = FALSE
+ Thread.critical = false
Err::UnknownLocker.Fail(Thread.current)
end
m = sync_mode if m == EX and sync_mode == SH
- runnable = FALSE
+ runnable = false
case m
when UN
- Thread.critical = FALSE
+ Thread.critical = false
Err::UnknownLocker.Fail(Thread.current)
when EX
@@ -208,7 +183,7 @@ module Sync_m
else
self.sync_mode = UN
end
- runnable = TRUE
+ runnable = true
end
else
Err::UnknownLocker.Fail(Thread.current)
@@ -222,7 +197,7 @@ module Sync_m
sync_sh_locker.delete(Thread.current)
if sync_sh_locker.empty? and sync_ex_count == 0
self.sync_mode = UN
- runnable = TRUE
+ runnable = true
end
end
end
@@ -235,7 +210,7 @@ module Sync_m
end
wait = sync_upgrade_waiting
self.sync_upgrade_waiting = []
- Thread.critical = FALSE
+ Thread.critical = false
for w, v in wait
w.run
@@ -243,17 +218,46 @@ module Sync_m
else
wait = sync_waiting
self.sync_waiting = []
- Thread.critical = FALSE
+ Thread.critical = false
for w in wait
w.run
end
end
end
- Thread.critical = FALSE
+ Thread.critical = false
self
end
+ def sync_synchronize(mode = EX)
+ sync_lock(mode)
+ begin
+ yield
+ ensure
+ sync_unlock
+ end
+ 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
+
+ private
+
+ def initialize(*args)
+ ret = super
+ @sync_mode = UN
+ @sync_waiting = []
+ @sync_upgrade_waiting = []
+ @sync_sh_locker = Hash.new
+ @sync_ex_locker = nil
+ @sync_ex_count = 0
+ return ret
+ end
+
def sync_try_lock_sub(m)
case m
when SH
@@ -261,18 +265,18 @@ module Sync_m
when UN
self.sync_mode = m
sync_sh_locker[Thread.current] = 1
- ret = TRUE
+ ret = true
when SH
count = 0 unless count = sync_sh_locker[Thread.current]
sync_sh_locker[Thread.current] = count + 1
- ret = TRUE
+ ret = true
when EX
- # 既に, モードがEXである時は, 必ずEXロックとなる.
+ # in EX mode, lock will upgrade to EX lock
if sync_ex_locker == Thread.current
self.sync_ex_count = sync_ex_count + 1
- ret = TRUE
+ ret = true
else
- ret = FALSE
+ ret = false
end
end
when EX
@@ -281,157 +285,29 @@ module Sync_m
self.sync_mode = m
self.sync_ex_locker = Thread.current
self.sync_ex_count = 1
- ret = TRUE
+ ret = true
elsif sync_mode == EX && sync_ex_locker == Thread.current
self.sync_ex_count = sync_ex_count + 1
- ret = TRUE
+ ret = true
else
- ret = FALSE
+ ret = false
end
else
- Thread.critical = FALSE
+ Thread.critical = false
Err::LockModeFailer.Fail mode
end
return ret
end
- private :sync_try_lock_sub
-
- def sync_synchronize(mode = EX)
- sync_lock(mode)
- begin
- yield
- ensure
- sync_unlock
- end
- end
-
- # internal class
- 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
- # Changed to use `final.rb'.
- # Finalizer.add(obj, For_primitive_object, :sync_finalize)
- ObjectSpace.define_finalizer(obj) do |id|
- For_primitive_object.sync_finalize(id)
- end
- end
-
- def initialize
- super
- Sync_Locked[id] = LockState.new(UN, [], [], Hash.new, nil, 0 )
- self
- end
-
- def sync_extended
- super
- initialize
- end
-
- def For_primitive_object.sync_finalize(id)
- 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 initialize
- super
- @sync_mode = UN
- @sync_waiting = []
- @sync_upgrade_waiting = []
- @sync_sh_locker = Hash.new
- @sync_ex_locker = nil
- @sync_ex_count = 0
- self
- end
-
- def sync_extended
- super
- initialize
- 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
- Sync_m.extend_class self
- #include Sync_m
+ include Sync_m
+
+ private
def initialize
super
end
-
end
Synchronizer = Sync
diff --git a/lib/telnet.rb b/lib/telnet.rb
new file mode 100644
index 0000000..96e2cac
--- /dev/null
+++ b/lib/telnet.rb
@@ -0,0 +1,636 @@
+=begin
+$Date: 1999/08/10 05:20:21 $
+
+== SIMPLE TELNET CLIANT LIBRARY
+
+telnet.rb
+
+Version 0.232
+
+Wakou Aoyama <wakou@fsinet.or.jp>
+
+
+=== MAKE NEW TELNET OBJECT
+
+ host = Telnet.new({"Binmode" => false, # default: false
+ "Host" => "localhost", # default: "localhost"
+ "Output_log" => "output_log", # default: not output
+ "Dump_log" => "dump_log", # default: not output
+ "Port" => 23, # default: 23
+ "Prompt" => /[$%#>] \z/n, # default: /[$%#>] \z/n
+ "Telnetmode" => true, # default: true
+ "Timeout" => 10, # default: 10
+ # if ignore timeout then set "Timeout" to false.
+ "Waittime" => 0, # default: 0
+ "Proxy" => proxy}) # default: nil
+ # proxy is Telnet or TCPsocket object
+
+Telnet object has socket class methods.
+
+if set "Telnetmode" option to false. not telnet command interpretation.
+"Waittime" is time to confirm "Prompt". There is a possibility that
+the same character as "Prompt" is included in the data, and, when
+the network or the host is very heavy, the value is enlarged.
+
+=== STATUS OUTPUT
+
+ host = Telnet.new({"Host" => "localhost"){|c| print c }
+
+connection status output.
+
+example
+
+ Trying localhost...
+ Connected to localhost.
+
+
+=== WAIT FOR MATCH
+
+ line = host.waitfor(/match/)
+ line = host.waitfor({"Match" => /match/,
+ "String" => "string",
+ "Timeout" => secs})
+ # if ignore timeout then set "Timeout" to false.
+
+if set "String" option, then Match == Regexp.new(quote("string"))
+
+
+==== REALTIME OUTPUT
+
+ host.waitfor(/match/){|c| print c }
+ host.waitfor({"Match" => /match/,
+ "String" => "string",
+ "Timeout" => secs}){|c| print c}
+
+of cource, set sync=true or flush is necessary.
+
+
+=== SEND STRING AND WAIT PROMPT
+
+ line = host.cmd("string")
+ line = host.cmd({"String" => "string",
+ "Prompt" => /[$%#>] \z/n,
+ "Timeout" => 10})
+
+
+==== REALTIME OUTPUT
+
+ host.cmd("string"){|c| print c }
+ host.cmd({"String" => "string",
+ "Prompt" => /[$%#>] \z/n,
+ "Timeout" => 10}){|c| print c }
+
+of cource, set sync=true or flush is necessary.
+
+
+=== SEND STRING
+
+ host.print("string")
+
+
+=== TURN TELNET COMMAND INTERPRETATION
+
+ host.telnetmode # turn on/off
+ host.telnetmode(true) # on
+ host.telnetmode(false) # off
+
+
+=== TOGGLE NEWLINE TRANSLATION
+
+ host.binmode # turn true/false
+ host.binmode(true) # no translate newline
+ host.binmode(false) # translate newline
+
+
+=== LOGIN
+
+ host.login("username", "password")
+ host.login({"Name" => "username",
+ "Password" => "password",
+ "Prompt" => /[$%#>] \z/n,
+ "Timeout" => 10})
+
+
+==== REALTIME OUTPUT
+
+ host.login("username", "password"){|c| print c }
+ host.login({"Name" => "username",
+ "Password" => "password",
+ "Prompt" => /[$%#>] \z/n,
+ "Timeout" => 10}){|c| print c }
+
+of cource, set sync=true or flush is necessary.
+
+
+== EXAMPLE
+
+=== LOGIN AND SEND COMMAND
+
+ localhost = Telnet.new({"Host" => "localhost",
+ "Timeout" => 10,
+ "Prompt" => /[$%#>] \z/n})
+ localhost.login("username", "password"){|c| print c }
+ localhost.cmd("command"){|c| print c }
+ localhost.close
+
+
+=== CHECKS A POP SERVER TO SEE IF YOU HAVE MAIL
+
+ pop = Telnet.new({"Host" => "your_destination_host_here",
+ "Port" => 110,
+ "Telnetmode" => false,
+ "Prompt" => /^\+OK/n})
+ pop.cmd("user " + "your_username_here"){|c| print c}
+ pop.cmd("pass " + "your_password_here"){|c| print c}
+ pop.cmd("list"){|c| print c}
+
+
+== HISTORY
+
+=== Version 0.232
+
+1999/08/10 05:20:21
+
+- STATUS OUTPUT sample code typo. thanks to Tadayoshi Funaba <tadf@kt.rim.or.jp>
+ host = Telnet.new({"Hosh" => "localhost"){|c| print c }
+ host = Telnet.new({"Host" => "localhost"){|c| print c }
+
+=== Version 0.231
+
+1999/07/16 13:39:42
+
+- TRUE --> true, FALSE --> false
+
+=== Version 0.23
+
+1999/07/15 22:32:09
+
+- waitfor: if end of file reached, then return nil.
+
+=== Version 0.22
+
+1999/06/29 09:08:51
+
+- new, waitfor, cmd: {"Timeout" => false} # ignore timeout
+
+=== Version 0.21
+
+1999/06/28 18:18:55
+
+- waitfor: not rescue (EOFError)
+
+=== Version 0.20
+
+1999/06/04 06:24:58
+
+- waitfor: support for divided telnet command
+
+=== Version 0.181
+
+1999/05/22
+
+- bug fix: print method
+
+=== Version 0.18
+
+1999/05/14
+
+- respond to "IAC WON'T SGA" with "IAC DON'T SGA"
+- DON'T SGA : end of line --> CR + LF
+- bug fix: preprocess method
+
+=== Version 0.17
+
+1999/04/30
+
+- bug fix: $! + "\n" --> $!.to_s + "\n"
+
+=== Version 0.163
+
+1999/04/11
+
+- STDOUT.write(message) --> yield(message) if iterator?
+
+=== Version 0.162
+
+1999/03/17
+
+- add "Proxy" option
+- required timeout.rb
+
+=== Version 0.161
+
+1999/02/03
+
+- select --> IO::select
+
+=== Version 0.16
+
+1998/10/09
+
+- preprocess method change for the better
+- add binmode method.
+- change default Binmode. TRUE --> FALSE
+
+=== Version 0.15
+
+1998/10/04
+
+- add telnetmode method.
+
+=== Version 0.141
+
+1998/09/22
+
+- change default prompt. /[$%#>] $/ --> /[$%#>] \Z/
+
+=== Version 0.14
+
+1998/09/01
+
+- IAC WILL SGA send EOL --> CR+NULL
+- IAC WILL SGA IAC DO BIN send EOL --> CR
+- NONE send EOL --> LF
+- add Dump_log option.
+
+=== Version 0.13
+
+1998/08/25
+
+- add print method.
+
+=== Version 0.122
+
+1998/08/05
+
+- support for HP-UX 10.20 thanks to WATANABE Tetsuya <tetsu@jpn.hp.com>
+- socket.<< --> socket.write
+
+=== Version 0.121
+
+1998/07/15
+
+- string.+= --> string.concat
+
+=== Version 0.12
+
+1998/06/01
+
+- add timeout, waittime.
+
+=== Version 0.11
+
+1998/04/21
+
+- add realtime output.
+
+=== Version 0.10
+
+1998/04/13
+
+- first release.
+
+=end
+
+require "socket"
+require "delegate"
+require "thread"
+require "timeout"
+TimeOut = TimeoutError
+
+class Telnet < SimpleDelegator
+
+ IAC = 255.chr # "\377" # interpret as command:
+ DONT = 254.chr # "\376" # you are not to use option
+ DO = 253.chr # "\375" # please, you use option
+ WONT = 252.chr # "\374" # I won't use option
+ WILL = 251.chr # "\373" # I will use option
+ SB = 250.chr # "\372" # interpret as subnegotiation
+ GA = 249.chr # "\371" # you may reverse the line
+ EL = 248.chr # "\370" # erase the current line
+ EC = 247.chr # "\367" # erase the current character
+ AYT = 246.chr # "\366" # are you there
+ AO = 245.chr # "\365" # abort output--but let prog finish
+ IP = 244.chr # "\364" # interrupt process--permanently
+ BREAK = 243.chr # "\363" # break
+ DM = 242.chr # "\362" # data mark--for connect. cleaning
+ NOP = 241.chr # "\361" # nop
+ SE = 240.chr # "\360" # end sub negotiation
+ EOR = 239.chr # "\357" # end of record (transparent mode)
+ ABORT = 238.chr # "\356" # Abort process
+ SUSP = 237.chr # "\355" # Suspend process
+ EOF = 236.chr # "\354" # End of file
+ SYNCH = 242.chr # "\362" # for telfunc calls
+
+ OPT_BINARY = 0.chr # "\000" # Binary Transmission
+ OPT_ECHO = 1.chr # "\001" # Echo
+ OPT_RCP = 2.chr # "\002" # Reconnection
+ OPT_SGA = 3.chr # "\003" # Suppress Go Ahead
+ OPT_NAMS = 4.chr # "\004" # Approx Message Size Negotiation
+ OPT_STATUS = 5.chr # "\005" # Status
+ OPT_TM = 6.chr # "\006" # Timing Mark
+ OPT_RCTE = 7.chr # "\a" # Remote Controlled Trans and Echo
+ OPT_NAOL = 8.chr # "\010" # Output Line Width
+ OPT_NAOP = 9.chr # "\t" # Output Page Size
+ OPT_NAOCRD = 10.chr # "\n" # Output Carriage-Return Disposition
+ OPT_NAOHTS = 11.chr # "\v" # Output Horizontal Tab Stops
+ OPT_NAOHTD = 12.chr # "\f" # Output Horizontal Tab Disposition
+ OPT_NAOFFD = 13.chr # "\r" # Output Formfeed Disposition
+ OPT_NAOVTS = 14.chr # "\016" # Output Vertical Tabstops
+ OPT_NAOVTD = 15.chr # "\017" # Output Vertical Tab Disposition
+ OPT_NAOLFD = 16.chr # "\020" # Output Linefeed Disposition
+ OPT_XASCII = 17.chr # "\021" # Extended ASCII
+ OPT_LOGOUT = 18.chr # "\022" # Logout
+ OPT_BM = 19.chr # "\023" # Byte Macro
+ OPT_DET = 20.chr # "\024" # Data Entry Terminal
+ OPT_SUPDUP = 21.chr # "\025" # SUPDUP
+ OPT_SUPDUPOUTPUT = 22.chr # "\026" # SUPDUP Output
+ OPT_SNDLOC = 23.chr # "\027" # Send Location
+ OPT_TTYPE = 24.chr # "\030" # Terminal Type
+ OPT_EOR = 25.chr # "\031" # End of Record
+ OPT_TUID = 26.chr # "\032" # TACACS User Identification
+ OPT_OUTMRK = 27.chr # "\e" # Output Marking
+ OPT_TTYLOC = 28.chr # "\034" # Terminal Location Number
+ OPT_3270REGIME = 29.chr # "\035" # Telnet 3270 Regime
+ OPT_X3PAD = 30.chr # "\036" # X.3 PAD
+ OPT_NAWS = 31.chr # "\037" # Negotiate About Window Size
+ OPT_TSPEED = 32.chr # " " # Terminal Speed
+ OPT_LFLOW = 33.chr # "!" # Remote Flow Control
+ OPT_LINEMODE = 34.chr # "\"" # Linemode
+ OPT_XDISPLOC = 35.chr # "#" # X Display Location
+ OPT_OLD_ENVIRON = 36.chr # "$" # Environment Option
+ OPT_AUTHENTICATION = 37.chr # "%" # Authentication Option
+ OPT_ENCRYPT = 38.chr # "&" # Encryption Option
+ OPT_NEW_ENVIRON = 39.chr # "'" # New Environment Option
+ OPT_EXOPL = 255.chr # "\377" # Extended-Options-List
+
+ NULL = "\000"
+ CR = "\015"
+ LF = "\012"
+ EOL = CR + LF
+v = $-v
+$-v = false
+ VERSION = "0.232"
+ RELEASE_DATE = "$Date: 1999/08/10 05:20:21 $"
+$-v = v
+
+ def initialize(options)
+ @options = options
+ @options["Binmode"] = false unless @options.key?("Binmode")
+ @options["Host"] = "localhost" unless @options.key?("Host")
+ @options["Port"] = 23 unless @options.key?("Port")
+ @options["Prompt"] = /[$%#>] \z/n unless @options.key?("Prompt")
+ @options["Telnetmode"] = true unless @options.key?("Telnetmode")
+ @options["Timeout"] = 10 unless @options.key?("Timeout")
+ @options["Waittime"] = 0 unless @options.key?("Waittime")
+
+ @telnet_option = { "SGA" => false, "BINARY" => false }
+
+ if @options.key?("Output_log")
+ @log = File.open(@options["Output_log"], 'a+')
+ @log.sync = true
+ @log.binmode
+ end
+
+ if @options.key?("Dump_log")
+ @dumplog = File.open(@options["Dump_log"], 'a+')
+ @dumplog.sync = true
+ @dumplog.binmode
+ end
+
+ if @options.key?("Proxy")
+ if @options["Proxy"].kind_of?(Telnet)
+ @sock = @options["Proxy"].sock
+ elsif @options["Proxy"].kind_of?(TCPsocket)
+ @sock = @options["Proxy"]
+ else
+ raise "Error; Proxy is Telnet or TCPSocket object."
+ end
+ else
+ message = "Trying " + @options["Host"] + "...\n"
+ yield(message) if iterator?
+ @log.write(message) if @options.key?("Output_log")
+ @dumplog.write(message) if @options.key?("Dump_log")
+
+ begin
+ if @options["Timeout"] == false
+ @sock = TCPsocket.open(@options["Host"], @options["Port"])
+ else
+ timeout(@options["Timeout"]){
+ @sock = TCPsocket.open(@options["Host"], @options["Port"])
+ }
+ end
+ rescue TimeoutError
+ raise TimeOut, "timed-out; opening of the host"
+ rescue
+ @log.write($!.to_s + "\n") if @options.key?("Output_log")
+ @dumplog.write($!.to_s + "\n") if @options.key?("Dump_log")
+ raise
+ end
+ @sock.sync = true
+ @sock.binmode
+
+ message = "Connected to " + @options["Host"] + ".\n"
+ yield(message) if iterator?
+ @log.write(message) if @options.key?("Output_log")
+ @dumplog.write(message) if @options.key?("Dump_log")
+ end
+
+ super(@sock)
+ end # initialize
+
+ attr :sock
+
+ def telnetmode(mode = 'turn')
+ if 'turn' == mode
+ @options["Telnetmode"] = @options["Telnetmode"] ? false : true
+ else
+ @options["Telnetmode"] = mode ? true : false
+ end
+ end
+
+ def binmode(mode = 'turn')
+ if 'turn' == mode
+ @options["Binmode"] = @options["Binmode"] ? false : true
+ else
+ @options["Binmode"] = mode ? true : false
+ end
+ end
+
+ def preprocess(string)
+ str = string.dup
+
+ # combine CR+NULL into CR
+ str.gsub!(/#{CR}#{NULL}/no, CR) if @options["Telnetmode"]
+
+ # combine EOL into "\n"
+ str.gsub!(/#{EOL}/no, "\n") unless @options["Binmode"]
+
+ # respond to "IAC DO x"
+ str.gsub!(/([^#{IAC}]?)#{IAC}#{DO}([#{OPT_BINARY}-#{OPT_NEW_ENVIRON}#{OPT_EXOPL}])/no){
+ if OPT_BINARY == $2
+ @telnet_option["BINARY"] = true
+ @sock.write(IAC + WILL + OPT_BINARY)
+ else
+ @sock.write(IAC + WONT + $2)
+ end
+ $1
+ }
+
+ # respond to "IAC DON'T x" with "IAC WON'T x"
+ str.gsub!(/([^#{IAC}]?)#{IAC}#{DONT}([#{OPT_BINARY}-#{OPT_NEW_ENVIRON}#{OPT_EXOPL}])/no){
+ @sock.write(IAC + WONT + $2)
+ $1
+ }
+
+ # respond to "IAC WILL x"
+ str.gsub!(/([^#{IAC}]?)#{IAC}#{WILL}([#{OPT_BINARY}-#{OPT_NEW_ENVIRON}#{OPT_EXOPL}])/no){
+ if OPT_ECHO == $2
+ @sock.write(IAC + DO + OPT_ECHO)
+ elsif OPT_SGA == $2
+ @telnet_option["SGA"] = true
+ @sock.write(IAC + DO + OPT_SGA)
+ end
+ $1
+ }
+
+ # respond to "IAC WON'T x"
+ str.gsub!(/([^#{IAC}]?)#{IAC}#{WONT}([#{OPT_BINARY}-#{OPT_NEW_ENVIRON}#{OPT_EXOPL}])/no){
+ if OPT_ECHO == $2
+ @sock.write(IAC + DONT + OPT_ECHO)
+ elsif OPT_SGA == $2
+ @telnet_option["SGA"] = false
+ @sock.write(IAC + DONT + OPT_SGA)
+ end
+ $1
+ }
+
+ # respond to "IAC AYT" (are you there)
+ str.gsub!(/([^#{IAC}]?)#{IAC}#{AYT}/no){
+ @sock.write("nobody here but us pigeons" + EOL)
+ $1
+ }
+
+ str.gsub!(/#{IAC}#{IAC}/no, IAC) # handle escaped IAC characters
+
+ str
+ end # preprocess
+
+ def waitfor(options)
+ time_out = @options["Timeout"]
+ waittime = @options["Waittime"]
+
+ if options.kind_of?(Hash)
+ prompt = if options.key?("Match")
+ options["Match"]
+ elsif options.key?("Prompt")
+ options["Prompt"]
+ elsif options.key?("String")
+ Regexp.new( Regexp.quote(options["String"]) )
+ end
+ time_out = options["Timeout"] if options.key?("Timeout")
+ waittime = options["Waittime"] if options.key?("Waittime")
+ else
+ prompt = options
+ end
+
+ if time_out == false
+ time_out = nil
+ end
+
+ line = ''
+ buf = ''
+ until(not IO::select([@sock], nil, nil, waittime) and prompt === line)
+ unless IO::select([@sock], nil, nil, time_out)
+ raise TimeOut, "timed-out; wait for the next data"
+ end
+ begin
+ c = @sock.sysread(1024 * 1024)
+ @dumplog.print(c) if @options.key?("Dump_log")
+ buf.concat c
+ if @options["Telnetmode"]
+ buf = preprocess(buf)
+ if /#{IAC}.?\z/no === buf
+ next
+ end
+ end
+ @log.print(buf) if @options.key?("Output_log")
+ yield buf if iterator?
+ line.concat(buf)
+ buf = ''
+ rescue EOFError # End of file reached
+ if line == ''
+ line = nil
+ yield nil if iterator?
+ end
+ break
+ end
+ end
+ line
+ end
+
+ def print(string)
+ str = string.dup + "\n"
+
+ str.gsub!(/#{IAC}/no, IAC + IAC) if @options["Telnetmode"]
+
+ unless @options["Binmode"]
+ if @telnet_option["BINARY"] and @telnet_option["SGA"]
+ # IAC WILL SGA IAC DO BIN send EOL --> CR
+ str.gsub!(/\n/n, CR)
+ elsif @telnet_option["SGA"]
+ # IAC WILL SGA send EOL --> CR+NULL
+ str.gsub!(/\n/n, CR + NULL)
+ else
+ # NONE send EOL --> CR+LF
+ str.gsub!(/\n/n, EOL)
+ end
+ end
+
+ @sock.write(str)
+ end
+
+ def cmd(options)
+ match = @options["Prompt"]
+ time_out = @options["Timeout"]
+
+ if options.kind_of?(Hash)
+ string = options["String"]
+ match = options["Match"] if options.key?("Match")
+ time_out = options["Timeout"] if options.key?("Timeout")
+ else
+ string = options
+ end
+
+ IO::select(nil, [@sock])
+ self.print(string)
+ if iterator?
+ waitfor({"Prompt" => match, "Timeout" => time_out}){|c| yield c }
+ else
+ waitfor({"Prompt" => match, "Timeout" => time_out})
+ end
+ end
+
+ def login(options, password = '')
+ if options.kind_of?(Hash)
+ username = options["Name"]
+ password = options["Password"]
+ else
+ username = options
+ end
+
+ if iterator?
+ line = waitfor(/login[: ]*\z/n){|c| yield c }
+ line.concat( cmd({"String" => username,
+ "Match" => /Password[: ]*\z/n}){|c| yield c } )
+ line.concat( cmd(password){|c| yield c } )
+ else
+ line = waitfor(/login[: ]*\z/n)
+ line.concat( cmd({"String" => username,
+ "Match" => /Password[: ]*\z/n}) )
+ line.concat( cmd(password) )
+ end
+ line
+ end
+
+end
diff --git a/lib/tempfile.rb b/lib/tempfile.rb
new file mode 100644
index 0000000..11a8fba
--- /dev/null
+++ b/lib/tempfile.rb
@@ -0,0 +1,94 @@
+#
+# $Id$
+#
+# The class for temporary files.
+# o creates a temporary file, which name is "basename.pid.n" with mode "w+".
+# o Tempfile objects can be used like IO object.
+# o with tmpfile.close(true) created temporary files are removed.
+# o created files are also removed on script termination.
+# o with Tempfile#open, you can reopen the temporary file.
+# o file mode of the temporary files are 0600.
+
+require 'delegate'
+require 'final'
+
+class Tempfile < SimpleDelegator
+ Max_try = 10
+
+ def Tempfile.callback(path)
+ lambda{
+ print "removing ", path, "..." if $DEBUG
+ if File.exist?(path)
+ File.unlink(path)
+ end
+ if File.exist?(path + '.lock')
+ Dir.rmdir(path + '.lock')
+ end
+ print "done\n" if $DEBUG
+ }
+ end
+
+ def initialize(basename, tmpdir=ENV['TMPDIR']||ENV['TMP']||ENV['TEMP']||'/tmp')
+ umask = File.umask(0177)
+ begin
+ n = 0
+ while true
+ begin
+ tmpname = sprintf('%s/%s%d.%d', tmpdir, basename, $$, n)
+ lock = tmpname + '.lock'
+ unless File.exist?(tmpname) or File.exist?(lock)
+ Dir.mkdir(lock)
+ break
+ end
+ rescue
+ raise "cannot generate tmpfile `%s'" % tmpname if n >= Max_try
+ #sleep(1)
+ end
+ n += 1
+ end
+
+ @clean_files = Tempfile.callback(tmpname)
+ ObjectSpace.define_finalizer(self, @clean_files)
+
+ @tmpfile = File.open(tmpname, 'w+')
+ @tmpname = tmpname
+ super(@tmpfile)
+ Dir.rmdir(lock)
+ ensure
+ File.umask(umask)
+ end
+ end
+
+ def Tempfile.open(*args)
+ Tempfile.new(*args)
+ end
+
+ def open
+ @tmpfile.close if @tmpfile
+ @tmpfile = File.open(@tmpname, 'r+')
+ __setobj__(@tmpfile)
+ end
+
+ def close(real=false)
+ @tmpfile.close if @tmpfile
+ @tmpfile = nil
+ if real
+ @clean_files.call
+ ObjectSpace.undefine_finalizer(self)
+ end
+ end
+
+ def path
+ @tmpname
+ end
+end
+
+if __FILE__ == $0
+# $DEBUG = true
+ f = Tempfile.new("foo")
+ f.print("foo\n")
+ f.close
+ f.open
+ p f.gets # => "foo\n"
+ f.close(true)
+end
diff --git a/lib/thread.rb b/lib/thread.rb
index ec75144..22610f2 100644
--- a/lib/thread.rb
+++ b/lib/thread.rb
@@ -17,6 +17,16 @@ if $DEBUG
Thread.abort_on_exception = true
end
+def Thread.exclusive
+ begin
+ Thread.critical = true
+ r = yield
+ ensure
+ Thread.critical = false
+ end
+ r
+end
+
class Mutex
def initialize
@waiting = []
@@ -52,10 +62,10 @@ class Mutex
def unlock
return unless @locked
- Thread.critical = TRUE
+ Thread.critical = true
t = @waiting.shift
- @locked = FALSE
- Thread.critical = FALSE
+ @locked = false
+ Thread.critical = false
t.run if t
self
end
@@ -68,39 +78,46 @@ class Mutex
unlock
end
end
+
+ def exclusive_unlock
+ return unless @locked
+ Thread.exclusive do
+ t = @waiting.shift
+ @locked = false
+ t.wakeup if t
+ yield
+ end
+ self
+ end
end
class ConditionVariable
def initialize
@waiters = []
- @waiters_mutex = Mutex.new
- @waiters.taint # enable tainted comunication
- self.taint
end
def wait(mutex)
- mutex.unlock
- @waiters_mutex.synchronize {
+ mutex.exclusive_unlock do
@waiters.push(Thread.current)
- }
- Thread.stop
+ Thread.stop
+ end
mutex.lock
end
def signal
- @waiters_mutex.synchronize {
- t = @waiters.shift
- t.run if t
- }
+ t = @waiters.shift
+ t.run if t
end
def broadcast
- @waiters_mutex.synchronize {
- for t in @waiters
- t.run
- end
+ waiters0 = nil
+ Thread.exclusive do
+ waiters0 = @waiters.dup
@waiters.clear
- }
+ end
+ for t in waiters0
+ t.run
+ end
end
end
@@ -120,6 +137,7 @@ class Queue
Thread.critical = false
t.run if t
end
+ alias enq push
def pop non_block=false
Thread.critical = true
@@ -139,11 +157,17 @@ class Queue
Thread.critical = false
end
end
+ alias shift pop
+ alias deq pop
def empty?
@que.length == 0
end
+ def clear
+ @que.replace([])
+ end
+
def length
@que.length
end
@@ -168,14 +192,14 @@ class SizedQueue<Queue
end
def max=(max)
- Thread.critical = TRUE
+ Thread.critical = true
if @max >= max
@max = max
- Thread.critical = FALSE
+ Thread.critical = false
else
diff = max - @max
@max = max
- Thread.critical = FALSE
+ Thread.critical = false
diff.times do
t = @queue_wait.shift
t.run if t
diff --git a/lib/timeout.rb b/lib/timeout.rb
new file mode 100644
index 0000000..d4ea758
--- /dev/null
+++ b/lib/timeout.rb
@@ -0,0 +1,42 @@
+#
+# timeout.rb -- execution timeout
+#
+#= SYNOPSIS
+#
+# require 'timeout'
+# status = timeout(5) {
+# # something may take time
+# }
+#
+#= DESCRIPTION
+#
+# timeout executes the block. If the block execution terminates successfully
+# before timeout, it returns true. If not, it terminates the execution and
+# raise TimeoutError exception.
+#
+#== Parameters
+#
+# : timout
+#
+# The time in seconds to wait for block teminatation.
+#
+#=end
+
+class TimeoutError<StandardError
+end
+
+Thread.abort_on_exception = true
+
+def timeout(sec)
+ begin
+ x = Thread.current
+ y = Thread.start {
+ sleep sec
+ x.raise TimeoutError, "execution expired" if x.status
+ }
+ yield sec
+ return true
+ ensure
+ Thread.kill y if y.status
+ end
+end
diff --git a/lib/tracer.rb b/lib/tracer.rb
index fbfca24..a8dc2a1 100644
--- a/lib/tracer.rb
+++ b/lib/tracer.rb
@@ -54,7 +54,7 @@ class Tracer
off
end
else
- set_trace_func proc{|event, file, line, id, binding|
+ set_trace_func proc{|event, file, line, id, binding, klass|
trace_func event, file, line, id, binding
}
print "Trace on\n" if Tracer.verbose?
diff --git a/lib/weakref.rb b/lib/weakref.rb
index c31e959..c6fe8cd 100644
--- a/lib/weakref.rb
+++ b/lib/weakref.rb
@@ -2,11 +2,12 @@
#
# Usage:
# foo = Object.new
-# foo.hash
+# foo = Object.new
+# p foo.to_s # original's class
# foo = WeakRef.new(foo)
-# foo.hash
+# p foo.to_s # should be same class
# ObjectSpace.garbage_collect
-# foo.hash # => Raises WeakRef::RefError (because original GC'ed)
+# p foo.to_s # should raise exception (recycled)
require "delegate"
@@ -15,27 +16,31 @@ class WeakRef<Delegator
class RefError<StandardError
end
- ID_MAP = {}
- ID_REV_MAP = {}
+ ID_MAP = {} # obj -> [ref,...]
+ ID_REV_MAP = {} # ref -> obj
ObjectSpace.add_finalizer(lambda{|id|
- rid = ID_MAP[id]
- if rid
- ID_REV_MAP[rid] = nil
+ rids = ID_MAP[id]
+ if rids
+ for rid in rids
+ ID_REV_MAP[rid] = nil
+ end
ID_MAP[id] = nil
end
rid = ID_REV_MAP[id]
if rid
ID_REV_MAP[id] = nil
- ID_MAP[rid] = nil
+ ID_MAP[rid].delete(id)
+ ID_MAP[rid] = nil if ID_MAP[rid].empty?
end
})
-
+
def initialize(orig)
super
@__id = orig.__id__
ObjectSpace.call_finalizer orig
ObjectSpace.call_finalizer self
- ID_MAP[@__id] = self.__id__
+ ID_MAP[@__id] = [] unless ID_MAP[@__id]
+ ID_MAP[@__id].concat self.__id__
ID_REV_MAP[self.id] = @__id
end
@@ -60,10 +65,11 @@ class WeakRef<Delegator
end
if __FILE__ == $0
+ require 'thread'
foo = Object.new
- p foo.hash # original's hash value
+ p foo.to_s # original's class
foo = WeakRef.new(foo)
- p foo.hash # should be same hash value
+ p foo.to_s # should be same class
ObjectSpace.garbage_collect
- p foo.hash # should raise exception (recycled)
+ p foo.to_s # should raise exception (recycled)
end