From 11dbedfaad4a9a9521ece2198a8dc491678b1902 Mon Sep 17 00:00:00 2001 From: shyouhei Date: Wed, 29 Aug 2007 04:06:12 +0000 Subject: add tag v1_8_6_5001 git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/tags/v1_8_6_5001@13304 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ruby_1_8_6/ext/dl/.cvsignore | 8 + ruby_1_8_6/ext/dl/depend | 46 ++ ruby_1_8_6/ext/dl/dl.c | 728 ++++++++++++++++++++++ ruby_1_8_6/ext/dl/dl.def | 59 ++ ruby_1_8_6/ext/dl/dl.h | 313 ++++++++++ ruby_1_8_6/ext/dl/doc/dl.txt | 266 ++++++++ ruby_1_8_6/ext/dl/extconf.rb | 193 ++++++ ruby_1_8_6/ext/dl/h2rb | 500 +++++++++++++++ ruby_1_8_6/ext/dl/handle.c | 215 +++++++ ruby_1_8_6/ext/dl/install.rb | 49 ++ ruby_1_8_6/ext/dl/lib/dl/import.rb | 225 +++++++ ruby_1_8_6/ext/dl/lib/dl/struct.rb | 149 +++++ ruby_1_8_6/ext/dl/lib/dl/types.rb | 245 ++++++++ ruby_1_8_6/ext/dl/lib/dl/win32.rb | 25 + ruby_1_8_6/ext/dl/mkcall.rb | 62 ++ ruby_1_8_6/ext/dl/mkcallback.rb | 56 ++ ruby_1_8_6/ext/dl/mkcbtable.rb | 18 + ruby_1_8_6/ext/dl/ptr.c | 1068 +++++++++++++++++++++++++++++++++ ruby_1_8_6/ext/dl/sample/c++sample.C | 35 ++ ruby_1_8_6/ext/dl/sample/c++sample.rb | 60 ++ ruby_1_8_6/ext/dl/sample/drives.rb | 70 +++ ruby_1_8_6/ext/dl/sample/getch.rb | 5 + ruby_1_8_6/ext/dl/sample/libc.rb | 69 +++ ruby_1_8_6/ext/dl/sample/msgbox.rb | 19 + ruby_1_8_6/ext/dl/sample/msgbox2.rb | 18 + ruby_1_8_6/ext/dl/sample/stream.rb | 87 +++ ruby_1_8_6/ext/dl/sym.c | 992 ++++++++++++++++++++++++++++++ ruby_1_8_6/ext/dl/test/libtest.def | 28 + ruby_1_8_6/ext/dl/test/test.c | 247 ++++++++ ruby_1_8_6/ext/dl/test/test.rb | 306 ++++++++++ ruby_1_8_6/ext/dl/type.rb | 115 ++++ 31 files changed, 6276 insertions(+) create mode 100644 ruby_1_8_6/ext/dl/.cvsignore create mode 100644 ruby_1_8_6/ext/dl/depend create mode 100644 ruby_1_8_6/ext/dl/dl.c create mode 100644 ruby_1_8_6/ext/dl/dl.def create mode 100644 ruby_1_8_6/ext/dl/dl.h create mode 100644 ruby_1_8_6/ext/dl/doc/dl.txt create mode 100644 ruby_1_8_6/ext/dl/extconf.rb create mode 100644 ruby_1_8_6/ext/dl/h2rb create mode 100644 ruby_1_8_6/ext/dl/handle.c create mode 100644 ruby_1_8_6/ext/dl/install.rb create mode 100644 ruby_1_8_6/ext/dl/lib/dl/import.rb create mode 100644 ruby_1_8_6/ext/dl/lib/dl/struct.rb create mode 100644 ruby_1_8_6/ext/dl/lib/dl/types.rb create mode 100644 ruby_1_8_6/ext/dl/lib/dl/win32.rb create mode 100644 ruby_1_8_6/ext/dl/mkcall.rb create mode 100644 ruby_1_8_6/ext/dl/mkcallback.rb create mode 100644 ruby_1_8_6/ext/dl/mkcbtable.rb create mode 100644 ruby_1_8_6/ext/dl/ptr.c create mode 100644 ruby_1_8_6/ext/dl/sample/c++sample.C create mode 100644 ruby_1_8_6/ext/dl/sample/c++sample.rb create mode 100644 ruby_1_8_6/ext/dl/sample/drives.rb create mode 100644 ruby_1_8_6/ext/dl/sample/getch.rb create mode 100644 ruby_1_8_6/ext/dl/sample/libc.rb create mode 100644 ruby_1_8_6/ext/dl/sample/msgbox.rb create mode 100644 ruby_1_8_6/ext/dl/sample/msgbox2.rb create mode 100644 ruby_1_8_6/ext/dl/sample/stream.rb create mode 100644 ruby_1_8_6/ext/dl/sym.c create mode 100644 ruby_1_8_6/ext/dl/test/libtest.def create mode 100644 ruby_1_8_6/ext/dl/test/test.c create mode 100644 ruby_1_8_6/ext/dl/test/test.rb create mode 100644 ruby_1_8_6/ext/dl/type.rb (limited to 'ruby_1_8_6/ext/dl') diff --git a/ruby_1_8_6/ext/dl/.cvsignore b/ruby_1_8_6/ext/dl/.cvsignore new file mode 100644 index 0000000000..6d884b6cec --- /dev/null +++ b/ruby_1_8_6/ext/dl/.cvsignore @@ -0,0 +1,8 @@ +Makefile +mkmf.log +dlconfig.h +dlconfig.rb +*.func +*.o +*~ +*.def diff --git a/ruby_1_8_6/ext/dl/depend b/ruby_1_8_6/ext/dl/depend new file mode 100644 index 0000000000..fba3df7a3d --- /dev/null +++ b/ruby_1_8_6/ext/dl/depend @@ -0,0 +1,46 @@ +LDSHARED_TEST = $(LDSHARED) $(LDFLAGS) test/test.o -o test/libtest.so $(LOCAL_LIBS) + +libtest.so: test/libtest.so + +test/libtest.so: test/test.o $(srcdir)/test/libtest.def + $(RUBY) -rftools -e 'ARGV.each do|d|File.mkpath(File.dirname(d))end' $@ + $(LDSHARED_TEST:dl.def=test/libtest.def) + +test/test.o: $(srcdir)/test/test.c + @$(RUBY) -rftools -e 'File.mkpath(*ARGV)' test + $(CC) $(CFLAGS) $(CPPFLAGS) -c $(srcdir)/test/test.c -o $@ + +test:: dl.so libtest.so force + $(RUBY) -I. -I$(srcdir)/lib $(srcdir)/test/test.rb + +force: + +.PHONY: force test + +allclean: distclean + @rm -f $(CLEANFILES) $(DISTCLEANFILES) + +$(OBJS): ./dlconfig.h + +sym.o: dl.h call.func + +dl.o: dl.h callback.func cbtable.func + +ptr.o: dl.h + +handle.o: dl.h + +call.func: $(srcdir)/mkcall.rb ./dlconfig.rb + @echo "Generating call.func" + @$(RUBY) $(srcdir)/mkcall.rb > $@ + +callback.func: $(srcdir)/mkcallback.rb ./dlconfig.rb + @echo "Generating callback.func" + @$(RUBY) $(srcdir)/mkcallback.rb > $@ + +cbtable.func: $(srcdir)/mkcbtable.rb ./dlconfig.rb + @echo "Generating cbtable.func" + @$(RUBY) $(srcdir)/mkcbtable.rb > $@ + +debug: + $(MAKE) CPPFLAGS="$(CPPFLAGS) -DDEBUG" diff --git a/ruby_1_8_6/ext/dl/dl.c b/ruby_1_8_6/ext/dl/dl.c new file mode 100644 index 0000000000..5ba3646ea3 --- /dev/null +++ b/ruby_1_8_6/ext/dl/dl.c @@ -0,0 +1,728 @@ +/* + * $Id$ + */ + +#include +#include +#include +#include "dl.h" + +VALUE rb_mDL; +VALUE rb_eDLError; +VALUE rb_eDLTypeError; + +static VALUE DLFuncTable; +static void *rb_dl_callback_table[CALLBACK_TYPES][MAX_CALLBACK]; +static ID id_call; + +static int +rb_dl_scan_callback_args(long stack[], const char *proto, + int *argc, VALUE argv[]) +{ + int i; + long *sp; + VALUE val; + + sp = stack; + for (i=1; proto[i]; i++) { + switch (proto[i]) { + case 'C': + { + char v; + v = (char)(*sp); + sp++; + val = INT2NUM(v); + } + break; + case 'H': + { + short v; + v = (short)(*sp); + sp++; + val = INT2NUM(v); + } + break; + case 'I': + { + int v; + v = (int)(*sp); + sp++; + val = INT2NUM(v); + } + break; + case 'L': + { + long v; + v = (long)(*sp); + sp++; + val = INT2NUM(v); + } + break; + case 'F': + { + float v; + memcpy(&v, sp, sizeof(float)); + sp += sizeof(float)/sizeof(long); + val = rb_float_new(v); + } + break; + case 'D': + { + double v; + memcpy(&v, sp, sizeof(double)); + sp += sizeof(double)/sizeof(long); + val = rb_float_new(v); + } + break; + case 'P': + { + void *v; + memcpy(&v, sp, sizeof(void*)); + sp++; + val = rb_dlptr_new(v, 0, 0); + } + break; + case 'S': + { + char *v; + memcpy(&v, sp, sizeof(void*)); + sp++; + val = rb_tainted_str_new2(v); + } + break; + default: + rb_raise(rb_eDLTypeError, "unsupported type `%c'", proto[i]); + break; + } + argv[i-1] = val; + } + *argc = (i - 1); + + return (*argc); +} + +#include "callback.func" + +static void +init_dl_func_table(){ +#include "cbtable.func" +} + +void * +dlmalloc(size_t size) +{ + DEBUG_CODE2({ + void *ptr; + + printf("dlmalloc(%d)",size); + ptr = xmalloc(size); + printf(":0x%x\n",ptr); + return ptr; + }, + { + return xmalloc(size); + }); +} + +void * +dlrealloc(void *ptr, size_t size) +{ + DEBUG_CODE({ + printf("dlrealloc(0x%x,%d)\n",ptr,size); + }); + return xrealloc(ptr, size); +} + +void +dlfree(void *ptr) +{ + DEBUG_CODE({ + printf("dlfree(0x%x)\n",ptr); + }); + xfree(ptr); +} + +char* +dlstrdup(const char *str) +{ + char *newstr; + + newstr = (char*)dlmalloc(strlen(str)+1); + strcpy(newstr,str); + + return newstr; +} + +size_t +dlsizeof(const char *cstr) +{ + size_t size; + int i, len, n, dlen; + char *d; + + len = strlen(cstr); + size = 0; + for (i=0; ilen; + *size = sizeof(float) * len; + ary = dlmalloc(*size); + for (i=0; i < len; i++) { + e = rb_ary_entry(v, i); + switch (TYPE(e)) { + case T_FLOAT: + ary[i] = (float)(RFLOAT(e)->value); + break; + case T_NIL: + ary[i] = 0.0; + break; + default: + rb_raise(rb_eDLTypeError, "unexpected type of the element #%d", i); + break; + } + } + + return ary; +} + +static double * +c_darray(VALUE v, long *size) +{ + int i, len; + double *ary; + VALUE e; + + len = RARRAY(v)->len; + *size = sizeof(double) * len; + ary = dlmalloc(*size); + for (i=0; i < len; i++) { + e = rb_ary_entry(v, i); + switch (TYPE(e)) { + case T_FLOAT: + ary[i] = (double)(RFLOAT(e)->value); + break; + case T_NIL: + ary[i] = 0.0; + break; + default: + rb_raise(rb_eDLTypeError, "unexpected type of the element #%d", i); + break; + } + } + + return ary; +} + +static long * +c_larray(VALUE v, long *size) +{ + int i, len; + long *ary; + VALUE e; + + len = RARRAY(v)->len; + *size = sizeof(long) * len; + ary = dlmalloc(*size); + for (i=0; i < len; i++) { + e = rb_ary_entry(v, i); + switch (TYPE(e)) { + case T_FIXNUM: + case T_BIGNUM: + ary[i] = (long)(NUM2INT(e)); + break; + case T_NIL: + ary[i] = 0; + break; + default: + rb_raise(rb_eDLTypeError, "unexpected type of the element #%d", i); + break; + } + } + + return ary; +} + +static int * +c_iarray(VALUE v, long *size) +{ + int i, len; + int *ary; + VALUE e; + + len = RARRAY(v)->len; + *size = sizeof(int) * len; + ary = dlmalloc(*size); + for (i=0; i < len; i++) { + e = rb_ary_entry(v, i); + switch (TYPE(e)) { + case T_FIXNUM: + case T_BIGNUM: + ary[i] = (int)(NUM2INT(e)); + break; + case T_NIL: + ary[i] = 0; + break; + default: + rb_raise(rb_eDLTypeError, "unexpected type of the element #%d", i); + break; + } + } + + return ary; +} + +static short * +c_harray(VALUE v, long *size) +{ + int i, len; + short *ary; + VALUE e; + + len = RARRAY(v)->len; + *size = sizeof(short) * len; + ary = dlmalloc(*size); + for (i=0; i < len; i++) { + e = rb_ary_entry(v, i); + switch (TYPE(e)) { + case T_FIXNUM: + case T_BIGNUM: + ary[i] = (short)(NUM2INT(e)); + break; + case T_NIL: + ary[i] = 0; + break; + default: + rb_raise(rb_eDLTypeError, "unexpected type of the element #%d", i); + break; + } + } + + return ary; +} + +static char * +c_carray(VALUE v, long *size) +{ + int i, len; + char *ary; + VALUE e; + + len = RARRAY(v)->len; + *size = sizeof(char) * len; + ary = dlmalloc(*size); + for (i=0; i < len; i++) { + e = rb_ary_entry(v, i); + switch (TYPE(e)) { + case T_FIXNUM: + case T_BIGNUM: + ary[i] = (char)(NUM2INT(e)); + break; + case T_NIL: + ary[i] = 0; + break; + default: + rb_raise(rb_eDLTypeError, "unexpected type of the element #%d", i); + break; + } + } + + return ary; +} + +static void * +c_parray(VALUE v, long *size) +{ + int i, len; + void **ary; + VALUE e, tmp; + + len = RARRAY(v)->len; + *size = sizeof(void*) * len; + ary = dlmalloc(*size); + for (i=0; i < len; i++) { + e = rb_ary_entry(v, i); + switch (TYPE(e)) { + default: + tmp = rb_check_string_type(e); + if (NIL_P(tmp)) { + rb_raise(rb_eDLTypeError, "unexpected type of the element #%d", i); + } + e = tmp; + /* fall through */ + case T_STRING: + rb_check_safe_str(e); + { + char *str, *src; + src = RSTRING(e)->ptr; + str = dlstrdup(src); + ary[i] = (void*)str; + } + break; + case T_NIL: + ary[i] = NULL; + break; + case T_DATA: + if (rb_obj_is_kind_of(e, rb_cDLPtrData)) { + struct ptr_data *pdata; + Data_Get_Struct(e, struct ptr_data, pdata); + ary[i] = (void*)(pdata->ptr); + } + else{ + e = rb_funcall(e, rb_intern("to_ptr"), 0); + if (rb_obj_is_kind_of(e, rb_cDLPtrData)) { + struct ptr_data *pdata; + Data_Get_Struct(e, struct ptr_data, pdata); + ary[i] = (void*)(pdata->ptr); + } + else{ + rb_raise(rb_eDLTypeError, "unexpected type of the element #%d", i); + } + } + break; + } + } + + return ary; +} + +void * +rb_ary2cary(char t, VALUE v, long *size) +{ + int len; + VALUE val0; + + val0 = rb_check_array_type(v); + if(NIL_P(val0)) { + rb_raise(rb_eDLTypeError, "an array is expected."); + } + v = val0; + + len = RARRAY(v)->len; + if (len == 0) { + return NULL; + } + + if (!size) { + size = ALLOCA_N(long,1); + } + + val0 = rb_ary_entry(v,0); + switch (TYPE(val0)) { + case T_FIXNUM: + case T_BIGNUM: + switch (t) { + case 'C': case 'c': + return (void*)c_carray(v,size); + case 'H': case 'h': + return (void*)c_harray(v,size); + case 'I': case 'i': + return (void*)c_iarray(v,size); + case 'L': case 'l': case 0: + return (void*)c_larray(v,size); + default: + rb_raise(rb_eDLTypeError, "type mismatch"); + } + case T_STRING: + return (void*)c_parray(v,size); + case T_FLOAT: + switch (t) { + case 'F': case 'f': + return (void*)c_farray(v,size); + case 'D': case 'd': case 0: + return (void*)c_darray(v,size); + } + rb_raise(rb_eDLTypeError, "type mismatch"); + case T_DATA: + if (rb_obj_is_kind_of(val0, rb_cDLPtrData)) { + return (void*)c_parray(v,size); + } + else{ + val0 = rb_funcall(val0, rb_intern("to_ptr"), 0); + if (rb_obj_is_kind_of(val0, rb_cDLPtrData)) { + return (void*)c_parray(v,size); + } + } + rb_raise(rb_eDLTypeError, "type mismatch"); + case T_NIL: + return (void*)c_parray(v, size); + default: + rb_raise(rb_eDLTypeError, "unsupported type"); + } +} + +VALUE +rb_str_to_ptr(VALUE self) +{ + char *ptr; + int len; + + len = RSTRING(self)->len; + ptr = (char*)dlmalloc(len + 1); + memcpy(ptr, RSTRING(self)->ptr, len); + ptr[len] = '\0'; + return rb_dlptr_new((void*)ptr,len,dlfree); +} + +VALUE +rb_ary_to_ptr(int argc, VALUE argv[], VALUE self) +{ + void *ptr; + VALUE t; + long size; + + switch (rb_scan_args(argc, argv, "01", &t)) { + case 1: + ptr = rb_ary2cary(StringValuePtr(t)[0], self, &size); + break; + case 0: + ptr = rb_ary2cary(0, self, &size); + break; + } + return ptr ? rb_dlptr_new(ptr, size, dlfree) : Qnil; +} + +VALUE +rb_io_to_ptr(VALUE self) +{ + OpenFile *fptr; + FILE *fp; + + GetOpenFile(self, fptr); + fp = fptr->f; + + return fp ? rb_dlptr_new(fp, 0, 0) : Qnil; +} + +VALUE +rb_dl_dlopen(int argc, VALUE argv[], VALUE self) +{ + rb_secure(4); + return rb_class_new_instance(argc, argv, rb_cDLHandle); +} + +VALUE +rb_dl_malloc(VALUE self, VALUE size) +{ + rb_secure(4); + return rb_dlptr_malloc(DLNUM2LONG(size), dlfree); +} + +VALUE +rb_dl_strdup(VALUE self, VALUE str) +{ + SafeStringValue(str); + return rb_dlptr_new(strdup(RSTRING(str)->ptr), RSTRING(str)->len, dlfree); +} + +static VALUE +rb_dl_sizeof(VALUE self, VALUE str) +{ + return INT2NUM(dlsizeof(StringValuePtr(str))); +} + +static VALUE +rb_dl_callback(int argc, VALUE argv[], VALUE self) +{ + VALUE type, proc; + int rettype, entry, i; + char fname[127]; + + rb_secure(4); + proc = Qnil; + switch (rb_scan_args(argc, argv, "11", &type, &proc)) { + case 1: + if (rb_block_given_p()) { + proc = rb_block_proc(); + } + else{ + proc = Qnil; + } + default: + break; + } + + StringValue(type); + switch (RSTRING(type)->ptr[0]) { + case '0': + rettype = 0x00; + break; + case 'C': + rettype = 0x01; + break; + case 'H': + rettype = 0x02; + break; + case 'I': + rettype = 0x03; + break; + case 'L': + rettype = 0x04; + break; + case 'F': + rettype = 0x05; + break; + case 'D': + rettype = 0x06; + break; + case 'P': + rettype = 0x07; + break; + default: + rb_raise(rb_eDLTypeError, "unsupported type `%c'", RSTRING(type)->ptr[0]); + } + + entry = -1; + for (i=0; i < MAX_CALLBACK; i++) { + if (rb_hash_aref(DLFuncTable, rb_assoc_new(INT2NUM(rettype), INT2NUM(i))) == Qnil) { + entry = i; + break; + } + } + if (entry < 0) { + rb_raise(rb_eDLError, "too many callbacks are defined."); + } + + rb_hash_aset(DLFuncTable, + rb_assoc_new(INT2NUM(rettype),INT2NUM(entry)), + rb_assoc_new(type,proc)); + sprintf(fname, "rb_dl_callback_func_%d_%d", rettype, entry); + return rb_dlsym_new((void (*)())rb_dl_callback_table[rettype][entry], + fname, RSTRING(type)->ptr); +} + +static VALUE +rb_dl_remove_callback(VALUE mod, VALUE sym) +{ + freefunc_t f; + int i, j; + + rb_secure(4); + f = rb_dlsym2csym(sym); + for (i=0; i < CALLBACK_TYPES; i++) { + for (j=0; j < MAX_CALLBACK; j++) { + if (rb_dl_callback_table[i][j] == f) { + rb_hash_aset(DLFuncTable, rb_assoc_new(INT2NUM(i),INT2NUM(j)),Qnil); + break; + } + } + } + return Qnil; +} + +void +Init_dl() +{ + void Init_dlptr(); + void Init_dlsym(); + void Init_dlhandle(); + + id_call = rb_intern("call"); + + 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); + + DLFuncTable = rb_hash_new(); + init_dl_func_table(); + rb_define_const(rb_mDL, "FuncTable", DLFuncTable); + + 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, "ALIGN_INT", INT2NUM(ALIGN_INT)); + rb_define_const(rb_mDL, "ALIGN_LONG", INT2NUM(ALIGN_LONG)); + rb_define_const(rb_mDL, "ALIGN_FLOAT", INT2NUM(ALIGN_FLOAT)); + rb_define_const(rb_mDL, "ALIGN_SHORT", INT2NUM(ALIGN_SHORT)); + rb_define_const(rb_mDL, "ALIGN_DOUBLE",INT2NUM(ALIGN_DOUBLE)); + rb_define_const(rb_mDL, "ALIGN_VOIDP", INT2NUM(ALIGN_VOIDP)); + + rb_define_const(rb_mDL, "MAX_ARG", INT2NUM(MAX_ARG)); + rb_define_const(rb_mDL, "DLSTACK", rb_tainted_str_new2(DLSTACK_METHOD)); + + rb_define_module_function(rb_mDL, "dlopen", rb_dl_dlopen, -1); + rb_define_module_function(rb_mDL, "callback", rb_dl_callback, -1); + rb_define_module_function(rb_mDL, "define_callback", rb_dl_callback, -1); + rb_define_module_function(rb_mDL, "remove_callback", rb_dl_remove_callback, 1); + rb_define_module_function(rb_mDL, "malloc", rb_dl_malloc, 1); + rb_define_module_function(rb_mDL, "strdup", rb_dl_strdup, 1); + rb_define_module_function(rb_mDL, "sizeof", rb_dl_sizeof, 1); + + Init_dlptr(); + Init_dlsym(); + Init_dlhandle(); + + rb_define_const(rb_mDL, "FREE", rb_dlsym_new(dlfree, "free", "0P")); + + rb_define_method(rb_cString, "to_ptr", rb_str_to_ptr, 0); + rb_define_method(rb_cArray, "to_ptr", rb_ary_to_ptr, -1); + rb_define_method(rb_cIO, "to_ptr", rb_io_to_ptr, 0); +} diff --git a/ruby_1_8_6/ext/dl/dl.def b/ruby_1_8_6/ext/dl/dl.def new file mode 100644 index 0000000000..cdab4af90d --- /dev/null +++ b/ruby_1_8_6/ext/dl/dl.def @@ -0,0 +1,59 @@ +EXPORTS +Init_dl +dlfree +dlmalloc +dlrealloc +dlstrdup +rb_ary_to_ptr +rb_dl_dlopen +rb_dl_malloc +rb_dl_strdup +rb_eDLError +rb_eDLTypeError +rb_io_to_ptr +rb_mDL +rb_str_to_ptr +Init_dlhandle +rb_cDLHandle +rb_dlhandle_close +rb_dlhandle_disable_close +rb_dlhandle_enable_close +rb_dlhandle_sym +Init_dlptr +rb_cDLPtrData +rb_dlmem_each +rb_dlptr2cptr +rb_dlptr_malloc +rb_dlptr_aref +rb_dlptr_aset +rb_dlptr_cmp +rb_dlptr_define_data_type +rb_dlptr_define_struct +rb_dlptr_define_union +rb_dlptr_eql +rb_dlptr_free_get +rb_dlptr_free_set +rb_dlptr_get_data_type +rb_dlptr_inspect +rb_dlptr_minus +rb_dlptr_new +rb_dlptr_new2 +rb_dlptr_null_p +rb_dlptr_plus +rb_dlptr_ptr +rb_dlptr_ref +rb_dlptr_to_array +rb_dlptr_to_i +rb_dlptr_to_s +rb_dlptr_to_str +rb_mDLMemorySpace +Init_dlsym +rb_cDLSymbol +rb_dlsym2csym +rb_dlsym_call +rb_dlsym_cproto +rb_dlsym_inspect +rb_dlsym_name +rb_dlsym_new +rb_dlsym_proto +rb_dlsym_to_ptr diff --git a/ruby_1_8_6/ext/dl/dl.h b/ruby_1_8_6/ext/dl/dl.h new file mode 100644 index 0000000000..1faa316cf1 --- /dev/null +++ b/ruby_1_8_6/ext/dl/dl.h @@ -0,0 +1,313 @@ +/* -*- C -*- + * $Id$ + */ + +#ifndef RUBY_DL_H +#define RUBY_DL_H + +#include +#include + +#if defined(HAVE_DLFCN_H) +# include +# /* 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 +# 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 + +#if !defined(StringValue) +# define StringValue(v) if(TYPE(v) != T_STRING) v = rb_str_to_str(v) +#endif +#if !defined(StringValuePtr) +# define StringValuePtr(v) RSTRING((TYPE(v) == T_STRING) ? (v) : rb_str_to_str(v))->ptr +#endif + +#ifdef DEBUG +#define DEBUG_CODE(b) {printf("DEBUG:%d\n",__LINE__);b;} +#define DEBUG_CODE2(b1,b2) {printf("DEBUG:%d\n",__LINE__);b1;} +#else +#define DEBUG_CODE(b) +#define DEBUG_CODE2(b1,b2) b2 +#endif + +#define VOID_DLTYPE 0x00 +#define CHAR_DLTYPE 0x01 +#define SHORT_DLTYPE 0x02 +#define INT_DLTYPE 0x03 +#define LONG_DLTYPE 0x04 +#define FLOAT_DLTYPE 0x05 +#define DOUBLE_DLTYPE 0x06 +#define VOIDP_DLTYPE 0x07 + +#define ARG_TYPE(x,i) (((x) & (0x07 << ((i)*3))) >> ((i)*3)) +#define PUSH_ARG(x,t) do{x <<= 3; x |= t;}while(0) +#define PUSH_0(x) PUSH_ARG(x,VOID_DLTYPE) + +#if SIZEOF_INT == SIZEOF_LONG +# define PUSH_I(x) PUSH_ARG(x,LONG_DLTYPE) +# define ANY2I(x) x.l +# define DLINT(x) (long)x +#else +# define PUSH_I(x) PUSH_ARG(x,INT_DLTYPE) +# define ANY2I(x) x.i +# define DLINT(x) (int)x +#endif +#define PUSH_L(x) PUSH_ARG(x,LONG_DLTYPE) +#define ANY2L(x) x.l +#define DLLONG(x) (long)x + +#if defined(WITH_TYPE_FLOAT) +# if SIZEOF_FLOAT == SIZEOF_DOUBLE +# define PUSH_F(x) PUSH_ARG(x,DOUBLE_DLTYPE) +# define ANY2F(x) (x.d) +# define DLFLOAT(x) ((double)x) +# else +# define PUSH_F(x) PUSH_ARG(x,FLOAT_DLTYPE) +# define ANY2F(x) (x.f) +# define DLFLOAT(x) ((float)x) +# endif +#else +# define PUSH_F(x) PUSH_ARG(x,DOUBLE_DLTYPE) +# define ANY2F(x) (x.d) +# define DLFLOAT(x) ((double)x) +#endif +#define PUSH_D(x) PUSH_ARG(x,DOUBLE_DLTYPE) +#define ANY2D(x) (x.d) +#define DLDOUBLE(x) ((double)x) + +#if SIZEOF_INT == SIZEOF_VOIDP && SIZEOF_INT != SIZEOF_LONG +# define PUSH_P(x) PUSH_ARG(x,INT_DLTYPE) +# define ANY2P(x) (x.i) +# define DLVOIDP(x) ((int)x) +#elif SIZEOF_LONG == SIZEOF_VOIDP +# define PUSH_P(x) PUSH_ARG(x,LONG_DLTYPE) +# define ANY2P(x) (x.l) +# define DLVOIDP(x) ((long)x) +#else +# define PUSH_P(x) PUSH_ARG(x,VOIDP_DLTYPE) +# define ANY2P(x) (x.p) +# define DLVOIDP(x) ((void*)p) +#endif + +#if defined(WITH_TYPE_CHAR) +# define PUSH_C(x) PUSH_ARG(x,CHAR_DLTYPE) +# define ANY2C(x) (x.c) +# define DLCHAR(x) ((char)x) +#else +# define PUSH_C(x) PUSH_I(x) +# define ANY2C(x) ANY2I(x) +# define DLCHAR(x) DLINT(x) +#endif + +#if defined(WITH_TYPE_SHORT) +# define PUSH_H(x) PUSH_ARG(x,SHORT_DLTYPE) +# define ANY2H(x) (x.h) +# define DLSHORT(x) ((short)x) +#else +# define PUSH_H(x) PUSH_I(x) +# define ANY2H(x) ANY2I(x) +# define DLSHORT(x) DLINT(x) +#endif + +#define PUSH_S(x) PUSH_P(x) +#define ANY2S(x) ANY2P(x) +#define DLSTR(x) DLVOIDP(x) + +#define CBPUSH_0(x) PUSH_0(x) +#define CBPUSH_C(x) PUSH_C(x) +#define CBPUSH_H(x) PUSH_H(x) +#define CBPUSH_I(x) PUSH_I(x) +#define CBPUSH_L(x) PUSH_L(x) +#define CBPUSH_F(x) PUSH_F(x) +#define CBPUSH_D(x) PUSH_D(x) +#if defined(WITH_CBTYPE_VOIDP) +# define CBPUSH_P(x) PUSH_ARG(x,VOIDP_DLTYPE) +#else +# define CBPUSH_P(x) PUSH_P(x) +#endif + + +#if defined(USE_INLINE_ASM) +# if defined(__i386__) && defined(__GNUC__) +# define DLSTACK +# define DLSTACK_METHOD "asm" +# define DLSTACK_REVERSE +# define DLSTACK_PROTO +# define DLSTACK_ARGS +# define DLSTACK_START(sym) +# define DLSTACK_END(sym) +# define DLSTACK_PUSH_C(x) asm volatile ("pushl %0" :: "g" (x)); +# define DLSTACK_PUSH_H(x) asm volatile ("pushl %0" :: "g" (x)); +# define DLSTACK_PUSH_I(x) asm volatile ("pushl %0" :: "g" (x)); +# define DLSTACK_PUSH_L(x) asm volatile ("pushl %0" :: "g" (x)); +# define DLSTACK_PUSH_P(x) asm volatile ("pushl %0" :: "g" (x)); +# define DLSTACK_PUSH_F(x) asm volatile ("flds %0"::"g"(x));\ + asm volatile ("subl $4,%esp");\ + asm volatile ("fstps (%esp)"); +# define DLSTACK_PUSH_D(x) asm volatile ("fldl %0"::"g"(x));\ + asm volatile ("subl $8,%esp");\ + asm volatile ("fstpl (%esp)") +# else +# error --with-asm is not supported on this machine +# endif +#elif defined(USE_DLSTACK) +# define DLSTACK +# define DLSTACK_GUARD +# define DLSTACK_METHOD "dl" +# define DLSTACK_PROTO long,long,long,long,long,\ + long,long,long,long,long,\ + long,long,long,long,long +# define DLSTACK_ARGS 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] +# define DLSTACK_SIZE (sizeof(long)*15) +# define DLSTACK_START(sym) +# define DLSTACK_END(sym) +# define DLSTACK_PUSH_C(x) {long v=(long)x; memcpy(sp,&v,sizeof(long)); sp++;} +# define DLSTACK_PUSH_H(x) {long v=(long)x; memcpy(sp,&v,sizeof(long)); sp++;} +# define DLSTACK_PUSH_I(x) {long v=(long)x; memcpy(sp,&v,sizeof(long)); sp++;} +# define DLSTACK_PUSH_L(x) memcpy(sp,&x,sizeof(long)); sp++; +# define DLSTACK_PUSH_P(x) memcpy(sp,&x,sizeof(void*)); sp++; +# define DLSTACK_PUSH_F(x) memcpy(sp,&x,sizeof(float)); sp+=sizeof(float)/sizeof(long); +# define DLSTACK_PUSH_D(x) memcpy(sp,&x,sizeof(double)); sp+=sizeof(double)/sizeof(long); +#else +# define DLSTACK_METHOD "none" +#endif + +extern VALUE rb_mDL; +extern VALUE rb_mDLMemorySpace; +extern VALUE rb_cDLHandle; +extern VALUE rb_cDLSymbol; +extern VALUE rb_cDLPtrData; +extern VALUE rb_cDLStructData; + +extern VALUE rb_eDLError; +extern VALUE rb_eDLTypeError; + +#if defined(LONG2NUM) && (SIZEOF_LONG == SIZEOF_VOIDP) +# define DLLONG2NUM(x) LONG2NUM((long)x) +# define DLNUM2LONG(x) (long)(NUM2LONG(x)) +#else +# define DLLONG2NUM(x) INT2NUM((long)x) +# define DLNUM2LONG(x) (long)(NUM2INT(x)) +#endif + +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; + +#define ALIGN_VOIDP (sizeof(s_voidp) - sizeof(void *)) +#define ALIGN_SHORT (sizeof(s_short) - sizeof(short)) +#define ALIGN_INT (sizeof(s_int) - sizeof(int)) +#define ALIGN_LONG (sizeof(s_long) - sizeof(long)) +#define ALIGN_FLOAT (sizeof(s_float) - sizeof(float)) +#define ALIGN_DOUBLE (sizeof(s_double) - sizeof(double)) + +/* for compatibility */ +#define VOIDP_ALIGN ALIGN_VOIDP +#define SHORT_ALIGN ALIGN_SHORT +#define INT_ALIGN ALIGN_INT +#define LONG_ALIGN ALIGN_LONG +#define FLOAT_ALIGN ALIGN_FLOAT +#define DOUBLE_ALIGN ALIGN_DOUBLE + +#define DLALIGN(ptr,offset,align) {\ + while( (((unsigned long)((char *)ptr + offset)) % align) != 0 ) offset++;\ +} + +typedef void (*freefunc_t)(void *); +#define DLFREEFUNC(func) ((freefunc_t)(func)) + +typedef union { + void* p; + char c; + short h; + int i; + long l; + float f; + double d; + char *s; +} ANY_TYPE; + +struct dl_handle { + void *ptr; + int open; + int enable_close; +}; + +struct sym_data { + void *func; + char *name; + char *type; + int len; +}; + +enum DLPTR_CTYPE { + DLPTR_CTYPE_UNKNOWN, + DLPTR_CTYPE_STRUCT, + DLPTR_CTYPE_UNION +}; + +struct ptr_data { + void *ptr; /* a pointer to the data */ + freefunc_t free; /* free() */ + char *stype; /* array of type specifiers */ + int *ssize; /* size[i] = sizeof(type[i]) > 0 */ + int slen; /* the number of type specifiers */ + ID *ids; + int ids_num; + int ctype; /* DLPTR_CTYPE_UNKNOWN, DLPTR_CTYPE_STRUCT, DLPTR_CTYPE_UNION */ + long size; +}; + +#define RDLPTR(obj) ((struct ptr_data *)(DATA_PTR(obj))) +#define RDLSYM(obj) ((struct sym_data *)(DATA_PTR(obj))) + +void dlfree(void*); +void *dlmalloc(size_t); +void *dlrealloc(void*,size_t); +char *dlstrdup(const char *); +size_t dlsizeof(const char *); + +void *rb_ary2cary(char t, VALUE ary, long *size); + +/* +void rb_dlmem_delete(void *ptr); +void rb_dlmem_aset(void *ptr, VALUE obj); +VALUE rb_dlmem_aref(void *ptr); +*/ + +void dlptr_free(struct ptr_data *data); +void dlptr_init(VALUE val); + +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); +void *rb_dlptr2cptr(VALUE val); + +VALUE rb_dlsym_new(void (*func)(), const char *name, const char *type); +freefunc_t rb_dlsym2csym(VALUE val); + + +#endif /* RUBY_DL_H */ diff --git a/ruby_1_8_6/ext/dl/doc/dl.txt b/ruby_1_8_6/ext/dl/doc/dl.txt new file mode 100644 index 0000000000..893bd21d79 --- /dev/null +++ b/ruby_1_8_6/ext/dl/doc/dl.txt @@ -0,0 +1,266 @@ +=begin + += Ruby/DL + +Ruby/DL provides an interface to the dynamic linker such as dlopen() on UNIX +and LoadLibrary() on Windows. + += Building and Installing + + $ ruby extconf.rb # to create the Makefile + $ make # to build the library 'dl.so' + $ make libtest.so # to build the C library 'libtest.so' for the test script + $ make test # to run the test script + $ make install # to install the library + $ make clean # to remove the created files without Makefile + $ make distclean # to remove the all created files + += Using Ruby/DL + +We should usually use DL::Importable module provided by "dl/import.rb". +It has high-level functions to access library functions. We use +DL::Importable module to extend a module as follows: + + require "dl/import" + module LIBC + extend DL::Importable + end + +Now we can use methods dlload and extern in this module. We load the +libraries using dlload, and define wrapper methods to library functions +using extern respectively as follows: + + module LIBC + extend DL::Importable + dlload "libc.so.6","libm.so.6" + extern "int strlen(char*)" + end + # Note that we should not include the module LIBC from some reason. + +We can call the library function strlen() using LIBC.strlen. If the first +character of given function name is an uppercase, the first character of the +defined method name becomes lowercase. +We can also construct memory images of structures and unions using functions +struct and union which are defined in "dl/struct.rb" as follows: + + require "dl/import" + require "dl/struct" + module LIBC + extend DL::Importable + Timeval = struct [ # define timeval structure. + "long tv_sec", + "long tv_uses", + ] + end + val = LIBC::Timeval.malloc # allocate memory. + +Notice that the above example takes LIBC::Timeval.malloc to allocate memory, +rather than LIBC::Timeval.new. It is because DL::Timeval.new is for wrapping +an object, PtrData, which has already been created. + +We can define a callback using the module function "callback" as follows: + + module Foo + extend DL::Importable + def my_comp(str1,str2) + str1 <=> str2 + end + COMPARE = callback "int my_comp(char*,char*)" + end + +where Foo::COMPARE is a Symbol object which invokes the method "my_comp". + +DL::Importable module is very useful. However, we sometimes encounter a case +that we must directly use low-level functions such as dlsym(). In such case, +we would use DL module functions. They are described in next section. + += DL module + +Module DL consists of three classes, a few module functions and constants. +The class Symbol represents the symbol we can call. The class PtrData +indicates a memory block such as a pointer in C. An object instantiated from +the class Handle keeps a handle to opened library. + +== Constants + +* VERSION +* MAJOR_VERSION +* MINOR_VERSION +* PATCH_VERSION +* RTLD_GLOBAL +* RTLD_LAZY +* RTLD_NOW +* MAX_ARG +* MAX_CBARG +* MAX_CBENT + +== Functions + +* handle = dlopen(lib){|handle| ... } + * is quite equal to `Handle.new(lib)' + +* sym = set_callback(cbtype, entry){|args| ... } +* sym = set_callback(cbtype, entry, proc) + * makes entry-th pre-defined function to call the proc or given block. the + entry-th pre-defined function is specified by cbtype and entry. cbtype is a + prototype of the callback. see also the section `Type specifiers' about + cbtype. + +* sym = get_callback(cbtype, entry) + * returns the Proc object which is given by the above function + `set_callback'. + +* ptr = malloc(size, [free = nil]) + * allocates the size bytes, and returns the pointer as a PtrData object ptr. + +* ptr = strdup(str) + * returns a PtrData object ptr which represents the pointer to a new string + which is a duplicate of the string str. + +* size = sizeof(type) + * returns the size of type. `sizeof("C") + sizeof("L")' is not equal to + `sizeof("CL")'. the latter is assumed to returns the enough size of the + structure `struct foo { char c; long l; }', but the size may not equal to + `sizeof(foo)' of C. + +== Handle class + +* handle = Handle.new(lib){|handle| ... } + * opens a library lib and returns a Handle object handle. if a block is + given, the handle is automatically closed as the block ends. + +* Handle#close + * closes the handle opened by the above Handle.new(lib). + +* sym = Handle#sym(func, prototype = "0"), + sym = Handle#[func, prototype = nil] + + * obtains the pointer to a function called func and returns a Symbol object + or a DataPtr object. prototype is a string which consists of type + specifiers, it indicates the function's prototype. see also the section + `Type specifiers'. + +== Symbol class + +* sym = Symbol.new(addr, type = nil, name = nil) + * creates the Symbol object sym with the type type if type is not nil. addr + is the address where the function is allocated. If type is nil, it returns + a DataPtr object. + +* Symbol::char2type(char) + * takes a character char that represents a type and returns the type + specifier of the C language. + +* str = Symbol#proto() + * returns the function prototype. + +* str = Symbol#name() + * Returns the function name. + +* str = Symbol#cproto(), + str = Symbol#to_s() + * returns the prototype of the C language. + +* str = Symbol#inspect() + * returns the inspectable string. + +* r,rs = Symbol#call(arg1,arg2,...,argN), + r,rs = Symbol#[](arg1,arg2,...,argN) + * calls the function with parameters arg1, arg2, ..., argN. and the result + consists of the return value r and parameters rs. rs is an array. + +* ptr = Symbol#to_ptr + * returns the corresponding PtrData object ptr. + +== PtrData class + +* ptr = PtrData.new(addr, [size = 0, free = nil]) + * returns the PtrData object representing the pointer which indicates the + address addr. GC frees the memory using the free function. + +* PtrData#free=(sym) + * If you specify a symbol object sym, GC frees the memory using the function + represented by sym. + +* sym = PtrData#free + * returns a symbol object sym which is used when GC frees the memory. it + usually configured by `PtrData#free=' or `PtrData.new'. + +* size = PtrData#size, PtrData#size=(size) + * gets and sets allocated size of the memory. + +* ary = PtrData#to_a(type, [size]) + * returns an array of the type which specified with type. type must be one of + 'S','P','I','L','D' and 'F'. + +* str = PtrData#to_s([len]) + * returns a string which length is len. if len is omitted, the end of the + string is '\0'. + +* ptr = PtrData#ptr,+@ + * returns the pointed value as a PtrData object ptr. + +* ptr = PtrData#ref,-@ + * returns the reference as a PtrData object ptr. + +* ptr = PtrData#+ + * returns the PtrData object + +* ptr = PtrData#- + * returns the PtrData object + +* PtrData#struct!(type, *members) + * defines the data type to get access to a structure member with a symbol. + (see also PtrData#[]) + +* PtrData#union!(type, *members) + * defines the data type to get access to a union member with a symbol. (see + also PtrData#[]) + +* val = PtrData#[key], PtrData#[key, num = 0] + * if the key is a string or symbol, this method returns the value of the + structure/union member which has the type defined by PtrData# + {struct!,union!}. if the key is a integer value and this object represents + the pointer ptr, it returns the value of `(ptr + key).to_s(num)' + +* PtrData#[key,num]=val, PtrData#[key]=val + * if the key is a string or symbol, this method substitute the value of the + structure/union member with val. if the key is a integer value and val is a + string, this method copies num bytes of val to the memory area ptr using + memcpy(3). + +== Type specifiers + +the prototype consists of the following type specifiers, first element of +prototype represents the type of return value, and remaining elements represent +the type of each argument. + + C : char + c : char * + H : short + h : short * + I : int + i : int * + L : long + l : long * + F : float + f : float * + D : double + d : double * + S : const char * + s : char * + A : const type[] + a : type[] (allocates new memory space) + P : void * (same as 'p') + p : void * (same as 'P') + 0 : void function (this must be a first character of the prototype) + +the cbtype consists of type specifiers 0, C, I, H, L, F, D, S and P. +for example: + + DL.callback('IPP'){|ptr1,ptr2| + str1 = ptr1.ptr.to_s + str2 = ptr2.ptr.to_s + str1 <=> str2 + } +=end diff --git a/ruby_1_8_6/ext/dl/extconf.rb b/ruby_1_8_6/ext/dl/extconf.rb new file mode 100644 index 0000000000..beb15ab04c --- /dev/null +++ b/ruby_1_8_6/ext/dl/extconf.rb @@ -0,0 +1,193 @@ +require 'mkmf' + +begin # for the exception SystemExit + +$:.unshift File.dirname(__FILE__) +require 'type' + +if( ARGV.include?("--help") ) + print < + --with-callback= + --enable-asm use the embedded assembler for passing arguments. + (this option is available for i386 machine now.) + --enable-dlstack use a stack emulation for constructing function call. +EOF + exit(0) +end + +($CPPFLAGS || $CFLAGS) << " -I." + +if (Config::CONFIG['CC'] =~ /gcc/) # from Win32API + $CFLAGS << " -fno-defer-pop -fno-omit-frame-pointer" +end + +$with_dlstack ||= true +$with_asm = ! $with_dlstack + +$with_type_int = try_cpp(<\n") + exit(1) + end +end +max_arg ||= 6 + +max_callback = with_config("callback","10").to_i +callback_types = DLTYPE.keys.length + + +$dlconfig_h = <] [-d] [] +EOF +end + +while( ARGV[0] ) + case( ARGV[0] ) + when "-r" + ARGV.shift + $recursive = true + when "-R" + ARGV.shift + $recursive = false + when "-l" + ARGV.shift + $insert_require = true + when "-L" + ARGV.shift + $insert_require = false + when "-c" + ARGV.shift + $conly = true + when "-C" + ARGV.shift + $conly = false + when "-f" + ARGV.shift + $force = true + when "-F" + ARGV.shift + $force = false + when "-I" + ARGV.shift + $inc_path << ARGV.shift + when "-d" + ARGV.shift + $DEBUG = true + when "-h","--help" + print_usage() + exit 0 + when /-.*/ + $stderr.print("unknown option '#{ARGV[0]}'.\n") + print_usage() + exit 0 + else + $infilename = ARGV.shift + end +end + +$inc_dir = File.join(CONFIG["prefix"], "lib", "ruby", + CONFIG["MAJOR"] + "." + CONFIG["MINOR"], + "dl") + +class H2RBError < StandardError; end + + +class H2RB + def initialize(inc_dir = nil, inc_path = nil, insert_require = nil) + @inc_path = inc_path || [] + @inc_dir = inc_dir || '.' + @indent = 0 + @parsed_files = [] + @insert_require = insert_require || false + end + + def find_path(file) + if( ! file ) + return nil + end + if( File.exist?(file) ) + if( file[0] == ?/ ) + return file + else + return file + end + end + @inc_path.each{|path| + full = File.join(path, file) + if( File.exist?(full) ) + return full + end + } + return nil + end + + def strip_comment(line) + if( @commented ) + if( e = line.index("*/") ) + line[0..(e+1)] = "" + @commented = false + else + line = "" + end + else + if( s = line.index("/*") ) + if( e = line.index("*/") ) + line[s..(e+1)] = "" + else + line[s..-1] = "" + @commented = true + end + elsif( s = line.index("//") ) + line[s..(-1)] = "" + end + end + + line.gsub!(/\s+$/,"") + return line + end + + def up_indent + @indent += 1 + end + + def down_indent + @indent -= 1 + if( @indent < 0 ) + raise + end + end + + def indent + " " * @indent + end + + def rescue_begin + line = "#{indent}begin" + up_indent + return line + end + + def rescue_nameerror + down_indent + line = [ + "#{indent}rescue NameError => e", + "#{indent} raise e if( $DEBUG )", + "#{indent}end"].join($/) + return line + end + + def parse_enum(line) + if( line =~ /enum\s+(\S+\s+)?\{(.+)\}/ ) + enum_name = $1 + enum_block = $2 + if( enum_name ) + line = "#{indent}# -- enum #{enum_name}\n" + else + line = "#{indent}# -- enum\n" + end + enums = enum_block.split(/,/).collect{|e| e.strip} + i = 0 + enums.each{|elem| + var,val = elem.split(/=/).collect{|e| e.strip} + if( val ) + i = val.to_i + end + line += "#{indent}#{var} = #{i.to_s}\n" + i += 1 + } + line += "#{indent}# -- end of enum" + return line + else + return nil + end + end + + def parse_define(line) + case line + when /^#\s*define\s+(\S+)\(\)/ + line = nil + when /^#\s*define\s+(\S+)\((.+)\)\s+(.+)$/ + if( @conly ) + line = nil + else + defname = $1 + defargs = $2 + defval = $3 + if( !valid_ruby_code?(defval) ) + defval = "nil # #{defval}" + end + if( defname[0,1] =~ /^[A-Z]$/ ) + line = "#{indent}#{defname} = proc{|#{defargs}| #{defval}}" + else + line = [ + "#{indent}def #{defname}(#{defargs})", + "#{indent} #{defval}", + "#{indent}end" + ].join("\n") + end + end + when /^#\s*define\s+(\S+)\((.+)\)$/ + if( @conly ) + line = nil + else + defname = $1 + defargs = $2 + defval = nil + if( !valid_ruby_code?(defval) ) + defval = "nil # #{defval}" + end + if( defname[0,1] =~ /^[A-Z]$/ ) + line = "#{indent}#{defname} = proc{|#{defargs}| #{defval}}" + else + line = [ + "#{indent}def #{defname}(#{defargs})", + "#{indent} #{defval}", + "#{indent}end" + ].join("\n") + end + end + when /^#\s*define\s+(\S+)\s+(.+)$/ + defname = $1 + defval = $2 + if( !valid_ruby_code?(defval) ) + defval = "nil # #{defval}" + end + line = [rescue_begin, "#{indent}#{defname} = #{defval}", rescue_nameerror].join($/) + when /^#\s*define\s+(\S+)$/ + defname = $1 + line = "#{indent}#{defname} = nil" + else + line = nil + end + return line + end + + def parse_undef(line) + case line + when /^#\s*undef\s+([A-Z]\S+)$/ + defname = $1 + line = "#{indent}remove_const(:#{defname})" + when /^#\s*undef\s+(\S+)$/ + defname = $1 + line = "#{indent}#{defname} = nil" + else + line = nil + end + return line + end + + def parse_ifdef(line) + case line + when /^#\s*ifdef\s+(\S+)$/ + defname = $1 + line = [ + rescue_begin, + "#{indent}if( defined?(#{defname}) && ! #{defname}.nil? )"].join($/) + else + line = nil + end + return line + end + + def parse_ifndef(line) + case line + when /^#\s*ifndef\s+(\S+)$/ + defname = $1 + line = [ + rescue_begin, + "#{indent}if( ! defined?(#{defname}) || #{defname}.nil? )"].join($/) + else + line = nil + end + return line + end + + def parse_if(line) + case line + when /^#\s*if\s+(.+)$/ + cond = $1 + cond.gsub!(/defined(.+)/){ "defined?(#{$1}) && ! #{$1}.nil?" } + if( valid_ruby_code?(cond) ) + line = "#{indent}if( #{cond} )" + else + line = "#{indent}if( false ) # #{cond}" + end + line = [rescue_begin, line].join($/) + else + line = nil + end + return line + end + + def parse_elif(line) + case line + when /^#\s*elif\s+(.+)$/ + cond = $1 + cond.gsub!("defined","defined?") + line = "#{indent}elsif( #{cond} )" + else + line = nil + end + return line + end + + def parse_else(line) + case line + when /^#\s*else\s*/ + line = "#{indent}else" + else + line = nil + end + return line + end + + def parse_endif(line) + case line + when /^#\s*endif\s*$/ + line = ["#{indent}end", rescue_nameerror].join($/) + else + line = nil + end + return line + end + + def parse_include(line) + if( ! @insert_require ) + return nil + end + + file = nil + case line + when /^#\s*include "(.+)"$/ + file = $1 + line = "#{indent}require '#{file}'" + when /^#\s*include \<(.+)\>$/ + file = $1 + line = "#{indent}require '#{file}'" + else + line = nil + end + if( @recursive && file && (!@parsed_files.include?(file)) ) + parse(file, @recursive, @force, @conly) + end + return line + end + + + def open_files(infilename) + if( ! infilename ) + return [$stdin, $stdout] + end + + old_infilename = infilename + infilename = find_path(infilename) + if( ! infilename ) + $stderr.print("'#{old_infilename}' was not found.\n") + return [nil,nil] + end + + if( infilename ) + if( infilename[0,1] == '/' ) + outfilename = File.join(@inc_dir, infilename[1..-1] + ".rb") + else + outfilename = infilename + ".rb" + end + File.mkpath(File.dirname(outfilename)) + else + outfilename = nil + end + + if( infilename ) + fin = File.open(infilename,"r") + else + fin = $stdin + end + if( outfilename ) + if( File.exist?(outfilename) && (!@force) ) + $stderr.print("'#{outfilename}' have already existed.\n") + return [fin, nil] + end + fout = File.open(outfilename,"w") + else + fout = $stdout + end + + $stderr.print("#{infilename} -> #{outfilename}\n") + if( fout ) + dir = File.dirname(outfilename) + if( dir[0,1] != "." && dir != "" ) + fout.print("if( ! $LOAD_PATH.include?('#{dir}') )\n", + " $LOAD_PATH.push('#{dir}')\n", + "end\n") + end + end + return [fin,fout] + end + + def parse(infilename = nil, recursive = false, force = false, conly = false) + @commented = false + @recursive = recursive + @force = force + @conly = conly + @parsed_files << infilename + + fin,fout = open_files(infilename) + if( !fin ) + return + end + + begin + line_number = 0 + pre_line = nil + fin.each_line{|line| + line_number += 1 + line.chop! + if( $DEBUG ) + $stderr.print("#{line_number}:(#{@indent}):", line, "\n") + end + + if( pre_line ) + line = pre_line + line + pre_line = nil + end + + if( line[-1,1] == "\\" ) + pre_line = line[0..-2] + next + end + + if( eidx = line.index("enum ") ) + pre_line = line[eidx .. -1] + if( i = line.index("{") && j = line.index("}") ) + line = line[0..j] + pre_line = nil + else + next + end + end + + line = strip_comment(line) + case line + when /^enum\s/ + line = parse_enum(line) + when /^#\s*define\s/ + line = parse_define(line) + when /^#\s*undef\s/ + line = parse_undef(line) + when /^#\s*ifdef\s/ + line = parse_ifdef(line) + up_indent + when /^#\s*ifndef\s/ + line = parse_ifndef(line) + up_indent + when /^#\s*if\s/ + line = parse_if(line) + up_indent + when /^#\s*elif\s/ + down_indent + line = parse_elif(line) + up_indent + when /^#\s*else/ + down_indent + line = parse_else(line) + up_indent + when /^#\s*endif/ + down_indent + line = parse_endif(line) + when /^#\s*include\s/ + line = parse_include(line) + else + line = nil + end + if( line && fout ) + fout.print(line, " # #{line_number}",$/) + end + } + ensure + fin.close if fin + fout.close if fout + end + end +end + +h2rb = H2RB.new($inc_dir, $inc_path, $insert_require) +h2rb.parse($infilename, $recursive, $force, $conly) diff --git a/ruby_1_8_6/ext/dl/handle.c b/ruby_1_8_6/ext/dl/handle.c new file mode 100644 index 0000000000..69d47caac0 --- /dev/null +++ b/ruby_1_8_6/ext/dl/handle.c @@ -0,0 +1,215 @@ +/* -*- C -*- + * $Id$ + */ + +#include +#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, "11", &lib, &flag)) { + 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_eRuntimeError, "%s", err); + } +#else + if (!ptr) { + err = dlerror(); + rb_raise(rb_eRuntimeError, "%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 DLLONG2NUM(dlhandle); +} + +VALUE +rb_dlhandle_to_ptr(VALUE self) +{ + struct dl_handle *dlhandle; + + Data_Get_Struct(self, struct dl_handle, dlhandle); + return rb_dlptr_new(dlhandle, sizeof(dlhandle), 0); +} + +VALUE +rb_dlhandle_sym(int argc, VALUE argv[], VALUE self) +{ + VALUE sym, type; + void (*func)(); + VALUE val; + struct dl_handle *dlhandle; + void *handle; + const char *name, *stype; + const char *err; + + rb_secure(2); + if (rb_scan_args(argc, argv, "11", &sym, &type) == 2) { + SafeStringValue(type); + stype = StringValuePtr(type); + } + else{ + stype = NULL; + } + + if (sym == Qnil) { +#if defined(RTLD_NEXT) + name = RTLD_NEXT; +#else + name = NULL; +#endif + } + else{ + SafeStringValue(sym); + name = StringValuePtr(sym); + } + + Data_Get_Struct(self, struct dl_handle, dlhandle); + if (!dlhandle->open) { + rb_raise(rb_eRuntimeError, "closed handle"); + } + handle = dlhandle->ptr; + + func = dlsym(handle, name); +#if defined(HAVE_DLERROR) + if (!func && (err = dlerror())) +#else + if (!func) +#endif + { +#if defined(__CYGWIN__) || defined(WIN32) || defined(__MINGW32__) + { + int len = strlen(name); + char *name_a = (char*)dlmalloc(len+2); + strcpy(name_a, name); + name_a[len] = 'A'; + name_a[len+1] = '\0'; + func = dlsym(handle, name_a); + dlfree(name_a); +#if defined(HAVE_DLERROR) + if (!func && (err = dlerror())) +#else + if (!func) +#endif + { + rb_raise(rb_eRuntimeError, "unknown symbol \"%sA\"", name); + } + } +#else + rb_raise(rb_eRuntimeError, "unknown symbol \"%s\"", name); +#endif + } + val = rb_dlsym_new(func, name, stype); + + return val; +} + +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, "to_ptr", rb_dlhandle_to_ptr, 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); +} diff --git a/ruby_1_8_6/ext/dl/install.rb b/ruby_1_8_6/ext/dl/install.rb new file mode 100644 index 0000000000..69b1834301 --- /dev/null +++ b/ruby_1_8_6/ext/dl/install.rb @@ -0,0 +1,49 @@ +require 'mkmf' +require 'ftools' + +SO_LIBS = ["dl.so"] + +$ruby_version = CONFIG['MAJOR'] + "." + CONFIG['MINOR'] +$prefix = CONFIG['prefix'] +$libdir = File.join($prefix,'lib') +$rubylibdir = File.join($libdir, 'ruby', $ruby_version) +$arch = CONFIG['arch'] +$archdir = File.join($rubylibdir, $arch) + +def find(dir, match = /./) + Dir.chdir(dir) + files = [] + Dir.new(".").each{|file| + if( file != "." && file != ".." ) + case File.ftype(file) + when "file" + if( file =~ match ) + files.push(File.join(dir,file)) + end + when "directory" + files += find(file, match).collect{|f| File.join(dir,f)} + end + end + } + Dir.chdir("..") + return files +end + +def install() + rb_files = find(File.join(".","lib"), /.rb$/) + + SO_LIBS.each{|f| + File.makedirs($rubylibdir, "#{$archdir}") + File.install(f, File.join($archdir,f), 0555, true) + } + + rb_files.each{|f| + origfile = f + instfile = File.join($rubylibdir, origfile.sub("./lib/","")) + instdir = File.dirname(instfile) + File.makedirs(instdir) + File.install(origfile, instfile, 0644, true) + } +end + +install() diff --git a/ruby_1_8_6/ext/dl/lib/dl/import.rb b/ruby_1_8_6/ext/dl/lib/dl/import.rb new file mode 100644 index 0000000000..01ee2490e8 --- /dev/null +++ b/ruby_1_8_6/ext/dl/lib/dl/import.rb @@ -0,0 +1,225 @@ +# -*- ruby -*- + +require 'dl' +require 'dl/types' + +module DL + module Importable + LIB_MAP = {} + + module Internal + def init_types() + @types ||= ::DL::Types.new + end + + def init_sym() + @SYM ||= {} + end + + def [](name) + return @SYM[name.to_s][0] + end + + def dlload(*libnames) + if( !defined?(@LIBS) ) + @LIBS = [] + end + libnames.each{|libname| + if( !LIB_MAP[libname] ) + LIB_MAP[libname] = DL.dlopen(libname) + end + @LIBS.push(LIB_MAP[libname]) + } + end + alias dllink :dlload + + def parse_cproto(proto) + proto = proto.gsub(/\s+/, " ").strip + case proto + when /^([\d\w\*_\s]+)\(([\d\w\*_\s\,\[\]]*)\)$/ + ret = $1 + args = $2.strip() + ret = ret.split(/\s+/) + args = args.split(/\s*,\s*/) + func = ret.pop() + if( func =~ /^\*/ ) + func.gsub!(/^\*+/,"") + ret.push("*") + end + ret = ret.join(" ") + return [func, ret, args] + else + raise(RuntimeError,"can't parse the function prototype: #{proto}") + end + end + + # example: + # extern "int strlen(char*)" + # + def extern(proto) + func,ret,args = parse_cproto(proto) + return import(func, ret, args) + end + + # example: + # callback "int method_name(int, char*)" + # + def callback(proto) + func,ret,args = parse_cproto(proto) + + init_types() + init_sym() + + rty,renc,rdec = @types.encode_return_type(ret) + if( !rty ) + raise(TypeError, "unsupported type: #{ret}") + end + ty,enc,dec = encode_argument_types(args) + symty = rty + ty + + module_eval("module_function :#{func}") + sym = module_eval([ + "DL::callback(\"#{symty}\"){|*args|", + " sym,rdec,enc,dec = @SYM['#{func}']", + " args = enc.call(args) if enc", + " r,rs = #{func}(*args)", + " r = renc.call(r) if rdec", + " rs = dec.call(rs) if (dec && rs)", + " @retval = r", + " @args = rs", + " r", + "}", + ].join("\n")) + + @SYM[func] = [sym,rdec,enc,dec] + + return sym + end + + # example: + # typealias("uint", "unsigned int") + # + def typealias(alias_type, ty1, enc1=nil, dec1=nil, ty2=nil, enc2=nil, dec2=nil) + init_types() + @types.typealias(alias_type, ty1, enc1, dec1, + ty2||ty1, enc2, dec2) + end + + # example: + # symbol "foo_value" + # symbol "foo_func", "IIP" + # + def symbol(name, ty = nil) + sym = nil + @LIBS.each{|lib| + begin + if( ty ) + sym = lib[name, ty] + else + sym = lib[name] + end + rescue + next + end + } + if( !sym ) + raise(RuntimeError, "can't find the symbol `#{name}'") + end + return sym + end + + # example: + # import("get_length", "int", ["void*", "int"]) + # + def import(name, rettype, argtypes = nil) + init_types() + init_sym() + + rty,_,rdec = @types.encode_return_type(rettype) + if( !rty ) + raise(TypeError, "unsupported type: #{rettype}") + end + ty,enc,dec = encode_argument_types(argtypes) + symty = rty + ty + + sym = symbol(name, symty) + + mname = name.dup + if( ?A <= mname[0] && mname[0] <= ?Z ) + mname[0,1] = mname[0,1].downcase + end + @SYM[mname] = [sym,rdec,enc,dec] + + module_eval [ + "def #{mname}(*args)", + " sym,rdec,enc,dec = @SYM['#{mname}']", + " args = enc.call(args) if enc", + if( $DEBUG ) + " p \"[DL] call #{mname} with \#{args.inspect}\"" + else + "" + end, + " r,rs = sym.call(*args)", + if( $DEBUG ) + " p \"[DL] retval=\#{r.inspect} args=\#{rs.inspect}\"" + else + "" + end, + " r = rdec.call(r) if rdec", + " rs = dec.call(rs) if dec", + " @retval = r", + " @args = rs", + " return r", + "end", + "module_function :#{mname}", + ].join("\n") + + return sym + end + + def _args_ + return @args + end + + def _retval_ + return @retval + end + + def encode_argument_types(tys) + init_types() + encty = [] + enc = nil + dec = nil + tys.each_with_index{|ty,idx| + ty,c1,c2 = @types.encode_argument_type(ty) + if( !ty ) + raise(TypeError, "unsupported type: #{ty}") + end + encty.push(ty) + if( enc ) + if( c1 ) + conv1 = enc + enc = proc{|v| v = conv1.call(v); v[idx] = c1.call(v[idx]); v} + end + else + if( c1 ) + enc = proc{|v| v[idx] = c1.call(v[idx]); v} + end + end + if( dec ) + if( c2 ) + conv2 = dec + dec = proc{|v| v = conv2.call(v); v[idx] = c2.call(v[idx]); v} + end + else + if( c2 ) + dec = proc{|v| v[idx] = c2.call(v[idx]); v} + end + end + } + return [encty.join, enc, dec] + end + end # end of Internal + include Internal + end # end of Importable +end diff --git a/ruby_1_8_6/ext/dl/lib/dl/struct.rb b/ruby_1_8_6/ext/dl/lib/dl/struct.rb new file mode 100644 index 0000000000..33f303fe22 --- /dev/null +++ b/ruby_1_8_6/ext/dl/lib/dl/struct.rb @@ -0,0 +1,149 @@ +# -*- ruby -*- + +require 'dl' +require 'dl/import' + +module DL + module Importable + module Internal + def define_struct(contents) + init_types() + Struct.new(@types, contents) + end + alias struct define_struct + + def define_union(contents) + init_types() + Union.new(@types, contents) + end + alias union define_union + + class Memory + def initialize(ptr, names, ty, len, enc, dec) + @ptr = ptr + @names = names + @ty = ty + @len = len + @enc = enc + @dec = dec + + # define methods + @names.each{|name| + instance_eval [ + "def #{name}", + " v = @ptr[\"#{name}\"]", + " if( @len[\"#{name}\"] )", + " v = v.collect{|x| @dec[\"#{name}\"] ? @dec[\"#{name}\"].call(x) : x }", + " else", + " v = @dec[\"#{name}\"].call(v) if @dec[\"#{name}\"]", + " end", + " return v", + "end", + "def #{name}=(v)", + " if( @len[\"#{name}\"] )", + " v = v.collect{|x| @enc[\"#{name}\"] ? @enc[\"#{name}\"].call(x) : x }", + " else", + " v = @enc[\"#{name}\"].call(v) if @enc[\"#{name}\"]", + " end", + " @ptr[\"#{name}\"] = v", + " return v", + "end", + ].join("\n") + } + end + + def to_ptr + return @ptr + end + + def size + return @ptr.size + end + end + + class Struct + def initialize(types, contents) + @names = [] + @ty = {} + @len = {} + @enc = {} + @dec = {} + @size = 0 + @tys = "" + @types = types + parse(contents) + end + + def size + return @size + end + + def members + return @names + end + + # ptr must be a PtrData object. + def new(ptr) + ptr.struct!(@tys, *@names) + mem = Memory.new(ptr, @names, @ty, @len, @enc, @dec) + return mem + end + + def malloc(size = nil) + if( !size ) + size = @size + end + ptr = DL::malloc(size) + return new(ptr) + end + + def parse(contents) + contents.each{|elem| + name,ty,num,enc,dec = parse_elem(elem) + @names.push(name) + @ty[name] = ty + @len[name] = num + @enc[name] = enc + @dec[name] = dec + if( num ) + @tys += "#{ty}#{num}" + else + @tys += ty + end + } + @size = DL.sizeof(@tys) + end + + def parse_elem(elem) + elem.strip! + case elem + when /^([\w\d_\*]+)([\*\s]+)([\w\d_]+)$/ + ty = ($1 + $2).strip + name = $3 + num = nil; + when /^([\w\d_\*]+)([\*\s]+)([\w\d_]+)\[(\d+)\]$/ + ty = ($1 + $2).strip + name = $3 + num = $4.to_i + else + raise(RuntimeError, "invalid element: #{elem}") + end + ty,enc,dec = @types.encode_struct_type(ty) + if( !ty ) + raise(TypeError, "unsupported type: #{ty}") + end + return [name,ty,num,enc,dec] + end + end # class Struct + + class Union < Struct + def new + ptr = DL::malloc(@size) + ptr.union!(@tys, *@names) + mem = Memory.new(ptr, @names, @ty, @len, @enc, @dec) + return mem + end + end + end # module Internal + end # module Importable +end # module DL diff --git a/ruby_1_8_6/ext/dl/lib/dl/types.rb b/ruby_1_8_6/ext/dl/lib/dl/types.rb new file mode 100644 index 0000000000..1144917dae --- /dev/null +++ b/ruby_1_8_6/ext/dl/lib/dl/types.rb @@ -0,0 +1,245 @@ +# -*- ruby -*- + +require 'dl' + +module DL + class Types + TYPES = [ + # FORMAT: + # ["alias name", + # "type name", encoding_method, decoding_method, for function prototypes + # "type name", encoding_method, decoding_method] for structures (not implemented) + + # for Windows + ["DWORD", "unsigned long", nil, nil, + "unsigned long", nil, nil], + ["PDWORD", "unsigned long *", nil, nil, + "unsigned long *", nil, nil], + ["WORD", "unsigned short", nil, nil, + "unsigned short", nil, nil], + ["PWORD", "unsigned int *", nil, nil, + "unsigned int *", nil, nil], + ["BYTE", "unsigned char", nil, nil, + "unsigned char", nil, nil], + ["PBYTE", "unsigned char *", nil, nil, + "unsigned char *", nil, nil], + ["BOOL", "ibool", nil, nil, + "ibool", nil, nil], + ["ATOM", "int", nil, nil, + "int", nil, nil], + ["BYTE", "unsigned char", nil, nil, + "unsigned char", nil, nil], + ["PBYTE", "unsigned char *", nil, nil, + "unsigned char *", nil, nil], + ["UINT", "unsigned int", nil, nil, + "unsigned int", nil, nil], + ["ULONG", "unsigned long", nil, nil, + "unsigned long", nil, nil], + ["UCHAR", "unsigned char", nil, nil, + "unsigned char", nil, nil], + ["HANDLE", "unsigned long", nil, nil, + "unsigned long", nil, nil], + ["PHANDLE","void*", nil, nil, + "void*", nil, nil], + ["PVOID", "void*", nil, nil, + "void*", nil, nil], + ["LPCSTR", "char*", nil, nil, + "char*", nil, nil], + ["HDC", "unsigned int", nil, nil, + "unsigned int", nil, nil], + ["HWND", "unsigned int", nil, nil, + "unsigned int", nil, nil], + + # Others + ["uint", "unsigned int", nil, nil, + "unsigned int", nil, nil], + ["u_int", "unsigned int", nil, nil, + "unsigned int", nil, nil], + ["ulong", "unsigned long", nil, nil, + "unsigned long", nil, nil], + ["u_long", "unsigned long", nil, nil, + "unsigned long", nil, nil], + + # DL::Importable primitive types + ["ibool", + "I", + proc{|v| v ? 1 : 0}, + proc{|v| (v != 0) ? true : false}, + "I", + proc{|v| v ? 1 : 0 }, + proc{|v| (v != 0) ? true : false} ], + ["cbool", + "C", + proc{|v| v ? 1 : 0}, + proc{|v| (v != 0) ? true : false}, + "C", + proc{|v,len| v ? 1 : 0}, + proc{|v,len| (v != 0) ? true : false}], + ["lbool", + "L", + proc{|v| v ? 1 : 0}, + proc{|v| (v != 0) ? true : false}, + "L", + proc{|v,len| v ? 1 : 0}, + proc{|v,len| (v != 0) ? true : false}], + ["unsigned char", + "C", + proc{|v| [v].pack("C").unpack("c")[0]}, + proc{|v| [v].pack("c").unpack("C")[0]}, + "C", + proc{|v| [v].pack("C").unpack("c")[0]}, + proc{|v| [v].pack("c").unpack("C")[0]}], + ["unsigned short", + "H", + proc{|v| [v].pack("S").unpack("s")[0]}, + proc{|v| [v].pack("s").unpack("S")[0]}, + "H", + proc{|v| [v].pack("S").unpack("s")[0]}, + proc{|v| [v].pack("s").unpack("S")[0]}], + ["unsigned int", + "I", + proc{|v| [v].pack("I").unpack("i")[0]}, + proc{|v| [v].pack("i").unpack("I")[0]}, + "I", + proc{|v| [v].pack("I").unpack("i")[0]}, + proc{|v| [v].pack("i").unpack("I")[0]}], + ["unsigned long", + "L", + proc{|v| [v].pack("L").unpack("l")[0]}, + proc{|v| [v].pack("l").unpack("L")[0]}, + "L", + proc{|v| [v].pack("L").unpack("l")[0]}, + proc{|v| [v].pack("l").unpack("L")[0]}], + ["unsigned char ref", + "c", + proc{|v| [v].pack("C").unpack("c")[0]}, + proc{|v| [v].pack("c").unpack("C")[0]}, + nil, nil, nil], + ["unsigned int ref", + "i", + proc{|v| [v].pack("I").unpack("i")[0]}, + proc{|v| [v].pack("i").unpack("I")[0]}, + nil, nil, nil], + ["unsigned long ref", + "l", + proc{|v| [v].pack("L").unpack("l")[0]}, + proc{|v| [v].pack("l").unpack("L")[0]}, + nil, nil, nil], + ["char ref", "c", nil, nil, + nil, nil, nil], + ["short ref", "h", nil, nil, + nil, nil, nil], + ["int ref", "i", nil, nil, + nil, nil, nil], + ["long ref", "l", nil, nil, + nil, nil, nil], + ["float ref", "f", nil, nil, + nil, nil, nil], + ["double ref","d", nil, nil, + nil, nil, nil], + ["char", "C", nil, nil, + "C", nil, nil], + ["short", "H", nil, nil, + "H", nil, nil], + ["int", "I", nil, nil, + "I", nil, nil], + ["long", "L", nil, nil, + "L", nil, nil], + ["float", "F", nil, nil, + "F", nil, nil], + ["double", "D", nil, nil, + "D", nil, nil], + [/^char\s*\*$/,"s",nil, nil, + "S",nil, nil], + [/^const char\s*\*$/,"S",nil, nil, + "S",nil, nil], + [/^.+\*$/, "P", nil, nil, + "P", nil, nil], + [/^.+\[\]$/, "a", nil, nil, + "a", nil, nil], + ["void", "0", nil, nil, + nil, nil, nil], + ] + + def initialize + init_types() + end + + def typealias(ty1, ty2, enc=nil, dec=nil, ty3=nil, senc=nil, sdec=nil) + @TYDEFS.unshift([ty1, ty2, enc, dec, ty3, senc, sdec]) + end + + def init_types + @TYDEFS = TYPES.dup + end + + def encode_argument_type(alias_type) + proc_encode = nil + proc_decode = nil + @TYDEFS.each{|aty,ty,enc,dec,_,_,_| + if( (aty.is_a?(Regexp) && (aty =~ alias_type)) || (aty == alias_type) ) + alias_type = alias_type.gsub(aty,ty) if ty + alias_type.strip! if alias_type + if( proc_encode ) + if( enc ) + conv1 = proc_encode + proc_encode = proc{|v| enc.call(conv1.call(v))} + end + else + if( enc ) + proc_encode = enc + end + end + if( proc_decode ) + if( dec ) + conv2 = proc_decode + proc_decode = proc{|v| dec.call(conv2.call(v))} + end + else + if( dec ) + proc_decode = dec + end + end + end + } + return [alias_type, proc_encode, proc_decode] + end + + def encode_return_type(ty) + ty, enc, dec = encode_argument_type(ty) + return [ty, enc, dec] + end + + def encode_struct_type(alias_type) + proc_encode = nil + proc_decode = nil + @TYDEFS.each{|aty,_,_,_,ty,enc,dec| + if( (aty.is_a?(Regexp) && (aty =~ alias_type)) || (aty == alias_type) ) + alias_type = alias_type.gsub(aty,ty) if ty + alias_type.strip! if alias_type + if( proc_encode ) + if( enc ) + conv1 = proc_encode + proc_encode = proc{|v| enc.call(conv1.call(v))} + end + else + if( enc ) + proc_encode = enc + end + end + if( proc_decode ) + if( dec ) + conv2 = proc_decode + proc_decode = proc{|v| dec.call(conv2.call(v))} + end + else + if( dec ) + proc_decode = dec + end + end + end + } + return [alias_type, proc_encode, proc_decode] + end + end # end of Types +end diff --git a/ruby_1_8_6/ext/dl/lib/dl/win32.rb b/ruby_1_8_6/ext/dl/lib/dl/win32.rb new file mode 100644 index 0000000000..0fed47c324 --- /dev/null +++ b/ruby_1_8_6/ext/dl/lib/dl/win32.rb @@ -0,0 +1,25 @@ +# -*- ruby -*- + +require 'dl' + +class Win32API + DLL = {} + + def initialize(dllname, func, import, export = "0") + prototype = (export + import.to_s).tr("VPpNnLlIi", "0SSI").sub(/^(.)0*$/, '\1') + handle = DLL[dllname] ||= DL::Handle.new(dllname) + @sym = handle.sym(func, prototype) + end + + def call(*args) + import = @sym.proto.split("", 2)[1] + args.each_with_index do |x, i| + args[i] = nil if x == 0 and import[i] == ?S + args[i], = [x].pack("I").unpack("i") if import[i] == ?I + end + ret, = @sym.call(*args) + return ret || 0 + end + + alias Call call +end diff --git a/ruby_1_8_6/ext/dl/mkcall.rb b/ruby_1_8_6/ext/dl/mkcall.rb new file mode 100644 index 0000000000..6a85570152 --- /dev/null +++ b/ruby_1_8_6/ext/dl/mkcall.rb @@ -0,0 +1,62 @@ +# -*- ruby -*- + +require 'mkmf' +$:.unshift File.dirname(__FILE__) +require 'type' +require 'dlconfig' + +def output_arg(x,i) + "args[#{i}].#{DLTYPE[x][:stmem]}" +end + +def output_args(types) + t = [] + types[1..-1].each_with_index{|x,i| t.push(output_arg(x,i))} + t.join(",") +end + +def output_callfunc(types) + t = types[0] + stmem = DLTYPE[t][:stmem] + ctypes = types2ctypes(types) + if( t == VOID ) + callstm = "(*f)(#{output_args(types)})" + else + callstm = "ret.#{stmem} = (*f)(#{output_args(types)})" + end + [ "{", + "#{ctypes[0]} (*f)(#{ctypes[1..-1].join(',')}) = func;", + "#{callstm};", + "}"].join(" ") +end + +def output_case(types) + num = types2num(types) + callfunc_stm = output_callfunc(types) +<len >= #{argc.to_s} )", + " rb_raise(rb_eArgError, \"too many arguments\");", + " rb_dl_scan_callback_args(buff, RSTRING(proto)->ptr, &argc, argv);", + " retval = rb_funcall2(proc, id_call, argc, argv);", + "", + ret_code, + "}", + ].join("\n") + + return code +end + +DLTYPE.keys.sort.each{|t| + for n in 0..(MAX_CALLBACK - 1) + print(mkfunc(t, n, 15), "\n\n") + end +} diff --git a/ruby_1_8_6/ext/dl/mkcbtable.rb b/ruby_1_8_6/ext/dl/mkcbtable.rb new file mode 100644 index 0000000000..165c4bdc88 --- /dev/null +++ b/ruby_1_8_6/ext/dl/mkcbtable.rb @@ -0,0 +1,18 @@ +# -*- ruby -*- + +require 'mkmf' +$:.unshift File.dirname(__FILE__) +require 'type' +require 'dlconfig' + +def mktable(rettype, fnum, argc) + code = + "rb_dl_callback_table[#{rettype}][#{fnum}] = &rb_dl_callback_func_#{rettype.to_s}_#{fnum};" + return code +end + +DLTYPE.keys.sort.each{|t| + for n in 0..(MAX_CALLBACK - 1) + print(mktable(t, n, 15), "\n") + end +} diff --git a/ruby_1_8_6/ext/dl/ptr.c b/ruby_1_8_6/ext/dl/ptr.c new file mode 100644 index 0000000000..5112151733 --- /dev/null +++ b/ruby_1_8_6/ext/dl/ptr.c @@ -0,0 +1,1068 @@ +/* -*- C -*- + * $Id$ + */ + +#include +#include +#include /* for ruby version code */ +#include "dl.h" + +VALUE rb_cDLPtrData; +VALUE rb_mDLMemorySpace; +static VALUE DLMemoryTable; + +#ifndef T_SYMBOL +# define T_SYMBOL T_FIXNUM +#endif + +#if RUBY_VERSION_CODE < 171 +static VALUE +rb_hash_delete(VALUE hash, VALUE key) +{ + return rb_funcall(hash, rb_intern("delete"), 1, key); +} +#endif + +static void +rb_dlmem_delete(void *ptr) +{ + rb_secure(4); + rb_hash_delete(DLMemoryTable, DLLONG2NUM(ptr)); +} + +static void +rb_dlmem_aset(void *ptr, VALUE obj) +{ + if (obj == Qnil) { + rb_dlmem_delete(ptr); + } + else{ + rb_hash_aset(DLMemoryTable, DLLONG2NUM(ptr), DLLONG2NUM(obj)); + } +} + +static VALUE +rb_dlmem_aref(void *ptr) +{ + VALUE val; + + val = rb_hash_aref(DLMemoryTable, DLLONG2NUM(ptr)); + return val == Qnil ? Qnil : (VALUE)DLNUM2LONG(val); +} + +void +dlptr_free(struct ptr_data *data) +{ + if (data->ptr) { + DEBUG_CODE({ + printf("dlptr_free(): removing the pointer `0x%x' from the MemorySpace\n", + data->ptr); + }); + rb_dlmem_delete(data->ptr); + if (data->free) { + DEBUG_CODE({ + printf("dlptr_free(): 0x%x(data->ptr:0x%x)\n",data->free,data->ptr); + }); + (*(data->free))(data->ptr); + } + } + if (data->stype) dlfree(data->stype); + if (data->ssize) dlfree(data->ssize); + if (data->ids) dlfree(data->ids); +} + +void +dlptr_init(VALUE val) +{ + struct ptr_data *data; + + Data_Get_Struct(val, struct ptr_data, data); + DEBUG_CODE({ + printf("dlptr_init(): add the pointer `0x%x' to the MemorySpace\n", + data->ptr); + }); + rb_dlmem_aset(data->ptr, val); + 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); + if (ptr) { + val = rb_dlmem_aref(ptr); + if (val == Qnil) { + val = Data_Make_Struct(klass, struct ptr_data, + 0, dlptr_free, data); + data->ptr = ptr; + data->free = func; + data->ctype = DLPTR_CTYPE_UNKNOWN; + data->stype = NULL; + data->ssize = NULL; + data->slen = 0; + data->size = size; + data->ids = NULL; + data->ids_num = 0; + dlptr_init(val); + } + else{ + if (func) { + Data_Get_Struct(val, struct ptr_data, data); + data->free = func; + } + } + } + else{ + val = Qnil; + } + + return val; +} + +VALUE +rb_dlptr_new(void *ptr, long size, freefunc_t func) +{ + return rb_dlptr_new2(rb_cDLPtrData, ptr, size, func); +} + +VALUE +rb_dlptr_malloc(long size, freefunc_t func) +{ + void *ptr; + + rb_secure(4); + ptr = dlmalloc((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_cDLPtrData)) { + 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, 0, dlptr_free, data); + data->ptr = 0; + data->free = 0; + data->ctype = DLPTR_CTYPE_UNKNOWN; + data->stype = NULL; + data->ssize = NULL; + data->slen = 0; + data->size = 0; + data->ids = NULL; + data->ids_num = 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*)(DLNUM2LONG(rb_Integer(ptr))); + break; + case 2: + p = (void*)(DLNUM2LONG(rb_Integer(ptr))); + s = DLNUM2LONG(size); + break; + case 3: + p = (void*)(DLNUM2LONG(rb_Integer(ptr))); + s = DLNUM2LONG(size); + f = rb_dlsym2csym(sym); + 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 = NULL; + + switch (rb_scan_args(argc, argv, "11", &size, &sym)) { + case 1: + s = NUM2INT(size); + break; + case 2: + s = NUM2INT(size); + f = rb_dlsym2csym(sym); + 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 DLLONG2NUM(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; + + Data_Get_Struct(self, struct ptr_data, data); + + data->free = DLFREEFUNC(rb_dlsym2csym(val)); + + return Qnil; +} + +VALUE +rb_dlptr_free_get(VALUE self) +{ + struct ptr_data *pdata; + + Data_Get_Struct(self, struct ptr_data, pdata); + + return rb_dlsym_new(pdata->free,"(free)","0P"); +} + +VALUE +rb_dlptr_to_array(int argc, VALUE argv[], VALUE self) +{ + struct ptr_data *data; + int n; + int i; + int t; + VALUE ary; + VALUE type, size; + + Data_Get_Struct(self, struct ptr_data, data); + + switch (rb_scan_args(argc, argv, "11", &type, &size)) { + case 2: + t = StringValuePtr(type)[0]; + n = NUM2INT(size); + break; + case 1: + t = StringValuePtr(type)[0]; + switch (t) { + case 'C': + n = data->size; + break; + case 'H': + n = data->size / sizeof(short); + break; + case 'I': + n = data->size / sizeof(int); + break; + case 'L': + n = data->size / sizeof(long); + break; + case 'F': + n = data->size / sizeof(float); + break; + case 'D': + n = data->size / sizeof(double); + break; + case 'P': case 'p': + n = data->size / sizeof(void*); + break; + case 'S': case 's': + for (n=0; ((void**)(data->ptr))[n]; n++) {}; + break; + default: + n = 0; + } + break; + default: + rb_bug("rb_dlptr_to_array"); + } + + ary = rb_ary_new(); + + for (i=0; i < n; i++) { + switch (t) { + case 'C': + rb_ary_push(ary, INT2NUM(((char*)(data->ptr))[i])); + break; + case 'H': + rb_ary_push(ary, INT2NUM(((short*)(data->ptr))[i])); + break; + case 'I': + rb_ary_push(ary, INT2NUM(((int*)(data->ptr))[i])); + break; + case 'L': + rb_ary_push(ary, DLLONG2NUM(((long*)(data->ptr))[i])); + break; + case 'D': + rb_ary_push(ary, rb_float_new(((double*)(data->ptr))[i])); + break; + case 'F': + rb_ary_push(ary, rb_float_new(((float*)(data->ptr))[i])); + break; + case 'S': + { + char *str = ((char**)(data->ptr))[i]; + if (str) { + rb_ary_push(ary, rb_tainted_str_new2(str)); + } + else{ + rb_ary_push(ary, Qnil); + } + } + break; + case 's': + { + char *str = ((char**)(data->ptr))[i]; + if (str) { + rb_ary_push(ary, rb_tainted_str_new2(str)); + xfree(str); + } + else{ + rb_ary_push(ary, Qnil); + } + } + break; + case 'P': + rb_ary_push(ary, rb_dlptr_new(((void**)(data->ptr))[i],0,0)); + break; + case 'p': + rb_ary_push(ary, + rb_dlptr_new(((void**)(data->ptr))[i],0,dlfree)); + break; + } + } + + return ary; +} + + +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:0x%lx ptr=0x%lx size=%ld free=0x%lx>", + rb_class2name(CLASS_OF(self)), data, data->ptr, data->size, + (long)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 DLLONG2NUM((long)ptr1 - (long)ptr2); +} + +VALUE +rb_dlptr_plus(VALUE self, VALUE other) +{ + void *ptr; + long num, size; + + ptr = rb_dlptr2cptr(self); + size = RDLPTR(self)->size; + num = DLNUM2LONG(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 = RDLPTR(self)->size; + num = DLNUM2LONG(other); + return rb_dlptr_new((char *)ptr - num, size + num, 0); +} + +VALUE +rb_dlptr_define_data_type(int argc, VALUE argv[], VALUE self) +{ + VALUE data_type, type, rest, vid; + struct ptr_data *data; + int i, t, num; + char *ctype; + + rb_scan_args(argc, argv, "11*", &data_type, &type, &rest); + Data_Get_Struct(self, struct ptr_data, data); + + if (argc == 1 || (argc == 2 && type == Qnil)) { + if (NUM2INT(data_type) == DLPTR_CTYPE_UNKNOWN) { + data->ctype = DLPTR_CTYPE_UNKNOWN; + data->slen = 0; + data->ids_num = 0; + if (data->stype) { + dlfree(data->stype); + data->stype = NULL; + } + if (data->ids) { + dlfree(data->ids); + data->ids = NULL; + } + return Qnil; + } + else{ + rb_raise(rb_eArgError, "wrong arguments"); + } + } + + t = NUM2INT(data_type); + StringValue(type); + Check_Type(rest, T_ARRAY); + num = RARRAY(rest)->len; + for (i=0; ictype = t; + data->slen = num; + data->ids_num = num; + if (data->stype) dlfree(data->stype); + data->stype = (char*)dlmalloc(sizeof(char) * num); + if (data->ssize) dlfree(data->ssize); + data->ssize = (int*)dlmalloc(sizeof(int) * num); + if (data->ids) dlfree(data->ids); + data->ids = (ID*)dlmalloc(sizeof(ID) * data->ids_num); + + ctype = StringValuePtr(type); + for (i=0; iids[i] = rb_to_id(vid); + data->stype[i] = *ctype; + ctype ++; + if (isdigit(*ctype)) { + char *p, *d; + for (p=ctype; isdigit(*p); p++) ; + d = ALLOCA_N(char, p - ctype + 1); + strncpy(d, ctype, p - ctype); + d[p - ctype] = '\0'; + data->ssize[i] = atoi(d); + ctype = p; + } + else{ + data->ssize[i] = 1; + } + } + + if (*ctype) { + rb_raise(rb_eArgError, "too few/many arguments"); + } + + if (!data->size) + data->size = dlsizeof(RSTRING(type)->ptr); + + return Qnil; +} + +VALUE +rb_dlptr_define_struct(int argc, VALUE argv[], VALUE self) +{ + VALUE *pass_argv; + int pass_argc, i; + + pass_argc = argc + 1; + pass_argv = ALLOCA_N(VALUE, pass_argc); + pass_argv[0] = INT2FIX(DLPTR_CTYPE_STRUCT); + for (i=1; istype) + return rb_assoc_new(INT2FIX(data->ctype), + rb_tainted_str_new(data->stype, data->slen)); + else + return rb_assoc_new(INT2FIX(data->ctype), Qnil); +} + +static VALUE +cary2ary(void *ptr, char t, int len) +{ + VALUE ary; + VALUE elem; + int i; + + if (len < 1) + return Qnil; + + if (len == 1) { + switch (t) { + case 'I': + elem = INT2NUM(*((int*)ptr)); + ptr = (char *)ptr + sizeof(int); + break; + case 'L': + elem = DLLONG2NUM(*((long*)ptr)); + ptr = (char *)ptr + sizeof(long); + break; + case 'P': + case 'S': + elem = rb_dlptr_new(*((void**)ptr),0, 0); + ptr = (char *)ptr + sizeof(void*); + break; + case 'F': + elem = rb_float_new(*((float*)ptr)); + ptr = (char *)ptr + sizeof(float); + break; + case 'D': + elem = rb_float_new(*((double*)ptr)); + ptr = (char *)ptr + sizeof(double); + break; + case 'C': + elem = INT2NUM(*((char*)ptr)); + ptr = (char *)ptr + sizeof(char); + break; + case 'H': + elem = INT2NUM(*((short*)ptr)); + ptr = (char *)ptr + sizeof(short); + break; + default: + rb_raise(rb_eDLTypeError, "unsupported type '%c'", t); + } + return elem; + } + + ary = rb_ary_new(); + for (i=0; i < len; i++) { + switch (t) { + case 'I': + elem = INT2NUM(*((int*)ptr)); + ptr = (char *)ptr + sizeof(int); + break; + case 'L': + elem = DLLONG2NUM(*((long*)ptr)); + ptr = (char *)ptr + sizeof(long); + break; + case 'P': + case 'S': + elem = rb_dlptr_new(*((void**)ptr), 0, 0); + ptr = (char *)ptr + sizeof(void*); + break; + case 'F': + elem = rb_float_new(*((float*)ptr)); + ptr = (char *)ptr + sizeof(float); + break; + case 'D': + elem = rb_float_new(*((float*)ptr)); + ptr = (char *)ptr + sizeof(double); + break; + case 'C': + elem = INT2NUM(*((char*)ptr)); + ptr = (char *)ptr + sizeof(char); + break; + case 'H': + elem = INT2NUM(*((short*)ptr)); + ptr = (char *)ptr + sizeof(short); + break; + default: + rb_raise(rb_eDLTypeError, "unsupported type '%c'", t); + } + rb_ary_push(ary, elem); + } + + return ary; +} + +VALUE +rb_dlptr_aref(int argc, VALUE argv[], VALUE self) +{ + VALUE key = Qnil, num = Qnil; + ID id; + struct ptr_data *data; + int i; + int offset; + + if (rb_scan_args(argc, argv, "11", &key, &num) == 1) { + num = INT2NUM(0); + } + + if (TYPE(key) == T_FIXNUM || TYPE(key) == T_BIGNUM) { + VALUE pass[1]; + pass[0] = num; + return rb_dlptr_to_str(1, pass, rb_dlptr_plus(self, key)); + } + rb_to_id(key); + if (! (TYPE(key) == T_STRING || TYPE(key) == T_SYMBOL)) { + rb_raise(rb_eTypeError, "the key must be a string or symbol"); + } + + id = rb_to_id(key); + Data_Get_Struct(self, struct ptr_data, data); + offset = 0; + switch (data->ctype) { + case DLPTR_CTYPE_STRUCT: + for (i=0; i < data->ids_num; i++) { + switch (data->stype[i]) { + case 'I': + DLALIGN(data->ptr,offset,INT_ALIGN); + break; + case 'L': + DLALIGN(data->ptr,offset,LONG_ALIGN); + break; + case 'P': + case 'S': + DLALIGN(data->ptr,offset,VOIDP_ALIGN); + break; + case 'F': + DLALIGN(data->ptr,offset,FLOAT_ALIGN); + break; + case 'D': + DLALIGN(data->ptr,offset,DOUBLE_ALIGN); + break; + case 'C': + break; + case 'H': + DLALIGN(data->ptr,offset,SHORT_ALIGN); + break; + default: + rb_raise(rb_eDLTypeError, "unsupported type '%c'", data->stype[i]); + } + if (data->ids[i] == id) { + return cary2ary((char *)data->ptr + offset, data->stype[i], data->ssize[i]); + } + switch (data->stype[i]) { + case 'I': + offset += sizeof(int) * data->ssize[i]; + break; + case 'L': + offset += sizeof(long) * data->ssize[i]; + break; + case 'P': + case 'S': + offset += sizeof(void*) * data->ssize[i]; + break; + case 'F': + offset += sizeof(float) * data->ssize[i]; + break; + case 'D': + offset += sizeof(double) * data->ssize[i]; + break; + case 'C': + offset += sizeof(char) * data->ssize[i]; + break; + case 'H': + offset += sizeof(short) * data->ssize[i]; + break; + default: + rb_raise(rb_eDLTypeError, "unsupported type '%c'", data->stype[i]); + } + } + break; + case DLPTR_CTYPE_UNION: + for (i=0; i < data->ids_num; i++) { + if (data->ids[i] == id) { + return cary2ary((char *)data->ptr + offset, data->stype[i], data->ssize[i]); + } + } + break; + } /* end of switch */ + + rb_raise(rb_eNameError, "undefined key `%s' for %s", + rb_id2name(id), rb_class2name(CLASS_OF(self))); + + return Qnil; +} + +static void * +ary2cary(char t, VALUE val, long *size) +{ + void *ptr; + + if (TYPE(val) == T_ARRAY) { + ptr = rb_ary2cary(t, val, size); + } + else{ + ptr = rb_ary2cary(t, rb_ary_new3(1, val), size); + } + return ptr; +} + +VALUE +rb_dlptr_aset(int argc, VALUE argv[], VALUE self) +{ + VALUE key = Qnil, num = Qnil, val = Qnil; + ID id; + struct ptr_data *data; + int i; + int offset; + long memsize; + void *memimg; + + rb_secure(4); + switch (rb_scan_args(argc, argv, "21", &key, &num, &val)) { + case 2: + val = num; + num = Qnil; + break; + } + + if (TYPE(key) == T_FIXNUM || TYPE(key) == T_BIGNUM) { + void *dst, *src; + long len; + + StringValue(val); + Data_Get_Struct(self, struct ptr_data, data); + dst = (void*)((long)(data->ptr) + DLNUM2LONG(key)); + src = RSTRING(val)->ptr; + len = RSTRING(val)->len; + if (num == Qnil) { + memcpy(dst, src, len); + } + else{ + long n = NUM2INT(num); + memcpy(dst, src, n < len ? n : len); + if (n > len) MEMZERO((char*)dst + len, char, n - len); + } + return val; + } + + id = rb_to_id(key); + Data_Get_Struct(self, struct ptr_data, data); + switch (data->ctype) { + case DLPTR_CTYPE_STRUCT: + offset = 0; + for (i=0; i < data->ids_num; i++) { + switch (data->stype[i]) { + case 'I': + DLALIGN(data->ptr,offset,INT_ALIGN); + break; + case 'L': + DLALIGN(data->ptr,offset,LONG_ALIGN); + break; + case 'P': + case 'S': + DLALIGN(data->ptr,offset,VOIDP_ALIGN); + break; + case 'D': + DLALIGN(data->ptr,offset,DOUBLE_ALIGN); + break; + case 'F': + DLALIGN(data->ptr,offset,FLOAT_ALIGN); + break; + case 'C': + break; + case 'H': + DLALIGN(data->ptr,offset,SHORT_ALIGN); + break; + default: + rb_raise(rb_eDLTypeError, "unsupported type '%c'", data->stype[i]); + } + if (data->ids[i] == id) { + memimg = ary2cary(data->stype[i], val, &memsize); + memcpy((char *)data->ptr + offset, memimg, memsize); + dlfree(memimg); + return val; + } + switch (data->stype[i]) { + case 'I': + case 'i': + offset += sizeof(int) * data->ssize[i]; + break; + case 'L': + case 'l': + offset += sizeof(long) * data->ssize[i]; + break; + case 'P': + case 'p': + case 'S': + case 's': + offset += sizeof(void*) * data->ssize[i]; + break; + case 'D': + case 'd': + offset += sizeof(double) * data->ssize[i]; + break; + case 'F': + case 'f': + offset += sizeof(float) * data->ssize[i]; + break; + case 'C': + case 'c': + offset += sizeof(char) * data->ssize[i]; + break; + case 'H': + case 'h': + offset += sizeof(short) * data->ssize[i]; + break; + default: + rb_raise(rb_eDLTypeError, "unsupported type '%c'", data->stype[i]); + } + } + return val; + /* break; */ + case DLPTR_CTYPE_UNION: + for (i=0; i < data->ids_num; i++) { + if (data->ids[i] == id) { + switch (data->stype[i]) { + case 'I': case 'i': + memsize = sizeof(int) * data->ssize[i]; + break; + case 'L': case 'l': + memsize = sizeof(long) * data->ssize[i]; + break; + case 'P': case 'p': + case 'S': case 's': + memsize = sizeof(void*) * data->ssize[i]; + break; + case 'F': case 'f': + memsize = sizeof(float) * data->ssize[i]; + break; + case 'D': case 'd': + memsize = sizeof(double) * data->ssize[i]; + break; + case 'C': case 'c': + memsize = sizeof(char) * data->ssize[i]; + break; + case 'H': case 'h': + memsize = sizeof(short) * data->ssize[i]; + break; + default: + rb_raise(rb_eDLTypeError, "unsupported type '%c'", data->stype[i]); + } + memimg = ary2cary(data->stype[i], val, NULL); + memcpy(data->ptr, memimg, memsize); + dlfree(memimg); + } + } + return val; + /* break; */ + } + + rb_raise(rb_eNameError, "undefined key `%s' for %s", + rb_id2name(id), rb_class2name(CLASS_OF(self))); + + return Qnil; +} + +VALUE +rb_dlptr_size(int argc, VALUE argv[], VALUE self) +{ + VALUE size; + + if (rb_scan_args(argc, argv, "01", &size) == 0){ + return DLLONG2NUM(RDLPTR(self)->size); + } + else{ + RDLPTR(self)->size = DLNUM2LONG(size); + return size; + } +} + +static VALUE +dlmem_each_i(VALUE assoc, void *data) +{ + VALUE key, val; + key = rb_ary_entry(assoc, 0); + val = rb_ary_entry(assoc, 1); + rb_yield(rb_assoc_new(key,(VALUE)DLNUM2LONG(val))); + return Qnil; +} + +VALUE +rb_dlmem_each(VALUE self) +{ + rb_iterate(rb_each, DLMemoryTable, dlmem_each_i, 0); + return Qnil; +} + +void +Init_dlptr() +{ + rb_cDLPtrData = rb_define_class_under(rb_mDL, "PtrData", rb_cObject); + rb_define_alloc_func(rb_cDLPtrData, rb_dlptr_s_allocate); + rb_define_singleton_method(rb_cDLPtrData, "malloc", rb_dlptr_s_malloc, -1); + rb_define_method(rb_cDLPtrData, "initialize", rb_dlptr_initialize, -1); + rb_define_method(rb_cDLPtrData, "free=", rb_dlptr_free_set, 1); + rb_define_method(rb_cDLPtrData, "free", rb_dlptr_free_get, 0); + rb_define_method(rb_cDLPtrData, "to_i", rb_dlptr_to_i, 0); + rb_define_method(rb_cDLPtrData, "ptr", rb_dlptr_ptr, 0); + rb_define_method(rb_cDLPtrData, "+@", rb_dlptr_ptr, 0); + rb_define_method(rb_cDLPtrData, "ref", rb_dlptr_ref, 0); + rb_define_method(rb_cDLPtrData, "-@", rb_dlptr_ref, 0); + rb_define_method(rb_cDLPtrData, "null?", rb_dlptr_null_p, 0); + rb_define_method(rb_cDLPtrData, "to_a", rb_dlptr_to_array, -1); + rb_define_method(rb_cDLPtrData, "to_s", rb_dlptr_to_s, -1); + rb_define_method(rb_cDLPtrData, "to_str", rb_dlptr_to_str, -1); + rb_define_method(rb_cDLPtrData, "inspect", rb_dlptr_inspect, 0); + rb_define_method(rb_cDLPtrData, "<=>", rb_dlptr_cmp, 1); + rb_define_method(rb_cDLPtrData, "==", rb_dlptr_eql, 1); + rb_define_method(rb_cDLPtrData, "eql?", rb_dlptr_eql, 1); + rb_define_method(rb_cDLPtrData, "+", rb_dlptr_plus, 1); + rb_define_method(rb_cDLPtrData, "-", rb_dlptr_minus, 1); + rb_define_method(rb_cDLPtrData, "define_data_type", + rb_dlptr_define_data_type, -1); + rb_define_method(rb_cDLPtrData, "struct!", rb_dlptr_define_struct, -1); + rb_define_method(rb_cDLPtrData, "union!", rb_dlptr_define_union, -1); + rb_define_method(rb_cDLPtrData, "data_type", rb_dlptr_get_data_type, 0); + rb_define_method(rb_cDLPtrData, "[]", rb_dlptr_aref, -1); + rb_define_method(rb_cDLPtrData, "[]=", rb_dlptr_aset, -1); + rb_define_method(rb_cDLPtrData, "size", rb_dlptr_size, -1); + rb_define_method(rb_cDLPtrData, "size=", rb_dlptr_size, -1); + + rb_mDLMemorySpace = rb_define_module_under(rb_mDL, "MemorySpace"); + DLMemoryTable = rb_hash_new(); + rb_define_const(rb_mDLMemorySpace, "MemoryTable", DLMemoryTable); + rb_define_module_function(rb_mDLMemorySpace, "each", rb_dlmem_each, 0); +} diff --git a/ruby_1_8_6/ext/dl/sample/c++sample.C b/ruby_1_8_6/ext/dl/sample/c++sample.C new file mode 100644 index 0000000000..d083d337a7 --- /dev/null +++ b/ruby_1_8_6/ext/dl/sample/c++sample.C @@ -0,0 +1,35 @@ +#include + +class Person { +private: + const char *name; + int age; + +public: + Person(const char *name, int age); + const char * get_name(); + int get_age(); + void set_age(int i); +}; + +Person::Person(const char *name, int age) + : name(name), age(age) +{ + /* empty */ +} + +const char * +Person::get_name() +{ + return name; +} + +int +Person::get_age(){ + return age; +} + +void +Person::set_age(int i){ + age = i; +} diff --git a/ruby_1_8_6/ext/dl/sample/c++sample.rb b/ruby_1_8_6/ext/dl/sample/c++sample.rb new file mode 100644 index 0000000000..29887df845 --- /dev/null +++ b/ruby_1_8_6/ext/dl/sample/c++sample.rb @@ -0,0 +1,60 @@ +=begin + This script shows how to deal with C++ classes using Ruby/DL. + You must build a dynamic loadable library using "c++sample.C" + to run this script as follows: + $ g++ -o libsample.so -shared c++sample.C +=end + +require 'dl' +require 'dl/import' +require 'dl/struct' + +# Give a name of dynamic loadable library +LIBNAME = ARGV[0] || "libsample.so" + +class Person + module Core + extend DL::Importable + + dlload LIBNAME + + # mangled symbol names + extern "void __6PersonPCci(void *, const char *, int)" + extern "const char *get_name__6Person(void *)" + extern "int get_age__6Person(void *)" + extern "void set_age__6Personi(void *, int)" + + Data = struct [ + "char *name", + "int age", + ] + end + + def initialize(name, age) + @ptr = Core::Data.alloc + Core::__6PersonPCci(@ptr, name, age) + end + + def get_name() + str = Core::get_name__6Person(@ptr) + if( str ) + str.to_s + else + nil + end + end + + def get_age() + Core::get_age__6Person(@ptr) + end + + def set_age(age) + Core::set_age__6Personi(@ptr, age) + end +end + +obj = Person.new("ttate", 1) +p obj.get_name() +p obj.get_age() +obj.set_age(10) +p obj.get_age() diff --git a/ruby_1_8_6/ext/dl/sample/drives.rb b/ruby_1_8_6/ext/dl/sample/drives.rb new file mode 100644 index 0000000000..8a590404b1 --- /dev/null +++ b/ruby_1_8_6/ext/dl/sample/drives.rb @@ -0,0 +1,70 @@ +# -*- ruby -*- +# drives.rb -- find existing drives and show the drive type. + +require 'dl' +require 'dl/import' + +module Kernel32 + extend DL::Importable + + dlload "kernel32" + + extern "long GetLogicalDrives()" + extern "int GetDriveType(char*)" + extern "long GetDiskFreeSpace(char*, long ref, long ref, long ref, long ref)" +end + +include Kernel32 + +buff = Kernel32.getLogicalDrives() + +i = 0 +ds = [] +while( i < 26 ) + mask = (1 << i) + if( buff & mask > 0 ) + ds.push((65+i).chr) + end + i += 1 +end + +=begin +From the cygwin's /usr/include/w32api/winbase.h: +#define DRIVE_UNKNOWN 0 +#define DRIVE_NO_ROOT_DIR 1 +#define DRIVE_REMOVABLE 2 +#define DRIVE_FIXED 3 +#define DRIVE_REMOTE 4 +#define DRIVE_CDROM 5 +#define DRIVE_RAMDISK 6 +=end + +types = [ + "unknown", + "no root dir", + "Removable", + "Fixed", + "Remote", + "CDROM", + "RAM", +] +print("Drive : Type (Free Space/Available Space)\n") +ds.each{|d| + t = Kernel32.getDriveType(d + ":\\") + Kernel32.getDiskFreeSpace(d + ":\\", 0, 0, 0, 0) + _,sec_per_clus,byte_per_sec,free_clus,total_clus = Kernel32._args_ + fbytes = sec_per_clus * byte_per_sec * free_clus + tbytes = sec_per_clus * byte_per_sec * total_clus + unit = "B" + if( fbytes > 1024 && tbytes > 1024 ) + fbytes = fbytes / 1024 + tbytes = tbytes / 1024 + unit = "K" + end + if( fbytes > 1024 && tbytes > 1024 ) + fbytes = fbytes / 1024 + tbytes = tbytes / 1024 + unit = "M" + end + print("#{d} : #{types[t]} (#{fbytes} #{unit}/#{tbytes} #{unit})\n") +} diff --git a/ruby_1_8_6/ext/dl/sample/getch.rb b/ruby_1_8_6/ext/dl/sample/getch.rb new file mode 100644 index 0000000000..3f7261c979 --- /dev/null +++ b/ruby_1_8_6/ext/dl/sample/getch.rb @@ -0,0 +1,5 @@ +require 'dl' + +crtdll = DL::dlopen("crtdll") +getch = crtdll['_getch', 'L'] +print(getch.call, "\n") diff --git a/ruby_1_8_6/ext/dl/sample/libc.rb b/ruby_1_8_6/ext/dl/sample/libc.rb new file mode 100644 index 0000000000..a1f6fbe543 --- /dev/null +++ b/ruby_1_8_6/ext/dl/sample/libc.rb @@ -0,0 +1,69 @@ +require "dl/import" +require "dl/struct" + +module LIBC + extend DL::Importable + + begin + dlload "libc.so.6" + rescue + dlload "libc.so.5" + end + + extern "int atoi(char*)" + extern "ibool isdigit(int)" + extern "int gettimeofday(struct timeval *, struct timezone *)" + extern "char* strcat(char*, char*)" + extern "FILE* fopen(char*, char*)" + extern "int fclose(FILE*)" + extern "int fgetc(FILE*)" + extern "int strlen(char*)" + extern "void qsort(void*, int, int, void*)" + + def str_qsort(ary, comp) + len = ary.length + r,rs = qsort(ary, len, DL.sizeof('P'), comp) + return rs[0].to_a('S', len) + end + + Timeval = struct [ + "long tv_sec", + "long tv_usec", + ] + + Timezone = struct [ + "int tz_minuteswest", + "int tz_dsttime", + ] + + def my_compare(ptr1, ptr2) + ptr1.ptr.to_s <=> ptr2.ptr.to_s + end + COMPARE = callback("int my_compare(char**, char**)") +end + + +$cb1 = DL.callback('IPP'){|ptr1, ptr2| + str1 = ptr1.ptr.to_s + str2 = ptr2.ptr.to_s + str1 <=> str2 +} + +p LIBC.atoi("10") + +p LIBC.isdigit(?1) + +p LIBC.isdigit(?a) + +p LIBC.strcat("a", "b") + +ary = ["a","c","b"] +ptr = ary.to_ptr +LIBC.qsort(ptr, ary.length, DL.sizeof('P'), LIBC::COMPARE) +p ptr.to_a('S', ary.length) + +tv = LIBC::Timeval.malloc +tz = LIBC::Timezone.malloc +LIBC.gettimeofday(tv, tz) + +p Time.at(tv.tv_sec) diff --git a/ruby_1_8_6/ext/dl/sample/msgbox.rb b/ruby_1_8_6/ext/dl/sample/msgbox.rb new file mode 100644 index 0000000000..091e646091 --- /dev/null +++ b/ruby_1_8_6/ext/dl/sample/msgbox.rb @@ -0,0 +1,19 @@ +# This script works on Windows. + +require 'dl' + +User32 = DL.dlopen("user32") +Kernel32 = DL.dlopen("kernel32") + +MB_OK = 0 +MB_OKCANCEL = 1 + +message_box = User32['MessageBoxA', 'ILSSI'] +r,rs = message_box.call(0, 'ok?', 'error', MB_OKCANCEL) + +case r +when 1 + print("OK!\n") +when 2 + print("Cancel!\n") +end diff --git a/ruby_1_8_6/ext/dl/sample/msgbox2.rb b/ruby_1_8_6/ext/dl/sample/msgbox2.rb new file mode 100644 index 0000000000..e49846cc5e --- /dev/null +++ b/ruby_1_8_6/ext/dl/sample/msgbox2.rb @@ -0,0 +1,18 @@ +# This script works on Windows. + +require 'dl/win32' + +MB_OK = 0 +MB_OKCANCEL = 1 + +message_box = Win32API.new("user32",'MessageBoxA', 'ISSI', 'I') +r = message_box.call(0, 'ok?', 'error', MB_OKCANCEL) + +case r +when 1 + print("OK!\n") +when 2 + print("Cancel!\n") +else + p r +end diff --git a/ruby_1_8_6/ext/dl/sample/stream.rb b/ruby_1_8_6/ext/dl/sample/stream.rb new file mode 100644 index 0000000000..179836999d --- /dev/null +++ b/ruby_1_8_6/ext/dl/sample/stream.rb @@ -0,0 +1,87 @@ +# -*- ruby -*- +# Display a file name and stream names of a file with those size. + +require 'dl' +require 'dl/import' + +module NTFS + extend DL::Importable + + dlload "kernel32.dll" + + OPEN_EXISTING = 3 + GENERIC_READ = 0x80000000 + BACKUP_DATA = 0x00000001 + BACKUP_ALTERNATE_DATA = 0x00000004 + FILE_SHARE_READ = 0x00000001 + FILE_FLAG_BACKUP_SEMANTICS = 0x02000000 + + typealias "LPSECURITY_ATTRIBUTES", "void*" + + extern "BOOL BackupRead(HANDLE, PBYTE, DWORD, PDWORD, BOOL, BOOL, PVOID)" + extern "BOOL BackupSeek(HANDLE, DWORD, DWORD, PDWORD, PDWORD, PVOID)" + extern "BOOL CloseHandle(HANDLE)" + extern "HANDLE CreateFile(LPCSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, + DWORD, DWORD, HANDLE)" + + module_function + + def streams(filename) + status = [] + h = createFile(filename,GENERIC_READ,FILE_SHARE_READ,nil, + OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS,0) + if( h != 0 ) + begin + # allocate the memory for backup data used in backupRead(). + data = DL.malloc(DL.sizeof("L5")) + data.struct!("LLLLL", :id, :attrs, :size_low, :size_high, :name_size) + + # allocate memories for references to long values used in backupRead(). + context = DL.malloc(DL.sizeof("L")) + lval = DL.malloc(DL.sizeof("L")) + + while( backupRead(h, data, data.size, lval, false, false, context) ) + size = data[:size_low] + (data[:size_high] << (DL.sizeof("I") * 8)) + case data[:id] + when BACKUP_ALTERNATE_DATA + stream_name = DL.malloc(data[:name_size]) + backupRead(h, stream_name, stream_name.size, + lval, false, false, context) + name = stream_name[0, stream_name.size] + name.tr!("\000","") + if( name =~ /^:(.*?):.*$/ ) + status.push([$1,size]) + end + when BACKUP_DATA + status.push([nil,size]) + else + raise(RuntimeError, "unknown data type #{data[:id]}.") + end + l1 = DL.malloc(DL.sizeof("L")) + l2 = DL.malloc(DL.sizeof("L")) + if( !backupSeek(h, data[:size_low], data[:size_high], l1, l2, context) ) + break + end + end + ensure + backupRead(h, nil, 0, lval, true, false, context) + closeHandle(h) + end + return status + else + raise(RuntimeError, "can't open #{filename}.\n") + end + end +end + +ARGV.each{|filename| + if( File.exist?(filename) ) + NTFS.streams(filename).each{|name,size| + if( name ) + print("#{filename}:#{name}\t#{size}bytes\n") + else + print("#{filename}\t#{size}bytes\n") + end + } + end +} diff --git a/ruby_1_8_6/ext/dl/sym.c b/ruby_1_8_6/ext/dl/sym.c new file mode 100644 index 0000000000..01e0474f58 --- /dev/null +++ b/ruby_1_8_6/ext/dl/sym.c @@ -0,0 +1,992 @@ +/* -*- C -*- + * $Id$ + */ + +#include +#include +#include "dl.h" + +VALUE rb_cDLSymbol; + +static const char * +char2type(int ch) +{ + switch (ch) { + case '0': + return "void"; + case 'P': + return "void *"; + case 'p': + return "void *"; + case 'C': + return "char"; + case 'c': + return "char *"; + case 'H': + return "short"; + case 'h': + return "short *"; + case 'I': + return "int"; + case 'i': + return "int *"; + case 'L': + return "long"; + case 'l': + return "long *"; + case 'F': + return "double"; + case 'f': + return "double *"; + case 'D': + return "double"; + case 'd': + return "double *"; + case 'S': + return "const char *"; + case 's': + return "char *"; + case 'A': + return "[]"; + case 'a': + return "[]"; /* ?? */ + } + return NULL; +} + +void +dlsym_free(struct sym_data *data) +{ + if( data->name ){ + DEBUG_CODE({ + printf("dlsym_free(): free(data->name:%s)\n",data->name); + }); + free(data->name); + } + if( data->type ){ + DEBUG_CODE({ + printf("dlsym_free(): free(data->type:%s)\n",data->type); + }); + free(data->type); + } +} + +VALUE +rb_dlsym_new(void (*func)(), const char *name, const char *type) +{ + VALUE val; + struct sym_data *data; + const char *ptype; + + rb_secure(4); + if( !type || !type[0] ){ + return rb_dlptr_new((void*)func, 0, 0); + } + + for( ptype = type; *ptype; ptype ++ ){ + if( ! char2type(*ptype) ){ + rb_raise(rb_eDLTypeError, "unknown type specifier '%c'", *ptype); + } + } + + if( func ){ + val = Data_Make_Struct(rb_cDLSymbol, struct sym_data, 0, dlsym_free, data); + data->func = func; + data->name = name ? strdup(name) : NULL; + data->type = type ? strdup(type) : NULL; + data->len = type ? strlen(type) : 0; +#if !(defined(DLSTACK)) + if( data->len - 1 > MAX_ARG ){ + rb_raise(rb_eDLError, "maximum number of arguments is %d.", MAX_ARG); + } +#endif + } + else{ + val = Qnil; + } + + return val; +} + +freefunc_t +rb_dlsym2csym(VALUE val) +{ + struct sym_data *data; + freefunc_t func; + + if( rb_obj_is_kind_of(val, rb_cDLSymbol) ){ + Data_Get_Struct(val, struct sym_data, data); + func = data->func; + } + else if( val == Qnil ){ + func = NULL; + } + else{ + rb_raise(rb_eTypeError, "DL::Symbol was expected"); + } + + return func; +} + +VALUE +rb_dlsym_s_allocate(VALUE klass) +{ + VALUE obj; + struct sym_data *data; + + obj = Data_Make_Struct(klass, struct sym_data, 0, dlsym_free, data); + data->func = 0; + data->name = 0; + data->type = 0; + data->len = 0; + + return obj; +} + +VALUE +rb_dlsym_initialize(int argc, VALUE argv[], VALUE self) +{ + VALUE addr, name, type; + struct sym_data *data; + void *saddr; + const char *sname, *stype; + + rb_scan_args(argc, argv, "12", &addr, &name, &type); + + saddr = (void*)(DLNUM2LONG(rb_Integer(addr))); + if (!NIL_P(name)) StringValue(name); + stype = NIL_P(type) ? NULL : StringValuePtr(type); + sname = NIL_P(name) ? NULL : RSTRING(name)->ptr; + + if( saddr ){ + Data_Get_Struct(self, struct sym_data, data); + if( data->name ) free(data->name); + if( data->type ) free(data->type); + data->func = saddr; + data->name = sname ? strdup(sname) : 0; + data->type = stype ? strdup(stype) : 0; + data->len = stype ? strlen(stype) : 0; + } + + return Qnil; +} + +VALUE +rb_s_dlsym_char2type(VALUE self, VALUE ch) +{ + const char *type; + + type = char2type(StringValuePtr(ch)[0]); + + if (type == NULL) + return Qnil; + else + return rb_str_new2(type); +} + +VALUE +rb_dlsym_name(VALUE self) +{ + struct sym_data *sym; + + Data_Get_Struct(self, struct sym_data, sym); + return sym->name ? rb_tainted_str_new2(sym->name) : Qnil; +} + +VALUE +rb_dlsym_proto(VALUE self) +{ + struct sym_data *sym; + + Data_Get_Struct(self, struct sym_data, sym); + return sym->type ? rb_tainted_str_new2(sym->type) : Qnil; +} + +VALUE +rb_dlsym_cproto(VALUE self) +{ + struct sym_data *sym; + const char *ptype, *typestr; + size_t len; + VALUE val; + + Data_Get_Struct(self, struct sym_data, sym); + + ptype = sym->type; + + if( ptype ){ + typestr = char2type(*ptype++); + len = strlen(typestr); + + val = rb_tainted_str_new(typestr, len); + if (typestr[len - 1] != '*') + rb_str_cat(val, " ", 1); + + if( sym->name ){ + rb_str_cat2(val, sym->name); + } + else{ + rb_str_cat2(val, "(null)"); + } + rb_str_cat(val, "(", 1); + + while (*ptype) { + const char *ty = char2type(*ptype++); + rb_str_cat2(val, ty); + if (*ptype) + rb_str_cat(val, ", ", 2); + } + + rb_str_cat(val, ");", 2); + } + else{ + val = rb_tainted_str_new2("void ("); + if( sym->name ){ + rb_str_cat2(val, sym->name); + } + else{ + rb_str_cat2(val, "(null)"); + } + rb_str_cat2(val, ")()"); + } + + return val; +} + +VALUE +rb_dlsym_inspect(VALUE self) +{ + VALUE proto; + VALUE val; + char *str; + int str_size; + struct sym_data *sym; + + Data_Get_Struct(self, struct sym_data, sym); + proto = rb_dlsym_cproto(self); + + str_size = RSTRING(proto)->len + 100; + str = dlmalloc(str_size); + snprintf(str, str_size - 1, + "#", + sym, sym->func, RSTRING(proto)->ptr); + val = rb_tainted_str_new2(str); + dlfree(str); + + return val; +} + +static int +stack_size(struct sym_data *sym) +{ + int i; + int size; + + size = 0; + for( i=1; i < sym->len; i++ ){ + switch(sym->type[i]){ + case 'C': + case 'H': + case 'I': + case 'L': + size += sizeof(long); + break; + case 'F': + size += sizeof(float); + break; + case 'D': + size += sizeof(double); + break; + case 'c': + case 'h': + case 'i': + case 'l': + case 'f': + case 'd': + case 'p': + case 'P': + case 's': + case 'S': + case 'a': + case 'A': + size += sizeof(void*); + break; + default: + return -(sym->type[i]); + } + } + return size; +} + +static ID rb_dl_id_DLErrno; + +static VALUE +rb_dl_get_last_error(VALUE self) +{ + return rb_thread_local_aref(rb_thread_current(), rb_dl_id_DLErrno); +} + +static VALUE +rb_dl_set_last_error(VALUE self, VALUE val) +{ + errno = NUM2INT(val); + rb_thread_local_aset(rb_thread_current(), rb_dl_id_DLErrno, val); + return Qnil; +} + +#ifdef HAVE_WINDOWS_H +#include +static ID rb_dl_id_DLW32Error; + +static VALUE +rb_dl_win32_get_last_error(VALUE self) +{ + return rb_thread_local_aref(rb_thread_current(), rb_dl_id_DLW32Error); +} + +static VALUE +rb_dl_win32_set_last_error(VALUE self, VALUE val) +{ + SetLastError(NUM2INT(val)); + rb_thread_local_aset(rb_thread_current(), rb_dl_id_DLW32Error, val); + return Qnil; +} +#endif + +#ifdef DLSTACK_GUARD +# ifdef __MSVC_RUNTIME_CHECKS +# pragma runtime_checks("s", off) +# endif +# if _MSC_VER >= 1300 +__declspec(noinline) +# endif +static int +rb_dlsym_guardcall(char type, ANY_TYPE *ret, long *stack, void *func) +{ + char *volatile guard = ALLOCA_N(char, 1); /* guard stack pointer */ + switch(type){ + case '0': + { + void (*f)(DLSTACK_PROTO) = func; + f(DLSTACK_ARGS); + } + break; + case 'P': + case 'p': + { + void * (*f)(DLSTACK_PROTO) = func; + ret->p = f(DLSTACK_ARGS); + } + break; + case 'C': + case 'c': + { + char (*f)(DLSTACK_PROTO) = func; + ret->c = f(DLSTACK_ARGS); + } + break; + case 'H': + case 'h': + { + short (*f)(DLSTACK_PROTO) = func; + ret->h = f(DLSTACK_ARGS); + } + break; + case 'I': + case 'i': + { + int (*f)(DLSTACK_PROTO) = func; + ret->i = f(DLSTACK_ARGS); + } + break; + case 'L': + case 'l': + { + long (*f)(DLSTACK_PROTO) = func; + ret->l = f(DLSTACK_ARGS); + } + break; + case 'F': + case 'f': + { + float (*f)(DLSTACK_PROTO) = func; + ret->f = f(DLSTACK_ARGS); + } + break; + case 'D': + case 'd': + { + double (*f)(DLSTACK_PROTO) = func; + ret->d = f(DLSTACK_ARGS); + } + break; + case 'S': + case 's': + { + char * (*f)(DLSTACK_PROTO) = func; + ret->s = f(DLSTACK_ARGS); + } + break; + default: + return 0; + } + return 1; +} +# ifdef __MSVC_RUNTIME_CHECKS +# pragma runtime_checks("s", restore) +# endif +#endif /* defined(DLSTACK_GUARD) */ + +VALUE +rb_dlsym_call(int argc, VALUE argv[], VALUE self) +{ + struct sym_data *sym; + ANY_TYPE *args; + ANY_TYPE *dargs; + ANY_TYPE ret; + int *dtypes; + VALUE val; + VALUE dvals; + int i; + long ftype; + void *func; + + rb_secure_update(self); + Data_Get_Struct(self, struct sym_data, sym); + DEBUG_CODE({ + printf("rb_dlsym_call(): type = '%s', func = 0x%x\n", sym->type, sym->func); + }); + if( (sym->len - 1) != argc ){ + rb_raise(rb_eArgError, "%d arguments are needed", sym->len - 1); + } + + ftype = 0; + dvals = Qnil; + + args = ALLOC_N(ANY_TYPE, sym->len - 1); + dargs = ALLOC_N(ANY_TYPE, sym->len - 1); + dtypes = ALLOC_N(int, sym->len - 1); +#define FREE_ARGS {xfree(args); xfree(dargs); xfree(dtypes);} + + for( i = sym->len - 2; i >= 0; i-- ){ + dtypes[i] = 0; + + switch( sym->type[i+1] ){ + case 'p': + dtypes[i] = 'p'; + case 'P': + { + struct ptr_data *data; + VALUE pval; + + if( argv[i] == Qnil ){ + ANY2P(args[i]) = DLVOIDP(0); + } + else{ + if( rb_obj_is_kind_of(argv[i], rb_cDLPtrData) ){ + pval = argv[i]; + } + else{ + pval = rb_funcall(argv[i], rb_intern("to_ptr"), 0); + if( !rb_obj_is_kind_of(pval, rb_cDLPtrData) ){ + rb_raise(rb_eDLTypeError, "unexpected type of argument #%d", i); + } + } + Data_Get_Struct(pval, struct ptr_data, data); + ANY2P(args[i]) = DLVOIDP(data->ptr); + } + } + PUSH_P(ftype); + break; + case 'a': + dtypes[i] = 'a'; + case 'A': + if( argv[i] == Qnil ){ + ANY2P(args[i]) = DLVOIDP(0); + } + else{ + ANY2P(args[i]) = DLVOIDP(rb_ary2cary(0, argv[i], NULL)); + } + PUSH_P(ftype); + break; + case 'C': + ANY2C(args[i]) = DLCHAR(NUM2CHR(argv[i])); + PUSH_C(ftype); + break; + case 'c': + ANY2C(dargs[i]) = DLCHAR(NUM2CHR(argv[i])); + ANY2P(args[i]) = DLVOIDP(&(ANY2C(dargs[i]))); + dtypes[i] = 'c'; + PUSH_P(ftype); + break; + case 'H': + ANY2H(args[i]) = DLSHORT(NUM2INT(argv[i])); + PUSH_C(ftype); + break; + case 'h': + ANY2H(dargs[i]) = DLSHORT(NUM2INT(argv[i])); + ANY2P(args[i]) = DLVOIDP(&(ANY2H(dargs[i]))); + dtypes[i] = 'h'; + PUSH_P(ftype); + break; + case 'I': + ANY2I(args[i]) = DLINT(NUM2INT(argv[i])); + PUSH_I(ftype); + break; + case 'i': + ANY2I(dargs[i]) = DLINT(NUM2INT(argv[i])); + ANY2P(args[i]) = DLVOIDP(&(ANY2I(dargs[i]))); + dtypes[i] = 'i'; + PUSH_P(ftype); + break; + case 'L': + ANY2L(args[i]) = DLNUM2LONG(argv[i]); + PUSH_L(ftype); + break; + case 'l': + ANY2L(dargs[i]) = DLNUM2LONG(argv[i]); + ANY2P(args[i]) = DLVOIDP(&(ANY2L(dargs[i]))); + dtypes[i] = 'l'; + PUSH_P(ftype); + break; + case 'F': + Check_Type(argv[i], T_FLOAT); + ANY2F(args[i]) = DLFLOAT(RFLOAT(argv[i])->value); + PUSH_F(ftype); + break; + case 'f': + Check_Type(argv[i], T_FLOAT); + ANY2F(dargs[i]) = DLFLOAT(RFLOAT(argv[i])->value); + ANY2P(args[i]) = DLVOIDP(&(ANY2F(dargs[i]))); + dtypes[i] = 'f'; + PUSH_P(ftype); + break; + case 'D': + Check_Type(argv[i], T_FLOAT); + ANY2D(args[i]) = RFLOAT(argv[i])->value; + PUSH_D(ftype); + break; + case 'd': + Check_Type(argv[i], T_FLOAT); + ANY2D(dargs[i]) = RFLOAT(argv[i])->value; + ANY2P(args[i]) = DLVOIDP(&(ANY2D(dargs[i]))); + dtypes[i] = 'd'; + PUSH_P(ftype); + break; + case 'S': + if( argv[i] == Qnil ){ + ANY2S(args[i]) = DLSTR(0); + } + else{ + VALUE str = argv[i]; + SafeStringValue(str); + ANY2S(args[i]) = DLSTR(RSTRING(str)->ptr); + } + PUSH_P(ftype); + break; + case 's': + { + VALUE str = argv[i]; + SafeStringValue(str); + ANY2S(args[i]) = DLSTR(dlmalloc(RSTRING(str)->len + 1)); + memcpy((char*)(ANY2S(args[i])), RSTRING(str)->ptr, RSTRING(str)->len + 1); + dtypes[i] = 's'; + } + PUSH_P(ftype); + break; + default: + FREE_ARGS; + rb_raise(rb_eDLTypeError, + "unknown type '%c' of the return value.", + sym->type[i+1]); + } + } + + switch( sym->type[0] ){ + case '0': + PUSH_0(ftype); + break; + case 'P': + case 'p': + case 'S': + case 's': + case 'A': + case 'a': + PUSH_P(ftype); + break; + case 'C': + case 'c': + PUSH_C(ftype); + break; + case 'H': + case 'h': + PUSH_H(ftype); + break; + case 'I': + case 'i': + PUSH_I(ftype); + break; + case 'L': + case 'l': + PUSH_L(ftype); + break; + case 'F': + case 'f': + PUSH_F(ftype); + break; + case 'D': + case 'd': + PUSH_D(ftype); + break; + default: + FREE_ARGS; + rb_raise(rb_eDLTypeError, + "unknown type `%c' of the return value.", + sym->type[0]); + } + + func = sym->func; + +#if defined(DLSTACK) + { +#if defined(DLSTACK_SIZE) + int stk_size; + long stack[DLSTACK_SIZE]; + long *sp; + + sp = stack; + stk_size = stack_size(sym); + if( stk_size < 0 ){ + FREE_ARGS; + rb_raise(rb_eDLTypeError, "unknown type '%c'.", -stk_size); + } + else if( stk_size > (int)(DLSTACK_SIZE) ){ + FREE_ARGS; + rb_raise(rb_eArgError, "too many arguments."); + } +#endif + + DLSTACK_START(sym); + +#if defined(DLSTACK_REVERSE) + for( i = sym->len - 2; i >= 0; i-- ) +#else + for( i = 0; i <= sym->len -2; i++ ) +#endif + { + switch( sym->type[i+1] ){ + case 'p': + case 'P': + DLSTACK_PUSH_P(ANY2P(args[i])); + break; + case 'a': + case 'A': + DLSTACK_PUSH_P(ANY2P(args[i])); + break; + case 'C': + DLSTACK_PUSH_C(ANY2C(args[i])); + break; + case 'c': + DLSTACK_PUSH_P(ANY2P(args[i])); + break; + case 'H': + DLSTACK_PUSH_H(ANY2H(args[i])); + break; + case 'h': + DLSTACK_PUSH_P(ANY2P(args[i])); + break; + case 'I': + DLSTACK_PUSH_I(ANY2I(args[i])); + break; + case 'i': + DLSTACK_PUSH_P(ANY2P(args[i])); + break; + case 'L': + DLSTACK_PUSH_L(ANY2L(args[i])); + break; + case 'l': + DLSTACK_PUSH_P(ANY2P(args[i])); + break; + case 'F': + DLSTACK_PUSH_F(ANY2F(args[i])); + break; + case 'f': + DLSTACK_PUSH_P(ANY2P(args[i])); + break; + case 'D': + DLSTACK_PUSH_D(ANY2D(args[i])); + break; + case 'd': + DLSTACK_PUSH_P(ANY2P(args[i])); + break; + case 'S': + case 's': + DLSTACK_PUSH_P(ANY2S(args[i])); + break; + } + } + DLSTACK_END(sym->type); + +#ifdef DLSTACK_GUARD + if(!rb_dlsym_guardcall(sym->type[0], &ret, stack, func)) { + FREE_ARGS; + rb_raise(rb_eDLTypeError, "unknown type `%c'", sym->type[0]); + } +#else /* defined(DLSTACK_GUARD) */ + { + switch( sym->type[0] ){ + case '0': + { + void (*f)(DLSTACK_PROTO) = func; + f(DLSTACK_ARGS); + } + break; + case 'P': + case 'p': + { + void * (*f)(DLSTACK_PROTO) = func; + ret.p = f(DLSTACK_ARGS); + } + break; + case 'C': + case 'c': + { + char (*f)(DLSTACK_PROTO) = func; + ret.c = f(DLSTACK_ARGS); + } + break; + case 'H': + case 'h': + { + short (*f)(DLSTACK_PROTO) = func; + ret.h = f(DLSTACK_ARGS); + } + break; + case 'I': + case 'i': + { + int (*f)(DLSTACK_PROTO) = func; + ret.i = f(DLSTACK_ARGS); + } + break; + case 'L': + case 'l': + { + long (*f)(DLSTACK_PROTO) = func; + ret.l = f(DLSTACK_ARGS); + } + break; + case 'F': + case 'f': + { + float (*f)(DLSTACK_PROTO) = func; + ret.f = f(DLSTACK_ARGS); + } + break; + case 'D': + case 'd': + { + double (*f)(DLSTACK_PROTO) = func; + ret.d = f(DLSTACK_ARGS); + } + break; + case 'S': + case 's': + { + char * (*f)(DLSTACK_PROTO) = func; + ret.s = f(DLSTACK_ARGS); + } + break; + default: + FREE_ARGS; + rb_raise(rb_eDLTypeError, "unknown type `%c'", sym->type[0]); + } + } +#endif /* defubed(DLSTACK_GUARD) */ + + { + /* + * We should get the value of errno/GetLastError() before calling another functions. + */ + int last_errno = errno; +#ifdef _WIN32 + DWORD win32_last_err = GetLastError(); +#endif + + rb_thread_local_aset(rb_thread_current(), rb_dl_id_DLErrno, INT2NUM(last_errno)); +#ifdef _WIN32 + rb_thread_local_aset(rb_thread_current(), rb_dl_id_DLW32Error, INT2NUM(win32_last_err)); +#endif + } + + } +#else /* defined(DLSTACK) */ + switch(ftype){ +#include "call.func" + default: + FREE_ARGS; + rb_raise(rb_eDLTypeError, "unsupported function type `%s'", sym->type); + } +#endif /* defined(DLSTACK) */ + + switch( sym->type[0] ){ + case '0': + val = Qnil; + break; + case 'P': + val = rb_dlptr_new((void*)(ANY2P(ret)), 0, 0); + break; + case 'p': + val = rb_dlptr_new((void*)(ANY2P(ret)), 0, dlfree); + break; + case 'C': + case 'c': + val = CHR2FIX((char)(ANY2C(ret))); + break; + case 'H': + case 'h': + val = INT2NUM((short)(ANY2H(ret))); + break; + case 'I': + case 'i': + val = INT2NUM((int)(ANY2I(ret))); + break; + case 'L': + case 'l': + val = DLLONG2NUM((long)(ANY2L(ret))); + break; + case 'F': + case 'f': + val = rb_float_new((double)(ANY2F(ret))); + break; + case 'D': + case 'd': + val = rb_float_new((double)(ANY2D(ret))); + break; + case 'S': + if( ANY2S(ret) ){ + val = rb_tainted_str_new2((char*)(ANY2S(ret))); + } + else{ + val = Qnil; + } + break; + case 's': + if( ANY2S(ret) ){ + val = rb_tainted_str_new2((char*)(ANY2S(ret))); + DEBUG_CODE({ + printf("dlfree(%s)\n",(char*)(ANY2S(ret))); + }); + dlfree((void*)(ANY2S(ret))); + } + else{ + val = Qnil; + } + break; + default: + FREE_ARGS; + rb_raise(rb_eDLTypeError, "unknown type `%c'", sym->type[0]); + } + + dvals = rb_ary_new(); + for( i = 0; i <= sym->len - 2; i++ ){ + if( dtypes[i] ){ + switch( dtypes[i] ){ + case 'c': + rb_ary_push(dvals, CHR2FIX(*((char*)(ANY2P(args[i]))))); + break; + case 'h': + rb_ary_push(dvals, INT2NUM(*((short*)(ANY2P(args[i]))))); + break; + case 'i': + rb_ary_push(dvals, INT2NUM(*((int*)(ANY2P(args[i]))))); + break; + case 'l': + rb_ary_push(dvals, DLLONG2NUM(*((long*)(ANY2P(args[i]))))); + break; + case 'f': + rb_ary_push(dvals, rb_float_new(*((float*)(ANY2P(args[i]))))); + break; + case 'd': + rb_ary_push(dvals, rb_float_new(*((double*)(ANY2P(args[i]))))); + break; + case 'p': + rb_ary_push(dvals, rb_dlptr_new((void*)(ANY2P(args[i])), 0, 0)); + break; + case 'a': + rb_ary_push(dvals, rb_dlptr_new((void*)ANY2P(args[i]), 0, 0)); + break; + case 's': + rb_ary_push(dvals, rb_tainted_str_new2((char*)ANY2S(args[i]))); + DEBUG_CODE({ + printf("dlfree(%s)\n",(char*)ANY2S(args[i])); + }); + dlfree((void*)ANY2S(args[i])); + break; + default: + { + char c = dtypes[i]; + FREE_ARGS; + rb_raise(rb_eRuntimeError, "unknown argument type '%c'", i, c); + } + } + } + else{ + switch( sym->type[i+1] ){ + case 'A': + dlfree((void*)ANY2P(args[i])); + break; + } + rb_ary_push(dvals, argv[i]); + } + } + + FREE_ARGS; +#undef FREE_ARGS + return rb_assoc_new(val,dvals); +} + +VALUE +rb_dlsym_to_i(VALUE self) +{ + struct sym_data *sym; + + Data_Get_Struct(self, struct sym_data, sym); + return DLLONG2NUM(sym); +} + +VALUE +rb_dlsym_to_ptr(VALUE self) +{ + struct sym_data *sym; + + Data_Get_Struct(self, struct sym_data, sym); + return rb_dlptr_new(sym->func, sizeof(freefunc_t), 0); +} + +void +Init_dlsym() +{ + rb_cDLSymbol = rb_define_class_under(rb_mDL, "Symbol", rb_cObject); + rb_define_alloc_func(rb_cDLSymbol, rb_dlsym_s_allocate); + rb_define_singleton_method(rb_cDLSymbol, "char2type", rb_s_dlsym_char2type, 1); + rb_define_method(rb_cDLSymbol, "initialize", rb_dlsym_initialize, -1); + rb_define_method(rb_cDLSymbol, "call", rb_dlsym_call, -1); + rb_define_method(rb_cDLSymbol, "[]", rb_dlsym_call, -1); + rb_define_method(rb_cDLSymbol, "name", rb_dlsym_name, 0); + rb_define_method(rb_cDLSymbol, "proto", rb_dlsym_proto, 0); + rb_define_method(rb_cDLSymbol, "cproto", rb_dlsym_cproto, 0); + rb_define_method(rb_cDLSymbol, "inspect", rb_dlsym_inspect, 0); + rb_define_method(rb_cDLSymbol, "to_s", rb_dlsym_cproto, 0); + rb_define_method(rb_cDLSymbol, "to_ptr", rb_dlsym_to_ptr, 0); + rb_define_method(rb_cDLSymbol, "to_i", rb_dlsym_to_i, 0); + + rb_dl_id_DLErrno = rb_intern("DLErrno"); + rb_define_singleton_method(rb_mDL, "last_error", rb_dl_get_last_error, 0); + rb_define_singleton_method(rb_mDL, "last_error=", rb_dl_set_last_error, 1); +#ifdef _WIN32 + rb_dl_id_DLW32Error = rb_intern("DLW32Error"); + rb_define_singleton_method(rb_mDL, "win32_last_error", rb_dl_win32_get_last_error, 0); + rb_define_singleton_method(rb_mDL, "win32_last_error=", rb_dl_win32_set_last_error, 1); +#endif +} diff --git a/ruby_1_8_6/ext/dl/test/libtest.def b/ruby_1_8_6/ext/dl/test/libtest.def new file mode 100644 index 0000000000..8ecefc917b --- /dev/null +++ b/ruby_1_8_6/ext/dl/test/libtest.def @@ -0,0 +1,28 @@ +EXPORTS +test_alloc_test_struct +test_append +test_arylen +test_c2i +test_call_func1 +test_callback1 +test_close +test_d2f +test_f2d +test_fill_test_struct +test_fill_test_union +test_gets +test_i2c +test_init +test_isucc +test_lcc +test_lsucc +test_open +test_strcat +test_strlen +test_succ +test_data_init +test_data_add +test_data_aref +test_set_long_value +test_get_long_value +internal_long_value diff --git a/ruby_1_8_6/ext/dl/test/test.c b/ruby_1_8_6/ext/dl/test/test.c new file mode 100644 index 0000000000..7321379390 --- /dev/null +++ b/ruby_1_8_6/ext/dl/test/test.c @@ -0,0 +1,247 @@ +#include +#include + +static char internal_string[] = "internal_string"; +long internal_long_value = 100; + +struct test_struct { + char c; + long l; +}; + +union test_union { + char c; + int i; + long l; + void *p; +}; + +struct test_data { + char name[1024]; + struct test_data *next; +}; + +long +test_get_long_value() +{ + return internal_long_value; +}; + +void +test_set_long_value(long l) +{ + internal_long_value = l; +}; + +void +test_fill_test_struct(struct test_struct *ptr, char c, long l) +{ + ptr->c = c; + ptr->l = l; +}; + +void +test_fill_test_union(union test_union *ptr, long l) +{ + ptr->l = l; +}; + +struct test_struct * +test_alloc_test_struct(char c, long l) +{ + struct test_struct *data; + + data = (struct test_struct *)malloc(sizeof(struct test_struct)); + data->c = c; + data->l = l; + + return data; +}; + +int +test_c2i(char c) +{ + return (int)c; +}; + +char +test_i2c(int i) +{ + return (char)i; +}; + +long +test_lcc(char c1, char c2) +{ + return (long)(c1 + c2); +}; + +double +test_f2d(float f) +{ + double d; + d = f; + return d; +}; + +float +test_d2f(double d) +{ + float f; + f = d; + return f; +}; + +int +test_strlen(const char *str) +{ + return strlen(str); +}; + +int +test_isucc(int i) +{ + return (i+1); +}; + +long +test_lsucc(long l) +{ + return (l+1); +}; + +void +test_succ(long *l) +{ + (*l)++; +}; + +char * +test_strcat(char *str1, const char *str2) +{ + return strcat(str1, str2); +}; + +int +test_arylen(char *ary[]) +{ + int i; + for( i=0; ary[i]; i++ ){}; + return i; +}; + +void +test_append(char *ary[], int len, char *astr) +{ + int i; + int size1,size2; + char *str; + + size2 = strlen(astr); + + for( i=0; i <= len - 1; i++ ){ + size1 = strlen(ary[i]); + str = (char*)malloc(size1 + size2 + 1); + strcpy(str, ary[i]); + strcat(str, astr); + ary[i] = str; + }; +}; + +int +test_init(int *argc, char **argv[]) +{ + int i; + char s[256]; + + for( i=0; i < (*argc); i++ ){ + sprintf(s, "arg%d", i); + if( strcmp((*argv)[i], s) != 0 ){ + return 1; + } + } + return 0; +} + +FILE * +test_open(const char *filename, const char *mode) +{ + FILE *file; + file = fopen(filename,mode); + return file; +}; + +void +test_close(FILE *file) +{ + fclose(file); +}; + +char * +test_gets(char *s, int size, FILE *f) +{ + return fgets(s,size,f); +}; + +typedef int callback1_t(int, char *); +#define CALLBACK_MSG "callback message" + +int +test_callback1(int err, const char *msg) +{ + if( strcmp(msg, CALLBACK_MSG) == 0 ){ + return 1; + } + else{ + return 0; + } +} + +int +test_call_func1(callback1_t *func) +{ + if( func ){ + return (*func)(0, CALLBACK_MSG); + } + else{ + return 0; + } +} + +struct test_data * +test_data_init() +{ + struct test_data *data; + + data = (struct test_data *)malloc(sizeof(struct test_data)); + data->next = NULL; + memset(data->name, 0, 1024); + + return data; +}; + +void +test_data_add(struct test_data *list, const char *name) +{ + struct test_data *data; + + data = (struct test_data *)malloc(sizeof(struct test_data)); + memset(data->name, 0, 1024); + strncpy(data->name, name, 1024); + data->next = list->next; + list->next = data; +}; + +struct test_data * +test_data_aref(struct test_data *list, int i) +{ + struct test_data *data; + int j; + + for( data = list->next, j=0; data; data = data->next, j++ ){ + if( i == j ){ + return data; + }; + }; + return NULL; +}; diff --git a/ruby_1_8_6/ext/dl/test/test.rb b/ruby_1_8_6/ext/dl/test/test.rb new file mode 100644 index 0000000000..bf8dfc18e3 --- /dev/null +++ b/ruby_1_8_6/ext/dl/test/test.rb @@ -0,0 +1,306 @@ +# -*- ruby -*- + +require 'dl' +require 'dl/import' + +$FAIL = 0 +$TOTAL = 0 + +def assert(label, ty, *conds) + $TOTAL += 1 + cond = !conds.include?(false) + if( cond ) + printf("succeed in `#{label}'\n") + else + $FAIL += 1 + case ty + when :may + printf("fail in `#{label}' ... expected\n") + when :must + printf("fail in `#{label}' ... unexpected\n") + when :raise + raise(RuntimeError, "fail in `#{label}'") + end + end +end + +def debug(*xs) + if( $DEBUG ) + xs.each{|x| + p x + } + end +end + +print("DLSTACK = #{DL::DLSTACK}\n") +print("MAX_ARG = #{DL::MAX_ARG}\n") +print("\n") +print("DL::FREE = #{DL::FREE.inspect}\n") +print("\n") + +$LIB = nil +if( !$LIB && File.exist?("libtest.so") ) + $LIB = "./libtest.so" +end +if( !$LIB && File.exist?("test/libtest.so") ) + $LIB = "./test/libtest.so" +end + +module LIBTest + extend DL::Importable + + dlload($LIB) + extern "int test_c2i(char)" + extern "char test_i2c(int)" + extern "long test_lcc(char, char)" + extern "double test_f2d(float)" + extern "float test_d2f(double)" + extern "int test_strlen(char*)" + extern "int test_isucc(int)" + extern "long test_lsucc(long)" + extern "void test_succ(long *)" + extern "int test_arylen(int [])" + extern "void test_append(char*[], int, char *)" +end + +DL.dlopen($LIB){|h| + c2i = h["test_c2i","IC"] + debug c2i + r,rs = c2i[?a] + debug r,rs + assert("c2i", :may, r == ?a) + assert("extern c2i", :must, r == LIBTest.test_c2i(?a)) + + i2c = h["test_i2c","CI"] + debug i2c + r,rs = i2c[?a] + debug r,rs + assert("i2c", :may, r == ?a) + assert("exern i2c", :must, r == LIBTest.test_i2c(?a)) + + lcc = h["test_lcc","LCC"] + debug lcc + r,rs = lcc[1,2] + assert("lcc", :may, r == 3) + assert("extern lcc", :must, r == LIBTest.test_lcc(1,2)) + + f2d = h["test_f2d","DF"] + debug f2d + r,rs = f2d[20.001] + debug r,rs + assert("f2d", :may, r.to_i == 20) + assert("extern f2d", :must, r = LIBTest.test_f2d(20.001)) + + d2f = h["test_d2f","FD"] + debug d2f + r,rs = d2f[20.001] + debug r,rs + assert("d2f", :may, r.to_i == 20) + assert("extern d2f", :must, r == LIBTest.test_d2f(20.001)) + + strlen = h["test_strlen","IS"] + debug strlen + r,rs = strlen["0123456789"] + debug r,rs + assert("strlen", :must, r == 10) + assert("extern strlen", :must, r == LIBTest.test_strlen("0123456789")) + + isucc = h["test_isucc","II"] + debug isucc + r,rs = isucc[2] + debug r,rs + assert("isucc", :must, r == 3) + assert("extern isucc", :must, r == LIBTest.test_isucc(2)) + + lsucc = h["test_lsucc","LL"] + debug lsucc + r,rs = lsucc[10000000] + debug r,rs + assert("lsucc", :must, r == 10000001) + assert("extern lsucc", :must, r == LIBTest.test_lsucc(10000000)) + + succ = h["test_succ","0l"] + debug succ + r,rs = succ[0] + debug r,rs + assert("succ", :must, rs[0] == 1) + l = DL.malloc(DL.sizeof("L")) + l.struct!("L",:lval) + LIBTest.test_succ(l) + assert("extern succ", :must, rs[0] == l[:lval]) + + arylen = h["test_arylen","IA"] + debug arylen + r,rs = arylen[["a","b","c","d",nil]] + debug r,rs + assert("arylen", :must, r == 4) + + arylen = h["test_arylen","IP"] + debug arylen + r,rs = arylen[["a","b","c","d",nil]] + debug r,rs + assert("arylen", :must, r == 4) + assert("extern arylen", :must, r == LIBTest.test_arylen(["a","b","c","d",nil])) + + append = h["test_append","0aIS"] + debug append + r,rs = append[["a","b","c"],3,"x"] + debug r,rs + assert("append", :must, rs[0].to_a('S',3) == ["ax","bx","cx"]) + + LIBTest.test_append(["a","b","c"],3,"x") + assert("extern append", :must, rs[0].to_a('S',3) == LIBTest._args_[0].to_a('S',3)) + + strcat = h["test_strcat","SsS"] + debug strcat + r,rs = strcat["abc\0","x"] + debug r,rs + assert("strcat", :must, rs[0].to_s == "abcx") + + init = h["test_init","IiP"] + debug init + argc = 3 + argv = ["arg0","arg1","arg2"].to_ptr + r,rs = init[argc, argv.ref] + assert("init", :must, r == 0) +} + + +h = DL.dlopen($LIB) + +sym_open = h["test_open", "PSS"] +sym_gets = h["test_gets", "SsIP"] +sym_close = h["test_close", "0P"] +debug sym_open,sym_gets,sym_close + +line = "Hello world!\n" +File.open("tmp.txt", "w"){|f| + f.print(line) +} + +fp,rs = sym_open["tmp.txt", "r"] +if( fp ) + fp.free = sym_close + r,rs = sym_gets[" " * 256, 256, fp] + debug r,rs + assert("open,gets", :must, rs[0] == line) + ObjectSpace.define_finalizer(fp) {File.unlink("tmp.txt")} + fp = nil +else + assert("open,gets", :must, line == nil) + File.unlink("tmp.txt") +end + + +callback1 = h["test_callback1"] +debug callback1 +r,rs = h["test_call_func1", "IP"][callback1] +debug r,rs +assert("callback1", :must, r == 1) + + +callback2 = DL.callback("LLP"){|num,ptr| + msg = ptr.to_s + if( msg == "callback message" ) + 2 + else + 0 + end +} +debug callback2 +r,rs = h["test_call_func1", "IP"][callback2] +debug r,rs +assert("callback2", :must, r == 2) +DL.remove_callback(callback2) + +ptr = DL.malloc(DL.sizeof('CL')) +ptr.struct!("CL", :c, :l) +ptr["c"] = 0 +ptr["l"] = 0 +r,rs = h["test_fill_test_struct","0PIL"][ptr,100,1000] +debug r,rs +assert("fill_test_struct", :must, ptr["c"] == 100, ptr["l"] == 1000) +assert("fill_test_struct", :must, ptr[:c] == 100, ptr[:l] == 1000) unless (Fixnum === :-) + + +r,rs = h["test_alloc_test_struct", "PIL"][100,200] +r.free = DL::FREE +r.struct!("CL", :c, :l) +assert("alloc_test_struct", :must, r["c"] == 100, r["l"] == 200) +assert("alloc_test_struct", :must, r[:c] == 100, r[:l] == 200) unless (Fixnum === :-) + +ptr = h["test_strlen"] +sym1 = DL::Symbol.new(ptr,"foo","0") +sym2 = h["test_strlen","LS"] +assert("Symbol.new", :must, ptr == sym1.to_ptr, sym1.to_ptr == sym2.to_ptr) + +set_val = h["test_set_long_value","0"] +get_val = h["test_get_long_value","L"] +lval = get_val[][0] +ptr = h["internal_long_value"] +ptr.struct!("L", :l) +assert("get value", :must, ptr["l"] == lval) +assert("get value", :must, ptr[:l] == lval) unless (Fixnum === :-) +ptr["l"] = 200 +lval = get_val[][0] +assert("set value", :must, ptr["l"] == lval) +assert("set value", :must, ptr[:l] == lval) unless (Fixnum === :-) + + +data_init = h["test_data_init", "P"] +data_add = h["test_data_add", "0PS"] +data_aref = h["test_data_aref", "PPI"] +r,rs = data_init[] +ptr = r +data_add[ptr, "name1"] +data_add[ptr, "name2"] +data_add[ptr, "name3"] + +r,rs = data_aref[ptr, 1] +ptr = r +ptr.struct!("C1024P", :name, :next) +assert("data_aref", :must, + ptr["name"].collect{|c| c.chr}.join.split("\0")[0] == "name2") +assert("data_aref", :must, + ptr["name"].collect{|c| c.chr}.join.split("\0")[0] == "name2") unless (Fixnum === :-) + +ptr = ptr["next"] +ptr.struct!("C1024P", :name, :next) +assert("data_aref", :must, + ptr["name"].collect{|c| c.chr}.join.split("\0")[0] == "name1") +assert("data_aref", :must, + ptr["name"].collect{|c| c.chr}.join.split("\0")[0] == "name1") unless (Fixnum === :-) + +GC.start + +ptr = DL::malloc(32) +ptr.struct!("CHIL", "c", "h", "i", "l") +ptr["c"] = 1 +ptr["h"] = 2 +ptr["i"] = 3 +ptr["l"] = 4 +assert("struct!", :must, + ptr["c"] == 1 && + ptr["h"] == 2 && + ptr["i"] == 3 && + ptr["l"] == 4) + +ptr = DL::malloc(DL::sizeof("IP")) +ptr.struct!("IP", "n", "ptr") +ptr["n"] = 10 +ptr["ptr"] = nil +assert("struct!", :must, ptr["n"] == 10 && ptr["ptr"] == nil) + +ptr = DL::malloc(16) +ptr.struct!("CICI", "c1", "i1", "c2", "i2") +ptr["c1"] = 0xf1 +ptr["c2"] = 0xf2 +c1 = [ptr["c1"]].pack("c").unpack("C")[0] +c2 = [ptr["c2"]].pack("c").unpack("C")[0] +assert("struct!", :must, + c1 == 0xf1 && + c2 == 0xf2) + + +GC.start +printf("fail/total = #{$FAIL}/#{$TOTAL}\n") diff --git a/ruby_1_8_6/ext/dl/type.rb b/ruby_1_8_6/ext/dl/type.rb new file mode 100644 index 0000000000..804420c395 --- /dev/null +++ b/ruby_1_8_6/ext/dl/type.rb @@ -0,0 +1,115 @@ +# example: +# DLTYPE[INT][:rb2c]["arg0"] => "NUM2INT(arg0)" +# DLTYPE[DOUBLE][:c2rb]["r"] => "rb_float_new(r)" + +DLTYPE = { + VOID = 0x00 => { + :name => 'VOID', + :rb2c => nil, + :c2rb => nil, + :ctype => "void", + :stmem => "v", + :sym => true, + :cb => true, + }, + CHAR = 0x01 => { + :name => 'CHAR', + :rb2c => proc{|x| "NUM2CHR(#{x})"}, + :c2rb => proc{|x| "CHR2FIX(#{x})"}, + :ctype => "char", + :stmem => "c", + :sym => false, + :cb => false, + }, + SHORT = 0x02 => { + :name => 'SHORT', + :rb2c => proc{|x| "FIX2INT(#{x})"}, + :c2rb => proc{|x| "INT2FIX(#{x})"}, + :ctype => "short", + :stmem => "h", + :sym => false, + :cb => false, + }, + INT = 0x03 => { + :name => 'INT', + :rb2c => proc{|x| "NUM2INT(#{x})"}, + :c2rb => proc{|x| "INT2NUM(#{x})"}, + :ctype => "int", + :stmem => "i", + :sym => true, + :cb => false, + }, + LONG = 0x04 => { + :name => 'LONG', + :rb2c => proc{|x| "NUM2INT(#{x})"}, + :c2rb => proc{|x| "INT2NUM(#{x})"}, + :ctype => "long", + :stmem => "l", + :sym => true, + :cb => true, + }, + FLOAT = 0x05 => { + :name => 'FLOAT', + :rb2c => proc{|x| "(float)(RFLOAT(#{x})->value)"}, + :c2rb => proc{|x| "rb_float_new((double)#{x})"}, + :ctype => "float", + :stmem => "f", + :sym => false, + :cb => false, + }, + DOUBLE = 0x06 => { + :name => 'DOUBLE', + :rb2c => proc{|x| "RFLOAT(#{x})->value"}, + :c2rb => proc{|x| "rb_float_new(#{x})"}, + :ctype => "double", + :stmem => "d", + :sym => true, + :cb => true, + }, + VOIDP = 0x07 => { + :name => 'VOIDP', + :rb2c => proc{|x| "rb_dlptr2cptr(#{x})"}, + :c2rb => proc{|x| "rb_dlptr_new(#{x},sizeof(void*),0)"}, + :ctype => "void *", + :stmem => "p", + :sym => true, + :cb => true, + }, +} + +def tpush(t, x) + (t << 3)|x +end + +def tget(t, i) + (t & (0x07 << (i * 3))) >> (i * 3) +end + +def types2num(types) + res = 0x00 + r = types.reverse + r.each{|t| + res = tpush(res,t) + } + res +end + +def num2types(num) + ts = [] + i = 0 + t = tget(num,i) + while( (t != VOID && i > 0) || (i == 0) ) + ts.push(DLTYPE[t][:ctype]) + i += 1 + t = tget(num,i) + end + ts +end + +def types2ctypes(types) + res = [] + types.each{|t| + res.push(DLTYPE[t][:ctype]) + } + res +end -- cgit v1.2.3