Add ruby-dl
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@2324 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
64b6406445
commit
7d711b817e
166
ext/dl/Changes
Normal file
166
ext/dl/Changes
Normal file
@ -0,0 +1,166 @@
|
||||
1.0.2 -> 1.1.0
|
||||
---------------
|
||||
* Use inline assembler for gcc on ix86 as a default.
|
||||
* Add DL::Importable module (defined in "dl/import.rb").
|
||||
|
||||
1.0.1 -> 1.0.2
|
||||
--------------
|
||||
* Fix an installation problem, thanks to Nakada.
|
||||
* Handle#to_i, to_ptr is added.
|
||||
* lib/dl/win32.rb is added for Win32API compatibility.
|
||||
|
||||
1.0 -> 1.0.1
|
||||
-------------
|
||||
* Fix PtrData#to_s.
|
||||
* Add PtrData#to_str(size).
|
||||
|
||||
0.9 -> 1.0 (stable)
|
||||
-------------------
|
||||
* PtrData object keeps size data if possible.
|
||||
* PtrData#size is added.
|
||||
* LoadLibary(), FreeLibrary() and GetProcAddress() are used on
|
||||
windows instead of dlopen(),dlclose() and dlsym().
|
||||
|
||||
0.8.1 -> 0.9
|
||||
------------
|
||||
* You can use inline assembler to constracting the function calls by
|
||||
building the library using --with-asm options for extconf.rb.
|
||||
But now this can work with GNU assembler on i386 machines. If you try
|
||||
this mechanism, you can get rid of the limit of number of parameters.
|
||||
|
||||
0.8 -> 0.8.1
|
||||
-------------
|
||||
* rb_dlsym_call() calls xmalloc() or dlmalloc() instread of
|
||||
alloca() because of portability.
|
||||
|
||||
* 'h2rb' get to parse the enumeration type.
|
||||
|
||||
0.7.1 -> 0.8
|
||||
-------------
|
||||
* If <type> of Symbol.new(addr, name = nil, type = nil) is nil,
|
||||
it returns a DataPtr object.
|
||||
|
||||
* PtrData#[] returns the memory image, and PtrData#[]= is used
|
||||
to copy the memory image to specified area.
|
||||
|
||||
* Handle#sym(symbol_name) returns a PtrData object, and
|
||||
Handle#sym(symbol_name, type_spec) returns a Symbol object.
|
||||
|
||||
* We can use the number following a type specifier to represent the
|
||||
length of an array. For example, if you'd like to represent the
|
||||
following structure, we use 'C1024I' when using PtrData#struct! or
|
||||
PtrData#union!.
|
||||
|
||||
struct {
|
||||
char name[1024];
|
||||
int age;
|
||||
}
|
||||
|
||||
0.6 -> 0.7
|
||||
-----------
|
||||
* type `ANY_FUNC' is removed, it is because the method for
|
||||
calling the function obtained by dlsym() was changed.
|
||||
|
||||
* `char', `short' and `float' types are supported, if you'd
|
||||
like to use those type exactly and run extconf.rb with the
|
||||
option `--with-type-{char,short,float}'.
|
||||
|
||||
* `DL.sizeof(type)' returns the size of the <type> with the
|
||||
alignment. so `DL.sizeof("C") + DL.sizeof("L")' is not equal
|
||||
to `DL.sizeof("CL")'. it is assumed that the latter returns
|
||||
the enough size for the following structure:
|
||||
struct foo { char x; long y; }
|
||||
but it may not equal to `sizeof(struct foo)' of C.
|
||||
|
||||
* new methods:
|
||||
- PtrData#define_data_type
|
||||
- PtrData#struct!
|
||||
- PtrData#union!
|
||||
- PtrData#data_type
|
||||
- PtrData#[]
|
||||
- PtrData#[]=
|
||||
- Symbol.new
|
||||
|
||||
0.5 -> 0.6
|
||||
-----------
|
||||
* DL.set_callback is changed.
|
||||
- set_callback(type,num,proc) [old style]
|
||||
- set_callback(type,num){...} [new style]
|
||||
|
||||
* the handle object don't call dlclose() at the time of GC.
|
||||
if you need to call dlclose(), use Handle#enable_close.
|
||||
|
||||
* new methods:
|
||||
- PtrData#{+,-}
|
||||
- PtrData#{+@,-@} (= PtrData#{ptr,ref})
|
||||
- DL.malloc
|
||||
- DL.strdup
|
||||
- MemorySpace.each
|
||||
|
||||
* some memory leaks are fixed.
|
||||
|
||||
0.4 -> 0.5
|
||||
----------
|
||||
* new methods:
|
||||
- DL.dlopen (= DL::Handle.new)
|
||||
- PtrData#ref
|
||||
- PtrData#==
|
||||
- PtrData#eql?
|
||||
- String#to_ptr
|
||||
- Handle#enable_close
|
||||
- Handle#disable_close
|
||||
|
||||
* PtrData#ptr returns the pointed value (*ptr).
|
||||
|
||||
* PtrData#ref returns the reference (&ptr).
|
||||
`ptr.ref.ptr == ptr' must be true.
|
||||
|
||||
(experiment)
|
||||
* the callback function is supported.
|
||||
|
||||
* new methods:
|
||||
- DL.set_callback
|
||||
- DL.get_callback
|
||||
|
||||
|
||||
0.3 -> 0.4
|
||||
----------
|
||||
* Symbol#call supports the mechanism for converting any object
|
||||
to PtrData object automatically using 'to_ptr' method, if the
|
||||
argument type is 'P' or 'p'.
|
||||
|
||||
* new methods are added.
|
||||
- Array#to_ptr
|
||||
- IO#to_ptr
|
||||
- Symbol#to_ptr
|
||||
- Symbol#[]
|
||||
|
||||
* new constant is added.
|
||||
- DL::FREE is a symbol object for representing the function 'free'.
|
||||
|
||||
* the specification of PtrData#free was changed.
|
||||
|
||||
* new internal functions are added.
|
||||
- rb_dlptr2cptr()
|
||||
- rb_dlsym2csym()
|
||||
- rb_dlsym_new()
|
||||
|
||||
* 'dl.h' is new file.
|
||||
|
||||
* 'extconf.rb' and 'depend' ware modified so that we can build
|
||||
the library in a directory except 'srcdir' (by N. Nakada).
|
||||
|
||||
* (experimental) 'h2rb' is a new script which converts C header
|
||||
files into ruby scripts.
|
||||
|
||||
0.2 -> 0.3
|
||||
----------
|
||||
* many useful functions ware added (by Akinori Musha).
|
||||
|
||||
* the type of 'long' was supported (by Akinori Musha).
|
||||
|
||||
* some methods of the PtrData ware added for handling pointer data.
|
||||
|
||||
* bug fix for mutable int and long.
|
||||
|
||||
* the type of array was supported.
|
24
ext/dl/MANIFEST
Normal file
24
ext/dl/MANIFEST
Normal file
@ -0,0 +1,24 @@
|
||||
.cvsignore
|
||||
Changes
|
||||
MANIFEST
|
||||
README
|
||||
README.html
|
||||
depend
|
||||
dl.c
|
||||
dl.h
|
||||
dl.def
|
||||
extconf.rb
|
||||
h2rb
|
||||
handle.c
|
||||
mkcall.rb
|
||||
mkcallback.rb
|
||||
mkcbtable.rb
|
||||
ptr.c
|
||||
sym.c
|
||||
type.rb
|
||||
test/test.c
|
||||
test/test.rb
|
||||
sample/drives.rb
|
||||
sample/getch.rb
|
||||
sample/libc.rb
|
||||
sample/msgbox.rb
|
186
ext/dl/README
Normal file
186
ext/dl/README
Normal file
@ -0,0 +1,186 @@
|
||||
Ruby/DL
|
||||
|
||||
an interface to dynamic linking loader
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Ruby/DL
|
||||
|
||||
`Ruby/DL' provides an interface to the dynamic linking loader.
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
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
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Functions and Classes
|
||||
|
||||
after loading the `dl' library, we get access to the module called `DL'. the DL
|
||||
module has the following constants, functions and classes.
|
||||
|
||||
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.
|
||||
|
||||
class Handle
|
||||
|
||||
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'.
|
||||
|
||||
class Symbol
|
||||
|
||||
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.
|
||||
|
||||
class PtrData
|
||||
|
||||
ptr = PtrData.new(addr, [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 : a character (char)
|
||||
c : a pointer to a character (char *)
|
||||
H : a short integer (short)
|
||||
h : a pointer to a short integer (short *)
|
||||
I : an integer (char, short, int)
|
||||
i : a pointer to an integer (char *, short *, int *)
|
||||
L : a long integer (long)
|
||||
l : a pointer to a long integer (long *)
|
||||
F : a real (float)
|
||||
f : a pointer to a real (float *)
|
||||
D : a real (double)
|
||||
d : a pointer to a real (double *)
|
||||
S : an immutable string (const char *)
|
||||
s : a mutable string (char *)
|
||||
A : an array (const type[])
|
||||
a : a mutable array (type[])
|
||||
P : a pointer (void *)
|
||||
p : a mutable object (void *)
|
||||
0 : void function (this must be a first character of the prototype)
|
||||
|
||||
the cbtype consists of type specifiers 0, I, L, D and P.
|
||||
for example:
|
||||
|
||||
DL.set_callback('IPP',0){|ptr1,ptr2|
|
||||
str1 = ptr1.ptr.to_s
|
||||
str2 = ptr2.ptr.to_s
|
||||
return str1 <=> str2
|
||||
}
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
ttate@kt.jaist.ac.jp
|
247
ext/dl/README.html
Normal file
247
ext/dl/README.html
Normal file
@ -0,0 +1,247 @@
|
||||
<html>
|
||||
<head><title>Ruby/DL</title></head>
|
||||
<body>
|
||||
<center>
|
||||
<h2>Ruby/DL</h2>
|
||||
an interface to dynamic linking loader
|
||||
</center>
|
||||
|
||||
<hr>
|
||||
<h2>Ruby/DL</h2>
|
||||
|
||||
`Ruby/DL' provides an interface to the dynamic linking loader.
|
||||
|
||||
<hr>
|
||||
<h2>Installing</h2>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
$ 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
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<hr>
|
||||
<h2>Functions and Classes</h2>
|
||||
|
||||
after loading the `dl' library, we get access to the module called `DL'.
|
||||
the DL module has the following constants, functions and classes.
|
||||
|
||||
<h2>Constants</h2>
|
||||
|
||||
VERSION<br>
|
||||
MAJOR_VERSION<br>
|
||||
MINOR_VERSION<br>
|
||||
PATCH_VERSION<br>
|
||||
RTLD_GLOBAL<br>
|
||||
RTLD_LAZY<br>
|
||||
RTLD_NOW<br>
|
||||
MAX_ARG<br>
|
||||
MAX_CBARG<br>
|
||||
MAX_CBENT<br>
|
||||
|
||||
<h2>Functions</h2>
|
||||
|
||||
<dl>
|
||||
<dt>handle = dlopen(lib){|handle| ... }</dt>
|
||||
<dd>is quite equal to `Handle.new(lib)'
|
||||
|
||||
<dt>sym = set_callback(cbtype, entry){|args| ... }
|
||||
<dt>sym = set_callback(cbtype, entry, proc)
|
||||
<dd>makes <u>entry</u>-th pre-defined function to call the <u>proc</u>
|
||||
or given block.
|
||||
the <u>entry</u>-th pre-defined function is specified by
|
||||
<u>cbtype</u> and <u>entry</u>.
|
||||
<u>cbtype</u> is a prototype of the callback.
|
||||
see also the section `Type specifiers' about <u>cbtype</u>.
|
||||
|
||||
<dt>sym = get_callback(cbtype, entry)
|
||||
<dd>returns the Proc object which is given by the above function `set_callback'.
|
||||
|
||||
<dt>ptr = malloc(size, [free = nil])
|
||||
<dd>allocates the <u>size</u> bytes, and returns the pointer as a
|
||||
PtrData object <u>ptr</u>.
|
||||
|
||||
<dt>ptr = strdup(str)
|
||||
<dd>returns a PtrData object <u>ptr</u> which represents the pointer to
|
||||
a new string which is a duplicate of the string <u>str</u>.
|
||||
|
||||
<dt>size = sizeof(type)
|
||||
<dd>returns the size of <u>type</u>. `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.
|
||||
</dl>
|
||||
|
||||
<h2>class Handle</h2>
|
||||
|
||||
<dl>
|
||||
<dt>handle = Handle.new(lib){|handle| ... }</dt>
|
||||
<dd>opens a library <u>lib</u> and returns a Handle object
|
||||
<u>handle</u>. if a block is given, the handle is
|
||||
automatically closed as the block ends.
|
||||
|
||||
<dt>Handle#close
|
||||
<dd>closes the handle opened by the above Handle.new(lib).
|
||||
|
||||
<dt>sym = Handle#sym(func, prototype = "0")
|
||||
<dt>sym = Handle#[func, prototype = nil]
|
||||
<dd>obtains the pointer to a function called <u>func</u> and returns
|
||||
a Symbol object or a DataPtr object.
|
||||
<u>prototype</u> is a string which consists of type specifiers,
|
||||
it indicates the function's prototype.
|
||||
see also the section `Type specifiers'.
|
||||
</dl>
|
||||
|
||||
<h2>class Symbol</h2>
|
||||
|
||||
<dl>
|
||||
<dt>sym = Symbol.new(addr, type = nil, name = nil)
|
||||
<dd>creates the Symbol object <u>sym</u> with the type <u>type</u>
|
||||
if <u>type</u> is not nil. <u>addr</u> is the address where the
|
||||
function is allocated. If <u>type</u> is nil, it returns a DataPtr
|
||||
object.
|
||||
|
||||
<dt>Symbol::char2type(char)
|
||||
<dd>takes a character <u>char</u> that represents a type and returns
|
||||
the type specifier of the C language.
|
||||
|
||||
<dt>str = Symbol#proto()
|
||||
<dd>returns the function prototype.
|
||||
|
||||
<dt>str = Symbol#name()
|
||||
<dd>Returns the function name.
|
||||
|
||||
<dt>str = Symbol#cproto()
|
||||
<dt>str = Symbol#to_s()
|
||||
<dd>returns the prototype of the C language.
|
||||
|
||||
<dt>str = Symbol#inspect()
|
||||
<dd>returns the inspectable string.
|
||||
|
||||
<dt>r,rs = Symbol#call(arg1,arg2,...,argN)
|
||||
<dt>r,rs = Symbol#[](arg1,arg2,...,argN)
|
||||
<dd>calls the function with parameters arg1, arg2, ..., argN.
|
||||
and the result consists of the return value <u>r</u> and
|
||||
parameters <u>rs</u>. <u>rs</u> is an array.
|
||||
|
||||
<dt>ptr = Symbol#to_ptr
|
||||
<dd>returns the corresponding PtrData object <u>ptr</u>.
|
||||
</dl>
|
||||
|
||||
<h2>class PtrData</h2>
|
||||
|
||||
<dl>
|
||||
<dt>ptr = PtrData.new(addr, [free = nil])
|
||||
<dd>returns the PtrData object representing the pointer which
|
||||
indicates the address <u>addr</u>.
|
||||
GC frees the memory using the <u>free</u> function.
|
||||
|
||||
<dt>PtrData#free=(sym)
|
||||
<dd>if you specify a symbol object <u>sym</u>, GC frees the memory
|
||||
using the function represented by <u>sym</u>.
|
||||
|
||||
<dt>sym = PtrData#free
|
||||
<dd>returns a symbol object <u>sym</u> which is used when GC frees
|
||||
the memory. it usually configured by `PtrData#free=' or `PtrData.new'.
|
||||
|
||||
<dt>size = PtrData#size, PtrData#size=(size)
|
||||
<dd>gets and sets allocated size of the memory.
|
||||
|
||||
<dt>ary = PtrData#to_a(type, [size])
|
||||
<dd>returns an array of the type which specified with <u>type</u>.
|
||||
<u>type</u> must be one of 'S','P','I','L','D' and 'F'.
|
||||
|
||||
<dt>str = PtrData#to_s([len])
|
||||
<dd>returns a string which length is <u>len</u>. if <u>len</u>
|
||||
is omitted, the end of the string is '\0'.
|
||||
|
||||
<dt>ptr = PtrData#ptr,+@
|
||||
<dd>returns the pointed value as a PtrData object <u>ptr</u>.
|
||||
|
||||
<dt>ptr = PtrData#ref,-@
|
||||
<dd>returns the reference as a PtrData object <u>ptr</u>.
|
||||
|
||||
<dt>ptr = PtrData#+
|
||||
<dd>returns the PtrData object
|
||||
|
||||
<dt>ptr = PtrData#-
|
||||
<dd>returns the PtrData object
|
||||
|
||||
<dt>PtrData#struct!(type, *members)
|
||||
<dd>defines the data type to get access to a structure member with a symbol.
|
||||
(see also PtrData#[])
|
||||
|
||||
<dt>PtrData#union!(type, *members)
|
||||
<dd>defines the data type to get access to a union member with a symbol.
|
||||
(see also PtrData#[])
|
||||
|
||||
<dt>val = PtrData#[key], PtrData#[key, num = 0]
|
||||
<dd>if the <u>key</u> 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 <u>key</u> is a integer value and this object represents
|
||||
the pointer <u>ptr</u>, it returns the value of
|
||||
`(<u>ptr</u> + <u>key</u>).to_s(num)'
|
||||
|
||||
<dt>PtrData#[key,num]=val, PtrData#[key]=val
|
||||
<dd>if the <u>key</u> is a string or symbol, this method substitute
|
||||
the value of the structure/union member with <u>val</u>.
|
||||
if the <u>key</u> is a integer value and <u>val</u> is a string,
|
||||
this method copies <u>num</u> bytes of <u>val</u> to the memory
|
||||
area <u>ptr</u> using memcpy(3).
|
||||
</dl>
|
||||
|
||||
<hr>
|
||||
<h2>Type specifiers</h2>
|
||||
|
||||
the <u>prototype</u> consists of the following type specifiers,
|
||||
first element of <u>prototype</u> represents the type of return value,
|
||||
and remaining elements represent the type of each argument.
|
||||
|
||||
<blockquote>
|
||||
C : a character (char)<br>
|
||||
c : a pointer to a character (char *)<br>
|
||||
H : a short integer (short)<br>
|
||||
h : a pointer to a short integer (short *)<br>
|
||||
I : an integer (char, short, int)<br>
|
||||
i : a pointer to an integer (char *, short *, int *)<br>
|
||||
L : a long integer (long)<br>
|
||||
l : a pointer to a long integer (long *)<br>
|
||||
F : a real (float)<br>
|
||||
f : a pointer to a real (float *)<br>
|
||||
D : a real (double)<br>
|
||||
d : a pointer to a real (double *)<br>
|
||||
S : an immutable string (const char *)<br>
|
||||
s : a mutable string (char *)<br>
|
||||
A : an array (const type[])<br>
|
||||
a : a mutable array (type[])<br>
|
||||
P : a pointer (void *)<br>
|
||||
p : a mutable object (void *)<br>
|
||||
0 : void function
|
||||
(this must be a first character of the <u>prototype</u>)<br>
|
||||
</blockquote>
|
||||
|
||||
the <u>cbtype</u> consists of type specifiers 0, I, L, D and P.
|
||||
<br>
|
||||
for example:
|
||||
<blockquote>
|
||||
<pre>
|
||||
DL.set_callback('IPP',0){|ptr1,ptr2|
|
||||
str1 = ptr1.ptr.to_s
|
||||
str2 = ptr2.ptr.to_s
|
||||
return str1 <=> str2
|
||||
}
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<hr>
|
||||
<i>ttate@kt.jaist.ac.jp</i>
|
||||
|
||||
</body>
|
||||
</html>
|
45
ext/dl/depend
Normal file
45
ext/dl/depend
Normal file
@ -0,0 +1,45 @@
|
||||
RUBY = $(RUBY_INSTALL_NAME)$(EXEEXT)
|
||||
CLEANFILES = test/test.o
|
||||
DISTCLEANFILES = call.func callback.func cbtable.func dlconfig.rb dlconfig.h \
|
||||
test/libtest.so test/*~ *~ mkmf.log
|
||||
|
||||
libtest.so: test/libtest.so
|
||||
|
||||
test/libtest.so: test/test.o test/libtest.def
|
||||
$(RUBY) -rftools -e 'ARGV.each{|d|File.mkpath(File.dirname(d))}' $@
|
||||
`$(RUBY) -e 'print ARGV.join(" ").gsub(/dl\\.def/,"test/libtest.def")' $(LDSHARED)` $(LDFLAGS) test/test.o -o test/libtest.so
|
||||
|
||||
test/test.o: test/test.c
|
||||
@$(RUBY) -rftools -e 'File.mkpath(*ARGV)' test
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -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: call.func
|
||||
|
||||
dl.o: callback.func cbtable.func
|
||||
|
||||
call.func: mkcall.rb dlconfig.rb
|
||||
@echo "Generating call.func"
|
||||
@$(RUBY) $< > $@
|
||||
|
||||
callback.func: mkcallback.rb dlconfig.rb
|
||||
@echo "Generating callback.func"
|
||||
@$(RUBY) $< > $@
|
||||
|
||||
cbtable.func: mkcbtable.rb dlconfig.rb
|
||||
@echo "Generating cbtable.func"
|
||||
@$(RUBY) $< > $@
|
||||
|
||||
debug:
|
||||
$(MAKE) CFLAGS+=-DDEBUG
|
655
ext/dl/dl.c
Normal file
655
ext/dl/dl.c
Normal file
@ -0,0 +1,655 @@
|
||||
/*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include <ruby.h>
|
||||
#include <rubyio.h>
|
||||
#include "dl.h"
|
||||
|
||||
VALUE rb_mDL;
|
||||
VALUE rb_eDLError;
|
||||
VALUE rb_eDLTypeError;
|
||||
|
||||
static VALUE DLFuncTable;
|
||||
static void *rb_dl_func_table[MAX_CALLBACK_TYPE][MAX_CALLBACK];
|
||||
static ID id_call;
|
||||
|
||||
#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':
|
||||
DLALIGN(0,size,VOIDP_ALIGN);
|
||||
case 'p':
|
||||
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;
|
||||
|
||||
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) ){
|
||||
case T_STRING:
|
||||
{
|
||||
char *str, *src;
|
||||
src = STR2CSTR(e);
|
||||
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;
|
||||
default:
|
||||
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;
|
||||
|
||||
if( TYPE(v) != T_ARRAY ){
|
||||
rb_raise(rb_eDLTypeError, "an array is expected.");
|
||||
};
|
||||
|
||||
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");
|
||||
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, STR2CSTR(self), 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(STR2CSTR(t)[0], self, &size);
|
||||
break;
|
||||
case 0:
|
||||
ptr = rb_ary2cary(0, self, &size);
|
||||
break;
|
||||
};
|
||||
return ptr ? rb_dlptr_new(ptr, size, dlfree) : Qnil;
|
||||
};
|
||||
|
||||
VALUE
|
||||
rb_io_to_ptr(VALUE self)
|
||||
{
|
||||
OpenFile *fptr;
|
||||
FILE *fp;
|
||||
|
||||
GetOpenFile(self, fptr);
|
||||
fp = fptr->f;
|
||||
|
||||
return fp ? rb_dlptr_new(fp, sizeof(FILE), 0) : Qnil;
|
||||
};
|
||||
|
||||
VALUE
|
||||
rb_dl_dlopen(int argc, VALUE argv[], VALUE self)
|
||||
{
|
||||
return rb_dlhandle_s_new(argc, argv, rb_cDLHandle);
|
||||
};
|
||||
|
||||
VALUE
|
||||
rb_dl_malloc(VALUE self, VALUE size)
|
||||
{
|
||||
void *ptr;
|
||||
long s;
|
||||
|
||||
s = DLNUM2LONG(size);
|
||||
ptr = dlmalloc((size_t)s);
|
||||
memset(ptr,0,(size_t)s);
|
||||
return rb_dlptr_new(ptr, s, dlfree);
|
||||
};
|
||||
|
||||
VALUE
|
||||
rb_dl_strdup(VALUE self, VALUE str)
|
||||
{
|
||||
void *p;
|
||||
|
||||
str = rb_String(str);
|
||||
return rb_dlptr_new(strdup(STR2CSTR(str)), RSTRING(str)->len, dlfree);
|
||||
};
|
||||
|
||||
static VALUE
|
||||
rb_dl_sizeof(VALUE self, VALUE str)
|
||||
{
|
||||
return INT2NUM(dlsizeof(STR2CSTR(str)));
|
||||
};
|
||||
|
||||
static VALUE
|
||||
rb_dl_callback_type(VALUE str)
|
||||
{
|
||||
char *type;
|
||||
int len;
|
||||
int i;
|
||||
long ftype;
|
||||
|
||||
ftype = 0;
|
||||
type = STR2CSTR(str);
|
||||
len = RSTRING(str)->len;
|
||||
|
||||
if( len - 1 > MAX_CBARG ){
|
||||
rb_raise(rb_eDLError, "maximum number of the argument is %d.", MAX_CBARG);
|
||||
};
|
||||
|
||||
for( i = len - 1; i > 0; i-- ){
|
||||
switch( type[i] ){
|
||||
case 'P':
|
||||
CBPUSH_P(ftype);
|
||||
break;
|
||||
case 'I':
|
||||
CBPUSH_I(ftype);
|
||||
break;
|
||||
case 'L':
|
||||
CBPUSH_L(ftype);
|
||||
break;
|
||||
case 'F':
|
||||
CBPUSH_F(ftype);
|
||||
break;
|
||||
case 'D':
|
||||
CBPUSH_D(ftype);
|
||||
default:
|
||||
rb_raise(rb_eDLError, "unsupported type `%c'", type[i]);
|
||||
break;
|
||||
};
|
||||
};
|
||||
|
||||
switch( type[0] ){
|
||||
case '0':
|
||||
CBPUSH_0(ftype);
|
||||
break;
|
||||
case 'P':
|
||||
CBPUSH_P(ftype);
|
||||
break;
|
||||
case 'I':
|
||||
CBPUSH_I(ftype);
|
||||
break;
|
||||
case 'L':
|
||||
CBPUSH_L(ftype);
|
||||
break;
|
||||
case 'F':
|
||||
CBPUSH_F(ftype);
|
||||
break;
|
||||
case 'D':
|
||||
CBPUSH_D(ftype);
|
||||
break;
|
||||
default:
|
||||
rb_raise(rb_eDLError, "unsupported type `%c'", type[i]);
|
||||
break;
|
||||
};
|
||||
|
||||
return INT2NUM(ftype);
|
||||
};
|
||||
|
||||
VALUE
|
||||
rb_dl_set_callback(int argc, VALUE argv[], VALUE self)
|
||||
{
|
||||
VALUE types, num, proc;
|
||||
VALUE key;
|
||||
VALUE entry;
|
||||
void *func;
|
||||
|
||||
char func_name[1024];
|
||||
extern dln_sym();
|
||||
|
||||
switch( rb_scan_args(argc, argv, "21", &types, &num, &proc) ){
|
||||
case 2:
|
||||
proc = rb_f_lambda();
|
||||
break;
|
||||
case 3:
|
||||
break;
|
||||
default:
|
||||
rb_bug("rb_dl_set_callback");
|
||||
};
|
||||
|
||||
key = rb_dl_callback_type(types);
|
||||
entry = rb_hash_aref(DLFuncTable, key);
|
||||
if( entry == Qnil ){
|
||||
entry = rb_hash_new();
|
||||
rb_hash_aset(DLFuncTable, key, entry);
|
||||
};
|
||||
|
||||
func = rb_dl_func_table[NUM2INT(key)][NUM2INT(num)];
|
||||
if( func ){
|
||||
rb_hash_aset(entry, num, proc);
|
||||
snprintf(func_name, 1023, "rb_dl_func%d_%d", NUM2INT(key), NUM2INT(num));
|
||||
return rb_dlsym_new(func, func_name, STR2CSTR(types));
|
||||
}
|
||||
else{
|
||||
return Qnil;
|
||||
};
|
||||
};
|
||||
|
||||
VALUE
|
||||
rb_dl_get_callback(VALUE self, VALUE types, VALUE num)
|
||||
{
|
||||
VALUE key;
|
||||
VALUE entry;
|
||||
|
||||
key = rb_dl_callback_type(types);
|
||||
entry = rb_hash_aref(DLFuncTable, key);
|
||||
if( entry == Qnil ){
|
||||
return Qnil;
|
||||
};
|
||||
return rb_hash_aref(entry, num);
|
||||
};
|
||||
|
||||
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, "VERSION", rb_tainted_str_new2(DL_VERSION));
|
||||
rb_define_const(rb_mDL, "MAJOR_VERSION", INT2NUM(DL_MAJOR_VERSION));
|
||||
rb_define_const(rb_mDL, "MINOR_VERSION", INT2NUM(DL_MINOR_VERSION));
|
||||
rb_define_const(rb_mDL, "PATCH_VERSION", INT2NUM(DL_PATCH_VERSION));
|
||||
rb_define_const(rb_mDL, "MAX_ARG", INT2NUM(MAX_ARG));
|
||||
rb_define_const(rb_mDL, "MAX_CBARG", INT2NUM(MAX_CBARG));
|
||||
rb_define_const(rb_mDL, "MAX_CBENT", INT2NUM(MAX_CBENT));
|
||||
|
||||
rb_define_module_function(rb_mDL, "dlopen", rb_dl_dlopen, -1);
|
||||
rb_define_module_function(rb_mDL, "set_callback", rb_dl_set_callback, -1);
|
||||
rb_define_module_function(rb_mDL, "get_callback", rb_dl_get_callback, 2);
|
||||
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);
|
||||
};
|
70
ext/dl/dl.def
Normal file
70
ext/dl/dl.def
Normal file
@ -0,0 +1,70 @@
|
||||
EXPORTS
|
||||
Init_dl
|
||||
dlfree
|
||||
dlmalloc
|
||||
dlrealloc
|
||||
dlstrdup
|
||||
rb_ary2cary
|
||||
rb_ary_to_ptr
|
||||
rb_dl_dlopen
|
||||
rb_dl_get_callback
|
||||
rb_dl_malloc
|
||||
rb_dl_set_callback
|
||||
rb_dl_strdup
|
||||
rb_eDLError
|
||||
rb_eDLTypeError
|
||||
rb_io_to_ptr
|
||||
rb_mDL
|
||||
rb_str_to_ptr
|
||||
Init_dlhandle
|
||||
dlhandle_free
|
||||
rb_cDLHandle
|
||||
rb_dlhandle_close
|
||||
rb_dlhandle_disable_close
|
||||
rb_dlhandle_enable_close
|
||||
rb_dlhandle_init
|
||||
rb_dlhandle_s_new
|
||||
rb_dlhandle_sym
|
||||
Init_dlptr
|
||||
dlptr_free
|
||||
dlptr_init
|
||||
rb_cDLPtrData
|
||||
rb_dlmem_each
|
||||
rb_dlptr2cptr
|
||||
rb_dlptr_alloc
|
||||
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_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
|
||||
dlsym_free
|
||||
rb_cDLSymbol
|
||||
rb_dlsym2csym
|
||||
rb_dlsym_call
|
||||
rb_dlsym_cproto
|
||||
rb_dlsym_initialize
|
||||
rb_dlsym_inspect
|
||||
rb_dlsym_name
|
||||
rb_dlsym_new
|
||||
rb_dlsym_proto
|
||||
rb_dlsym_s_new
|
||||
rb_dlsym_to_ptr
|
||||
rb_s_dlsym_char2type
|
282
ext/dl/dl.h
Normal file
282
ext/dl/dl.h
Normal file
@ -0,0 +1,282 @@
|
||||
/* -*- C -*-
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef RUBY_DL_H
|
||||
#define RUBY_DL_H
|
||||
|
||||
#include <ruby.h>
|
||||
#include <dlconfig.h>
|
||||
|
||||
#if defined(HAVE_DLFCN_H)
|
||||
# include <dlfcn.h>
|
||||
#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
|
||||
|
||||
#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 DL_VERSION "1.1.0"
|
||||
#define DL_MAJOR_VERSION 1
|
||||
#define DL_MINOR_VERSION 1
|
||||
#define DL_PATCH_VERSION 0
|
||||
|
||||
#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 ASM_START(type)
|
||||
# define ASM_END(type)
|
||||
# define ASM_PUSH_C(x) asm volatile ("pushl %0" :: "g" (x));
|
||||
# define ASM_PUSH_H(x) asm volatile ("pushl %0" :: "g" (x));
|
||||
# define ASM_PUSH_I(x) asm volatile ("pushl %0" :: "g" (x));
|
||||
# define ASM_PUSH_L(x) asm volatile ("pushl %0" :: "g" (x));
|
||||
# define ASM_PUSH_P(x) asm volatile ("pushl %0" :: "g" (x));
|
||||
# define ASM_PUSH_F(x) asm volatile ("flds %0"::"g"(x));\
|
||||
asm volatile ("subl $4,%esp");\
|
||||
asm volatile ("fstps (%esp)");
|
||||
# define ASM_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
|
||||
#else
|
||||
# define ASM_START(type)
|
||||
# define ASM_END(type)
|
||||
# define ASM_PUSH_C(x)
|
||||
# define ASM_PUSH_I(x)
|
||||
# define ASM_PUSH_L(x)
|
||||
# define ASM_PUSH_P(x)
|
||||
# define ASM_PUSH_F(x)
|
||||
# define ASM_PUSH_D(x)
|
||||
#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)(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_alloc(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 */
|
197
ext/dl/extconf.rb
Normal file
197
ext/dl/extconf.rb
Normal file
@ -0,0 +1,197 @@
|
||||
require 'mkmf'
|
||||
$:.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-asm use the embedded assembler for passing arguments.
|
||||
(this option is available for i386 machine now.)
|
||||
--with-args=<max_arg>,<max_cbarg>,<max_cbent>
|
||||
<max_arg>: maximum number of arguments of the function
|
||||
<max_cbarg>: maximum number of arguments of the callback
|
||||
<max_cbent>: maximum number of callback entries
|
||||
EOF
|
||||
exit(0)
|
||||
end
|
||||
|
||||
($CPPFLAGS || $CFLAGS) << " -I."
|
||||
|
||||
case RUBY_PLATFORM # from Win32API
|
||||
when /cygwin/,/mingw/
|
||||
$CFLAGS << " -fno-defer-pop -fno-omit-frame-pointer"
|
||||
end
|
||||
|
||||
if (Config::CONFIG['CC'] =~ /gcc/) && (Config::CONFIG['arch'] =~ /i.86/)
|
||||
$with_asm = true
|
||||
else
|
||||
$with_asm = false
|
||||
end
|
||||
|
||||
$with_type_int = try_run(<<EOF)
|
||||
int main(){ return sizeof(int) == sizeof(long); }
|
||||
EOF
|
||||
|
||||
$with_type_float = try_run(<<EOF)
|
||||
int main(){ return sizeof(float) == sizeof(double); }
|
||||
EOF
|
||||
|
||||
$with_type_voidp = try_run(<<EOF)
|
||||
int main(){
|
||||
return (sizeof(void *) == sizeof(long))
|
||||
|| (sizeof(void *) == sizeof(int));
|
||||
}
|
||||
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_cbtype_voidp = DLTYPE[VOIDP][:cb]
|
||||
|
||||
$with_type_char = with_config("type-char") ? true : false
|
||||
$with_type_short = with_config("type-short") ? true : false
|
||||
$with_type_float = with_config("type-float") ? true : false
|
||||
|
||||
$with_asm = with_config("asm") ? true : $with_asm
|
||||
|
||||
args = with_config("args")
|
||||
max_arg = max_cbarg = max_cbent = nil
|
||||
if( $with_asm )
|
||||
$with_type_char = true
|
||||
$with_type_short = true
|
||||
$with_type_float = true
|
||||
max_arg = 0
|
||||
end
|
||||
if( args )
|
||||
max_arg,max_cbarg,max_cbent = args.split(",").collect{|c| c.to_i}
|
||||
if( !(max_arg && max_cbarg && max_cbent) )
|
||||
print("--with-args=<max_arg>,<max_cbarg>,<max_cbent>\n")
|
||||
exit(1)
|
||||
end
|
||||
end
|
||||
max_arg ||= 6
|
||||
max_cbarg ||= 3
|
||||
max_cbent ||= 3
|
||||
|
||||
max_callback_type = types2num(DLTYPE.keys.sort[-1,1] * (max_cbarg + 1)) + 1
|
||||
max_callback = max_cbent
|
||||
|
||||
#m = [1].pack("i")
|
||||
#c,cs = m.unpack("c")
|
||||
#bigendian = (c == 0)
|
||||
#print("bigendian ... #{bigendian ? 'true' : 'false'}\n")
|
||||
|
||||
|
||||
$dlconfig_h = <<EOF
|
||||
#define MAX_ARG #{max_arg}
|
||||
#define MAX_CBARG #{max_cbarg}
|
||||
#define MAX_CBENT #{max_cbent}
|
||||
#define MAX_CALLBACK_TYPE #{max_callback_type}
|
||||
#define MAX_CALLBACK #{max_callback}
|
||||
EOF
|
||||
|
||||
def dlc_define(const)
|
||||
$dlconfig_h << "#if !defined(#{const})\n" +
|
||||
"# define #{const}\n" +
|
||||
"#endif\n"
|
||||
end
|
||||
|
||||
if( $with_asm )
|
||||
$dlconfig_h << "#define USE_INLINE_ASM\n"
|
||||
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( $with_cbtype_voidp )
|
||||
$dlconfig_h << "#define WITH_CBTYPE_VOIDP\n"
|
||||
end
|
||||
#if( bigendian )
|
||||
# $dlconfig_h << "#define BIGENDIAN"
|
||||
#else
|
||||
# $dlconfig_h << "#define LITTLEENDIAN"
|
||||
#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_header("windows.h") )
|
||||
dlc_define("HAVE_WINDOWS_H")
|
||||
have_func("LoadLibrary")
|
||||
have_func("FreeLibrary")
|
||||
have_func("GetProcAddress")
|
||||
else
|
||||
exit(0)
|
||||
end
|
||||
|
||||
method(:have_func).arity == 1 or have_func("rb_str_cat2", "ruby.h")
|
||||
if method(:have_func).arity == 1 or !have_func("rb_block_given_p", "ruby.h")
|
||||
$dlconfig_h << "#define rb_block_given_p rb_iterator_p\n"
|
||||
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_CBARG = #{max_cbarg}
|
||||
MAX_CBENT = #{max_cbent}
|
||||
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)", ""],
|
||||
]
|
||||
|
||||
create_makefile('dl')
|
500
ext/dl/h2rb
Normal file
500
ext/dl/h2rb
Normal file
@ -0,0 +1,500 @@
|
||||
#!/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)
|
207
ext/dl/handle.c
Normal file
207
ext/dl/handle.c
Normal file
@ -0,0 +1,207 @@
|
||||
/* -*- C -*-
|
||||
* $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_new(int argc, VALUE argv[], VALUE self)
|
||||
{
|
||||
void *ptr;
|
||||
VALUE val;
|
||||
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 = STR2CSTR(lib);
|
||||
cflag = RTLD_LAZY | RTLD_GLOBAL;
|
||||
break;
|
||||
case 2:
|
||||
clib = STR2CSTR(lib);
|
||||
cflag = NUM2INT(flag);
|
||||
break;
|
||||
default:
|
||||
rb_bug("rb_dlhandle_new");
|
||||
};
|
||||
|
||||
ptr = dlopen(clib, cflag);
|
||||
#if defined(HAVE_DLERROR)
|
||||
if( (err = dlerror()) ){
|
||||
rb_raise(rb_eRuntimeError, err);
|
||||
};
|
||||
#else
|
||||
if( !ptr ){
|
||||
err = dlerror();
|
||||
rb_raise(rb_eRuntimeError, err);
|
||||
};
|
||||
#endif
|
||||
val = Data_Make_Struct(rb_cDLHandle, struct dl_handle, 0,
|
||||
dlhandle_free, dlhandle);
|
||||
dlhandle->ptr = ptr;
|
||||
dlhandle->open = 1;
|
||||
dlhandle->enable_close = 0;
|
||||
|
||||
rb_obj_call_init(val, argc, argv);
|
||||
|
||||
if( rb_block_given_p() ){
|
||||
rb_ensure(rb_yield, val, rb_dlhandle_close, val);
|
||||
};
|
||||
|
||||
return val;
|
||||
};
|
||||
|
||||
VALUE
|
||||
rb_dlhandle_init(int argc, VALUE argv[], VALUE 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 sym_data *data;
|
||||
int *ctypes;
|
||||
int i, ctypes_len;
|
||||
struct dl_handle *dlhandle;
|
||||
void *handle;
|
||||
const char *name, *stype;
|
||||
const char *err;
|
||||
|
||||
if( rb_scan_args(argc, argv, "11", &sym, &type) == 2 ){
|
||||
Check_Type(type, T_STRING);
|
||||
stype = STR2CSTR(type);
|
||||
}
|
||||
else{
|
||||
stype = NULL;
|
||||
};
|
||||
|
||||
if( sym == Qnil ){
|
||||
#if defined(RTLD_NEXT)
|
||||
name = RTLD_NEXT;
|
||||
#else
|
||||
name = NULL;
|
||||
#endif
|
||||
}
|
||||
else{
|
||||
Check_Type(sym, T_STRING);
|
||||
name = STR2CSTR(sym);
|
||||
};
|
||||
|
||||
|
||||
Data_Get_Struct(self, struct dl_handle, dlhandle);
|
||||
handle = dlhandle->ptr;
|
||||
|
||||
func = dlsym(handle, name);
|
||||
#if defined(HAVE_DLERROR)
|
||||
if( (err = dlerror()) && (!func) )
|
||||
#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( (err = dlerror()) && (!func) )
|
||||
#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_cData);
|
||||
rb_define_singleton_method(rb_cDLHandle, "new", rb_dlhandle_s_new, -1);
|
||||
rb_define_method(rb_cDLHandle, "initialize", rb_dlhandle_init, -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);
|
||||
};
|
49
ext/dl/install.rb
Normal file
49
ext/dl/install.rb
Normal file
@ -0,0 +1,49 @@
|
||||
require 'mkmf'
|
||||
require 'ftools'
|
||||
|
||||
SO_LIBS = ["dl.so"]
|
||||
|
||||
$ruby_version = CONFIG['MAJOR'] + "." + CONFIG['MINOR']
|
||||
$prefix = CONFIG['prefix']
|
||||
$libdir = File.join($prefix,'lib')
|
||||
$rubylibdir = File.join($libdir, 'ruby', $ruby_version)
|
||||
$arch = CONFIG['arch']
|
||||
$archdir = File.join($rubylibdir, $arch)
|
||||
|
||||
def find(dir, match = /./)
|
||||
Dir.chdir(dir)
|
||||
files = []
|
||||
Dir.new(".").each{|file|
|
||||
if( file != "." && file != ".." )
|
||||
case File.ftype(file)
|
||||
when "file"
|
||||
if( file =~ match )
|
||||
files.push(File.join(dir,file))
|
||||
end
|
||||
when "directory"
|
||||
files += find(file, match).collect{|f| File.join(dir,f)}
|
||||
end
|
||||
end
|
||||
}
|
||||
Dir.chdir("..")
|
||||
return files
|
||||
end
|
||||
|
||||
def install()
|
||||
rb_files = find(File.join(".","lib"), /.rb$/)
|
||||
|
||||
SO_LIBS.each{|f|
|
||||
File.makedirs($rubylibdir, "#{$archdir}")
|
||||
File.install(f, File.join($archdir,f), 0555, true)
|
||||
}
|
||||
|
||||
rb_files.each{|f|
|
||||
origfile = f
|
||||
instfile = File.join($rubylibdir, origfile.sub("./lib/",""))
|
||||
instdir = File.dirname(instfile)
|
||||
File.makedirs(instdir)
|
||||
File.install(origfile, instfile, 0644, true)
|
||||
}
|
||||
end
|
||||
|
||||
install()
|
228
ext/dl/lib/dl/import.rb
Normal file
228
ext/dl/lib/dl/import.rb
Normal file
@ -0,0 +1,228 @@
|
||||
# -*- ruby -*-
|
||||
|
||||
require 'dl'
|
||||
|
||||
module DL
|
||||
module Importable
|
||||
LIB_MAP = {}
|
||||
|
||||
module Internal
|
||||
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
|
||||
|
||||
# example:
|
||||
# extern "int strlen(char*)"
|
||||
#
|
||||
def extern(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
|
||||
ret = ret.join(" ")
|
||||
return import(func, ret, args)
|
||||
else
|
||||
raise(RuntimeError,"can't parse the function prototype: #{proto}")
|
||||
end
|
||||
end
|
||||
|
||||
# example:
|
||||
# import("get_length", "int", ["void*", "int"])
|
||||
#
|
||||
def import(name, rettype, argtypes = nil)
|
||||
if( !defined?(@SYM) )
|
||||
@SYM = {}
|
||||
end
|
||||
@LIBS.each{|lib|
|
||||
rty,_,rdec = encode_type(rettype)
|
||||
ty,enc,dec = encode_types(argtypes)
|
||||
symty = rty + ty
|
||||
|
||||
begin
|
||||
sym = lib[name, symty]
|
||||
rescue
|
||||
next
|
||||
end
|
||||
|
||||
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( $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,
|
||||
" @retval = rdec.call(r)",
|
||||
" @args = dec.call(rs)",
|
||||
" return @retval",
|
||||
"end",
|
||||
"module_function :#{mname}",
|
||||
].join("\n")
|
||||
|
||||
return @SYM[mname]
|
||||
}
|
||||
raise(RuntimeError, "can't find #{name}.")
|
||||
end
|
||||
|
||||
def _args_
|
||||
return @args
|
||||
end
|
||||
|
||||
def _retval_
|
||||
return @retval
|
||||
end
|
||||
|
||||
def typealias(ty1, ty2, enc=nil, dec=nil)
|
||||
check_type
|
||||
@TYDEFS.unshift([ty1,ty2, enc,dec])
|
||||
end
|
||||
|
||||
def encode_type(ty)
|
||||
check_type
|
||||
orig_ty = ty
|
||||
enc = proc{|v| v}
|
||||
dec = proc{|v| v}
|
||||
@TYDEFS.each{|t1,t2,c1,c2|
|
||||
if( t1.is_a?(String) )
|
||||
t1 = Regexp.new("^" + t1 + "$")
|
||||
end
|
||||
if( ty =~ t1 )
|
||||
ty = ty.gsub(t1,t2)
|
||||
if( c1 )
|
||||
conv1 = enc
|
||||
enc = proc{|v| c1.call(conv1.call(v))}
|
||||
end
|
||||
if( c2 )
|
||||
conv2 = dec
|
||||
dec = proc{|v| c2.call(conv2.call(v))}
|
||||
end
|
||||
end
|
||||
}
|
||||
ty = ty.strip
|
||||
if( ty.length != 1 )
|
||||
raise(TypeError, "unknown type: #{orig_ty}.")
|
||||
end
|
||||
return [ty,enc,dec]
|
||||
end
|
||||
|
||||
def encode_types(tys)
|
||||
encty = []
|
||||
enc = proc{|v| v}
|
||||
dec = proc{|v| v}
|
||||
tys.each_with_index{|ty,idx|
|
||||
ty,c1,c2 = encode_type(ty)
|
||||
encty.push(ty)
|
||||
conv1 = enc
|
||||
enc = proc{|v| v = conv1.call(v); v[idx] = c1.call(v[idx]); v}
|
||||
conv2 = dec
|
||||
dec = proc{|v| v = conv2.call(v); v[idx] = c2.call(v[idx]); v}
|
||||
}
|
||||
return [encty.join, enc, dec]
|
||||
end
|
||||
|
||||
def check_type
|
||||
if( !defined?(@TYDEFS) )
|
||||
init_type
|
||||
end
|
||||
end
|
||||
|
||||
def init_type
|
||||
@TYDEFS = [
|
||||
# for Windows
|
||||
["DWORD", "unsigned long", nil, nil],
|
||||
["PDWORD", "unsigned long *", nil, nil],
|
||||
["WORD", "unsigned int", nil, nil],
|
||||
["PWORD", "unsigned int *", nil, nil],
|
||||
["BOOL", "ibool", nil, nil],
|
||||
["ATOM", "int", nil, nil],
|
||||
["BYTE", "unsigned char", nil, nil],
|
||||
["PBYTE", "unsigned char *", nil, nil],
|
||||
["UINT", "unsigned int", nil, nil],
|
||||
["ULONG", "unsigned long", nil, nil],
|
||||
["UCHAR", "unsigned char", nil, nil],
|
||||
["HANDLE", "unsigned long", nil, nil],
|
||||
["PHANDLE","void*", nil, nil],
|
||||
["PVOID", "void*", nil, nil],
|
||||
["LPCSTR", "char*", nil, nil],
|
||||
|
||||
# Others
|
||||
["uint", "unsigned int", nil, nil],
|
||||
["u_int", "unsigned int", nil, nil],
|
||||
["ulong", "unsigned long", nil, nil],
|
||||
["u_long", "unsigned long", nil, nil],
|
||||
|
||||
# DL::Importable primitive types
|
||||
["ibool", "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}],
|
||||
["lbool", "L",
|
||||
proc{|v| v ? 1 : 0},
|
||||
proc{|v| (v != 0) ? true : false}],
|
||||
["unsigned char", "I",
|
||||
proc{|v| [v].pack("C").unpack("c")[0]},
|
||||
proc{|v| [v].pack("c").unpack("C")[0]}],
|
||||
["unsigned int", "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]}],
|
||||
["unsigned char ref", "i",
|
||||
proc{|v| [v].pack("C").unpack("c")[0]},
|
||||
proc{|v| [v].pack("c").unpack("C")[0]}],
|
||||
["unsigned int ref", "i",
|
||||
proc{|v| [v].pack("I").unpack("i")[0]},
|
||||
proc{|v| [v].pack("i").unpack("I")[0]}],
|
||||
["unsigned long ref", "l",
|
||||
proc{|v| [v].pack("L").unpack("l")[0]},
|
||||
proc{|v| [v].pack("l").unpack("L")[0]}],
|
||||
["char ref", "c", nil, nil],
|
||||
["short ref", "h", nil, nil],
|
||||
["int ref", "i", nil, nil],
|
||||
["long ref", "l", nil, nil],
|
||||
["float ref", "f", nil, nil],
|
||||
["double ref","d", nil, nil],
|
||||
["char", "C", nil, nil],
|
||||
["short", "H", nil, nil],
|
||||
["int", "I", nil, nil],
|
||||
["long", "L", nil, nil],
|
||||
["float", "F", nil, nil],
|
||||
["double", "D", nil, nil],
|
||||
[/.+\*/, "P", nil, nil],
|
||||
[/.+\[\]/, "a", nil, nil],
|
||||
["void", "0", nil, nil],
|
||||
]
|
||||
end
|
||||
end # end of Internal
|
||||
include Internal
|
||||
end # end of Importable
|
||||
end
|
26
ext/dl/lib/dl/win32.rb
Normal file
26
ext/dl/lib/dl/win32.rb
Normal file
@ -0,0 +1,26 @@
|
||||
# -*- ruby -*-
|
||||
|
||||
require 'dl'
|
||||
|
||||
class Win32API
|
||||
LIBRARY = {}
|
||||
|
||||
attr_reader :val, :args
|
||||
|
||||
def initialize(lib, func, args, ret)
|
||||
LIBRARY[lib] ||= DL.dlopen(lib)
|
||||
ty = (ret + args).tr('V','0')
|
||||
@sym = LIBRARY[lib].sym(func, ty)
|
||||
@__dll__ = LIBRARY[lib].to_i
|
||||
@__dllname__ = lib
|
||||
@__proc__ = @sym.to_i
|
||||
@val = nil
|
||||
@args = []
|
||||
end
|
||||
|
||||
def call(*args)
|
||||
@val,@args = @sym.call(*args)
|
||||
return @val
|
||||
end
|
||||
alias Call call
|
||||
end
|
68
ext/dl/mkcall.rb
Normal file
68
ext/dl/mkcall.rb
Normal file
@ -0,0 +1,68 @@
|
||||
# -*- ruby -*-
|
||||
|
||||
require 'mkmf'
|
||||
$:.unshift File.dirname(__FILE__)
|
||||
require 'type'
|
||||
require 'dlconfig'
|
||||
|
||||
$int_eq_long = try_run(<<EOF)
|
||||
int main() {
|
||||
return sizeof(int) == sizeof(long) ? 0 : 1;
|
||||
}
|
||||
EOF
|
||||
|
||||
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
|
||||
}
|
83
ext/dl/mkcallback.rb
Normal file
83
ext/dl/mkcallback.rb
Normal file
@ -0,0 +1,83 @@
|
||||
# -*- ruby -*-
|
||||
|
||||
require 'mkmf'
|
||||
$:.unshift File.dirname(__FILE__)
|
||||
require 'type'
|
||||
require 'dlconfig'
|
||||
|
||||
$int_eq_long = try_run(<<EOF)
|
||||
int main() {
|
||||
return sizeof(int) == sizeof(long) ? 0 : 1;
|
||||
}
|
||||
EOF
|
||||
|
||||
def func_arg(x,i)
|
||||
ctype = DLTYPE[x][:ctype]
|
||||
"#{ctype} arg#{i}"
|
||||
end
|
||||
|
||||
def func_args(types)
|
||||
t = []
|
||||
types[1..-1].each_with_index{|x,i| t.push(func_arg(x,i))}
|
||||
t.join(", ")
|
||||
end
|
||||
|
||||
def funcall_args(types)
|
||||
num = types.length - 1
|
||||
if( num > 0 )
|
||||
t = []
|
||||
types[1..-1].each_with_index{|x,i| t.push(DLTYPE[x][:c2rb].call("arg#{i}"))}
|
||||
return num.to_s + ", " + t.join(", ")
|
||||
else
|
||||
return num.to_s
|
||||
end
|
||||
end
|
||||
|
||||
def output_func(types, n = 0)
|
||||
func_name = "rb_dl_func#{types2num(types)}_#{n}"
|
||||
code =
|
||||
"#{func_name}(#{func_args(types)}) /* #{types2ctypes(types).inspect} */\n" +
|
||||
"{\n" +
|
||||
" VALUE val, obj;\n" +
|
||||
"#ifdef DEBUG\n" +
|
||||
" printf(\"#{func_name}()\\n\");\n" +
|
||||
"#endif\n" +
|
||||
" obj = rb_hash_aref(DLFuncTable, INT2NUM(#{types2num(types)}));\n" +
|
||||
" obj = rb_hash_aref(obj,INT2NUM(#{n}));\n" +
|
||||
" val = rb_funcall(obj, id_call,\n" +
|
||||
" #{funcall_args(types)});\n"
|
||||
|
||||
rtype = DLTYPE[types[0]][:ctype]
|
||||
rcode = DLTYPE[types[0]][:rb2c]
|
||||
if( rcode )
|
||||
code += " return #{rcode.call('val')};\n"
|
||||
end
|
||||
|
||||
code =
|
||||
rtype + "\n" +
|
||||
code +
|
||||
"}\n\n"
|
||||
if( n < MAX_CBENT - 1)
|
||||
return code + output_func(types, n+1)
|
||||
else
|
||||
return code
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def rec_output(types = [VOID])
|
||||
print output_func(types)
|
||||
if( types.length <= MAX_CBARG )
|
||||
DLTYPE.keys.sort.each{|t|
|
||||
if( t != VOID && DLTYPE[t][:cb] )
|
||||
rec_output(types + [t])
|
||||
end
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
DLTYPE.keys.sort.each{|t|
|
||||
if( DLTYPE[t][:cb] )
|
||||
rec_output([t])
|
||||
end
|
||||
}
|
42
ext/dl/mkcbtable.rb
Normal file
42
ext/dl/mkcbtable.rb
Normal file
@ -0,0 +1,42 @@
|
||||
# -*- ruby -*-
|
||||
|
||||
require 'mkmf'
|
||||
$:.unshift File.dirname(__FILE__)
|
||||
require 'type'
|
||||
require 'dlconfig'
|
||||
|
||||
$int_eq_long = try_run(<<EOF)
|
||||
int main() {
|
||||
return sizeof(int) == sizeof(long) ? 0 : 1;
|
||||
}
|
||||
EOF
|
||||
|
||||
def output_func(types, n = 0)
|
||||
code =
|
||||
"/* #{types2ctypes(types).inspect} */\n" +
|
||||
"rb_dl_func_table[#{types2num(types)}][#{n}] " +
|
||||
"= rb_dl_func#{types2num(types)}_#{n};\n"
|
||||
if( n < MAX_CBENT - 1)
|
||||
return code + output_func(types, n+1)
|
||||
else
|
||||
return code
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def rec_output(types = [VOID])
|
||||
print output_func(types)
|
||||
if( types.length <= MAX_CBARG )
|
||||
DLTYPE.keys.sort.each{|t|
|
||||
if( t != VOID && DLTYPE[t][:cb] )
|
||||
rec_output(types + [t])
|
||||
end
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
DLTYPE.keys.sort.each{|t|
|
||||
if( DLTYPE[t][:cb] )
|
||||
rec_output([t])
|
||||
end
|
||||
}
|
1075
ext/dl/ptr.c
Normal file
1075
ext/dl/ptr.c
Normal file
File diff suppressed because it is too large
Load Diff
70
ext/dl/sample/drives.rb
Normal file
70
ext/dl/sample/drives.rb
Normal file
@ -0,0 +1,70 @@
|
||||
# -*- ruby -*-
|
||||
# drives.rb -- find existing drives and show the drive type.
|
||||
|
||||
require 'dl'
|
||||
require 'dl/import'
|
||||
|
||||
module Kernel32
|
||||
extend DL::Importable
|
||||
|
||||
dlload "kernel32"
|
||||
|
||||
extern "long GetLogicalDrives()"
|
||||
extern "int GetDriveType(char*)"
|
||||
extern "long GetDiskFreeSpace(char*, long ref, long ref, long ref, long ref)"
|
||||
end
|
||||
|
||||
include Kernel32
|
||||
|
||||
buff = Kernel32.getLogicalDrives()
|
||||
|
||||
i = 0
|
||||
ds = []
|
||||
while( i < 26 )
|
||||
mask = (1 << i)
|
||||
if( buff & mask > 0 )
|
||||
ds.push((65+i).chr)
|
||||
end
|
||||
i += 1
|
||||
end
|
||||
|
||||
=begin
|
||||
From the cygwin's /usr/include/w32api/winbase.h:
|
||||
#define DRIVE_UNKNOWN 0
|
||||
#define DRIVE_NO_ROOT_DIR 1
|
||||
#define DRIVE_REMOVABLE 2
|
||||
#define DRIVE_FIXED 3
|
||||
#define DRIVE_REMOTE 4
|
||||
#define DRIVE_CDROM 5
|
||||
#define DRIVE_RAMDISK 6
|
||||
=end
|
||||
|
||||
types = [
|
||||
"unknown",
|
||||
"no root dir",
|
||||
"Removable",
|
||||
"Fixed",
|
||||
"Remote",
|
||||
"CDROM",
|
||||
"RAM",
|
||||
]
|
||||
print("Drive : Type (Free Space/Available Space)\n")
|
||||
ds.each{|d|
|
||||
t = Kernel32.getDriveType(d + ":\\")
|
||||
Kernel32.getDiskFreeSpace(d + ":\\", 0, 0, 0, 0)
|
||||
_,sec_per_clus,byte_per_sec,free_clus,total_clus = Kernel32._args_
|
||||
fbytes = sec_per_clus * byte_per_sec * free_clus
|
||||
tbytes = sec_per_clus * byte_per_sec * total_clus
|
||||
unit = "B"
|
||||
if( fbytes > 1024 && tbytes > 1024 )
|
||||
fbytes = fbytes / 1024
|
||||
tbytes = tbytes / 1024
|
||||
unit = "K"
|
||||
end
|
||||
if( fbytes > 1024 && tbytes > 1024 )
|
||||
fbytes = fbytes / 1024
|
||||
tbytes = tbytes / 1024
|
||||
unit = "M"
|
||||
end
|
||||
print("#{d} : #{types[t]} (#{fbytes} #{unit}/#{tbytes} #{unit})\n")
|
||||
}
|
5
ext/dl/sample/getch.rb
Normal file
5
ext/dl/sample/getch.rb
Normal file
@ -0,0 +1,5 @@
|
||||
require 'dl'
|
||||
|
||||
crtdll = DL::dlopen("crtdll")
|
||||
getch = crtdll['_getch', 'L']
|
||||
print(getch.call, "\n")
|
84
ext/dl/sample/libc.rb
Normal file
84
ext/dl/sample/libc.rb
Normal file
@ -0,0 +1,84 @@
|
||||
require 'dl'
|
||||
|
||||
module LIBC
|
||||
begin
|
||||
LIB = DL.dlopen('libc.so.6')
|
||||
rescue RuntimeError
|
||||
LIB = DL.dlopen('libc.so.5')
|
||||
end
|
||||
|
||||
SYM = {
|
||||
:atoi => LIB['atoi', 'IS'],
|
||||
:isdigit => LIB['isdigit', 'II'],
|
||||
}
|
||||
|
||||
def atoi(str)
|
||||
r,rs = SYM[:atoi].call(str)
|
||||
return r
|
||||
end
|
||||
|
||||
def isdigit(c)
|
||||
r,rs = SYM[:isdigit].call(c)
|
||||
return (r != 0)
|
||||
end
|
||||
end
|
||||
|
||||
module LIBC
|
||||
SYM[:strcat] = LIB['strcat', 'SsS']
|
||||
def strcat(str1,str2)
|
||||
r,rs = SYM[:strcat].call(str1 + "\0#{str2}",str2)
|
||||
return rs[0]
|
||||
end
|
||||
end
|
||||
|
||||
module LIBC
|
||||
SYM[:fopen] = LIB['fopen', 'PSS']
|
||||
SYM[:fclose] = LIB['fclose', '0P']
|
||||
SYM[:fgetc] = LIB['fgetc', 'IP']
|
||||
|
||||
def fopen(filename, mode)
|
||||
r,rs = SYM[:fopen].call(filename, mode)
|
||||
return r
|
||||
end
|
||||
|
||||
def fclose(ptr)
|
||||
SYM[:fclose].call(ptr)
|
||||
return nil
|
||||
end
|
||||
|
||||
def fgetc(ptr)
|
||||
r,rs = SYM[:fgetc].call(ptr)
|
||||
return r
|
||||
end
|
||||
end
|
||||
|
||||
module LIBC
|
||||
SYM[:strlen] = LIB['strlen', 'IP']
|
||||
def strlen(str)
|
||||
r,rs = SYM[:strlen].call(str)
|
||||
return r
|
||||
end
|
||||
end
|
||||
|
||||
$cb1 = DL.set_callback('IPP', 0){|ptr1, ptr2|
|
||||
str1 = ptr1.ptr.to_s
|
||||
str2 = ptr2.ptr.to_s
|
||||
str1 <=> str2
|
||||
}
|
||||
|
||||
module LIBC
|
||||
SYM[:qsort] = LIB['qsort', '0aIIP']
|
||||
def qsort(ary, comp)
|
||||
len = ary.length
|
||||
r,rs = SYM[:qsort].call(ary, len, DL.sizeof('P'), comp)
|
||||
return rs[0].to_a('S', len)
|
||||
end
|
||||
end
|
||||
|
||||
include LIBC
|
||||
|
||||
p atoi("10")
|
||||
p isdigit(?1)
|
||||
p isdigit(?a)
|
||||
p strcat("a", "b")
|
||||
p qsort(["a","c","b"],$cb1)
|
19
ext/dl/sample/msgbox.rb
Normal file
19
ext/dl/sample/msgbox.rb
Normal file
@ -0,0 +1,19 @@
|
||||
# This script works on Windows.
|
||||
|
||||
require 'dl'
|
||||
|
||||
User32 = DL.dlopen("user32")
|
||||
Kernel32 = DL.dlopen("kernel32")
|
||||
|
||||
MB_OK = 0
|
||||
MB_OKCANCEL = 1
|
||||
|
||||
message_box = User32['MessageBoxA', 'ILSSI']
|
||||
r,rs = message_box.call(0, 'ok?', 'error', MB_OKCANCEL)
|
||||
|
||||
case r
|
||||
when 1
|
||||
print("OK!\n")
|
||||
when 2
|
||||
print("Cancel!\n")
|
||||
end
|
18
ext/dl/sample/msgbox2.rb
Normal file
18
ext/dl/sample/msgbox2.rb
Normal file
@ -0,0 +1,18 @@
|
||||
# This script works on Windows.
|
||||
|
||||
require 'dl/win32'
|
||||
|
||||
MB_OK = 0
|
||||
MB_OKCANCEL = 1
|
||||
|
||||
message_box = Win32API.new("user32",'MessageBoxA', 'ISSI', 'I')
|
||||
r = message_box.call(0, 'ok?', 'error', MB_OKCANCEL)
|
||||
|
||||
case r
|
||||
when 1
|
||||
print("OK!\n")
|
||||
when 2
|
||||
print("Cancel!\n")
|
||||
else
|
||||
p r
|
||||
end
|
87
ext/dl/sample/stream.rb
Normal file
87
ext/dl/sample/stream.rb
Normal file
@ -0,0 +1,87 @@
|
||||
# -*- ruby -*-
|
||||
# Display a file name and stream names of a file with those size.
|
||||
|
||||
require 'dl'
|
||||
require 'dl/import'
|
||||
|
||||
module NTFS
|
||||
extend DL::Importable
|
||||
|
||||
dlload "kernel32.dll"
|
||||
|
||||
OPEN_EXISTING = 3
|
||||
GENERIC_READ = 0x80000000
|
||||
BACKUP_DATA = 0x00000001
|
||||
BACKUP_ALTERNATE_DATA = 0x00000004
|
||||
FILE_SHARE_READ = 0x00000001
|
||||
FILE_FLAG_BACKUP_SEMANTICS = 0x02000000
|
||||
|
||||
typealias "LPSECURITY_ATTRIBUTES", "void*"
|
||||
|
||||
extern "BOOL BackupRead(HANDLE, PBYTE, DWORD, PDWORD, BOOL, BOOL, PVOID)"
|
||||
extern "BOOL BackupSeek(HANDLE, DWORD, DWORD, PDWORD, PDWORD, PVOID)"
|
||||
extern "BOOL CloseHandle(HANDLE)"
|
||||
extern "HANDLE CreateFile(LPCSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES,
|
||||
DWORD, DWORD, HANDLE)"
|
||||
|
||||
module_function
|
||||
|
||||
def streams(filename)
|
||||
status = []
|
||||
h = createFile(filename,GENERIC_READ,FILE_SHARE_READ,nil,
|
||||
OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS,0)
|
||||
if( h != 0 )
|
||||
begin
|
||||
# allocate the memory for backup data used in backupRead().
|
||||
data = DL.malloc(DL.sizeof("L5"))
|
||||
data.struct!("LLLLL", :id, :attrs, :size_low, :size_high, :name_size)
|
||||
|
||||
# allocate memories for references to long values used in backupRead().
|
||||
context = DL.malloc(DL.sizeof("L"))
|
||||
lval = DL.malloc(DL.sizeof("L"))
|
||||
|
||||
while( backupRead(h, data, data.size, lval, false, false, context) )
|
||||
size = data[:size_low] + (data[:size_high] << (DL.sizeof("I") * 8))
|
||||
case data[:id]
|
||||
when BACKUP_ALTERNATE_DATA
|
||||
stream_name = DL.malloc(data[:name_size])
|
||||
backupRead(h, stream_name, stream_name.size,
|
||||
lval, false, false, context)
|
||||
name = stream_name[0, stream_name.size]
|
||||
name.tr!("\000","")
|
||||
if( name =~ /^:(.*?):.*$/ )
|
||||
status.push([$1,size])
|
||||
end
|
||||
when BACKUP_DATA
|
||||
status.push([nil,size])
|
||||
else
|
||||
raise(RuntimeError, "unknown data type #{data[:id]}.")
|
||||
end
|
||||
l1 = DL.malloc(DL.sizeof("L"))
|
||||
l2 = DL.malloc(DL.sizeof("L"))
|
||||
if( !backupSeek(h, data[:size_low], data[:size_high], l1, l2, context) )
|
||||
break
|
||||
end
|
||||
end
|
||||
ensure
|
||||
backupRead(h, nil, 0, lval, true, false, context)
|
||||
closeHandle(h)
|
||||
end
|
||||
return status
|
||||
else
|
||||
raise(RuntimeError, "can't open #{filename}.\n")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
ARGV.each{|filename|
|
||||
if( File.exist?(filename) )
|
||||
NTFS.streams(filename).each{|name,size|
|
||||
if( name )
|
||||
print("#{filename}:#{name}\t#{size}bytes\n")
|
||||
else
|
||||
print("#{filename}\t#{size}bytes\n")
|
||||
end
|
||||
}
|
||||
end
|
||||
}
|
771
ext/dl/sym.c
Normal file
771
ext/dl/sym.c
Normal file
@ -0,0 +1,771 @@
|
||||
/* -*- C -*-
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include <ruby.h>
|
||||
#include "dl.h"
|
||||
|
||||
VALUE rb_cDLSymbol;
|
||||
|
||||
#ifndef HAVE_RB_STR_CAT2
|
||||
static VALUE
|
||||
rb_str_cat2(VALUE str, const char *s)
|
||||
{
|
||||
return rb_str_cat(str, s, strlen(s));
|
||||
}
|
||||
#endif
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
#ifndef USE_INLINE_ASM
|
||||
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;
|
||||
void (*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_new(int argc, VALUE argv[], VALUE self)
|
||||
{
|
||||
VALUE addr, name, type;
|
||||
VALUE val;
|
||||
void *saddr;
|
||||
const char *sname, *stype;
|
||||
|
||||
switch( rb_scan_args(argc, argv, "12", &addr, &name, &type) ){
|
||||
case 3:
|
||||
break;
|
||||
case 2:
|
||||
type = Qnil;
|
||||
break;
|
||||
case 1:
|
||||
name = Qnil;
|
||||
type = Qnil;
|
||||
};
|
||||
|
||||
saddr = (void*)(DLNUM2LONG(rb_Integer(addr)));
|
||||
sname = (name == Qnil) ? NULL : STR2CSTR(name);
|
||||
stype = (type == Qnil) ? NULL : STR2CSTR(type);
|
||||
|
||||
val = rb_dlsym_new(saddr, sname, stype);
|
||||
|
||||
if( val != Qnil ){
|
||||
rb_obj_call_init(val, argc, argv);
|
||||
};
|
||||
|
||||
return val;
|
||||
};
|
||||
|
||||
VALUE
|
||||
rb_dlsym_initialize(int argc, VALUE argv[], VALUE self)
|
||||
{
|
||||
return Qnil;
|
||||
};
|
||||
|
||||
VALUE
|
||||
rb_s_dlsym_char2type(VALUE self, VALUE ch)
|
||||
{
|
||||
const char *type;
|
||||
|
||||
type = char2type(STR2CSTR(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%x func=0x%x '%s'>",
|
||||
sym, sym->func, STR2CSTR(proto));
|
||||
val = rb_tainted_str_new2(str);
|
||||
dlfree(str);
|
||||
|
||||
return val;
|
||||
};
|
||||
|
||||
|
||||
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;
|
||||
|
||||
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(NUM2CHR(argv[i]));
|
||||
PUSH_C(ftype);
|
||||
break;
|
||||
case 'h':
|
||||
ANY2H(dargs[i]) = DLSHORT(NUM2CHR(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{
|
||||
ANY2S(args[i]) = DLSTR(STR2CSTR(argv[i]));
|
||||
};
|
||||
PUSH_P(ftype);
|
||||
break;
|
||||
case 's':
|
||||
if( argv[i] == Qnil ){
|
||||
raise(rb_eDLError, "#%d must be a string",i);
|
||||
};
|
||||
ANY2S(args[i]) = DLSTR(dlmalloc(RSTRING(argv[i])->len + 1));
|
||||
memcpy((char*)(ANY2S(args[i])), STR2CSTR(argv[i]), RSTRING(argv[i])->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;
|
||||
|
||||
#ifdef USE_INLINE_ASM
|
||||
ASM_START(sym->type);
|
||||
for( i = sym->len - 2; i >= 0; i-- ){
|
||||
switch( sym->type[i+1] ){
|
||||
case 'p':
|
||||
case 'P':
|
||||
ASM_PUSH_P(ANY2P(args[i]));
|
||||
break;
|
||||
case 'a':
|
||||
case 'A':
|
||||
ASM_PUSH_P(ANY2P(args[i]));
|
||||
break;
|
||||
case 'C':
|
||||
ASM_PUSH_C(ANY2C(args[i]));
|
||||
break;
|
||||
case 'c':
|
||||
ASM_PUSH_P(ANY2P(args[i]));
|
||||
break;
|
||||
case 'H':
|
||||
ASM_PUSH_H(ANY2H(args[i]));
|
||||
break;
|
||||
case 'h':
|
||||
ASM_PUSH_P(ANY2P(args[i]));
|
||||
break;
|
||||
case 'I':
|
||||
ASM_PUSH_I(ANY2I(args[i]));
|
||||
break;
|
||||
case 'i':
|
||||
ASM_PUSH_P(ANY2P(args[i]));
|
||||
break;
|
||||
case 'L':
|
||||
ASM_PUSH_L(ANY2L(args[i]));
|
||||
break;
|
||||
case 'l':
|
||||
ASM_PUSH_P(ANY2P(args[i]));
|
||||
break;
|
||||
case 'F':
|
||||
ASM_PUSH_F(ANY2F(args[i]));
|
||||
break;
|
||||
case 'f':
|
||||
ASM_PUSH_P(ANY2P(args[i]));
|
||||
break;
|
||||
case 'D':
|
||||
ASM_PUSH_D(ANY2D(args[i]));
|
||||
break;
|
||||
case 'd':
|
||||
ASM_PUSH_P(ANY2P(args[i]));
|
||||
break;
|
||||
case 'S':
|
||||
case 's':
|
||||
ASM_PUSH_P(ANY2S(args[i]));
|
||||
break;
|
||||
};
|
||||
}
|
||||
ASM_END(sym->type);
|
||||
|
||||
{
|
||||
switch( sym->type[0] ){
|
||||
case '0':
|
||||
{
|
||||
void (*f)() = func;
|
||||
f();
|
||||
};
|
||||
break;
|
||||
case 'P':
|
||||
case 'p':
|
||||
{
|
||||
void * (*f)() = func;
|
||||
ret.p = f();
|
||||
};
|
||||
break;
|
||||
case 'C':
|
||||
case 'c':
|
||||
{
|
||||
char (*f)() = func;
|
||||
ret.c = f();
|
||||
};
|
||||
break;
|
||||
case 'H':
|
||||
case 'h':
|
||||
{
|
||||
short (*f)() = func;
|
||||
ret.h = f();
|
||||
};
|
||||
break;
|
||||
case 'I':
|
||||
case 'i':
|
||||
{
|
||||
int (*f)() = func;
|
||||
ret.i = f();
|
||||
};
|
||||
break;
|
||||
case 'L':
|
||||
case 'l':
|
||||
{
|
||||
long (*f)() = func;
|
||||
ret.l = f();
|
||||
};
|
||||
break;
|
||||
case 'F':
|
||||
case 'f':
|
||||
{
|
||||
float (*f)() = func;
|
||||
ret.f = f();
|
||||
};
|
||||
break;
|
||||
case 'D':
|
||||
case 'd':
|
||||
{
|
||||
double (*f)() = func;
|
||||
ret.d = f();
|
||||
};
|
||||
break;
|
||||
case 'S':
|
||||
case 's':
|
||||
{
|
||||
char * (*f)() = func;
|
||||
ret.s = f();
|
||||
};
|
||||
break;
|
||||
default:
|
||||
FREE_ARGS;
|
||||
rb_raise(rb_eDLTypeError, "unknown type `%c'", sym->type[0]);
|
||||
};
|
||||
};
|
||||
#else
|
||||
switch(ftype){
|
||||
#include "call.func"
|
||||
default:
|
||||
FREE_ARGS;
|
||||
rb_raise(rb_eDLTypeError, "unsupported function type `%s'", sym->type);
|
||||
};
|
||||
#endif
|
||||
|
||||
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_cData);
|
||||
rb_define_singleton_method(rb_cDLSymbol, "new", rb_dlsym_s_new, -1);
|
||||
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);
|
||||
};
|
29
ext/dl/test/libtest.def
Normal file
29
ext/dl/test/libtest.def
Normal file
@ -0,0 +1,29 @@
|
||||
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_print
|
||||
test_data_aref
|
||||
test_set_long_value
|
||||
test_get_long_value
|
||||
internal_long_value
|
251
ext/dl/test/test.c
Normal file
251
ext/dl/test/test.c
Normal file
@ -0,0 +1,251 @@
|
||||
#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;
|
||||
};
|
||||
};
|
||||
|
||||
void
|
||||
test_init(int *argc, char **argv[])
|
||||
{
|
||||
int i;
|
||||
printf("test_init(0x%x,0x%x)\n",argc,argv);
|
||||
printf("\t*(0x%x) => %d\n",argc,*argc);
|
||||
for( i=0; i < (*argc); i++ ){
|
||||
printf("\t(*(0x%x)[%d]) => %s\n", argv, i, (*argv)[i]);
|
||||
};
|
||||
};
|
||||
|
||||
FILE *
|
||||
test_open(const char *filename, const char *mode)
|
||||
{
|
||||
FILE *file;
|
||||
file = fopen(filename,mode);
|
||||
printf("test_open(%s,%s):0x%x\n",filename,mode,file);
|
||||
return file;
|
||||
};
|
||||
|
||||
void
|
||||
test_close(FILE *file)
|
||||
{
|
||||
printf("test_close(0x%x)\n",file);
|
||||
fclose(file);
|
||||
};
|
||||
|
||||
char *
|
||||
test_gets(char *s, int size, FILE *f)
|
||||
{
|
||||
return fgets(s,size,f);
|
||||
};
|
||||
|
||||
typedef int callback1_t(int, char *);
|
||||
|
||||
int
|
||||
test_callback1(int err, const char *msg)
|
||||
{
|
||||
printf("internal callback function (err = %d, msg = '%s')\n",
|
||||
err, msg ? msg : "(null)");
|
||||
return 1;
|
||||
};
|
||||
|
||||
int
|
||||
test_call_func1(callback1_t *func)
|
||||
{
|
||||
if( func ){
|
||||
return (*func)(0, "this is test_call_func1.");
|
||||
}
|
||||
else{
|
||||
printf("test_call_func1(func = 0)\n");
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
|
||||
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));
|
||||
strcpy(data->name, name);
|
||||
data->next = list->next;
|
||||
list->next = data;
|
||||
};
|
||||
|
||||
void
|
||||
test_data_print(struct test_data *list)
|
||||
{
|
||||
struct test_data *data;
|
||||
|
||||
for( data = list->next; data; data = data->next ){
|
||||
printf("name = %s\n", data->name);
|
||||
};
|
||||
};
|
||||
|
||||
struct 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;
|
||||
};
|
272
ext/dl/test/test.rb
Normal file
272
ext/dl/test/test.rb
Normal file
@ -0,0 +1,272 @@
|
||||
# -*- ruby -*-
|
||||
|
||||
require 'dl'
|
||||
require 'dl/import'
|
||||
|
||||
def assert(label, ty, *conds)
|
||||
cond = !conds.include?(false)
|
||||
if( cond )
|
||||
printf("succeed in `#{label}'\n")
|
||||
else
|
||||
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("VERSION = #{DL::VERSION}\n")
|
||||
print("MAJOR_VERSION = #{DL::MAJOR_VERSION}\n")
|
||||
print("MINOR_VERSION = #{DL::MINOR_VERSION}\n")
|
||||
print("\n")
|
||||
print("MAX_ARG = #{DL::MAX_ARG}\n")
|
||||
print("MAX_CBARG = #{DL::MAX_CBARG}\n")
|
||||
print("MAX_CBENT = #{DL::MAX_CBENT}\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","0iP"]
|
||||
debug init
|
||||
argc = 3
|
||||
argv = ["arg0","arg1","arg2"].to_ptr
|
||||
r,rs = init[argc, argv.ref]
|
||||
debug r,rs
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
else
|
||||
assert("open,gets", :must, line == nil)
|
||||
end
|
||||
File.unlink("tmp.txt")
|
||||
|
||||
|
||||
callback1 = h["test_callback1"]
|
||||
debug callback1
|
||||
r,rs = h["test_call_func1", "IP"][callback1]
|
||||
debug r,rs
|
||||
assert("callback1", :must, r == 1)
|
||||
|
||||
|
||||
callback2 = DL.set_callback("LLP", 0){|arg1,arg2|
|
||||
ptr = arg2 # DL::PtrData.new(arg2)
|
||||
msg = ptr.to_s
|
||||
print("user defined callback function",
|
||||
"(err = #{arg1}, msg = '#{msg}')\n")
|
||||
2
|
||||
}
|
||||
debug callback2
|
||||
r,rs = h["test_call_func1", "IP"][callback2]
|
||||
debug r,rs
|
||||
assert("callback2", :must, r == 2)
|
||||
|
||||
|
||||
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_print = h["test_data_print", "0P"]
|
||||
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"]
|
||||
data_print[ptr]
|
||||
|
||||
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
|
115
ext/dl/type.rb
Normal file
115
ext/dl/type.rb
Normal file
@ -0,0 +1,115 @@
|
||||
# example:
|
||||
# DLTYPE[INT][:rb2c]["arg0"] => "NUM2INT(arg0)"
|
||||
# DLTYPE[DOUBLE][:c2rb]["r"] => "rb_float_new(r)"
|
||||
|
||||
DLTYPE = {
|
||||
VOID = 0x00 => {
|
||||
:name => 'VOID',
|
||||
:rb2c => nil,
|
||||
:c2rb => nil,
|
||||
:ctype => "void",
|
||||
:stmem => "v",
|
||||
:sym => true,
|
||||
:cb => true,
|
||||
},
|
||||
CHAR = 0x01 => {
|
||||
:name => 'CHAR',
|
||||
:rb2c => proc{|x| "NUM2CHR(#{x})"},
|
||||
:c2rb => proc{|x| "CHR2FIX(#{x})"},
|
||||
:ctype => "char",
|
||||
:stmem => "c",
|
||||
:sym => false,
|
||||
:cb => false,
|
||||
},
|
||||
SHORT = 0x02 => {
|
||||
:name => 'SHORT',
|
||||
:rb2c => proc{|x| "FIX2INT(#{x})"},
|
||||
:c2rb => proc{|x| "INT2FIX(#{x})"},
|
||||
:ctype => "short",
|
||||
:stmem => "h",
|
||||
:sym => false,
|
||||
:cb => false,
|
||||
},
|
||||
INT = 0x03 => {
|
||||
:name => 'INT',
|
||||
:rb2c => proc{|x| "NUM2INT(#{x})"},
|
||||
:c2rb => proc{|x| "INT2NUM(#{x})"},
|
||||
:ctype => "int",
|
||||
:stmem => "i",
|
||||
:sym => true,
|
||||
:cb => false,
|
||||
},
|
||||
LONG = 0x04 => {
|
||||
:name => 'LONG',
|
||||
:rb2c => proc{|x| "NUM2INT(#{x})"},
|
||||
:c2rb => proc{|x| "INT2NUM(#{x})"},
|
||||
:ctype => "long",
|
||||
:stmem => "l",
|
||||
:sym => true,
|
||||
:cb => true,
|
||||
},
|
||||
FLOAT = 0x05 => {
|
||||
:name => 'FLOAT',
|
||||
:rb2c => proc{|x| "(float)(RFLOAT(#{x})->value)"},
|
||||
:c2rb => proc{|x| "rb_float_new((double)#{x})"},
|
||||
:ctype => "float",
|
||||
:stmem => "f",
|
||||
:sym => false,
|
||||
:cb => false,
|
||||
},
|
||||
DOUBLE = 0x06 => {
|
||||
:name => 'DOUBLE',
|
||||
:rb2c => proc{|x| "RFLOAT(#{x})->value"},
|
||||
:c2rb => proc{|x| "rb_float_new(#{x})"},
|
||||
:ctype => "double",
|
||||
:stmem => "d",
|
||||
:sym => true,
|
||||
:cb => true,
|
||||
},
|
||||
VOIDP = 0x07 => {
|
||||
:name => 'VOIDP',
|
||||
:rb2c => proc{|x| "rb_dlptr2cptr(#{x})"},
|
||||
:c2rb => proc{|x| "rb_dlptr_new(#{x},sizeof(void*),0)"},
|
||||
:ctype => "void *",
|
||||
:stmem => "p",
|
||||
:sym => true,
|
||||
:cb => true,
|
||||
},
|
||||
}
|
||||
|
||||
def tpush(t, x)
|
||||
(t << 3)|x
|
||||
end
|
||||
|
||||
def tget(t, i)
|
||||
(t & (0x07 << (i * 3))) >> (i * 3)
|
||||
end
|
||||
|
||||
def types2num(types)
|
||||
res = 0x00
|
||||
r = types.reverse
|
||||
r.each{|t|
|
||||
res = tpush(res,t)
|
||||
}
|
||||
res
|
||||
end
|
||||
|
||||
def num2types(num)
|
||||
ts = []
|
||||
i = 0
|
||||
t = tget(num,i)
|
||||
while( (t != VOID && i > 0) || (i == 0) )
|
||||
ts.push(DLTYPE[t][:ctype])
|
||||
i += 1
|
||||
t = tget(num,i)
|
||||
end
|
||||
ts
|
||||
end
|
||||
|
||||
def types2ctypes(types)
|
||||
res = []
|
||||
types.each{|t|
|
||||
res.push(DLTYPE[t][:ctype])
|
||||
}
|
||||
res
|
||||
end
|
Loading…
x
Reference in New Issue
Block a user