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

yarv-diff:408

From: ko1 atdot.net
Date: 7 Nov 2006 13:23:26 +0900
Subject: [yarv-diff:408] r576 - in trunk: . ext ext/dbm ext/dl ext/dl/lib ext/dl/lib/dl ext/dl/test ext/gdbm ext/iconv ext/io ext/io/wait ext/io/wait/lib ext/pty ext/pty/lib ext/sdbm lib/webrick test test/dbm test/gdbm test/io test/io/nonblock test/logger test/net test/net/http test/net/imap test/readline test/sdbm test/soap test/soap/asp.net test/soap/calc test/soap/fault test/soap/header test/soap/helloworld test/soap/marshal test/soap/ssl test/soap/struct test/soap/swa test/soap/wsdlDriver test/webrick test/win32ole test/wsdl test/wsdl/any test/wsdl/axisArray test/wsdl/datetime test/wsdl/document test/wsdl/map test/wsdl/marshal test/wsdl/qualified test/wsdl/raa test/wsdl/ref test/wsdl/rpc test/wsdl/simpletype test/wsdl/simpletype/rpc test/wsdl/soap test/xsd test/xsd/codegen

Author: ko1
Date: 2006-11-07 13:23:15 +0900 (Tue, 07 Nov 2006)
New Revision: 576

Added:
   trunk/ext/dbm/
   trunk/ext/dbm/dbm.c
   trunk/ext/dbm/depend
   trunk/ext/dbm/extconf.rb
   trunk/ext/dl/
   trunk/ext/dl/cfunc.c
   trunk/ext/dl/cptr.c
   trunk/ext/dl/depend
   trunk/ext/dl/dl.c
   trunk/ext/dl/dl.h
   trunk/ext/dl/doc/
   trunk/ext/dl/extconf.rb
   trunk/ext/dl/handle.c
   trunk/ext/dl/lib/
   trunk/ext/dl/lib/dl/
   trunk/ext/dl/lib/dl/callback.rb
   trunk/ext/dl/lib/dl/cparser.rb
   trunk/ext/dl/lib/dl/func.rb
   trunk/ext/dl/lib/dl/import.rb
   trunk/ext/dl/lib/dl/pack.rb
   trunk/ext/dl/lib/dl/stack.rb
   trunk/ext/dl/lib/dl/struct.rb
   trunk/ext/dl/lib/dl/types.rb
   trunk/ext/dl/lib/dl/value.rb
   trunk/ext/dl/mkcallback.rb
   trunk/ext/dl/sample/
   trunk/ext/dl/test/
   trunk/ext/dl/test/test_all.rb
   trunk/ext/dl/test/test_base.rb
   trunk/ext/dl/test/test_dl2.rb
   trunk/ext/dl/test/test_func.rb
   trunk/ext/dl/test/test_import.rb
   trunk/ext/dl/test/test_win32.rb
   trunk/ext/gdbm/
   trunk/ext/gdbm/README
   trunk/ext/gdbm/depend
   trunk/ext/gdbm/extconf.rb
   trunk/ext/gdbm/gdbm.c
   trunk/ext/iconv/
   trunk/ext/iconv/charset_alias.rb
   trunk/ext/iconv/depend
   trunk/ext/iconv/extconf.rb
   trunk/ext/iconv/iconv.c
   trunk/ext/iconv/mkwrapper.rb
   trunk/ext/io/
   trunk/ext/io/wait/
   trunk/ext/io/wait/extconf.rb
   trunk/ext/io/wait/lib/
   trunk/ext/io/wait/lib/nonblock.rb
   trunk/ext/io/wait/wait.c
   trunk/ext/pty/
   trunk/ext/pty/README
   trunk/ext/pty/README.expect
   trunk/ext/pty/README.expect.ja
   trunk/ext/pty/README.ja
   trunk/ext/pty/depend
   trunk/ext/pty/expect_sample.rb
   trunk/ext/pty/extconf.rb
   trunk/ext/pty/lib/
   trunk/ext/pty/lib/expect.rb
   trunk/ext/pty/pty.c
   trunk/ext/pty/script.rb
   trunk/ext/pty/shl.rb
   trunk/ext/sdbm/
   trunk/ext/sdbm/_sdbm.c
   trunk/ext/sdbm/depend
   trunk/ext/sdbm/extconf.rb
   trunk/ext/sdbm/init.c
   trunk/ext/sdbm/sdbm.h
   trunk/test/dbm/
   trunk/test/dbm/test_dbm.rb
   trunk/test/gdbm/
   trunk/test/gdbm/test_gdbm.rb
   trunk/test/io/
   trunk/test/io/nonblock/
   trunk/test/io/nonblock/test_flush.rb
   trunk/test/logger/
   trunk/test/logger/test_logger.rb
   trunk/test/net/
   trunk/test/net/http/
   trunk/test/net/http/test_http.rb
   trunk/test/net/http/test_httpheader.rb
   trunk/test/net/http/test_https_proxy.rb
   trunk/test/net/imap/
   trunk/test/net/imap/test_imap.rb
   trunk/test/readline/
   trunk/test/readline/test_readline.rb
   trunk/test/rexml/
   trunk/test/sdbm/
   trunk/test/sdbm/test_sdbm.rb
   trunk/test/soap/
   trunk/test/soap/asp.net/
   trunk/test/soap/asp.net/hello.wsdl
   trunk/test/soap/asp.net/test_aspdotnet.rb
   trunk/test/soap/calc/
   trunk/test/soap/calc/calc.rb
   trunk/test/soap/calc/calc2.rb
   trunk/test/soap/calc/server.cgi
   trunk/test/soap/calc/server.rb
   trunk/test/soap/calc/server2.rb
   trunk/test/soap/calc/test_calc.rb
   trunk/test/soap/calc/test_calc2.rb
   trunk/test/soap/calc/test_calc_cgi.rb
   trunk/test/soap/fault/
   trunk/test/soap/fault/test_customfault.rb
   trunk/test/soap/header/
   trunk/test/soap/header/server.cgi
   trunk/test/soap/header/test_authheader.rb
   trunk/test/soap/header/test_authheader_cgi.rb
   trunk/test/soap/header/test_simplehandler.rb
   trunk/test/soap/helloworld/
   trunk/test/soap/helloworld/hw_s.rb
   trunk/test/soap/helloworld/test_helloworld.rb
   trunk/test/soap/marshal/
   trunk/test/soap/marshal/test_digraph.rb
   trunk/test/soap/marshal/test_marshal.rb
   trunk/test/soap/marshal/test_struct.rb
   trunk/test/soap/ssl/
   trunk/test/soap/ssl/README
   trunk/test/soap/ssl/ca.cert
   trunk/test/soap/ssl/client.cert
   trunk/test/soap/ssl/client.key
   trunk/test/soap/ssl/server.cert
   trunk/test/soap/ssl/server.key
   trunk/test/soap/ssl/sslsvr.rb
   trunk/test/soap/ssl/subca.cert
   trunk/test/soap/ssl/test_ssl.rb
   trunk/test/soap/struct/
   trunk/test/soap/struct/test_struct.rb
   trunk/test/soap/swa/
   trunk/test/soap/swa/test_file.rb
   trunk/test/soap/test_basetype.rb
   trunk/test/soap/test_envelopenamespace.rb
   trunk/test/soap/test_httpconfigloader.rb
   trunk/test/soap/test_mapping.rb
   trunk/test/soap/test_no_indent.rb
   trunk/test/soap/test_property.rb
   trunk/test/soap/test_soapelement.rb
   trunk/test/soap/test_streamhandler.rb
   trunk/test/soap/test_styleuse.rb
   trunk/test/soap/wsdlDriver/
   trunk/test/soap/wsdlDriver/README.txt
   trunk/test/soap/wsdlDriver/calc.wsdl
   trunk/test/soap/wsdlDriver/document.wsdl
   trunk/test/soap/wsdlDriver/echo_version.rb
   trunk/test/soap/wsdlDriver/simpletype.wsdl
   trunk/test/soap/wsdlDriver/test_calc.rb
   trunk/test/soap/wsdlDriver/test_document.rb
   trunk/test/soap/wsdlDriver/test_simpletype.rb
   trunk/test/webrick/
   trunk/test/webrick/test_cgi.rb
   trunk/test/webrick/test_cookie.rb
   trunk/test/webrick/test_filehandler.rb
   trunk/test/webrick/test_httpauth.rb
   trunk/test/webrick/test_httprequest.rb
   trunk/test/webrick/test_httpserver.rb
   trunk/test/webrick/test_httputils.rb
   trunk/test/webrick/test_httpversion.rb
   trunk/test/webrick/test_server.rb
   trunk/test/webrick/test_utils.rb
   trunk/test/webrick/utils.rb
   trunk/test/webrick/webrick.cgi
   trunk/test/win32ole/
   trunk/test/win32ole/test_folderitem2_invokeverb.rb
   trunk/test/win32ole/test_nil2vtempty.rb
   trunk/test/win32ole/test_ole_methods.rb
   trunk/test/win32ole/test_propertyputref.rb
   trunk/test/win32ole/test_win32ole.rb
   trunk/test/win32ole/test_win32ole_event.rb
   trunk/test/win32ole/test_win32ole_method.rb
   trunk/test/win32ole/test_win32ole_param.rb
   trunk/test/win32ole/test_win32ole_type.rb
   trunk/test/win32ole/test_win32ole_typelib.rb
   trunk/test/win32ole/test_win32ole_variable.rb
   trunk/test/win32ole/test_win32ole_variant.rb
   trunk/test/win32ole/test_win32ole_variant_m.rb
   trunk/test/win32ole/test_word.rb
   trunk/test/wsdl/
   trunk/test/wsdl/any/
   trunk/test/wsdl/any/any.wsdl
   trunk/test/wsdl/any/expectedDriver.rb
   trunk/test/wsdl/any/expectedEcho.rb
   trunk/test/wsdl/any/expectedService.rb
   trunk/test/wsdl/any/test_any.rb
   trunk/test/wsdl/axisArray/
   trunk/test/wsdl/axisArray/axisArray.wsdl
   trunk/test/wsdl/axisArray/itemList.rb
   trunk/test/wsdl/axisArray/test_axisarray.rb
   trunk/test/wsdl/datetime/
   trunk/test/wsdl/datetime/DatetimeService.rb
   trunk/test/wsdl/datetime/datetime.rb
   trunk/test/wsdl/datetime/datetime.wsdl
   trunk/test/wsdl/datetime/datetimeServant.rb
   trunk/test/wsdl/datetime/test_datetime.rb
   trunk/test/wsdl/document/
   trunk/test/wsdl/document/document.wsdl
   trunk/test/wsdl/document/number.wsdl
   trunk/test/wsdl/document/ping_nosoapaction.wsdl
   trunk/test/wsdl/document/test_nosoapaction.rb
   trunk/test/wsdl/document/test_number.rb
   trunk/test/wsdl/document/test_rpc.rb
   trunk/test/wsdl/emptycomplextype.wsdl
   trunk/test/wsdl/map/
   trunk/test/wsdl/map/map.wsdl
   trunk/test/wsdl/map/map.xml
   trunk/test/wsdl/map/test_map.rb
   trunk/test/wsdl/marshal/
   trunk/test/wsdl/marshal/person.wsdl
   trunk/test/wsdl/marshal/person_org.rb
   trunk/test/wsdl/marshal/test_wsdlmarshal.rb
   trunk/test/wsdl/multiplefault.wsdl
   trunk/test/wsdl/qualified/
   trunk/test/wsdl/qualified/lp.wsdl
   trunk/test/wsdl/qualified/lp.xsd
   trunk/test/wsdl/qualified/np.wsdl
   trunk/test/wsdl/qualified/test_qualified.rb
   trunk/test/wsdl/qualified/test_unqualified.rb
   trunk/test/wsdl/raa/
   trunk/test/wsdl/raa/RAA.rb
   trunk/test/wsdl/raa/RAAServant.rb
   trunk/test/wsdl/raa/RAAService.rb
   trunk/test/wsdl/raa/README.txt
   trunk/test/wsdl/raa/raa.wsdl
   trunk/test/wsdl/raa/server.rb
   trunk/test/wsdl/raa/test_raa.rb
   trunk/test/wsdl/ref/
   trunk/test/wsdl/ref/expectedProduct.rb
   trunk/test/wsdl/ref/product.wsdl
   trunk/test/wsdl/ref/test_ref.rb
   trunk/test/wsdl/rpc/
   trunk/test/wsdl/rpc/rpc.wsdl
   trunk/test/wsdl/rpc/test-rpc-lit.wsdl
   trunk/test/wsdl/rpc/test-rpc-lit12.wsdl
   trunk/test/wsdl/rpc/test_rpc.rb
   trunk/test/wsdl/rpc/test_rpc_lit.rb
   trunk/test/wsdl/simpletype/
   trunk/test/wsdl/simpletype/rpc/
   trunk/test/wsdl/simpletype/rpc/expectedClient.rb
   trunk/test/wsdl/simpletype/rpc/expectedDriver.rb
   trunk/test/wsdl/simpletype/rpc/expectedEchoVersion.rb
   trunk/test/wsdl/simpletype/rpc/expectedServant.rb
   trunk/test/wsdl/simpletype/rpc/expectedService.rb
   trunk/test/wsdl/simpletype/rpc/rpc.wsdl
   trunk/test/wsdl/simpletype/rpc/test_rpc.rb
   trunk/test/wsdl/simpletype/simpletype.wsdl
   trunk/test/wsdl/simpletype/test_simpletype.rb
   trunk/test/wsdl/soap/
   trunk/test/wsdl/soap/soapbodyparts.wsdl
   trunk/test/wsdl/soap/test_soapbodyparts.rb
   trunk/test/wsdl/test_emptycomplextype.rb
   trunk/test/wsdl/test_fault.rb
   trunk/test/wsdl/test_multiplefault.rb
   trunk/test/xsd/
   trunk/test/xsd/codegen/
   trunk/test/xsd/codegen/test_classdef.rb
   trunk/test/xsd/noencoding.xml
   trunk/test/xsd/test_noencoding.rb
   trunk/test/xsd/test_xmlschemaparser.rb
   trunk/test/xsd/test_xsd.rb
   trunk/test/xsd/xmlschema.xml
Modified:
   trunk/ChangeLog
   trunk/eval.c
   trunk/lib/webrick/utils.rb
   trunk/ruby.h
   trunk/version.h
Log:
	* eval.c (rb_set_errinfo) : added

	* ruby.h : ditto

	* version.h : fix version number

	* lib/webrick/utils.rb : fix to remove Thread.critical

	* ext/dbm, dl, gdbm, iconv, io, pty, sdbm : added

	* test/dbm, gdbm, io, logger, net, readline, sdbm, soap, 
	  webrick, win32ole, wsdl, xsd : added



Modified: trunk/ChangeLog
===================================================================
--- trunk/ChangeLog	2006-11-06 13:53:20 UTC (rev 575)
+++ trunk/ChangeLog	2006-11-07 04:23:15 UTC (rev 576)
@@ -4,6 +4,22 @@
 #  from Mon, 03 May 2004 01:24:19 +0900
 #
 
+2006-11-07(Tue) 13:17:10 +0900  Koichi Sasada  <ko1 atdot.net>
+
+	* eval.c (rb_set_errinfo) : added
+
+	* ruby.h : ditto
+
+	* version.h : fix version number
+
+	* lib/webrick/utils.rb : fix to remove Thread.critical
+
+	* ext/dbm, dl, gdbm, iconv, io, pty, sdbm : added
+
+	* test/dbm, gdbm, io, logger, net, readline, sdbm, soap, 
+	  webrick, win32ole, wsdl, xsd : added
+
+
 2006-11-06(Mon) 22:32:18 +0900  Koichi Sasada  <ko1 atdot.net>
 
 	* array.c : import Ruby HEAD

Modified: trunk/eval.c
===================================================================
--- trunk/eval.c	2006-11-06 13:53:20 UTC (rev 575)
+++ trunk/eval.c	2006-11-07 04:23:15 UTC (rev 576)
@@ -2713,7 +2713,7 @@
 }
 
 VALUE
-rb_errinfo()
+rb_errinfo(void)
 {
     return get_errinfo();
 }
@@ -2729,6 +2729,12 @@
     }
 }
 
