[前][次][番号順一覧][スレッド一覧][生データ]

yarv-diff:222

From: ko1 atdot.net
Date: 11 Feb 2006 05:42:52 -0000
Subject: [yarv-diff:222] r379 - in trunk: . ext/digest ext/digest/sha2 ext/etc ext/win32ole lib lib/net lib/test/unit missing rb sample test test/ruby

Author: ko1
Date: 2006-02-11 14:42:50 +0900 (Sat, 11 Feb 2006)
New Revision: 379

Added:
   trunk/lib/net/
   trunk/lib/net/.document
   trunk/lib/net/ftp.rb
   trunk/lib/net/http.rb
   trunk/lib/net/https.rb
   trunk/lib/net/imap.rb
   trunk/lib/net/pop.rb
   trunk/lib/net/protocol.rb
   trunk/lib/net/smtp.rb
   trunk/lib/net/telnet.rb
   trunk/lib/open-uri.rb
   trunk/lib/timeout.rb
Modified:
   trunk/
   trunk/ChangeLog
   trunk/array.c
   trunk/compar.c
   trunk/dln.c
   trunk/enum.c
   trunk/enumerator.c
   trunk/error.c
   trunk/eval.c
   trunk/eval_thread.c
   trunk/ext/digest/digest.c
   trunk/ext/digest/digest.h
   trunk/ext/digest/sha2/sha2.c
   trunk/ext/etc/etc.c
   trunk/ext/win32ole/win32ole.c
   trunk/hash.c
   trunk/intern.h
   trunk/io.c
   trunk/lib/cgi.rb
   trunk/lib/complex.rb
   trunk/lib/delegate.rb
   trunk/lib/erb.rb
   trunk/lib/fileutils.rb
   trunk/lib/matrix.rb
   trunk/lib/mkmf.rb
   trunk/lib/optparse.rb
   trunk/lib/ostruct.rb
   trunk/lib/pp.rb
   trunk/lib/test/unit/autorunner.rb
   trunk/lib/tmpdir.rb
   trunk/main.c
   trunk/missing.h
   trunk/missing/flock.c
   trunk/missing/isinf.c
   trunk/missing/vsnprintf.c
   trunk/node.h
   trunk/object.c
   trunk/parse.y
   trunk/rb/mklog.rb
   trunk/ruby.c
   trunk/sample/test.rb
   trunk/sprintf.c
   trunk/st.c
   trunk/test.rb
   trunk/test/ruby/test_whileuntil.rb
   trunk/test/runner.rb
   trunk/thread.c
   trunk/thread_pthread.h
   trunk/thread_win32.h
   trunk/time.c
   trunk/yarvcore.c
Log:
 r552@leremita:  ko1 | 2006-02-11 14:42:07 +0900
 	* rb/mklog.rb : use svk
 
 	* error.c : remove newline
 
 	* eval.c (rb_block_call) : added
 
 	* eval_thread.c : remove some unused functions, comments
 
 	* thread.c : add comments (move from eval_thread.c) and support Mutex
 
 	* thread.c (rb_thread_select) : supported
 
 	* thread_pthread.h (native_mutex_trylock) : added (macro)
 
 	* thread_win32.h (native_mutex_trylock) : added
 
 	* yarvcore.c : remove unused code
 
 	* array.c : import ruby 1.9
 
 	* compar.c : ditto
 
 	* dln.c : ditto
 
 	* enum.c : ditto
 
 	* enumerator.c : ditto
 
 	* ext/digest/digest.c : ditto
 
 	* ext/digest/digest.h : ditto
 
 	* ext/digest/sha2/sha2.c : ditto
 
 	* ext/etc/etc.c : ditto
 
 	* ext/win32ole/win32ole.c : ditto
 
 	* hash.c : ditto
 
 	* intern.h : ditto
 
 	* io.c : ditto
 
 	* main.c : ditto
 
 	* missing.h : ditto
 
 	* missing/flock.c : ditto
 
 	* missing/isinf.c : ditto
 
 	* missing/vsnprintf.c : ditto
 
 	* lib/cgi.rb : ditto
 
 	* lib/complex.rb : ditto
 
 	* lib/delegate.rb : ditto
 
 	* lib/erb.rb : ditto
 
 	* lib/fileutils.rb : ditto
 
 	* lib/matrix.rb : ditto
 
 	* lib/mkmf.rb : ditto
 
 	* lib/optparse.rb : ditto
 
 	* lib/ostruct.rb : ditto
 
 	* lib/pp.rb : ditto
 
 	* lib/timeout.rb : ditto
 
 	* lib/tmpdir.rb : ditto
 
 	* lib/test/unit/autorunner.rb : ditto
 
 	* node.h : ditto
 
 	* object.c : ditto
 
 	* parse.y : ditto
 
 	* ruby.c : ditto
 
 	* sample/test.rb : ditto
 
 	* sprintf.c : ditto
 
 	* st.c : ditto
 
 	* test/ruby/test_whileuntil.rb : ditto
 
 	* test/runner.rb : ditto
 
 	* time.c : ditto
 
 	* lib/net/.document : added
 
 	* lib/net/ftp.rb : ditto
 
 	* lib/net/http.rb : ditto
 
 	* lib/net/https.rb : ditto
 
 	* lib/net/imap.rb : ditto
 
 	* lib/net/pop.rb : ditto
 
 	* lib/net/protocol.rb : ditto
 
 	* lib/net/smtp.rb : ditto
 
 	* lib/net/telnet.rb : ditto
 
 	* lib/open-uri.rb : ditto
 



Property changes on: trunk
___________________________________________________________________
Name: svk:merge
   + 81cd9672-7512-7e48-ae48-6936450e977d:/local/yarv/trunk:552

Modified: trunk/ChangeLog
===================================================================
--- trunk/ChangeLog	2006-02-09 23:21:27 UTC (rev 378)
+++ trunk/ChangeLog	2006-02-11 05:42:50 UTC (rev 379)
@@ -4,6 +4,129 @@
 #  from Mon, 03 May 2004 01:24:19 +0900
 #
 
+2006-02-11(Sat) 14:29:01 +0900  Koichi Sasada  <ko1 atdot.net>
+
+	* rb/mklog.rb : use svk
+
+	* error.c : remove newline
+
+	* eval.c (rb_block_call) : added
+
+	* eval_thread.c : remove some unused functions, comments
+
+	* thread.c : add comments (move from eval_thread.c) and support Mutex
+
+	* thread.c (rb_thread_select) : supported
+
+	* thread_pthread.h (native_mutex_trylock) : added (macro)
+
+	* thread_win32.h (native_mutex_trylock) : added
+
+	* yarvcore.c : remove unused code
+
+	* array.c : import ruby 1.9
+
+	* compar.c : ditto
+
+	* dln.c : ditto
+
+	* enum.c : ditto
+
+	* enumerator.c : ditto
+
+	* ext/digest/digest.c : ditto
+
+	* ext/digest/digest.h : ditto
+
+	* ext/digest/sha2/sha2.c : ditto
+
+	* ext/etc/etc.c : ditto
+
+	* ext/win32ole/win32ole.c : ditto
+
+	* hash.c : ditto
+
+	* intern.h : ditto
+
+	* io.c : ditto
+
+	* main.c : ditto
+
+	* missing.h : ditto
+
+	* missing/flock.c : ditto
+
+	* missing/isinf.c : ditto
+
+	* missing/vsnprintf.c : ditto
+
+	* lib/cgi.rb : ditto
+
+	* lib/complex.rb : ditto
+
+	* lib/delegate.rb : ditto
+
+	* lib/erb.rb : ditto
+
+	* lib/fileutils.rb : ditto
+
+	* lib/matrix.rb : ditto
+
+	* lib/mkmf.rb : ditto
+
+	* lib/optparse.rb : ditto
+
+	* lib/ostruct.rb : ditto
+
+	* lib/pp.rb : ditto
+
+	* lib/timeout.rb : ditto
+
+	* lib/tmpdir.rb : ditto
+
+	* lib/test/unit/autorunner.rb : ditto
+
+	* node.h : ditto
+
+	* object.c : ditto
+
+	* parse.y : ditto
+
+	* ruby.c : ditto
+
+	* sample/test.rb : ditto
+
+	* sprintf.c : ditto
+
+	* st.c : ditto
+
+	* test/ruby/test_whileuntil.rb : ditto
+
+	* test/runner.rb : ditto
+
+	* time.c : ditto
+
+	* lib/net/.document : added
+
+	* lib/net/ftp.rb : ditto
+
+	* lib/net/http.rb : ditto
+
+	* lib/net/https.rb : ditto
+
+	* lib/net/imap.rb : ditto
+
+	* lib/net/pop.rb : ditto
+
+	* lib/net/protocol.rb : ditto
+
+	* lib/net/smtp.rb : ditto
+
+	* lib/net/telnet.rb : ditto
+
+	* lib/open-uri.rb : ditto
+
+
 2006-02-10(Fri) 08:07:34 +0900  Koichi Sasada  <ko1 atdot.net>
 
 	* compile.c, insns.def, yarvcore.h : support defined?(private_method) and

Modified: trunk/array.c
===================================================================
--- trunk/array.c	2006-02-09 23:21:27 UTC (rev 378)
+++ trunk/array.c	2006-02-11 05:42:50 UTC (rev 379)
@@ -2,8 +2,8 @@
 
   array.c -
 
-  $Author: ocean $
-  $Date: 2005/11/15 07:37:39 $
+  $Author: akr $
+  $Date: 2005/12/12 16:46:59 $
   created at: Fri Aug  6 09:46:12 JST 1993
 
   Copyright (C) 1993-2003 Yukihiro Matsumoto
@@ -2517,7 +2517,8 @@
 static VALUE
 rb_ary_diff(VALUE ary1, VALUE ary2)
 {
-    VALUE ary3, hash;
+    VALUE ary3;
+    volatile VALUE hash;
     long i;
 
     hash = ary_make_hash(to_ary(ary2), 0);

Modified: trunk/compar.c
===================================================================
--- trunk/compar.c	2006-02-09 23:21:27 UTC (rev 378)
+++ trunk/compar.c	2006-02-11 05:42:50 UTC (rev 379)
@@ -3,7 +3,7 @@
   compar.c -
 
   $Author: matz $
-  $Date: 2005/09/12 15:23:54 $
+  $Date: 2005/12/12 00:35:09 $
   created at: Thu Aug 26 14:39:48 JST 1993
 
   Copyright (C) 1993-2003 Yukihiro Matsumoto
@@ -53,7 +53,7 @@
 {
     VALUE c = rb_funcall(a[0], cmp, 1, a[1]);
 
-    if (NIL_P(c)) return Qnil;
+    if (NIL_P(c)) return Qfalse;
     if (rb_cmpint(c, a[0], a[1]) == 0) return Qtrue;
     return Qfalse;
 }
@@ -61,7 +61,7 @@
 static VALUE
 cmp_failed(void)
 {
-    return Qnil;
+    return Qfalse;
 }
 
 /*

Modified: trunk/dln.c
===================================================================
--- trunk/dln.c	2006-02-09 23:21:27 UTC (rev 378)
+++ trunk/dln.c	2006-02-11 05:42:50 UTC (rev 379)
@@ -2,8 +2,8 @@
 
   dln.c -
 
-  $Author: ocean $
-  $Date: 2005/09/12 11:03:24 $
+  $Author: nobu $
+  $Date: 2006/01/25 13:29:44 $
   created at: Tue Jan 18 17:05:06 JST 1994
 
   Copyright (C) 1993-2003 Yukihiro Matsumoto
@@ -89,8 +89,6 @@
 # include <image.h>
 #endif
 
-int eaccess(const char *, int);
-
 #ifndef NO_DLN_LOAD
 
 #if defined(HAVE_DLOPEN) && !defined(USE_DLN_A_OUT) && !defined(_AIX) && !defined(__APPLE__) && !defined(_UNICOSMP)
@@ -1645,6 +1643,7 @@
     char *p = win32;
     char *dst = posix;
 
+    posix[0] = '\0';
     for (p = win32; *p; p++)
 	if (*p == ';') {
 	    *p = 0;

Modified: trunk/enum.c
===================================================================
--- trunk/enum.c	2006-02-09 23:21:27 UTC (rev 378)
+++ trunk/enum.c	2006-02-11 05:42:50 UTC (rev 379)
@@ -17,12 +17,6 @@
 VALUE rb_mEnumerable;
 static ID id_each, id_eqq, id_cmp;
 
-VALUE
-rb_each(VALUE obj)
-{
-    return rb_funcall(obj, id_each, 0, 0);
-}
-
 static VALUE
 grep_i(VALUE i, VALUE *arg)
 {
@@ -68,7 +62,7 @@
     arg[0] = pat;
     arg[1] = ary;
 
-    rb_iterate(rb_each, obj, rb_block_given_p() ? grep_iter_i : grep_i, (VALUE)arg);
+    rb_block_call(obj, id_each, 0, 0, rb_block_given_p() ? grep_iter_i : grep_i, (VALUE)arg);
     
     return ary;
 }
@@ -117,13 +111,13 @@
 	rb_scan_args(argc, argv, "1", &item);
 	args[0] = item;
 	args[1] = 0;
-	rb_iterate(rb_each, obj, count_i, (VALUE)&args);
+	rb_block_call(obj, id_each, 0, 0, count_i, (VALUE)&args);
 	return INT2NUM(args[1]);
     }
     else {
 	long n = 0;
 
-	rb_iterate(rb_each, obj, count_iter_i, (VALUE)&n);
+	rb_block_call(obj, id_each, 0, 0, count_iter_i, (VALUE)&n);
 	return INT2NUM(n);
     }
 }
@@ -161,7 +155,7 @@
 
     rb_scan_args(argc, argv, "01", &if_none);
     RETURN_ENUMERATOR(obj, argc, argv);
-    rb_iterate(rb_each, obj, find_i, (VALUE)&memo);
+    rb_block_call(obj, id_each, 0, 0, find_i, (VALUE)&memo);
     if (memo != Qundef) {
 	return memo;
     }
@@ -203,7 +197,7 @@
     RETURN_ENUMERATOR(obj, 0, 0);
     memo[0] = Qundef;
     memo[1] = 0;
-    rb_iterate(rb_each, obj, find_index_i, (VALUE)memo);
+    rb_block_call(obj, id_each, 0, 0, find_index_i, (VALUE)memo);
     if (memo[0] != Qundef) {
 	return memo[0];
     }
@@ -240,7 +234,7 @@
     RETURN_ENUMERATOR(obj, 0, 0);
 
     ary = rb_ary_new();
-    rb_iterate(rb_each, obj, find_all_i, ary);
+    rb_block_call(obj, id_each, 0, 0, find_all_i, ary);
 
     return ary;
 }
@@ -273,7 +267,7 @@
     RETURN_ENUMERATOR(obj, 0, 0);
 
     ary = rb_ary_new();
-    rb_iterate(rb_each, obj, reject_i, ary);
+    rb_block_call(obj, id_each, 0, 0, reject_i, ary);
 
     return ary;
 }
@@ -315,7 +309,7 @@
     RETURN_ENUMERATOR(obj, 0, 0);
 
     ary = rb_ary_new();
-    rb_iterate(rb_each, obj, collect_i, ary);
+    rb_block_call(obj, id_each, 0, 0, collect_i, ary);
 
     return ary;
 }
@@ -335,7 +329,7 @@
 {
     VALUE ary = rb_ary_new();
 
-    rb_iterate(rb_each, obj, collect_all, ary);
+    rb_block_call(obj, id_each, 0, 0, collect_all, ary);
 
     return ary;
 }
@@ -390,7 +384,7 @@
 
     if (rb_scan_args(argc, argv, "01", &memo) == 0)
 	memo = Qundef;
-    rb_iterate(rb_each, obj, inject_i, (VALUE)&memo);
+    rb_block_call(obj, id_each, 0, 0, inject_i, (VALUE)&memo);
     if (memo == Qundef) return Qnil;
     return memo;
 }
@@ -428,7 +422,7 @@
 
     ary[0] = rb_ary_new();
     ary[1] = rb_ary_new();
-    rb_iterate(rb_each, obj, partition_i, (VALUE)ary);
+    rb_block_call(obj, id_each, 0, 0, partition_i, (VALUE)ary);
 
     return rb_assoc_new(ary[0], ary[1]);
 }
@@ -470,7 +464,7 @@
     RETURN_ENUMERATOR(obj, 0, 0);
 
     hash = rb_hash_new();
-    rb_iterate(rb_each, obj, group_by_i, hash);
+    rb_block_call(obj, id_each, 0, 0, group_by_i, hash);
 
     return hash;
 }
@@ -520,7 +514,7 @@
 	ary[0] = n;
 	ary[1] = rb_ary_new2(NUM2LONG(n));
     }
-    rb_iterate(rb_each, obj, first_i, (VALUE)ary);
+    rb_block_call(obj, id_each, 0, 0, first_i, (VALUE)ary);
 
     return ary[1];
 }
@@ -656,7 +650,7 @@
 	ary = rb_ary_new();
     }
     RBASIC(ary)->klass = 0;
-    rb_iterate(rb_each, obj, sort_by_i, ary);
+    rb_block_call(obj, id_each, 0, 0, sort_by_i, ary);
     if (RARRAY(ary)->len > 1) {
 	ruby_qsort(RARRAY(ary)->ptr, RARRAY(ary)->len, sizeof(VALUE), sort_by_cmp, 0);
     }
@@ -712,7 +706,7 @@
 {
     VALUE result = Qtrue;
 
-    rb_iterate(rb_each, obj, rb_block_given_p() ? all_iter_i : all_i, (VALUE)&result);
+    rb_block_call(obj, id_each, 0, 0, rb_block_given_p() ? all_iter_i : all_i, (VALUE)&result);
     return result;
 }
 
@@ -759,7 +753,7 @@
 {
     VALUE result = Qfalse;
 
-    rb_iterate(rb_each, obj, rb_block_given_p() ? any_iter_i : any_i, (VALUE)&result);
+    rb_block_call(obj, id_each, 0, 0, rb_block_given_p() ? any_iter_i : any_i, (VALUE)&result);
     return result;
 }
 
@@ -812,7 +806,7 @@
 {
     VALUE result = Qundef;
 
-    rb_iterate(rb_each, obj, rb_block_given_p() ? one_iter_i : one_i, (VALUE)&result);
+    rb_block_call(obj, id_each, 0, 0, rb_block_given_p() ? one_iter_i : one_i, (VALUE)&result);
     if (result == Qundef) return Qfalse;
     return result;
 }
@@ -857,7 +851,7 @@
 {
     VALUE result = Qtrue;
 
-    rb_iterate(rb_each, obj, rb_block_given_p() ? none_iter_i : none_i, (VALUE)&result);
+    rb_block_call(obj, id_each, 0, 0, rb_block_given_p() ? none_iter_i : none_i, (VALUE)&result);
     return result;
 }
 
@@ -915,7 +909,7 @@
 {
     VALUE result = Qundef;
 
-    rb_iterate(rb_each, obj, rb_block_given_p() ? min_ii : min_i, (VALUE)&result);
+    rb_block_call(obj, id_each, 0, 0, rb_block_given_p() ? min_ii : min_i, (VALUE)&result);
     if (result == Qundef) return Qnil;
     return result;
 }
@@ -973,7 +967,7 @@
 {
     VALUE result = Qundef;
 
-    rb_iterate(rb_each, obj, rb_block_given_p() ? max_ii : max_i, (VALUE)&result);
+    rb_block_call(obj, id_each, 0, 0, rb_block_given_p() ? max_ii : max_i, (VALUE)&result);
     if (result == Qundef) return Qnil;
     return result;
 }
@@ -1015,7 +1009,7 @@
 
     memo[0] = Qundef;
     memo[1] = Qnil;
-    rb_iterate(rb_each, obj, min_by_i, (VALUE)memo);
+    rb_block_call(obj, id_each, 0, 0, min_by_i, (VALUE)memo);
     return memo[1];
 }
 
@@ -1056,7 +1050,7 @@
 
     memo[0] = Qundef;
     memo[1] = Qnil;
-    rb_iterate(rb_each, obj, max_by_i, (VALUE)memo);
+    rb_block_call(obj, id_each, 0, 0, max_by_i, (VALUE)memo);
     return memo[1];
 }
 
@@ -1090,7 +1084,7 @@
 
     memo[0] = val;
     memo[1] = Qfalse;
-    rb_iterate(rb_each, obj, member_i, (VALUE)memo);
+    rb_block_call(obj, id_each, 0, 0, member_i, (VALUE)memo);
     return memo[1];
 }
 
@@ -1124,7 +1118,7 @@
 
     RETURN_ENUMERATOR(obj, 0, 0);
 
-    rb_iterate(rb_each, obj, each_with_index_i, (VALUE)&memo);
+    rb_block_call(obj, id_each, 0, 0, each_with_index_i, (VALUE)&memo);
     return obj;
 }
 
@@ -1188,7 +1182,7 @@
     memo[0] = result;
     memo[1] = rb_ary_new4(argc, argv);
     memo[2] = 0;
-    rb_iterate(rb_each, obj, zip_i, (VALUE)memo);
+    rb_block_call(obj, id_each, 0, 0, zip_i, (VALUE)memo);
 
     return result;
 }

Modified: trunk/enumerator.c
===================================================================
--- trunk/enumerator.c	2006-02-09 23:21:27 UTC (rev 378)
+++ trunk/enumerator.c	2006-02-11 05:42:50 UTC (rev 379)
@@ -2,13 +2,13 @@
 
   enumerator.c - provides Enumerator class
 
-  $Author: nobu $
+  $Author: matz $
 
   Copyright (C) 2001-2003 Akinori MUSHA
 
   $Idaemons: /home/cvs/rb/enumerator/enumerator.c,v 1.1.1.1 2001/07/15 10:12:48 knu Exp $
   $RoughId: enumerator.c,v 1.6 2003/07/27 11:03:24 nobu Exp $
-  $Id: enumerator.c,v 1.9 2005/10/27 11:35:24 nobu Exp $
+  $Id: enumerator.c,v 1.10 2006/02/03 09:15:42 matz Exp $
 
 ************************************************/
 
@@ -32,18 +32,6 @@
     return rb_proc_call(proc, args);
 }
 
