зеркало из https://github.com/github/ruby.git
remove all files to replace ruby-dl with ruby-dl2.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@7882 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
Родитель
889ca023e3
Коммит
4ae9132605
|
@ -1,46 +0,0 @@
|
|||
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"
|
721
ext/dl/dl.c
721
ext/dl/dl.c
|
@ -1,721 +0,0 @@
|
|||
/* -*- mode: C; c-file-style: "gnu" -*-
|
||||
/*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include <ruby.h>
|
||||
#include <rubyio.h>
|
||||
#include <ctype.h>
|
||||
#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, "scan_callback_args: 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));
|
||||
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; i<len; i++) {
|
||||
n = 1;
|
||||
if (ISDIGIT(cstr[i+1])) {
|
||||
dlen = 1;
|
||||
while (ISDIGIT(cstr[i+dlen])) { dlen ++; };
|
||||
dlen --;
|
||||
d = ALLOCA_N(char, dlen + 1);
|
||||
strncpy(d, cstr + i + 1, dlen);
|
||||
d[dlen] = '\0';
|
||||
n = atoi(d);
|
||||
}
|
||||
else{
|
||||
dlen = 0;
|
||||
}
|
||||
|
||||
switch (cstr[i]) {
|
||||
case 'I':
|
||||
DLALIGN(0,size,INT_ALIGN);
|
||||
case 'i':
|
||||
size += sizeof(int) * n;
|
||||
break;
|
||||
case 'L':
|
||||
DLALIGN(0,size,LONG_ALIGN);
|
||||
case 'l':
|
||||
size += sizeof(long) * n;
|
||||
break;
|
||||
case 'F':
|
||||
DLALIGN(0,size,FLOAT_ALIGN);
|
||||
case 'f':
|
||||
size += sizeof(float) * n;
|
||||
break;
|
||||
case 'D':
|
||||
DLALIGN(0,size,DOUBLE_ALIGN);
|
||||
case 'd':
|
||||
size += sizeof(double) * n;
|
||||
break;
|
||||
case 'C':
|
||||
case 'c':
|
||||
size += sizeof(char) * n;
|
||||
break;
|
||||
case 'H':
|
||||
DLALIGN(0,size,SHORT_ALIGN);
|
||||
case 'h':
|
||||
size += sizeof(short) * n;
|
||||
break;
|
||||
case 'P':
|
||||
case 'S':
|
||||
DLALIGN(0,size,VOIDP_ALIGN);
|
||||
case 'p':
|
||||
case 's':
|
||||
size += sizeof(void*) * n;
|
||||
break;
|
||||
default:
|
||||
rb_raise(rb_eDLTypeError, "unexpected type '%c'", cstr[i]);
|
||||
break;
|
||||
}
|
||||
i += dlen;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static float *
|
||||
c_farray(VALUE v, long *size)
|
||||
{
|
||||
int i, len;
|
||||
float *ary;
|
||||
VALUE e;
|
||||
|
||||
len = RARRAY(v)->len;
|
||||
*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{
|
||||
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(TYPE(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);
|
||||
}
|
||||
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 = rb_io_stdio_file(fptr);
|
||||
|
||||
return fp ? rb_dlptr_new(fp, sizeof(FILE), 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)
|
||||
{
|
||||
void *ptr;
|
||||
long len;
|
||||
|
||||
SafeStringValue(str);
|
||||
len = RSTRING(str)->len;
|
||||
ptr = memcpy(dlmalloc(len + 1), RSTRING(str)->ptr, len + 1);
|
||||
((char *)ptr)[len] = '\0';
|
||||
return rb_dlptr_new(ptr, 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);
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
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
|
313
ext/dl/dl.h
313
ext/dl/dl.h
|
@ -1,313 +0,0 @@
|
|||
/* -*- mode: C; c-file-style: "gnu" -*-
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef RUBY_DL_H
|
||||
#define RUBY_DL_H
|
||||
|
||||
#include <ruby.h>
|
||||
#include <dlconfig.h>
|
||||
|
||||
#if defined(HAVE_DLFCN_H)
|
||||
# include <dlfcn.h>
|
||||
# /* some stranger systems may not define all of these */
|
||||
#ifndef RTLD_LAZY
|
||||
#define RTLD_LAZY 0
|
||||
#endif
|
||||
#ifndef RTLD_GLOBAL
|
||||
#define RTLD_GLOBAL 0
|
||||
#endif
|
||||
#ifndef RTLD_NOW
|
||||
#define RTLD_NOW 0
|
||||
#endif
|
||||
#else
|
||||
# if defined(HAVE_WINDOWS_H)
|
||||
# include <windows.h>
|
||||
# define dlclose(ptr) FreeLibrary((HINSTANCE)ptr)
|
||||
# define dlopen(name,flag) ((void*)LoadLibrary(name))
|
||||
# define dlerror() "unknown error"
|
||||
# define dlsym(handle,name) ((void*)GetProcAddress(handle,name))
|
||||
# define RTLD_LAZY -1
|
||||
# define RTLD_NOW -1
|
||||
# define RTLD_GLOBAL -1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#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 */
|
|
@ -1,266 +0,0 @@
|
|||
=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
|
|
@ -1,193 +0,0 @@
|
|||
require 'mkmf'
|
||||
|
||||
begin # for the exception SystemExit
|
||||
|
||||
$:.unshift File.dirname(__FILE__)
|
||||
require 'type'
|
||||
|
||||
if( ARGV.include?("--help") )
|
||||
print <<EOF
|
||||
--help print this messages
|
||||
--with-type-char strictly use type 'char'
|
||||
--with-type-short strictly use type 'short'
|
||||
--with-type-float strictly use type 'float'
|
||||
--with-args=<max_arg>
|
||||
--with-callback=<max_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(<<EOF)
|
||||
#include "config.h"
|
||||
#if SIZEOF_INT == SIZEOF_LONG
|
||||
#error int not needed
|
||||
#endif
|
||||
EOF
|
||||
|
||||
$with_type_float = try_cpp(<<EOF)
|
||||
#include "config.h"
|
||||
#if SIZEOF_FLOAT == SIZEOF_DOUBLE
|
||||
#error float not needed
|
||||
#endif
|
||||
EOF
|
||||
|
||||
$with_type_voidp = try_cpp(<<EOF)
|
||||
#include "config.h"
|
||||
#if SIZEOF_VOIDP == SIZEOF_INT || SIZEOF_VOIDP == SIZEOF_LONG
|
||||
#error void* not needed
|
||||
#endif
|
||||
EOF
|
||||
|
||||
$with_type_char = DLTYPE[CHAR][:sym]
|
||||
$with_type_short = DLTYPE[SHORT][:sym]
|
||||
$with_type_long = DLTYPE[LONG][:sym]
|
||||
$with_type_double= DLTYPE[DOUBLE][:sym]
|
||||
$with_type_int &= DLTYPE[INT][:sym]
|
||||
$with_type_float &= DLTYPE[FLOAT][:sym]
|
||||
$with_type_voidp &= DLTYPE[VOIDP][:sym]
|
||||
|
||||
$with_type_char = enable_config("type-char", $with_type_char)
|
||||
$with_type_short = enable_config("type-short", $with_type_short)
|
||||
$with_type_float = enable_config("type-float", $with_type_float)
|
||||
|
||||
$with_asm = enable_config("asm", $with_asm)
|
||||
$with_dlstack = enable_config("dlstack", $with_dlstack)
|
||||
|
||||
args = with_config("args")
|
||||
max_arg = nil
|
||||
if( $with_asm || $with_dlstack )
|
||||
$with_type_char = true
|
||||
$with_type_short = true
|
||||
$with_type_float = true
|
||||
max_arg = 0
|
||||
end
|
||||
if( args )
|
||||
max_arg = args.to_i
|
||||
if( !max_arg )
|
||||
print("--with-args=<max_arg>\n")
|
||||
exit(1)
|
||||
end
|
||||
end
|
||||
max_arg ||= 6
|
||||
|
||||
max_callback = with_config("callback","10").to_i
|
||||
callback_types = DLTYPE.keys.length
|
||||
|
||||
|
||||
$dlconfig_h = <<EOF
|
||||
#define MAX_ARG #{max_arg}
|
||||
EOF
|
||||
|
||||
def dlc_define(const)
|
||||
$dlconfig_h << "#if !defined(#{const})\n" +
|
||||
"# define #{const}\n" +
|
||||
"#endif\n"
|
||||
end
|
||||
|
||||
$dlconfig_h << "#define MAX_CALLBACK #{max_callback}\n"
|
||||
$dlconfig_h << "#define CALLBACK_TYPES #{callback_types}\n"
|
||||
if( $with_dlstack )
|
||||
$dlconfig_h << "#define USE_DLSTACK\n"
|
||||
else
|
||||
if( $with_asm )
|
||||
$dlconfig_h << "#define USE_INLINE_ASM\n"
|
||||
end
|
||||
end
|
||||
if( $with_type_char )
|
||||
$dlconfig_h << "#define WITH_TYPE_CHAR\n"
|
||||
end
|
||||
if( $with_type_short )
|
||||
$dlconfig_h << "#define WITH_TYPE_SHORT\n"
|
||||
end
|
||||
if( $with_type_long )
|
||||
$dlconfig_h << "#define WITH_TYPE_LONG\n"
|
||||
end
|
||||
if( $with_type_double )
|
||||
$dlconfig_h << "#define WITH_TYPE_DOUBLE\n"
|
||||
end
|
||||
if( $with_type_float )
|
||||
$dlconfig_h << "#define WITH_TYPE_FLOAT\n"
|
||||
end
|
||||
if( $with_type_int )
|
||||
$dlconfig_h << "#define WITH_TYPE_INT\n"
|
||||
end
|
||||
if( $with_type_voidp )
|
||||
$dlconfig_h << "#define WITH_TYPE_VOIDP\n"
|
||||
end
|
||||
|
||||
if( have_header("windows.h") )
|
||||
have_library("kernel32")
|
||||
have_func("GetLastError", "windows.h")
|
||||
dlc_define("HAVE_WINDOWS_H")
|
||||
have_windows_h = true
|
||||
end
|
||||
|
||||
if( have_header("dlfcn.h") )
|
||||
dlc_define("HAVE_DLFCN_H")
|
||||
have_library("dl")
|
||||
have_func("dlopen")
|
||||
have_func("dlclose")
|
||||
have_func("dlsym")
|
||||
if( have_func("dlerror") )
|
||||
dlc_define("HAVE_DLERROR")
|
||||
end
|
||||
elsif ( have_windows_h )
|
||||
have_func("LoadLibrary")
|
||||
have_func("FreeLibrary")
|
||||
have_func("GetProcAddress")
|
||||
else
|
||||
exit(0)
|
||||
end
|
||||
|
||||
def File.update(file, str)
|
||||
begin
|
||||
open(file){|f|f.read} == str
|
||||
rescue Errno::ENOENT
|
||||
false
|
||||
end or open(file, "w"){|f|f.print(str)}
|
||||
end
|
||||
|
||||
File.update("dlconfig.h", <<EOF)
|
||||
#ifndef DLCONFIG_H
|
||||
#define DLCONFIG_H
|
||||
#{$dlconfig_h}
|
||||
#endif /* DLCONFIG_H */
|
||||
EOF
|
||||
|
||||
File.update("dlconfig.rb", <<EOF)
|
||||
MAX_ARG = #{max_arg}
|
||||
MAX_CALLBACK = #{max_callback}
|
||||
CALLBACK_TYPES = #{callback_types}
|
||||
DLTYPE[CHAR][:sym] = #{$with_type_char}
|
||||
DLTYPE[SHORT][:sym] = #{$with_type_short}
|
||||
DLTYPE[INT][:sym] = #{$with_type_int}
|
||||
DLTYPE[LONG][:sym] = #{$with_type_long}
|
||||
DLTYPE[FLOAT][:sym] = #{$with_type_float}
|
||||
DLTYPE[DOUBLE][:sym]= #{$with_type_double}
|
||||
DLTYPE[VOIDP][:sym] = #{$with_type_voidp}
|
||||
EOF
|
||||
|
||||
$INSTALLFILES = [
|
||||
["./dlconfig.h", "$(archdir)$(target_prefix)", "."],
|
||||
["dl.h", "$(archdir)$(target_prefix)", ""],
|
||||
]
|
||||
$cleanfiles = %w[test/test.o]
|
||||
$distcleanfiles = %w[call.func callback.func cbtable.func dlconfig.rb
|
||||
./dlconfig.h test/libtest.so test/*~ *~ mkmf.log]
|
||||
|
||||
create_makefile('dl')
|
||||
rescue SystemExit
|
||||
# do nothing
|
||||
end
|
500
ext/dl/h2rb
500
ext/dl/h2rb
|
@ -1,500 +0,0 @@
|
|||
#!/usr/bin/env ruby
|
||||
# -*- ruby -*-
|
||||
# $Id$
|
||||
|
||||
require 'mkmf'
|
||||
require 'ftools'
|
||||
|
||||
$recursive = false
|
||||
$force = false
|
||||
$conly = true
|
||||
$inc_path = []
|
||||
$infilename= nil
|
||||
$insert_require = true
|
||||
|
||||
def valid_ruby_code?(code)
|
||||
begin
|
||||
eval("BEGIN {return true}; #{code}")
|
||||
rescue SyntaxError
|
||||
return false
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
def print_usage
|
||||
print <<EOF
|
||||
h2rb [-r] [-I <path>] [-d] [<filename>]
|
||||
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)
|
215
ext/dl/handle.c
215
ext/dl/handle.c
|
@ -1,215 +0,0 @@
|
|||
/* -*- mode: C; c-file-style: "gnu" -*-
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include <ruby.h>
|
||||
#include "dl.h"
|
||||
|
||||
VALUE rb_cDLHandle;
|
||||
|
||||
void
|
||||
dlhandle_free(struct dl_handle *dlhandle)
|
||||
{
|
||||
if (dlhandle->ptr && dlhandle->open && dlhandle->enable_close) {
|
||||
dlclose(dlhandle->ptr);
|
||||
}
|
||||
}
|
||||
|
||||
VALUE
|
||||
rb_dlhandle_close(VALUE self)
|
||||
{
|
||||
struct dl_handle *dlhandle;
|
||||
|
||||
Data_Get_Struct(self, struct dl_handle, dlhandle);
|
||||
dlhandle->open = 0;
|
||||
return INT2NUM(dlclose(dlhandle->ptr));
|
||||
}
|
||||
|
||||
VALUE
|
||||
rb_dlhandle_s_allocate(VALUE klass)
|
||||
{
|
||||
VALUE obj;
|
||||
struct dl_handle *dlhandle;
|
||||
|
||||
obj = Data_Make_Struct(rb_cDLHandle, struct dl_handle, 0,
|
||||
dlhandle_free, dlhandle);
|
||||
dlhandle->ptr = 0;
|
||||
dlhandle->open = 0;
|
||||
dlhandle->enable_close = 0;
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
VALUE
|
||||
rb_dlhandle_initialize(int argc, VALUE argv[], VALUE self)
|
||||
{
|
||||
void *ptr;
|
||||
struct dl_handle *dlhandle;
|
||||
VALUE lib, flag;
|
||||
char *clib;
|
||||
int cflag;
|
||||
const char *err;
|
||||
|
||||
switch (rb_scan_args(argc, argv, "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, err);
|
||||
}
|
||||
#else
|
||||
if (!ptr) {
|
||||
err = dlerror();
|
||||
rb_raise(rb_eRuntimeError, 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);
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
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()
|
|
@ -1,224 +0,0 @@
|
|||
# -*- 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
|
||||
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",
|
||||
" @retval",
|
||||
"}",
|
||||
].join("\n"))
|
||||
|
||||
@SYM[func] = [sym,rdec,enc,dec]
|
||||
|
||||
return sym
|
||||
end
|
||||
|
||||
# example:
|
||||
# typealias("uint", "unsigned int")
|
||||
#
|
||||
def typealias(*args)
|
||||
init_types()
|
||||
@types.typealias(*args)
|
||||
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 @retval",
|
||||
"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
|
|
@ -1,149 +0,0 @@
|
|||
# -*- 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
|
|
@ -1,245 +0,0 @@
|
|||
# -*- 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
|
|
@ -1,25 +0,0 @@
|
|||
# -*- ruby -*-
|
||||
|
||||
require 'dl'
|
||||
|
||||
class Win32API
|
||||
DLL = {}
|
||||
|
||||
def initialize(dllname, func, import, export = "0")
|
||||
prototype = (export + import.to_s).tr("VPpNnLlIi", "0SSI")
|
||||
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
|
|
@ -1,62 +0,0 @@
|
|||
# -*- 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)
|
||||
<<EOF
|
||||
case #{num}:
|
||||
#ifdef DEBUG
|
||||
printf("#{callfunc_stm}\\n");
|
||||
#endif
|
||||
#{callfunc_stm};
|
||||
break;
|
||||
EOF
|
||||
end
|
||||
|
||||
def rec_output(types = [VOID])
|
||||
print output_case(types)
|
||||
if( types.length <= MAX_ARG )
|
||||
DLTYPE.keys.sort.each{|t|
|
||||
if( t != VOID && DLTYPE[t][:sym] )
|
||||
rec_output(types + [t])
|
||||
end
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
DLTYPE.keys.sort.each{|t|
|
||||
if( DLTYPE[t][:sym] )
|
||||
$stderr.printf(" #{DLTYPE[t][:ctype]}\n")
|
||||
rec_output([t])
|
||||
end
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
# -*- ruby -*-
|
||||
|
||||
require 'mkmf'
|
||||
$:.unshift File.dirname(__FILE__)
|
||||
require 'type'
|
||||
require 'dlconfig'
|
||||
|
||||
def mkfunc(rettype, fnum, argc)
|
||||
args = (0..(argc-1)).collect{|i| "long arg#{i}"}.join(", ")
|
||||
|
||||
subst_code = (0..(argc-1)).collect{|i|
|
||||
" buff[#{i.to_s}] = arg#{i.to_s};"
|
||||
}.join("\n")
|
||||
|
||||
ret_code =
|
||||
if( DLTYPE[rettype][:c2rb] )
|
||||
" return #{DLTYPE[rettype][:rb2c]['retval']};"
|
||||
else
|
||||
" /* no return value */"
|
||||
end
|
||||
|
||||
code = [
|
||||
"static #{DLTYPE[rettype][:ctype]}",
|
||||
"rb_dl_callback_func_#{rettype.to_s}_#{fnum.to_s}(#{args})",
|
||||
"{",
|
||||
" VALUE retval, proto, proc, obj;",
|
||||
" VALUE argv[#{argc.to_s}];",
|
||||
" int argc;",
|
||||
" long buff[#{argc.to_s}];",
|
||||
"",
|
||||
subst_code,
|
||||
"",
|
||||
" obj = rb_hash_aref(DLFuncTable, rb_assoc_new(INT2NUM(#{rettype.to_s}),INT2NUM(#{fnum.to_s})));",
|
||||
" proto = rb_ary_entry(obj, 0);",
|
||||
" proc = rb_ary_entry(obj, 1);",
|
||||
" Check_Type(proto, T_STRING);",
|
||||
" if( RSTRING(proto)->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
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
# -*- 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
|
||||
}
|
1083
ext/dl/ptr.c
1083
ext/dl/ptr.c
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,35 +0,0 @@
|
|||
#include <stdio.h>
|
||||
|
||||
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;
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
=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()
|
|
@ -1,70 +0,0 @@
|
|||
# -*- 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")
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
require 'dl'
|
||||
|
||||
crtdll = DL::dlopen("crtdll")
|
||||
getch = crtdll['_getch', 'L']
|
||||
print(getch.call, "\n")
|
|
@ -1,69 +0,0 @@
|
|||
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)
|
|
@ -1,19 +0,0 @@
|
|||
# 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
|
|
@ -1,18 +0,0 @@
|
|||
# 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
|
|
@ -1,87 +0,0 @@
|
|||
# -*- 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
|
||||
}
|
991
ext/dl/sym.c
991
ext/dl/sym.c
|
@ -1,991 +0,0 @@
|
|||
/* -*- mode: C; c-file-style: "gnu" -*-
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include <ruby.h>
|
||||
#include <errno.h>
|
||||
#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,
|
||||
"#<DL::Symbol:0x%p func=0x%p '%s'>",
|
||||
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 <windows.h>
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
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
|
|
@ -1,247 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
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;
|
||||
};
|
|
@ -1,295 +0,0 @@
|
|||
# -*- 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(1024)
|
||||
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)
|
||||
|
||||
GC.start
|
||||
printf("fail/total = #{$FAIL}/#{$TOTAL}\n")
|
115
ext/dl/type.rb
115
ext/dl/type.rb
|
@ -1,115 +0,0 @@
|
|||
# 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
|
Загрузка…
Ссылка в новой задаче