+void
+rb_set_errinfo(VALUE err)
+{
+    errinfo_setter(err, 0, 0);
+}
+
 static VALUE
 errat_getter(ID id)
 {

Added: trunk/ext/dbm/dbm.c
===================================================================
--- trunk/ext/dbm/dbm.c	2006-11-06 13:53:20 UTC (rev 575)
+++ trunk/ext/dbm/dbm.c	2006-11-07 04:23:15 UTC (rev 576)
@@ -0,0 +1,732 @@
+/************************************************
+
+  dbm.c -
+
+  $Author: matz $
+  $Date: 2006/09/02 14:41:39 $
+  created at: Mon Jan 24 15:59:52 JST 1994
+
+  Copyright (C) 1995-2001 Yukihiro Matsumoto
+
+************************************************/
+
+#include "ruby.h"
+
+#ifdef HAVE_CDEFS_H
+# include <cdefs.h>
+#endif
+#ifdef HAVE_SYS_CDEFS_H
+# include <sys/cdefs.h>
+#endif
+#include DBM_HDR
+#include <fcntl.h>
+#include <errno.h>
+
+static VALUE rb_cDBM, rb_eDBMError;
+
+#define RUBY_DBM_RW_BIT 0x20000000
+
+struct dbmdata {
+    int  di_size;
+    DBM *di_dbm;
+};
+
+static void
+closed_dbm(void)
+{
+    rb_raise(rb_eDBMError, "closed DBM file");
+}
+
+#define GetDBM(obj, dbmp) {\
+    Data_Get_Struct(obj, struct dbmdata, dbmp);\
+    if (dbmp == 0) closed_dbm();\
+    if (dbmp->di_dbm == 0) closed_dbm();\
+}
+
+#define GetDBM2(obj, data, dbm) {\
+    GetDBM(obj, data);\
+    (dbm) = dbmp->di_dbm;\
+}
+
+static void
+free_dbm(struct dbmdata *dbmp)
+{
+    if (dbmp) {
+	if (dbmp->di_dbm) dbm_close(dbmp->di_dbm);
+	free(dbmp);
+    }
+}
+
+static VALUE
+fdbm_close(VALUE obj)
+{
+    struct dbmdata *dbmp;
+
+    GetDBM(obj, dbmp);
+    dbm_close(dbmp->di_dbm);
+    dbmp->di_dbm = 0;
+
+    return Qnil;
+}
+
+static VALUE
+fdbm_closed(VALUE obj)
+{
+    struct dbmdata *dbmp;
+
+    Data_Get_Struct(obj, struct dbmdata, dbmp);
+    if (dbmp == 0)
+	return Qtrue;
+    if (dbmp->di_dbm == 0)
+	return Qtrue;
+
+    return Qfalse;
+}
+
+static VALUE
+fdbm_alloc(VALUE klass)
+{
+    return Data_Wrap_Struct(klass, 0, free_dbm, 0);
+}
+
+static VALUE
+fdbm_initialize(int argc, VALUE *argv, VALUE obj)
+{
+    VALUE file, vmode, vflags;
+    DBM *dbm;
+    struct dbmdata *dbmp;
+    int mode, flags = 0;
+
+    if (rb_scan_args(argc, argv, "12", &file, &vmode, &vflags) == 1) {
+	mode = 0666;		/* default value */
+    }
+    else if (NIL_P(vmode)) {
+	mode = -1;		/* return nil if DB not exist */
+    }
+    else {
+	mode = NUM2INT(vmode);
+    }
+
+    if (!NIL_P(vflags))
+        flags = NUM2INT(vflags);
+
+    SafeStringValue(file);
+
+    if (flags & RUBY_DBM_RW_BIT) {
+        flags &= ~RUBY_DBM_RW_BIT;
+        dbm = dbm_open(RSTRING_PTR(file), flags, mode);
+    }
+    else {
+        dbm = 0;
+        if (mode >= 0) {
+            dbm = dbm_open(RSTRING_PTR(file), O_RDWR|O_CREAT, mode);
+        }
+        if (!dbm) {
+            dbm = dbm_open(RSTRING_PTR(file), O_RDWR, 0);
+        }
+        if (!dbm) {
+            dbm = dbm_open(RSTRING_PTR(file), O_RDONLY, 0);
+        }
+    }
+
+    if (!dbm) {
+	if (mode == -1) return Qnil;
+	rb_sys_fail(RSTRING_PTR(file));
+    }
+
+    dbmp = ALLOC(struct dbmdata);
+    DATA_PTR(obj) = dbmp;
+    dbmp->di_dbm = dbm;
+    dbmp->di_size = -1;
+
+    return obj;
+}
+
+static VALUE
+fdbm_s_open(int argc, VALUE *argv, VALUE klass)
+{
+    VALUE obj = Data_Wrap_Struct(klass, 0, free_dbm, 0);
+
+    if (NIL_P(fdbm_initialize(argc, argv, obj))) {
+	return Qnil;
+    }
+
+    if (rb_block_given_p()) {
+        return rb_ensure(rb_yield, obj, fdbm_close, obj);
+    }
+
+    return obj;
+}
+
+static VALUE
+fdbm_fetch(VALUE obj, VALUE keystr, VALUE ifnone)
+{
+    datum key, value;
+    struct dbmdata *dbmp;
+    DBM *dbm;
+
+    StringValue(keystr);
+    key.dptr = RSTRING_PTR(keystr);
+    key.dsize = RSTRING_LEN(keystr);
+
+    GetDBM2(obj, dbmp, dbm);
+    value = dbm_fetch(dbm, key);
+    if (value.dptr == 0) {
+	if (ifnone == Qnil && rb_block_given_p())
+	    return rb_yield(rb_tainted_str_new(key.dptr, key.dsize));
+	return ifnone;
+    }
+    return rb_tainted_str_new(value.dptr, value.dsize);
+}
+
+static VALUE
+fdbm_aref(VALUE obj, VALUE keystr)
+{
+    return fdbm_fetch(obj, keystr, Qnil);
+}
+
+static VALUE
+fdbm_fetch_m(int argc, VALUE *argv, VALUE obj)
+{
+    VALUE keystr, valstr, ifnone;
+
+    rb_scan_args(argc, argv, "11", &keystr, &ifnone);
+    valstr = fdbm_fetch(obj, keystr, ifnone);
+    if (argc == 1 && !rb_block_given_p() && NIL_P(valstr))
+	rb_raise(rb_eIndexError, "key not found");
+
+    return valstr;
+}
+
+static VALUE
+fdbm_index(VALUE obj, VALUE valstr)
+{
+    datum key, val;
+    struct dbmdata *dbmp;
+    DBM *dbm;
+
+    StringValue(valstr);
+    val.dptr = RSTRING_PTR(valstr);
+    val.dsize = RSTRING_LEN(valstr);
+
+    GetDBM2(obj, dbmp, dbm);
+    for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
+	val = dbm_fetch(dbm, key);
+	if (val.dsize == RSTRING_LEN(valstr) &&
+	    memcmp(val.dptr, RSTRING_PTR(valstr), val.dsize) == 0) {
+	    return rb_tainted_str_new(key.dptr, key.dsize);
+	}
+    }
+    return Qnil;
+}
+
+static VALUE
+fdbm_select(VALUE obj)
+{
+    VALUE new = rb_ary_new();
+    datum key, val;
+    DBM *dbm;
+    struct dbmdata *dbmp;
+
+    GetDBM2(obj, dbmp, dbm);
+    for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
+	VALUE assoc, v;
+	val = dbm_fetch(dbm, key);
+	assoc = rb_assoc_new(rb_tainted_str_new(key.dptr, key.dsize),
+			     rb_tainted_str_new(val.dptr, val.dsize));
+	v = rb_yield(assoc);
+	if (RTEST(v)) {
+	    rb_ary_push(new, assoc);
+	}
+	GetDBM2(obj, dbmp, dbm);
+    }
+
+    return new;
+}
+
+static VALUE
+fdbm_values_at(int argc, VALUE *argv, VALUE obj)
+{
+    VALUE new = rb_ary_new2(argc);
+    int i;
+
+    for (i=0; i<argc; i++) {
+        rb_ary_push(new, fdbm_fetch(obj, argv[i], Qnil));
+    }
+
+    return new;
+}
+
+static void
+fdbm_modify(VALUE obj)
+{
+    rb_secure(4);
+    if (OBJ_FROZEN(obj)) rb_error_frozen("DBM");
+}
+
+static VALUE
+fdbm_delete(VALUE obj, VALUE keystr)
+{
+    datum key, value;
+    struct dbmdata *dbmp;
+    DBM *dbm;
+    VALUE valstr;
+
+    fdbm_modify(obj);
+    StringValue(keystr);
+    key.dptr = RSTRING_PTR(keystr);
+    key.dsize = RSTRING_LEN(keystr);
+
+    GetDBM2(obj, dbmp, dbm);
+
+    value = dbm_fetch(dbm, key);
+    if (value.dptr == 0) {
+	if (rb_block_given_p()) return rb_yield(keystr);
+	return Qnil;
+    }
+
+    /* need to save value before dbm_delete() */
+    valstr = rb_tainted_str_new(value.dptr, value.dsize);
+
+    if (dbm_delete(dbm, key)) {
+	dbmp->di_size = -1;
+	rb_raise(rb_eDBMError, "dbm_delete failed");
+    }
+    else if (dbmp->di_size >= 0) {
+	dbmp->di_size--;
+    }
+    return valstr;
+}
+
+static VALUE
+fdbm_shift(VALUE obj)
+{
+    datum key, val;
+    struct dbmdata *dbmp;
+    DBM *dbm;
+    VALUE keystr, valstr;
+
+    fdbm_modify(obj);
+    GetDBM2(obj, dbmp, dbm);
+    dbmp->di_size = -1;
+
+    key = dbm_firstkey(dbm); 
+    if (!key.dptr) return Qnil;
+    val = dbm_fetch(dbm, key);
+    keystr = rb_tainted_str_new(key.dptr, key.dsize);
+    valstr = rb_tainted_str_new(val.dptr, val.dsize);
+    dbm_delete(dbm, key);
+
+    return rb_assoc_new(keystr, valstr);
+}
+
+static VALUE
+fdbm_delete_if(VALUE obj)
+{
+    datum key, val;
+    struct dbmdata *dbmp;
+    DBM *dbm;
+    VALUE keystr, valstr;
+    VALUE ret, ary = rb_ary_new();
+    int i, status = 0, n;
+
+    fdbm_modify(obj);
+    GetDBM2(obj, dbmp, dbm);
+    n = dbmp->di_size;
+    dbmp->di_size = -1;
+
+    for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
+	val = dbm_fetch(dbm, key);
+	keystr = rb_tainted_str_new(key.dptr, key.dsize);
+	valstr = rb_tainted_str_new(val.dptr, val.dsize);
+        ret = rb_protect(rb_yield, rb_assoc_new(rb_str_dup(keystr), valstr), &status);
+        if (status != 0) break;
+	if (RTEST(ret)) rb_ary_push(ary, keystr);
+	GetDBM2(obj, dbmp, dbm);
+    }
+
+    for (i = 0; i < RARRAY_LEN(ary); i++) {
+	keystr = RARRAY_PTR(ary)[i];
+	StringValue(keystr);
+	key.dptr = RSTRING_PTR(keystr);
+	key.dsize = RSTRING_LEN(keystr);
+	if (dbm_delete(dbm, key)) {
+	    rb_raise(rb_eDBMError, "dbm_delete failed");
+	}
+    }
+    if (status) rb_jump_tag(status);
+    if (n > 0) dbmp->di_size = n - RARRAY_LEN(ary);
+
+    return obj;
+}
+
+static VALUE
+fdbm_clear(VALUE obj)
+{
+    datum key;
+    struct dbmdata *dbmp;
+    DBM *dbm;
+
+    fdbm_modify(obj);
+    GetDBM2(obj, dbmp, dbm);
+    dbmp->di_size = -1;
+    while (key = dbm_firstkey(dbm), key.dptr) {
+	if (dbm_delete(dbm, key)) {
+	    rb_raise(rb_eDBMError, "dbm_delete failed");
+	}
+    }
+    dbmp->di_size = 0;
+
+    return obj;
+}
+
+static VALUE
+fdbm_invert(VALUE obj)
+{
+    datum key, val;
+    struct dbmdata *dbmp;
+    DBM *dbm;
+    VALUE keystr, valstr;
+    VALUE hash = rb_hash_new();
+
+    GetDBM2(obj, dbmp, dbm);
+    for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
+	val = dbm_fetch(dbm, key);
+	keystr = rb_tainted_str_new(key.dptr, key.dsize);
+	valstr = rb_tainted_str_new(val.dptr, val.dsize);
+	rb_hash_aset(hash, valstr, keystr);
+    }
+    return hash;
+}
+
+static VALUE fdbm_store(VALUE,VALUE,VALUE);
+
+static VALUE
+update_i(VALUE pair, VALUE dbm)
+{
+    Check_Type(pair, T_ARRAY);
+    if (RARRAY_LEN(pair) < 2) {
+	rb_raise(rb_eArgError, "pair must be [key, value]");
+    }
+    fdbm_store(dbm, RARRAY_PTR(pair)[0], RARRAY_PTR(pair)[1]);
+    return Qnil;
+}
+
+static VALUE
+fdbm_update(VALUE obj, VALUE other)
+{
+    rb_block_call(other, rb_intern("each_pair"), 0, 0, update_i, obj);
+    return obj;
+}
+
+static VALUE
+fdbm_replace(VALUE obj, VALUE other)
+{
+    fdbm_clear(obj);
+    rb_block_call(other, rb_intern("each_pair"), 0, 0, update_i, obj);
+    return obj;
+}
+
+static VALUE
+fdbm_store(VALUE obj, VALUE keystr, VALUE valstr)
+{
+    datum key, val;
+    struct dbmdata *dbmp;
+    DBM *dbm;
+
+    fdbm_modify(obj);
+    keystr = rb_obj_as_string(keystr);
+    valstr = rb_obj_as_string(valstr);
+
+    key.dptr = RSTRING_PTR(keystr);
+    key.dsize = RSTRING_LEN(keystr);
+
+    val.dptr = RSTRING_PTR(valstr);
+    val.dsize = RSTRING_LEN(valstr);
+
+    GetDBM2(obj, dbmp, dbm);
+    dbmp->di_size = -1;
+    if (dbm_store(dbm, key, val, DBM_REPLACE)) {
+#ifdef HAVE_DBM_CLEARERR
+	dbm_clearerr(dbm);
+#endif
+	if (errno == EPERM) rb_sys_fail(0);
+	rb_raise(rb_eDBMError, "dbm_store failed");
+    }
+
+    return valstr;
+}
+
+static VALUE
+fdbm_length(VALUE obj)
+{
+    datum key;
+    struct dbmdata *dbmp;
+    DBM *dbm;
+    int i = 0;
+
+    GetDBM2(obj, dbmp, dbm);
+    if (dbmp->di_size > 0) return INT2FIX(dbmp->di_size);
+
+    for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
+	i++;
+    }
+    dbmp->di_size = i;
+
+    return INT2FIX(i);
+}
+
+static VALUE
+fdbm_empty_p(VALUE obj)
+{
+    datum key;
+    struct dbmdata *dbmp;
+    DBM *dbm;
+    int i = 0;
+
+    GetDBM2(obj, dbmp, dbm);
+    if (dbmp->di_size < 0) {
+	dbm = dbmp->di_dbm;
+
+	for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
+	    i++;
+	}
+    }
+    else {
+	i = dbmp->di_size;
+    }
+    if (i == 0) return Qtrue;
+    return Qfalse;
+}
+
+static VALUE
+fdbm_each_value(VALUE obj)
+{
+    datum key, val;
+    struct dbmdata *dbmp;
+    DBM *dbm;
+
+    GetDBM2(obj, dbmp, dbm);
+    for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
+	val = dbm_fetch(dbm, key);
+	rb_yield(rb_tainted_str_new(val.dptr, val.dsize));
+	GetDBM2(obj, dbmp, dbm);
+    }
+    return obj;
+}
+
+static VALUE
+fdbm_each_key(VALUE obj)
+{
+    datum key;
+    struct dbmdata *dbmp;
+    DBM *dbm;
+
+    GetDBM2(obj, dbmp, dbm);
+    for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
+	rb_yield(rb_tainted_str_new(key.dptr, key.dsize));
+	GetDBM2(obj, dbmp, dbm);
+    }
+    return obj;
+}
+
+static VALUE
+fdbm_each_pair(VALUE obj)
+{
+    datum key, val;
+    DBM *dbm;
+    struct dbmdata *dbmp;
+    VALUE keystr, valstr;
+
+    GetDBM2(obj, dbmp, dbm);
+
+    for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
+	val = dbm_fetch(dbm, key);
+	keystr = rb_tainted_str_new(key.dptr, key.dsize);
+	valstr = rb_tainted_str_new(val.dptr, val.dsize);
+	rb_yield(rb_assoc_new(keystr, valstr));
+	GetDBM2(obj, dbmp, dbm);
+    }
+
+    return obj;
+}
+
+static VALUE
+fdbm_keys(VALUE obj)
+{
+    datum key;
+    struct dbmdata *dbmp;
+    DBM *dbm;
+    VALUE ary;
+
+    GetDBM2(obj, dbmp, dbm);
+
+    ary = rb_ary_new();
+    for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
+	rb_ary_push(ary, rb_tainted_str_new(key.dptr, key.dsize));
+    }
+
+    return ary;
+}
+
+static VALUE
+fdbm_values(VALUE obj)
+{
+    datum key, val;
+    struct dbmdata *dbmp;
+    DBM *dbm;
+    VALUE ary;
+
+    GetDBM2(obj, dbmp, dbm);
+    ary = rb_ary_new();
+    for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
+	val = dbm_fetch(dbm, key);
+	rb_ary_push(ary, rb_tainted_str_new(val.dptr, val.dsize));
+    }
+
+    return ary;
+}
+
+static VALUE
+fdbm_has_key(VALUE obj, VALUE keystr)
+{
+    datum key, val;
+    struct dbmdata *dbmp;
+    DBM *dbm;
+
+    StringValue(keystr);
+    key.dptr = RSTRING_PTR(keystr);
+    key.dsize = RSTRING_LEN(keystr);
+
+    GetDBM2(obj, dbmp, dbm);
+    val = dbm_fetch(dbm, key);
+    if (val.dptr) return Qtrue;
+    return Qfalse;
+}
+
+static VALUE
+fdbm_has_value(VALUE obj, VALUE valstr)
+{
+    datum key, val;
+    struct dbmdata *dbmp;
+    DBM *dbm;
+
+    StringValue(valstr);
+    val.dptr = RSTRING_PTR(valstr);
+    val.dsize = RSTRING_LEN(valstr);
+
+    GetDBM2(obj, dbmp, dbm);
+    for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
+	val = dbm_fetch(dbm, key);
+	if (val.dsize == RSTRING_LEN(valstr) &&
+	    memcmp(val.dptr, RSTRING_PTR(valstr), val.dsize) == 0)
+	    return Qtrue;
+    }
+    return Qfalse;
+}
+
+static VALUE
+fdbm_to_a(VALUE obj)
+{
+    datum key, val;
+    struct dbmdata *dbmp;
+    DBM *dbm;
+    VALUE ary;
+
+    GetDBM2(obj, dbmp, dbm);
+    ary = rb_ary_new();
+    for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
+	val = dbm_fetch(dbm, key);
+	rb_ary_push(ary, rb_assoc_new(rb_tainted_str_new(key.dptr, key.dsize),
+				      rb_tainted_str_new(val.dptr, val.dsize)));
+    }
+
+    return ary;
+}
+
+static VALUE
+fdbm_to_hash(VALUE obj)
+{
+    datum key, val;
+    struct dbmdata *dbmp;
+    DBM *dbm;
+    VALUE hash;
+
+    GetDBM2(obj, dbmp, dbm);
+    hash = rb_hash_new();
+    for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
+	val = dbm_fetch(dbm, key);
+	rb_hash_aset(hash, rb_tainted_str_new(key.dptr, key.dsize),
+		           rb_tainted_str_new(val.dptr, val.dsize));
+    }
+
+    return hash;
+}
+
+static VALUE
+fdbm_reject(VALUE obj)
+{
+    return rb_hash_delete_if(fdbm_to_hash(obj));
+}
+
+void
+Init_dbm(void)
+{
+    rb_cDBM = rb_define_class("DBM", rb_cObject);
+    rb_eDBMError = rb_define_class("DBMError", rb_eStandardError);
+    rb_include_module(rb_cDBM, rb_mEnumerable);
+
+    rb_define_alloc_func(rb_cDBM, fdbm_alloc);
+    rb_define_singleton_method(rb_cDBM, "open", fdbm_s_open, -1);
+
+    rb_define_method(rb_cDBM, "initialize", fdbm_initialize, -1);
+    rb_define_method(rb_cDBM, "close", fdbm_close, 0);
+    rb_define_method(rb_cDBM, "closed?", fdbm_closed, 0);
+    rb_define_method(rb_cDBM, "[]", fdbm_aref, 1);
+    rb_define_method(rb_cDBM, "fetch", fdbm_fetch_m, -1);
+    rb_define_method(rb_cDBM, "[]=", fdbm_store, 2);
+    rb_define_method(rb_cDBM, "store", fdbm_store, 2);
+    rb_define_method(rb_cDBM, "index",  fdbm_index, 1);
+    rb_define_method(rb_cDBM, "select",  fdbm_select, 0);
+    rb_define_method(rb_cDBM, "values_at", fdbm_values_at, -1);
+    rb_define_method(rb_cDBM, "length", fdbm_length, 0);
+    rb_define_method(rb_cDBM, "size", fdbm_length, 0);
+    rb_define_method(rb_cDBM, "empty?", fdbm_empty_p, 0);
+    rb_define_method(rb_cDBM, "each", fdbm_each_pair, 0);
+    rb_define_method(rb_cDBM, "each_value", fdbm_each_value, 0);
+    rb_define_method(rb_cDBM, "each_key", fdbm_each_key, 0);
+    rb_define_method(rb_cDBM, "each_pair", fdbm_each_pair, 0);
+    rb_define_method(rb_cDBM, "keys", fdbm_keys, 0);
+    rb_define_method(rb_cDBM, "values", fdbm_values, 0);
+    rb_define_method(rb_cDBM, "shift", fdbm_shift, 0);
+    rb_define_method(rb_cDBM, "delete", fdbm_delete, 1);
+    rb_define_method(rb_cDBM, "delete_if", fdbm_delete_if, 0);
+    rb_define_method(rb_cDBM, "reject!", fdbm_delete_if, 0);
+    rb_define_method(rb_cDBM, "reject", fdbm_reject, 0);
+    rb_define_method(rb_cDBM, "clear", fdbm_clear, 0);
+    rb_define_method(rb_cDBM,"invert", fdbm_invert, 0);
+    rb_define_method(rb_cDBM,"update", fdbm_update, 1);
+    rb_define_method(rb_cDBM,"replace", fdbm_replace, 1);
+
+    rb_define_method(rb_cDBM, "include?", fdbm_has_key, 1);
+    rb_define_method(rb_cDBM, "has_key?", fdbm_has_key, 1);
+    rb_define_method(rb_cDBM, "member?", fdbm_has_key, 1);
+    rb_define_method(rb_cDBM, "has_value?", fdbm_has_value, 1);
+    rb_define_method(rb_cDBM, "key?", fdbm_has_key, 1);
+    rb_define_method(rb_cDBM, "value?", fdbm_has_value, 1);
+
+    rb_define_method(rb_cDBM, "to_a", fdbm_to_a, 0);
+    rb_define_method(rb_cDBM, "to_hash", fdbm_to_hash, 0);
+
+    /* flags for dbm_open() */
+    rb_define_const(rb_cDBM, "READER",  INT2FIX(O_RDONLY|RUBY_DBM_RW_BIT));
+    rb_define_const(rb_cDBM, "WRITER",  INT2FIX(O_RDWR|RUBY_DBM_RW_BIT));
+    rb_define_const(rb_cDBM, "WRCREAT", INT2FIX(O_RDWR|O_CREAT|RUBY_DBM_RW_BIT));
+    rb_define_const(rb_cDBM, "NEWDB",   INT2FIX(O_RDWR|O_CREAT|O_TRUNC|RUBY_DBM_RW_BIT));
+
+#ifdef DB_VERSION_STRING
+    rb_define_const(rb_cDBM, "VERSION",  rb_str_new2(DB_VERSION_STRING));
+#else
+    rb_define_const(rb_cDBM, "VERSION",  rb_str_new2("unknown"));
+#endif
+}

Added: trunk/ext/dbm/depend
===================================================================
--- trunk/ext/dbm/depend	2006-11-06 13:53:20 UTC (rev 575)
+++ trunk/ext/dbm/depend	2006-11-07 04:23:15 UTC (rev 576)
@@ -0,0 +1 @@
+dbm.o: dbm.c $(hdrdir)/ruby.h $(topdir)/config.h $(hdrdir)/defines.h

Added: trunk/ext/dbm/extconf.rb
===================================================================
--- trunk/ext/dbm/extconf.rb	2006-11-06 13:53:20 UTC (rev 575)
+++ trunk/ext/dbm/extconf.rb	2006-11-07 04:23:15 UTC (rev 576)
@@ -0,0 +1,53 @@
+require 'mkmf'
+
+dir_config("dbm")
+
+if dblib = with_config("dbm-type", nil)
+  dblib = dblib.split(/[ ,]+/)
+else
+  dblib = %w(db db2 db1 dbm gdbm gdbm_compat qdbm)
+end
+
+headers = {
+  "db" => ["db.h"],
+  "db1" => ["db1/ndbm.h", "db1.h", "ndbm.h"],
+  "db2" => ["db2/db.h", "db2.h", "db.h"],
+  "dbm" => ["ndbm.h"],
+  "gdbm" => ["gdbm-ndbm.h", "ndbm.h"],
+  "gdbm_compat" => ["gdbm-ndbm.h", "ndbm.h"],
+  "qdbm" => ["relic.h"],
+}
+
+def headers.db_check(db)
+  db_prefix = nil
+  have_gdbm = false
+  hsearch = nil
+
+  case db
+  when /^db2?$/
+    db_prefix = "__db_n"
+    hsearch = "-DDB_DBM_HSEARCH "
+  when "gdbm"
+    have_gdbm = true
+  when "gdbm_compat"
+    have_gdbm = true
+    have_library("gdbm") or return false
+  end
+  db_prefix ||= ""
+
+  if (have_library(db, db_prefix+"dbm_open") || have_func(db_prefix+"dbm_open")) and
+      hdr = self.fetch(db, ["ndbm.h"]).find {|hdr| have_type("DBM", hdr, hsearch)}
+    have_func(db_prefix+"dbm_clearerr") unless have_gdbm
+    $defs << hsearch if hsearch
+    $defs << '-DDBM_HDR="<'+hdr+'>"'
+    true
+  else
+    false
+  end
+end
+
+if dblib.any? {|db| headers.db_check(db)}
+  have_header("cdefs.h")
+  have_header("sys/cdefs.h")
+  create_makefile("dbm")
+end