-static VALUE
-method_call(VALUE method, VALUE args)
-{
-    int argc = 0;
-    VALUE *argv = 0;
-    if (args) {
-	argc = RARRAY(args)->len;
-	argv = RARRAY(args)->ptr;
-    }
-    return rb_method_call(argc, argv, method);
-}
-
 struct enumerator {
     VALUE method;
     VALUE proc;
@@ -168,7 +156,7 @@
     args[0] = rb_ary_new2(size);
     args[1] = (VALUE)size;
 
-    rb_iterate(rb_each, obj, each_slice_i, (VALUE)args);
+    rb_block_call(obj, rb_intern("each"), 0, 0, each_slice_i, (VALUE)args);
 
     ary = args[0];
     if (RARRAY(ary)->len > 0) rb_yield(ary);
@@ -235,7 +223,7 @@
     args[0] = rb_ary_new2(size);
     args[1] = (VALUE)size;
 
-    rb_iterate(rb_each, obj, each_cons_i, (VALUE)args);
+    rb_block_call(obj, rb_intern("each"), 0, 0, each_cons_i, (VALUE)args);
 
     return Qnil;
 }
@@ -315,14 +303,6 @@
     return enumerator_init(enumerator_allocate(rb_cEnumerator), obj, meth, argc, argv);
 }
 
-static VALUE
-enumerator_iter(VALUE memo)
-{
-    struct enumerator *e = (struct enumerator *)memo;
-
-    return method_call(e->method, e->args);
-}
-
 /*
  *  call-seq:
  *    enum.each {...}
@@ -335,8 +315,14 @@
 enumerator_each(VALUE obj)
 {
     struct enumerator *e = enumerator_ptr(obj);
+    int argc = 0;
+    VALUE *argv = 0;
 
-    return rb_iterate(enumerator_iter, (VALUE)e, e->iter, (VALUE)e);
+    if (e->args) {
+	argc = RARRAY(e->args)->len;
+	argv = RARRAY(e->args)->ptr;
+    }
+    return rb_block_call(e->method, rb_intern("call"), argc, argv, e->iter, (VALUE)e);
 }
 
 static VALUE
@@ -360,8 +346,16 @@
 {
     struct enumerator *e = enumerator_ptr(obj);
     VALUE memo = 0;
+    int argc = 0;
+    VALUE *argv = 0;
 
-    return rb_iterate(enumerator_iter, (VALUE)e,
+    if (e->args) {
+	argc = RARRAY(e->args)->len;
+	argv = RARRAY(e->args)->ptr;
+    }
+    return rb_block_call(e->method, rb_intern("call"), argc, argv, e->iter, (VALUE)e);
+
+    return rb_block_call(e->method, rb_intern("call"), argc, argv,
 		      enumerator_with_index_i, (VALUE)&memo);
 }
 

Modified: trunk/error.c
===================================================================
--- trunk/error.c	2006-02-09 23:21:27 UTC (rev 378)
+++ trunk/error.c	2006-02-11 05:42:50 UTC (rev 379)
@@ -70,7 +70,6 @@
 rb_compile_error(const char *fmt, ...)
 {
     va_list args;
-
     va_start(args, fmt);
     err_print(fmt, args);
     va_end(args);

Modified: trunk/eval.c
===================================================================
--- trunk/eval.c	2006-02-09 23:21:27 UTC (rev 378)
+++ trunk/eval.c	2006-02-11 05:42:50 UTC (rev 379)
@@ -1316,7 +1316,37 @@
   return retval;
 }
 
+struct iter_method_arg {
+  VALUE obj;
+  ID mid;
+  int argc;
+  VALUE *argv;
+};
+
+static VALUE
+iterate_method(VALUE obj)
+{
+  struct iter_method_arg *arg;
+
+  arg = (struct iter_method_arg*)obj;
+  return rb_call(CLASS_OF(arg->obj), arg->obj, arg->mid,
+                 arg->argc, arg->argv, NOEX_PRIVATE);
+}
+
 VALUE
+rb_block_call(VALUE obj, ID mid, int argc, VALUE *argv,
+              VALUE (*bl_proc)(ANYARGS), VALUE data2)
+{
+  struct iter_method_arg arg;
+
+  arg.obj = obj;
+  arg.mid = mid;
+  arg.argc = argc;
+  arg.argv = argv;
+  return rb_iterate(iterate_method, (VALUE)&arg, bl_proc, data2);
+}
+
+VALUE
 #ifdef HAVE_STDARG_PROTOTYPES
 rb_rescue2(VALUE (*b_proc)(ANYARGS), VALUE data1, VALUE (*r_proc)(ANYARGS), VALUE data2, ...)
 #else

Modified: trunk/eval_thread.c
===================================================================
--- trunk/eval_thread.c	2006-02-09 23:21:27 UTC (rev 378)
+++ trunk/eval_thread.c	2006-02-11 05:42:50 UTC (rev 379)
@@ -691,23 +691,6 @@
     return n;
 }
 
-static int
-find_bad_fds(dst, src, max)
-    rb_fdset_t *dst, *src;
-    int max;
-{
-    int i, test = Qfalse;
-
-    if (max >= rb_fd_max(src)) max = rb_fd_max(src) - 1;
-    for (i=0; i<=max; i++) {
-	if (FD_ISSET(i, src) && !FD_ISSET(i, dst)) {
-	    FD_CLR(i, src);
-	    test = Qtrue;
-	}
-    }
-    return test;
-}
-
 void
 rb_thread_schedule()
 {
@@ -717,89 +700,6 @@
   /* UNSUPPORTED(rb_thread_schedule); */
 }
 
