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