Added: trunk/ext/dl/cfunc.c
===================================================================
--- trunk/ext/dl/cfunc.c	2006-11-06 13:53:20 UTC (rev 575)
+++ trunk/ext/dl/cfunc.c	2006-11-07 04:23:15 UTC (rev 576)
@@ -0,0 +1,509 @@
+/* -*- C -*-
+ * $Id: cfunc.c,v 1.8 2006/09/02 14:41:34 matz Exp $
+ */
+
+#include <ruby.h>
+#include <errno.h>
+#include "dl.h"
+
+VALUE rb_cDLCFunc;
+
+static ID id_last_error;
+
+static VALUE
+rb_dl_get_last_error(VALUE self)
+{
+    return rb_thread_local_aref(rb_thread_current(), id_last_error);
+}
+
+static VALUE
+rb_dl_set_last_error(VALUE self, VALUE val)
+{
+    rb_thread_local_aset(rb_thread_current(), id_last_error, val);
+    return Qnil;
+}
+
+#if defined(HAVE_WINDOWS_H)
+#include <windows.h>
+static ID id_win32_last_error;
+
+static VALUE
+rb_dl_get_win32_last_error(VALUE self)
+{
+    return rb_thread_local_aref(rb_thread_current(), id_win32_last_error);
+}
+
+static VALUE
+rb_dl_set_win32_last_error(VALUE self, VALUE val)
+{
+    rb_thread_local_aset(rb_thread_current(), id_win32_last_error, val);
+    return Qnil;
+}
+#endif
+
+
+void
+dlcfunc_free(struct cfunc_data *data)
+{
+  if( data->name ){
+      xfree(data->name);
+  }
+  xfree(data);
+}
+
+VALUE
+rb_dlcfunc_new(void (*func)(), int type, const char *name, ID calltype)
+{
+  VALUE val;
+  struct cfunc_data *data;
+
+  rb_secure(4);
+  if( func ){
+    val = Data_Make_Struct(rb_cDLCFunc, struct cfunc_data, 0, dlcfunc_free, data);
+    data->ptr  = func;
+    data->name = name ? strdup(name) : NULL;
+    data->type = type;
+    data->calltype = calltype;
+  }
+  else{
+    val = Qnil;
+  }
+
+  return val;
+}
+
+void *
+rb_dlcfunc2ptr(VALUE val)
+{
+  struct cfunc_data *data;
+  void * func;
+
+  if( rb_obj_is_kind_of(val, rb_cDLCFunc) ){
+    Data_Get_Struct(val, struct cfunc_data, data);
+    func = data->ptr;
+  }
+  else if( val == Qnil ){
+    func = NULL;
+  }
+  else{
+    rb_raise(rb_eTypeError, "DL::CFunc was expected");
+  }
+
+  return func;
+}
+
+VALUE
+rb_dlcfunc_s_allocate(VALUE klass)
+{
+  VALUE obj;
+  struct cfunc_data *data;
+
+  obj = Data_Make_Struct(klass, struct cfunc_data, 0, dlcfunc_free, data);
+  data->ptr  = 0;
+  data->name = 0;
+  data->type = 0;
+  data->calltype = CFUNC_CDECL;
+
+  return obj;
+}
+
+VALUE
+rb_dlcfunc_initialize(int argc, VALUE argv[], VALUE self)
+{
+    VALUE addr, name, type, calltype;
+    struct cfunc_data *data;
+    void *saddr;
+    const char *sname;
+    
+    rb_scan_args(argc, argv, "13", &addr, &type, &name, &calltype);
+    
+    saddr = (void*)(NUM2PTR(rb_Integer(addr)));
+    sname = NIL_P(name) ? NULL : StringValuePtr(name);
+    
+    Data_Get_Struct(self, struct cfunc_data, data);
+    if( data->name ) xfree(data->name);
+    data->ptr  = saddr;
+    data->name = sname ? strdup(sname) : 0;
+    data->type = (type == Qnil) ? DLTYPE_VOID : NUM2INT(type);
+    data->calltype = (calltype == Qnil) ? CFUNC_CDECL : SYM2ID(calltype);
+
+    return Qnil;
+}
+
+VALUE
+rb_dlcfunc_name(VALUE self)
+{
+    struct cfunc_data *cfunc;
+
+    Data_Get_Struct(self, struct cfunc_data, cfunc);
+    return cfunc->name ? rb_tainted_str_new2(cfunc->name) : Qnil;
+}
+
+VALUE
+rb_dlcfunc_ctype(VALUE self)
+{
+    struct cfunc_data *cfunc;
+
+    Data_Get_Struct(self, struct cfunc_data, cfunc);
+    return INT2NUM(cfunc->type);
+}
+
+VALUE
+rb_dlcfunc_set_ctype(VALUE self, VALUE ctype)
+{
+    struct cfunc_data *cfunc;
+
+    Data_Get_Struct(self, struct cfunc_data, cfunc);
+    cfunc->type = NUM2INT(ctype);
+    return ctype;
+}
+
+VALUE
+rb_dlcfunc_calltype(VALUE self)
+{
+    struct cfunc_data *cfunc;
+
+    Data_Get_Struct(self, struct cfunc_data, cfunc);
+    return ID2SYM(cfunc->calltype);
+}
+
+VALUE
+rb_dlcfunc_set_calltype(VALUE self, VALUE sym)
+{
+    struct cfunc_data *cfunc;
+
+    Data_Get_Struct(self, struct cfunc_data, cfunc);
+    cfunc->calltype = SYM2ID(sym);
+    return sym;
+}
+
+
+VALUE
+rb_dlcfunc_ptr(VALUE self)
+{
+    struct cfunc_data *cfunc;
+
+    Data_Get_Struct(self, struct cfunc_data, cfunc);
+    return PTR2NUM(cfunc->ptr);
+}
+
+VALUE
+rb_dlcfunc_set_ptr(VALUE self, VALUE addr)
+{
+    struct cfunc_data *cfunc;
+
+    Data_Get_Struct(self, struct cfunc_data, cfunc);
+    cfunc->ptr = NUM2PTR(addr);
+
+    return Qnil;
+}
+
+VALUE
+rb_dlcfunc_inspect(VALUE self)
+{
+    VALUE val;
+    char  *str;
+    int str_size;
+    struct cfunc_data *cfunc;
+    
+    Data_Get_Struct(self, struct cfunc_data, cfunc);
+    
+    str_size = (cfunc->name ? strlen(cfunc->name) : 0) + 100;
+    str = ruby_xmalloc(str_size);
+    snprintf(str, str_size - 1,
+	     "#<DL::CFunc:%p ptr=%p type=%d name='%s'>",
+	     cfunc,
+	     cfunc->ptr,
+	     cfunc->type,
+	     cfunc->name ? cfunc->name : "");
+    val = rb_tainted_str_new2(str);
+    ruby_xfree(str);
+
+    return val;
+}
+
+
+# define DECL_FUNC_CDECL(f,ret,args)  ret (FUNC_CDECL(*f))(args)
+# define DECL_FUNC_STDCALL(f,ret,args)  ret (FUNC_STDCALL(*f))(args)
+
+#define CALL_CASE switch( RARRAY_LEN(ary) ){ \
+  CASE(0); break; \
+  CASE(1); break; CASE(2); break; CASE(3); break; CASE(4); break; CASE(5); break; \
+  CASE(6); break; CASE(7); break; CASE(8); break; CASE(9); break; CASE(10);break; \
+  CASE(11);break; CASE(12);break; CASE(13);break; CASE(14);break; CASE(15);break; \
+  CASE(16);break; CASE(17);break; CASE(18);break; CASE(19);break; CASE(20);break; \
+  default: rb_raise(rb_eArgError, "too many arguments"); \
+}
+
+
+VALUE
+rb_dlcfunc_call(VALUE self, VALUE ary)
+{
+    struct cfunc_data *cfunc;
+    int i;
+    DLSTACK_TYPE stack[DLSTACK_SIZE];
+    VALUE result = Qnil;
+
+    rb_secure_update(self);
+
+    memset(stack, 0, sizeof(DLSTACK_TYPE) * DLSTACK_SIZE);
+    Check_Type(ary, T_ARRAY);
+    
+    Data_Get_Struct(self, struct cfunc_data, cfunc);
+
+    if( cfunc->ptr == 0 ){
+	rb_raise(rb_eDLError, "can't call null-function");
+	return Qnil;
+    }
+    
+    for( i = 0; i < RARRAY_LEN(ary); i++ ){
+	if( i >= DLSTACK_SIZE ){
+	    rb_raise(rb_eDLError, "too many arguments (stack overflow)");
+	}
+	stack[i] = NUM2LONG(RARRAY_PTR(ary)[i]);
+    }
+    
+    /* calltype == CFUNC_CDECL */
+    if( cfunc->calltype == CFUNC_CDECL ){
+	switch( cfunc->type ){
+	case DLTYPE_VOID:
+#define CASE(n) case n: { \
+            DECL_FUNC_CDECL(f,void,DLSTACK_PROTO##n) = cfunc->ptr; \
+	    f(DLSTACK_ARGS##n(stack)); \
+	    result = Qnil; \
+}
+	    CALL_CASE;
+#undef CASE
+	    break;
+	case DLTYPE_VOIDP:
+#define CASE(n) case n: { \
+	    DECL_FUNC_CDECL(f,void*,DLSTACK_PROTO##n) = cfunc->ptr; \
+	    void * ret; \
+	    ret = f(DLSTACK_ARGS##n(stack)); \
+	    result = PTR2NUM(ret); \
+}
+	    CALL_CASE;
+#undef CASE
+	    break;
+	case DLTYPE_CHAR:
+#define CASE(n) case n: { \
+	    DECL_FUNC_CDECL(f,char,DLSTACK_PROTO##n) = cfunc->ptr; \
+	    char ret; \
+	    ret = f(DLSTACK_ARGS##n(stack)); \
+	    result = CHR2FIX(ret); \
+}
+	    CALL_CASE;
+#undef CASE
+	    break;
+	case DLTYPE_SHORT:
+#define CASE(n) case n: { \
+	    DECL_FUNC_CDECL(f,short,DLSTACK_PROTO##n) = cfunc->ptr; \
+	    short ret; \
+	    ret = f(DLSTACK_ARGS##n(stack)); \
+	    result = INT2NUM((int)ret); \
+}
+	    CALL_CASE;
+#undef CASE
+	    break;
+	case DLTYPE_INT:
+#define CASE(n) case n: { \
+	    DECL_FUNC_CDECL(f,int,DLSTACK_PROTO##n) = cfunc->ptr; \
+	    int ret; \
+	    ret = f(DLSTACK_ARGS##n(stack)); \
+	    result = INT2NUM(ret); \
+}
+	    CALL_CASE;
+#undef CASE
+	    break;
+	case DLTYPE_LONG:
+#define CASE(n) case n: { \
+	    DECL_FUNC_CDECL(f,long,DLSTACK_PROTO##n) = cfunc->ptr; \
+	    long ret; \
+	    ret = f(DLSTACK_ARGS##n(stack)); \
+	    result = LONG2NUM(ret); \
+}
+	    CALL_CASE;
+#undef CASE
+	    break;
+#if HAVE_LONG_LONG  /* used in ruby.h */
+	case DLTYPE_LONG_LONG:
+#define CASE(n) case n: { \
+	    DECL_FUNC_CDECL(f,LONG_LONG,DLSTACK_PROTO) = cfunc->ptr; \
+	    LONG_LONG ret; \
+	    ret = f(DLSTACK_ARGS(stack)); \
+	    result = LL2NUM(ret); \
+}
+	    CALL_CASE;
+#undef CASE
+	    break;
+#endif
+	case DLTYPE_FLOAT:
+#define CASE(n) case n: { \
+	    DECL_FUNC_CDECL(f,float,DLSTACK_PROTO) = cfunc->ptr; \
+	    float ret; \
+	    ret = f(DLSTACK_ARGS(stack)); \
+	    result = rb_float_new(ret); \
+}
+	    CALL_CASE;
+#undef CASE
+	    break;
+	case DLTYPE_DOUBLE:
+#define CASE(n) case n: { \
+	    DECL_FUNC_CDECL(f,double,DLSTACK_PROTO) = cfunc->ptr; \
+	    double ret; \
+	    ret = f(DLSTACK_ARGS(stack)); \
+	    result = rb_float_new(ret); \
+}
+	    CALL_CASE;
+#undef CASE
+	    break;
+	default:
+	    rb_raise(rb_eDLTypeError, "unknown type %d", cfunc->type);
+	}
+    }
+    else if( cfunc->calltype == CFUNC_STDCALL ){
+	/* calltype == CFUNC_STDCALL */
+	switch( cfunc->type ){
+	case DLTYPE_VOID:
+#define CASE(n) case n: { \
+            DECL_FUNC_STDCALL(f,void,DLSTACK_PROTO##n) = cfunc->ptr; \
+	    f(DLSTACK_ARGS##n(stack)); \
+	    result = Qnil; \
+}
+	    CALL_CASE;
+#undef CASE
+	    break;
+	case DLTYPE_VOIDP:
+#define CASE(n) case n: { \
+	    DECL_FUNC_STDCALL(f,void*,DLSTACK_PROTO##n) = cfunc->ptr; \
+	    void * ret; \
+	    ret = f(DLSTACK_ARGS##n(stack)); \
+	    result = PTR2NUM(ret); \
+}
+	    CALL_CASE;
+#undef CASE
+	    break;
+	case DLTYPE_CHAR:
+#define CASE(n) case n: { \
+	    DECL_FUNC_STDCALL(f,char,DLSTACK_PROTO##n) = cfunc->ptr; \
+	    char ret; \
+	    ret = f(DLSTACK_ARGS##n(stack)); \
+	    result = CHR2FIX(ret); \
+}
+	    CALL_CASE;
+#undef CASE
+	    break;
+	case DLTYPE_SHORT:
+#define CASE(n) case n: { \
+	    DECL_FUNC_STDCALL(f,short,DLSTACK_PROTO##n) = cfunc->ptr; \
+	    short ret; \
+	    ret = f(DLSTACK_ARGS##n(stack)); \
+	    result = INT2NUM((int)ret); \
+}
+	    CALL_CASE;
+#undef CASE
+	    break;
+	case DLTYPE_INT:
+#define CASE(n) case n: { \
+	    DECL_FUNC_STDCALL(f,int,DLSTACK_PROTO##n) = cfunc->ptr; \
+	    int ret; \
+	    ret = f(DLSTACK_ARGS##n(stack)); \
+	    result = INT2NUM(ret); \
+}
+	    CALL_CASE;
+#undef CASE
+	    break;
+	case DLTYPE_LONG:
+#define CASE(n) case n: { \
+	    DECL_FUNC_STDCALL(f,long,DLSTACK_PROTO##n) = cfunc->ptr; \
+	    long ret; \
+	    ret = f(DLSTACK_ARGS##n(stack)); \
+	    result = LONG2NUM(ret); \
+}
+	    CALL_CASE;
+#undef CASE
+	    break;
+#if HAVE_LONG_LONG  /* used in ruby.h */
+	case DLTYPE_LONG_LONG:
+#define CASE(n) case n: { \
+	    DECL_FUNC_STDCALL(f,LONG_LONG,DLSTACK_PROTO) = cfunc->ptr; \
+	    LONG_LONG ret; \
+	    ret = f(DLSTACK_ARGS(stack)); \
+	    result = LL2NUM(ret); \
+}
+	    CALL_CASE;
+#undef CASE
+	    break;
+#endif
+	case DLTYPE_FLOAT:
+#define CASE(n) case n: { \
+	    DECL_FUNC_STDCALL(f,float,DLSTACK_PROTO) = cfunc->ptr; \
+	    float ret; \
+	    ret = f(DLSTACK_ARGS(stack)); \
+	    result = rb_float_new(ret); \
+}
+	    CALL_CASE;
+#undef CASE
+	    break;
+	case DLTYPE_DOUBLE:
+#define CASE(n) case n: { \
+	    DECL_FUNC_STDCALL(f,double,DLSTACK_PROTO) = cfunc->ptr; \
+	    double ret; \
+	    ret = f(DLSTACK_ARGS(stack)); \
+	    result = rb_float_new(ret); \
+}
+	    CALL_CASE;
+#undef CASE
+	    break;
+	default:
+	    rb_raise(rb_eDLTypeError, "unknown type %d", cfunc->type);
+	}
+    }
+    else{
+	rb_raise(rb_eDLError, "unsupported call type: %x", cfunc->calltype);
+    }
+
+    rb_dl_set_last_error(self, INT2NUM(errno));
+#if defined(HAVE_WINDOWS_H)
+    rb_dl_set_win32_last_error(self, INT2NUM(GetLastError()));
+#endif
+
+    return result;
+}
+
+VALUE
+rb_dlcfunc_to_i(VALUE self)
+{
+  struct cfunc_data *cfunc;
+
+  Data_Get_Struct(self, struct cfunc_data, cfunc);
+  return PTR2NUM(cfunc->ptr);
+}
+
+void
+Init_dlcfunc()
+{
+    id_last_error = rb_intern("__DL2_LAST_ERROR__");
+#if defined(HAVE_WINDOWS_H)
+    id_win32_last_error = rb_intern("__DL2_WIN32_LAST_ERROR__");
+#endif
+    rb_cDLCFunc = rb_define_class_under(rb_mDL, "CFunc", rb_cObject);
+    rb_define_alloc_func(rb_cDLCFunc, rb_dlcfunc_s_allocate);
+    rb_define_module_function(rb_cDLCFunc, "last_error", rb_dl_get_last_error, 0);
+#if defined(HAVE_WINDOWS_H)
+    rb_define_module_function(rb_cDLCFunc, "win32_last_error", rb_dl_get_win32_last_error, 0);
+#endif
+    rb_define_method(rb_cDLCFunc, "initialize", rb_dlcfunc_initialize, -1);
+    rb_define_method(rb_cDLCFunc, "call", rb_dlcfunc_call, 1);
+    rb_define_method(rb_cDLCFunc, "[]",   rb_dlcfunc_call, 1);
+    rb_define_method(rb_cDLCFunc, "name", rb_dlcfunc_name, 0);
+    rb_define_method(rb_cDLCFunc, "ctype", rb_dlcfunc_ctype, 0);
+    rb_define_method(rb_cDLCFunc, "ctype=", rb_dlcfunc_set_ctype, 1);
+    rb_define_method(rb_cDLCFunc, "calltype", rb_dlcfunc_calltype, 0);
+    rb_define_method(rb_cDLCFunc, "calltype=", rb_dlcfunc_set_calltype, 1);
+    rb_define_method(rb_cDLCFunc, "ptr",  rb_dlcfunc_ptr, 0);
+    rb_define_method(rb_cDLCFunc, "ptr=", rb_dlcfunc_set_ptr, 1);
+    rb_define_method(rb_cDLCFunc, "inspect", rb_dlcfunc_inspect, 0);
+    rb_define_method(rb_cDLCFunc, "to_s", rb_dlcfunc_inspect, 0);
+    rb_define_method(rb_cDLCFunc, "to_i", rb_dlcfunc_to_i, 0);
+}

Added: trunk/ext/dl/cptr.c
===================================================================
--- trunk/ext/dl/cptr.c	2006-11-06 13:53:20 UTC (rev 575)
+++ trunk/ext/dl/cptr.c	2006-11-07 04:23:15 UTC (rev 576)
@@ -0,0 +1,483 @@
+/* -*- C -*-
+ * $Id: cptr.c,v 1.8 2006/08/31 12:10:07 usa Exp $
+ */
+
+#include <ruby.h>
+#include <rubyio.h>
+#include <ctype.h>
+#include <version.h> /* for ruby version code */
+#include "dl.h"
+
+VALUE rb_cDLCPtr;
+
+static ID id_to_ptr;
+
+static void
+dlptr_free(struct ptr_data *data)
+{
+  if (data->ptr) {
+      if (data->free) {
+	  (*(data->free))(data->ptr);
+      }
+  }
+}
+
+static void
+dlptr_mark(struct ptr_data *data)
+{
+}
+
+void
+dlptr_init(VALUE val)
+{
+  struct ptr_data *data;
+
+  Data_Get_Struct(val, struct ptr_data, data);
+  OBJ_TAINT(val);
+}
+
+VALUE
+rb_dlptr_new2(VALUE klass, void *ptr, long size, freefunc_t func)
+{
+  struct ptr_data *data;
+  VALUE val;
+
+  rb_secure(4);
+  val = Data_Make_Struct(klass, struct ptr_data,
+			 0, dlptr_free, data);
+  data->ptr = ptr;
+  data->free = func;
+  data->size = size;
+  dlptr_init(val);
+
+  return val;
+}
+
+VALUE
+rb_dlptr_new(void *ptr, long size, freefunc_t func)
+{
+  return rb_dlptr_new2(rb_cDLCPtr, ptr, size, func);
+}
+
+VALUE
+rb_dlptr_malloc(long size, freefunc_t func)
+{
+  void *ptr;
+
+  rb_secure(4);
+  ptr = ruby_xmalloc((size_t)size);
+  memset(ptr,0,(size_t)size);
+  return rb_dlptr_new(ptr, size, func);
+}
+
+void *
+rb_dlptr2cptr(VALUE val)
+{
+  struct ptr_data *data;
+  void *ptr;
+
+  if (rb_obj_is_kind_of(val, rb_cDLCPtr)) {
+    Data_Get_Struct(val, struct ptr_data, data);
+    ptr = data->ptr;
+  }
+  else if (val == Qnil) {
+    ptr = NULL;
+  }
+  else{
+    rb_raise(rb_eTypeError, "DL::PtrData was expected");
+  }
+    
+  return ptr;
+}
+
+static VALUE
+rb_dlptr_s_allocate(VALUE klass)
+{
+  VALUE obj;
+  struct ptr_data *data;
+
+  rb_secure(4);
+  obj = Data_Make_Struct(klass, struct ptr_data, dlptr_mark, dlptr_free, data);
+  data->ptr = 0;
+  data->size = 0;
+  data->free = 0;
+
+  return obj;
+}
+
+static VALUE
+rb_dlptr_initialize(int argc, VALUE argv[], VALUE self)
+{
+  VALUE ptr, sym, size;
+  struct ptr_data *data;
+  void *p = NULL;
+  freefunc_t f = NULL;
+  long s = 0;
+
+  switch (rb_scan_args(argc, argv, "12", &ptr, &size, &sym)) {
+  case 1:
+    p = (void*)(NUM2PTR(rb_Integer(ptr)));
+    break;
+  case 2:
+    p = (void*)(NUM2PTR(rb_Integer(ptr)));
+    s = NUM2LONG(size);
+    break;
+  case 3:
+    p = (void*)(NUM2PTR(rb_Integer(ptr)));
+    s = NUM2LONG(size);
+    f = NIL_P(sym) ? NULL : RCFUNC_DATA(sym)->ptr;
+    break;
+  default:
+    rb_bug("rb_dlptr_initialize");
+  }
+
+  if (p) {
+    Data_Get_Struct(self, struct ptr_data, data);
+    if (data->ptr && data->free) {
+      /* Free previous memory. Use of inappropriate initialize may cause SEGV. */
+      (*(data->free))(data->ptr);
+    }
+    data->ptr  = p;
+    data->size = s;
+    data->free = f;
+  }
+
+  return Qnil;
+}
+
+static VALUE
+rb_dlptr_s_malloc(int argc, VALUE argv[], VALUE klass)
+{
+  VALUE size, sym, obj;
+  int   s;
+  freefunc_t f;
+
+  switch (rb_scan_args(argc, argv, "11", &size, &sym)) {
+  case 1:
+    s = NUM2LONG(size);
+    f = NULL;
+    break;
+  case 2:
+    s = NUM2LONG(size);
+    f = RCFUNC_DATA(sym)->ptr;
+    break;
+  default:
+    rb_bug("rb_dlptr_s_malloc");
+  }
+
+  obj = rb_dlptr_malloc(s,f);
+
+  return obj;
+}
+
+VALUE
+rb_dlptr_to_i(VALUE self)
+{
+  struct ptr_data *data;
+
+  Data_Get_Struct(self, struct ptr_data, data);
+  return PTR2NUM(data->ptr);
+}
+
+VALUE
+rb_dlptr_to_value(VALUE self)
+{
+    struct ptr_data *data;
+    Data_Get_Struct(self, struct ptr_data, data);
+    return (VALUE)(data->ptr);
+}
+
+VALUE
+rb_dlptr_ptr(VALUE self)
+{
+  struct ptr_data *data;
+
+  Data_Get_Struct(self, struct ptr_data, data);
+  return rb_dlptr_new(*((void**)(data->ptr)),0,0);
+}
+
+VALUE
+rb_dlptr_ref(VALUE self)
+{
+  struct ptr_data *data;
+
+  Data_Get_Struct(self, struct ptr_data, data);
+  return rb_dlptr_new(&(data->ptr),0,0);
+}
+
+VALUE
+rb_dlptr_null_p(VALUE self)
+{
+  struct ptr_data *data;
+
+  Data_Get_Struct(self, struct ptr_data, data);
+  return data->ptr ? Qfalse : Qtrue;
+}
+
+VALUE
+rb_dlptr_free_set(VALUE self, VALUE val)
+{
+  struct ptr_data *data;
+  extern VALUE rb_cDLCFunc;
+
+  Data_Get_Struct(self, struct ptr_data, data);
+  if( rb_obj_is_kind_of(val, rb_cDLCFunc) == Qtrue ){
+      data->free = RCFUNC_DATA(val)->ptr;
+  }
+  else{
+      data->free = NUM2PTR(rb_Integer(val));
+  }
+
+  return Qnil;
+}
+
+VALUE
+rb_dlptr_free_get(VALUE self)
+{
+  struct ptr_data *pdata;
+
+  Data_Get_Struct(self, struct ptr_data, pdata);
+
+  return rb_dlcfunc_new(pdata->free, DLTYPE_VOID, "free<anonymous>", CFUNC_CDECL);
+}
+
+VALUE
+rb_dlptr_to_s(int argc, VALUE argv[], VALUE self)
+{
+  struct ptr_data *data;
+  VALUE arg1, val;
+  int len;
+
+  Data_Get_Struct(self, struct ptr_data, data);
+  switch (rb_scan_args(argc, argv, "01", &arg1)) {
+  case 0:
+    val = rb_tainted_str_new2((char*)(data->ptr));
+    break;
+  case 1:
+    len = NUM2INT(arg1);
+    val = rb_tainted_str_new((char*)(data->ptr), len);
+    break;
+  default:
+    rb_bug("rb_dlptr_to_s");
+  }
+
+  return val;
+}
+
+VALUE
+rb_dlptr_to_str(int argc, VALUE argv[], VALUE self)
+{
+  struct ptr_data *data;
+  VALUE arg1, val;
+  int len;
+
+  Data_Get_Struct(self, struct ptr_data, data);
+  switch (rb_scan_args(argc, argv, "01", &arg1)) {
+  case 0:
+    val = rb_tainted_str_new((char*)(data->ptr),data->size);
+    break;
+  case 1:
+    len = NUM2INT(arg1);
+    val = rb_tainted_str_new((char*)(data->ptr), len);
+    break;
+  default:
+    rb_bug("rb_dlptr_to_str");
+  }
+
+  return val;
+}
+
+VALUE
+rb_dlptr_inspect(VALUE self)
+{
+  struct ptr_data *data;
+  char str[1024];
+
+  Data_Get_Struct(self, struct ptr_data, data);
+  snprintf(str, 1023, "#<%s:%p ptr=%p size=%ld free=%p>",
+	   rb_class2name(CLASS_OF(self)), data, data->ptr, data->size, data->free);
+  return rb_str_new2(str);
+}
+
+VALUE
+rb_dlptr_eql(VALUE self, VALUE other)
+{
+  void *ptr1, *ptr2;
+  ptr1 = rb_dlptr2cptr(self);
+  ptr2 = rb_dlptr2cptr(other);
+
+  return ptr1 == ptr2 ? Qtrue : Qfalse;
+}
+
+VALUE
+rb_dlptr_cmp(VALUE self, VALUE other)
+{
+  void *ptr1, *ptr2;
+  ptr1 = rb_dlptr2cptr(self);
+  ptr2 = rb_dlptr2cptr(other);
+  return PTR2NUM((long)ptr1 - (long)ptr2);
+}
+
+VALUE
+rb_dlptr_plus(VALUE self, VALUE other)
+{
+  void *ptr;
+  long num, size;
+
+  ptr = rb_dlptr2cptr(self);
+  size = RPTR_DATA(self)->size;
+  num = NUM2LONG(other);
+  return rb_dlptr_new((char *)ptr + num, size - num, 0);
+}
+
+VALUE
+rb_dlptr_minus(VALUE self, VALUE other)
+{
+  void *ptr;
+  long num, size;
+
+  ptr = rb_dlptr2cptr(self);
+  size = RPTR_DATA(self)->size;
+  num = NUM2LONG(other);
+  return rb_dlptr_new((char *)ptr - num, size + num, 0);
+}
+
+VALUE
+rb_dlptr_aref(int argc, VALUE argv[], VALUE self)
+{
+    VALUE arg0, arg1;
+    VALUE retval = Qnil;
+    size_t offset, len;
+
+    switch( rb_scan_args(argc, argv, "11", &arg0, &arg1) ){
+    case 1:
+	offset = NUM2ULONG(arg0);
+	retval = INT2NUM(*((char*)RPTR_DATA(self)->ptr + offset));
+	break;
+    case 2:
+	offset = NUM2ULONG(arg0);
+	len    = NUM2ULONG(arg1);
+	retval = rb_tainted_str_new((char *)RPTR_DATA(self)->ptr + offset, len);
+	break;
+    default:
+	rb_bug("rb_dlptr_aref()");
+    }
+    return retval;
+}
+
+VALUE
+rb_dlptr_aset(int argc, VALUE argv[], VALUE self)
+{
+    VALUE arg0, arg1, arg2;
+    VALUE retval = Qnil;
+    size_t offset, len;
+    void *mem;
+
+    switch( rb_scan_args(argc, argv, "21", &arg0, &arg1, &arg2) ){
+    case 2:
+	offset = NUM2ULONG(arg0);
+	((char*)RPTR_DATA(self)->ptr)[offset] = NUM2UINT(arg1);
+	retval = arg1;
+	break;
+    case 3:
+	offset = NUM2ULONG(arg0);
+	len    = NUM2ULONG(arg1);
+	if( TYPE(arg2) == T_STRING ){
+	    mem = StringValuePtr(arg2);
+	}
+	else if( rb_obj_is_kind_of(arg2, rb_cDLCPtr) ){
+	    mem = rb_dlptr2cptr(arg2);
+	}
+	else{
+	    mem    = NUM2PTR(arg2);
+	}
+	memcpy((char *)RPTR_DATA(self)->ptr + offset, mem, len);
+	retval = arg2;
+	break;
+    default:
+	rb_bug("rb_dlptr_aset()");
+    }
+    return retval;
+}
+
+VALUE
+rb_dlptr_size(int argc, VALUE argv[], VALUE self)
+{
+  VALUE size;
+
+  if (rb_scan_args(argc, argv, "01", &size) == 0){
+    return LONG2NUM(RPTR_DATA(self)->size);
+  }
+  else{
+    RPTR_DATA(self)->size = NUM2LONG(size);
+    return size;
+  }
+}
+
+VALUE
+rb_dlptr_s_to_ptr(VALUE self, VALUE val)
+{
+    if( rb_obj_is_kind_of(val, rb_cIO) == Qtrue ){
+	OpenFile *fptr;
+	FILE *fp;
+	GetOpenFile(val, fptr);
+#if RUBY_VERSION_CODE >= 190
+	fp = rb_io_stdio_file(fptr);
+#else
+	fp = fptr->f;
+#endif
+	return rb_dlptr_new(fp, 0, NULL);
+    }
+    else if( rb_obj_is_kind_of(val, rb_cString) == Qtrue ){
+        char *ptr = StringValuePtr(val);
+        return rb_dlptr_new(ptr, RSTRING_LEN(val), NULL); 
+    }
+    else if( rb_respond_to(val, id_to_ptr) ){
+	VALUE vptr = rb_funcall(val, id_to_ptr, 0);
+	if( rb_obj_is_kind_of(vptr, rb_cDLCPtr) ){
+	    return vptr;
+	}
+	else{
+	    rb_raise(rb_eDLError, "to_ptr should return a CPtr object");
+	}
+    }
+    else{
+	return rb_dlptr_new(NUM2PTR(rb_Integer(val)), 0, NULL);
+    }
+}
+
+void
+Init_dlptr()
+{
+    id_to_ptr = rb_intern("to_ptr");
+
+    rb_cDLCPtr = rb_define_class_under(rb_mDL, "CPtr", rb_cObject);
+    rb_define_alloc_func(rb_cDLCPtr, rb_dlptr_s_allocate);
+    rb_define_singleton_method(rb_cDLCPtr, "malloc", rb_dlptr_s_malloc, -1);
+    rb_define_singleton_method(rb_cDLCPtr, "to_ptr", rb_dlptr_s_to_ptr, 1);
+    rb_define_singleton_method(rb_cDLCPtr, "[]", rb_dlptr_s_to_ptr, 1);
+    rb_define_method(rb_cDLCPtr, "initialize", rb_dlptr_initialize, -1);
+    rb_define_method(rb_cDLCPtr, "free=", rb_dlptr_free_set, 1);
+    rb_define_method(rb_cDLCPtr, "free",  rb_dlptr_free_get, 0);
+    rb_define_method(rb_cDLCPtr, "to_i",  rb_dlptr_to_i, 0);
+    rb_define_method(rb_cDLCPtr, "to_value",  rb_dlptr_to_value, 0);
+    rb_define_method(rb_cDLCPtr, "ptr",   rb_dlptr_ptr, 0);
+    rb_define_method(rb_cDLCPtr, "+@", rb_dlptr_ptr, 0);
+    rb_define_method(rb_cDLCPtr, "ref",   rb_dlptr_ref, 0);
+    rb_define_method(rb_cDLCPtr, "-@", rb_dlptr_ref, 0);
+    rb_define_method(rb_cDLCPtr, "null?", rb_dlptr_null_p, 0);
+    rb_define_method(rb_cDLCPtr, "to_s", rb_dlptr_to_s, -1);
+    rb_define_method(rb_cDLCPtr, "to_str", rb_dlptr_to_str, -1);
+    rb_define_method(rb_cDLCPtr, "inspect", rb_dlptr_inspect, 0);
+    rb_define_method(rb_cDLCPtr, "<=>", rb_dlptr_cmp, 1);
+    rb_define_method(rb_cDLCPtr, "==", rb_dlptr_eql, 1);
+    rb_define_method(rb_cDLCPtr, "eql?", rb_dlptr_eql, 1);
+    rb_define_method(rb_cDLCPtr, "+", rb_dlptr_plus, 1);
+    rb_define_method(rb_cDLCPtr, "-", rb_dlptr_minus, 1);
+    rb_define_method(rb_cDLCPtr, "[]", rb_dlptr_aref, -1);
+    rb_define_method(rb_cDLCPtr, "[]=", rb_dlptr_aset, -1);
+    rb_define_method(rb_cDLCPtr, "size", rb_dlptr_size, -1);
+    rb_define_method(rb_cDLCPtr, "size=", rb_dlptr_size, -1);
+
+    rb_define_const(rb_mDL, "NULL", rb_dlptr_new(0, 0, 0));
+}

Added: trunk/ext/dl/depend
===================================================================
--- trunk/ext/dl/depend	2006-11-06 13:53:20 UTC (rev 575)
+++ trunk/ext/dl/depend	2006-11-07 04:23:15 UTC (rev 576)
@@ -0,0 +1,11 @@
+cfunc.o: cfunc.c dl.h
+
+cptr.o: cptr.c dl.h
+
+handle.o: handle.c dl.h
+
+dl.o: dl.c dl.h callback.h
+
+callback.h: $(srcdir)/mkcallback.rb dl.h
+	@echo "generating callback.h"
+	@$(RUBY) $(srcdir)/mkcallback.rb $(srcdir)/dl.h > $@

Added: trunk/ext/dl/dl.c
===================================================================
--- trunk/ext/dl/dl.c	2006-11-06 13:53:20 UTC (rev 575)
+++ trunk/ext/dl/dl.c	2006-11-07 04:23:15 UTC (rev 576)
@@ -0,0 +1,133 @@
+#include <ruby.h>
+#include <rubyio.h>
+#include <version.h>
+#include <ctype.h>
+#include "dl.h"
+
+VALUE rb_mDL;
+VALUE rb_eDLError;
+VALUE rb_eDLTypeError;
+
+ID rbdl_id_cdecl;
+ID rbdl_id_stdcall;
+
+VALUE
+rb_dl_dlopen(int argc, VALUE argv[], VALUE self)
+{
+    rb_secure(2);
+    return rb_class_new_instance(argc, argv, rb_cDLHandle);
+}
+
+VALUE
+rb_dl_malloc(VALUE self, VALUE size)
+{
+    void *ptr;
+
+    ptr = (void*)ruby_xmalloc(NUM2INT(size));
+    return PTR2NUM(ptr);
+}
+
+VALUE
+rb_dl_realloc(VALUE self, VALUE addr, VALUE size)
+{
+    void *ptr = NUM2PTR(addr);
+
+    ptr = (void*)ruby_xrealloc(ptr, NUM2INT(size));
+    return PTR2NUM(ptr);
+}
+
+VALUE
+rb_dl_free(VALUE self, VALUE addr)
+{
+    void *ptr = NUM2PTR(addr);
+    ruby_xfree(ptr);
+    return Qnil;
+}
+
+VALUE
+rb_dl_ptr2value(VALUE self, VALUE addr)
+{
+    return (VALUE)NUM2PTR(addr);
+}
+
+VALUE
+rb_dl_value2ptr(VALUE self, VALUE val)
+{
+    return PTR2NUM((void*)val);
+}
+
+#include "callback.h"
+
+void
+Init_dl()
+{
+    void Init_dlhandle();
+    void Init_dlcfunc();
+    void Init_dlptr();
+
+    rbdl_id_cdecl = rb_intern("cdecl");
+    rbdl_id_stdcall = rb_intern("stdcall");
+
+    rb_mDL = rb_define_module("DL");
+    rb_eDLError = rb_define_class_under(rb_mDL, "DLError", rb_eStandardError);
+    rb_eDLTypeError = rb_define_class_under(rb_mDL, "DLTypeError", rb_eDLError);
+
+    rb_define_const(rb_mDL, "MAX_CALLBACK", INT2NUM(MAX_CALLBACK));
+    rb_define_const(rb_mDL, "DLSTACK_SIZE", INT2NUM(DLSTACK_SIZE));
+
+    rb_dl_init_callbacks();
+
+    rb_define_const(rb_mDL, "RTLD_GLOBAL", INT2NUM(RTLD_GLOBAL));
+    rb_define_const(rb_mDL, "RTLD_LAZY",   INT2NUM(RTLD_LAZY));
+    rb_define_const(rb_mDL, "RTLD_NOW",    INT2NUM(RTLD_NOW));
+
+    rb_define_const(rb_mDL, "TYPE_VOID",  INT2NUM(DLTYPE_VOID));
+    rb_define_const(rb_mDL, "TYPE_VOIDP",  INT2NUM(DLTYPE_VOIDP));
+    rb_define_const(rb_mDL, "TYPE_CHAR",  INT2NUM(DLTYPE_CHAR));
+    rb_define_const(rb_mDL, "TYPE_SHORT",  INT2NUM(DLTYPE_SHORT));
+    rb_define_const(rb_mDL, "TYPE_INT",  INT2NUM(DLTYPE_INT));
+    rb_define_const(rb_mDL, "TYPE_LONG",  INT2NUM(DLTYPE_LONG));
+#if HAVE_LONG_LONG
+    rb_define_const(rb_mDL, "TYPE_LONG_LONG",  INT2NUM(DLTYPE_LONG_LONG));
+#endif
+    rb_define_const(rb_mDL, "TYPE_FLOAT",  INT2NUM(DLTYPE_FLOAT));
+    rb_define_const(rb_mDL, "TYPE_DOUBLE",  INT2NUM(DLTYPE_DOUBLE));
+
+    rb_define_const(rb_mDL, "ALIGN_VOIDP", INT2NUM(ALIGN_VOIDP));
+    rb_define_const(rb_mDL, "ALIGN_CHAR",  INT2NUM(ALIGN_CHAR));
+    rb_define_const(rb_mDL, "ALIGN_SHORT", INT2NUM(ALIGN_SHORT));
+    rb_define_const(rb_mDL, "ALIGN_INT",   INT2NUM(ALIGN_INT));
+    rb_define_const(rb_mDL, "ALIGN_LONG",  INT2NUM(ALIGN_LONG));
+#if HAVE_LONG_LONG
+    rb_define_const(rb_mDL, "ALIGN_LONG_LONG",  INT2NUM(ALIGN_LONG_LONG));
+#endif
+    rb_define_const(rb_mDL, "ALIGN_FLOAT", INT2NUM(ALIGN_FLOAT));
+    rb_define_const(rb_mDL, "ALIGN_DOUBLE",INT2NUM(ALIGN_DOUBLE));
+
+    rb_define_const(rb_mDL, "SIZEOF_VOIDP", INT2NUM(sizeof(void*)));
+    rb_define_const(rb_mDL, "SIZEOF_CHAR",  INT2NUM(sizeof(char)));
+    rb_define_const(rb_mDL, "SIZEOF_SHORT", INT2NUM(sizeof(short)));
+    rb_define_const(rb_mDL, "SIZEOF_INT",   INT2NUM(sizeof(int)));
+    rb_define_const(rb_mDL, "SIZEOF_LONG",  INT2NUM(sizeof(long)));
+#if HAVE_LONG_LONG
+    rb_define_const(rb_mDL, "SIZEOF_LONG_LONG",  INT2NUM(sizeof(LONG_LONG)));
+#endif
+    rb_define_const(rb_mDL, "SIZEOF_FLOAT", INT2NUM(sizeof(float)));
+    rb_define_const(rb_mDL, "SIZEOF_DOUBLE",INT2NUM(sizeof(double)));
+
+    rb_define_module_function(rb_mDL, "dlwrap", rb_dl_value2ptr, 1);
+    rb_define_module_function(rb_mDL, "dlunwrap", rb_dl_ptr2value, 1);
+
+    rb_define_module_function(rb_mDL, "dlopen", rb_dl_dlopen, -1);
+    rb_define_module_function(rb_mDL, "malloc", rb_dl_malloc, 1);
+    rb_define_module_function(rb_mDL, "realloc", rb_dl_realloc, 2);
+    rb_define_module_function(rb_mDL, "free", rb_dl_free, 1);
+
+    rb_define_const(rb_mDL, "RUBY_FREE", PTR2NUM(ruby_xfree));
+    rb_define_const(rb_mDL, "BUILD_RUBY_PLATFORM", rb_str_new2(RUBY_PLATFORM));
+    rb_define_const(rb_mDL, "BUILD_RUBY_VERSION",  rb_str_new2(RUBY_VERSION));
+
+    Init_dlhandle();
+    Init_dlcfunc();
+    Init_dlptr();
+}

Added: trunk/ext/dl/dl.h
===================================================================
--- trunk/ext/dl/dl.h	2006-11-06 13:53:20 UTC (rev 575)
+++ trunk/ext/dl/dl.h	2006-11-07 04:23:15 UTC (rev 576)
@@ -0,0 +1,190 @@
+#ifndef RUBY_DL_H
+#define RUBY_DL_H
+
+#include <ruby.h>
+
+#if !defined(FUNC_CDECL)
+#  define FUNC_CDECL(x) x
+#endif
+#if !defined(FUNC_STDCALL)
+#  define FUNC_STDCALL(x) x
+#endif
+
+#if defined(HAVE_DLFCN_H)
+# include <dlfcn.h>
+# /* some stranger systems may not define all of these */
+#ifndef RTLD_LAZY
+#define RTLD_LAZY 0
+#endif
+#ifndef RTLD_GLOBAL
+#define RTLD_GLOBAL 0
+#endif
+#ifndef RTLD_NOW
+#define RTLD_NOW 0
+#endif
+#else
+# if defined(HAVE_WINDOWS_H)
+#   include <windows.h>
+#   define dlclose(ptr) FreeLibrary((HINSTANCE)ptr)
+#   define dlopen(name,flag) ((void*)LoadLibrary(name))
+#   define dlerror()    "unknown error"
+#   define dlsym(handle,name) ((void*)GetProcAddress(handle,name))
+#   define RTLD_LAZY -1
+#   define RTLD_NOW  -1
+#   define RTLD_GLOBAL -1
+# endif
+#endif
+
+#define MAX_CALLBACK 5
+#define DLSTACK_TYPE long
+#define DLSTACK_SIZE (20)
+#define DLSTACK_PROTO \
+    DLSTACK_TYPE,DLSTACK_TYPE,DLSTACK_TYPE,DLSTACK_TYPE,DLSTACK_TYPE,\
+    DLSTACK_TYPE,DLSTACK_TYPE,DLSTACK_TYPE,DLSTACK_TYPE,DLSTACK_TYPE,\
+    DLSTACK_TYPE,DLSTACK_TYPE,DLSTACK_TYPE,DLSTACK_TYPE,DLSTACK_TYPE,\
+    DLSTACK_TYPE,DLSTACK_TYPE,DLSTACK_TYPE,DLSTACK_TYPE,DLSTACK_TYPE
+#define DLSTACK_ARGS(stack) \
+    stack[0],stack[1],stack[2],stack[3],stack[4],\
+    stack[5],stack[6],stack[7],stack[8],stack[9],\
+    stack[10],stack[11],stack[12],stack[13],stack[14],\
+    stack[15],stack[16],stack[17],stack[18],stack[19]
+
+#define DLSTACK_PROTO0 
+#define DLSTACK_PROTO1 DLSTACK_TYPE
+#define DLSTACK_PROTO2 DLSTACK_PROTO1, DLSTACK_TYPE
+#define DLSTACK_PROTO3 DLSTACK_PROTO2, DLSTACK_TYPE
+#define DLSTACK_PROTO4 DLSTACK_PROTO3, DLSTACK_TYPE
+#define DLSTACK_PROTO4 DLSTACK_PROTO3, DLSTACK_TYPE
+#define DLSTACK_PROTO5 DLSTACK_PROTO4, DLSTACK_TYPE
+#define DLSTACK_PROTO6 DLSTACK_PROTO5, DLSTACK_TYPE
+#define DLSTACK_PROTO7 DLSTACK_PROTO6, DLSTACK_TYPE
+#define DLSTACK_PROTO8 DLSTACK_PROTO7, DLSTACK_TYPE
+#define DLSTACK_PROTO9 DLSTACK_PROTO8, DLSTACK_TYPE
+#define DLSTACK_PROTO10 DLSTACK_PROTO9, DLSTACK_TYPE
+#define DLSTACK_PROTO11 DLSTACK_PROTO10, DLSTACK_TYPE
+#define DLSTACK_PROTO12 DLSTACK_PROTO11, DLSTACK_TYPE
+#define DLSTACK_PROTO13 DLSTACK_PROTO12, DLSTACK_TYPE
+#define DLSTACK_PROTO14 DLSTACK_PROTO13, DLSTACK_TYPE
+#define DLSTACK_PROTO14 DLSTACK_PROTO13, DLSTACK_TYPE
+#define DLSTACK_PROTO15 DLSTACK_PROTO14, DLSTACK_TYPE
+#define DLSTACK_PROTO16 DLSTACK_PROTO15, DLSTACK_TYPE
+#define DLSTACK_PROTO17 DLSTACK_PROTO16, DLSTACK_TYPE
+#define DLSTACK_PROTO18 DLSTACK_PROTO17, DLSTACK_TYPE
+#define DLSTACK_PROTO19 DLSTACK_PROTO18, DLSTACK_TYPE
+#define DLSTACK_PROTO20 DLSTACK_PROTO19, DLSTACK_TYPE
+
+#define DLSTACK_ARGS0(stack)
+#define DLSTACK_ARGS1(stack) stack[0]
+#define DLSTACK_ARGS2(stack) DLSTACK_ARGS1(stack), stack[1]
+#define DLSTACK_ARGS3(stack) DLSTACK_ARGS2(stack), stack[2]
+#define DLSTACK_ARGS4(stack) DLSTACK_ARGS3(stack), stack[3]
+#define DLSTACK_ARGS5(stack) DLSTACK_ARGS4(stack), stack[4]
+#define DLSTACK_ARGS6(stack) DLSTACK_ARGS5(stack), stack[5]
+#define DLSTACK_ARGS7(stack) DLSTACK_ARGS6(stack), stack[6]
+#define DLSTACK_ARGS8(stack) DLSTACK_ARGS7(stack), stack[7]
+#define DLSTACK_ARGS9(stack) DLSTACK_ARGS8(stack), stack[8]
+#define DLSTACK_ARGS10(stack) DLSTACK_ARGS9(stack), stack[9]
+#define DLSTACK_ARGS11(stack) DLSTACK_ARGS10(stack), stack[10]
+#define DLSTACK_ARGS12(stack) DLSTACK_ARGS11(stack), stack[11]
+#define DLSTACK_ARGS13(stack) DLSTACK_ARGS12(stack), stack[12]
+#define DLSTACK_ARGS14(stack) DLSTACK_ARGS13(stack), stack[13]
+#define DLSTACK_ARGS15(stack) DLSTACK_ARGS14(stack), stack[14]
+#define DLSTACK_ARGS16(stack) DLSTACK_ARGS15(stack), stack[15]
+#define DLSTACK_ARGS17(stack) DLSTACK_ARGS16(stack), stack[16]
+#define DLSTACK_ARGS18(stack) DLSTACK_ARGS17(stack), stack[17]
+#define DLSTACK_ARGS19(stack) DLSTACK_ARGS18(stack), stack[18]
+#define DLSTACK_ARGS20(stack) DLSTACK_ARGS19(stack), stack[19]
+
+extern VALUE rb_mDL;
+extern VALUE rb_cDLHandle;
+extern VALUE rb_cDLSymbol;
+extern VALUE rb_eDLError;
+extern VALUE rb_eDLTypeError;
+
+typedef struct { char c; void *x; } s_voidp;
+typedef struct { char c; short x; } s_short;
+typedef struct { char c; int x; } s_int;
+typedef struct { char c; long x; } s_long;
+typedef struct { char c; float x; } s_float;
+typedef struct { char c; double x; } s_double;
+#if HAVE_LONG_LONG
+typedef struct { char c; LONG_LONG x; } s_long_long;
+#endif
+
+#define ALIGN_VOIDP  (sizeof(s_voidp) - sizeof(void *))
+#define ALIGN_SHORT  (sizeof(s_short) - sizeof(short))
+#define ALIGN_CHAR   (1)
+#define ALIGN_INT    (sizeof(s_int) - sizeof(int))
+#define ALIGN_LONG   (sizeof(s_long) - sizeof(long))
+#if HAVE_LONG_LONG
+#define ALIGN_LONG_LONG (sizeof(s_long_long) - sizeof(LONG_LONG))
+#endif
+#define ALIGN_FLOAT  (sizeof(s_float) - sizeof(float))
+#define ALIGN_DOUBLE (sizeof(s_double) - sizeof(double))
+
+#define DLALIGN(ptr,offset,align) {\
+  while( (((unsigned long)((char *)ptr + offset)) % align) != 0 ) offset++;\
+}
+
+
+#define DLTYPE_VOID  0
+#define DLTYPE_VOIDP 1
+#define DLTYPE_CHAR  2
+#define DLTYPE_SHORT 3
+#define DLTYPE_INT   4
+#define DLTYPE_LONG  5
+#if HAVE_LONG_LONG
+#define DLTYPE_LONG_LONG 6
+#endif
+#define DLTYPE_FLOAT 7
+#define DLTYPE_DOUBLE 8
+#define MAX_DLTYPE 9
+
+#if SIZEOF_VOIDP == SIZEOF_LONG
+# define PTR2NUM(x)   (ULONG2NUM((unsigned long)(x)))
+# define NUM2PTR(x)   ((void*)(NUM2ULONG(x)))
+#else
+/* # error --->> Ruby/DL2 requires sizeof(void*) == sizeof(long) to be compiled. <<--- */
+# define PTR2NUM(x)   (ULL2NUM((unsigned long long)(x)))
+# define NUM2PTR(x)   ((void*)(NUM2ULL(x)))
+#endif
+
+#define BOOL2INT(x)  ((x == Qtrue)?1:0)
+#define INT2BOOL(x)  (x?Qtrue:Qfalse)
+
+typedef void (*freefunc_t)(void*);
+
+struct dl_handle {
+    void *ptr;
+    int  open;
+    int  enable_close;
+};
+
+
+struct cfunc_data {
+    void *ptr;
+    char *name;
+    int  type;
+    ID   calltype;
+};
+extern ID rbdl_id_cdecl;
+extern ID rbdl_id_stdcall;
+#define CFUNC_CDECL   (rbdl_id_cdecl)
+#define CFUNC_STDCALL (rbdl_id_stdcall)
+
+struct ptr_data {
+    void *ptr;
+    long size;
+    freefunc_t free;
+};
+
+#define RDL_HANDLE(obj) ((struct dl_handle *)(DATA_PTR(obj)))
+#define RCFUNC_DATA(obj) ((struct cfunc_data *)(DATA_PTR(obj)))
+#define RPTR_DATA(obj) ((struct ptr_data *)(DATA_PTR(obj)))
+
+VALUE rb_dlcfunc_new(void (*func)(), int dltype, const char * name, ID calltype);
+VALUE rb_dlptr_new(void *ptr, long size, freefunc_t func);
+VALUE rb_dlptr_new2(VALUE klass, void *ptr, long size, freefunc_t func);
+VALUE rb_dlptr_malloc(long size, freefunc_t func);
+
+#endif

Added: trunk/ext/dl/extconf.rb
===================================================================
--- trunk/ext/dl/extconf.rb	2006-11-06 13:53:20 UTC (rev 575)
+++ trunk/ext/dl/extconf.rb	2006-11-07 04:23:15 UTC (rev 576)
@@ -0,0 +1,30 @@
+require 'mkmf'
+
+if( RbConfig::CONFIG['CC'] =~ /gcc/ )
+  $CFLAGS << " -fno-defer-pop -fno-omit-frame-pointer"
+end
+
+$INSTALLFILES = [
+  ["dl.h", "$(archdir)$(target_prefix)", ""],
+]
+$distcleanfiles << "callback.h"
+
+
+check = true
+if( have_header("dlfcn.h") )
+  have_library("dl")
+  check &&= have_func("dlopen")
+  check &&= have_func("dlclose")
+  check &&= have_func("dlsym")
+  have_func("dlerror")
+elsif( have_header("windows.h") )
+  check &&= have_func("LoadLibrary")
+  check &&= have_func("FreeLibrary")
+  check &&= have_func("GetProcAddress")
+else
+  check = false
+end
+
+if( check )
+  create_makefile("dl")
+end

Added: trunk/ext/dl/handle.c
===================================================================
--- trunk/ext/dl/handle.c	2006-11-06 13:53:20 UTC (rev 575)
+++ trunk/ext/dl/handle.c	2006-11-07 04:23:15 UTC (rev 576)
@@ -0,0 +1,227 @@
+/* -*- C -*-
+ * $Id: handle.c,v 1.20 2006/10/14 14:33:10 matz Exp $
+ */
+
+#include <ruby.h>
+#include "dl.h"
+
+VALUE rb_cDLHandle;
+
+void
+dlhandle_free(struct dl_handle *dlhandle)
+{
+  if( dlhandle->ptr && dlhandle->open && dlhandle->enable_close ){
+    dlclose(dlhandle->ptr);
+  }
+}
+
+VALUE
+rb_dlhandle_close(VALUE self)
+{
+  struct dl_handle *dlhandle;
+
+  Data_Get_Struct(self, struct dl_handle, dlhandle);
+  dlhandle->open = 0;
+  return INT2NUM(dlclose(dlhandle->ptr));
+}
+
+VALUE
+rb_dlhandle_s_allocate(VALUE klass)
+{
+  VALUE obj;
+  struct dl_handle *dlhandle;
+
+  obj = Data_Make_Struct(rb_cDLHandle, struct dl_handle, 0,
+			 dlhandle_free, dlhandle);
+  dlhandle->ptr  = 0;
+  dlhandle->open = 0;
+  dlhandle->enable_close = 0;
+
+  return obj;
+}
+
+VALUE
+rb_dlhandle_initialize(int argc, VALUE argv[], VALUE self)
+{
+  void *ptr;
+  struct dl_handle *dlhandle;
+  VALUE lib, flag;
+  char  *clib;
+  int   cflag;
+  const char *err;
+
+  switch( rb_scan_args(argc, argv, "02", &lib, &flag) ){
+  case 0:
+    clib = NULL;
+    cflag = RTLD_LAZY | RTLD_GLOBAL;
+    break;
+  case 1:
+    clib = NIL_P(lib) ? NULL : StringValuePtr(lib);
+    cflag = RTLD_LAZY | RTLD_GLOBAL;
+    break;
+  case 2:
+    clib = NIL_P(lib) ? NULL : StringValuePtr(lib);
+    cflag = NUM2INT(flag);
+    break;
+  default:
+    rb_bug("rb_dlhandle_new");
+  }
+
+  ptr = dlopen(clib, cflag);
+#if defined(HAVE_DLERROR)
+  if( !ptr && (err = dlerror()) ){
+    rb_raise(rb_eDLError, "%s", err);
+  }
+#else
+  if( !ptr ){
+    err = dlerror();
+    rb_raise(rb_eDLError, "%s", err);
+  }
+#endif
+  Data_Get_Struct(self, struct dl_handle, dlhandle);
+  if( dlhandle->ptr && dlhandle->open && dlhandle->enable_close ){
+    dlclose(dlhandle->ptr);
+  }
+  dlhandle->ptr = ptr;
+  dlhandle->open = 1;
+  dlhandle->enable_close = 0;
+
+  if( rb_block_given_p() ){
+    rb_ensure(rb_yield, self, rb_dlhandle_close, self);
+  }
+
+  return Qnil;
+}
+
+VALUE
+rb_dlhandle_enable_close(VALUE self)
+{
+  struct dl_handle *dlhandle;
+
+  Data_Get_Struct(self, struct dl_handle, dlhandle);
+  dlhandle->enable_close = 1;
+  return Qnil;
+}
+
+VALUE
+rb_dlhandle_disable_close(VALUE self)
+{
+  struct dl_handle *dlhandle;
+
+  Data_Get_Struct(self, struct dl_handle, dlhandle);
+  dlhandle->enable_close = 0;
+  return Qnil;
+}
+
+VALUE
+rb_dlhandle_to_i(VALUE self)
+{
+  struct dl_handle *dlhandle;
+
+  Data_Get_Struct(self, struct dl_handle, dlhandle);
+  return PTR2NUM(dlhandle);
+}
+
+VALUE
+rb_dlhandle_sym(VALUE self, VALUE sym)
+{
+    void (*func)();
+    struct dl_handle *dlhandle;
+    void *handle;
+    const char *name;
+    const char *err;
+    int i;
+
+#if defined(HAVE_DLERROR)
+# define CHECK_DLERROR if( err = dlerror() ){ func = 0; }
+#else
+# define CHECK_DLERROR
+#endif
+
+    rb_secure(2);
+
+    if( sym == Qnil ){
+#if defined(RTLD_NEXT)
+	name = RTLD_NEXT;
+#else
+	name = NULL;
+#endif
+    }
+    else{
+	name = StringValuePtr(sym);
+    }
+
+
+    Data_Get_Struct(self, struct dl_handle, dlhandle);
+    if( ! dlhandle->open ){
+	rb_raise(rb_eDLError, "closed handle");
+    }
+    handle = dlhandle->ptr;
+
+    func = dlsym(handle, name);
+    CHECK_DLERROR;
+    if( !func ){
+#if defined(__CYGWIN__) || defined(WIN32) || defined(__MINGW32__)
+	{
+	    int  len = strlen(name);
+	    char *name_a = (char*)xmalloc(len+2);
+	    strcpy(name_a, name);
+	    name_a[len]   = 'A';
+	    name_a[len+1] = '\0';
+	    func = dlsym(handle, name_a);
+	    xfree(name_a);
+	    CHECK_DLERROR;
+	    if( !func ){
+		for( i = 0; i < 256; i += 4 ){
+		    int  len = strlen(name);
+		    char *name_n = (char*)xmalloc(len+5);
+		    sprintf(name_n, "%s@%d%c", name, i, 0);
+		    func = dlsym(handle, name_n);
+		    xfree(name_n);
+		    CHECK_DLERROR;
+		    if( func )
+                    {
+			break;
+		    }
+		}
+		CHECK_DLERROR;
+		if( !func ){
+		    rb_raise(rb_eDLError, "unknown symbol \"%s\"", name);
+		}
+	    }
+	}
+#else
+	for( i = 0; i < 256; i += 4 ){
+	    int  len = strlen(name);
+	    char *name_n = (char*)xmalloc(len+4);
+	    sprintf(name_n, "%s@%d", name, i);
+	    func = dlsym(handle, name_n);
+	    xfree(name_n);
+	    CHECK_DLERROR;
+            if( func ){
+		break;
+	    }
+	}
+	CHECK_DLERROR;
+        if( !func ){
+	    rb_raise(rb_eDLError, "unknown symbol \"%s\"", name);
+	}
+#endif
+    }
+
+    return PTR2NUM(func);
+}
+
+void
+Init_dlhandle()
+{
+    rb_cDLHandle = rb_define_class_under(rb_mDL, "Handle", rb_cObject);
+    rb_define_alloc_func(rb_cDLHandle, rb_dlhandle_s_allocate);
+    rb_define_method(rb_cDLHandle, "initialize", rb_dlhandle_initialize, -1);
+    rb_define_method(rb_cDLHandle, "to_i", rb_dlhandle_to_i, 0);
+    rb_define_method(rb_cDLHandle, "close", rb_dlhandle_close, 0);
+    rb_define_method(rb_cDLHandle, "sym",  rb_dlhandle_sym, 1);
+    rb_define_method(rb_cDLHandle, "[]",  rb_dlhandle_sym,  1);
+    rb_define_method(rb_cDLHandle, "disable_close", rb_dlhandle_disable_close, 0);
+    rb_define_method(rb_cDLHandle, "enable_close", rb_dlhandle_enable_close, 0);
+}

Added: trunk/ext/dl/lib/dl/callback.rb
===================================================================
--- trunk/ext/dl/lib/dl/callback.rb	2006-11-06 13:53:20 UTC (rev 575)
+++ trunk/ext/dl/lib/dl/callback.rb	2006-11-07 04:23:15 UTC (rev 576)
@@ -0,0 +1,69 @@
+require 'dl'
+require 'thread'
+
+module DL
+  SEM = Mutex.new
+
+  def set_callback_internal(proc_entry, addr_entry, argc, ty, &cbp)
+    if( argc < 0 )
+      raise(ArgumentError, "arity should not be less than 0.")
+    end
+    addr = nil
+    SEM.synchronize{
+      ary = proc_entry[ty]
+      (0...MAX_CALLBACK).each{|n|
+        idx = (n * DLSTACK_SIZE) + argc
+        if( ary[idx].nil? )
+          ary[idx] = cbp
+          addr = addr_entry[ty][idx]
+          break
+        end
+      }
+    }
+    addr
+  end
+
+  def set_cdecl_callback(ty, argc, &cbp)
+    set_callback_internal(CdeclCallbackProcs, CdeclCallbackAddrs, argc, ty, &cbp)
+  end
+
+  def set_stdcall_callback(ty, argc, &cbp)
+    set_callback_internal(StdcallCallbackProcs, StdcallCallbackAddrs, argc, ty, &cbp)
+  end
+
+  def remove_callback_internal(proc_entry, addr_entry, addr, ctype = nil)
+    index = nil
+    if( ctype )
+      addr_entry[ctype].each_with_index{|xaddr, idx|
+        if( xaddr == addr )
+          index = idx
+        end
+      }
+    else
+      addr_entry.each{|ty,entry|
+        entry.each_with_index{|xaddr, idx|
+          if( xaddr == addr )
+            index = idx
+          end
+        }
+      }
+    end
+    if( proc_entry[ctype][index] )
+      proc_entry[ctype][index] = nil
+      return true
+    else
+      return false
+    end
+  end
+
+  def remove_cdecl_callback(addr, ctype = nil)
+    remove_callback_internal(CdeclCallbackProcs, CdeclCallbackAddrs, addr, ctype)
+  end
+
+  def remove_stdcall_callback(addr, ctype = nil)
+    remove_callback_internal(StdcallCallbackProcs, StdcallCallbackAddrs, addr, ctype)
+  end
+
+  alias set_callback set_cdecl_callback
+  alias remove_callback remove_cdecl_callback
+end

Added: trunk/ext/dl/lib/dl/cparser.rb
===================================================================
--- trunk/ext/dl/lib/dl/cparser.rb	2006-11-06 13:53:20 UTC (rev 575)
+++ trunk/ext/dl/lib/dl/cparser.rb	2006-11-07 04:23:15 UTC (rev 576)
@@ -0,0 +1,109 @@
+module DL
+  module CParser
+    def parse_struct_signature(signature, tymap=nil)
+      if( signature.is_a?(String) )
+        signature = signature.split("\s*,\s*")
+      end
+      mems = []
+      tys  = []
+      signature.each{|msig|
+        tks = msig.split(/\s+(\*)?/)
+        ty = tks[0..-2].join(" ")
+        member = tks[-1]
+
+        case ty
+        when /\[(\d+)\]/
+          n = $1.to_i
+          ty.gsub!(/\s*\[\d+\]/,"")
+          ty = [ty, n]
+        when /\[\]/
+          ty.gsub!(/\s*\[\]/, "*")
+        end
+
+        case member
+        when /\[(\d+)\]/
+          ty = [ty, $1.to_i]
+          member.gsub!(/\s*\[\d+\]/,"")
+        when /\[\]/
+          ty = ty + "*"
+          member.gsub!(/\s*\[\]/, "")
+        end
+
+        mems.push(member)
+        tys.push(parse_ctype(ty,tymap))
+      }
+      return tys, mems
+    end
+
+    def parse_signature(signature, tymap=nil)
+      tymap ||= {}
+      signature = signature.gsub(/\s+/, " ").strip
+      case signature
+      when /^([\d\w@\*_\s]+)\(([\d\w\*_\s\,\[\]]*)\)$/
+        ret = $1
+        args = $2
+        ret = ret.split(/\s+/)
+        args = args.split(/\s*,\s*/)
+        func = ret.pop
+        if( func =~ /^\*/ )
+          func.gsub!(/^\*+/,"")
+          ret.push("*")
+        end
+        ret  = ret.join(" ")
+        return [func, parse_ctype(ret, tymap), args.collect{|arg| parse_ctype(arg, tymap)}]
+      else
+        raise(RuntimeError,"can't parse the function prototype: #{proto}")
+      end
+    end
+
+    def parse_ctype(ty, tymap=nil)
+      tymap ||= {}
+      case ty
+      when Array
+        return [parse_ctype(ty[0], tymap), ty[1]]
+      when "void"
+        return TYPE_VOID
+      when "char"
+        return TYPE_CHAR
+      when "unsigned char"
+        return  -TYPE_CHAR
+      when "short"
+        return TYPE_SHORT
+      when "unsigned short"
+        return -TYPE_SHORT
+      when "int"
+        return TYPE_INT
+      when "unsigned int"
+        return -TYPE_INT
+      when "long"
+        return TYPE_LONG
+      when "unsigned long"
+        return -TYPE_LONG
+      when "long long"
+        if( defined?(TYPE_LONG_LONG) )
+          return TYPE_LONG_LONG
+        else
+          raise(RuntimeError, "unsupported type: #{ty}")
+        end
+      when "unsigned long long"
+        if( defined?(TYPE_LONG_LONG) )
+          return -TYPE_LONG_LONG
+        else
+          raise(RuntimeError, "unsupported type: #{ty}")
+        end
+      when "float"
+        return TYPE_FLOAT
+      when "double"
+        return TYPE_DOUBLE
+      when /\*/, /\[\s*\]/
+        return TYPE_VOIDP
+      else
+        if( tymap[ty] )
+          return parse_ctype(tymap[ty], tymap)
+        else
+          raise(DLError, "unknown type: #{ty}")
+        end
+      end
+    end
+  end
+end

Added: trunk/ext/dl/lib/dl/func.rb
===================================================================
--- trunk/ext/dl/lib/dl/func.rb	2006-11-06 13:53:20 UTC (rev 575)
+++ trunk/ext/dl/lib/dl/func.rb	2006-11-07 04:23:15 UTC (rev 576)
@@ -0,0 +1,141 @@
+require 'dl'
+require 'dl/callback'
+require 'dl/stack'
+require 'dl/value'
+require 'thread'
+
+module DL
+  class Function
+    include DL
+    include ValueUtil
+
+    def initialize(cfunc, argtypes, &proc)
+      @cfunc = cfunc
+      @stack = Stack.new(argtypes.collect{|ty| ty.abs})
+      if( @cfunc.ctype < 0 )
+        @cfunc.ctype = @cfunc.ctype.abs
+        @unsigned = true
+      end
+      if( proc )
+        bind(&proc)
+      end
+    end
+
+    def to_i()
+      @cfunc.to_i
+    end
+
+    def call(*args, &block)
+      funcs = []
+      args = wrap_args(args, @stack.types, funcs, &block)
+      r = @cfunc.call( stack.pack(args))
+      funcs.each{|f| f.unbind_at_call()}
+      return wrap_result(r)
+    end
+
+    def wrap_result(r)
+      case @cfunc.ctype
+      when TYPE_VOIDP
+        r = CPtr.new(r)
+      else
+        if( @unsigned )
+          r = unsigned_value(r, @cfunc.ctype)
+        end
+      end
+      r
+    end
+
+    def bind(&block)
+      if( !block )
+        raise(RuntimeError, "block must be given.")
+      end
+      if( @cfunc.ptr == 0 )
+        cb = Proc.new{|*args|
+          ary = @stack.unpack(args)
+          @stack.types.each_with_index{|ty, idx|
+            case ty
+            when TYPE_VOIDP
+              ary[idx] = CPtr.new(ary[idx])
+            end
+          }
+          r = block.call(*ary)
+          wrap_arg(r, @cfunc.ctype, [])
+        }
+        case @cfunc.calltype
+        when :cdecl
+          @cfunc.ptr = set_cdecl_callback( cfunc.ctype, @stack.size, &cb)
+        when :stdcall
+          @cfunc.ptr = set_stdcall_callback( cfunc.ctype, @stack.size, &cb)
+        else
+          raise(RuntimeError, "unsupported calltype: #{ cfunc.calltype}")
+        end
+        if( @cfunc.ptr == 0 )
+          raise(RuntimeException, "can't bind C function.")
+        end
+      end
+    end
+
+    def unbind()
+      if( @cfunc.ptr != 0 )
+        case @cfunc.calltype
+        when :cdecl
+          remove_cdecl_callback( cfunc.ptr, @cfunc.ctype)
+        when :stdcall
+          remove_stdcall_callback( cfunc.ptr, @cfunc.ctype)
+        else
+          raise(RuntimeError, "unsupported calltype: #{ cfunc.calltype}")
+        end
+        @cfunc.ptr = 0
+      end
+    end
+
+    def bind_at_call(&block)
+      bind(&block)
+    end
+
+    def unbind_at_call()
+    end
+  end
+
+  class TempFunction < Function
+    def bind_at_call(&block)
+      bind(&block)
+    end
+
+    def unbind_at_call()
+      unbind()
+    end
+  end
+
+  class CarriedFunction < Function
+    def initialize(cfunc, argtypes, n)
+      super(cfunc, argtypes)
+      @carrier = []
+      @index = n
+      @mutex = Mutex.new
+    end
+
+    def create_carrier(data)
+      ary = []
+      userdata = [ary, data]
+      @mutex.lock()
+      @carrier.push(userdata)
+      return dlwrap(userdata)
+    end
+
+    def bind_at_call(&block)
+      userdata = @carrier[-1]
+      userdata[0].push(block)
+      bind{|*args|
+        ptr = args[@index]
+        if( !ptr )
+          raise(RuntimeError, "The index of userdata should be lower than #{args.size}.")
+        end
+        userdata = dlunwrap(Integer(ptr))
+        args[@index] = userdata[1]
+        userdata[0][0].call(*args)
+      }
+      @mutex.unlock()
+    end
+  end
+end

Added: trunk/ext/dl/lib/dl/import.rb
===================================================================
--- trunk/ext/dl/lib/dl/import.rb	2006-11-06 13:53:20 UTC (rev 575)
+++ trunk/ext/dl/lib/dl/import.rb	2006-11-07 04:23:15 UTC (rev 576)
@@ -0,0 +1,215 @@
+require 'dl'
+require 'dl/func.rb'
+require 'dl/struct.rb'
+require 'dl/cparser.rb'
+
+module DL
+  class CompositeHandler
+    def initialize(handlers)
+      @handlers = handlers
+    end
+
+    def handlers()
+      @handlers
+    end
+
+    def sym(symbol)
+      @handlers.each{|handle|
+        if( handle )
+          begin
+            addr = handle.sym(symbol)
+            return addr
+          rescue DLError
+          end
+        end
+      }
+      return nil
+    end
+
+    def [](symbol)
+      sym(symbol)
+    end
+  end
+
+  module Importer
+    include DL
+    include CParser
+    extend Importer
+
+    def dlload(*libs)
+      handles = libs.collect{|lib|
+        case lib
+        when nil
+          nil
+        when Handle
+          lib
+        when Importer
+          lib.handlers
+        else
+          begin
+            DL.dlopen(lib)
+          rescue DLError
+            raise(DLError, "can't load #{lib}")
+          end
+        end
+      }.flatten()
+      @handler = CompositeHandler.new(handles)
+      @func_map = {}
+      @type_alias = {}
+    end
+
+    def typealias(alias_type, orig_type)
+      @type_alias[alias_type] = orig_type
+    end
+
+    def sizeof(ty)
+      case ty
+      when String
+        ty = parse_ctype(ty, @type_alias).abs()
+        case ty
+        when TYPE_CHAR
+          return SIZEOF_CHAR
+        when TYPE_SHORT
+          return SIZEOF_SHORT
+        when TYPE_INT
+          return SIZEOF_INT
+        when TYPE_LONG
+          return SIZEOF_LONG
+        when TYPE_LONG_LONG
+          return SIZEOF_LONG_LON
+        when TYPE_FLOAT
+          return SIZEOF_FLOAT
+        when TYPE_DOUBLE
+          return SIZEOF_DOUBLE
+        when TYPE_VOIDP
+          return SIZEOF_VOIDP
+        else
+          raise(DLError, "unknown type: #{ty}")
+        end
+      when Class
+        if( ty.instance_methods().include?("to_ptr") )
+          return ty.size()
+        end
+      end
+      return CPtr[ty].size()
+    end
+
+    def parse_bind_options(opts)
+      h = {}
+      prekey = nil
+      while( opt = opts.shift() )
+        case opt
+        when :stdcall, :cdecl
+          h[:call_type] = opt
+        when :carried, :temp, :temporal, :bind
+          h[:callback_type] = opt
+          h[:carrier] = opts.shift()
+        else
+          h[opt] = true
+        end
+      end
+      h
+    end
+    private :parse_bind_options
+
+    def extern(signature, *opts)
+      symname, ctype, argtype = parse_signature(signature, @type_alias)
+      opt = parse_bind_options(opts)
+      f = import_function(symname, ctype, argtype, opt[:call_type])
+      name = symname.gsub(/@.+/,'')
+      @func_map[name] = f
+      # define_method(name){|*args,&block| f.call(*args,&block)}
+      module_eval(<<-EOS)
+        def #{name}(*args, &block)
+          @func_map['#{name}'].call(*args,&block)
+        end
+      EOS
+      module_function(name)
+      f
+    end
+
+    def bind(signature, *opts, &blk)
+      name, ctype, argtype = parse_signature(signature, @type_alias)
+      h = parse_bind_options(opts)
+      case h[:callback_type]
+      when :bind, nil
+        f = bind_function(name, ctype, argtype, h[:call_type], &blk)
+      when :temp, :temporal
+        f = create_temp_function(name, ctype, argtype, h[:call_type])
+      when :carried
+        f = create_carried_function(name, ctype, argtype, h[:call_type], h[:carrier])
+      else
+        raise(RuntimeError, "unknown callback type: #{h[:callback_type]}")
+      end
+      @func_map[name] = f
+      #define_method(name){|*args,&block| f.call(*args,&block)}
+      module_eval(<<-EOS)
+        def #{name}(*args,&block)
+          @func_map['#{name}'].call(*args,&block)
+        end
+      EOS
+      module_function(name)
+      f
+    end
+
+    def struct(signature)
+      tys, mems = parse_struct_signature(signature, @type_alias)
+      DL::CStructBuilder.create(CStruct, tys, mems)
+    end
+
+    def union(signature)
+      tys, mems = parse_struct_signature(signature, @type_alias)
+      DL::CStructBuilder.create(CUnion, tys, mems)
+    end
+
+    def [](name)
+      @func_map[name]
+    end
+
+    def create_value(ty, val=nil)
+      s = struct([ty + " value"])
+      ptr = s.malloc()
+      if( val )
+        ptr.value = val
+      end
+      return ptr
+    end
+    alias value create_value
+
+    def import_value(ty, addr)
+      s = struct([ty + " value"])
+      ptr = s.new(addr)
+      return ptr
+    end
+
+    def import_symbol(name)
+      addr = @handler.sym(name)
+      if( !addr )
+        raise(DLError, "cannot find the symbol: #{name}")
+      end
+      CPtr.new(addr)
+    end
+
+    def import_function(name, ctype, argtype, call_type = nil)
+      addr = @handler.sym(name)
+      if( !addr )
+        raise(DLError, "cannot find the function: #{name}()")
+      end
+      Function.new(CFunc.new(addr, ctype, name, call_type || :cdecl), argtype)
+    end
+
+    def bind_function(name, ctype, argtype, call_type = nil, &block)
+      f = Function.new(CFunc.new(0, ctype, name, call_type || :cdecl), argtype)
+      f.bind(&block)
+      f
+    end
+
+    def create_temp_function(name, ctype, argtype, call_type = nil)
+      TempFunction.new(CFunc.new(0, ctype, name, call_type || :cdecl), argtype)
+    end
+
+    def create_carried_function(name, ctype, argtype, call_type = nil, n = 0)
+      CarriedFunction.new(CFunc.new(0, ctype, name, call_type || :cdecl), argtype, n)
+    end
+  end
+end

Added: trunk/ext/dl/lib/dl/pack.rb
===================================================================
--- trunk/ext/dl/lib/dl/pack.rb	2006-11-06 13:53:20 UTC (rev 575)
+++ trunk/ext/dl/lib/dl/pack.rb	2006-11-07 04:23:15 UTC (rev 576)
@@ -0,0 +1,173 @@
+require 'dl'
+
+module DL
+  module PackInfo
+    if( defined?(TYPE_LONG_LONG) )
+    ALIGN_MAP = {
+      TYPE_VOIDP => ALIGN_VOIDP,
+      TYPE_CHAR  => ALIGN_CHAR,
+      TYPE_SHORT => ALIGN_SHORT,
+      TYPE_INT   => ALIGN_INT,
+      TYPE_LONG  => ALIGN_LONG,
+      TYPE_LONG_LONG => ALIGN_LONG_LONG,
+      TYPE_FLOAT => ALIGN_FLOAT,
+      TYPE_DOUBLE => ALIGN_DOUBLE,
+      -TYPE_CHAR  => ALIGN_CHAR,
+      -TYPE_SHORT => ALIGN_SHORT,
+      -TYPE_INT   => ALIGN_INT,
+      -TYPE_LONG  => ALIGN_LONG,
+      -TYPE_LONG_LONG => ALIGN_LONG_LONG,
+    }
+
+    PACK_MAP = {
+      TYPE_VOIDP => ((SIZEOF_VOIDP == SIZEOF_LONG_LONG) ? "q" : "l!"),
+      TYPE_CHAR  => "c",
+      TYPE_SHORT => "s!",
+      TYPE_INT   => "i!",
+      TYPE_LONG  => "l!",
+      TYPE_LONG_LONG => "q",
+      TYPE_FLOAT => "f",
+      TYPE_DOUBLE => "d",
+      -TYPE_CHAR  => "c",
+      -TYPE_SHORT => "s!",
+      -TYPE_INT   => "i!",
+      -TYPE_LONG  => "l!",
+      -TYPE_LONG_LONG => "q",
+    }
+
+    SIZE_MAP = {
+      TYPE_VOIDP => SIZEOF_VOIDP,
+      TYPE_CHAR  => SIZEOF_CHAR,
+      TYPE_SHORT => SIZEOF_SHORT,
+      TYPE_INT   => SIZEOF_INT,
+      TYPE_LONG  => SIZEOF_LONG,
+      TYPE_LONG_LONG => SIZEOF_LONG_LONG,
+      TYPE_FLOAT => SIZEOF_FLOAT,
+      TYPE_DOUBLE => SIZEOF_DOUBLE,
+      -TYPE_CHAR  => SIZEOF_CHAR,
+      -TYPE_SHORT => SIZEOF_SHORT,
+      -TYPE_INT   => SIZEOF_INT,
+      -TYPE_LONG  => SIZEOF_LONG,
+      -TYPE_LONG_LONG => SIZEOF_LONG_LONG,
+    }
+    else
+    ALIGN_MAP = {
+      TYPE_VOIDP => ALIGN_VOIDP,
+      TYPE_CHAR  => ALIGN_CHAR,
+      TYPE_SHORT => ALIGN_SHORT,
+      TYPE_INT   => ALIGN_INT,
+      TYPE_LONG  => ALIGN_LONG,
+      TYPE_FLOAT => ALIGN_FLOAT,
+      TYPE_DOUBLE => ALIGN_DOUBLE,
+      -TYPE_CHAR  => ALIGN_CHAR,
+      -TYPE_SHORT => ALIGN_SHORT,
+      -TYPE_INT   => ALIGN_INT,
+      -TYPE_LONG  => ALIGN_LONG,
+    }
+
+    PACK_MAP = {
+      TYPE_VOIDP => ((SIZEOF_VOIDP == SIZEOF_LONG_LONG) ? "q" : "l!"),
+      TYPE_CHAR  => "c",
+      TYPE_SHORT => "s!",
+      TYPE_INT   => "i!",
+      TYPE_LONG  => "l!",
+      TYPE_FLOAT => "f",
+      TYPE_DOUBLE => "d",
+      -TYPE_CHAR  => "c",
+      -TYPE_SHORT => "s!",
+      -TYPE_INT   => "i!",
+      -TYPE_LONG  => "l!",
+    }
+
+    SIZE_MAP = {
+      TYPE_VOIDP => SIZEOF_VOIDP,
+      TYPE_CHAR  => SIZEOF_CHAR,
+      TYPE_SHORT => SIZEOF_SHORT,
+      TYPE_INT   => SIZEOF_INT,
+      TYPE_LONG  => SIZEOF_LONG,
+      TYPE_FLOAT => SIZEOF_FLOAT,
+      TYPE_DOUBLE => SIZEOF_DOUBLE,
+      -TYPE_CHAR  => SIZEOF_CHAR,
+      -TYPE_SHORT => SIZEOF_SHORT,
+      -TYPE_INT   => SIZEOF_INT,
+      -TYPE_LONG  => SIZEOF_LONG,
+    }
+    end
+
+    def align(addr, align)
+      d = addr % align
+      if( d == 0 )
+        addr
+      else
+        addr + (align - d)
+      end
+    end
+    module_function :align
+  end
+
+  class Packer
+    include PackInfo
+
+    def Packer.[](*types)
+      Packer.new(types)
+    end
+
+    def initialize(types)
+      parse_types(types)
+    end
+
+    def size()
+      @size
+    end
+    
+    def pack(ary)
+      case SIZEOF_VOIDP
+      when SIZEOF_LONG
+        ary.pack(@template)
+      when SIZEOF_LONG
+        ary.pack(@template)
+      else
+        raise(RuntimeError, "sizeof(void*)?")
+      end
+    end
+
+    def unpack(ary)
+      case SIZEOF_VOIDP
+      when SIZEOF_LONG
+        ary.join().unpack(@template)
+      when SIZEOF_LONG_LONG
+        ary.join().unpack(@template)
+      else
+        raise(RuntimeError, "sizeof(void*)?")
+      end
+    end
+    
+    private
+    
+    def parse_types(types)
+      @template = ""
+      addr     = 0
+      types.each{|t|
+        orig_addr = addr
+        if( t.is_a?(Array) )
+          addr = align(orig_addr, ALIGN_MAP[TYPE_VOIDP])
+        else
+          addr = align(orig_addr, ALIGN_MAP[t])
+        end
+        d = addr - orig_addr
+        if( d > 0 )
+          @template << "x#{d}"
+        end
+        if( t.is_a?(Array) )
+          @template << (PACK_MAP[t[0]] * t[1])
+          addr += (SIZE_MAP[t[0]] * t[1])
+        else
+          @template << PACK_MAP[t]
+          addr += SIZE_MAP[t]
+        end
+      }
+      addr = align(addr, ALIGN_MAP[TYPE_VOIDP])
+      @size = addr
+    end
+  end
+end

Added: trunk/ext/dl/lib/dl/stack.rb
===================================================================
--- trunk/ext/dl/lib/dl/stack.rb	2006-11-06 13:53:20 UTC (rev 575)
+++ trunk/ext/dl/lib/dl/stack.rb	2006-11-07 04:23:15 UTC (rev 576)
@@ -0,0 +1,140 @@
+require 'dl'
+
+module DL
+  class Stack
+    def Stack.[](*types)
+      Stack.new(types)
+    end
+
+    def initialize(types)
+      parse_types(types)
+    end
+
+    def size()
+      @size
+    end
+
+    def types()
+      @types
+    end
+
+    def pack(ary)
+      case SIZEOF_VOIDP
+      when SIZEOF_LONG
+        ary.pack( template).unpack('l!*')
+      when SIZEOF_LONG_LONG
+        ary.pack( template).unpack('q*')
+      else
+        raise(RuntimeError, "sizeof(void*)?")
+      end
+    end
+
+    def unpack(ary)
+      case SIZEOF_VOIDP
+      when SIZEOF_LONG
+        ary.pack('l!*').unpack(@template)
+      when SIZEOF_LONG_LONG
+        ary.pack('q*').unpack(@template)
+      else
+        raise(RuntimeError, "sizeof(void*)?")
+      end
+    end
+    
+    private
+    
+    def align(addr, align)
+      d = addr % align
+      if( d == 0 )
+        addr
+      else
+        addr + (align - d)
+      end
+    end
+
+if( defined?(TYPE_LONG_LONG) )
+    ALIGN_MAP = {
+      TYPE_VOIDP => ALIGN_VOIDP,
+      TYPE_CHAR  => ALIGN_VOIDP,
+      TYPE_SHORT => ALIGN_VOIDP,
+      TYPE_INT   => ALIGN_VOIDP,
+      TYPE_LONG  => ALIGN_VOIDP,
+      TYPE_LONG_LONG => ALIGN_LONG_LONG,
+      TYPE_FLOAT => ALIGN_FLOAT,
+      TYPE_DOUBLE => ALIGN_DOUBLE,
+    }
+
+    PACK_MAP = {
+      TYPE_VOIDP => ((SIZEOF_VOIDP == SIZEOF_LONG_LONG)? "q" : "l!"),
+      TYPE_CHAR  => "c",
+      TYPE_SHORT => "s!",
+      TYPE_INT   => "i!",
+      TYPE_LONG  => "l!",
+      TYPE_LONG_LONG => "q",
+      TYPE_FLOAT => "f",
+      TYPE_DOUBLE => "d",
+    }
+
+    SIZE_MAP = {
+      TYPE_VOIDP => SIZEOF_VOIDP,
+      TYPE_CHAR  => SIZEOF_CHAR,
+      TYPE_SHORT => SIZEOF_SHORT,
+      TYPE_INT   => SIZEOF_INT,
+      TYPE_LONG  => SIZEOF_LONG,
+      TYPE_LONG_LONG => SIZEOF_LONG_LONG,
+      TYPE_FLOAT => SIZEOF_FLOAT,
+      TYPE_DOUBLE => SIZEOF_DOUBLE,
+    }
+else
+    ALIGN_MAP = {
+      TYPE_VOIDP => ALIGN_VOIDP,
+      TYPE_CHAR  => ALIGN_VOIDP,
+      TYPE_SHORT => ALIGN_VOIDP,
+      TYPE_INT   => ALIGN_VOIDP,
+      TYPE_LONG  => ALIGN_VOIDP,
+      TYPE_FLOAT => ALIGN_FLOAT,
+      TYPE_DOUBLE => ALIGN_DOUBLE,
+    }
+
+    PACK_MAP = {
+      TYPE_VOIDP => ((SIZEOF_VOIDP == SIZEOF_LONG_LONG)? "q" : "l!"),
+      TYPE_CHAR  => "c",
+      TYPE_SHORT => "s!",
+      TYPE_INT   => "i!",
+      TYPE_LONG  => "l!",
+      TYPE_FLOAT => "f",
+      TYPE_DOUBLE => "d",
+    }
+
+    SIZE_MAP = {
+      TYPE_VOIDP => SIZEOF_VOIDP,
+      TYPE_CHAR  => SIZEOF_CHAR,
+      TYPE_SHORT => SIZEOF_SHORT,
+      TYPE_INT   => SIZEOF_INT,
+      TYPE_LONG  => SIZEOF_LONG,
+      TYPE_FLOAT => SIZEOF_FLOAT,
+      TYPE_DOUBLE => SIZEOF_DOUBLE,
+    }
+end
+
+    def parse_types(types)
+      @types = types
+      @template = ""
+      addr      = 0
+      types.each{|t|
+        orig_addr = addr
+        addr = align(orig_addr, ALIGN_MAP[t])
+        d = addr - orig_addr
+        if( d > 0 )
+          @template << "x#{d}"
+        end
+        @template << PACK_MAP[t]
+        addr += SIZE_MAP[t]
+      }
+      if( addr % SIZEOF_VOIDP == 0 )
+        @size = addr / SIZEOF_VOIDP
+      else
+        @size = (addr / SIZEOF_VOIDP) + 1
+      end
+    end
+  end
+end

Added: trunk/ext/dl/lib/dl/struct.rb
===================================================================
--- trunk/ext/dl/lib/dl/struct.rb	2006-11-06 13:53:20 UTC (rev 575)
+++ trunk/ext/dl/lib/dl/struct.rb	2006-11-07 04:23:15 UTC (rev 576)
@@ -0,0 +1,213 @@
+require 'dl'
+require 'dl/pack.rb'
+
+module DL
+  class CStruct
+    def CStruct.entity_class()
+      CStructEntity
+    end
+  end
+
+  class CUnion
+    def CUnion.entity_class()
+      CUnionEntity
+    end
+  end
+
+  module CStructBuilder
+    def create(klass, types, members)
+      new_class = Class.new(klass){
+        define_method(:initialize){|addr|
+          @entity = klass.entity_class.new(addr, types)
+          @entity.assign_names(members)
+        }
+        define_method(:to_ptr){ @entity }
+        define_method(:to_i){ @entity.to_i }
+        members.each{|name|
+          define_method(name){ @entity[name] }
+          define_method(name + "="){|val| @entity[name] = val }
+        }
+      }
+      size = klass.entity_class.size(types)
+      new_class.module_eval(<<-EOS)
+        def new_class.size()
+          #{size}
+        end
+        def new_class.malloc()
+          addr = DL.malloc(#{size})
+          new(addr)
+        end
+      EOS
+      return new_class
+    end
+    module_function :create
+  end
+
+  class CStructEntity < CPtr
+    include PackInfo
+    include ValueUtil
+
+    def CStructEntity.malloc(types, func = nil)
+      addr = DL.malloc(CStructEntity.size(types))
+      CStructEntity.new(addr, types, func)
+    end
+
+    def CStructEntity.size(types)
+      offset = 0
+      max_align = 0
+      types.each_with_index{|t,i|
+        orig_offset = offset
+        if( t.is_a?(Array) )
+          align = PackInfo::ALIGN_MAP[t[0]]
+          offset = PackInfo.align(orig_offset, align)
+          size = offset - orig_offset
+          offset += (PackInfo::SIZE_MAP[t[0]] * t[1])
+        else
+          align = PackInfo::ALIGN_MAP[t]
+          offset = PackInfo.align(orig_offset, align)
+          size = offset - orig_offset
+          offset += PackInfo::SIZE_MAP[t]
+        end
+        if (max_align < align)
+          max_align = align
+        end
+      }
+      offset = PackInfo.align(offset, max_align)
+      offset
+    end
+
+    def initialize(addr, types, func = nil)
+      set_ctypes(types)
+      super(addr, @size, func)
+    end
+
+    def assign_names(members)
+      @members = members
+    end
+
+    def set_ctypes(types)
+      @ctypes = types
+      @offset = []
+      offset = 0
+      max_align = 0
+      types.each_with_index{|t,i|
+        orig_offset = offset
+        if( t.is_a?(Array) )
+          align = ALIGN_MAP[t[0]]
+        else
+          align = ALIGN_MAP[t]
+        end
+        offset = PackInfo.align(orig_offset, align)
+        size = offset - orig_offset
+        @offset[i] = offset
+        if( t.is_a?(Array) )
+          offset += (SIZE_MAP[t[0]] * t[1])
+        else
+          offset += SIZE_MAP[t]
+        end
+        if (max_align < align)
+          max_align = align
+        end
+      }
+      offset = PackInfo.align(offset, max_align)
+      @size = offset
+    end
+
+    def [](name)
+      idx = @members.index(name)
+      if( idx.nil? )
+        raise(ArgumentError, "no such member: #{name}")
+      end
+      ty = @ctypes[idx]
+      if( ty.is_a?(Array) )
+        r = super(@offset[idx], SIZE_MAP[ty[0]] * ty[1])
+      else
+        r = super(@offset[idx], SIZE_MAP[ty.abs])
+      end
+      packer = Packer.new([ty])
+      val = packer.unpack([r])
+      case ty
+      when Array
+        case ty[0]
+        when TYPE_VOIDP
+          val = val.collect{|v| CPtr.new(v)}
+        end
+      when TYPE_VOIDP
+        val = CPtr.new(val[0])
+      else
+        val = val[0]
+      end
+      if( ty.is_a?(Integer) && (ty < 0) )
+        return unsigned_value(val, ty)
+      elsif( ty.is_a?(Array) && (ty[0] < 0) )
+        return val.collect{|v| unsigned_value(v,ty[0])}
+      else
+        return val
+      end
+    end
+
+    def []=(name, val)
+      idx = @members.index(name)
+      if( idx.nil? )
+        raise(ArgumentError, "no such member: #{name}")
+      end
+      ty  = @ctypes[idx]
+      packer = Packer.new([ty])
+      val = wrap_arg(val, ty, [])
+      buff = packer.pack([val].flatten())
+      super(@offset[idx], buff.size, buff)
+      if( ty.is_a?(Integer) && (ty < 0) )
+        return unsigned_value(val, ty)
+      elsif( ty.is_a?(Array) && (ty[0] < 0) )
+        return val.collect{|v| unsigned_value(v,ty[0])}
+      else
+        return val
+      end
+    end
+
+    def to_s()
+      super(@size)
+    end
+  end
+
+  class CUnionEntity < CStructEntity
+    include PackInfo
+
+    def CUnionEntity.malloc(types, func=nil)
+      addr = DL.malloc(CUnionEntity.size(types))
+      CUnionEntity.new(addr, types, func)
+    end
+
+    def CUnionEntity.size(types)
+      size   = 0
+      types.each_with_index{|t,i|
+        if( t.is_a?(Array) )
+          tsize = PackInfo::SIZE_MAP[t[0]] * t[1]
+        else
+          tsize = PackInfo::SIZE_MAP[t]
+        end
+        if( tsize > size )
+          size = tsize
+        end
+      }
+    end
+
+    def set_ctypes(types)
+      @ctypes = types
+      @offset = []
+      @size   = 0
+      types.each_with_index{|t,i|
+        @offset[i] = 0
+        if( t.is_a?(Array) )
+          size = SIZE_MAP[t[0]] * t[1]
+        else
+          size = SIZE_MAP[t]
+        end
+        if( size > @size )
+          @size = size
+        end
+      }
+    end
+  end
+end
+

Added: trunk/ext/dl/lib/dl/types.rb
===================================================================
--- trunk/ext/dl/lib/dl/types.rb	2006-11-06 13:53:20 UTC (rev 575)
+++ trunk/ext/dl/lib/dl/types.rb	2006-11-07 04:23:15 UTC (rev 576)
@@ -0,0 +1,40 @@
+module DL
+  module Win32Types
+    def included(m)
+      m.module_eval{
+        typealias "DWORD", "unsigned long"
+        typealias "PDWORD", "unsigned long *"
+        typealias "WORD", "unsigned short"
+        typealias "PWORD", "unsigned short *"
+        typealias "BOOL", "int"
+        typealias "ATOM", "int"
+        typealias "BYTE", "unsigned char"
+        typealias "PBYTE", "unsigned char *"
+        typealias "UINT", "unsigned int"
+        typealias "ULONG", "unsigned long"
+        typealias "UCHAR", "unsigned char"
+        typealias "HANDLE", "unsigned long"
+        typealias "PHANDLE", "void*"
+        typealias "PVOID", "void*"
+        typealias "LPCSTR", "char*"
+        typealias "LPSTR", "char*"
+        typealias "HINSTANCE", "unsigned int"
+        typealias "HDC", "unsigned int"
+        typealias "HWND", "unsigned int"
+      }
+    end
+    module_function :included
+  end
+
+  module BasicTypes
+    def included(m)
+      m.module_eval{
+        typealias "uint", "unsigned int"
+        typealias "u_int", "unsigned int"
+        typealias "ulong", "unsigned long"
+        typealias "u_long", "unsigned long"
+      }
+    end
+    module_function :included
+  end
+end

Added: trunk/ext/dl/lib/dl/value.rb
===================================================================
--- trunk/ext/dl/lib/dl/value.rb	2006-11-06 13:53:20 UTC (rev 575)
+++ trunk/ext/dl/lib/dl/value.rb	2006-11-07 04:23:15 UTC (rev 576)
@@ -0,0 +1,108 @@
+require 'dl'
+
+module DL
+  module ValueUtil
+    def unsigned_value(val, ty)
+      case ty.abs
+      when TYPE_CHAR
+        [val].pack("c").unpack("C")[0]
+      when TYPE_SHORT
+        [val].pack("s!").unpack("S!")[0]
+      when TYPE_INT
+        [val].pack("i!").unpack("I!")[0]
+      when TYPE_LONG
+        [val].pack("l!").unpack("L!")[0]
+      when TYPE_LONG_LONG
+        [val].pack("q!").unpack("Q!")[0]
+      else
+        val
+      end
+    end
+
+    def signed_value(val, ty)
+      case ty.abs
+      when TYPE_CHAR
+        [val].pack("C").unpack("c")[0]
+      when TYPE_SHORT
+        [val].pack("S!").unpack("s!")[0]
+      when TYPE_INT
+        [val].pack("I!").unpack("i!")[0]
+      when TYPE_LONG
+        [val].pack("L!").unpack("l!")[0]
+      when TYPE_LONG_LONG
+        [val].pack("Q!").unpack("q!")[0]
+      else
+        val
+      end
+    end
+
+    def wrap_args(args, tys, funcs, &block)
+      result = []
+      tys ||= []
+      args.each_with_index{|arg, idx|
+        result.push(wrap_arg(arg, tys[idx], funcs, &block))
+      }
+      result
+    end
+
+    def wrap_arg(arg, ty, funcs, &block)
+        funcs ||= []
+        case arg
+        when CPtr
+          return arg.to_i
+        when IO
+          case ty
+          when TYPE_VOIDP
+            return CPtr[arg].to_i
+          else
+            return arg.to_i
+          end
+        when Function
+          if( block )
+            arg.bind_at_call(&block)
+            funcs.push(arg)
+          end
+          return arg.to_i
+        when String
+          if( ty.is_a?(Array) )
+            return arg.unpack('C*')
+          else
+            case SIZEOF_VOIDP
+            when SIZEOF_LONG
+              return [arg].pack("p").unpack("l!")[0]
+            when SIZEOF_LONG_LONG
+              return [arg].pack("p").unpack("q")[0]
+            else
+              raise(RuntimeError, "sizeof(void*)?")
+            end
+          end
+        when Float, Integer
+          return arg
+        when Array
+          if( ty.is_a?(Array) ) # used only by struct
+            case ty[0]
+            when TYPE_VOIDP
+              return arg.collect{|v| Integer(v)}
+            when TYPE_CHAR
+              if( arg.is_a?(String) )
+                return val.unpack('C*')
+              end
+            end
+            return arg
+          else
+            return arg
+          end
+        else
+          if( arg.respond_to?(:to_ptr) )
+            return arg.to_ptr.to_i
+          else
+            begin
+              return Integer(arg)
+            rescue
+              raise(ArgumentError, "unknown argument type: #{arg.class}")
+            end
+          end
+        end
+    end
+  end
+end

Added: trunk/ext/dl/mkcallback.rb
===================================================================
--- trunk/ext/dl/mkcallback.rb	2006-11-06 13:53:20 UTC (rev 575)
+++ trunk/ext/dl/mkcallback.rb	2006-11-07 04:23:15 UTC (rev 576)
@@ -0,0 +1,189 @@
+$out  ||= $stdout
+$dl_h = ARGV[0] || "dl.h"
+
+# import DLSTACK_SIZE, DLSTACK_ARGS and so on
+File.open($dl_h){|f|
+  pre = ""
+  f.each{|line|
+    line.chop!
+    if( line[-1] == ?\ )
+      line.chop!
+      line.concat(" ")
+      pre += line
+      next
+    end
+    if( pre.size > 0 )
+      line = pre + line
+      pre  = ""
+    end
+    case line
+    when /#define\s+DLSTACK_SIZE\s+\(?(\d+)\)?/
+      DLSTACK_SIZE = $1.to_i
+    when /#define\s+DLSTACK_ARGS\s+(.+)/
+      DLSTACK_ARGS = $1.to_i
+    when /#define\s+DLTYPE_([A-Z_]+)\s+\(?(\d+)\)?/
+      eval("#{$1} = #{$2}")
+    when /#define\s+MAX_DLTYPE\s+\(?(\d+)\)?/
+      MAX_DLTYPE  = $1.to_i
+    when /#define\s+MAX_CALLBACK\s+\(?(\d+)\)?/
+      MAX_CALLBACK = $1.to_i
+    end
+  }
+}
+
+CDECL = "cdecl"
+STDCALL = "stdcall"
+
+CALLTYPES = [CDECL, STDCALL]
+
+DLTYPE = {
+  VOID => {
+    :name => 'void',
+    :type => 'void',
+    :conv => nil,
+  },
+  CHAR => {
+    :name => 'char',
+    :type => 'char',
+    :conv => 'NUM2CHR(%s)'
+  },
+  SHORT => {
+    :name => 'short',
+    :type => 'short',
+    :conv => 'NUM2INT(%s)',
+  },
+  INT => {
+    :name => 'int',
+    :type => 'int',
+    :conv => 'NUM2INT(%s)',
+  },
+  LONG  => {
+    :name => 'long',
+    :type => 'long',
+    :conv => 'NUM2LONG(%s)',
+  },
+  LONG_LONG => {
+    :name => 'long_long',
+    :type => 'LONG_LONG',
+    :conv => 'NUM2LL(%s)',
+  },
+  FLOAT => {
+    :name => 'float',
+    :type => 'float',
+    :conv => 'RFLOAT(%s)->value',
+  },
+  DOUBLE => {
+    :name => 'double',
+    :type => 'double',
+    :conv => 'RFLOAT(%s)->value',
+  },
+  VOIDP => {
+    :name => 'ptr',
+    :type => 'void *',
+    :conv => 'NUM2PTR(%s)',
+  },
+}
+
+
+def func_name(ty, argc, n, calltype)
+  "rb_dl_callback_#{DLTYPE[ty][:name]}_#{argc}_#{n}_#{calltype}"
+end
+
+$out << (<<EOS)
+VALUE rb_DLCdeclCallbackAddrs, rb_DLCdeclCallbackProcs;
+VALUE rb_DLStdcallCallbackAddrs, rb_DLStdcallCallbackProcs;
+/*static void *cdecl_callbacks[MAX_DLTYPE][MAX_CALLBACK];*/
+/*static void *stdcall_callbacks[MAX_DLTYPE][MAX_CALLBACK];*/
+static ID   cb_call;
+EOS
+
+for calltype in CALLTYPES
+  case calltype
+  when CDECL
+    proc_entry = "rb_DLCdeclCallbackProcs"
+  when STDCALL
+    proc_entry = "rb_DLStdcallCallbackProcs"
+  else
+    raise "unknown calltype: #{calltype}"
+  end
+  for ty in 0..(MAX_DLTYPE-1)
+    for argc in 0..(DLSTACK_SIZE-1)
+      for n in 0..(MAX_CALLBACK-1)
+        $out << (<<-EOS)
+
+static #{DLTYPE[ty][:type]}
+FUNC_#{calltype.upcase}(#{func_name(ty,argc,n,calltype)})(#{(0...argc).collect{|i| "DLSTACK_TYPE stack" + i.to_s}.join(", ")})
+{
+    VALUE ret, cb#{argc > 0 ? ", args[#{argc}]" : ""};
+#{
+      (0...argc).collect{|i|
+	"    args[%d] = LONG2NUM(stack%d);" % [i,i]
+      }.join("\n")
+}
+    cb = rb_ary_entry(rb_ary_entry(#{proc_entry}, #{ty}), #{(n * DLSTACK_SIZE) + argc});
+    ret = rb_funcall2(cb, cb_call, #{argc}, #{argc > 0 ? 'args' : 'NULL'});
+    return #{DLTYPE[ty][:conv] ? DLTYPE[ty][:conv] % "ret" : ""};
+}
+
+        EOS
+      end
+    end
+  end
+end
+
+$out << (<<EOS)
+static void
+rb_dl_init_callbacks()
+{
+    cb_call = rb_intern("call");		       
+
+    rb_DLCdeclCallbackProcs = rb_ary_new();
+    rb_DLCdeclCallbackAddrs = rb_ary_new();
+    rb_DLStdcallCallbackProcs = rb_ary_new();
+    rb_DLStdcallCallbackAddrs = rb_ary_new();
+    rb_define_const(rb_mDL, "CdeclCallbackProcs", rb_DLCdeclCallbackProcs);
+    rb_define_const(rb_mDL, "CdeclCallbackAddrs", rb_DLCdeclCallbackAddrs);
+    rb_define_const(rb_mDL, "StdcallCallbackProcs", rb_DLStdcallCallbackProcs);
+    rb_define_const(rb_mDL, "StdcallCallbackAddrs", rb_DLStdcallCallbackAddrs);
+#{
+    (0...MAX_DLTYPE).collect{|ty|
+      sprintf("    rb_ary_push(rb_DLCdeclCallbackProcs, rb_ary_new3(%d,%s));",
+              MAX_CALLBACK * DLSTACK_SIZE,
+              (0...MAX_CALLBACK).collect{
+                (0...DLSTACK_SIZE).collect{ "Qnil" }.join(",")
+              }.join(","))
+    }.join("\n")
+}
+#{
+    (0...MAX_DLTYPE).collect{|ty|
+      sprintf("    rb_ary_push(rb_DLCdeclCallbackAddrs, rb_ary_new3(%d,%s));",
+              MAX_CALLBACK * DLSTACK_SIZE,
+              (0...MAX_CALLBACK).collect{|i|
+                (0...DLSTACK_SIZE).collect{|argc|
+                  "PTR2NUM(%s)" % func_name(ty,argc,i,CDECL)
+                }.join(",")
+              }.join(","))
+    }.join("\n")
+}
+#{
+    (0...MAX_DLTYPE).collect{|ty|
+      sprintf("    rb_ary_push(rb_DLStdcallCallbackProcs, rb_ary_new3(%d,%s));",
+              MAX_CALLBACK * DLSTACK_SIZE,
+              (0...MAX_CALLBACK).collect{
+                (0...DLSTACK_SIZE).collect{ "Qnil" }.join(",")
+              }.join(","))
+    }.join("\n")
+}
+#{
+    (0...MAX_DLTYPE).collect{|ty|
+      sprintf("    rb_ary_push(rb_DLStdcallCallbackAddrs, rb_ary_new3(%d,%s));",
+              MAX_CALLBACK * DLSTACK_SIZE,
+              (0...MAX_CALLBACK).collect{|i|
+                (0...DLSTACK_SIZE).collect{|argc|
+                  "PTR2NUM(%s)" % func_name(ty,argc,i,STDCALL)
+                }.join(",")
+              }.join(","))
+    }.join("\n")
+}
+}
+EOS

Added: trunk/ext/dl/test/test_all.rb
===================================================================
--- trunk/ext/dl/test/test_all.rb	2006-11-06 13:53:20 UTC (rev 575)
+++ trunk/ext/dl/test/test_all.rb	2006-11-07 04:23:15 UTC (rev 576)
@@ -0,0 +1,11 @@
+require 'test_base'
+require 'dl/import'
+
+require 'test_dl2'
+require 'test_func'
+require 'test_import'
+
+case RUBY_PLATFORM
+when /cygwin/, /mingw32/, /mswin32/, /bccwin32/
+  require 'test_win32'
+end

Added: trunk/ext/dl/test/test_base.rb
===================================================================
--- trunk/ext/dl/test/test_base.rb	2006-11-06 13:53:20 UTC (rev 575)
+++ trunk/ext/dl/test/test_base.rb	2006-11-07 04:23:15 UTC (rev 576)
@@ -0,0 +1,52 @@
+require 'test/unit'
+require 'dl'
+
+case RUBY_PLATFORM
+when /cygwin/
+  LIBC_SO = "cygwin1.dll"
+  LIBM_SO = "cygwin1.dll"
+when /linux/
+  LIBC_SO = "/lib/libc.so.6"
+  LIBM_SO = "/lib/libm.so.6"
+when /mingw/, /mswin32/
+  LIBC_SO = "msvcrt.dll"
+  LIBM_SO = "msvcrt.dll"
+else
+  LIBC_SO = ARGV[0]
+  LIBM_SO = ARGV[1]
+  if( !(LIBC_SO && LIBM_SO) )
+    $stderr.puts("#{$0} <libc> <libm>")
+    exit
+  end
+end
+
+module DL
+  class TestBase < Test::Unit::TestCase
+    include Math
+    include DL
+
+    def setup
+      @libc = dlopen(LIBC_SO)
+      @libm = dlopen(LIBM_SO)
+    end
+    
+    def assert_match(expected, actual, message="")
+      assert(expected === actual, message)
+    end
+
+    def assert_positive(actual)
+      assert(actual > 0)
+    end
+
+    def assert_zero(actual)
+      assert(actual == 0)
+    end
+
+    def assert_negative(actual)
+      assert(actual < 0)
+    end
+
+    def test_empty()
+    end
+  end
+end

Added: trunk/ext/dl/test/test_dl2.rb
===================================================================
--- trunk/ext/dl/test/test_dl2.rb	2006-11-06 13:53:20 UTC (rev 575)
+++ trunk/ext/dl/test/test_dl2.rb	2006-11-07 04:23:15 UTC (rev 576)
@@ -0,0 +1,111 @@
+require 'test_base.rb'
+require 'dl/callback'
+
+module DL
+class TestDL < TestBase
+  def test_call_int()
+    cfunc = CFunc.new(@libc['atoi'], TYPE_INT, 'atoi')
+    x = cfunc.call(["100"].pack("p").unpack("l!*"))
+    assert_equal(100, x)
+
+    cfunc = CFunc.new(@libc['atoi'], TYPE_INT, 'atoi')
+    x = cfunc.call(["-100"].pack("p").unpack("l!*"))
+    assert_equal(-100, x)
+  end
+
+  def test_call_long()
+    cfunc = CFunc.new(@libc['atol'], TYPE_LONG, 'atol')
+    x = cfunc.call(["100"].pack("p").unpack("l!*"))
+    assert_equal(100, x)
+    cfunc = CFunc.new(@libc['atol'], TYPE_LONG, 'atol')
+    x = cfunc.call(["-100"].pack("p").unpack("l!*"))
+    assert_equal(-100, x)
+  end
+
+  def test_call_double()
+    cfunc = CFunc.new(@libc['atof'], TYPE_DOUBLE, 'atof')
+    x = cfunc.call(["0.1"].pack("p").unpack("l!*"))
+    assert_match(0.09..0.11, x)
+
+    cfunc = CFunc.new(@libc['atof'], TYPE_DOUBLE, 'atof')
+    x = cfunc.call(["-0.1"].pack("p").unpack("l!*"))
+    assert_match(-0.11 .. -0.09, x)
+  end
+
+  def test_sin()
+    cfunc = CFunc.new(@libm['sin'], TYPE_DOUBLE, 'sin')
+    x = cfunc.call([3.14/2].pack("d").unpack("l!*"))
+    assert_equal(x, Math.sin(3.14/2))
+
+    cfunc = CFunc.new(@libm['sin'], TYPE_DOUBLE, 'sin')
+    x = cfunc.call([-3.14/2].pack("d").unpack("l!*"))
+    assert_equal(Math.sin(-3.14/2), x)
+  end
+
+  def test_strlen()
+    cfunc = CFunc.new(@libc['strlen'], TYPE_INT, 'strlen')
+    x = cfunc.call(["abc"].pack("p").unpack("l!*"))
+    assert_equal("abc".size, x)
+  end
+
+  def test_strcpy()
+    buff = "xxxx"
+    str  = "abc"
+    cfunc = CFunc.new(@libc['strcpy'], TYPE_VOIDP, 'strcpy')
+    x = cfunc.call([buff,str].pack("pp").unpack("l!*"))
+    assert_equal("abc\0", buff)
+    assert_equal("abc\0", CPtr.new(x).to_s(4))
+
+    buff = "xxxx"
+    str  = "abc"
+    cfunc = CFunc.new(@libc['strncpy'], TYPE_VOIDP, 'strncpy')
+    x = cfunc.call([buff,str,3].pack("ppi").unpack("l!*"))
+    assert_equal("abcx", buff)
+    assert_equal("abcx", CPtr.new(x).to_s(4))
+
+    ptr = CPtr.malloc(4)
+    str = "abc"
+    cfunc = CFunc.new(@libc['strcpy'], TYPE_VOIDP, 'strcpy')
+    x = cfunc.call([ptr.to_i,str].pack("lp").unpack("l!*"))
+    assert_equal("abc\0", ptr[0,4])
+    assert_equal("abc\0", CPtr.new(x).to_s(4))
+  end
+
+  def test_callback()
+    buff = "foobarbaz"
+    cb = set_callback(TYPE_INT,2){|x,y| CPtr.new(x)[0] <=> CPtr.new(y)[0]}
+    cfunc = CFunc.new(@libc['qsort'], TYPE_VOID, 'qsort')
+    cfunc.call([buff, buff.size, 1, cb].pack("pI!I!L!").unpack("l!*"))
+    assert_equal('aabbfoorz', buff)
+  end
+
+  def test_dlwrap()
+    ary = [0,1,2,4,5]
+    addr = dlwrap(ary)
+    ary2 = dlunwrap(addr)
+    assert_equal(ary, ary2)
+  end
+
+  def test_cptr()
+    check = Proc.new{|str,ptr|
+      assert_equal(str.size(), ptr.size())
+      assert_equal(str, ptr.to_s())
+      assert_equal(str[0,2], ptr.to_s(2))
+      assert_equal(str[0,2], ptr[0,2])
+      assert_equal(str[1,2], ptr[1,2])
+      assert_equal(str[1,0], ptr[1,0])
+      assert_equal(str[0].ord, ptr[0])
+      assert_equal(str[1].ord, ptr[1])
+    }
+    str = 'abc'
+    ptr = CPtr[str]
+    check.call(str, ptr)
+    str[0] = "c"
+    ptr[0] = "c".ord
+    check.call(str, ptr)
+    str[0,2] = "aa"
+    ptr[0,2] = "aa"
+    check.call(str, ptr)
+  end
+end
+end # module DL

Added: trunk/ext/dl/test/test_func.rb
===================================================================
--- trunk/ext/dl/test/test_func.rb	2006-11-06 13:53:20 UTC (rev 575)
+++ trunk/ext/dl/test/test_func.rb	2006-11-07 04:23:15 UTC (rev 576)
@@ -0,0 +1,62 @@
+require 'test_base'
+require 'dl/func'
+
+module DL
+  class TestFunc < TestBase
+    def test_strcpy()
+      f = Function.new(CFunc.new(@libc['strcpy'], TYPE_VOIDP, 'strcpy'),
+                       [TYPE_VOIDP, TYPE_VOIDP])
+      buff = "000"
+      str = f.call(buff, "123")
+      assert_equal("123", buff)
+      assert_equal("123", str.to_s)
+    end
+
+    def test_isdigit()
+      f = Function.new(CFunc.new(@libc['isdigit'], TYPE_INT, 'isdigit'),
+                       [TYPE_INT])
+      r1 = f.call(?1)
+      r2 = f.call(?2)
+      rr = f.call(?r)
+      assert_positive(r1)
+      assert_positive(r2)
+      assert_zero(rr)
+    end
+
+    def test_atof()
+      f = Function.new(CFunc.new(@libc['atof'], TYPE_FLOAT, 'atof'),
+                       [TYPE_VOIDP])
+      r = f.call("12.34")
+      assert_match(12.00..13.00, r)
+    end
+
+    def test_strtod()
+      f = Function.new(CFunc.new(@libc['strtod'], TYPE_DOUBLE, 'strtod'),
+                       [TYPE_VOIDP, TYPE_VOIDP])
+      buff1 = "12.34"
+      buff2 = "     "
+      r = f.call(buff1, buff2)
+      assert_match(12.00..13.00, r)
+    end
+
+    def test_qsort1()
+      cb = Function.new(CFunc.new(0, TYPE_INT, '<callback>qsort'),
+                        [TYPE_VOIDP, TYPE_VOIDP]){|x,y| CPtr.new(x)[0] <=> CPtr.new(y)[0]}
+      qsort = Function.new(CFunc.new(@libc['qsort'], TYPE_VOID, 'qsort'),
+                           [TYPE_VOIDP, TYPE_INT, TYPE_INT, TYPE_VOIDP])
+      buff = "9341"
+      qsort.call(buff, buff.size, 1, cb)
+      assert_equal("1349", buff)
+    end
+
+    def test_qsort2()
+      cb = TempFunction.new(CFunc.new(0, TYPE_INT, '<callback>qsort'),
+                               [TYPE_VOIDP, TYPE_VOIDP])
+      qsort = Function.new(CFunc.new(@libc['qsort'], TYPE_VOID, 'qsort'),
+                           [TYPE_VOIDP, TYPE_INT, TYPE_INT, TYPE_VOIDP])
+      buff = "9341"
+      qsort.call(buff, buff.size, 1, cb){|x,y| CPtr.new(x)[0] <=> CPtr.new(y)[0]}
+      assert_equal("1349", buff)
+    end
+  end
+end

Added: trunk/ext/dl/test/test_import.rb
===================================================================
--- trunk/ext/dl/test/test_import.rb	2006-11-06 13:53:20 UTC (rev 575)
+++ trunk/ext/dl/test/test_import.rb	2006-11-07 04:23:15 UTC (rev 576)
@@ -0,0 +1,154 @@
+require 'test_base'
+require 'dl/import'
+
+module DL
+  module LIBC
+    extend Importer
+    dlload LIBC_SO, LIBM_SO
+
+    typealias 'string', 'char*'
+    typealias 'FILE*', 'void*'
+
+    extern "void *strcpy(char*, char*)"
+    extern "int isdigit(int)"
+    extern "float atof(string)"
+    extern "unsigned long strtoul(char*, char **, int)"
+    extern "int qsort(void*, int, int, void*)"
+    extern "void fprintf(FILE*, char*)"
+    extern "int gettimeofday(timeval*, timezone*)" rescue nil
+
+    QsortCallback = bind("void *qsort_callback(void*, void*)", :temp)
+    BoundQsortCallback = bind("void *qsort_callback(void*, void*)"){|ptr1,ptr2| ptr1[0] <=> ptr2[0]}
+    Timeval = struct [
+      "long tv_sec",
+      "long tv_usec",
+    ]
+    Timezone = struct [
+      "int tz_minuteswest",
+      "int tz_dsttime",
+    ]
+    MyStruct = struct [
+      "short num[5]",
+      "char c",
+      "unsigned char buff[7]",
+    ]
+
+    CallCallback = bind("void call_callback(void*, void*)"){|ptr1, ptr2|
+      f = Function.new(CFunc.new(ptr1.to_i, DL::TYPE_VOID, "<anonymous>"), [TYPE_VOIDP])
+      f.call(ptr2)
+    }
+    CarriedFunction = bind("void callback_function(void*)", :carried, 0)
+  end
+
+  class TestImport < TestBase
+    def test_malloc()
+      s1 = LIBC::Timeval.malloc()
+      s2 = LIBC::Timeval.malloc()
+      assert_not_equal(s1.to_ptr.to_i, s2.to_ptr.to_i)
+    end
+
+    def test_sizeof()
+      assert_equal(DL::SIZEOF_VOIDP, LIBC.sizeof("FILE*"))
+      assert_equal(LIBC::MyStruct.size(), LIBC.sizeof(LIBC::MyStruct))
+    end
+
+    def test_unsigned_result()
+      d = (2 ** 31) + 1
+      
+      r = LIBC.strtoul(d.to_s, 0, 0)
+      assert_equal(d, r)
+    end
+
+    def test_io()
+      if( RUBY_PLATFORM != DL::BUILD_RUBY_PLATFORM )
+        return
+      end
+      io_in,io_out = IO.pipe()
+      LIBC.fprintf(io_out, "hello")
+      io_out.flush()
+      io_out.close()
+      str = io_in.read()
+      io_in.close()
+      assert_equal("hello", str)
+    end
+
+    def test_value()
+      i = LIBC.value('int', 2)
+      assert_equal(2, i.value)
+      
+      d = LIBC.value('double', 2.0)
+      assert_equal(2.0, d.value)
+
+      ary = LIBC.value('int[3]', [0,1,2])
+      assert_equal([0,1,2], ary.value)
+    end
+
+    def test_carried_function()
+      data1 = "data"
+      data2 = nil
+      LIBC.call_callback(LIBC::CarriedFunction, LIBC::CarriedFunction.create_carrier(data1)){|d|
+        data2 = d
+      }
+      assert_equal(data1, data2)
+    end
+
+    def test_struct()
+      s = LIBC::MyStruct.malloc()
+      s.num = [0,1,2,3,4]
+      s.c = ?a
+      s.buff = "012345\377"
+      assert_equal([0,1,2,3,4], s.num)
+      assert_equal(?a, s.c)
+      assert_equal([?0,?1,?2,?3,?4,?5,?\377], s.buff)
+    end
+
+    def test_gettimeofday()
+      if( defined?(LIBC.gettimeofday) )
+        timeval = LIBC::Timeval.malloc()
+        timezone = LIBC::Timezone.malloc()
+        LIBC.gettimeofday(timeval, timezone)
+        cur = Time.now()
+        assert(cur.to_i - 2 <= timeval.tv_sec && timeval.tv_sec <= cur.to_i)
+      end
+    end
+
+    def test_strcpy()
+      buff = "000"
+      str = LIBC.strcpy(buff, "123")
+      assert_equal("123", buff)
+      assert_equal("123", str.to_s)
+    end
+
+    def test_isdigit()
+      r1 = LIBC.isdigit(?1)
+      r2 = LIBC.isdigit(?2)
+      rr = LIBC.isdigit(?r)
+      assert_positive(r1)
+      assert_positive(r2)
+      assert_zero(rr)
+    end
+
+    def test_atof()
+      r = LIBC.atof("12.34")
+      assert_match(12.00..13.00, r)
+    end
+
+    def test_strtod()
+      f = Function.new(CFunc.new(@libc['strtod'], TYPE_DOUBLE, 'strtod'),
+                       [TYPE_VOIDP, TYPE_VOIDP])
+      buff1 = "12.34"
+      buff2 = "     "
+      r = f.call(buff1, buff2)
+      assert_match(12.00..13.00, r)
+    end
+
+    def test_qsort()
+      buff = "9341"
+      LIBC.qsort(buff, buff.size, 1, LIBC::QsortCallback){|ptr1,ptr2| ptr1[0] <=> ptr2[0]}
+      assert_equal("1349", buff)
+      buff = "9341"
+      LIBC.qsort(buff, buff.size, 1, LIBC::BoundQsortCallback)
+      assert_equal("1349", buff)
+    end
+  end