-int
-rb_thread_select(max, read, write, except, timeout)
-    int max;
-    fd_set *read, *write, *except;
-    struct timeval *timeout;
-{
-  UNSUPPORTED(rb_thread_select);
-  return 0;
-}
-
-static int
-rb_thread_join(rb_thread_t th, double limit)
-{
-    return Qtrue;
-}
-
-/*
- *  call-seq:
- *     thr.join          => thr
- *     thr.join(limit)   => thr
- *  
- *  The calling thread will suspend execution and run <i>thr</i>. Does not
- *  return until <i>thr</i> exits or until <i>limit</i> seconds have passed. If
- *  the time limit expires, <code>nil</code> will be returned, otherwise
- *  <i>thr</i> is returned.
- *     
- *  Any threads not joined will be killed when the main program exits.  If
- *  <i>thr</i> had previously raised an exception and the
- *  <code>abort_on_exception</code> and <code>$DEBUG</code> flags are not set
- *  (so the exception has not yet been processed) it will be processed at this
- *  time.
- *     
- *     a = Thread.new { print "a"; sleep(10); print "b"; print "c" }
- *     x = Thread.new { print "x"; Thread.pass; print "y"; print "z" }
- *     x.join # Let x thread finish, a will be killed on exit.
- *     
- *  <em>produces:</em>
- *     
- *     axyz
- *     
- *  The following example illustrates the <i>limit</i> parameter.
- *     
- *     y = Thread.new { 4.times { sleep 0.1; puts 'tick... ' }}
- *     puts "Waiting" until y.join(0.15)
- *     
- *  <em>produces:</em>
- *     
- *     tick...
- *     Waiting
- *     tick...
- *     Waitingtick...
- *     
- *     
- *     tick...
- */
-
-static VALUE
-rb_thread_join_m(argc, argv, thread)
-    int argc;
-    VALUE *argv;
-    VALUE thread;
-{
-    VALUE limit;
-    double delay = DELAY_INFTY;
-    rb_thread_t th = rb_thread_check(thread);
-
-    rb_scan_args(argc, argv, "01", &limit);
-    if (!NIL_P(limit)) delay = rb_num2dbl(limit);
-    if (!rb_thread_join(th, delay))
-	return Qnil;
-    return thread;
-}
-
-
-/*
- *  call-seq:
- *     Thread.current   => thread
- *  
- *  Returns the currently executing thread.
- *     
- *     Thread.current   #=> #<Thread:0x401bdf4c run>
- */
-
 VALUE
 rb_thread_current()
 {

Modified: trunk/ext/digest/digest.c
===================================================================
--- trunk/ext/digest/digest.c	2006-02-09 23:21:27 UTC (rev 378)
+++ trunk/ext/digest/digest.c	2006-02-11 05:42:50 UTC (rev 379)
@@ -2,14 +2,14 @@
 
   digest.c -
 
-  $Author: matz $
+  $Author: akr $
   created at: Fri May 25 08:57:27 JST 2001
 
   Copyright (C) 1995-2001 Yukihiro Matsumoto
   Copyright (C) 2001 Akinori MUSHA
 
   $RoughId: digest.c,v 1.16 2001/07/13 15:38:27 knu Exp $
-  $Id: digest.c,v 1.15 2004/09/17 09:24:11 matz Exp $
+  $Id: digest.c,v 1.17 2005/12/12 05:15:33 akr Exp $
 
 ************************************************/
 
@@ -41,8 +41,7 @@
  */
 
 static algo_t *
-get_digest_base_metadata(klass)
-    VALUE klass;
+get_digest_base_metadata(VALUE klass)
 {
     VALUE obj;
     algo_t *algo;
@@ -58,10 +57,8 @@
     return algo;
 }
 
-static VALUE rb_digest_base_alloc _((VALUE));
 static VALUE
-rb_digest_base_alloc(klass)
-    VALUE klass;
+rb_digest_base_alloc(VALUE klass)
 {
     algo_t *algo;
     VALUE obj;
@@ -83,15 +80,11 @@
 }
 
 static VALUE
-rb_digest_base_s_digest(klass, str)
-    VALUE klass;
-    VALUE str;
+rb_digest_base_s_digest(VALUE klass, VALUE str)
 {
     algo_t *algo;
     void *pctx;
-    size_t len;
-    unsigned char *digest;
-    VALUE obj = rb_digest_base_alloc(klass);
+    volatile VALUE obj = rb_digest_base_alloc(klass);
 
     algo = get_digest_base_metadata(klass);
     Data_Get_Struct(obj, void, pctx);
@@ -99,28 +92,18 @@
     StringValue(str);
     algo->update_func(pctx, RSTRING(str)->ptr, RSTRING(str)->len);
 
-    len = algo->digest_len;
+    str = rb_str_new(0, algo->digest_len);
+    algo->final_func(RSTRING(str)->ptr, pctx);
 
-    digest = xmalloc(len);
-    algo->final_func(digest, pctx);
-
-    obj = rb_str_new(digest, len);
-
-    free(digest);
-
-    return obj;
+    return str;
 }
 
 static VALUE
-rb_digest_base_s_hexdigest(klass, str)
-    VALUE klass;
-    VALUE str;
+rb_digest_base_s_hexdigest(VALUE klass, VALUE str)
 {
     algo_t *algo;
     void *pctx;
-    size_t len;
-    unsigned char *hexdigest;
-    VALUE obj = rb_digest_base_alloc(klass);
+    volatile VALUE obj = rb_digest_base_alloc(klass);
 
     algo = get_digest_base_metadata(klass);
     Data_Get_Struct(obj, void, pctx);
@@ -128,21 +111,14 @@
     StringValue(str);
     algo->update_func(pctx, RSTRING(str)->ptr, RSTRING(str)->len);
 
-    len = algo->digest_len * 2;
+    str = rb_str_new(0, algo->digest_len * 2);
+    algo->end_func(pctx, RSTRING(str)->ptr);
 
-    hexdigest = xmalloc(len + 1); /* +1 is for '\0' */
-    algo->end_func(pctx, hexdigest);
-
-    obj = rb_str_new(hexdigest, len);
-
-    free(hexdigest);
-
-    return obj;
+    return str;
 }
 
 static VALUE
-rb_digest_base_copy(copy, obj)
-    VALUE copy, obj;
+rb_digest_base_copy(VALUE copy, VALUE obj)
 {
     algo_t *algo;
     void *pctx1, *pctx2;
@@ -161,8 +137,7 @@
 }
 
 static VALUE
-rb_digest_base_update(self, str)
-    VALUE self, str;
+rb_digest_base_update(VALUE self, VALUE str)
 {
     algo_t *algo;
     void *pctx;
@@ -177,10 +152,7 @@
 }
 
 static VALUE
-rb_digest_base_init(argc, argv, self)
-    int argc;
-    VALUE* argv;
-    VALUE self;
+rb_digest_base_init(int argc, VALUE *argv, VALUE self)
 {
     VALUE arg;
 
@@ -192,70 +164,53 @@
 }
 
 static VALUE
-rb_digest_base_digest(self)
-    VALUE self;
+rb_digest_base_digest(VALUE self)
 {
     algo_t *algo;
     void *pctx1, *pctx2;
-    unsigned char *digest;
     size_t len;
     VALUE str;
 
     algo = get_digest_base_metadata(rb_obj_class(self));
     Data_Get_Struct(self, void, pctx1);
 
-    len = algo->ctx_size;
+    str = rb_str_new(0, algo->digest_len);
 
+    len = algo->ctx_size;
     pctx2 = xmalloc(len);
     memcpy(pctx2, pctx1, len);
 
-    len = algo->digest_len;
-
-    digest = xmalloc(len);
-    algo->final_func(digest, pctx2);
-
-    str = rb_str_new(digest, len);
-
-    free(digest);
+    algo->final_func(RSTRING(str)->ptr, pctx2);
     free(pctx2);
 
     return str;
 }
 
 static VALUE
-rb_digest_base_hexdigest(self)
-    VALUE self;
+rb_digest_base_hexdigest(VALUE self)
 {
     algo_t *algo;
     void *pctx1, *pctx2;
-    unsigned char *hexdigest;
     size_t len;
     VALUE str;
 
     algo = get_digest_base_metadata(rb_obj_class(self));
     Data_Get_Struct(self, void, pctx1);
 
-    len = algo->ctx_size;
+    str = rb_str_new(0, algo->digest_len * 2);
 
+    len = algo->ctx_size;
     pctx2 = xmalloc(len);
     memcpy(pctx2, pctx1, len);
 
-    len = algo->digest_len * 2;
-
-    hexdigest = xmalloc(len + 1); /* +1 is for '\0' */
-    algo->end_func(pctx2, hexdigest);
-
-    str = rb_str_new(hexdigest, len);
-
-    free(hexdigest);
+    algo->end_func(pctx2, RSTRING(str)->ptr);
     free(pctx2);
 
     return str;
 }
 
 static VALUE
-rb_digest_base_equal(self, other)
-    VALUE self, other;
+rb_digest_base_equal(VALUE self, VALUE other)
 {
     algo_t *algo;
     VALUE klass;

Modified: trunk/ext/digest/digest.h
===================================================================
--- trunk/ext/digest/digest.h	2006-02-09 23:21:27 UTC (rev 378)
+++ trunk/ext/digest/digest.h	2006-02-11 05:42:50 UTC (rev 379)
@@ -2,24 +2,24 @@
 
   digest.c -
 
-  $Author: knu $
+  $Author: matz $
   created at: Fri May 25 08:54:56 JST 2001
 
 
   Copyright (C) 2001 Akinori MUSHA
 
   $RoughId: digest.h,v 1.3 2001/07/13 15:38:27 knu Exp $
-  $Id: digest.h,v 1.1 2001/07/13 20:06:13 knu Exp $
+  $Id: digest.h,v 1.2 2005/12/12 00:35:08 matz Exp $
 
 ************************************************/
 
 #include "ruby.h"
 
-typedef void (*hash_init_func_t) _((void *));
-typedef void (*hash_update_func_t) _((void *, unsigned char *, size_t));
-typedef void (*hash_end_func_t) _((void *, unsigned char *));
-typedef void (*hash_final_func_t) _((unsigned char *, void *));
-typedef int (*hash_equal_func_t) _((void *, void *));
+typedef void (*hash_init_func_t)(void *);
+typedef void (*hash_update_func_t)(void *, unsigned char *, size_t);
+typedef void (*hash_end_func_t)(void *, unsigned char *);
+typedef void (*hash_final_func_t)(unsigned char *, void *);
+typedef int (*hash_equal_func_t)(void *, void *);
 
 typedef struct {
     size_t digest_len;

Modified: trunk/ext/digest/sha2/sha2.c
===================================================================
--- trunk/ext/digest/sha2/sha2.c	2006-02-09 23:21:27 UTC (rev 378)
+++ trunk/ext/digest/sha2/sha2.c	2006-02-11 05:42:50 UTC (rev 379)
@@ -34,7 +34,7 @@
  */
 
 /* $RoughId: sha2.c,v 1.3 2002/02/26 22:03:36 knu Exp $ */
-/* $Id: sha2.c,v 1.4 2003/07/26 15:03:12 matz Exp $ */
+/* $Id: sha2.c,v 1.5 2005/12/29 12:05:01 matz Exp $ */
 
 #include "sha2.h"
 #include <stdio.h>
@@ -67,7 +67,7 @@
 typedef uint32_t sha2_word32;	/* Exactly 4 bytes */
 typedef uint64_t sha2_word64;	/* Exactly 8 bytes */
 
-#if defined(__GNUC__) || defined(_HPUX_SOURCE)
+#if defined(__GNUC__) || defined(_HPUX_SOURCE) || defined(__IBMC__)
 #define ULL(number)	number##ULL
 #else
 #define ULL(number)	(uint64_t)(number)

Modified: trunk/ext/etc/etc.c
===================================================================
--- trunk/ext/etc/etc.c	2006-02-09 23:21:27 UTC (rev 378)
+++ trunk/ext/etc/etc.c	2006-02-11 05:42:50 UTC (rev 379)
@@ -3,7 +3,7 @@
   etc.c -
 
   $Author: matz $
-  $Date: 2005/11/01 13:04:34 $
+  $Date: 2005/12/12 00:35:07 $
   created at: Tue Mar 22 18:39:19 JST 1994
 
 ************************************************/
@@ -521,6 +521,7 @@
     rb_define_module_function(mEtc, "endgrent", etc_endgrent, 0);
     rb_define_module_function(mEtc, "getgrent", etc_getgrent, 0);
 
+    rb_global_variable(&sPasswd);
     sPasswd =  rb_struct_define("Passwd",
 				"name", "passwd", "uid", "gid",
 #ifdef HAVE_ST_PW_GECOS
@@ -546,14 +547,13 @@
 				"expire",
 #endif
 				NULL);
-    rb_global_variable(&sPasswd);
 
 #ifdef HAVE_GETGRENT
+    rb_global_variable(&sGroup);
     sGroup = rb_struct_define("Group", "name",
 #ifdef HAVE_ST_GR_PASSWD
 			      "passwd",
 #endif
 			      "gid", "mem", NULL);
-    rb_global_variable(&sGroup);
 #endif
 }

Modified: trunk/ext/win32ole/win32ole.c
===================================================================
--- trunk/ext/win32ole/win32ole.c	2006-02-09 23:21:27 UTC (rev 378)
+++ trunk/ext/win32ole/win32ole.c	2006-02-11 05:42:50 UTC (rev 379)
@@ -12,7 +12,7 @@
  */
 
 /*
-  $Date: 2005/09/23 08:39:24 $
+  $Date: 2006/02/03 09:15:37 $
   modified for win32ole (ruby) by Masaki.Suketa <masaki.suketa nifty.ne.jp>
  */
 
@@ -2218,7 +2218,7 @@
         op.dp.cArgs = cNamedArgs + argc - 2;
         op.pNamedArgs = ALLOCA_N(OLECHAR*, cNamedArgs + 1);
         op.dp.rgvarg = ALLOCA_N(VARIANTARG, op.dp.cArgs);
-        rb_iterate(rb_each, param, hash2named_arg, (VALUE)&op);
+        rb_block_call(param, rb_intern("each"), 0, 0, hash2named_arg, (VALUE)&op);
 
         pDispID = ALLOCA_N(DISPID, cNamedArgs + 1);
         op.pNamedArgs[0] = ole_mb2wc(StringValuePtr(cmd), -1);
@@ -6904,8 +6904,8 @@
 void
 Init_win32ole()
 {
+    rb_global_variable(&ary_ole_event);
     ary_ole_event = rb_ary_new();
-    rb_global_variable(&ary_ole_event);
     id_events = rb_intern("events");
 
     com_vtbl.QueryInterface = QueryInterface;
@@ -6915,8 +6915,8 @@
     com_vtbl.GetTypeInfo = GetTypeInfo;
     com_vtbl.GetIDsOfNames = GetIDsOfNames;
     com_vtbl.Invoke = Invoke;
+    rb_global_variable(&com_hash);
     com_hash = Data_Wrap_Struct(rb_cData, rb_mark_hash, st_free_table, st_init_numtable());
-    rb_global_variable(&com_hash);
 
     cWIN32OLE = rb_define_class("WIN32OLE", rb_cObject);
 

Modified: trunk/hash.c
===================================================================
--- trunk/hash.c	2006-02-09 23:21:27 UTC (rev 378)
+++ trunk/hash.c	2006-02-11 05:42:50 UTC (rev 379)
@@ -3,7 +3,7 @@
   hash.c -
 
   $Author: ocean $
-  $Date: 2005/10/20 02:56:22 $
+  $Date: 2006/02/01 13:27:10 $
   created at: Mon Nov 22 18:51:18 JST 1993
 
   Copyright (C) 1993-2003 Yukihiro Matsumoto
@@ -196,8 +196,6 @@
     rb_ensure(hash_foreach_call, (VALUE)&arg, hash_foreach_ensure, hash);
 }
 
-static VALUE hash_alloc(VALUE);
-
 static VALUE
 hash_alloc(VALUE klass)
 {
@@ -1690,7 +1688,7 @@
      *         RTL's environ global variable directly yet.
      */
     SetEnvironmentVariable(name,value);
-#elif defined __CYGWIN__
+#elif defined(HAVE_SETENV) && defined(HAVE_UNSETENV)
 #undef setenv
 #undef unsetenv
     if (value)

Modified: trunk/intern.h
===================================================================
--- trunk/intern.h	2006-02-09 23:21:27 UTC (rev 378)
+++ trunk/intern.h	2006-02-11 05:42:50 UTC (rev 379)
@@ -3,7 +3,7 @@
   intern.h -
 
   $Author: nobu $
-  $Date: 2005/11/11 17:11:05 $
+  $Date: 2006/01/25 13:29:44 $
   created at: Thu Jun 10 14:22:17 JST 1993
 
   Copyright (C) 1993-2003 Yukihiro Matsumoto
@@ -200,7 +200,6 @@
 void ruby_set_current_source(void);
 NORETURN(void rb_exc_raise(VALUE));
 NORETURN(void rb_exc_fatal(VALUE));
-VALUE rb_make_exception(int argc, VALUE *argv);
 VALUE rb_f_exit(int,VALUE*);
 VALUE rb_f_abort(int,VALUE*);
 void rb_remove_method(VALUE, const char*);
@@ -284,7 +283,6 @@
 void rb_thread_atfork(void);
 VALUE rb_exec_recursive(VALUE(*)(VALUE, VALUE, int),VALUE,VALUE);
 /* file.c */
-int eaccess(const char*, int);
 VALUE rb_file_s_expand_path(int, VALUE *);
 VALUE rb_file_expand_path(VALUE, VALUE);
 void rb_file_const(const char*, VALUE);

Modified: trunk/io.c
===================================================================
--- trunk/io.c	2006-02-09 23:21:27 UTC (rev 378)
+++ trunk/io.c	2006-02-11 05:42:50 UTC (rev 379)
@@ -3798,12 +3798,7 @@
 void
 rb_write_error2(const char *mesg, long len)
 {
-    if (rb_stderr == orig_stderr || RFILE(orig_stderr)->fptr->fd < 0) {
-	fwrite(mesg, sizeof(char), len, stderr);
-    }
-    else {
 	rb_io_write(rb_stderr, rb_str_new(mesg, len));
-    }
 }
 
 void
@@ -5246,7 +5241,7 @@
     if (TYPE(current_file) != T_FILE) {
 	for (;;) {
 	    if (!next_argv()) return argf;
-	    rb_iterate(rb_each, current_file, rb_yield, 0);
+	    rb_block_call(current_file, rb_intern("each"), 0, 0, rb_yield, 0);
 	    next_p = 1;
 	}
     }

Modified: trunk/lib/cgi.rb
===================================================================
--- trunk/lib/cgi.rb	2006-02-09 23:21:27 UTC (rev 378)
+++ trunk/lib/cgi.rb	2006-02-11 05:42:50 UTC (rev 379)
@@ -284,7 +284,7 @@
   # Standard internet newline sequence
   EOL = CR + LF
 
-  REVISION = '$Id: cgi.rb,v 1.83 2005/10/21 09:00:00 matz Exp $' #:nodoc:
+  REVISION = '$Id: cgi.rb,v 1.84 2005/12/29 12:03:55 matz Exp $' #:nodoc:
 
   NEEDS_BINMODE = true if /WIN/ni.match(RUBY_PLATFORM) 
 
@@ -993,22 +993,9 @@
 
       loop do
         head = nil
-        if 10240 < content_length
-          require "tempfile"
-          body = Tempfile.new("CGI")
-        else
-          begin
-            require "stringio"
-            body = StringIO.new
-          rescue LoadError
-            require "tempfile"
-            body = Tempfile.new("CGI")
-          end
-        end
-        body.binmode if defined? body.binmode
+        body = MorphingBody.new
 
         until head and /#{boundary}(?:#{EOL}|--)/n.match(buf)
-
           if (not head) and /#{EOL}#{EOL}/n.match(buf)
             buf = buf.sub(/\A((?:.|\n)*?#{EOL})#{EOL}/n) do
               head = $1.dup
@@ -1042,6 +1029,7 @@
           ""
         end
 
+        p body
         body.rewind
 
         /Content-Disposition:.* filename="?([^\";]*)"?/ni.match(head)
@@ -1062,7 +1050,7 @@
         end
 
         /Content-Disposition:.* name="?([^\";]*)"?/ni.match(head)
-        name = $1.dup
+        name = ($1 || "").dup
 
         if params.has_key?(name)
           params[name].push(body)
@@ -1081,8 +1069,7 @@
     def read_from_cmdline
       require "shellwords"
 
-      string =
-      unless ARGV.empty? && !$CGI_DONTINPUT
+      string = unless ARGV.empty?
         ARGV.join(' ')
       else
         if STDIN.tty?
@@ -1103,6 +1090,59 @@
     end
     private :read_from_cmdline
 
+    # A wrapper class to use a StringIO object as the body and switch
+    # to a TempFile when the passed threshold is passed.
+    class MorphingBody
+      begin
+        require "stringio"
+        @@small_buffer = lambda{StringIO.new}
+      rescue LoadError
+        require "tempfile"
+        @@small_buffer = lambda{
+          n = Tempfile.new("CGI")
+          n.binmode
+          n
+        }
+      end
+
+      def initialize(morph_threshold = 10240)
+        @threshold = morph_threshold
+        @body =   small_buffer.call
+        @cur_size = 0
+        @morph_check = true
+      end
+
+      def print(data)
+        if @morph_check && (@cur_size + data.size > @threshold)
+          convert_body
+        end
+        @body.print data
+      end
+      def rewind
+        @body.rewind
+      end
+      def path
+        @body.path
+      end
+
+      # returns the true body object.
+      def extract
+        @body
+      end
+
+      private
+      def convert_body
+        new_body = TempFile.new("CGI")
+        new_body.binmode if defined? @body.binmode
+        new_body.binmode if defined? new_body.binmode
+
+        @body.rewind
+        new_body.print @body.read
+        @body = new_body
+        @morph_check = false
+      end
+    end
+
     # Initialize the data from the query.
     #
     # Handles multipart forms (in particular, forms that involve file uploads).

Modified: trunk/lib/complex.rb
===================================================================
--- trunk/lib/complex.rb	2006-02-09 23:21:27 UTC (rev 378)
+++ trunk/lib/complex.rb	2006-02-11 05:42:50 UTC (rev 379)
@@ -103,6 +103,10 @@
 
   undef step
 
+  def scalar?
+    false
+  end
+
   def Complex.generic?(other) # :nodoc:
     other.kind_of?(Integer) or
     other.kind_of?(Float) or
@@ -306,12 +310,7 @@
   end
   alias conj conjugate
   
-  #
-  # Compares the absolute values of the two numbers.
-  #
-  def <=> (other)
-    self.abs <=> other.abs
-  end
+  undef <=>
   
   #
   # Test for numerical equality (<tt>a == a + 0<i>i</i></tt>).

Modified: trunk/lib/delegate.rb
===================================================================
--- trunk/lib/delegate.rb	2006-02-09 23:21:27 UTC (rev 378)
+++ trunk/lib/delegate.rb	2006-02-11 05:42:50 UTC (rev 379)
@@ -121,6 +121,7 @@
     undef_method m
   end
 
+  module MethodDelegation
   #
   # Pass in the _obj_ to delegate method calls to.  All methods supported by
   # _obj_ will be delegated to.
@@ -130,13 +131,14 @@
   end
 
   # Handles the magic of delegation through \_\_getobj\_\_.
-  def method_missing(m, *args)
+    def method_missing(m, *args, &block)
     begin
       target = self.__getobj__
       unless target.respond_to?(m)
-        super(m, *args)
+          super(m, *args, &block)
+        else
+          target.__send__(m, *args, &block)
       end
-      target.__send__(m, *args)
     rescue Exception
       $@.delete_if{|s| /^#{__FILE__}:\d+:in `method_missing'$/ =~ s} #`
       ::Kernel::raise
@@ -153,6 +155,21 @@
   end
 
   #
+    # Returns true if two objects are considered same.
+    # 
+    def ==(obj)
+      return true if obj.equal?(self)
+      self.__getobj__ == obj
+    end
+
+    # 
+    # Returns true only if two objects are identical.
+    # 
+    def equal?(obj)
+      self.object_id == obj.object_id
+    end
+
+    #
   # This method must be overridden by subclasses and should return the object
   # method calls are being delegated to.
   #
@@ -176,6 +193,21 @@
   def marshal_load(obj)
     __setobj__(obj)
   end
+
+    # Clone support for the object returned by \_\_getobj\_\_.
+    def clone
+      new = super
+      new.__setobj__(__getobj__.clone)
+      new
+    end
+    # Duplication support for the object returned by \_\_getobj\_\_.
+    def dup
+      new = super
+      new.__setobj__(__getobj__.dup)
+      new
+    end
+  end
+  include MethodDelegation
 end
 
 #
@@ -208,19 +240,6 @@
     raise ArgumentError, "cannot delegate to self" if self.equal?(obj)
     @_sd_obj = obj
   end
-
-  # Clone support for the object returned by \_\_getobj\_\_.
-  def clone
-    copy = super
-    copy.__setobj__(__getobj__.clone)
-    copy
-  end
-  # Duplication support for the object returned by \_\_getobj\_\_.
-  def dup
-    copy = super
-    copy.__setobj__(__getobj__.dup)
-    copy
-  end
 end
 
 # :stopdoc:
@@ -243,24 +262,12 @@
   klass = Class.new
   methods = superclass.public_instance_methods(true)
   methods -= [
-    "__id__", "object_id", "__send__", "respond_to?",
+    "__id__", "object_id", "__send__", "respond_to?", "==", "equal?",
     "initialize", "method_missing", "__getobj__", "__setobj__",
     "clone", "dup", "marshal_dump", "marshal_load",
   ]
   klass.module_eval {
-    def initialize(obj)  # :nodoc:
-      @_dc_obj = obj
-    end
-    def method_missing(m, *args)  # :nodoc:
-      unless @_dc_obj.respond_to?(m)
-        super(m, *args)
-      end
-      @_dc_obj.__send__(m, *args)
-    end
-    def respond_to?(m)  # :nodoc:
-      return true if super
-      return @_dc_obj.respond_to?(m)
-    end
+    include Delegator::MethodDelegation
     def __getobj__  # :nodoc:
       @_dc_obj
     end
@@ -268,14 +275,6 @@
       raise ArgumentError, "cannot delegate to self" if self.equal?(obj)
       @_dc_obj = obj
     end
-    def clone  # :nodoc:
-      super
-      __setobj__(__getobj__.clone)
-    end
-    def dup  # :nodoc:
-      super
-      __setobj__(__getobj__.dup)
-    end
   }
   for method in methods
     begin
@@ -309,15 +308,23 @@
   p ary.class
   ary.push 25
   p ary
+  ary.push 42
+  ary.each {|x| p x}
 
   foo = Object.new
   def foo.test
     25
   end
+  def foo.iter
+    yield self
+  end
   def foo.error
     raise 'this is OK'
   end
   foo2 = SimpleDelegator.new(foo)
+  p foo2
+  foo2.instance_eval{print "foo\n"}
   p foo.test == foo2.test	# => true
+  p foo2.iter{[55,true]}        # => true
   foo2.error			# raise error!
 end

Modified: trunk/lib/erb.rb
===================================================================
--- trunk/lib/erb.rb	2006-02-09 23:21:27 UTC (rev 378)
+++ trunk/lib/erb.rb	2006-02-11 05:42:50 UTC (rev 379)
@@ -236,7 +236,7 @@
 # Rails, the web application framework, uses ERB to create views.
 #
 class ERB
-  Revision = '$Date: 2005/02/12 16:34:45 $' 	#'
+  Revision = '$Date: 2006/01/10 15:21:45 $' 	#'
 
   # Returns revision information for the erb.rb module.
   def self.version
@@ -558,7 +558,7 @@
 		out.push(content)
 	      end
 	    when '<%='
-	      out.push("#{ put_cmd}((#{content}).to_s)")
+	      out.push("#{ insert_cmd}((#{content}).to_s)")
 	    when '<%#'
 	      # out.push("# #{content.dump}")
 	    end
@@ -607,11 +607,12 @@
     def initialize(trim_mode)
       @percent, @trim_mode = prepare_trim_mode(trim_mode)
       @put_cmd = 'print'
+      @insert_cmd = @put_cmd
       @pre_cmd = []
       @post_cmd = []
     end
     attr_reader :percent, :trim_mode
-    attr_accessor :put_cmd, :pre_cmd, :post_cmd
+    attr_accessor :put_cmd, :insert_cmd, :pre_cmd, :post_cmd
   end
 end
 
@@ -705,6 +706,7 @@
   #
   def set_eoutvar(compiler, eoutvar = '_erbout')
     compiler.put_cmd = "#{eoutvar}.concat"
+    compiler.insert_cmd = "#{eoutvar}.concat"
 
     cmd = []
     cmd.push "#{eoutvar} = ''"
@@ -822,5 +824,3 @@
     module_function :def_erb_method
   end
 end
-
-

Modified: trunk/lib/fileutils.rb
===================================================================
--- trunk/lib/fileutils.rb	2006-02-09 23:21:27 UTC (rev 378)
+++ trunk/lib/fileutils.rb	2006-02-11 05:42:50 UTC (rev 379)
@@ -274,7 +274,7 @@
   # <b><tt>ln(old, new, options = {})</tt></b>
   #
   # Creates a hard link +new+ which points to +old+.
-  # If +new+ already exists and it is a directory, creates a symbolic link +new/old+.
+  # If +new+ already exists and it is a directory, creates a link +new/old+.
   # If +new+ already exists and it is not a directory, raises Errno::EEXIST.
   # But if :force option is set, overwrite +new+.
   # 
@@ -500,6 +500,7 @@
           File.rename s, d
         rescue Errno::EXDEV
           copy_entry s, d, true
+          File.unlink s
         end
       rescue SystemCallError
         raise unless options[:force]

Modified: trunk/lib/matrix.rb
===================================================================
--- trunk/lib/matrix.rb	2006-02-09 23:21:27 UTC (rev 378)
+++ trunk/lib/matrix.rb	2006-02-11 05:42:50 UTC (rev 379)
@@ -2,8 +2,8 @@
 #--
 #   matrix.rb - 
 #       $Release Version: 1.0$
-#       $Revision: 1.11 $
-#       $Date: 1999/10/06 11:01:53 $
+#   	$Revision: 1.13 $
+#   	$Date: 2001/12/09 14:22:23 $
 #       Original Version from Smalltalk-80 version
 #          on July 23, 1985 at 8:37:17 am
 #       by Keiju ISHITSUKA
@@ -105,7 +105,7 @@
 # * <tt> #inspect                       </tt>
 #
 class Matrix
-  @RCS_ID='-$Id: matrix.rb,v 1.11 1999/10/06 11:01:53 keiju Exp keiju $-'
+  @RCS_ID='-$Id: matrix.rb,v 1.13 2001/12/09 14:22:23 keiju Exp keiju $-'
   
 #  extend Exception2MessageMapper
   include ExceptionForMatrix
@@ -265,7 +265,16 @@
   def [](i, j)
     @rows[i][j]
   end
+  alias element []
+  alias component []
 
+  def []=(i, j, v)
+    @rows[i][j] = v
+  end
+  alias set_element []=
+  alias set_component []=
+  private :[]=, :set_element, :set_component
+
   #
   # Returns the number of rows.
   #
@@ -320,7 +329,7 @@
   #
   # Returns a matrix that is the result of iteration of the given block over all
   # elements of the matrix.
-  #   Matrix[ [1,2], [3,4] ].collect { |i| i**2 }
+  #   Matrix[ [1,2], [3,4] ].collect { |e| e**2 }
   #     => 1  4
   #        9 16
   #
@@ -668,9 +677,13 @@
   
   #
   # Returns the determinant of the matrix.  If the matrix is not square, the
-  # result is 0.
+  # result is 0. This method's algorism is Gaussian elimination method
+  # and using Numeric#quo(). Beware that using Float values, with their
+  # usual lack of precision, can affect the value returned by this method.  Use
+  # Rational values or Matrix#det_e instead if this is important to you.
+  #
   #   Matrix[[7,6], [3,9]].determinant
-  #     => 63
+  #     => 63.0
   #
   def determinant
     return 0 unless square?
@@ -705,9 +718,54 @@
   alias det determinant
         
   #
-  # Returns the rank of the matrix.  Beware that using Float values, with their
-  # usual lack of precision, can affect the value returned by this method.  Use
-  # Rational values instead if this is important to you.
+  # Returns the determinant of the matrix.  If the matrix is not square, the
+  # result is 0. This method's algorism is Gaussian elimination method. 
+  # This method uses Euclidean algorism. If all elements are integer,
+  # really exact value. But, if an element is a float, can't return
+  # exact value.   
+  #
+  #   Matrix[[7,6], [3,9]].determinant
+  #     => 63
+  #
+  def determinant_e
+    return 0 unless square?
+    
+    size = row_size - 1
+    a = to_a
+    
+    det = 1
+    k = 0
+    begin 
+      if a[k][k].zero?
+        i = k
+        begin
+          return 0 if (i += 1) > size
+        end while a[i][k].zero?
+        a[i], a[k] = a[k], a[i]
+        det *= -1
+      end
+      (k + 1).upto(size) do |i|
+        q = a[i][k] / a[k][k]
+        k.upto(size) do |j|
+          a[i][j] -= a[k][j] * q
+        end
+        unless a[i][k].zero?
+          a[i], a[k] = a[k], a[i]
+          det *= -1
+          redo
+        end
+      end
+      det *= a[k][k]
+    end while (k += 1) <= size
+    det
+  end
+  alias det_e determinant_e
+
+  #
+  # Returns the rank of the matrix. Beware that using Float values,
+  # probably return faild value. Use Rational values or Matrix#rank_e
+  # for getting exact result.
+  #
   #   Matrix[[7,6], [3,9]].rank
   #     => 2
   #
@@ -770,6 +828,41 @@
   end
 
   #
+  # Returns the rank of the matrix. This method uses Euclidean
+  # algorism. If all elements are integer, really exact value. But, if
+  # an element is a float, can't return exact value.  
+  #
+  #   Matrix[[7,6], [3,9]].rank
+  #     => 2
+  #
+  def rank_e
+    a = to_a
+    a_column_size = column_size
+    a_row_size = row_size
+    pi = 0
+    (0 ... a_column_size).each do |j|
+      if i = (pi ... a_row_size).find{|i0| !a[i0][j].zero?}
+        if i != pi
+          a[pi], a[i] = a[i], a[pi]
+        end
+        (pi + 1 ... a_row_size).each do |k|
+          q = a[k][j] / a[pi][j]
+          (pi ... a_column_size).each do |j0|
+            a[k][j0] -= q * a[pi][j0]
+          end
+          if k > pi && !a[k][j].zero?
+            a[k], a[pi] = a[pi], a[k]
+            redo
+          end
+        end
+        pi += 1
+      end
+    end
+    pi
+  end
+
+
+  #
   # Returns the trace (sum of diagonal elements) of the matrix.
   #   Matrix[[7,6], [3,9]].trace
   #     => 16
@@ -844,6 +937,18 @@
     @rows.collect{|row| row.collect{|e| e}}
   end
   
+  def elements_to_f
+    collect{|e| e.to_f}
+  end
+  
+  def elements_to_i
+    collect{|e| e.to_i}
+  end
+  
+  def elements_to_r
+    collect{|e| e.to_r}
+  end
+  
   #--
   # PRINTING -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
   #++
@@ -922,7 +1027,7 @@
       when Vector
         Scalar.Raise WrongArgType, other.class, "Numeric or Scalar or Matrix"
       when Matrix
-        self * _M.inverse
+	self * other.inverse
       else
         x, y = other.coerce(self)
         x.quo(y)
@@ -1034,6 +1139,15 @@
   def [](i)
     @elements[i]
   end
+  alias element []
+  alias component []
+
+  def []=(i, v)
+    @elements[i]= v
+  end
+  alias set_element []=
+  alias set_component []=
+  private :[]=, :set_element, :set_component
   
   #
   # Returns the number of elements in the vector.
@@ -1236,6 +1350,18 @@
     @elements.dup
   end
   
+  def elements_to_f
+    collect{|e| e.to_f}
+  end
+  
+  def elements_to_i
+    collect{|e| e.to_i}
+  end
+  
+  def elements_to_r
+    collect{|e| e.to_r}
+  end
+  
   #
   # FIXME: describe Vector#coerce.
   #

Modified: trunk/lib/mkmf.rb
===================================================================
--- trunk/lib/mkmf.rb	2006-02-09 23:21:27 UTC (rev 378)
+++ trunk/lib/mkmf.rb	2006-02-11 05:42:50 UTC (rev 379)
@@ -534,7 +534,7 @@
 end
 
 def checking_for(m, fmt = nil)
-  f = caller[0][/in `(.*)'$/, 1] and f << ": " #` for vim, ' for xyzzy
+  f = caller[0][/in `(.*)'$/, 1] and f << ": " #` for vim
   m = "checking for #{m}... "
   message "%s", m
   a = r = nil
@@ -793,11 +793,25 @@
   $configure_args.fetch(config.tr('_', '-'), *defaults, &block)
 end
 
-def with_config(config, *defaults, &block)
-  unless /^--with[-_]/ =~ config
-    config = '--with-' + config
+def with_config(config, *defaults)
+  config = config.sub(/^--with[-_]/, '')
+  val = arg_config("--with-"+config) do
+    if arg_config("--without-"+config)
+      false
+    elsif block_given?
+      yield(config, *defaults)
+    else
+      break *defaults
+    end
   end
-  arg_config(config, *defaults, &block)
+  case val
+  when "yes"
+    true
+  when "no"
+    false
+  else
+    val
+  end
 end
 
 def enable_config(config, *defaults)
@@ -1037,7 +1051,7 @@
     if File.exist?(File.join(srcdir, target + '.def'))
       deffile = "$(srcdir)/$(TARGET).def"
       unless EXPORT_PREFIX.empty?
-        makedef = %{-pe "sub!(/^(?=\\w)/,'#{EXPORT_PREFIX}') unless 1../^EXPORTS$/i"}
+        makedef = %{-pe "$_.sub!(/^(?=\\w)/,'#{EXPORT_PREFIX}') unless 1../^EXPORTS$/i"}
       end
     else
       makedef = %{-e "puts 'EXPORTS', '#{EXPORT_PREFIX}Init_$(TARGET)'"}
@@ -1088,7 +1102,7 @@
   mfile.print CLEANINGS
   dirs = []
   mfile.print "install: install-so install-rb\n\n"
-  sodir = dir = "$(RUBYARCHDIR)"
+  sodir = (dir = "$(RUBYARCHDIR)").dup
   mfile.print("install-so: #{dir}\n")
   if target
     f = "$(DLLIB)"
@@ -1108,10 +1122,10 @@
       mfile.print "\t$(INSTALL_PROG) #{f} #{dir}\n"
     end
   end
-  dirs << (dir = "$(RUBYLIBDIR)")
   mfile.print("install-rb: pre-install-rb install-rb-default\n")
   mfile.print("install-rb-default: pre-install-rb-default\n")
-  mfile.print("pre-install-rb pre-install-rb-default: #{dir}\n")
+  mfile.print("pre-install-rb: Makefile\n")
+  mfile.print("pre-install-rb-default: Makefile\n")
   for sfx, i in [["-default", [["lib/**/*.rb", "$(RUBYLIBDIR)", "lib"]]], ["", $INSTALLFILES]]
     files = install_files(mfile, i, nil, srcprefix) or next
     for dir, *files in files
@@ -1382,5 +1396,5 @@
 "
 
 if not $extmk and /\A(extconf|makefile).rb\z/ =~ File.basename($0)
-  # END {mkmf_failed($0)}
+  END {mkmf_failed($0)}
 end

Added: trunk/lib/net/.document
===================================================================
--- trunk/lib/net/.document	2006-02-09 23:21:27 UTC (rev 378)
+++ trunk/lib/net/.document	2006-02-11 05:42:50 UTC (rev 379)
@@ -0,0 +1,8 @@
+ftp.rb
+http.rb
+https.rb
+imap.rb
+pop.rb
+smtp.rb
+smtps.rb
+telnet.rb

Added: trunk/lib/net/ftp.rb
===================================================================
--- trunk/lib/net/ftp.rb	2006-02-09 23:21:27 UTC (rev 378)
+++ trunk/lib/net/ftp.rb	2006-02-11 05:42:50 UTC (rev 379)
@@ -0,0 +1,964 @@
+# 
+# = net/ftp.rb - FTP Client Library
+# 
+# Written by Shugo Maeda <shugo ruby-lang.org>.
+#
+# Documentation by Gavin Sinclair, sourced from "Programming Ruby" (Hunt/Thomas)
+# and "Ruby In a Nutshell" (Matsumoto), used with permission.
+# 
+# This library is distributed under the terms of the Ruby license.
+# You can freely distribute/modify this library.
+#
+# It is included in the Ruby standard library.
+#
+# See the Net::FTP class for an overview.
+#
+
+require "socket"
+require "monitor"
+
+module Net
+
+  # :stopdoc:
+  class FTPError < StandardError; end
+  class FTPReplyError < FTPError; end
+  class FTPTempError < FTPError; end 
+  class FTPPermError < FTPError; end 
+  class FTPProtoError < FTPError; end
+  # :startdoc:
+
+  #
+  # This class implements the File Transfer Protocol.  If you have used a
+  # command-line FTP program, and are familiar with the commands, you will be
+  # able to use this class easily.  Some extra features are included to take
+  # advantage of Ruby's style and strengths.
+  #
+  # == Example
+  # 
+  #   require 'net/ftp'
+  #
+  # === Example 1
+  #  
+  #   ftp = Net::FTP.new('ftp.netlab.co.jp')
+  #   ftp.login
+  #   files = ftp.chdir('pub/lang/ruby/contrib')
+  #   files = ftp.list('n*')
+  #   ftp.getbinaryfile('nif.rb-0.91.gz', 'nif.gz', 1024)
+  #   ftp.close
+  #
+  # === Example 2
+  #
+  #   Net::FTP.open('ftp.netlab.co.jp') do |ftp|
+  #     ftp.login
+  #     files = ftp.chdir('pub/lang/ruby/contrib')
+  #     files = ftp.list('n*')
+  #     ftp.getbinaryfile('nif.rb-0.91.gz', 'nif.gz', 1024)
+  #   end
+  #
+  # == Major Methods
+  #
+  # The following are the methods most likely to be useful to users:
+  # - FTP.open
+  # - #getbinaryfile
+  # - #gettextfile
+  # - #putbinaryfile
+  # - #puttextfile
+  # - #chdir
+  # - #nlst
+  # - #size
+  # - #rename
+  # - #delete
+  #
+  class FTP
+    include MonitorMixin
+    
+    # :stopdoc:
+    FTP_PORT = 21
+    CRLF = "\r\n"
+    DEFAULT_BLOCKSIZE = 4096
+    # :startdoc:
+    
+    # When +true+, transfers are performed in binary mode.  Default: +true+.
+    attr_reader :binary
+
+    # When +true+, the connection is in passive mode.  Default: +false+.
+    attr_accessor :passive
+
+    # When +true+, all traffic to and from the server is written
+    # to +$stdout+.  Default: +false+.
+    attr_accessor :debug_mode
+
+    # Sets or retrieves the +resume+ status, which decides whether incomplete
+    # transfers are resumed or restarted.  Default: +false+.
+    attr_accessor :resume
+
+    # The server's welcome message.
+    attr_reader :welcome
+
+    # The server's last response code.
+    attr_reader :last_response_code
+    alias lastresp last_response_code
+
+    # The server's last response.
+    attr_reader :last_response
+    
+    #
+    # A synonym for <tt>FTP.new</tt>, but with a mandatory host parameter.
+    #
+    # If a block is given, it is passed the +FTP+ object, which will be closed
+    # when the block finishes, or when an exception is raised.
+    #
+    def FTP.open(host, user = nil, passwd = nil, acct = nil)
+      if block_given?
+        ftp = new(host, user, passwd, acct)
+        begin
+          yield ftp
+        ensure
+          ftp.close
+        end
+      else
+        new(host, user, passwd, acct)
+      end
+    end
+    
+    #
+    # Creates and returns a new +FTP+ object. If a +host+ is given, a connection
+    # is made. Additionally, if the +user+ is given, the given user name,
+    # password, and (optionally) account are used to log in.  See #login.
+    #
+    def initialize(host = nil, user = nil, passwd = nil, acct = nil)
+      super()
+      @binary = false
+      @passive = false
+      @debug_mode = false
+      @resume = false
+      if host
+	connect(host)
+	if user
+	  login(user, passwd, acct)
+	end
+      end
+    end
+
+    def binary=(newmode)
+      if newmode != @binary
+        @binary = newmode
+        @binary ? voidcmd("TYPE I") : voidcmd("TYPE A")
+      end
+    end
+
+    def with_binary(newmode)
+      oldmode = binary
+      self.binary = newmode
+      begin
+        yield
+      ensure
+        self.binary = oldmode
+      end
+    end
+    private :with_binary
+
+    # Obsolete
+    def return_code
+      $stderr.puts("warning: Net::FTP#return_code is obsolete and do nothing")
+      return "\n"
+    end
+
+    # Obsolete
+    def return_code=(s)
+      $stderr.puts("warning: Net::FTP#return_code= is obsolete and do nothing")
+    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
+    
+    #
+    # Establishes an FTP connection to host, optionally overriding the default
+    # port. If the environment variable +SOCKS_SERVER+ is set, sets up the
+    # connection through a SOCKS proxy. Raises an exception (typically
+    # <tt>Errno::ECONNREFUSED</tt>) if the connection cannot be established.
+    #
+    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
+
+    #
+    # WRITEME or make private
+    #
+    def set_socket(sock, get_greeting = true)
+      synchronize do
+	@sock = sock
+	if get_greeting
+	  voidresp
+	end
+      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
+      line.sub!(/(\r\n|\n|\r)\z/n, "")
+      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
+      @last_response = getmultiline
+      @last_response_code = @last_response[0, 3]
+      case @last_response_code
+      when /\A[123]/
+	return @last_response
+      when /\A4/
+	raise FTPTempError, @last_response
+      when /\A5/
+	raise FTPPermError, @last_response
+      else
+	raise FTPProtoError, @last_response
+      end
+    end
+    private :getresp
+    
+    def voidresp
+      resp = getresp
+      if resp[0] != ?2
+	raise FTPReplyError, resp
+      end
+    end
+    private :voidresp
+    
+    #
+    # Sends a command and returns the response.
+    #
+    def sendcmd(cmd)
+      synchronize do
+	putline(cmd)
+	return getresp
+      end
+    end
+    
+    #
+    # Sends a command and expect a response beginning with '2'.
+    #
+    def voidcmd(cmd)
+      synchronize do
+	putline(cmd)
+	voidresp
+      end
+    end
+    
+    def sendport(host, port)
+      af = ( sock.peeraddr)[0]
+      if af == "AF_INET"
+	hbytes = host.split(".")
+	pbytes = [port / 256, port % 256]
+	bytes = hbytes + pbytes
+	cmd = "PORT " + bytes.join(",")
+      elsif af == "AF_INET6"
+	cmd = "EPRT |2|" + host + "|" + sprintf("%d", port) + "|"
+      else
+	raise FTPProtoError, host
+      end
+      voidcmd(cmd)
+    end
+    private :sendport
+    
+    def makeport
+      sock = TCPServer.open( sock.addr[3], 0)
+      port = sock.addr[1]
+      host = sock.addr[3]
+      resp = sendport(host, port)
+      return sock
+    end
+    private :makeport
+    
+    def makepasv
+      if @sock.peeraddr[0] == "AF_INET"
+	host, port = parse227(sendcmd("PASV"))
+      else
+	host, port = parse229(sendcmd("EPSV"))
+	#     host, port = parse228(sendcmd("LPSV"))
+      end
+      return host, port
+    end
+    private :makepasv
+    
+    def transfercmd(cmd, rest_offset = nil)
+      if @passive
+	host, port = makepasv
+	conn = open_socket(host, port)
+	if @resume and rest_offset
+	  resp = sendcmd("REST " + rest_offset.to_s) 
+	  if resp[0] != ?3
+	    raise FTPReplyError, resp
+	  end
+	end
+	resp = sendcmd(cmd)
+	if resp[0] != ?1
+	  raise FTPReplyError, resp
+	end
+      else
+	sock = makeport
+	if @resume and rest_offset
+	  resp = sendcmd("REST " + rest_offset.to_s) 
+	  if resp[0] != ?3
+	    raise FTPReplyError, resp
+	  end
+	end
+	resp = sendcmd(cmd)
+	if resp[0] != ?1
+	  raise FTPReplyError, resp
+	end
+	conn = sock.accept
+	sock.close
+      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
+    
+    #
+    # Logs in to the remote host. The session must have been previously
+    # connected.  If +user+ is the string "anonymous" and the +password+ is
+    # +nil+, a password of <tt>user@host</tt> is synthesized. If the +acct+
+    # parameter is not +nil+, an FTP ACCT command is sent following the
+    # successful login.  Raises an exception on error (typically
+    # <tt>Net::FTPPermError</tt>).
+    #
+    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
+      self.binary = true
+    end
+    
+    #
+    # Puts the connection into binary (image) mode, issues the given command,
+    # and fetches the data returned, passing it to the associated block in
+    # chunks of +blocksize+ characters. Note that +cmd+ is a server command
+    # (such as "RETR myfile").
+    #
+    def retrbinary(cmd, blocksize, rest_offset = nil) # :yield: data
+      synchronize do
+	with_binary(true) do
+          conn = transfercmd(cmd, rest_offset)
+          loop do
+            data = conn.read(blocksize)
+            break if data == nil
+            yield(data)
+          end
+          conn.close
+          voidresp
+        end
+      end
+    end
+    
+    #
+    # Puts the connection into ASCII (text) mode, issues the given command, and
+    # passes the resulting data, one line at a time, to the associated block. If
+    # no block is given, prints the lines. Note that +cmd+ is a server command
+    # (such as "RETR myfile").
+    #
+    def retrlines(cmd) # :yield: line
+      synchronize do
+	with_binary(false) do
+          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
+            yield(line)
+          end
+          conn.close
+          voidresp
+        end
+      end
+    end
+    
+    #
+    # Puts the connection into binary (image) mode, issues the given server-side
+    # command (such as "STOR myfile"), and sends the contents of the file named
+    # +file+ to the server. If the optional block is given, it also passes it
+    # the data, in chunks of +blocksize+ characters.
+    #
+    def storbinary(cmd, file, blocksize, rest_offset = nil, &block) # :yield: data
+      if rest_offset
+        file.seek(rest_offset, IO::SEEK_SET)
+      end
+      synchronize do
+	with_binary(true) do
+          conn = transfercmd(cmd, rest_offset)
+          loop do
+            buf = file.read(blocksize)
+            break if buf == nil
+            conn.write(buf)
+            yield(buf) if block
+          end
+          conn.close
+          voidresp
+        end
+      end
+    end
+    
+    #
+    # Puts the connection into ASCII (text) mode, issues the given server-side
+    # command (such as "STOR myfile"), and sends the contents of the file
+    # named +file+ to the server, one line at a time. If the optional block is
+    # given, it also passes it the lines.
+    #
+    def storlines(cmd, file, &block) # :yield: line
+      synchronize do
+	with_binary(false) do
+          conn = transfercmd(cmd)
+          loop do
+            buf = file.gets
+            break if buf == nil
+            if buf[-2, 2] != CRLF
+              buf = buf.chomp + CRLF
+            end
+            conn.write(buf)
+            yield(buf) if block
+          end
+          conn.close
+          voidresp
+        end
+      end
+    end
+
+    #
+    # Retrieves +remotefile+ in binary mode, storing the result in +localfile+.
+    # If +localfile+ is nil, returns retrieved data.
+    # If a block is supplied, it is passed the retrieved data in +blocksize+
+    # chunks.
+    #
+    def getbinaryfile(remotefile, localfile = File.basename(remotefile),
+		      blocksize = DEFAULT_BLOCKSIZE) # :yield: data
+      result = nil
+      if localfile
+        if @resume
+          rest_offset = File.size?(localfile)
+          f = open(localfile, "a")
+        else
+          rest_offset = nil
+          f = open(localfile, "w")
+        end
+      elsif !block_given?
+        result = ""
+      end
+      begin
+	f.binmode if localfile
+	retrbinary("RETR " + remotefile, blocksize, rest_offset) do |data|
+	  f.write(data) if localfile
+	  yield(data) if block_given?
+          result.concat(data) if result
+	end
+        return result
+      ensure
+	f.close if localfile
+      end
+    end
+    
+    #
+    # Retrieves +remotefile+ in ASCII (text) mode, storing the result in
+    # +localfile+.
+    # If +localfile+ is nil, returns retrieved data.
+    # If a block is supplied, it is passed the retrieved data one
+    # line at a time.
+    #
+    def gettextfile(remotefile, localfile = File.basename(remotefile)) # :yield: line
+      result = nil
+      if localfile
+        f = open(localfile, "w")
+      elsif !block_given?
+        result = ""
+      end
+      begin
+	retrlines("RETR " + remotefile) do |line|
+	  f.puts(line) if localfile
+	  yield(line) if block_given?
+          result.concat(line + "\n") if result
+	end
+        return result
+      ensure
+	f.close if localfile
+      end
+    end
+
+    #
+    # Retrieves +remotefile+ in whatever mode the session is set (text or
+    # binary).  See #gettextfile and #getbinaryfile.
+    #
+    def get(remotefile, localfile = File.basename(remotefile),
+	    blocksize = DEFAULT_BLOCKSIZE, &block) # :yield: data
+      if @binary
+	getbinaryfile(remotefile, localfile, blocksize, &block)
+      else
+	gettextfile(remotefile, localfile, &block)
+      end
+    end
+    
+    #
+    # Transfers +localfile+ to the server in binary mode, storing the result in
+    # +remotefile+. If a block is supplied, calls it, passing in the transmitted
+    # data in +blocksize+ chunks.
+    #
+    def putbinaryfile(localfile, remotefile = File.basename(localfile),
+		      blocksize = DEFAULT_BLOCKSIZE, &block) # :yield: data
+      if @resume
+        begin
+          rest_offset = size(remotefile)
+        rescue Net::FTPPermError
+          rest_offset = nil
+        end
+      else
+	rest_offset = nil
+      end
+      f = open(localfile)
+      begin
+	f.binmode
+	storbinary("STOR " + remotefile, f, blocksize, rest_offset, &block)
+      ensure
+	f.close
+      end
+    end
+    
+    #
+    # Transfers +localfile+ to the server in ASCII (text) mode, storing the result
+    # in +remotefile+. If callback or an associated block is supplied, calls it,
+    # passing in the transmitted data one line at a time.
+    #
+    def puttextfile(localfile, remotefile = File.basename(localfile), &block) # :yield: line
+      f = open(localfile)
+      begin
+	storlines("STOR " + remotefile, f, &block)
+      ensure
+	f.close
+      end
+    end
+
+    #
+    # Transfers +localfile+ to the server in whatever mode the session is set
+    # (text or binary).  See #puttextfile and #putbinaryfile.
+    #
+    def put(localfile, remotefile = File.basename(localfile),
+	    blocksize = DEFAULT_BLOCKSIZE, &block)
+      if @binary
+	putbinaryfile(localfile, remotefile, blocksize, &block)
+      else
+	puttextfile(localfile, remotefile, &block)
+      end
+    end
+
+    #
+    # Sends the ACCT command.  TODO: more info.
+    #
+    def acct(account)
+      cmd = "ACCT " + account
+      voidcmd(cmd)
+    end
+    
+    #
+    # Returns an array of filenames in the remote directory.
+    #
+    def nlst(dir = nil)
+      cmd = "NLST"
+      if dir
+	cmd = cmd + " " + dir
+      end
+      files = []
+      retrlines(cmd) do |line|
+	files.push(line)
+      end
+      return files
+    end
+    
+    #
+    # Returns an array of file information in the directory (the output is like
+    # `ls -l`).  If a block is given, it iterates through the listing.
+    #
+    def list(*args, &block) # :yield: line
+      cmd = "LIST"
+      args.each do |arg|
+	cmd = cmd + " " + arg
+      end
+      if block
+	retrlines(cmd, &block)
+      else
+	lines = []
+	retrlines(cmd) do |line|
+	  lines << line
+	end
+	return lines
+      end
+    end
+    alias ls list
+    alias dir list
+    
+    #
+    # Renames a file on the server.
+    #
+    def rename(fromname, toname)
+      resp = sendcmd("RNFR " + fromname)
+      if resp[0] != ?3
+	raise FTPReplyError, resp
+      end
+      voidcmd("RNTO " + toname)
+    end
+    
+    #
+    # Deletes a file on the server.
+    #
+    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
+    
+    #
+    # Changes the (remote) directory.
+    #
+    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
+    
+    #
+    # Returns the size of the given (remote) filename.
+    #
+    def size(filename)
+      with_binary(true) do
+        resp = sendcmd("SIZE " + filename)
+        if resp[0, 3] != "213" 
+          raise FTPReplyError, resp
+        end
+        return resp[3..-1].strip.to_i
+      end
+    end
+    
+    MDTM_REGEXP = /^(\d\d\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)/  # :nodoc:
+    
+    #
+    # Returns the last modification time of the (remote) file.  If +local+ is
+    # +true+, it is returned as a local time, otherwise it's a UTC time.
+    #
+    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
+    
+    #
+    # Creates a remote directory.
+    #
+    def mkdir(dirname)
+      resp = sendcmd("MKD " + dirname)
+      return parse257(resp)
+    end
+    
+    #
+    # Removes a remote directory.
+    #
+    def rmdir(dirname)
+      voidcmd("RMD " + dirname)
+    end
+    
+    #
+    # Returns the current remote directory.
+    #
+    def pwd
+      resp = sendcmd("PWD")
+      return parse257(resp)
+    end
+    alias getdir pwd
+    
+    #
+    # Returns system information.
+    #
+    def system
+      resp = sendcmd("SYST")
+      if resp[0, 3] != "215"
+	raise FTPReplyError, resp
+      end
+      return resp[4 .. -1]
+    end
+    
+    #
+    # Aborts the previous command (ABOR command).
+    #
+    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
+    
+    #
+    # Returns the status (STAT command).
+    #
+    def status
+      line = "STAT" + CRLF
+      print "put: STAT\n" if @debug_mode
+      @sock.send(line, Socket::MSG_OOB)
+      return getresp
+    end
+    
+    #
+    # Issues the MDTM command.  TODO: more info.
+    #
+    def mdtm(filename)
+      resp = sendcmd("MDTM " + filename)
+      if resp[0, 3] == "213"
+	return resp[3 .. -1].strip
+      end
+    end
+    
+    #
+    # Issues the HELP command.
+    #
+    def help(arg = nil)
+      cmd = "HELP"
+      if arg
+	cmd = cmd + " " + arg
+      end
+      sendcmd(cmd)
+    end
+    
+    #
+    # Exits the FTP session.
+    #
+    def quit
+      voidcmd("QUIT")
+    end
+
+    #
+    # Issues a NOOP command.
+    #
+    def noop
+      voidcmd("NOOP")
+    end
+
+    #
+    # Issues a SITE command.
+    #
+    def site(arg)
+      cmd = "SITE " + arg
+      voidcmd(cmd)
+    end
+    
+    #
+    # Closes the connection.  Further operations are impossible until you open
+    # a new connection with #connect.
+    #
+    def close
+      @sock.close if @sock and not @sock.closed?
+    end
+    
+    #
+    # Returns +true+ iff the connection is closed.
+    #
+    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 = (numbers[4].to_i << 8) + numbers[5].to_i
+      return host, port
+    end
+    private :parse227
+    
+    def parse228(resp)
+      if resp[0, 3] != "228"
+	raise FTPReplyError, resp
+      end
+      left = resp.index("(")
+      right = resp.index(")")
+      if left == nil or right == nil
+	raise FTPProtoError, resp
+      end
+      numbers = resp[left + 1 .. right - 1].split(",")
+      if numbers[0] == "4"
+	if numbers.length != 9 || numbers[1] != "4" || numbers[2 + 4] != "2"
+	  raise FTPProtoError, resp
+	end
+	host = numbers[2, 4].join(".")
+	port = (numbers[7].to_i << 8) + numbers[8].to_i
+      elsif numbers[0] == "6"
+	if numbers.length != 21 || numbers[1] != "16" || numbers[2 + 16] != "2"
+	  raise FTPProtoError, resp
+	end
+	v6 = ["", "", "", "", "", "", "", ""]
+	for i in 0 .. 7
+	  v6[i] = sprintf("%02x%02x", numbers[(i * 2) + 2].to_i,
+			  numbers[(i * 2) + 3].to_i)
+	end
+	host = v6[0, 8].join(":")
+	port = (numbers[19].to_i << 8) + numbers[20].to_i
+      end 
+      return host, port
+    end
+    private :parse228
+    
+    def parse229(resp)
+      if resp[0, 3] != "229"
+	raise FTPReplyError, resp
+      end
+      left = resp.index("(")
+      right = resp.index(")")
+      if left == nil or right == nil
+	raise FTPProtoError, resp
+      end
+      numbers = resp[left + 1 .. right - 1].split(resp[left + 1, 1])
+      if numbers.length != 4
+	raise FTPProtoError, resp
+      end
+      port = numbers[3].to_i
+      host = ( sock.peeraddr())[3]
+      return host, port
+    end
+    private :parse229
+    
+    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
+
+end
+
+
+# Documentation comments:
+#  - sourced from pickaxe and nutshell, with improvements (hopefully)
+#  - three methods should be private (search WRITEME)
+#  - two methods need more information (search TODO)

Added: trunk/lib/net/http.rb
===================================================================
--- trunk/lib/net/http.rb	2006-02-09 23:21:27 UTC (rev 378)
+++ trunk/lib/net/http.rb	2006-02-11 05:42:50 UTC (rev 379)
@@ -0,0 +1,2243 @@
+#
+# = net/http.rb
+#
+# Copyright (c) 1999-2006 Yukihiro Matsumoto
+# Copyright (c) 1999-2006 Minero Aoki
+# Copyright (c) 2001 GOTOU Yuuzou
+# 
+# Written and maintained by Minero Aoki <aamine loveruby.net>.
+# HTTPS support added by GOTOU Yuuzou <gotoyuzo notwork.org>.
+#
+# This file is derived from "http-access.rb".
+#
+# Documented by Minero Aoki; converted to RDoc by William Webber.
+# 
+# This program is free software. You can re-distribute and/or
+# modify this program under the same terms of ruby itself ---
+# Ruby Distribution License or GNU General Public License.
+#
+# See Net::HTTP for an overview and examples. 
+# 
+# NOTE: You can find Japanese version of this document here:
+# http://www.ruby-lang.org/ja/man/?cmd=view;name=net%2Fhttp.rb
+# 
+#--
+# $Id: http.rb,v 1.129 2006/02/05 09:50:38 aamine Exp $
+#++ 
+
+require 'net/protocol'
+require 'uri'
+
+module Net   #:nodoc:
+
+  # :stopdoc:
+  class HTTPBadResponse < StandardError; end
+  class HTTPHeaderSyntaxError < StandardError; end
+  # :startdoc:
+
+  # == What Is This Library?
+  # 
+  # This library provides your program functions to access WWW
+  # documents via HTTP, Hyper Text Transfer Protocol version 1.1.
+  # For details of HTTP, refer [RFC2616]
+  # (http://www.ietf.org/rfc/rfc2616.txt).
+  # 
+  # == Examples
+  # 
+  # === Getting Document From WWW Server
+  # 
+  # Example #1: Simple GET+print
+  # 
+  #     require 'net/http'
+  #     Net::HTTP.get_print 'www.example.com', '/index.html'
+  # 
+  # Example #2: Simple GET+print by URL
+  # 
+  #     require 'net/http'
+  #     require 'uri'
+  #     Net::HTTP.get_print URI.parse('http://www.example.com/index.html')
+  # 
+  # Example #3: More generic GET+print
+  # 
+  #     require 'net/http'
+  #     require 'uri'
+  #
+  #     url = URI.parse('http://www.example.com/index.html')
+  #     res = Net::HTTP.start(url.host, url.port) {|http|
+  #       http.get('/index.html')
+  #     }
+  #     puts res.body
+  #
+  # Example #4: More generic GET+print
+  # 
+  #     require 'net/http'
+  #
+  #     url = URI.parse('http://www.example.com/index.html')
+  #     req = Net::HTTP::Get.new(url.path)
+  #     res = Net::HTTP.start(url.host, url.port) {|http|
+  #       http.request(req)
+  #     }
+  #     puts res.body
+  # 
+  # === Posting Form Data
+  # 
+  #     require 'net/http'
+  #     require 'uri'
+  #
+  #     #1: Simple POST
+  #     res = Net::HTTP.post_form(URI.parse('http://www.example.com/search.cgi'),
+  #                               {'q'=>'ruby', 'max'=>'50'})
+  #     puts res.body
+  #
+  #     #2: POST with basic authentication
+  #     res = Net::HTTP.post_form(URI.parse('http://jack:pass www.example.com/todo.cgi'),
+  #                                         {'from'=>'2005-01-01', 'to'=>'2005-03-31'})
+  #     puts res.body
+  #
+  #     #3: Detailed control
+  #     url = URI.parse('http://www.example.com/todo.cgi')
+  #     req = Net::HTTP::Post.new(url.path)
+  #     req.basic_auth 'jack', 'pass'
+  #     req.set_form_data({'from'=>'2005-01-01', 'to'=>'2005-03-31'}, ';')
+  #     res = Net::HTTP.new(url.host, url.port).start { http.request(req) }
+  #     case res
+  #     when Net::HTTPSuccess, Net::HTTPRedirection
+  #       # OK
+  #     else
+  #       res.error!
+  #     end
+  # 
+  # === Accessing via Proxy
+  # 
+  # Net::HTTP.Proxy creates http proxy class. It has same
+  # methods of Net::HTTP but its instances always connect to
+  # proxy, instead of given host.
+  # 
+  #     require 'net/http'
+  # 
+  #     proxy_addr = 'your.proxy.host'
+  #     proxy_port = 8080
+  #             :
+  #     Net::HTTP::Proxy(proxy_addr, proxy_port).start('www.example.com') {|http|
+  #       # always connect to your.proxy.addr:8080
+  #             :
+  #     }
+  # 
+  # Since Net::HTTP.Proxy returns Net::HTTP itself when proxy_addr is nil,
+  # there's no need to change code if there's proxy or not.
+  # 
+  # There are two additional parameters in Net::HTTP.Proxy which allow to
+  # specify proxy user name and password:
+  # 
+  #     Net::HTTP::Proxy(proxy_addr, proxy_port, proxy_user = nil, proxy_pass = nil)
+  # 
+  # You may use them to work with authorization-enabled proxies:
+  # 
+  #     require 'net/http'
+  #     require 'uri'
+  #     
+  #     proxy_host = 'your.proxy.host'
+  #     proxy_port = 8080
+  #     uri = URI.parse(ENV['http_proxy'])
+  #     proxy_user, proxy_pass = uri.userinfo.split(/:/) if uri.userinfo
+  #     Net::HTTP::Proxy(proxy_host, proxy_port,
+  #                      proxy_user, proxy_pass).start('www.example.com') {|http|
+  #       # always connect to your.proxy.addr:8080 using specified username and password
+  #             :
+  #     }
+  #
+  # Note that net/http never rely on HTTP_PROXY environment variable.
+  # If you want to use proxy, set it explicitly.
+  # 
+  # === Following Redirection
+  # 
+  #     require 'net/http'
+  #     require 'uri'
+  # 
+  #     def fetch(uri_str, limit = 10)
+  #       # You should choose better exception. 
+  #       raise ArgumentError, 'HTTP redirect too deep' if limit == 0
+  # 
+  #       response = Net::HTTP.get_response(URI.parse(uri_str))
+  #       case response
+  #       when Net::HTTPSuccess     then response
+  #       when Net::HTTPRedirection then fetch(response['location'], limit - 1)
+  #       else
+  #         response.error!
+  #       end
+  #     end
+  # 
+  #     print fetch('http://www.ruby-lang.org')
+  # 
+  # Net::HTTPSuccess and Net::HTTPRedirection is a HTTPResponse class.
+  # All HTTPResponse objects belong to its own response class which
+  # indicate HTTP result status. For details of response classes,
+  # see section "HTTP Response Classes".
+  # 
+  # === Basic Authentication
+  # 
+  #     require 'net/http'
+  # 
+  #     Net::HTTP.start('www.example.com') {|http|
+  #       req = Net::HTTP::Get.new('/secret-page.html')
+  #       req.basic_auth 'account', 'password'
+  #       response = http.request(req)
+  #       print response.body
+  #     }
+  # 
+  # === HTTP Request Classes
+  #
+  # Here is HTTP request class hierarchy.
+  #
+  #   Net::HTTPRequest
+  #       Net::HTTP::Get
+  #       Net::HTTP::Head
+  #       Net::HTTP::Post
+  #       Net::HTTP::Put
+  #       Net::HTTP::Proppatch
+  #       Net::HTTP::Lock
+  #       Net::HTTP::Unlock
+  #       Net::HTTP::Options
+  #       Net::HTTP::Propfind
+  #       Net::HTTP::Delete
+  #       Net::HTTP::Move
+  #       Net::HTTP::Copy
+  #       Net::HTTP::Mkcol
+  #       Net::HTTP::Trace
+  #
+  # === HTTP Response Classes
+  #
+  # Here is HTTP response class hierarchy.
+  # All classes are defined in Net module.
+  #
+  #   HTTPResponse
+  #       HTTPUnknownResponse
+  #       HTTPInformation                    # 1xx
+  #           HTTPContinue                       # 100
+  #           HTTPSwitchProtocl                  # 101
+  #       HTTPSuccess                        # 2xx
+  #           HTTPOK                             # 200
+  #           HTTPCreated                        # 201
+  #           HTTPAccepted                       # 202
+  #           HTTPNonAuthoritativeInformation    # 203
+  #           HTTPNoContent                      # 204
+  #           HTTPResetContent                   # 205
+  #           HTTPPartialContent                 # 206
+  #       HTTPRedirection                    # 3xx
+  #           HTTPMultipleChoice                 # 300
+  #           HTTPMovedPermanently               # 301
+  #           HTTPFound                          # 302
+  #           HTTPSeeOther                       # 303
+  #           HTTPNotModified                    # 304
+  #           HTTPUseProxy                       # 305
+  #           HTTPTemporaryRedirect              # 307
+  #       HTTPClientError                    # 4xx
+  #           HTTPBadRequest                     # 400
+  #           HTTPUnauthorized                   # 401
+  #           HTTPPaymentRequired                # 402
+  #           HTTPForbidden                      # 403
+  #           HTTPNotFound                       # 404
+  #           HTTPMethodNotAllowed               # 405
+  #           HTTPNotAcceptable                  # 406
+  #           HTTPProxyAuthenticationRequired    # 407
+  #           HTTPRequestTimeOut                 # 408
+  #           HTTPConflict                       # 409
+  #           HTTPGone                           # 410
+  #           HTTPLengthRequired                 # 411
+  #           HTTPPreconditionFailed             # 412
+  #           HTTPRequestEntityTooLarge          # 413
+  #           HTTPRequestURITooLong              # 414
+  #           HTTPUnsupportedMediaType           # 415
+  #           HTTPRequestedRangeNotSatisfiable   # 416
+  #           HTTPExpectationFailed              # 417
+  #       HTTPServerError                    # 5xx
+  #           HTTPInternalServerError            # 500
+  #           HTTPNotImplemented                 # 501
+  #           HTTPBadGateway                     # 502
+  #           HTTPServiceUnavailable             # 503
+  #           HTTPGatewayTimeOut                 # 504
+  #           HTTPVersionNotSupported            # 505
+  # 
+  # == Switching Net::HTTP versions
+  # 
+  # You can use net/http.rb 1.1 features (bundled with Ruby 1.6)
+  # by calling HTTP.version_1_1. Calling Net::HTTP.version_1_2
+  # allows you to use 1.2 features again.
+  # 
+  #     # example
+  #     Net::HTTP.start {|http1| ...(http1 has 1.2 features)... }
+  # 
+  #     Net::HTTP.version_1_1
+  #     Net::HTTP.start {|http2| ...(http2 has 1.1 features)... }
+  # 
+  #     Net::HTTP.version_1_2
+  #     Net::HTTP.start {|http3| ...(http3 has 1.2 features)... }
+  # 
+  # This function is NOT thread-safe.
+  #
+  class HTTP < Protocol
+
+    # :stopdoc:
+    Revision = %q$Revision: 1.129 $.split[1]
+    HTTPVersion = '1.1'
+    @newimpl = true
+    # :startdoc:
+
+    # Turns on net/http 1.2 (ruby 1.8) features.
+    # Defaults to ON in ruby 1.8.
+    #
+    # I strongly recommend to call this method always.
+    #
+    #   require 'net/http'
+    #   Net::HTTP.version_1_2
+    #
+    def HTTP.version_1_2
+      @newimpl = true
+    end
+
+    # Turns on net/http 1.1 (ruby 1.6) features.
+    # Defaults to OFF in ruby 1.8.
+    def HTTP.version_1_1
+      @newimpl = false
+    end
+
+    # true if net/http is in version 1.2 mode.
+    # Defaults to true.
+    def HTTP.version_1_2?
+      @newimpl
+    end
+
+    # true if net/http is in version 1.1 compatible mode.
+    # Defaults to true.
+    def HTTP.version_1_1?
+      not @newimpl
+    end
+
+    class << HTTP
+      alias is_version_1_1? version_1_1?   #:nodoc:
+      alias is_version_1_2? version_1_2?   #:nodoc:
+    end
+
+    #
+    # short cut methods
+    #
+
+    #
+    # Get body from target and output it to +$stdout+.  The
+    # target can either be specified as (+uri+), or as
+    # (+host+, +path+, +port+ = 80); so: 
+    #
+    #    Net::HTTP.get_print URI.parse('http://www.example.com/index.html')
+    #
+    # or:
+    #
+    #    Net::HTTP.get_print 'www.example.com', '/index.html'
+    #
+    def HTTP.get_print(uri_or_host, path = nil, port = nil)
+      get_response(uri_or_host, path, port) {|res|
+        res.read_body do |chunk|
+          $stdout.print chunk
+        end
+      }
+      nil
+    end
+
+    # Send a GET request to the target and return the response
+    # as a string.  The target can either be specified as
+    # (+uri+), or as (+host+, +path+, +port+ = 80); so:
+    # 
+    #    print Net::HTTP.get(URI.parse('http://www.example.com/index.html'))
+    #
+    # or:
+    #
+    #    print Net::HTTP.get('www.example.com', '/index.html')
+    #
+    def HTTP.get(uri_or_host, path = nil, port = nil)
+      get_response(uri_or_host, path, port).body
+    end
+
+    # Send a GET request to the target and return the response
+    # as a Net::HTTPResponse object.  The target can either be specified as
+    # (+uri+), or as (+host+, +path+, +port+ = 80); so:
+    # 
+    #    res = Net::HTTP.get_response(URI.parse('http://www.example.com/index.html'))
+    #    print res.body
+    #
+    # or:
+    #
+    #    res = Net::HTTP.get_response('www.example.com', '/index.html')
+    #    print res.body
+    #
+    def HTTP.get_response(uri_or_host, path = nil, port = nil, &block)
+      if path
+        host = uri_or_host
+        new(host, port || HTTP.default_port).start {|http|
+          return http.request_get(path, &block)
+        }
+      else
+        uri = uri_or_host
+        new(uri.host, uri.port).start {|http|
+          return http.request_get(uri.request_uri, &block)
+        }
+      end
+    end
+
+    # Posts HTML form data to the +URL+.
+    # Form data must be represented as a Hash of String to String, e.g:
+    #
+    #   { "cmd" => "search", "q" => "ruby", "max" => "50" }
+    #
+    # This method also does Basic Authentication iff +URL+.user exists.
+    #
+    # Example:
+    #
+    #   require 'net/http'
+    #   require 'uri'
+    #
+    #   HTTP.post_form URI.parse('http://www.example.com/search.cgi'),
+    #                  { "q" => "ruby", "max" => "50" }
+    #
+    def HTTP.post_form(url, params)
+      req = Post.new(url.path)
+      req.form_data = params
+      req.basic_auth url.user, url.password if url.user
+      new(url.host, url.port).start {|http|
+        http.request(req)
+      }
+    end
+
+    #
+    # HTTP session management
+    #
+
+    # The default port to use for HTTP requests; defaults to 80.
+    def HTTP.default_port
+      http_default_port()
+    end
+
+    # The default port to use for HTTP requests; defaults to 80.
+    def HTTP.http_default_port
+      80
+    end
+
+    # The default port to use for HTTPS requests; defaults to 443.
+    def HTTP.https_default_port
+      443
+    end
+
+    def HTTP.socket_type   #:nodoc: obsolete
+      BufferedIO
+    end
+
+    # creates a new Net::HTTP object and opens its TCP connection and 
+    # HTTP session.  If the optional block is given, the newly 
+    # created Net::HTTP object is passed to it and closed when the 
+    # block finishes.  In this case, the return value of this method
+    # is the return value of the block.  If no block is given, the
+    # return value of this method is the newly created Net::HTTP object
+    # itself, and the caller is responsible for closing it upon completion.
+    def HTTP.start(address, port = nil, p_addr = nil, p_port = nil, p_user = nil, p_pass = nil, &block) # :yield: +http+
+      new(address, port, p_addr, p_port, p_user, p_pass).start(&block)
+    end
+
+    class << HTTP
+      alias newobj new
+    end
+
+    # Creates a new Net::HTTP object.
+    # If +proxy_addr+ is given, creates an Net::HTTP object with proxy support.
+    # This method does not open the TCP connection.
+    def HTTP.new(address, port = nil, p_addr = nil, p_port = nil, p_user = nil, p_pass = nil)
+      h = Proxy(p_addr, p_port, p_user, p_pass).newobj(address, port)
+      h.instance_eval {
+        @newimpl = ::Net::HTTP.version_1_2?
+      }
+      h
+    end
+
+    # Creates a new Net::HTTP object for the specified +address+.
+    # This method does not open the TCP connection.
+    def initialize(address, port = nil)
+      @address = address
+      @port    = (port || HTTP.default_port)
+      @curr_http_version = HTTPVersion
+      @seems_1_0_server = false
+      @close_on_empty_response = false
+      @socket  = nil
+      @started = false
+      @open_timeout = nil
+      @read_timeout = 60
+      @debug_output = nil
+      @use_ssl = false
+      @ssl_context = nil
+    end
+
+    def inspect
+      "#<#{self.class} #{@address}:#{@port} open=#{started?}>"
+    end
+
+    # *WARNING* This method causes serious security hole.
+    # Never use this method in production code.
+    #
+    # Set an output stream for debugging.
+    #
+    #   http = Net::HTTP.new
+    #   http.set_debug_output $stderr
+    #   http.start { .... }
+    #
+    def set_debug_output(output)
+      warn 'Net::HTTP#set_debug_output called after HTTP started' if started?
+      @debug_output = output
+    end
+
+    # The host name to connect to.
+    attr_reader :address
+
+    # The port number to connect to.
+    attr_reader :port
+
+    # Seconds to wait until connection is opened.
+    # If the HTTP object cannot open a connection in this many seconds,
+    # it raises a TimeoutError exception.
+    attr_accessor :open_timeout
+
+    # Seconds to wait until reading one block (by one read(2) call).
+    # If the HTTP object cannot open a connection in this many seconds,
+    # it raises a TimeoutError exception.
+    attr_reader :read_timeout
+
+    # Setter for the read_timeout attribute.
+    def read_timeout=(sec)
+      @socket.read_timeout = sec if @socket
+      @read_timeout = sec
+    end
+
+    # returns true if the HTTP session is started.
+    def started?
+      @started
+    end
+
+    alias active? started?   #:nodoc: obsolete
+
+    attr_accessor :close_on_empty_response
+
+    # returns true if use SSL/TLS with HTTP.
+    def use_ssl?
+      false   # redefined in net/https
+    end
+
+    # Opens TCP connection and HTTP session.
+    # 
+    # When this method is called with block, gives a HTTP object
+    # to the block and closes the TCP connection / HTTP session
+    # after the block executed.
+    #
+    # When called with a block, returns the return value of the
+    # block; otherwise, returns self.
+    #
+    def start  # :yield: http
+      raise IOError, 'HTTP session already opened' if @started
+      if block_given?
+        begin
+          do_start
+          return yield(self)
+        ensure
+          do_finish
+        end
+      end
+      do_start
+      self
+    end
+
+    def do_start
+      connect
+      @started = true
+    end
+    private :do_start
+
+    def connect
+      D "opening connection to #{conn_address()}..."
+      s = timeout(@open_timeout) { TCPSocket.open(conn_address(), conn_port()) }
+      D "opened"
+      if use_ssl?
+        unless @ssl_context.verify_mode
+          warn "warning: peer certificate won't be verified in this SSL session"
+          @ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE
+        end
+        s = OpenSSL::SSL::SSLSocket.new(s, @ssl_context)
+        s.sync_close = true
+      end
+      @socket = BufferedIO.new(s)
+      @socket.read_timeout = @read_timeout
+      @socket.debug_output = @debug_output
+      if use_ssl?
+        if proxy?
+          @socket.writeline sprintf('CONNECT %s:%s HTTP/%s',
+                                    @address, @port, HTTPVersion)
+          @socket.writeline "Host: #{@address}:#{@port}"
+          if proxy_user
+            credential = ["#{proxy_user}:#{proxy_pass}"].pack('m')
+            credential.delete!("\r\n")
+            @socket.writeline "Proxy-Authorization: Basic #{credential}"
+          end
+          @socket.writeline ''
+          HTTPResponse.read_new( socket).value
+        end
+        s.connect
+      end
+      on_connect
+    end
+    private :connect
+
+    def on_connect
+    end
+    private :on_connect
+
+    # Finishes HTTP session and closes TCP connection.
+    # Raises IOError if not started.
+    def finish
+      raise IOError, 'HTTP session not yet started' unless started?
+      do_finish
+    end
+
+    def do_finish
+      @started = false
+      @socket.close if @socket and not @socket.closed?
+      @socket = nil
+    end
+    private :do_finish
+
+    #
+    # proxy
+    #
+
+    public
+
+    # no proxy
+    @is_proxy_class = false
+    @proxy_addr = nil
+    @proxy_port = nil
+    @proxy_user = nil
+    @proxy_pass = nil
+
+    # Creates an HTTP proxy class.
+    # Arguments are address/port of proxy host and username/password
+    # if authorization on proxy server is required.
+    # You can replace the HTTP class with created proxy class.
+    # 
+    # If ADDRESS is nil, this method returns self (Net::HTTP).
+    # 
+    #     # Example
+    #     proxy_class = Net::HTTP::Proxy('proxy.example.com', 8080)
+    #                     :
+    #     proxy_class.start('www.ruby-lang.org') {|http|
+    #       # connecting proxy.foo.org:8080
+    #                     :
+    #     }
+    # 
+    def HTTP.Proxy(p_addr, p_port = nil, p_user = nil, p_pass = nil)
+      return self unless p_addr
+      delta = ProxyDelta
+      proxyclass = Class.new(self)
+      proxyclass.module_eval {
+        include delta
+        # with proxy
+        @is_proxy_class = true
+        @proxy_address = p_addr
+        @proxy_port    = p_port || default_port()
+        @proxy_user    = p_user
+        @proxy_pass    = p_pass
+      }
+      proxyclass
+    end
+
+    class << HTTP
+      # returns true if self is a class which was created by HTTP::Proxy.
+      def proxy_class?
+        @is_proxy_class
+      end
+
+      attr_reader :proxy_address
+      attr_reader :proxy_port
+      attr_reader :proxy_user
+      attr_reader :proxy_pass
+    end
+
+    # True if self is a HTTP proxy class.
+    def proxy?
+      self.class.proxy_class?
+    end
+
+    # Address of proxy host. If self does not use a proxy, nil.
+    def proxy_address
+      self.class.proxy_address
+    end
+
+    # Port number of proxy host. If self does not use a proxy, nil.
+    def proxy_port
+      self.class.proxy_port
+    end
+
+    # User name for accessing proxy. If self does not use a proxy, nil.
+    def proxy_user
+      self.class.proxy_user
+    end
+
+    # User password for accessing proxy. If self does not use a proxy, nil.
+    def proxy_pass
+      self.class.proxy_pass
+    end
+
+    alias proxyaddr proxy_address   #:nodoc: obsolete
+    alias proxyport proxy_port      #:nodoc: obsolete
+
+    private
+
+    # without proxy
+
+    def conn_address
+      address()
+    end
+
+    def conn_port
+      port()
+    end
+
+    def edit_path(path)
+      path
+    end
+
+    module ProxyDelta   #:nodoc: internal use only
+      private
+
+      def conn_address
+        proxy_address()
+      end
+
+      def conn_port
+        proxy_port()
+      end
+
+      def edit_path(path)
+        use_ssl? ? path : "http://#{addr_port()}#{path}"
+      end
+    end
+
+    #
+    # HTTP operations
+    #
+
+    public
+
+    # Gets data from +path+ on the connected-to host.
+    # +header+ must be a Hash like { 'Accept' => '*/*', ... }.
+    #
+    # In version 1.1 (ruby 1.6), this method returns a pair of objects,
+    # a Net::HTTPResponse object and the entity body string.
+    # In version 1.2 (ruby 1.8), this method returns a Net::HTTPResponse
+    # object.
+    #
+    # If called with a block, yields each fragment of the
+    # entity body in turn as a string as it is read from
+    # the socket.  Note that in this case, the returned response
+    # object will *not* contain a (meaningful) body.
+    #
+    # +dest+ argument is obsolete.
+    # It still works but you must not use it.
+    #
+    # In version 1.1, this method might raise an exception for 
+    # 3xx (redirect). In this case you can get a HTTPResponse object
+    # by "anException.response".
+    #
+    # In version 1.2, this method never raises exception.
+    #
+    #     # version 1.1 (bundled with Ruby 1.6)
+    #     response, body = http.get('/index.html')
+    #
+    #     # version 1.2 (bundled with Ruby 1.8 or later)
+    #     response = http.get('/index.html')
+    #     
+    #     # using block
+    #     File.open('result.txt', 'w') {|f|
+    #       http.get('/~foo/') do |str|
+    #         f.write str
+    #       end
+    #     }
+    #
+    def get(path, initheader = nil, dest = nil, &block) # :yield: +body_segment+
+      res = nil
+      request(Get.new(path, initheader)) {|r|
+        r.read_body dest, &block
+        res = r
+      }
+      unless @newimpl
+        res.value
+        return res, res.body
+      end
+
+      res
+    end
+
+    # Gets only the header from +path+ on the connected-to host.
+    # +header+ is a Hash like { 'Accept' => '*/*', ... }.
+    # 
+    # This method returns a Net::HTTPResponse object.
+    # 
+    # In version 1.1, this method might raise an exception for 
+    # 3xx (redirect). On the case you can get a HTTPResponse object
+    # by "anException.response".
+    # In version 1.2, this method never raises an exception.
+    # 
+    #     response = nil
+    #     Net::HTTP.start('some.www.server', 80) {|http|
+    #       response = http.head('/index.html')
+    #     }
+    #     p response['content-type']
+    #
+    def head(path, initheader = nil) 
+      res = request(Head.new(path, initheader))
+      res.value unless @newimpl
+      res
+    end
+
+    # Posts +data+ (must be a String) to +path+. +header+ must be a Hash
+    # like { 'Accept' => '*/*', ... }.
+    # 
+    # In version 1.1 (ruby 1.6), this method returns a pair of objects, a
+    # Net::HTTPResponse object and an entity body string.
+    # In version 1.2 (ruby 1.8), this method returns a Net::HTTPResponse object.
+    # 
+    # If called with a block, yields each fragment of the
+    # entity body in turn as a string as it are read from
+    # the socket.  Note that in this case, the returned response
+    # object will *not* contain a (meaningful) body.
+    #
+    # +dest+ argument is obsolete.
+    # It still works but you must not use it.
+    # 
+    # In version 1.1, this method might raise an exception for 
+    # 3xx (redirect). In this case you can get an HTTPResponse object
+    # by "anException.response".
+    # In version 1.2, this method never raises exception.
+    # 
+    #     # version 1.1
+    #     response, body = http.post('/cgi-bin/search.rb', 'query=foo')
+    # 
+    #     # version 1.2
+    #     response = http.post('/cgi-bin/search.rb', 'query=foo')
+    # 
+    #     # using block
+    #     File.open('result.txt', 'w') {|f|
+    #       http.post('/cgi-bin/search.rb', 'query=foo') do |str|
+    #         f.write str
+    #       end
+    #     }
+    #
+    def post(path, data, initheader = nil, dest = nil, &block) # :yield: +body_segment+
+      res = nil
+      request(Post.new(path, initheader), data) {|r|
+        r.read_body dest, &block
+        res = r
+      }
+      unless @newimpl
+        res.value
+        return res, res.body
+      end
+
+      res
+    end
+
+    def put(path, data, initheader = nil)   #:nodoc:
+      res = request(Put.new(path, initheader), data)
+      res.value unless @newimpl
+      res
+    end
+
+    # Sends a PROPPATCH request to the +path+ and gets a response,
+    # as an HTTPResponse object.
+    def proppatch(path, body, initheader = nil)
+      request(Proppatch.new(path, initheader), body)
+    end
+
+    # Sends a LOCK request to the +path+ and gets a response,
+    # as an HTTPResponse object.
+    def lock(path, body, initheader = nil)
+      request(Lock.new(path, initheader), body)
+    end
+
+    # Sends a UNLOCK request to the +path+ and gets a response,
+    # as an HTTPResponse object.
+    def unlock(path, body, initheader = nil)
+      request(Unlock.new(path, initheader), body)
+    end
+
+    # Sends a OPTIONS request to the +path+ and gets a response,
+    # as an HTTPResponse object.
+    def options(path, initheader = nil)
+      request(Options.new(path, initheader))
+    end
+
+    # Sends a PROPFIND request to the +path+ and gets a response,
+    # as an HTTPResponse object.
+    def propfind(path, body = nil, initheader = {'Depth' => '0'})
+      request(Propfind.new(path, initheader), body)
+    end
+
+    # Sends a DELETE request to the +path+ and gets a response,
+    # as an HTTPResponse object.
+    def delete(path, initheader = {'Depth' => 'Infinity'})
+      request(Delete.new(path, initheader))
+    end
+
+    # Sends a MOVE request to the +path+ and gets a response,
+    # as an HTTPResponse object.
+    def move(path, initheader = nil)
+      request(Move.new(path, initheader))
+    end
+
+    # Sends a COPY request to the +path+ and gets a response,
+    # as an HTTPResponse object.
+    def copy(path, initheader = nil)
+      request(Copy.new(path, initheader))
+    end
+
+    # Sends a MKCOL request to the +path+ and gets a response,
+    # as an HTTPResponse object.
+    def mkcol(path, body = nil, initheader = nil)
+      request(Mkcol.new(path, initheader), body)
+    end
+
+    # Sends a TRACE request to the +path+ and gets a response,
+    # as an HTTPResponse object.
+    def trace(path, initheader = nil)
+      request(Trace.new(path, initheader))
+    end
+
+    # Sends a GET request to the +path+ and gets a response,
+    # as an HTTPResponse object.
+    # 
+    # When called with a block, yields an HTTPResponse object.
+    # The body of this response will not have been read yet;
+    # the caller can process it using HTTPResponse#read_body,
+    # if desired.
+    #
+    # Returns the response.
+    # 
+    # This method never raises Net::* exceptions.
+    # 
+    #     response = http.request_get('/index.html')
+    #     # The entity body is already read here.
+    #     p response['content-type']
+    #     puts response.body
+    # 
+    #     # using block
+    #     http.request_get('/index.html') {|response|
+    #       p response['content-type']
+    #       response.read_body do |str|   # read body now
+    #         print str
+    #       end
+    #     }
+    #
+    def request_get(path, initheader = nil, &block) # :yield: +response+
+      request(Get.new(path, initheader), &block)
+    end
+
+    # Sends a HEAD request to the +path+ and gets a response,
+    # as an HTTPResponse object.
+    #
+    # Returns the response.
+    # 
+    # This method never raises Net::* exceptions.
+    # 
+    #     response = http.request_head('/index.html')
+    #     p response['content-type']
+    #
+    def request_head(path, initheader = nil, &block)
+      request(Head.new(path, initheader), &block)
+    end
+
+    # Sends a POST request to the +path+ and gets a response,
+    # as an HTTPResponse object.
+    # 
+    # When called with a block, yields an HTTPResponse object.
+    # The body of this response will not have been read yet;
+    # the caller can process it using HTTPResponse#read_body,
+    # if desired.
+    #
+    # Returns the response.
+    # 
+    # This method never raises Net::* exceptions.
+    # 
+    #     # example
+    #     response = http.request_post('/cgi-bin/nice.rb', 'datadatadata...')
+    #     p response.status
+    #     puts response.body          # body is already read
+    # 
+    #     # using block
+    #     http.request_post('/cgi-bin/nice.rb', 'datadatadata...') {|response|
+    #       p response.status
+    #       p response['content-type']
+    #       response.read_body do |str|   # read body now
+    #         print str
+    #       end
+    #     }
+    #
+    def request_post(path, data, initheader = nil, &block) # :yield: +response+
+      request Post.new(path, initheader), data, &block
+    end
+
+    def request_put(path, data, initheader = nil, &block)   #:nodoc:
+      request Put.new(path, initheader), data, &block
+    end
+
+    alias get2   request_get    #:nodoc: obsolete
+    alias head2  request_head   #:nodoc: obsolete
+    alias post2  request_post   #:nodoc: obsolete
+    alias put2   request_put    #:nodoc: obsolete
+
+
+    # Sends an HTTP request to the HTTP server.
+    # This method also sends DATA string if DATA is given.
+    #
+    # Returns a HTTPResponse object.
+    # 
+    # This method never raises Net::* exceptions.
+    #
+    #    response = http.send_request('GET', '/index.html')
+    #    puts response.body
+    #
+    def send_request(name, path, data = nil, header = nil)
+      r = HTTPGenericRequest.new(name,(data ? true : false),true,path,header)
+      request r, data
+    end
+
+    # Sends an HTTPRequest object REQUEST to the HTTP server.
+    # This method also sends DATA string if REQUEST is a post/put request.
+    # Giving DATA for get/head request causes ArgumentError.
+    # 
+    # When called with a block, yields an HTTPResponse object.
+    # The body of this response will not have been read yet;
+    # the caller can process it using HTTPResponse#read_body,
+    # if desired.
+    #
+    # Returns a HTTPResponse object.
+    # 
+    # This method never raises Net::* exceptions.
+    #
+    def request(req, body = nil, &block)  # :yield: +response+
+      unless started?
+        start {
+          req['connection'] ||= 'close'
+          return request(req, body, &block)
+        }
+      end
+      if proxy_user()
+        unless use_ssl?
+          req.proxy_basic_auth proxy_user(), proxy_pass()
+        end
+      end
+
+      req.set_body_internal body
+      begin_transport req
+        req.exec @socket, @curr_http_version, edit_path(req.path)
+        begin
+          res = HTTPResponse.read_new(@socket)
+        end while res.kind_of?(HTTPContinue)
+        res.reading_body(@socket, req.response_body_permitted?) {
+          yield res if block_given?
+        }
+      end_transport req, res
+
+      res
+    end
+
+    private
+
+    def begin_transport(req)
+      if @socket.closed?
+        connect
+      end
+      if @seems_1_0_server
+        req['connection'] ||= 'close'
+      end
+      if not req.response_body_permitted? and @close_on_empty_response
+        req['connection'] ||= 'close'
+      end
+      req['host'] ||= addr_port()
+    end
+
+    def end_transport(req, res)
+      @curr_http_version = res.http_version
+      if not res.body and @close_on_empty_response
+        D 'Conn close'
+        @socket.close
+      elsif keep_alive?(req, res)
+        D 'Conn keep-alive'
+        if @socket.closed?
+          D 'Conn (but seems 1.0 server)'
+          @seems_1_0_server = true
+        end
+      else
+        D 'Conn close'
+        @socket.close
+      end
+    end
+
+    def keep_alive?(req, res)
+      return false if /close/i =~ req['connection'].to_s
+      return false if @seems_1_0_server
+      return true  if /keep-alive/i =~ res['connection'].to_s
+      return false if /close/i      =~ res['connection'].to_s
+      return true  if /keep-alive/i =~ res['proxy-connection'].to_s
+      return false if /close/i      =~ res['proxy-connection'].to_s
+      (@curr_http_version == '1.1')
+    end
+
+    #
+    # utils
+    #
+
+    private
+
+    def addr_port
+      if use_ssl?
+        address() + (port == HTTP.https_default_port ? '' : ":#{port()}")
+      else
+        address() + (port == HTTP.http_default_port ? '' : ":#{port()}")
+      end
+    end
+
+    def D(msg)
+      return unless @debug_output
+      @debug_output << msg
+      @debug_output << "\n"
+    end
+
+  end
+
+  HTTPSession = HTTP
+
+
+  #
+  # Header module.
+  #
+  # Provides access to @header in the mixed-into class as a hash-like
+  # object, except with case-insensitive keys.  Also provides
+  # methods for accessing commonly-used header values in a more
+  # convenient format.
+  #
+  module HTTPHeader
+
+    def initialize_http_header(initheader)
+      @header = {}
+      return unless initheader
+      initheader.each do |key, value|
+        warn "net/http: warning: duplicated HTTP header: #{key}" if key?(key) and $VERBOSE
+        @header[key.downcase] = [value.strip]
+      end
+    end
+
+    def size   #:nodoc: obsolete
+      @header.size
+    end
+
+    alias length size   #:nodoc: obsolete
+
+    # Returns the header field corresponding to the case-insensitive key.
+    # For example, a key of "Content-Type" might return "text/html"
+    def [](key)
+      a = @header[key.downcase] or return nil
+      a.join(', ')
+    end
+
+    # Sets the header field corresponding to the case-insensitive key.
+    def []=(key, val)
+      unless val
+        @header.delete key.downcase
+        return val
+      end
+      @header[key.downcase] = [val]
+    end
+
+    # [Ruby 1.8.3]
+    # Adds header field instead of replace.
+    # Second argument +val+ must be a String.
+    # See also #[]=, #[] and #get_fields.
+    #
+    #   request.add_field 'X-My-Header', 'a'
+    #   p request['X-My-Header']              #=> "a"
+    #   p request.get_fields('X-My-Header')   #=> ["a"]
+    #   request.add_field 'X-My-Header', 'b'
+    #   p request['X-My-Header']              #=> "a, b"
+    #   p request.get_fields('X-My-Header')   #=> ["a", "b"]
+    #   request.add_field 'X-My-Header', 'c'
+    #   p request['X-My-Header']              #=> "a, b, c"
+    #   p request.get_fields('X-My-Header')   #=> ["a", "b", "c"]
+    #
+    def add_field(key, val)
+      if @header.key?(key.downcase)
+        @header[key.downcase].concat [val]
+      else
+        @header[key.downcase] = [val]
+      end
+    end
+
+    # [Ruby 1.8.3]
+    # Returns an array of header field strings corresponding to the
+    # case-insensitive +key+.  This method allows you to get duplicated
+    # header fields without any processing.  See also #[].
+    #
+    #   p response.get_fields('Set-Cookie')
+    #     #=> ["session=al98axx; expires=Fri, 31-Dec-1999 23:58:23",
+    #          "query=rubyscript; expires=Fri, 31-Dec-1999 23:58:23"]
+    #   p response['Set-Cookie']
+    #     #=> "session=al98axx; expires=Fri, 31-Dec-1999 23:58:23, query=rubyscript; expires=Fri, 31-Dec-1999 23:58:23"
+    #
+    def get_fields(key)
+      return nil unless @header[key.downcase]
+      @header[key.downcase].dup
+    end
+
+    # Returns the header field corresponding to the case-insensitive key.
+    # Returns the default value +args+, or the result of the block, or nil,
+    # if there's no header field named key.  See Hash#fetch
+    def fetch(key, *args, &block)   #:yield: +key+
+      a = @header.fetch(key.downcase, *args, &block)
+      a.join(', ')
+    end
+
+    # Iterates for each header names and values.
+    def each_header   #:yield: +key+, +value+
+      @header.each do |k,va|
+        yield k, va.join(', ')
+      end
+    end
+
+    alias each each_header
+
+    # Iterates for each header names.
+    def each_name(&block)   #:yield: +key+
+      @header.each_key(&block)
+    end
+
+    alias each_key each_name
+
+    # Iterates for each capitalized header names.
+    def each_capitalized_name(&block)   #:yield: +key+
+      @header.each_key do |k|
+        yield capitalize(k)
+      end
+    end
+
+    # Iterates for each header values.
+    def each_value   #:yield: +value+
+      @header.each_value do |va|
+        yield va.join(', ')
+      end
+    end
+
+    # Removes a header field.
+    def delete(key)
+      @header.delete(key.downcase)
+    end
+
+    # true if +key+ header exists.
+    def key?(key)
+      @header.key?(key.downcase)
+    end
+
+    # Returns a Hash consist of header names and values.
+    def to_hash
+      @header.dup
+    end
+
+    # As for #each_header, except the keys are provided in capitalized form.
+    def each_capitalized
+      @header.each do |k,v|
+        yield capitalize(k), v.join(', ')
+      end
+    end
+
+    alias canonical_each each_capitalized
+
+    def capitalize(name)
+      name.split(/-/).map {|s| s.capitalize }.join('-')
+    end
+    private :capitalize
+
+    # Returns an Array of Range objects which represents Range: header field,
+    # or +nil+ if there is no such header.
+    def range
+      return nil unless @header['range']
+      self['Range'].split(/,/).map {|spec|
+        m = /bytes\s*=\s*(\d+)?\s*-\s*(\d+)?/i.match(spec) or
+                raise HTTPHeaderSyntaxError, "wrong Range: #{spec}"
+        d1 = m[1].to_i
+        d2 = m[2].to_i
+        if    m[1] and m[2] then  d1..d2
+        elsif m[1]          then  d1..-1
+        elsif          m[2] then -d2..-1
+        else
+          raise HTTPHeaderSyntaxError, 'range is not specified'
+        end
+      }
+    end
+
+    # Set Range: header from Range (arg r) or beginning index and
+    # length from it (arg idx&len).
+    #
+    #   req.range = (0..1023)
+    #   req.set_range 0, 1023
+    #
+    def set_range(r, e = nil)
+      unless r
+        @header.delete 'range'
+        return r
+      end
+      r = (r...r+e) if e
+      case r
+      when Numeric
+        n = r.to_i
+        rangestr = (n > 0 ? "0-#{n-1}" : "-#{-n}")
+      when Range
+        first = r.first
+        last = r.last
+        last -= 1 if r.exclude_end?
+        if last == -1
+          rangestr = (first > 0 ? "#{first}-" : "-#{-first}")
+        else
+          raise HTTPHeaderSyntaxError, 'range.first is negative' if first < 0
+          raise HTTPHeaderSyntaxError, 'range.last is negative' if last < 0
+          raise HTTPHeaderSyntaxError, 'must be .first < .last' if first > last
+          rangestr = "#{first}-#{last}"
+        end
+      else
+        raise TypeError, 'Range/Integer is required'
+      end
+      @header['range'] = ["bytes=#{rangestr}"]
+      r
+    end
+
+    alias range= set_range
+
+    # Returns an Integer object which represents the Content-Length: header field
+    # or +nil+ if that field is not provided.
+    def content_length
+      return nil unless key?('Content-Length')
+      len = self['Content-Length'].slice(/\d+/) or
+          raise HTTPHeaderSyntaxError, 'wrong Content-Length format'
+      len.to_i
+    end
+    
+    def content_length=(len)
+      unless len
+        @header.delete 'content-length'
+        return nil
+      end
+      @header['content-length'] = [len.to_i.to_s]
+    end
+
+    # Returns "true" if the "transfer-encoding" header is present and
+    # set to "chunked".  This is an HTTP/1.1 feature, allowing the 
+    # the content to be sent in "chunks" without at the outset
+    # stating the entire content length.
+    def chunked?
+      return false unless @header['transfer-encoding']
+      field = self['Transfer-Encoding']
+      (/(?:\A|[^\-\w])chunked(?![\-\w])/i =~ field) ? true : false
+    end
+
+    # Returns a Range object which represents Content-Range: header field.
+    # This indicates, for a partial entity body, where this fragment
+    # fits inside the full entity body, as range of byte offsets.
+    def content_range
+      return nil unless @header['content-range']
+      m = %r<bytes\s+(\d+)-(\d+)/(\d+|\*)>i.match(self['Content-Range']) or
+          raise HTTPHeaderSyntaxError, 'wrong Content-Range format'
+      m[1].to_i .. m[2].to_i + 1
+    end
+
+    # The length of the range represented in Content-Range: header.
+    def range_length
+      r = content_range() or return nil
+      r.end - r.begin
+    end
+
+    def content_type
+      "#{main_type()}/#{sub_type()}"
+    end
+
+    def main_type
+      return nil unless @header['content-type']
+      self['Content-Type'].split(';').first.to_s.split('/')[0].to_s.strip
+    end
+    
+    def sub_type
+      return nil unless @header['content-type']
+      self['Content-Type'].split(';').first.to_s.split('/')[1].to_s.strip
+    end
+
+    def type_params
+      result = {}
+      self['Content-Type'].to_s.split(';')[1..-1].each do |param|
+        k, v = *param.split('=', 2)
+        result[k.strip] = v.strip
+      end
+      result
+    end
+
+    def set_content_type(type, params = {})
+      @header['content-type'] = [type + params.map{|k,v|"; #{k}=#{v}"}.join('')]
+    end
+
+    alias content_type= set_content_type
+
+    def set_form_data(params, sep = '&')
+      self.body = params.map {|k,v| "#{urlencode(k.to_s)}=#{urlencode(v.to_s)}" }.join(sep)
+      self.content_type = 'application/x-www-form-urlencoded'
+    end
+
+    alias form_data= set_form_data
+
+    def urlencode(str)
+      str.gsub(/[^a-zA-Z0-9_\.\-]/n) {|s| sprintf('%%%02x', s[0]) }
+    end
+    private :urlencode
+
+    # Set the Authorization: header for "Basic" authorization.
+    def basic_auth(account, password)
+      @header['authorization'] = [basic_encode(account, password)]
+    end
+
+    # Set Proxy-Authorization: header for "Basic" authorization.
+    def proxy_basic_auth(account, password)
+      @header['proxy-authorization'] = [basic_encode(account, password)]
+    end
+
+    def basic_encode(account, password)
+      'Basic ' + ["#{account}:#{password}"].pack('m').delete("\r\n")
+    end
+    private :basic_encode
+
+  end
+
+
+  #
+  # Parent of HTTPRequest class.  Do not use this directly; use
+  # a subclass of HTTPRequest.
+  #
+  # Mixes in the HTTPHeader module.
+  #
+  class HTTPGenericRequest
+
+    include HTTPHeader
+
+    def initialize(m, reqbody, resbody, path, initheader = nil)
+      @method = m
+      @request_has_body = reqbody
+      @response_has_body = resbody
+      raise ArgumentError, "HTTP request path is empty" if path.empty?
+      @path = path
+      initialize_http_header initheader
+      self['Accept'] ||= '*/*'
+      @body = nil
+      @body_stream = nil
+    end
+
+    attr_reader :method
+    attr_reader :path
+
+    def inspect
+      "\#<#{self.class} #{@method}>"
+    end
+
+    def request_body_permitted?
+      @request_has_body
+    end
+
+    def response_body_permitted?
+      @response_has_body
+    end
+
+    def body_exist?
+      warn "Net::HTTPRequest#body_exist? is obsolete; use response_body_permitted?" if $VERBOSE
+      response_body_permitted?
+    end
+
+    attr_reader :body
+
+    def body=(str)
+      @body = str
+      @body_stream = nil
+      str
+    end
+
+    attr_reader :body_stream
+
+    def body_stream=(input)
+      @body = nil
+      @body_stream = input
+      input
+    end
+
+    def set_body_internal(str)   #:nodoc: internal use only
+      raise ArgumentError, "both of body argument and HTTPRequest#body set" if str and (@body or @body_stream)
+      self.body = str if str
+    end
+
+    #
+    # write
+    #
+
+    def exec(sock, ver, path)   #:nodoc: internal use only
+      if @body
+        send_request_with_body sock, ver, path, @body
+      elsif @body_stream
+        send_request_with_body_stream sock, ver, path, @body_stream
+      else
+        write_header sock, ver, path
+      end
+    end
+
+    private
+
+    def send_request_with_body(sock, ver, path, body)
+      self.content_length = body.length
+      delete 'Transfer-Encoding'
+      unless content_type()
+        warn 'net/http: warning: Content-Type did not set; using application/x-www-form-urlencoded' if $VERBOSE
+        set_content_type 'application/x-www-form-urlencoded'
+      end
+      write_header sock, ver, path
+      sock.write body
+    end
+
+    def send_request_with_body_stream(sock, ver, path, f)
+      raise ArgumentError, "Content-Length not given and Transfer-Encoding is not `chunked'" unless content_length() or chunked?
+      unless content_type()
+        warn 'net/http: warning: Content-Type did not set; using application/x-www-form-urlencoded' if $VERBOSE
+        set_content_type 'application/x-www-form-urlencoded'
+      end
+      write_header sock, ver, path
+      if chunked?
+        while s = f.read(1024)
+          sock.write(sprintf("%x\r\n", s.length) << s << "\r\n")
+        end
+        sock.write "0\r\n\r\n"
+      else
+        while s = f.read(1024)
+          sock.write s
+        end
+      end
+    end
+
+    def write_header(sock, ver, path)
+      buf = "#{@method} #{path} HTTP/#{ver}\r\n"
+      each_capitalized do |k,v|
+        buf << "#{k}: #{v}\r\n"
+      end
+      buf << "\r\n"
+      sock.write buf
+    end
+  
+  end
+
+
+  # 
+  # HTTP request class. This class wraps request header and entity path.
+  # You *must* use its subclass, Net::HTTP::Get, Post, Head.
+  # 
+  class HTTPRequest < HTTPGenericRequest
+
+    # Creates HTTP request object.
+    def initialize(path, initheader = nil)
+      super self.class::METHOD,
+            self.class::REQUEST_HAS_BODY,
+            self.class::RESPONSE_HAS_BODY,
+            path, initheader
+    end
+  end
+
+
+  class HTTP   # reopen
+    #
+    # HTTP 1.1 methods --- RFC2616
+    #
+
+    class Get < HTTPRequest
+      METHOD = 'GET'
+      REQUEST_HAS_BODY  = false
+      RESPONSE_HAS_BO