summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authormatz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>1999-01-20 04:59:39 +0000
committermatz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>1999-01-20 04:59:39 +0000
commit62e648e148b3cb9f96dcce808c55c02b7ccb4486 (patch)
tree9708892ece92e860d81559ab55e6b1f9400d7ffc /lib
parentaeb049c573be4dc24dd20650f40e4777e0f698cf (diff)
ruby 1.3 cycle
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/RUBY@372 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'lib')
-rw-r--r--lib/Env.rb31
-rw-r--r--lib/README61
-rw-r--r--lib/base64.rb45
-rw-r--r--lib/cgi-lib.rb39
-rw-r--r--lib/complex.rb14
-rw-r--r--lib/date.rb91
-rw-r--r--lib/date2.rb219
-rw-r--r--lib/debug.rb12
-rw-r--r--lib/delegate.rb100
-rw-r--r--lib/e2mmap.rb77
-rw-r--r--lib/eregex.rb11
-rw-r--r--lib/final.rb41
-rw-r--r--lib/finalize.rb66
-rw-r--r--lib/find.rb4
-rw-r--r--lib/ftools.rb31
-rw-r--r--lib/ftplib.rb1123
-rw-r--r--lib/getoptlong.rb473
-rw-r--r--lib/getopts.rb3
-rw-r--r--lib/importenv.rb15
-rw-r--r--lib/jcode.rb23
-rw-r--r--lib/mailread.rb5
-rw-r--r--lib/mathn.rb5
-rw-r--r--lib/matrix.rb239
-rw-r--r--lib/mkmf.rb144
-rw-r--r--lib/monitor.rb325
-rw-r--r--lib/mutex_m.rb60
-rw-r--r--lib/observer.rb8
-rw-r--r--lib/open3.rb55
-rw-r--r--lib/parsearg.rb5
-rw-r--r--lib/parsedate.rb81
-rw-r--r--lib/ping.rb33
-rw-r--r--lib/profile.rb53
-rw-r--r--lib/pstore.rb39
-rw-r--r--lib/rational.rb9
-rw-r--r--lib/readbytes.rb36
-rw-r--r--lib/shellwords.rb16
-rw-r--r--lib/singleton.rb37
-rw-r--r--lib/sync.rb13
-rw-r--r--lib/telnet.rb439
-rw-r--r--lib/tempfile.rb91
-rw-r--r--lib/thread.rb163
-rw-r--r--lib/thwait.rb113
-rw-r--r--lib/timeout.rb42
-rw-r--r--lib/tracer.rb147
-rw-r--r--lib/weakref.rb39
45 files changed, 3618 insertions, 1058 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..09e5946
--- /dev/null
+++ b/lib/README
@@ -0,0 +1,61 @@
+English.rb access global variables by english names
+Env.rb access environment variables as globals
+README this file
+base64.rb encode/decode base64 (bit obsolete)
+cgi-lib.rb decode CGI data
+complex.rb complex number suppor
+date.rb date object (compatible)
+date2.rb date object based on Julian date
+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
+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
+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 (imcomlete)
+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
+tk.rb Tk interface
+tkafter.rb
+tkbgerror.rb Tk error module
+tkcanvas.rb Tk canvas interface
+tkclass.rb provides generic names for Tk classes
+tkdialog.rb Tk dialog class
+tkentry.rb Tk entry class
+tkfont.rb Tk font support
+tkmenubar.rb TK menubar utility
+tkmngfocus.rb focus manager
+tkpalette.rb pallete support
+tkscrollbox.rb scroll box, also example of compound widget
+tktext.rb text classes
+tkvirtevent.rb virtual event support
+tracer.rb execution tracer
+weakref.rb weak reference class
diff --git a/lib/base64.rb b/lib/base64.rb
index 96208a6..d7461d8 100644
--- a/lib/base64.rb
+++ b/lib/base64.rb
@@ -1,50 +1,25 @@
-def decode64(str)
- string = ''
- for line in str.split("\n")
- line.delete!('^A-Za-z0-9+/') # remove non-base64 chars
- line.tr!('A-Za-z0-9+/', ' -_') # convert to uuencoded format
- len = ["#{32 + line.length * 3 / 4}"].pack("c")
- # compute length byte
- string += "#{len}#{line}".unpack("u") # uudecode and concatenate
- end
- return string
-end
+require "kconv"
-def j2e(str)
- while str =~ /\033\$B([^\033]*)\033\(B/
- s = $1
- pre, post = $`, $'
- s.gsub!(/./) { |ch|
- (ch[0]|0x80).chr
- }
- str = pre + s + post
- end
-# str.gsub!(/\033\$B([^\033]*)\033\(B/) {
-# $1.gsub!(/./) { |ch|
-# (ch[0]|0x80).chr
-# }
-# }
- str
+def decode64(str)
+ str.unpack("m")[0]
end
def decode_b(str)
str.gsub!(/=\?ISO-2022-JP\?B\?([!->@-~]+)\?=/i) {
decode64($1)
}
+ str = Kconv::toeuc(str)
+ str.gsub!(/=\?SHIFT_JIS\?B\?([!->@-~]+)\?=/i) {
+ decode64($1)
+ }
+ str = Kconv::toeuc(str)
str.gsub!(/\n/, ' ')
str.gsub!(/\0/, '')
- j2e(str)
+ str
end
def encode64(bin)
- encode = ""
- pad = 0
- [bin].pack("u").each do |uu|
- len = (2 + (uu[0] - 32)* 4) / 3
- encode << uu[1, len].tr('` -_', 'AA-Za-z0-9+/')
- pad += uu.length - 2 - len
- end
- encode + "=" * (pad % 3)
+ [bin].pack("m")
end
def b64encode(bin, len = 60)
diff --git a/lib/cgi-lib.rb b/lib/cgi-lib.rb
index 5234e04..7033f0f 100644
--- a/lib/cgi-lib.rb
+++ b/lib/cgi-lib.rb
@@ -1,4 +1,3 @@
-#!/usr/local/bin/ruby
#
# Get CGI String
#
@@ -7,26 +6,26 @@
# foo = CGI.new
# foo['field'] <== value of 'field'
# foo.keys <== array of fields
-# foo.inputs <== hash of { <field> => <value> }
+# 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
-require "shellwords.rb"
+require "delegate"
-class CGI
- include Shellwords
+class CGI < SimpleDelegator
attr("inputs")
# original is CGI.pm
def read_from_cmdline
- words = shellwords(if not ARGV.empty? then
+ require "shellwords.rb"
+ words = Shellwords.shellwords(if not ARGV.empty? then
ARGV.join(' ')
else
- print "(offline mode: enter name=value pairs on standard input)\n"
+ STDERR.print "(offline mode: enter name=value pairs on standard input)\n" if STDIN.tty?
readlines.join(' ').gsub(/\n/, '')
end.gsub(/\\=/, '%3D').gsub(/\\&/, '%26'))
@@ -47,32 +46,32 @@ class CGI
end
module_function :escape, :unescape
- def initialize
- # exception messages should be printed to stdout.
- STDERR.reopen(STDOUT)
+ def initialize(input = $stdin)
@inputs = {}
case ENV['REQUEST_METHOD']
when "GET"
+ # exception messages should be printed to stdout.
+ STDERR.reopen(STDOUT)
ENV['QUERY_STRING'] or ""
when "POST"
- $stdin.read ENV['CONTENT_LENGTH'].to_i
+ # exception messages should be printed to stdout.
+ STDERR.reopen(STDOUT)
+ input.read Integer(ENV['CONTENT_LENGTH'])
else
read_from_cmdline
end.split(/&/).each do |x|
key, val = x.split(/=/,2).collect{|x|unescape(x)}
- @inputs[key] += ("\0" if @inputs[key]) + (val or "")
+ if @inputs.include?(key)
+ @inputs[key] += "\0" + (val or "")
+ else
+ @inputs[key] = (val or "")
+ end
end
- end
- def keys
- @inputs.keys
+ super(@inputs)
end
- def [](key)
- @inputs[key]
- end
-
def CGI.message(msg, title = "")
print "Content-type: text/html\n\n"
print "<html><head><title>"
@@ -84,7 +83,7 @@ class CGI
end
def CGI.error
- m = $!.dup
+ m = $!.to_s.dup
m.gsub!(/&/, '&amp;')
m.gsub!(/</, '&lt;')
m.gsub!(/>/, '&gt;')
diff --git a/lib/complex.rb b/lib/complex.rb
index aa5d219..59caad6 100644
--- a/lib/complex.rb
+++ b/lib/complex.rb
@@ -1,8 +1,8 @@
#
# complex.rb -
# $Release Version: 0.5 $
-# $Revision: 1.1 $
-# $Date: 1996/11/11 04:25:19 $
+# $Revision: 1.3 $
+# $Date: 1998/07/08 10:05:28 $
# by Keiju ISHITSUKA(SHL Japan Inc.)
#
# --
@@ -59,6 +59,7 @@ def Complex(a, b = 0)
end
class Complex < Numeric
+ @RCS_ID='-$Id: complex.rb,v 1.3 1998/07/08 10:05:28 keiju Exp keiju $-'
def Complex.generic?(other)
other.kind_of?(Integer) or
@@ -284,6 +285,11 @@ class Complex < Numeric
@real ^ @image
end
+ def inspect
+ sprintf("Complex(%s, %s)", @real.inspect, @image.inspect)
+ end
+
+
I = Complex(0,1)
attr :real
@@ -396,7 +402,7 @@ module Math
cos!(z)
else
Complex(cos!(z.real)*cosh!(z.image),
- sin!(z.real)*sinh!(z.image))
+ -sin!(z.real)*sinh!(z.image))
end
end
@@ -405,7 +411,7 @@ module Math
sin!(z)
else
Complex(sin!(z.real)*cosh!(z.image),
- -cos!(z.real)*sinh!(z.image))
+ cos!(z.real)*sinh!(z.image))
end
end
diff --git a/lib/date.rb b/lib/date.rb
index 998c2e8..9de49bc 100644
--- a/lib/date.rb
+++ b/lib/date.rb
@@ -1,8 +1,8 @@
#
# Date.rb -
# $Release Version: $
-# $Revision: 1.2 $
-# $Date: 1997/02/14 11:05:29 $
+# $Revision: 1.1.1.1.4.5 $
+# $Date: 1998/03/03 02:39:34 $
# by Yasuo OHBA(SHL Japan Inc. Technology Dept.)
#
# --
@@ -17,15 +17,34 @@
class Date
include Comparable
+ Weektag = [
+ "Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"
+ ]
+
+ Monthtag = [
+ "January","February","March","April", "May", "June","July",
+ "August", "September", "October", "November", "December"
+ ]
+
+ Monthtab = {
+ "jan"=>1, "feb"=>2, "mar"=>3, "apr"=>4, "may"=>5, "jun"=>6,
+ "jul"=>7, "aug"=>8, "sep"=>9, "oct"=>10, "nov"=>11, "dec"=>12
+ }
+
def initialize(y = 1, m = 1, d = 1)
- if y.kind_of?(String) && y.size == 8
- @year = y[0,4].to_i
- @month = y[4,2].to_i
- @day = y[6,2].to_i
+ if y.kind_of?(String)
+ case y
+ when /(\d\d\d\d)-?(?:(\d\d)-?(\d\d)?)?/
+ @year = $1.to_i
+ @month = if $2 then $2.to_i else 1 end
+ @day = if $3 then $3.to_i else 1 end
+ else
+ require 'parsedate'
+ @year, @month, @day = ParseDate.parsedate(y)
+ end
else
if m.kind_of?(String)
- ml = {"jan"=>1, "feb"=>2, "mar"=>3, "apr"=>4, "may"=>5, "jun"=>6, "jul"=>7, "aug"=>8, "sep"=>9, "oct"=>10, "nov"=>11, "dec"=>12}
- m = ml[m.downcase]
+ m = Monthtab[m.downcase]
if m.nil?
raise ArgumentError, "Wrong argument. (month)"
end
@@ -53,25 +72,35 @@ class Date
def period
return Date.period!(@year, @month, @day)
end
-
+
+ def jd
+ return period + 1721423
+ end
+
+ def mjd
+ return jd - 2400000.5
+ end
+
+ def to_s
+ format("%.3s, %.3s %2d %4d", name_of_week, name_of_month, @day, @year)
+ end
+
+ def inspect
+ to_s
+ end
+
def day_of_week
- dl = Date.daylist(@year)
- d = Date.jan1!(@year)
- for m in 1..(@month - 1)
- d += dl[m]
- end
- d += @day - 1
- if @year == 1752 && @month == 9 && @day >= 14
- d -= (14 - 3)
- end
- return (d % 7)
+ return (period + 5) % 7
end
- Weektag = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
def name_of_week
return Weektag[self.day_of_week]
end
+ def name_of_month
+ return Monthtag[@month-1]
+ end
+
def +(o)
if o.kind_of?(Numeric)
d = Integer(self.period + o)
@@ -80,6 +109,9 @@ class Date
else
raise TypeError, "Illegal type. (Integer or Date)"
end
+ if d <= 0
+ raise ArgumentError, "argument out of range. (self > other)"
+ end
return Date.at(d)
end
@@ -117,14 +149,13 @@ class Date
end
def leapyear?
- if Date.leapyear(@year) == 1
- return FALSE
- else
- return TRUE
- end
+ Date.leapyear(@year) != 1
end
def _check_date
+ if @year == nil or @month == nil or @day == nil
+ raise ArgumentError, "argument contains nil"
+ end
m = Date.daylist(@year)
if @month < 1 || @month > 12
raise ArgumentError, "argument(month) out of range."
@@ -151,7 +182,7 @@ end
def Date.at(d)
if d.kind_of? Time
- return Date.new(1900+d.year, d.mon+1, d.mday)
+ return Date.new(d.year, d.mon, d.mday)
end
if d.kind_of? Date
return Date.at(d.period)
@@ -189,10 +220,10 @@ def Date.period!(y, m, d)
p += dl[mm]
end
p += (y - 1) * 365 + ((y - 1) / 4.0).to_i
- if (y - 1) > 1752
- p -= ((y - 1 - 1752) / 100.0).to_i
- p += ((y - 1 - 1752) / 400.0).to_i
- p -= (14 - 3)
+ if y > 1752
+ p -= ((y - 1) / 100.0).to_i
+ p += ((y - 1) / 400.0).to_i
+ p += 2
elsif y == 1752 && m == 9 && d >= 14 && d <= 30
p -= (14 - 3)
end
diff --git a/lib/date2.rb b/lib/date2.rb
new file mode 100644
index 0000000..50c2ccf
--- /dev/null
+++ b/lib/date2.rb
@@ -0,0 +1,219 @@
+# date.rb: Written by Tadayoshi Funaba 1998
+# $Id: date.rb,v 1.4 1998/06/01 12:52:33 tadf Exp $
+
+class Date
+
+ include Comparable
+
+ MONTHNAMES = [ '', '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
+
+ def Date.civil_to_jd(y, m, d, gs = true)
+ if m <= 2 then
+ 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
+ unless
+ (if gs.kind_of? Numeric then jd >= gs else gs end) then
+ jd -= b
+ end
+ jd
+ end
+
+ def Date.jd_to_civil(jd, gs = true)
+ unless
+ (if gs.kind_of? Numeric then jd >= gs else gs end) then
+ 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 then
+ m = e - 1
+ y = c - 4716
+ else
+ m = e - 13
+ y = c - 4715
+ end
+ return y, m, dom
+ end
+
+ def Date.mjd_to_jd(mjd)
+ mjd + 2400000.5
+ end
+
+ def Date.jd_to_mjd(jd)
+ jd - 2400000.5
+ end
+
+ def Date.tjd_to_jd(tjd)
+ tjd + 2440000.5
+ end
+
+ def Date.jd_to_tjd(jd)
+ jd - 2440000.5
+ end
+
+ def Date.julian_leap? (y)
+ y % 4 == 0
+ end
+
+ def Date.gregorian_leap? (y)
+ y % 4 == 0 and y % 100 != 0 or y % 400 == 0
+ end
+
+ def Date.leap? (y)
+ Date.gregorian_leap?(y)
+ end
+
+ def initialize(jd = 0, gs = ITALY)
+ @jd, @gs = jd, gs
+ end
+
+ def Date.exist? (y, m, d, gs = true)
+ jd = Date.civil_to_jd(y, m, d, gs)
+ if [y, m, d] == Date.jd_to_civil(jd, gs) then
+ jd
+ end
+ end
+
+ def Date.new3(y = -4712, m = 1, d = 1, gs = ITALY)
+ unless jd = Date.exist?(y, m, d, gs) then
+ fail ArgumentError, 'invalid date'
+ end
+ Date.new(jd, gs)
+ end
+
+ def Date.today(gs = ITALY)
+ Date.new(Date.civil_to_jd(*(Time.now.to_a[3..5].reverse << gs)), gs)
+ 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.mday; @mday end
+ @year, @mon, @mday = Date.jd_to_civil(@jd, @gs)
+ end
+
+ private :civil
+
+ def year
+ civil
+ @year
+ end
+
+ def yday
+ def self.yday; @yday end
+ ns = if @gs.kind_of? Numeric then @jd >= @gs else @gs end
+ jd = Date.civil_to_jd(year - 1, 12, 31, ns)
+ @yday = @jd - jd
+ end
+
+ def mon
+ civil
+ @mon
+ end
+
+ def mday
+ civil
+ @mday
+ end
+
+ def wday
+ def self.wday; @wday end
+ @wday = (@jd + 1) % 7
+ end
+
+ def leap?
+ def self.leap?; @leap_p end
+ ns = if @gs.kind_of? Numeric then @jd >= @gs else @gs end
+ jd = Date.civil_to_jd(year, 2, 28, ns)
+ @leap_p = Date.jd_to_civil(jd + 1, ns)[1] == 2
+ end
+
+ def + (other)
+ if other.kind_of? Numeric then
+ return Date.new(@jd + other, @gs)
+ end
+ fail TypeError, 'expected numeric'
+ end
+
+ def - (other)
+ if other.kind_of? Numeric then
+ return Date.new(@jd - other, @gs)
+ elsif other.kind_of? Date then
+ return @jd - other.jd
+ end
+ fail TypeError, 'expected numeric or date'
+ end
+
+ def <=> (other)
+ if other.kind_of? Numeric then
+ return @jd <=> other
+ elsif other.kind_of? Date then
+ 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, @gs)
+ end
+ end
+
+ def upto(max)
+ @jd.upto(max.jd) do |jd|
+ yield Date.new(jd, @gs)
+ end
+ end
+
+ def step(max, step)
+ @jd.step(max.jd, step) do |jd|
+ yield Date.new(jd, @gs)
+ end
+ end
+
+ def eql? (other)
+ self == other
+ end
+
+ def hash
+ @jd
+ end
+
+ def to_s
+ format('%04d-%02d-%02d', year, mon, mday)
+ end
+
+end
diff --git a/lib/debug.rb b/lib/debug.rb
index 432c7b4..90270a3 100644
--- a/lib/debug.rb
+++ b/lib/debug.rb
@@ -11,6 +11,8 @@ class DEBUGGER__
@scripts = {}
end
+ DEBUG_LAST_CMD = []
+
def interrupt
@stop_next = 1
end
@@ -40,6 +42,11 @@ class DEBUGGER__
STDOUT.flush
while input = STDIN.gets
input.chop!
+ if input == ""
+ input = DEBUG_LAST_CMD[0]
+ else
+ DEBUG_LAST_CMD[0] = input
+ end
case input
when /^b(reak)?\s+(([^:\n]+:)?.+)/
pos = $2
@@ -169,7 +176,7 @@ class DEBUGGER__
printf "no sourcefile available for %s\n", file
end
when /^p\s+/
- p debug_eval($', binding)
+ p debug_eval($', binding) #'
else
v = debug_eval(input, binding)
p v unless v == nil
@@ -187,10 +194,13 @@ class DEBUGGER__
return "\n" unless line
return line
end
+ save = $DEBUG
begin
+ $DEBUG = FALSE
f = open(file)
lines = @scripts[file] = f.readlines
rescue
+ $DEBUG = save
@scripts[file] = TRUE
return "\n"
end
diff --git a/lib/delegate.rb b/lib/delegate.rb
index e5943ce..0771f2f 100644
--- a/lib/delegate.rb
+++ b/lib/delegate.rb
@@ -1,26 +1,51 @@
# Delegation class that delegates even methods defined in super class,
# which can not be covered with normal method_missing hack.
#
-# Delegater is the abstract delegation class. Need to redefine
-# `__getobj__' method in the subclass. SimpleDelegater is the
+# Delegator is the abstract delegation class. Need to redefine
+# `__getobj__' method in the subclass. SimpleDelegator is the
# concrete subclass for simple delegation.
#
# Usage:
# foo = Object.new
-# foo = SimpleDelegater.new(foo)
-# foo.type # => Object
+# foo2 = SimpleDelegator.new(foo)
+# foo.hash == foo2.hash # => true
+#
+# Foo = DelegateClass(Array)
+#
+# class ExtArray<DelegateClass(Array)
+# ...
+# end
-class Delegater
+class Delegator
def initialize(obj)
- preserved = ["id", "equal?", "__getobj__"]
+ preserved = ::Kernel.instance_methods
+ preserved -= ["to_s","to_a","inspect","==","=~","==="]
for t in self.type.ancestors
preserved |= t.instance_methods
- break if t == Delegater
+ preserved |= t.private_instance_methods
+ preserved |= t.protected_instance_methods
+ break if t == Delegator
end
for method in obj.methods
next if preserved.include? method
- eval "def self.#{method}(*args); __getobj__.send :#{method}, *args; end"
+ eval <<-EOS
+ def self.#{method}(*args, &block)
+ 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
+ raise
+ end
+ end
+ EOS
end
end
@@ -30,7 +55,7 @@ class Delegater
end
-class SimpleDelegater<Delegater
+class SimpleDelegator<Delegator
def initialize(obj)
super
@@ -41,4 +66,61 @@ class SimpleDelegater<Delegater
@obj
end
+ def __setobj__(obj)
+ @obj = obj
+ end
+end
+
+# backward compatibility ^_^;;;
+Delegater = Delegator
+SimpleDelegater = SimpleDelegator
+
+#
+def DelegateClass(superclass)
+ klass = Class.new
+ methods = superclass.instance_methods
+ methods -= ::Kernel.instance_methods
+ methods |= ["to_s","to_a","inspect","==","=~","==="]
+ klass.module_eval <<-EOS
+ def initialize(obj)
+ @obj = obj
+ end
+ EOS
+ for method in methods
+ klass.module_eval <<-EOS
+ def #{method}(*args, &block)
+ begin
+ @obj.__send__(:#{method}, *args, &block)
+ rescue
+ $@[0,2] = nil
+ raise
+ end
+ end
+ EOS
+ end
+ return klass;
+ end
+
+if __FILE__ == $0
+ class ExtArray<DelegateClass(Array)
+ def initialize()
+ super([])
+ end
+ end
+
+ ary = ExtArray.new
+ p ary.type
+ ary.push 25
+ p ary
+
+ foo = Object.new
+ def foo.test
+ 25
+ end
+ def foo.error
+ raise 'this is OK'
+ end
+ foo2 = SimpleDelegator.new(foo)
+ p foo.test == foo2.test # => true
+ foo2.error # raise error!
end
diff --git a/lib/e2mmap.rb b/lib/e2mmap.rb
index d10657b..bf860dc 100644
--- a/lib/e2mmap.rb
+++ b/lib/e2mmap.rb
@@ -1,11 +1,22 @@
#
# e2mmap.rb - for ruby 1.1
-# $Release Version: 1.1$
-# $Revision: 1.4 $
-# $Date: 1997/08/18 07:12:12 $
+# $Release Version: 1.2$
+# $Revision: 1.8 $
+# $Date: 1998/08/19 15:22:22 $
# by Keiju ISHITSUKA
#
# --
+# Usage:
+#
+# class Foo
+# extend Exception2MassageMapper
+# def_exception :NewExceptionClass, "message..."[, superclass]
+# def_e2meggage ExistingExceptionClass, "message..."
+# ...
+# end
+#
+# Foo.Fail NewExceptionClass, arg...
+# Foo.Fail ExistingExceptionClass, arg...
#
#
if VERSION < "1.1"
@@ -13,40 +24,60 @@ if VERSION < "1.1"
else
module Exception2MessageMapper
- RCS_ID='-$Header: /home/keiju/var/src/var.lib/ruby/RCS/e2mmap.rb,v 1.4 1997/08/18 07:12:12 keiju Exp keiju $-'
+ @RCS_ID='-$Id: e2mmap.rb,v 1.8 1998/08/19 15:22:22 keiju Exp keiju $-'
E2MM = Exception2MessageMapper
-
+
def E2MM.extend_object(cl)
super
cl.bind(self)
end
- # 以前との互換性のために残してある.
+ # backward compatibility
def E2MM.extend_to(b)
c = eval("self", b)
c.extend(self)
end
-# public :fail
- # alias e2mm_fail fail
+ # public :fail
+ alias fail! fail
+
+ #def fail(err = nil, *rest)
+ # super
+ #end
- def fail(err = nil, *rest)
- Exception2MessageMapper.fail Exception2MessageMapper::ErrNotRegisteredException, err.to_s
+ def Fail(err = nil, *rest)
+ Exception2MessageMapper.Fail Exception2MessageMapper::ErrNotRegisteredException, err.inspect
end
def bind(cl)
self.module_eval %q^
- E2MM_ErrorMSG = {}
+ E2MM_ErrorMSG = {} unless self.const_defined?(:E2MM_ErrorMSG)
# fail(err, *rest)
- # 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
+
+ # 過去の互換性のため
def self.fail(err = nil, *rest)
- $@ = caller(0) if $@.nil?
- $@.shift
if form = E2MM_ErrorMSG[err]
$! = err.new(sprintf(form, *rest))
+ $@ = caller(0) if $@.nil?
+ $@.shift
# e2mm_fail()
raise()
# elsif self == Exception2MessageMapper
@@ -63,7 +94,6 @@ else
# def_exception(c, m)
# c: exception
# m: message_form
- # 例外cのメッセージをmとする.
#
def self.def_e2message(c, m)
E2MM_ErrorMSG[c] = m
@@ -72,13 +102,21 @@ else
# def_exception(c, m)
# n: exception_name
# m: message_form
- # s: 例外スーパークラス(デフォルト: Exception)
- # 例外名``c''をもつ例外を定義し, そのメッセージをmとする.
+ # 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 = Exception)
+ 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)
+
const_set(n, e)
E2MM_ErrorMSG[e] = m
# const_get(:E2MM_ErrorMSG)[e] = m
@@ -91,4 +129,3 @@ else
def_exception(:ErrNotRegisteredException, "not registerd exception(%s)")
end
end
-
diff --git a/lib/eregex.rb b/lib/eregex.rb
index f214f6a..384d531 100644
--- a/lib/eregex.rb
+++ b/lib/eregex.rb
@@ -30,10 +30,7 @@ class Regexp
end
end
-p "abc" =~ /b/|/c/
-p "abc" =~ /b/&/c/
-
-
-
-
-
+if __FILE__ == $0
+ p "abc" =~ /b/|/c/
+ p "abc" =~ /b/&/c/
+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 9b2ffef..a07e67d 100644
--- a/lib/finalize.rb
+++ b/lib/finalize.rb
@@ -1,8 +1,8 @@
#
# finalizer.rb -
-# $Release Version: 0.2$
-# $Revision: 1.3 $
-# $Date: 1998/01/09 08:09:49 $
+# $Release Version: 0.3$
+# $Revision: 1.4 $
+# $Date: 1998/02/27 05:34:33 $
# by Keiju ISHITSUKA
#
# --
@@ -11,44 +11,42 @@
#
# add(obj, dependant, method = :finalize, *opt)
# add_dependency(obj, dependant, method = :finalize, *opt)
-# 依存関係 R_method(obj, dependant) の追加
+# add dependency R_method(obj, dependant)
#
# delete(obj_or_id, dependant, method = :finalize)
# delete_dependency(obj_or_id, dependant, method = :finalize)
-# 依存関係 R_method(obj, dependant) の削除
+# delete dependency R_method(obj, dependant)
# delete_all_dependency(obj_or_id, dependant)
-# 依存関係 R_*(obj, dependant) の削除
+# delete dependency R_*(obj, dependant)
# delete_by_dependant(dependant, method = :finalize)
-# 依存関係 R_method(*, dependant) の削除
+# delete dependency R_method(*, dependant)
# delete_all_by_dependant(dependant)
-# 依存関係 R_*(*, dependant) の削除
+# delete dependency R_*(*, dependant)
# delete_all
-# 全ての依存関係の削除.
+# delete all dependency R_*(*, *)
#
# finalize(obj_or_id, dependant, method = :finalize)
# finalize_dependency(obj_or_id, dependant, method = :finalize)
-# 依存関連 R_method(obj, dependtant) で結ばれるdependantを
-# finalizeする.
+# finalize the dependant connected by dependency R_method(obj, dependtant).
# finalize_all_dependency(obj_or_id, dependant)
-# 依存関連 R_*(obj, dependtant) で結ばれるdependantをfinalizeする.
+# finalize all dependants connected by dependency R_*(obj, dependtant).
# finalize_by_dependant(dependant, method = :finalize)
-# 依存関連 R_method(*, dependtant) で結ばれるdependantをfinalizeする.
+# finalize the dependant connected by dependency R_method(*, dependtant).
# fainalize_all_by_dependant(dependant)
-# 依存関連 R_*(*, dependtant) で結ばれるdependantをfinalizeする.
+# finalize all dependants connected by dependency R_*(*, dependant).
# finalize_all
-# Finalizerに登録される全てのdependantをfinalizeする
+# finalize all dependency registered to the Finalizer.
#
# safe{..}
-# gc時にFinalizerが起動するのを止める.
-#
+# stop invoking Finalizer on GC.
#
module Finalizer
- RCS_ID='-$Header: /home/keiju/var/src/var.lib/ruby/RCS/finalize.rb,v 1.3 1998/01/09 08:09:49 keiju Exp keiju $-'
+ RCS_ID='-$Id: finalize.rb,v 1.4 1998/02/27 05:34:33 keiju Exp keiju $-'
# @dependency: {id => [[dependant, method, *opt], ...], ...}
- # 依存関係 R_method(obj, dependant) の追加
+ # add dependency R_method(obj, dependant)
def add_dependency(obj, dependant, method = :finalize, *opt)
ObjectSpace.call_finalizer(obj)
method = method.intern unless method.kind_of?(Integer)
@@ -61,7 +59,7 @@ module Finalizer
end
alias add add_dependency
- # 依存関係 R_method(obj, dependant) の削除
+ # delete dependency R_method(obj, dependant)
def delete_dependency(id, dependant, method = :finalize)
id = id.id unless id.kind_of?(Integer)
method = method.intern unless method.kind_of?(Integer)
@@ -75,7 +73,7 @@ module Finalizer
end
alias delete delete_dependency
- # 依存関係 R_*(obj, dependant) の削除
+ # delete dependency R_*(obj, dependant)
def delete_all_dependency(id, dependant)
id = id.id unless id.kind_of?(Integer)
method = method.intern unless method.kind_of?(Integer)
@@ -88,30 +86,29 @@ module Finalizer
end
end
- # 依存関係 R_method(*, dependant) の削除
+ # delete dependency R_method(*, dependant)
def delete_by_dependant(dependant, method = :finalize)
method = method.intern unless method.kind_of?(Integer)
- for id in Dependency.keys
+ for id in @dependency.keys
delete(id, dependant, method)
end
end
- # 依存関係 R_*(*, dependant) の削除
+ # delete dependency R_*(*, dependant)
def delete_all_by_dependant(dependant)
for id in @dependency.keys
delete_all_dependency(id, dependant)
end
end
- # 依存関連 R_method(obj, dependtant) で結ばれるdependantをfinalizeす
- # る.
+ # finalize the depandant connected by dependency R_method(obj, dependtant)
def finalize_dependency(id, dependant, method = :finalize)
id = id.id unless id.kind_of?(Integer)
method = method.intern unless method.kind_of?(Integer)
for assocs in @dependency[id]
assocs.delete_if do
|d, m, *o|
- d.send(m, *o) if ret = d == dependant && m == method
+ d.send(m, id, *o) if ret = d == dependant && m == method
ret
end
@dependency.delete(id) if assoc.empty?
@@ -119,20 +116,20 @@ module Finalizer
end
alias finalize finalize_dependency
- # 依存関連 R_*(obj, dependtant) で結ばれるdependantをfinalizeする.
+ # finalize all dependants connected by dependency R_*(obj, dependtant)
def finalize_all_dependency(id, dependant)
id = id.id unless id.kind_of?(Integer)
method = method.intern unless method.kind_of?(Integer)
for assoc in @dependency[id]
assoc.delete_if do
|d, m, *o|
- d.send(m, *o) if ret = d == dependant
+ d.send(m, id, *o) if ret = d == dependant
end
@dependency.delete(id) if assoc.empty?
end
end
- # 依存関連 R_method(*, dependtant) で結ばれるdependantをfinalizeする.
+ # finalize the dependant connected by dependency R_method(*, dependtant)
def finalize_by_dependant(dependant, method = :finalize)
method = method.intern unless method.kind_of?(Integer)
for id in @dependency.keys
@@ -140,14 +137,14 @@ module Finalizer
end
end
- # 依存関連 R_*(*, dependtant) で結ばれるdependantをfinalizeする.
+ # finalize all dependants connected by dependency R_*(*, dependtant)
def fainalize_all_by_dependant(dependant)
for id in @dependency.keys
finalize_all_dependency(id, dependant)
end
end
- # Finalizerに登録されている全てのdependantをfinalizeする
+ # finalize all dependants registered to the Finalizer.
def finalize_all
for id, assocs in @dependency
for dependant, method, *opt in assocs
@@ -157,7 +154,7 @@ module Finalizer
end
end
- # finalize_* を安全に呼び出すためのイテレータ
+ # method to call finalize_* safely.
def safe
old_status = Thread.critical
Thread.critical = TRUE
@@ -167,7 +164,7 @@ module Finalizer
Thread.critical = old_status
end
- # ObjectSpace#add_finalizerへの登録関数
+ # registering function to ObjectSpace#add_finalizer
def final_of(id)
if assocs = @dependency.delete(id)
for dependant, method, *opt in assocs
@@ -202,4 +199,3 @@ module Finalizer
private_class_method :final_of
end
-
diff --git a/lib/find.rb b/lib/find.rb
index 5ecc543..3f1b82d 100644
--- a/lib/find.rb
+++ b/lib/find.rb
@@ -1,5 +1,5 @@
# Usage:
-# require "find.rb"
+# require "find"
#
# Find.find('/foo','/bar') {|f| ...}
# or
@@ -12,7 +12,7 @@ module Find
while file = path.shift
catch(:prune) {
yield file
- if File.directory? file and not File.symlink? file then
+ if File.directory? file then
d = Dir.open(file)
begin
for f in d
diff --git a/lib/ftools.rb b/lib/ftools.rb
index 59bc81b..7ccc7a4 100644
--- a/lib/ftools.rb
+++ b/lib/ftools.rb
@@ -30,7 +30,7 @@ class << File
to.binmode
begin
- while TRUE
+ while true
r = from.sysread(fsize)
rsize = r.size
w = 0
@@ -40,9 +40,9 @@ class << File
end
end
rescue EOFError
- ret = TRUE
+ ret = true
rescue
- ret = FALSE
+ ret = false
ensure
to.close
from.close
@@ -50,7 +50,7 @@ class << File
ret
end
- def copy from, to, verbose = FALSE
+ def copy from, to, verbose = false
$stderr.print from, " -> ", catname(from, to), "\n" if verbose
syscopy from, to
end
@@ -59,11 +59,11 @@ class << File
# move file
- def move from, to, verbose = FALSE
+ def move from, to, verbose = false
to = catname(from, to)
$stderr.print from, " -> ", to, "\n" if verbose
- if PLATFORM =~ /djgpp|cygwin32|mswin32/ and FileTest.file? to
+ if PLATFORM =~ /djgpp|cygwin|mswin32/ and FileTest.file? to
unlink to
end
begin
@@ -76,10 +76,10 @@ class << File
alias mv move
# compare two files
-# TRUE: identical
-# FALSE: not identical
+# true: identical
+# false: not identical
- def compare from, to, verbose = FALSE
+ def compare from, to, verbose = false
$stderr.print from, " <=> ", to, "\n" if verbose
fsize = size(from)
fsize = 1024 if fsize < 512
@@ -90,7 +90,7 @@ class << File
to = open(to, "r")
to.binmode
- ret = FALSE
+ ret = false
fr = tr = ''
begin
@@ -103,7 +103,7 @@ class << File
end
end
rescue
- ret = FALSE
+ ret = false
ensure
to.close
from.close
@@ -116,7 +116,7 @@ class << File
# unlink files safely
def safe_unlink(*files)
- verbose = if files[-1].is_a? String then FALSE else files.pop end
+ verbose = if files[-1].is_a? String then false else files.pop end
begin
$stderr.print files.join(" "), "\n" if verbose
chmod 0777, *files
@@ -129,7 +129,7 @@ class << File
alias rm_f safe_unlink
def makedirs(*dirs)
- verbose = if dirs[-1].is_a? String then FALSE else dirs.pop end
+ verbose = if dirs[-1].is_a? String then false else dirs.pop end
# mode = if dirs[-1].is_a? Fixnum then dirs.pop else 0755 end
mode = 0755
for dir in dirs
@@ -146,14 +146,15 @@ class << File
alias o_chmod chmod
def chmod(mode, *files)
- verbose = if files[-1].is_a? String then FALSE else files.pop end
+ verbose = if files[-1].is_a? String then false else files.pop end
$stderr.printf "chmod %04o %s\n", mode, files.join(" ") if verbose
o_chmod mode, *files
end
- def install(from, to, mode, verbose)
+ 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
cp from, to, verbose
chmod mode, to, verbose if mode
end
diff --git a/lib/ftplib.rb b/lib/ftplib.rb
index 34ee2f8..617d858 100644
--- a/lib/ftplib.rb
+++ b/lib/ftplib.rb
@@ -1,617 +1,574 @@
-### ftplib.rb -*- Mode: ruby; tab-width: 8; -*-
+## ftplib.rb
-## $Revision: 1.5 $
-## $Date: 1997/09/16 08:03:31 $
-## by maeda shugo <shugo@po.aianet.ne.jp>
+# Author: Shugo Maeda <shugo@po.aianet.ne.jp>
+# Version: $Revision: 1.7 $
-### Code:
+## Code:
require "socket"
-require "sync" if defined? Thread
+require "monitor"
-class FTPError < Exception; end
+class FTPError < StandardError; end
class FTPReplyError < FTPError; end
class FTPTempError < FTPError; end
class FTPPermError < FTPError; end
class FTPProtoError < FTPError; end
class FTP
-
- RCS_ID = '$Id: ftplib.rb,v 1.5 1997/09/16 08:03:31 shugo Exp $'
-
- FTP_PORT = 21
- CRLF = "\r\n"
-
- attr :passive, TRUE
- attr :return_code, TRUE
- attr :debug_mode, TRUE
- attr :welcome
- attr :lastresp
-
- THREAD_SAFE = defined?(Thread) != FALSE
-
- if THREAD_SAFE
- def synchronize(mode = :EX)
- if @sync
- @sync.synchronize(mode) do
- yield
- end
- end
- end
-
- def sock_synchronize(mode = :EX)
- if @sock
- @sock.synchronize(mode) do
- yield
- end
- end
- end
- else
- def synchronize(mode = :EX)
- yield
- end
-
- def sock_synchronize(mode = :EX)
- yield
- end
- end
- private :sock_synchronize
-
- def FTP.open(host, user = nil, passwd = nil, acct = nil)
- new(host, user, passwd, acct)
- end
+
+ RCS_ID = %q$Id: ftplib.rb,v 1.7 1998/04/13 12:34:24 shugo Exp shugo $
+
+ include MonitorMixin
+
+ FTP_PORT = 21
+ CRLF = "\r\n"
+
+ attr_accessor :passive, :return_code, :debug_mode
+ attr_reader :welcome, :lastresp
+
+ def FTP.open(host, user = nil, passwd = nil, acct = nil)
+ new(host, user, passwd, acct)
+ end
- def initialize(host = nil, user = nil,
- passwd = nil, acct = nil)
- if THREAD_SAFE
- @sync = Sync.new
- end
- @passive = FALSE
- @return_code = "\n"
- @debug_mode = FALSE
- if host
- connect(host)
- if user
- login(user, passwd, acct)
- end
- end
- end
-
- def open_socket(host, port)
- if defined? SOCKSsocket and ENV["SOCKS_SERVER"]
- @passive = TRUE
- SOCKSsocket.open(host, port)
- else
- TCPsocket.open(host, port)
- end
- end
- private :open_socket
-
- def connect(host, port = FTP_PORT)
- if @debug_mode
- print "connect: ", host, ", ", port, "\n"
- end
- synchronize do
- @sock = open_socket(host, port)
- if THREAD_SAFE
- @sock.extend Sync_m
- end
- voidresp
- end
- end
-
- def sanitize(s)
- if s =~ /^PASS /i
- s[0, 5] + "*" * (s.length - 5)
- else
- s
- end
- end
- private :sanitize
-
- def putline(line)
- if @debug_mode
- print "put: ", sanitize(line), "\n"
- end
- line = line + CRLF
- @sock.write(line)
- end
- private :putline
-
- def getline
- line = @sock.readline # if get EOF, raise EOFError
- if line[-2, 2] == CRLF
- line = line[0 .. -3]
- elsif line[-1] == ?\r or
- line[-1] == ?\n
- line = line[0 .. -2]
- end
- if @debug_mode
- print "get: ", sanitize(line), "\n"
- end
- line
- end
- private :getline
-
- def getmultiline
- line = getline
- buff = line
- if line[3] == ?-
- code = line[0, 3]
- begin
- line = getline
- buff << "\n" << line
- end until line[0, 3] == code and line[3] != ?-
- end
- buff << "\n"
- end
- private :getmultiline
-
- def getresp
- resp = getmultiline
- @lastresp = resp[0, 3]
- c = resp[0]
- case c
- when ?1, ?2, ?3
- return resp
- when ?4
- raise FTPTempError, resp
- when ?5
- raise FTPPermError, resp
- else
- raise FTPProtoError, resp
- end
- end
- private :getresp
-
- def voidresp
- resp = getresp
- if resp[0] != ?2
- raise FTPReplyError, resp
- end
- end
- private :voidresp
-
- def sendcmd(cmd)
- synchronize do
- sock_synchronize do
- putline(cmd)
- getresp
- end
- end
- end
-
- def voidcmd(cmd)
- synchronize do
- sock_synchronize do
- putline(cmd)
- voidresp
- end
- end
- nil
- end
-
- def sendport(host, port)
- hbytes = host.split(".")
- pbytes = [port / 256, port % 256]
- bytes = hbytes + pbytes
- cmd = "PORT " + bytes.join(",")
- voidcmd(cmd)
- end
- private :sendport
-
- def makeport
- sock = TCPserver.open(0)
- port = sock.addr[1]
- host = TCPsocket.getaddress(@sock.addr[2])
- resp = sendport(host, port)
- sock
- end
- private :makeport
-
- def transfercmd(cmd)
- if @passive
- host, port = parse227(sendcmd("PASV"))
- conn = open_socket(host, port)
- resp = sendcmd(cmd)
- if resp[0] != ?1
- raise FTPReplyError, resp
- end
- else
- sock = makeport
- resp = sendcmd(cmd)
- if resp[0] != ?1
- raise FTPReplyError, resp
- end
- conn = sock.accept
- end
- conn
- end
- private :transfercmd
-
- def getaddress
- thishost = Socket.gethostname
- if not thishost.index(".")
- thishost = Socket.gethostbyname(thishost)[0]
- end
- if ENV.has_key?("LOGNAME")
- realuser = ENV["LOGNAME"]
- elsif ENV.has_key?("USER")
- realuser = ENV["USER"]
- else
- realuser = "anonymous"
- end
- realuser + "@" + thishost
- end
- private :getaddress
-
- def login(user = "anonymous", passwd = nil, acct = nil)
- if user == "anonymous" and passwd == nil
- passwd = getaddress
- end
-
- resp = ""
- synchronize do
- resp = sendcmd('USER ' + user)
- if resp[0] == ?3
- resp = sendcmd('PASS ' + passwd)
- end
- if resp[0] == ?3
- resp = sendcmd('ACCT ' + acct)
- end
- end
- if resp[0] != ?2
- raise FTPReplyError, resp
- end
- @welcome = resp
- end
+ def initialize(host = nil, user = nil, passwd = nil, acct = nil)
+ super
+ @passive = false
+ @return_code = "\n"
+ @debug_mode = false
+ if host
+ connect(host)
+ if user
+ login(user, passwd, acct)
+ end
+ end
+ end
+
+ def open_socket(host, port)
+ if defined? SOCKSsocket and ENV["SOCKS_SERVER"]
+ @passive = true
+ return SOCKSsocket.open(host, port)
+ else
+ return TCPsocket.open(host, port)
+ end
+ end
+ private :open_socket
+
+ def connect(host, port = FTP_PORT)
+ if @debug_mode
+ print "connect: ", host, ", ", port, "\n"
+ end
+ synchronize do
+ @sock = open_socket(host, port)
+ voidresp
+ end
+ end
+
+ def sanitize(s)
+ if s =~ /^PASS /i
+ return s[0, 5] + "*" * (s.length - 5)
+ else
+ return s
+ end
+ end
+ private :sanitize
+
+ def putline(line)
+ if @debug_mode
+ print "put: ", sanitize(line), "\n"
+ end
+ line = line + CRLF
+ @sock.write(line)
+ end
+ private :putline
+
+ def getline
+ line = @sock.readline # if get EOF, raise EOFError
+ if line[-2, 2] == CRLF
+ line = line[0 .. -3]
+ elsif line[-1] == ?\r or
+ line[-1] == ?\n
+ line = line[0 .. -2]
+ end
+ if @debug_mode
+ print "get: ", sanitize(line), "\n"
+ end
+ return line
+ end
+ private :getline
+
+ def getmultiline
+ line = getline
+ buff = line
+ if line[3] == ?-
+ code = line[0, 3]
+ begin
+ line = getline
+ buff << "\n" << line
+ end until line[0, 3] == code and line[3] != ?-
+ end
+ return buff << "\n"
+ end
+ private :getmultiline
+
+ def getresp
+ resp = getmultiline
+ @lastresp = resp[0, 3]
+ c = resp[0]
+ case c
+ when ?1, ?2, ?3
+ return resp
+ when ?4
+ raise FTPTempError, resp
+ when ?5
+ raise FTPPermError, resp
+ else
+ raise FTPProtoError, resp
+ end
+ end
+ private :getresp
+
+ def voidresp
+ resp = getresp
+ if resp[0] != ?2
+ raise FTPReplyError, resp
+ end
+ end
+ private :voidresp
+
+ def sendcmd(cmd)
+ synchronize do
+ putline(cmd)
+ return getresp
+ end
+ end
- def retrbinary(cmd, blocksize, callback = Proc.new)
- synchronize do
- voidcmd("TYPE I")
- conn = transfercmd(cmd)
- while TRUE
- data = conn.read(blocksize)
- break if data == nil
- callback.call(data)
- end
- conn.close
- voidresp
- end
- end
+ def voidcmd(cmd)
+ synchronize do
+ putline(cmd)
+ voidresp
+ end
+ end
- def retrlines(cmd, callback = nil)
- if iterator?
- callback = Proc.new
- elsif not callback.is_a?(Proc)
- callback = Proc.new {|line| print line, "\n"}
- end
- synchronize do
- voidcmd("TYPE A")
- conn = transfercmd(cmd)
- while TRUE
- line = conn.gets
- break if line == nil
- if line[-2, 2] == CRLF
- line = line[0 .. -3]
- elsif line[-1] == ?\n
- line = line[0 .. -2]
- end
- callback.call(line)
- end
- conn.close
- voidresp
- end
- end
+ def sendport(host, port)
+ hbytes = host.split(".")
+ pbytes = [port / 256, port % 256]
+ bytes = hbytes + pbytes
+ cmd = "PORT " + bytes.join(",")
+ voidcmd(cmd)
+ end
+ private :sendport
+
+ def makeport
+ sock = TCPserver.open(0)
+ port = sock.addr[1]
+ host = TCPsocket.getaddress(@sock.addr[2])
+ resp = sendport(host, port)
+ return sock
+ end
+ private :makeport
+
+ def transfercmd(cmd)
+ if @passive
+ host, port = parse227(sendcmd("PASV"))
+ conn = open_socket(host, port)
+ resp = sendcmd(cmd)
+ if resp[0] != ?1
+ raise FTPReplyError, resp
+ end
+ else
+ sock = makeport
+ resp = sendcmd(cmd)
+ if resp[0] != ?1
+ raise FTPReplyError, resp
+ end
+ conn = sock.accept
+ end
+ return conn
+ end
+ private :transfercmd
+
+ def getaddress
+ thishost = Socket.gethostname
+ if not thishost.index(".")
+ thishost = Socket.gethostbyname(thishost)[0]
+ end
+ if ENV.has_key?("LOGNAME")
+ realuser = ENV["LOGNAME"]
+ elsif ENV.has_key?("USER")
+ realuser = ENV["USER"]
+ else
+ realuser = "anonymous"
+ end
+ return realuser + "@" + thishost
+ end
+ private :getaddress
- def storbinary(cmd, file, blocksize, callback = nil)
- if iterator?
- callback = Proc.new
- end
- use_callback = callback.is_a?(Proc)
- synchronize do
- voidcmd("TYPE I")
- conn = transfercmd(cmd)
- while TRUE
- buf = file.read(blocksize)
- break if buf == nil
- conn.write(buf)
- if use_callback
- callback.call(buf)
- end
- end
- conn.close
- voidresp
- end
- end
+ def login(user = "anonymous", passwd = nil, acct = nil)
+ if user == "anonymous" and passwd == nil
+ passwd = getaddress
+ end
+
+ resp = ""
+ synchronize do
+ resp = sendcmd('USER ' + user)
+ if resp[0] == ?3
+ resp = sendcmd('PASS ' + passwd)
+ end
+ if resp[0] == ?3
+ resp = sendcmd('ACCT ' + acct)
+ end
+ end
+ if resp[0] != ?2
+ raise FTPReplyError, resp
+ end
+ @welcome = resp
+ end
+
+ def retrbinary(cmd, blocksize, callback = Proc.new)
+ synchronize do
+ voidcmd("TYPE I")
+ conn = transfercmd(cmd)
+ loop do
+ data = conn.read(blocksize)
+ break if data == nil
+ callback.call(data)
+ end
+ conn.close
+ voidresp
+ end
+ end
- def storlines(cmd, file, callback = nil)
- if iterator?
- callback = Proc.new
- end
- use_callback = callback.is_a?(Proc)
- synchronize do
- voidcmd("TYPE A")
- conn = transfercmd(cmd)
- while TRUE
- buf = file.gets
- break if buf == nil
- if buf[-2, 2] != CRLF
- if buf[-1] == ?\r or
- buf[-1] == ?\n
- buf = buf[0 .. -2]
- end
- buf = buf + CRLF
- end
- conn.write(buf)
- if use_callback
- callback.call(buf)
- end
- end
- conn.close
- voidresp
- end
- end
+ def retrlines(cmd, callback = nil)
+ if iterator?
+ callback = Proc.new
+ elsif not callback.is_a?(Proc)
+ callback = Proc.new {|line| print line, "\n"}
+ end
+ synchronize do
+ voidcmd("TYPE A")
+ conn = transfercmd(cmd)
+ loop do
+ line = conn.gets
+ break if line == nil
+ if line[-2, 2] == CRLF
+ line = line[0 .. -3]
+ elsif line[-1] == ?\n
+ line = line[0 .. -2]
+ end
+ callback.call(line)
+ end
+ conn.close
+ voidresp
+ end
+ end
+
+ def storbinary(cmd, file, blocksize, callback = nil)
+ if iterator?
+ callback = Proc.new
+ end
+ use_callback = callback.is_a?(Proc)
+ synchronize do
+ voidcmd("TYPE I")
+ conn = transfercmd(cmd)
+ loop do
+ buf = file.read(blocksize)
+ break if buf == nil
+ conn.write(buf)
+ callback.call(buf) if use_callback
+ end
+ conn.close
+ voidresp
+ end
+ end
- def getbinaryfile(remotefile, localfile,
- blocksize, callback = nil)
- if iterator?
- callback = Proc.new
- end
- use_callback = callback.is_a?(Proc)
- f = open(localfile, "w")
- begin
+ def storlines(cmd, file, callback = nil)
+ if iterator?
+ callback = Proc.new
+ end
+ use_callback = callback.is_a?(Proc)
+ synchronize do
+ voidcmd("TYPE A")
+ conn = transfercmd(cmd)
+ loop do
+ buf = file.gets
+ break if buf == nil
+ if buf[-2, 2] != CRLF
+ if buf[-1] == ?\r or
+ buf[-1] == ?\n
+ buf = buf[0 .. -2]
+ end
+ buf = buf + CRLF
+ end
+ conn.write(buf)
+ callback.call(buf) if use_callback
+ end
+ conn.close
+ voidresp
+ end
+ end
+
+ def getbinaryfile(remotefile, localfile, blocksize, callback = nil)
+ if iterator?
+ callback = Proc.new
+ end
+ use_callback = callback.is_a?(Proc)
+ f = open(localfile, "w")
+ begin
f.binmode
- retrbinary("RETR " + remotefile, blocksize) do |data|
- f.write(data)
- if use_callback
- callback.call(data)
- end
- end
- ensure
- f.close
+ retrbinary("RETR " + remotefile, blocksize) do |data|
+ f.write(data)
+ callback.call(data) if use_callback
end
- end
+ ensure
+ f.close
+ end
+ end
- def gettextfile(remotefile, localfile, callback = nil)
- if iterator?
- callback = Proc.new
- end
- use_callback = callback.is_a?(Proc)
- f = open(localfile, "w")
- begin
- retrlines("RETR " + remotefile) do |line|
- line = line + @return_code
- f.write(line)
- if use_callback
- callback.call(line)
- end
- end
- ensure
- f.close
- end
- end
+ def gettextfile(remotefile, localfile, callback = nil)
+ if iterator?
+ callback = Proc.new
+ end
+ use_callback = callback.is_a?(Proc)
+ f = open(localfile, "w")
+ begin
+ retrlines("RETR " + remotefile) do |line|
+ line = line + @return_code
+ f.write(line)
+ callback.call(line) if use_callback
+ end
+ ensure
+ f.close
+ end
+ end
- def putbinaryfile(localfile, remotefile,
- blocksize, callback = nil)
- if iterator?
- callback = Proc.new
- end
- use_callback = callback.is_a?(Proc)
- f = open(localfile)
- begin
+ def putbinaryfile(localfile, remotefile, blocksize, callback = nil)
+ if iterator?
+ callback = Proc.new
+ end
+ use_callback = callback.is_a?(Proc)
+ f = open(localfile)
+ begin
f.binmode
- storbinary("STOR " + remotefile, f, blocksize) do |data|
- if use_callback
- callback.call(data)
- end
- end
- ensure
- f.close
+ storbinary("STOR " + remotefile, f, blocksize) do |data|
+ callback.call(data) if use_callback
end
- end
-
- def puttextfile(localfile, remotefile, callback = nil)
- if iterator?
- callback = Proc.new
- end
- use_callback = callback.is_a?(Proc)
- f = open(localfile)
- begin
- storlines("STOR " + remotefile, f) do |line|
- if use_callback
- callback.call(line)
- end
- end
- ensure
- f.close
- end
- end
-
- def acct(account)
- cmd = "ACCT " + account
- voidcmd(cmd)
- end
+ ensure
+ f.close
+ end
+ end
+
+ def puttextfile(localfile, remotefile, callback = nil)
+ if iterator?
+ callback = Proc.new
+ end
+ use_callback = callback.is_a?(Proc)
+ f = open(localfile)
+ begin
+ storlines("STOR " + remotefile, f) do |line|
+ callback.call(line) if use_callback
+ end
+ ensure
+ f.close
+ end
+ end
- def nlst(dir = nil)
- cmd = "NLST"
- if dir
- cmd = cmd + " " + dir
- end
- files = []
+ def acct(account)
+ cmd = "ACCT " + account
+ voidcmd(cmd)
+ end
+
+ def nlst(dir = nil)
+ cmd = "NLST"
+ if dir
+ cmd = cmd + " " + dir
+ end
+ files = []
+ retrlines(cmd) do |line|
+ files.push(line)
+ end
+ return files
+ end
+
+ def list(*args, &block)
+ cmd = "LIST"
+ args.each do |arg|
+ cmd = cmd + " " + arg
+ end
+ if block
+ retrlines(cmd, &block)
+ else
+ lines = []
retrlines(cmd) do |line|
- files.push(line)
+ lines << line
end
- files
- end
-
- def list(*args)
- cmd = "LIST"
- if iterator?
- callback = Proc.new
- elsif args[-1].is_a?(Proc)
- callback = args.pop
- else
- callback = nil
- end
- args.each do |arg|
- cmd = cmd + " " + arg
- end
- retrlines(cmd, callback)
- end
- alias ls list
- alias dir list
-
- def rename(fromname, toname)
- resp = sendcmd("RNFR " + fromname)
- if resp[0] != ?3
- raise FTPReplyError, resp
- end
- voidcmd("RNTO " + toname)
- end
-
- def delete(filename)
- resp = sendcmd("DELE " + filename)
- if resp[0, 3] == "250"
- return
- elsif resp[0] == ?5
- raise FTPPermError, resp
- else
- raise FTPReplyError, resp
- end
- end
-
- def chdir(dirname)
- if dirname == ".."
- begin
- voidcmd("CDUP")
- return
- rescue FTPPermError
- if $![0, 3] != "500"
- raise FTPPermError, $!
- end
- end
- end
- cmd = "CWD " + dirname
- voidcmd(cmd)
- end
-
- def size(filename)
- resp = sendcmd("SIZE " + filename)
- if resp[0, 3] == "213"
- return Integer(resp[3 .. -1].strip)
- end
- end
-
- def mkdir(dirname)
- resp = sendcmd("MKD " + dirname)
- return parse257(resp)
- end
-
- def rmdir(dirname)
- voidcmd("RMD " + dirname)
- end
+ return lines
+ end
+ end
+ alias ls list
+ alias dir list
+
+ def rename(fromname, toname)
+ resp = sendcmd("RNFR " + fromname)
+ if resp[0] != ?3
+ raise FTPReplyError, resp
+ end
+ voidcmd("RNTO " + toname)
+ end
+
+ def delete(filename)
+ resp = sendcmd("DELE " + filename)
+ if resp[0, 3] == "250"
+ return
+ elsif resp[0] == ?5
+ raise FTPPermError, resp
+ else
+ raise FTPReplyError, resp
+ end
+ end
+
+ def chdir(dirname)
+ if dirname == ".."
+ begin
+ voidcmd("CDUP")
+ return
+ rescue FTPPermError
+ if $![0, 3] != "500"
+ raise FTPPermError, $!
+ end
+ end
+ end
+ cmd = "CWD " + dirname
+ voidcmd(cmd)
+ end
- def pwd
- resp = sendcmd("PWD")
+ def size(filename)
+ voidcmd("TYPE I")
+ resp = sendcmd("SIZE " + filename)
+ if resp[0, 3] != "213"
+ raise FTPReplyError, resp
+ end
+ return resp[3..-1].strip
+ end
+
+ MDTM_REGEXP = /^(\d\d\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)$/
+
+ def mtime(filename, local = false)
+ str = mdtm(filename)
+ ary = str.scan(MDTM_REGEXP)[0].collect {|i| i.to_i}
+ return local ? Time.local(*ary) : Time.gm(*ary)
+ end
+
+ def mkdir(dirname)
+ resp = sendcmd("MKD " + dirname)
+ return parse257(resp)
+ end
+
+ def rmdir(dirname)
+ voidcmd("RMD " + dirname)
+ end
+
+ def pwd
+ resp = sendcmd("PWD")
return parse257(resp)
- end
- alias getdir pwd
-
- def system
- resp = sendcmd("SYST")
- if resp[0, 3] != "215"
- raise FTPReplyError, resp
- end
- return resp[4 .. -1]
- end
-
- def abort
- line = "ABOR" + CRLF
- resp = ""
- sock_synchronize do
- print "put: ABOR\n" if @debug_mode
- @sock.send(line, Socket::MSG_OOB)
- resp = getmultiline
- end
- unless ["426", "226", "225"].include?(resp[0, 3])
- raise FTPProtoError, resp
- end
- resp
- end
-
- def status
- line = "STAT" + CRLF
- resp = ""
- sock_synchronize do
- print "put: STAT\n" if @debug_mode
- @sock.send(line, Socket::MSG_OOB)
- resp = getresp
- end
- resp
- end
-
- def help(arg = nil)
- cmd = "HELP"
- if arg
- cmd = cmd + " " + arg
- end
- sendcmd(cmd)
- end
-
- def quit
- voidcmd("QUIT")
- end
-
- def close
- @sock.close if @sock and not @sock.closed?
- end
+ end
+ alias getdir pwd
+
+ def system
+ resp = sendcmd("SYST")
+ if resp[0, 3] != "215"
+ raise FTPReplyError, resp
+ end
+ return resp[4 .. -1]
+ end
+
+ def abort
+ line = "ABOR" + CRLF
+ print "put: ABOR\n" if @debug_mode
+ @sock.send(line, Socket::MSG_OOB)
+ resp = getmultiline
+ unless ["426", "226", "225"].include?(resp[0, 3])
+ raise FTPProtoError, resp
+ end
+ return resp
+ end
+ def status
+ line = "STAT" + CRLF
+ print "put: STAT\n" if @debug_mode
+ @sock.send(line, Socket::MSG_OOB)
+ return getresp
+ end
+
+ def mdtm(filename)
+ resp = sendcmd("MDTM " + filename)
+ if resp[0, 3] == "213"
+ return resp[3 .. -1].strip
+ end
+ end
+
+ def help(arg = nil)
+ cmd = "HELP"
+ if arg
+ cmd = cmd + " " + arg
+ end
+ sendcmd(cmd)
+ end
+
+ def quit
+ voidcmd("QUIT")
+ end
+
+ def close
+ @sock.close if @sock and not @sock.closed?
+ end
+
def closed?
@sock == nil or @sock.closed?
end
- def parse227(resp)
- if resp[0, 3] != "227"
- raise FTPReplyError, resp
- end
- left = resp.index("(")
- right = resp.index(")")
- if left == nil or right == nil
- raise FTPProtoError, resp
- end
- numbers = resp[left + 1 .. right - 1].split(",")
- if numbers.length != 6
- raise FTPProtoError, resp
- end
- host = numbers[0, 4].join(".")
- port = (Integer(numbers[4]) << 8) + Integer(numbers[5])
- return host, port
- end
- private :parse227
-
- def parse257(resp)
- if resp[0, 3] != "257"
- raise FTPReplyError, resp
- end
- if resp[3, 2] != ' "'
- return ""
- end
- dirname = ""
- i = 5
- n = resp.length
- while i < n
- c = resp[i, 1]
- i = i + 1
- if c == '"'
- if i > n or resp[i, 1] != '"'
- break
- end
- i = i + 1
- end
- dirname = dirname + c
- end
- return dirname
- end
- private :parse257
+ def parse227(resp)
+ if resp[0, 3] != "227"
+ raise FTPReplyError, resp
+ end
+ left = resp.index("(")
+ right = resp.index(")")
+ if left == nil or right == nil
+ raise FTPProtoError, resp
+ end
+ numbers = resp[left + 1 .. right - 1].split(",")
+ if numbers.length != 6
+ raise FTPProtoError, resp
+ end
+ host = numbers[0, 4].join(".")
+ port = (numbers[4].to_i << 8) + numbers[5].to_i
+ return host, port
+ end
+ private :parse227
+
+ def parse257(resp)
+ if resp[0, 3] != "257"
+ raise FTPReplyError, resp
+ end
+ if resp[3, 2] != ' "'
+ return ""
+ end
+ dirname = ""
+ i = 5
+ n = resp.length
+ while i < n
+ c = resp[i, 1]
+ i = i + 1
+ if c == '"'
+ if i > n or resp[i, 1] != '"'
+ break
+ end
+ i = i + 1
+ end
+ dirname = dirname + c
+ end
+ return dirname
+ end
+ private :parse257
end
+
+## ftplib.rb ends here
diff --git a/lib/getoptlong.rb b/lib/getoptlong.rb
new file mode 100644
index 0000000..98a73ae
--- /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_flag = 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_flag
+
+ @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 6929f7e..9e1e8a2 100644
--- a/lib/getopts.rb
+++ b/lib/getopts.rb
@@ -1,4 +1,3 @@
-#!/usr/local/bin/ruby
#
# getopts.rb -
# $Release Version: $
@@ -11,7 +10,7 @@
#
#
-$RCS_ID="$Header$"
+$RCS_ID=%q$Header$
def isSingle(lopt)
if lopt.index(":")
diff --git a/lib/importenv.rb b/lib/importenv.rb
index 4125376..10b2891 100644
--- a/lib/importenv.rb
+++ b/lib/importenv.rb
@@ -21,9 +21,12 @@ for k,v in ENV
EOS
end
-p $TERM
-$TERM = nil
-p $TERM
-p ENV["TERM"]
-$TERM = "foo"
-p ENV["TERM"]
+if __FILE__ == $0
+ p $TERM
+ $TERM = nil
+ p $TERM
+ p ENV["TERM"]
+ $TERM = "foo"
+ p ENV["TERM"]
+end
+
diff --git a/lib/jcode.rb b/lib/jcode.rb
index 40ab48d..50b7bee 100644
--- a/lib/jcode.rb
+++ b/lib/jcode.rb
@@ -11,13 +11,13 @@ class String
alias original_succ succ
private :original_succ
- def mbchar?(c)
+ def mbchar?
if $KCODE =~ /^s/i
- c =~ /[\x81-\x9f\xe0-\xef][\x40-\x7e\x80-\xfc]/n
+ self =~ /[\x81-\x9f\xe0-\xef][\x40-\x7e\x80-\xfc]/n
elsif $KCODE =~ /^e/i
- c =~ /[\xa1-\xfe][\xa1-\xfe]/n
+ self =~ /[\xa1-\xfe][\xa1-\xfe]/n
else
- FALSE
+ false
end
end
@@ -25,12 +25,13 @@ class String
if self[-2] && self[-2] & 0x80 != 0
s = self.dup
s[-1] += 1
- s[-1] += 1 if !mbchar?(s)
+ s[-1] += 1 if !s.mbchar?
return s
else
original_succ
end
end
+ alias next succ
def upto(to)
return if self > to
@@ -41,7 +42,7 @@ class String
if self[0..-2] == to[0..-2]
first = self[-2].chr
for c in self[-1] .. to[-1]
- if mbchar?(first+c.chr)
+ if (first+c.chr).mbchar?
yield self[0..-2]+c.chr
end
end
@@ -103,7 +104,7 @@ class String
end
def tr(from, to)
- self.dup.tr!(from, to)
+ (str = self.dup).tr!(from, to) or str
end
def delete!(del)
@@ -126,7 +127,7 @@ class String
end
def delete(del)
- self.dup.delete!(del)
+ (str = self.dup).delete!(del) or str
end
def squeeze!(del=nil)
@@ -154,7 +155,7 @@ class String
end
def squeeze(del=nil)
- self.dup.squeeze!(del)
+ (str = self.dup).squeeze!(del) or str
end
def tr_s!(from, to)
@@ -187,7 +188,7 @@ class String
end
def tr_s(from, to)
- self.dup.tr_s!(from,to)
+ (str = self.dup).tr_s!(from,to) or str
end
alias original_chop! chop!
@@ -201,7 +202,7 @@ class String
end
def chop
- self.dup.chop!
+ (str = self.dup).chop! or str
end
end
$VERBOSE = $vsave
diff --git a/lib/mailread.rb b/lib/mailread.rb
index a5d60c8..5e46606 100644
--- a/lib/mailread.rb
+++ b/lib/mailread.rb
@@ -1,7 +1,7 @@
class Mail
def initialize(f)
- unless f.kind_of?(IO)
+ unless defined? f.gets
f = open(f, "r")
opened = true
end
@@ -15,7 +15,8 @@ class Mail
break if /^$/ # end of header
if /^(\S+):\s*(.*)/
- @header[attr = $1.capitalize!] = $2
+ (attr = $1).capitalize!
+ @header[attr] = $2
elsif attr
sub!(/^\s*/, '')
@header[attr] += "\n" + $_
diff --git a/lib/mathn.rb b/lib/mathn.rb
index fdf27f6..265ef13 100644
--- a/lib/mathn.rb
+++ b/lib/mathn.rb
@@ -1,8 +1,8 @@
#
# mathn.rb -
# $Release Version: 0.5 $
-# $Revision: 1.1 $
-# $Date: 1997/07/03 04:43:47 $
+# $Revision: 1.1.1.1.4.1 $
+# $Date: 1998/01/16 12:36:05 $
# by Keiju ISHITSUKA(SHL Japan Inc.)
#
# --
@@ -96,6 +96,7 @@ class Prime
@counts.push @seed + @seed
return @seed
end
+ alias next succ
def each
loop do
diff --git a/lib/matrix.rb b/lib/matrix.rb
index 394c66f..64b0738 100644
--- a/lib/matrix.rb
+++ b/lib/matrix.rb
@@ -1,9 +1,8 @@
-#!/usr/local/bin/ruby
#
# matrix.rb -
# $Release Version: 1.0$
-# $Revision: 1.0 $
-# $Date: 97/05/23 11:35:28 $
+# $Revision: 1.6 $
+# $Date: 1998/07/31 03:39:49 $
# Original Version from Smalltalk-80 version
# on July 23, 1985 at 8:37:17 am
# by Keiju ISHITSUKA
@@ -18,9 +17,158 @@
# :
# rown]
#
-# column: 列
-# row: 行
#
+# module ExceptionForMatrix::
+# Exceptions:
+# ErrDimensionMismatch
+# number of column/row do not match
+# ErrNotRegular
+# not a regular matrix
+# ErrOperationNotDefined
+# specified operator is not defined (yet)
+#
+# class Matrix
+# include ExceptionForMatrix
+#
+# Methods:
+# class methods:
+# Matrix.[](*rows)
+# 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)
+# creates a matrix where `rows' indicates rows.
+# if optional argument `copy' is false, use the array as
+# internal structure of the metrix without copying.
+# Matrix.columns(columns)
+# creates a new matrix using `columns` as set of colums vectors.
+# Matrix.diagonal(*values)
+# creates a matrix where `columns' indicates columns.
+# Matrix.scalar(n, value)
+# creates a diagonal matrix such that the diagal compornents is
+# given by `values'.
+# Matrix.scalar(n, value)
+# creates an n-by-n scalar matrix such that the diagal compornent is
+# given by `value'.
+# Matrix.identity(n)
+# Matrix.unit(n)
+# Matrix.I(n)
+# creates an n-by-n unit matrix.
+# Matrix.zero(n)
+# creates an n-by-n zero matrix.
+# Matrix.row_vector(row)
+# creates a 1-by-n matrix such the row vector is `row'.
+# `row' is specifed as a Vector or an Array.
+# Matrix.column_vector(column)
+# creates a 1-by-n matrix such that column vector is `column'.
+# `column' is specifed as a Vector or an Array.
+# accessing:
+# [](i, j)
+# returns (i,j) compornent
+# row_size
+# returns the number of rows
+# column_size
+# returns the number of columns
+# row(i)
+# returns the i-th row vector.
+# when the block is supplied for the method, the block is iterated
+# over all row vectors.
+# column(j)
+# returns the jth column vector.
+# when the block is supplied for the method, the block is iterated
+# over all column vectors.
+# collect
+# map
+# creates a matrix which is the result of iteration of given
+# block over all compornents.
+# minor(*param)
+# returns sub matrix. parameter is specified as the following:
+# 1. from_row, row_size, from_col, size_col
+# 2. from_row..to_row, from_col..to_col
+# TESTING:
+# regular?
+# Is regular?
+# singular?
+# Is singular? i.e. Is non-regular?
+# square?
+# Is square?
+# ARITHMETIC:
+# *(m)
+# times
+# +(m)
+# plus
+# -(m)
+# minus
+# /(m)
+# self * m.inv
+# inverse
+# inv
+# inverse
+# **
+# power
+# Matrix functions:
+# determinant
+# det
+# returns the determinant
+# rank
+# returns the rank
+# trace
+# tr
+# returns the trace
+# transpose
+# t
+# returns the transposed
+# CONVERTING:
+# coerce(other)
+# row_vectors
+# array of row vectors
+# column_vectors
+# array of column vectors
+# to_a
+# converts each element to Array
+# to_f
+# converts each element to Float
+# to_i
+# converts each element to Integer
+# to_r
+# converts each element to Rational
+# PRINTING:
+# to_s
+# returns string representation
+# inspect
+#
+# class Vector
+# include ExceptionForMatrix
+#
+# INSTANCE CREATION:
+# Vector.[](*array)
+# Vector.elements(array, copy = TRUE)
+# ACCSESSING:
+# [](i)
+# size
+# ENUMRATIONS:
+# each2(v)
+# collect2(v)
+# ARITHMETIC:
+# *(x) "is matrix or number"
+# +(v)
+# -(v)
+# VECTOR FUNCTIONS:
+# inner_product(v)
+# collect
+# map
+# map2(v)
+# r
+# CONVERTING:
+# covector
+# to_a
+# to_f
+# to_i
+# to_r
+# coerce(other)
+# PRINTING:
+# to_s
+# inspect
require "e2mmap.rb"
@@ -36,8 +184,8 @@ module ExceptionForMatrix
end
class Matrix
- RCS_ID='-$Header: ruby-mode,v 1.2 91/04/20 17:24:57 keiju Locked $-'
-
+ @RCS_ID='-$Id: matrix.rb,v 1.6 1998/07/31 03:39:49 keiju Exp keiju $-'
+
include ExceptionForMatrix
# instance creations
@@ -144,6 +292,7 @@ class Matrix
if iterator?
for e in @rows[i]
yield e
+
end
else
Vector.elements(@rows[i])
@@ -211,6 +360,38 @@ class Matrix
column_size == row_size
end
+ # COMPARING
+ def ==(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
+
+ 0.upto(@rows.size - 1) do
+ |i|
+ return FALSE unless @rows[i] == rows[i]
+ end
+ TRUE
+ end
+
+ def clone
+ Matrix.rows(@rows)
+ end
+
+ def hash
+ value = 0
+ for row in @rows
+ for e in row
+ value ^= e.hash
+ end
+ end
+ return value
+ end
+
# ARITHMETIC
def *(m) #is matrix or vector or number"
@@ -297,6 +478,25 @@ class Matrix
}
Matrix.rows(rows, FALSE)
end
+
+ def /(other)
+ case other
+ when Numeric
+ rows = @rows.collect {
+ |row|
+ row.collect {
+ |e|
+ e / other
+ }
+ }
+ return Matrix.rows(rows, FALSE)
+ when Matrix
+ return self * other.inverse
+ else
+ x, y = other.coerce(self)
+ rerurn x / y
+ end
+ end
def inverse
Matrix.fail ErrDimensionMismatch unless square?
@@ -597,13 +797,12 @@ end
#----------------------------------------------------------------------
class Vector
include ExceptionForMatrix
-
#INSTANCE CREATION
private_class_method :new
def Vector.[](*array)
- new(:init_elements, array, copy = FALSE)
+ new(:init_elements, array, FALSE)
end
def Vector.elements(array, copy = TRUE)
@@ -649,6 +848,26 @@ class Vector
end
end
+ # COMPARING
+ def ==(other)
+ return FALSE unless Vector === other
+
+ other.compare_by(@elements)
+ end
+ alias eqn? ==
+
+ def compare_by(elements)
+ @elements == elements
+ end
+
+ def clone
+ Vector.elements(@elements)
+ end
+
+ def hash
+ @elements.hash
+ end
+
# ARITHMETIC
def *(x) "is matrix or number"
@@ -733,7 +952,7 @@ class Vector
for e in @elements
v += e*e
end
- return v.sqrt
+ return Math.sqrt(v)
end
# CONVERTING
diff --git a/lib/mkmf.rb b/lib/mkmf.rb
index 2bf3684..7e131fe 100644
--- a/lib/mkmf.rb
+++ b/lib/mkmf.rb
@@ -1,7 +1,8 @@
-# module to create Makefile for extention modules
+# module to create Makefile for extension modules
# invoke like: ruby -r mkmf extconf.rb
require 'rbconfig'
+require 'find'
include Config
@@ -36,6 +37,7 @@ $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"
@@ -47,28 +49,60 @@ else
exit 1
end
-nul = "> /dev/null"
-
CFLAGS = CONFIG["CFLAGS"]
if PLATFORM == "m68k-human"
- nul = "> nul"
CFLAGS.gsub!(/-c..-stack=[0-9]+ */, '')
end
-if $DEBUG
- nul = ""
+if /win32|djgpp|mingw32|m68k-human/i =~ 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"
+
+$orgerr = $stderr.dup
+$orgout = $stdout.dup
+def xsystem command
+ if $DEBUG
+ print command, "\n"
+ return system(command)
+ end
+ $stderr.reopen($null)
+ $stdout.reopen($null)
+ r = system(command)
+ $stderr.reopen($orgerr)
+ $stdout.reopen($orgout)
+ return r
end
-LINK = CONFIG["CC"]+" -o conftest -I#{$srcdir} " + CFLAGS + " %s " + CONFIG["LDFLAGS"] + " %s conftest.c " + CONFIG["LIBS"] + "%s " + nul + " 2>&1"
-CPP = CONFIG["CPP"] + " -E -I#{$srcdir} " + CFLAGS + " %s conftest.c " + nul + " 2>&1"
def try_link(libs)
- system(format(LINK, $CFLAGS, $LDFLAGS, libs))
+ xsystem(format(LINK, $CFLAGS, $LDFLAGS, libs))
end
def try_cpp
- system(format(CPP, $CFLAGS))
+ xsystem(format(CPP, $CFLAGS))
+end
+
+def install_rb(mfile)
+ path = []
+ dir = []
+ Find.find("lib") do |f|
+ next unless /\.rb$/ =~ f
+ f = f[4..-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
+ end
+ for f in path
+ mfile.printf "\t$(INSTALL_DATA) lib/%s $(libdir)/%s\n", f, f
+ end
end
-def have_library(lib, func)
+def have_library(lib, func="main")
printf "checking for %s() in -l%s... ", func, lib
STDOUT.flush
if $lib_cache[lib]
@@ -86,32 +120,40 @@ def have_library(lib, func)
end
end
- cfile = open("conftest.c", "w")
- cfile.printf "\
+ if func && func != ""
+ cfile = open("conftest.c", "w")
+ cfile.printf "\
int main() { return 0; }
int t() { %s(); return 0; }
", func
- cfile.close
+ cfile.close
- begin
+ 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
+ end
+ ensure
+ system "rm -f conftest*"
+ end
+ else
if $libs
libs = "-l" + lib + " " + $libs
else
libs = "-l" + lib
end
- unless try_link(libs)
- $lib_found[lib] = 'no'
- $found = TRUE
- print "no\n"
- return FALSE
- end
- ensure
- system "rm -f conftest*"
end
$libs = libs
- $lib_found[lib] = 'yes'
- $found = TRUE
+ $lib_cache[lib] = 'yes'
+ $cache_mod = TRUE
print "yes\n"
return TRUE
end
@@ -221,9 +263,15 @@ def create_makefile(target)
$defs.push(format("-DEXTLIB='%s'", libs.join(",")))
end
$libs = "" unless $libs
+ $DLDFLAGS = CONFIG["DLDFLAGS"]
+
+ if PLATFORM =~ /beos/
+ $libs = $libs + " -lruby"
+ $DLDFLAGS = $DLDFLAGS + " -L" + CONFIG["prefix"] + "/lib"
+ end
- if !$objs then
- $objs = Dir["*.c"]
+ unless $objs then
+ $objs = Dir["*.{c,cc}"]
for f in $objs
f.sub!(/\.(c|cc)$/, ".o")
end
@@ -239,15 +287,18 @@ SHELL = /bin/sh
srcdir = #{$srcdir}
hdrdir = #{$hdrdir}
-CC = gcc
+CC = #{CONFIG["CC"]}
-CFLAGS = #{CONFIG["CCDLFLAGS"]} -I#{$hdrdir} #{CFLAGS} #{$CFLAGS} #{$defs.join(" ")}
-DLDFLAGS = #{CONFIG["DLDFLAGS"]} #{$LDFLAGS}
+prefix = #{CONFIG["prefix"]}
+CFLAGS = #{CONFIG["CCDLFLAGS"]} -I$(hdrdir) -I#{CONFIG["includedir"]} #{CFLAGS} #{$CFLAGS} #{$defs.join(" ")}
+CXXFLAGS = $(CFLAGS)
+DLDFLAGS = #{$DLDFLAGS} #{$LDFLAGS}
LDSHARED = #{CONFIG["LDSHARED"]}
prefix = #{CONFIG["prefix"]}
exec_prefix = #{CONFIG["exec_prefix"]}
-libdir = #{$archdir}
+libdir = #{$libdir}
+archdir = #{$archdir}
#### End of system configuration section. ####
@@ -258,6 +309,7 @@ OBJS = #{$objs}
TARGET = #{target}.#{CONFIG["DLEXT"]}
INSTALL = #{$install}
+INSTALL_DATA = #{$install_data}
binsuffix = #{CONFIG["binsuffix"]}
@@ -269,21 +321,20 @@ clean:; @rm -f *.o *.so *.sl
realclean: clean
-install: $(libdir)/$(TARGET)
+install: $(archdir)/$(TARGET)
-$(libdir)/$(TARGET): $(TARGET)
+$(archdir)/$(TARGET): $(TARGET)
@test -d $(libdir) || mkdir $(libdir)
- $(INSTALL) $(TARGET) $(libdir)/$(TARGET)
+ @test -d $(archdir) || mkdir $(archdir)
+ $(INSTALL) $(TARGET) $(archdir)/$(TARGET)
EOMF
- for rb in Dir["lib/*.rb"]
- mfile.printf "\t$(INSTALL) %s %s\n", rb, $libdir
- end
+ install_rb(mfile)
mfile.printf "\n"
if CONFIG["DLEXT"] != "o"
mfile.printf <<EOMF
$(TARGET): $(OBJS)
- $(LDSHARED) $(DLDFLAGS) -o $(TARGET) $(OBJS) $(LOCAL_LIBS) $(LIBS)
+ $(LDSHARED) $(DLDFLAGS) -o $(TARGET) $(OBJS) $(LIBS) $(LOCAL_LIBS)
EOMF
elsif not File.exist?(target + ".c") and not File.exist?(target + ".cc") or
mfile.print "$(TARGET): $(OBJS)\n"
@@ -332,12 +383,19 @@ EOMF
rescue
end
end
+
+ if PLATFORM =~ /beos/
+ print "creating ruby.def\n"
+ open("ruby.def", "w") do |file|
+ file.print("EXPORTS\n") if PLATFORM =~ /^i/
+ file.print("Init_#{target}\n")
+ end
+ end
end
-$local_libs = nil
-$libs = nil
+$libs = PLATFORM =~ /cygwin32|beos/ ? nil : "-lc"
$objs = nil
-$CFLAGS = nil
-$LDFLAGS = nil
+$local_libs = ""
+$CFLAGS = ""
+$LDFLAGS = ""
$defs = []
-
diff --git a/lib/monitor.rb b/lib/monitor.rb
new file mode 100644
index 0000000..81fe8f2
--- /dev/null
+++ b/lib/monitor.rb
@@ -0,0 +1,325 @@
+## monitor.rb
+
+# Author: Shugo Maeda <shugo@po.aianet.ne.jp>
+# Version: $Revision: 0.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
+# }
+
+# ATTENTION:
+#
+# If you include MonitorMixin and override `initialize', you should
+# call `super'.
+# If you include MonitorMixin to built-in classes, you should override
+# `new' to call `mon_initialize'.
+
+## Code:
+
+require "final"
+
+module MonitorMixin
+
+ RCS_ID = %q$Id: monitor.rb,v 0.1 1998/03/01 08:40:18 shugo Exp shugo $
+
+ module Primitive
+
+ include MonitorMixin
+
+ MON_OWNER_TABLE = {}
+ MON_COUNT_TABLE = {}
+ MON_ENTERING_QUEUE_TABLE = {}
+ MON_WAITING_QUEUE_TABLE = {}
+
+ FINALIZER = Proc.new { |id|
+ MON_OWNER_TABLE.delete(id)
+ MON_COUNT_TABLE.delete(id)
+ MON_ENTERING_QUEUE_TABLE.delete(id)
+ MON_WAITING_QUEUE_TABLE.delete(id)
+ }
+
+ def self.extend_object(obj)
+ super(obj)
+ obj.mon_initialize
+ end
+
+ def mon_initialize
+ MON_OWNER_TABLE[id] = nil
+ MON_COUNT_TABLE[id] = 0
+ MON_ENTERING_QUEUE_TABLE[id] = []
+ MON_WAITING_QUEUE_TABLE[id] = []
+ ObjectSpace.define_finalizer(self, FINALIZER)
+ end
+
+ def mon_owner
+ return MON_OWNER_TABLE[id]
+ end
+
+ def mon_count
+ return MON_COUNT_TABLE[id]
+ end
+
+ def mon_entering_queue
+ return MON_ENTERING_QUEUE_TABLE[id]
+ end
+
+ def mon_waiting_queue
+ return MON_WAITING_QUEUE_TABLE[id]
+ end
+
+ def set_mon_owner(val)
+ return MON_OWNER_TABLE[id] = val
+ end
+
+ def set_mon_count(val)
+ return MON_COUNT_TABLE[id] = val
+ end
+
+ private :mon_count, :mon_entering_queue, :mon_waiting_queue,
+ :set_mon_owner, :set_mon_count
+ end
+
+ module NonPrimitive
+
+ include MonitorMixin
+
+ attr_reader :mon_owner, :mon_count,
+ :mon_entering_queue, :mon_waiting_queue
+
+ def self.extend_object(obj)
+ super(obj)
+ obj.mon_initialize
+ end
+
+ def mon_initialize
+ @mon_owner = nil
+ @mon_count = 0
+ @mon_entering_queue = []
+ @mon_waiting_queue = []
+ end
+
+ def set_mon_owner(val)
+ @mon_owner = val
+ end
+
+ def set_mon_count(val)
+ @mon_count = val
+ end
+
+ private :mon_count, :mon_entering_queue, :mon_waiting_queue,
+ :set_mon_owner, :set_mon_count
+ end
+
+ def self.extendable_module(obj)
+ if Fixnum === obj or TrueClass === obj or FalseClass === obj or
+ NilClass === obj
+ raise TypeError, "MonitorMixin can't extend #{obj.type}"
+ else
+ begin
+ obj.instance_eval("@mon_owner")
+ return NonPrimitive
+ rescue TypeError
+ return Primitive
+ end
+ end
+ end
+
+ def self.extend_object(obj)
+ obj.extend(extendable_module(obj))
+ end
+
+ def self.includable_module(klass)
+ if klass.instance_of?(Module)
+ return NonPrimitive
+ end
+ begin
+ dummy = klass.new
+ return extendable_module(dummy)
+ rescue ArgumentError
+ if klass.singleton_methods.include?("new")
+ return Primitive
+ else
+ return NonPrimitive
+ end
+ rescue NameError
+ raise TypeError, "#{klass} can't include MonitorMixin"
+ end
+ end
+
+ def self.append_features(klass)
+ mod = includable_module(klass)
+ klass.module_eval("include mod")
+ end
+
+ def initialize(*args)
+ super
+ mon_initialize
+ end
+
+ def try_mon_enter
+ result = false
+ Thread.critical = true
+ if mon_owner.nil?
+ set_mon_owner(Thread.current)
+ end
+ if mon_owner == Thread.current
+ set_mon_count(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
+ set_mon_owner(Thread.current)
+ set_mon_count(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
+ set_mon_count(mon_count - 1)
+ if mon_count == 0
+ set_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
+
+ class ConditionVariable
+ def initialize(monitor)
+ @monitor = monitor
+ @waiters = []
+ end
+
+ def wait
+ if @monitor.mon_owner != Thread.current
+ raise ThreadError, "current thread not owner"
+ end
+
+ @monitor.instance_eval(<<MON_EXIT)
+ Thread.critical = true
+ _count = mon_count
+ set_mon_count(0)
+ set_mon_owner(nil)
+ if mon_waiting_queue.empty?
+ t = mon_entering_queue.shift
+ else
+ t = mon_waiting_queue.shift
+ end
+ t.wakeup if t
+ Thread.critical = false
+MON_EXIT
+
+ Thread.critical = true
+ @waiters.push(Thread.current)
+ Thread.stop
+
+ @monitor.instance_eval(<<MON_ENTER)
+ Thread.critical = true
+ while mon_owner != nil && mon_owner != Thread.current
+ mon_waiting_queue.push(Thread.current)
+ Thread.stop
+ Thread.critical = true
+ end
+ set_mon_owner(Thread.current)
+ set_mon_count(_count)
+ Thread.critical = false
+MON_ENTER
+ 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
+ end
+
+ def new_cond
+ return ConditionVariable.new(self)
+ 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
+
+## monitor.rb ends here
diff --git a/lib/mutex_m.rb b/lib/mutex_m.rb
index 823888e..4b8d644 100644
--- a/lib/mutex_m.rb
+++ b/lib/mutex_m.rb
@@ -1,8 +1,8 @@
#
# mutex_m.rb -
# $Release Version: 2.0$
-# $Revision: 1.2 $
-# $Date: 1997/07/25 02:43:21 $
+# $Revision: 1.7 $
+# $Date: 1998/02/27 04:28:57 $
# Original from mutex.rb
# by Keiju ISHITSUKA(SHL Japan Inc.)
#
@@ -18,21 +18,50 @@
require "finalize"
module Mutex_m
- def Mutex_m.extend_object(obj)
+ 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
- eval "class << obj
- @mu_locked
- end"
- obj.extend(For_primitive_object)
+ obj.instance_eval "@mu_locked"
+ For_general_object
rescue TypeError
- obj.extend(For_general_object)
+ For_primitive_object
end
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
+ }
+ end
+
+ def Mutex_m.extend_object(obj)
+ obj.extend(Mutex_m.extendable_module(obj))
+ end
+
def mu_extended
unless (defined? locked? and
defined? lock and
@@ -40,7 +69,7 @@ module Mutex_m
defined? try_lock and
defined? synchronize)
eval "class << self
- alias locked mu_locked?
+ alias locked? mu_locked?
alias lock mu_lock
alias unlock mu_unlock
alias try_lock mu_try_lock
@@ -49,6 +78,7 @@ module Mutex_m
end
end
+ # locking
def mu_synchronize
begin
mu_lock
@@ -58,6 +88,7 @@ module Mutex_m
end
end
+ # internal class
module For_general_object
include Mutex_m
@@ -118,10 +149,16 @@ module Mutex_m
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)
@@ -146,7 +183,7 @@ module Mutex_m
ret = FALSE
else
Mu_Locked[self.id] = []
- Finalizer.set(self, For_primitive_object, :mu_delete_Locked)
+ Finalizer.add(self, For_primitive_object, :mu_finalize)
ret = TRUE
end
Thread.critical = FALSE
@@ -159,7 +196,7 @@ module Mutex_m
Thread.stop
end
Mu_Locked[self.id] = []
- Finalizer.add(self, For_primitive_object, :mu_delete_Locked)
+ Finalizer.add(self, For_primitive_object, :mu_finalize)
Thread.critical = FALSE
self
end
@@ -180,4 +217,3 @@ module Mutex_m
end
end
-
diff --git a/lib/observer.rb b/lib/observer.rb
index b802dac..5928367 100644
--- a/lib/observer.rb
+++ b/lib/observer.rb
@@ -30,9 +30,11 @@ module Observable
@observer_state
end
def notify_observers(*arg)
- if @observer_peers and @observer_state
- for i in @observer_peers
- i.update(*arg)
+ if @observer_state
+ if @observer_peers
+ for i in @observer_peers
+ i.update(*arg)
+ end
end
@observer_state = FALSE
end
diff --git a/lib/open3.rb b/lib/open3.rb
new file mode 100644
index 0000000..e8ba278
--- /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 = pipe # pipe[0] for read, pipe[1] for write
+ pr = pipe
+ pe = 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/parsearg.rb b/lib/parsearg.rb
index a0ef90f..b9f41d5 100644
--- a/lib/parsearg.rb
+++ b/lib/parsearg.rb
@@ -1,4 +1,3 @@
-#!/usr/local/bin/ruby
#
# parsearg.rb - parse arguments
# $Release Version: $
@@ -11,9 +10,9 @@
#
#
-$RCS_ID="$Header$"
+$RCS_ID=%q$Header$
-load("getopts.rb")
+require "getopts"
def printUsageAndExit()
if $USAGE
diff --git a/lib/parsedate.rb b/lib/parsedate.rb
index 1c1dda7..68550c6 100644
--- a/lib/parsedate.rb
+++ b/lib/parsedate.rb
@@ -4,39 +4,68 @@ module ParseDate
'may' => 5, 'jun' => 6, 'jul' => 7, 'aug' => 8,
'sep' => 9, 'oct' =>10, 'nov' =>11, 'dec' =>12 }
MONTHPAT = MONTHS.keys.join('|')
- DAYPAT = 'mon|tue|wed|thu|fri|sat|sun'
+ DAYS = {
+ 'sun' => 0, 'mon' => 1, 'tue' => 2, 'wed' => 3,
+ 'thu' => 4, 'fri' => 5, 'sat' => 6 }
+ DAYPAT = DAYS.keys.join('|')
def parsedate(date)
- if date.sub!(/(#{DAYPAT})/i, ' ')
- dayofweek = $1
+ # part of ISO 8601
+ # yyyy-mm-dd | yyyy-mm | yyyy
+ # date hh:mm:ss | date Thh:mm:ss
+ if date =~ /^(\d\d\d\d)-?(?:(\d\d)-?(\d\d)?)? *T?(?:(\d\d):?(\d\d):?(\d\d)?)?$/
+ return $1.to_i,
+ if $2 then $2.to_i else 1 end,
+ if $3 then $3.to_i else 1 end,
+ if $4 then $4.to_i end,
+ if $5 then $5.to_i end,
+ if $6 then $6.to_i end,
+ nil,
+ nil
end
- if date.sub!(/\s+(\d+:\d+(:\d+)?)/, ' ')
- time = $1
+ date = date.dup
+ if date.sub!(/(#{DAYPAT})[a-z]*,?/i, ' ')
+ wday = DAYS[$1.downcase]
end
- if date =~ /19(\d\d)/
- year = Integer($1)
+ if date.sub!(/(\d+):(\d+)(?::(\d+))?\s*(am|pm)?\s*(?:\s+([a-z]{1,4}(?:\s+[a-z]{1,4})?|[-+]\d{4}))?/i, ' ')
+ hour = $1.to_i
+ min = $2.to_i
+ if $3
+ sec = $3.to_i
+ end
+ if $4 == 'pm'
+ hour += 12
+ end
+ if $5
+ zone = $5
+ end
end
- if date.sub!(/\s*(\d+)\s+(#{MONTHPAT})\S*\s+/i, ' ')
- dayofmonth = $1.to_i
- monthname = $2
- elsif date.sub!(/\s*(#{MONTHPAT})\S*\s+(\d+)\s+/i, ' ')
- monthname = $1
- dayofmonth = $2.to_i
- elsif date.sub!(/\s*(#{MONTHPAT})\S*\s+(\d+)\D+/i, ' ')
- monthname = $1
- dayofmonth = $2.to_i
- elsif date.sub!(/\s*(\d\d?)\/(\d\d?)/, ' ')
- month = $1
- dayofmonth = $2.to_i
+ if date.sub!(/(\d+)\S*\s+(#{MONTHPAT})\S*(?:\s+(\d+))?/i, ' ')
+ mday = $1.to_i
+ mon = MONTHS[$2.downcase]
+ if $3
+ year = $3.to_i
+ end
+ elsif date.sub!(/(#{MONTHPAT})\S*\s+(\d+)\S*\s*,?(?:\s+(\d+))?/i, ' ')
+ mon = MONTHS[$1.downcase]
+ mday = $2.to_i
+ if $3
+ year = $3.to_i
+ end
+ elsif date.sub!(/(\d+)\/(\d+)(?:\/(\d+))/, ' ')
+ mon = $1.to_i
+ mday = $2.to_i
+ if $3
+ year = $3.to_i
+ end
end
- if monthname
- month = MONTHS[monthname.downcase]
- end
- if ! year && date =~ /\d\d/
- year = Integer($&)
- end
- return year, month, dayofmonth
+ return year, mon, mday, hour, min, sec, zone, wday
end
module_function :parsedate
end
+
+if __FILE__ == $0
+ p Time.now.asctime
+ p ParseDate.parsedate(Time.now.asctime)
+end
diff --git a/lib/ping.rb b/lib/ping.rb
index d742a50..065b1d2 100644
--- a/lib/ping.rb
+++ b/lib/ping.rb
@@ -26,6 +26,10 @@
#
# The timeout in seconds. If not specified it will default to 5 seconds.
#
+# : service
+#
+# The service port to connect. The default is "echo".
+#
#= WARNING
#
# pingecho() uses user-level thread to implement the timeout, so it may block
@@ -33,23 +37,26 @@
#
#=end
+require 'timeout'
+
module Ping
require "socket"
- def pingecho(host, timeout=5)
+ def pingecho(host, timeout=5, service="echo")
begin
- x = Thread.current
- y = Thread.start {
- sleep timeout
- x.raise RuntimeError if x.status
- }
- s = TCPsocket.new(host, "echo")
- s.close
- return TRUE
+ timeout(timeout) do
+ s = TCPsocket.new(host, service)
+ s.close
+ end
rescue
- return FALSE;
- ensure
- Thread.kill y if y.status
+ return false
end
+ return true
end
- module_function "pingecho"
+ module_function :pingecho
+end
+
+if $0 == __FILE__
+ host = ARGV[0]
+ host ||= "localhost"
+ printf("%s alive? - %s\n", host, Ping::pingecho(host, 5))
end
diff --git a/lib/profile.rb b/lib/profile.rb
new file mode 100644
index 0000000..3abcc37
--- /dev/null
+++ b/lib/profile.rb
@@ -0,0 +1,53 @@
+
+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 klass.kind_of? Class
+ name += "#"
+ else
+ name += "."
+ end
+ data = [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
+ 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/pstore.rb b/lib/pstore.rb
index 86f086d..2aa9864 100644
--- a/lib/pstore.rb
+++ b/lib/pstore.rb
@@ -1,5 +1,4 @@
-#!/usr/local/bin/ruby
-
+#
# How to use:
#
# db = PStore.new("/tmp/foo")
@@ -16,7 +15,8 @@
require "marshal"
class PStore
- Exception(:Error)
+ class Error < StandardError
+ end
def initialize(file)
dir = File::dirname(file)
@@ -89,33 +89,46 @@ class PStore
catch(:pstore_abort_transaction) do
value = yield(self)
end
+ rescue Exception
+ @abort = true
+ raise
ensure
unless @abort
- File::rename @filename, @filename+"~"
+ begin
+ File::rename @filename, @filename+"~"
+ rescue Errno::ENOENT
+ no_orig = true
+ end
begin
File::open(@filename, "w") do |file|
Marshal::dump(@table, file)
end
rescue
- File::rename @filename+"~", @filename
+ File::rename @filename+"~", @filename unless no_orig
end
end
@abort = false
end
ensure
+ @table = nil
@transaction = false
end
value
end
end
-db = PStore.new("/tmp/foo")
-db.transaction do
- p db.roots
- ary = db["root"] = [1,2,3,4]
- ary[0] = [1,1.5]
-end
+if __FILE__ == $0
+ db = PStore.new("/tmp/foo")
+ db.transaction do
+ p db.roots
+ ary = db["root"] = [1,2,3,4]
+ ary[1] = [1,1.5]
+ end
-db.transaction do
- p db["root"]
+ 1000.times do
+ db.transaction do
+ db["root"][0] += 1
+ p db["root"][0]
+ end
+ end
end
diff --git a/lib/rational.rb b/lib/rational.rb
index d4112c2..1282f56 100644
--- a/lib/rational.rb
+++ b/lib/rational.rb
@@ -1,8 +1,8 @@
#
# rational.rb -
# $Release Version: 0.5 $
-# $Revision: 1.1 $
-# $Date: 1996/11/11 04:25:14 $
+# $Revision: 1.3 $
+# $Date: 1998/03/11 14:09:03 $
# by Keiju ISHITSUKA(SHL Japan Inc.)
#
# --
@@ -44,7 +44,11 @@ def Rational(a, b = 1)
end
class Rational < Numeric
+ @RCS_ID='-$Id: rational.rb,v 1.3 1998/03/11 14:09:03 keiju Exp keiju $-'
+
def Rational.reduce(num, den = 1)
+ raise ZeroDivisionError, "denometor is 0" if den == 0
+
if den < 0
num = -num
den = -den
@@ -128,6 +132,7 @@ class Rational < Numeric
den = @denominator * a.numerator
Rational(num, den)
elsif a.kind_of?(Integer)
+ raise ZeroDivisionError, "devided by 0" if a == 0
self / Rational.new!(a, 1)
elsif a.kind_of?(Float)
Float(self) / a
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 9632f12..9154cd8 100644
--- a/lib/shellwords.rb
+++ b/lib/shellwords.rb
@@ -18,21 +18,19 @@ module Shellwords
while line != ''
field = ''
while TRUE
- if line.sub! /^"(([^"\\]|\\.)*)"/, '' then
+ if line.sub! /^"(([^"\\]|\\.)*)"/, '' then #"
snippet = $1
snippet.gsub! /\\(.)/, '\1'
- elsif line =~ /^"/ then
- STDOUT.print "Unmatched double quote: $_\n"
- exit
- elsif line.sub! /^'(([^'\\]|\\.)*)'/, '' then
+ elsif line =~ /^"/ then #"
+ raise ArgError, "Unmatched double quote: #{line}"
+ elsif line.sub! /^'(([^'\\]|\\.)*)'/, '' then #'
snippet = $1
snippet.gsub! /\\(.)/, '\1'
- elsif line =~ /^'/ then
- STDOUT.print "Unmatched single quote: $_\n"
- exit
+ elsif line =~ /^'/ then #'
+ raise ArgError, "Unmatched single quote: #{line}"
elsif line.sub! /^\\(.)/, '' then
snippet = $1
- elsif line.sub! /^([^\s\\'"]+)/, '' then
+ elsif line.sub! /^([^\s\\'"]+)/, '' then #'
snippet = $1
else
line.sub! /^\s+/, ''
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 b5a3fc3..9f9706d 100644
--- a/lib/sync.rb
+++ b/lib/sync.rb
@@ -4,6 +4,7 @@
# $Revision$
# $Date$
# by Keiju ISHITSUKA
+# modified by matz
#
# --
# Sync_m, Synchronizer_m
@@ -43,7 +44,7 @@ unless defined? Thread
fail "Thread not available for this ruby interpreter"
end
-require "finalize"
+require "final"
module Sync_m
RCS_ID='-$Header$-'
@@ -54,7 +55,7 @@ module Sync_m
EX = :EX
# 例外定義
- class Err < Exception
+ class Err < StandardError
def Err.Fail(*opt)
fail self, sprintf(self::Message, *opt)
end
@@ -296,8 +297,8 @@ module Sync_m
private :sync_try_lock_sub
def sync_synchronize(mode = EX)
+ sync_lock(mode)
begin
- sync_lock(mode)
yield
ensure
sync_unlock
@@ -321,7 +322,11 @@ module Sync_m
def For_primitive_object.extend_object(obj)
super
obj.sync_extended
- Finalizer.add(obj, For_primitive_object, :sync_finalize)
+ # 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
diff --git a/lib/telnet.rb b/lib/telnet.rb
new file mode 100644
index 0000000..e3c590c
--- /dev/null
+++ b/lib/telnet.rb
@@ -0,0 +1,439 @@
+#
+# telnet.rb
+# ver0.16 1998/10/09
+# Wakou Aoyama <wakou@fsinet.or.jp>
+#
+# ver0.16 1998/10/09
+# preprocess method change for the better
+# add binmode method.
+# change default Binmode
+# TRUE --> FALSE
+#
+# ver0.15 1998/10/04
+# add telnetmode method.
+#
+# ver0.141 1998/09/22
+# change default prompt
+# /[$%#>] $/ --> /[$%#>] \Z/
+#
+# ver0.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.
+#
+# ver0.13 1998/08/25
+# add print method.
+#
+# ver0.122 1998/08/05
+# support for HP-UX 10.20 thanks to WATANABE Tetsuya <tetsu@jpn.hp.com>
+# socket.<< --> socket.write
+#
+# ver0.121 1998/07/15
+# string.+= --> string.concat
+#
+# ver0.12 1998/06/01
+# add timeout, waittime.
+#
+# ver0.11 1998/04/21
+# add realtime output.
+#
+# ver0.10 1998/04/13
+# first release.
+#
+# == 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/, default: /[$%#>] \Z/
+# "Telnetmode" => TRUE, default: TRUE
+# "Timeout" => 10, default: 10
+# "Waittime" => 0}) default: 0
+#
+# if set "Telnetmode" option 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.
+#
+# == wait for match
+# line = host.waitfor(/match/)
+# line = host.waitfor({"Match" => /match/,
+# "String" => "string",
+# "Timeout" => secs})
+# if set "String" option. Match = Regexp.new(quote(string))
+#
+# realtime output. of cource, set sync=TRUE or flush is necessary.
+# host.waitfor(/match/){|c| print c }
+# host.waitfor({"Match" => /match/,
+# "String" => "string",
+# "Timeout" => secs}){|c| print c}
+#
+# == send string and wait prompt
+# line = host.cmd("string")
+# line = host.cmd({"String" => "string",
+# "Prompt" => /[$%#>] \Z/,
+# "Timeout" => 10})
+#
+# realtime output. of cource, set sync=TRUE or flush is necessary.
+# host.cmd("string"){|c| print c }
+# host.cmd({"String" => "string",
+# "Prompt" => /[$%#>] \Z/,
+# "Timeout" => 10}){|c| print c }
+#
+# == 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/,
+# "Timeout" => 10})
+#
+# realtime output. of cource, set sync=TRUE or flush is necessary.
+# host.login("username", "password"){|c| print c }
+# host.login({"Name" => "username",
+# "Password" => "password",
+# "Prompt" => /[$%#>] \Z/,
+# "Timeout" => 10}){|c| print c }
+#
+# and Telnet object has socket class methods
+#
+# == sample
+# localhost = Telnet.new({"Host" => "localhost",
+# "Timeout" => 10,
+# "Prompt" => /[$%#>] \Z/})
+# localhost.login("username", "password"){|c| print c }
+# localhost.cmd("command"){|c| print c }
+# localhost.close
+#
+# == sample 2
+# checks a POP server to see if you have mail.
+#
+# pop = Telnet.new({"Host" => "your_destination_host_here",
+# "Port" => 110,
+# "Telnetmode" => FALSE,
+# "Prompt" => /^\+OK/})
+# pop.cmd("user " + "your_username_here"){|c| print c}
+# pop.cmd("pass " + "your_password_here"){|c| print c}
+# pop.cmd("list"){|c| print c}
+
+require "socket"
+require "delegate"
+require "thread"
+
+class TimeOut < Exception
+end
+
+class Telnet < SimpleDelegator
+
+ def timeout(sec)
+ is_timeout = FALSE
+ begin
+ x = Thread.current
+ y = Thread.start {
+ sleep sec
+ if x.alive?
+ #print "timeout!\n"
+ x.raise TimeOut, "timeout"
+ end
+ }
+ begin
+ yield
+ rescue TimeOut
+ is_timeout = TRUE
+ end
+ ensure
+ Thread.kill y if y && y.alive?
+ end
+ is_timeout
+ end
+
+ IAC = 255.chr # interpret as command:
+ DONT = 254.chr # you are not to use option
+ DO = 253.chr # please, you use option
+ WONT = 252.chr # I won't use option
+ WILL = 251.chr # I will use option
+ SB = 250.chr # interpret as subnegotiation
+ GA = 249.chr # you may reverse the line
+ EL = 248.chr # erase the current line
+ EC = 247.chr # erase the current character
+ AYT = 246.chr # are you there
+ AO = 245.chr # abort output--but let prog finish
+ IP = 244.chr # interrupt process--permanently
+ BREAK = 243.chr # break
+ DM = 242.chr # data mark--for connect. cleaning
+ NOP = 241.chr # nop
+ SE = 240.chr # end sub negotiation
+ EOR = 239.chr # end of record (transparent mode)
+ ABORT = 238.chr # Abort process
+ SUSP = 237.chr # Suspend process
+ EOF = 236.chr # End of file
+ SYNCH = 242.chr # for telfunc calls
+
+ OPT_BINARY = 0.chr # Binary Transmission
+ OPT_ECHO = 1.chr # Echo
+ OPT_RCP = 2.chr # Reconnection
+ OPT_SGA = 3.chr # Suppress Go Ahead
+ OPT_NAMS = 4.chr # Approx Message Size Negotiation
+ OPT_STATUS = 5.chr # Status
+ OPT_TM = 6.chr # Timing Mark
+ OPT_RCTE = 7.chr # Remote Controlled Trans and Echo
+ OPT_NAOL = 8.chr # Output Line Width
+ OPT_NAOP = 9.chr # Output Page Size
+ OPT_NAOCRD = 10.chr # Output Carriage-Return Disposition
+ OPT_NAOHTS = 11.chr # Output Horizontal Tab Stops
+ OPT_NAOHTD = 12.chr # Output Horizontal Tab Disposition
+ OPT_NAOFFD = 13.chr # Output Formfeed Disposition
+ OPT_NAOVTS = 14.chr # Output Vertical Tabstops
+ OPT_NAOVTD = 15.chr # Output Vertical Tab Disposition
+ OPT_NAOLFD = 16.chr # Output Linefeed Disposition
+ OPT_XASCII = 17.chr # Extended ASCII
+ OPT_LOGOUT = 18.chr # Logout
+ OPT_BM = 19.chr # Byte Macro
+ OPT_DET = 20.chr # Data Entry Terminal
+ OPT_SUPDUP = 21.chr # SUPDUP
+ OPT_SUPDUPOUTPUT = 22.chr # SUPDUP Output
+ OPT_SNDLOC = 23.chr # Send Location
+ OPT_TTYPE = 24.chr # Terminal Type
+ OPT_EOR = 25.chr # End of Record
+ OPT_TUID = 26.chr # TACACS User Identification
+ OPT_OUTMRK = 27.chr # Output Marking
+ OPT_TTYLOC = 28.chr # Terminal Location Number
+ OPT_3270REGIME = 29.chr # Telnet 3270 Regime
+ OPT_X3PAD = 30.chr # X.3 PAD
+ OPT_NAWS = 31.chr # 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 # Extended-Options-List
+
+ NULL = "\000"
+ CR = "\015"
+ LF = "\012"
+ EOL = CR + LF
+
+ def initialize(options)
+ @options = options
+ @options["Binmode"] = FALSE if not @options.include?("Binmode")
+ @options["Host"] = "localhost" if not @options.include?("Host")
+ @options["Port"] = 23 if not @options.include?("Port")
+ @options["Prompt"] = /[$%#>] \Z/ if not @options.include?("Prompt")
+ @options["Telnetmode"] = TRUE if not @options.include?("Telnetmode")
+ @options["Timeout"] = 10 if not @options.include?("Timeout")
+ @options["Waittime"] = 0 if not @options.include?("Waittime")
+
+ @telnet_option = { "SGA" => FALSE, "BINARY" => FALSE }
+
+ if @options.include?("Output_log")
+ @log = File.open(@options["Output_log"], 'a+')
+ @log.sync = TRUE
+ @log.binmode
+ end
+
+ if @options.include?("Dump_log")
+ @dumplog = File.open(@options["Dump_log"], 'a+')
+ @dumplog.sync = TRUE
+ @dumplog.binmode
+ end
+
+ message = "Trying " + @options["Host"] + "...\n"
+ STDOUT.write(message)
+ @log.write(message) if @options.include?("Output_log")
+ @dumplog.write(message) if @options.include?("Dump_log")
+
+ is_timeout = timeout(@options["Timeout"]){
+ begin
+ @sock = TCPsocket.open(@options["Host"], @options["Port"])
+ rescue
+ @log.write($! + "\n") if @options.include?("Output_log")
+ @dumplog.write($! + "\n") if @options.include?("Dump_log")
+ raise
+ end
+ }
+ raise TimeOut, "timed-out; opening of the host" if is_timeout
+ @sock.sync = TRUE
+ @sock.binmode
+
+ message = "Connected to " + @options["Host"] + ".\n"
+ STDOUT.write(message)
+ @log.write(message) if @options.include?("Output_log")
+ @dumplog.write(message) if @options.include?("Dump_log")
+
+ super(@sock)
+ end
+
+ 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(str)
+
+ if not @options["Binmode"]
+ str.gsub!(/#{CR}#{NULL}/no, CR) # combine CR+NULL into CR
+ str.gsub!(/#{EOL}/no, "\n") # combine EOL into "\n"
+ end
+
+ # respond to "IAC DO x"
+ str.gsub!(/(?:(?!#{IAC}))?#{IAC}#{DO}([#{OPT_BINARY}-#{OPT_NEW_ENVIRON}#{OPT_EXOPL}])/no){
+ if OPT_BINARY == $1
+ @telnet_option["BINARY"] = TRUE
+ @sock.write(IAC + WILL + OPT_BINARY)
+ else
+ @sock.write(IAC + WONT + $1)
+ end
+ ''
+ }
+
+ # 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 + $1)
+ ''
+ }
+
+ # respond to "IAC WILL x"
+ str.gsub!(/(?:(?!#{IAC}))?#{IAC}#{WILL}([#{OPT_BINARY}-#{OPT_NEW_ENVIRON}#{OPT_EXOPL}])/no){
+ if OPT_SGA == $1
+ @telnet_option["SGA"] = TRUE
+ @sock.write(IAC + DO + OPT_SGA)
+ end
+ ''
+ }
+
+ # ignore "IAC WON'T x"
+ str.gsub!(/(?:(?!#{IAC}))?#{IAC}#{WONT}[#{OPT_BINARY}-#{OPT_NEW_ENVIRON}#{OPT_EXOPL}]/no, '')
+
+ # respond to "IAC AYT" (are you there)
+ str.gsub!(/(?:(?!#{IAC}))?#{IAC}#{AYT}/no){
+ @sock.write("nobody here but us pigeons" + EOL)
+ ''
+ }
+
+ str.gsub(/#{IAC}#{IAC}/no, IAC) # handle escaped IAC characters
+ end
+
+ def waitfor(options)
+ timeout = @options["Timeout"]
+ waittime = @options["Waittime"]
+
+ if options.kind_of?(Hash)
+ prompt = options["Prompt"] if options.include?("Prompt")
+ timeout = options["Timeout"] if options.include?("Timeout")
+ waittime = options["Waittime"] if options.include?("Waittime")
+ prompt = Regexp.new( Regexp.quote(options["String"]) ) if
+ options.include?("String")
+ else
+ prompt = options
+ end
+
+ line = ''
+ until(not select([@sock], nil, nil, waittime) and prompt === line)
+ raise TimeOut, "timed-out; wait for the next data" if
+ not select([@sock], nil, nil, timeout)
+ buf = ''
+ begin
+ buf = @sock.sysread(1024 * 1024)
+ @dumplog.print(buf) if @options.include?("Dump_log")
+ buf = preprocess(buf) if @options["Telnetmode"]
+ rescue EOFError # End of file reached
+ break
+ ensure
+ @log.print(buf) if @options.include?("Output_log")
+ yield buf if iterator?
+ line.concat(buf)
+ end
+ end
+ line
+ end
+
+ def print(string)
+ string.gsub!(/#{IAC}/no, IAC + IAC) if @options["Telnetmode"]
+ if @options["Binmode"]
+ @sock.write(string)
+ else
+ if @telnet_option["BINARY"] and @telnet_option["SGA"]
+ # IAC WILL SGA IAC DO BIN send EOL --> CR
+ @sock.write(string.gsub(/\n/, CR) + CR)
+ elsif @telnet_option["SGA"]
+ # IAC WILL SGA send EOL --> CR+NULL
+ @sock.write(string.gsub(/\n/, CR + NULL) + CR + NULL)
+ else
+ # NONE send EOL --> LF
+ @sock.write(string.gsub(/\n/, LF) + LF)
+ end
+ end
+ end
+
+ def cmd(options)
+ match = @options["Prompt"]
+ timeout = @options["Timeout"]
+
+ if options.kind_of?(Hash)
+ string = options["String"]
+ match = options["Match"] if options.include?("Match")
+ timeout = options["Timeout"] if options.include?("Timeout")
+ else
+ string = options
+ end
+
+ select(nil, [@sock])
+ print(string)
+ if iterator?
+ waitfor({"Prompt" => match, "Timeout" => timeout}){|c| yield c }
+ else
+ waitfor({"Prompt" => match, "Timeout" => timeout})
+ 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/){|c| yield c }
+ line.concat( cmd({"String" => username,
+ "Match" => /Password[: ]*\Z/}){|c| yield c } )
+ line.concat( cmd(password){|c| yield c } )
+ else
+ line = waitfor(/login[: ]*\Z/)
+ line.concat( cmd({"String" => username,
+ "Match" => /Password[: ]*\Z/}) )
+ line.concat( cmd(password) )
+ end
+ line
+ end
+
+end
diff --git a/lib/tempfile.rb b/lib/tempfile.rb
new file mode 100644
index 0000000..bf51ac2
--- /dev/null
+++ b/lib/tempfile.rb
@@ -0,0 +1,91 @@
+#
+# $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 = '/tmp')
+ umask = File.umask(0177)
+ tmpname = lock = nil
+ begin
+ n = 0
+ while true
+ begin
+ tmpname = sprintf('%s/%s.%d.%d', tmpdir, basename, $$, n)
+ lock = tmpname + '.lock'
+ unless 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
+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 4f294cc..ec75144 100644
--- a/lib/thread.rb
+++ b/lib/thread.rb
@@ -9,14 +9,20 @@ unless defined? Thread
end
unless defined? ThreadError
- class ThreadError<Exception
+ class ThreadError<StandardError
end
end
+if $DEBUG
+ Thread.abort_on_exception = true
+end
+
class Mutex
def initialize
@waiting = []
- @locked = FALSE;
+ @locked = false;
+ @waiting.taint # enable tainted comunication
+ self.taint
end
def locked?
@@ -24,42 +30,39 @@ class Mutex
end
def try_lock
- result = FALSE
- Thread.critical = TRUE
+ result = false
+ Thread.critical = true
unless @locked
- @locked = TRUE
- result = TRUE
+ @locked = true
+ result = true
end
- Thread.critical = FALSE
+ Thread.critical = false
result
end
def lock
- while (Thread.critical = TRUE; @locked)
+ while (Thread.critical = true; @locked)
@waiting.push Thread.current
Thread.stop
end
- @locked = TRUE
- Thread.critical = FALSE
+ @locked = true
+ Thread.critical = false
self
end
def unlock
return unless @locked
Thread.critical = TRUE
- wait = @waiting
- @waiting = []
+ t = @waiting.shift
@locked = FALSE
Thread.critical = FALSE
- for w in wait
- w.run
- end
+ t.run if t
self
end
def synchronize
+ lock
begin
- lock
yield
ensure
unlock
@@ -67,37 +70,74 @@ class Mutex
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 {
+ @waiters.push(Thread.current)
+ }
+ Thread.stop
+ mutex.lock
+ end
+
+ def signal
+ @waiters_mutex.synchronize {
+ t = @waiters.shift
+ t.run if t
+ }
+ end
+
+ def broadcast
+ @waiters_mutex.synchronize {
+ for t in @waiters
+ t.run
+ end
+ @waiters.clear
+ }
+ end
+end
+
class Queue
def initialize
@que = []
@waiting = []
+ @que.taint # enable tainted comunication
+ @waiting.taint
+ self.taint
end
def push(obj)
- Thread.critical = TRUE
+ Thread.critical = true
@que.push obj
t = @waiting.shift
- Thread.critical = FALSE
+ Thread.critical = false
t.run if t
end
- def pop non_block=FALSE
- item = nil
- until item
- Thread.critical = TRUE
- if @que.length == 0
- if non_block
- Thread.critical = FALSE
- raise ThreadError, "queue empty"
+ def pop non_block=false
+ Thread.critical = true
+ begin
+ loop do
+ if @que.length == 0
+ if non_block
+ raise ThreadError, "queue empty"
+ end
+ @waiting.push Thread.current
+ Thread.stop
+ else
+ return @que.shift
end
- @waiting.push Thread.current
- Thread.stop
- else
- item = @que.shift
end
+ ensure
+ Thread.critical = false
end
- Thread.critical = FALSE
- item
end
def empty?
@@ -107,4 +147,63 @@ class Queue
def length
@que.length
end
+ alias size length
+
+
+ def num_waiting
+ @waiting.size
+ end
+end
+
+class SizedQueue<Queue
+ def initialize(max)
+ @max = max
+ @queue_wait = []
+ @queue_wait.taint # enable tainted comunication
+ super()
+ end
+
+ def max
+ @max
+ end
+
+ def max=(max)
+ Thread.critical = TRUE
+ if @max >= max
+ @max = max
+ Thread.critical = FALSE
+ else
+ diff = max - @max
+ @max = max
+ Thread.critical = FALSE
+ diff.times do
+ t = @queue_wait.shift
+ t.run if t
+ end
+ end
+ max
+ end
+
+ def push(obj)
+ Thread.critical = true
+ while @que.length >= @max
+ @queue_wait.push Thread.current
+ Thread.stop
+ Thread.critical = true
+ end
+ super
+ end
+
+ def pop(*args)
+ Thread.critical = true
+ if @que.length < @max
+ t = @queue_wait.shift
+ t.run if t
+ end
+ super
+ end
+
+ def num_waiting
+ @waiting.size + @queue_wait.size
+ end
end
diff --git a/lib/thwait.rb b/lib/thwait.rb
index c638335..958163e 100644
--- a/lib/thwait.rb
+++ b/lib/thwait.rb
@@ -1,34 +1,53 @@
#
-# thwait.rb -
-# $Release Version: $
-# $Revision: 1.1 $
-# $Date: 1997/08/18 03:13:14 $
-# by Keiju ISHITSUKA(Nippon Rational Inc.)
+# thwait.rb - thread synchronization class
+# $Release Version: 0.9 $
+# $Revision: 1.3 $
+# $Date: 1998/06/26 03:19:34 $
+# by Keiju ISHITSUKA(Nihpon Rational Software Co.,Ltd.)
#
# --
+# feature:
+# provides synchronization for multiple threads.
#
-#
+# class methods:
+# * ThreadsWait.all_waits(thread1,...)
+# waits until all of specified threads are terminated.
+# if a block is supplied for the method, evaluates it for
+# each thread termination.
+# * th = ThreadsWait.new(thread1,...)
+# creates synchronization object, specifying thread(s) to wait.
+#
+# methods:
+# * th.threads
+# list threads to be synchronized
+# * th.empty?
+# is there any thread to be synchronized.
+# * th.finished?
+# is there already terminated thread.
+# * th.join(thread1,...)
+# wait for specified thread(s).
+# * th.join_nowait(threa1,...)
+# specifies thread(s) to wait. non-blocking.
+# * th.next_wait
+# waits until any of specified threads is terminated.
+# * th.all_waits
+# waits until all of specified threads are terminated.
+# if a block is supplied for the method, evaluates it for
+# each thread termination.
#
require "thread.rb"
require "e2mmap.rb"
class ThreadsWait
- RCS_ID='-$Header: /home/keiju/var/src/var.lib/ruby/RCS/thwait.rb,v 1.1 1997/08/18 03:13:14 keiju Exp keiju $-'
+ RCS_ID='-$Id: thwait.rb,v 1.3 1998/06/26 03:19:34 keiju Exp keiju $-'
Exception2MessageMapper.extend_to(binding)
- def_exception("ErrWaitThreadsNothing", "Wait threads nothing.")
- def_exception("FinshedThreadsNothing", "finished thread nothing.")
+ def_exception("ErrNoWaitingThread", "No threads for waiting.")
+ def_exception("ErrNoFinshedThread", "No finished threads.")
- # class mthods
- # all_waits
-
- #
- # 指定したスレッドが全て終了するまで待つ. イテレータとして呼ばれると
- # 指定したスレッドが終了するとイテレータを呼び出す.
- #
def ThreadsWait.all_waits(*threads)
- tw = ThreadsWait.new(th1, th2, th3, th4, th5)
+ tw = ThreadsWait.new(*threads)
if iterator?
tw.all_waits do
|th|
@@ -39,12 +58,6 @@ class ThreadsWait
end
end
- # initialize and terminating:
- # initialize
-
- #
- # 初期化. 待つスレッドの指定ができる.
- #
def initialize(*threads)
@threads = []
@wait_queue = Queue.new
@@ -52,24 +65,19 @@ class ThreadsWait
end
# accessing
- # threads
-
- # 待ちスレッドの一覧を返す.
+ # threads - list threads to be synchronized
attr :threads
# testing
# empty?
# finished?
- #
-
- #
- # 待ちスレッドが存在するかどうかを返す.
+
+ # is there any thread to be synchronized.
def empty?
@threads.empty?
end
- #
- # すでに終了したスレッドがあるかどうか返す
+ # is there already terminated thread.
def finished?
!@wait_queue.empty?
end
@@ -80,45 +88,40 @@ class ThreadsWait
# next_wait
# all_wait
- #
- # 待っているスレッドを追加し待ちにはいる.
- #
+ # adds thread(s) to join, waits for any of waiting threads to terminate.
def join(*threads)
join_nowait(*threads)
next_wait
end
- #
- # 待っているスレッドを追加する. 待ちには入らない.
- #
+ # adds thread(s) to join, no wait.
def join_nowait(*threads)
@threads.concat threads
for th in threads
Thread.start do
- th = Thread.join(th)
+ th = th.join
@wait_queue.push th
end
end
end
- #
- # 次の待ちにはいる.
- # 待つべきスレッドがなければ, 例外ErrWaitThreadsNothing を返す.
- # nonnlockが真の時には, nonblockingで調べる. 存在しなければ, 例外
- # FinishedThreadNothingを返す.
- #
+ # waits for any of waiting threads to terminate
+ # if there is no thread to wait, raises ErrNoWaitingThread.
+ # if `nonblock' is true, and there is no terminated thread,
+ # raises ErrNoFinishedThread.
def next_wait(nonblock = nil)
- Threads.Wait.fail ErrWaitThreadsNothing if @threads.empty?
-
- th = @wait_queue.pop(nonblock)
- @threads.delete th
- th
+ ThreadsWait.fail ErrNoWaitingThread if @threads.empty?
+ begin
+ @threads.delete(th = @wait_queue.pop(nonblock))
+ th
+ rescue ThreadError
+ ThreadsWait.fail ErrNoFinshedThread
+ end
end
- #
- # 全てのスレッドが終了するまで待つ. イテレータとして呼ばれた時は, ス
- # レッドが終了する度に, イテレータを呼び出す.
- #
+ # waits until all of specified threads are terminated.
+ # if a block is supplied for the method, evaluates it for
+ # each thread termination.
def all_waits
until @threads.empty?
th = next_wait
@@ -126,3 +129,5 @@ class ThreadsWait
end
end
end
+
+ThWait = ThreadsWait
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 d37339f..fbfca24 100644
--- a/lib/tracer.rb
+++ b/lib/tracer.rb
@@ -1,7 +1,28 @@
+#
+# tracer.rb -
+# $Release Version: 0.2$
+# $Revision: 1.8 $
+# $Date: 1998/05/19 03:42:49 $
+# by Keiju ISHITSUKA(Nippon Rational Inc.)
+#
+# --
+#
+#
+#
+
+#
+# tracer main class
+#
class Tracer
- MY_FILE_NAME_PATTERN = /^tracer\.(rb)?/
- Threads = Hash.new
- Sources = Hash.new
+ @RCS_ID='-$Id: tracer.rb,v 1.8 1998/05/19 03:42:49 keiju Exp keiju $-'
+
+ class << self
+ attr :verbose, TRUE
+ alias verbose? verbose
+ end
+ verbose = TRUE
+
+ MY_FILE_NAME = caller(0)[0].scan(/^(.*):[0-9]+$/)[0][0]
EVENT_SYMBOL = {
"line" => "-",
@@ -10,39 +31,89 @@ class Tracer
"class" => "C",
"end" => "E"}
+ def initialize
+ @threads = Hash.new
+ if defined? Thread.main
+ @threads[Thread.main.id] = 0
+ else
+ @threads[Thread.current.id] = 0
+ end
+
+ @get_line_procs = {}
+ @sources = {}
+
+ @filters = []
+ end
+
def on
- set_trace_func proc{|event, file, line, id, binding|
- trace_func event, file, line, id, binding
- }
- print "Trace on\n"
+ if iterator?
+ on
+ begin
+ yield
+ ensure
+ off
+ end
+ else
+ set_trace_func proc{|event, file, line, id, binding|
+ trace_func event, file, line, id, binding
+ }
+ print "Trace on\n" if Tracer.verbose?
+ end
end
def off
set_trace_func nil
- print "Trace off\n"
+ print "Trace off\n" if Tracer.verbose?
end
-
- def get_thread_no
- unless no = Threads[Thread.current.id]
- Threads[Thread.current.id] = no = Threads.size
- end
- no
+
+ def add_filter(p = proc)
+ @filters.push p
+ end
+
+ def set_get_line_procs(file, p = proc)
+ @get_line_procs[file] = p
end
def get_line(file, line)
- unless list = Sources[file]
- f =open(file)
- begin
- Sources[file] = list = f.readlines
- ensure
- f.close
+ if p = @get_line_procs[file]
+ return p.call line
+ end
+
+ unless list = @sources[file]
+# print file if $DEBUG
+ begin
+ f = open(file)
+ begin
+ @sources[file] = list = f.readlines
+ ensure
+ f.close
+ end
+ rescue
+ @sources[file] = list = []
end
end
- list[line - 1]
+ if l = list[line - 1]
+ l
+ else
+ "-\n"
+ end
+ end
+
+ def get_thread_no
+ if no = @threads[Thread.current.id]
+ no
+ else
+ @threads[Thread.current.id] = @threads.size
+ end
end
def trace_func(event, file, line, id, binding)
- return if File.basename(file) =~ MY_FILE_NAME_PATTERN
+ return if file == MY_FILE_NAME
+ #printf "Th: %s\n", Thread.current.inspect
+
+ for p in @filters
+ return unless p.call event, file, line, id, binding
+ end
Thread.critical = TRUE
printf("#%d:%s:%d:%s: %s",
@@ -56,20 +127,36 @@ class Tracer
Single = new
def Tracer.on
- Single.on
+ if iterator?
+ Single.on{yield}
+ else
+ Single.on
+ end
end
def Tracer.off
Single.off
end
-end
+ def Tracer.set_get_line_procs(file_name, p = proc)
+ Single.set_get_line_procs(file_name, p)
+ end
-if File.basename($0) =~ Tracer::MY_FILE_NAME_PATTERN
- $0 = ARGV.shift
+ def Tracer.add_filter(p = proc)
+ Single.add_filter(p)
+ end
- Tracer.on
- load $0
-else
- Tracer.on
+end
+
+if caller(0).size == 1
+ if $0 == Tracer::MY_FILE_NAME
+ # direct call
+
+ $0 = ARGV[0]
+ ARGV.shift
+ Tracer.on
+ require $0
+ else
+ Tracer.on
+ end
end
diff --git a/lib/weakref.rb b/lib/weakref.rb
index 93b2c65..c31e959 100644
--- a/lib/weakref.rb
+++ b/lib/weakref.rb
@@ -10,9 +10,10 @@
require "delegate"
-class WeakRef<Delegater
+class WeakRef<Delegator
- Exception :RefError
+ class RefError<StandardError
+ end
ID_MAP = {}
ID_REV_MAP = {}
@@ -31,26 +32,22 @@ class WeakRef<Delegater
def initialize(orig)
super
- @id = orig.id
+ @__id = orig.__id__
ObjectSpace.call_finalizer orig
- ID_MAP[@id] = self.id
- ID_REV_MAP[self.id] = @id
+ ObjectSpace.call_finalizer self
+ ID_MAP[@__id] = self.__id__
+ ID_REV_MAP[self.id] = @__id
end
def __getobj__
- unless ID_MAP[@id]
- $@ = caller(1)
- $! = RefError.new("Illegal Reference - probably recycled")
- raise
+ unless ID_MAP[@__id]
+ raise RefError, "Illegal Reference - probably recycled", caller(2)
end
- ObjectSpace.id2ref(@id)
-# ObjectSpace.each_object do |obj|
-# return obj if obj.id == @id
-# end
+ ObjectSpace._id2ref(@__id)
end
def weakref_alive?
- if ID_MAP[@id]
+ if ID_MAP[@__id]
true
else
false
@@ -62,9 +59,11 @@ class WeakRef<Delegater
end
end
-foo = Object.new
-p foo.hash
-foo = WeakRef.new(foo)
-p foo.hash
-ObjectSpace.garbage_collect
-p foo.hash
+if __FILE__ == $0
+ foo = Object.new
+ p foo.hash # original's hash value
+ foo = WeakRef.new(foo)
+ p foo.hash # should be same hash value
+ ObjectSpace.garbage_collect
+ p foo.hash # should raise exception (recycled)
+end