Ruby/DL and functions that modify a pointer

B

Ben Giddings

I just started using Ruby/DL and am amazed at what it can do. I've
almost got a really impressive demo to show off to my cow-orkers, but I
have one cow left to ork... er... I have one thing left to figure out.

Given some C code like this:

typdef struct {
int status;
int results[16];
} foo_t;

int get_results(handle_t the_handle, foo_t *results_ptr)
{
results_ptr->status = 0;
results_ptr->results[0] = 0xFF;

return 0;
}

How do I interface to that code in Ruby/DL?

I already have functions that take handles, I just treat it as a pointer
and everything works great:

require 'dl/import'
module LIBMYAPI
extend DL::Importable
dlload "./libmyapi.so.1.0.1"
typealias("size_t", "unsigned int")
typealias("id_t", "int")
extern "void *open_handle(char *)"
extern "char *get_version(void *)"
extern "int close_handle(void *)"
end

if __FILE__ == $0
hostname = 'foo'

handle = LIBMYAPI.open_handle("m4-c0050c")
result = LIBMYAPI.get_version(handle)
puts result
LIBM4API.close_handle(handle)
end

I just don't know how to tell Ruby/DL that get_results takes a pointer,
then changes it.

While I'm at it, what's the proper way to deal with a structure
containing an array, if you want to access things by name?

Something like this works for the 'timeval' struct, but I don't know how
to use it with structs containing arrays.

ptr = DL.malloc(DL.sizeof('LL'))
ptr.struct!('LL', :tv_sec, :tv_usec)
ptr[:tv_sec] = 10
ptr[:tv_usec] = 100
sec = ptr[:tv_sec]
usec = ptr[:tv_usec]

Thanks!

Ben
 
T

Takaaki Tateishi

Ben said:
Something like this works for the 'timeval' struct, but I don't know how
to use it with structs containing arrays.

Please use the method 'struct' like 'extern', and the following example
shows how to use it.


require 'dl/import'
require 'dl/struct'

module MyLIB
extend DL::Importable

MyStruct = struct [
"int foo[3]",
]
end

ptr = MyLIB::MyStruct.malloc()
ptr.foo = [0,1,2]
p ptr.foo


But I found a bug on 'dl/struct.rb', so please replace it with the following file.
http://www.ruby-lang.org/cgi-bin/cv...ontent-type=text/plain;only_with_tag=ruby_1_8
 
B

Ben Giddings

Takaaki said:
Please use the method 'struct' like 'extern', and the following example
shows how to use it.


require 'dl/import'
require 'dl/struct'

module MyLIB
extend DL::Importable

MyStruct = struct [
"int foo[3]",
]
end

ptr = MyLIB::MyStruct.malloc()
ptr.foo = [0,1,2]
p ptr.foo


But I found a bug on 'dl/struct.rb', so please replace it with the
following file.
http://www.ruby-lang.org/cgi-bin/cv...ontent-type=text/plain;only_with_tag=ruby_1_8

Thanks so much for your help Takaaki,

Do you know the answer to the other question? How to wrap a function
that modifies a structure you pass in?

For example:

#define VALID_DATA 1
#define ERROR 0

int get_data(struct mystruct *data_ptr)
{
if (error_happened())
{
return ERROR;
}
else
{
data_ptr->foo[0] = 0;
data_ptr->foo[1] = 0xFF;
}
}


How do I write Ruby/DL code that uses this function to get data out of
data_ptr?

I noticed that when using the Ruby/DL Symbols, calls like atoi["1"]
returns two things, the result and the args. Would these args contain
the modified structure?

The type of function I want to access from Ruby is "scanf" type
functions where the return value isn't the only data returned.

Thanks,

Ben
 
A

Asbjørn Reglund Thorsen

I am trying to write these two typemaps into ruby typemaps:

%typemap(out) int&{
/*long since Python do not have PyInt_FromInt*/
long *n = (long *) $1;
$result = PyInt_FromLong(*n);
}

%typemap(in) int &{
$1 = PyInt_AsLong($input);
}

This is what I tried, but did not work:

%typemap(out) int &{ //C->Ruby, Back to Ruby int object
long *n = (long *) $1;
$result = INT2NUM(*n);
}

%typemap(in) int &{ //Ruby->C, From Ruby integer to C long
$1 = NUM2INT($input);
}

I get error messages like:
error: invalid conversion from `int' to `int*'
and

What am I doing wrong ?
 
T

Takaaki Tateishi

Ben said:
Do you know the answer to the other question? How to wrap a function
that modifies a structure you pass in?

Just use 'extern' as follows:

module MyLIB
extend Importable
dlload "...."
MyStruct = struct [
"int foo[3]",
]
extern "int get_data(void*)"
end

ptr = MyLIB::MyStruct.malloc()
MyLIB.get_data(ptr)
 
L

Lyle Johnson

This is what I tried, but did not work:

%typemap(out) int &{ //C->Ruby, Back to Ruby int object
long *n = (long *) $1;
$result = INT2NUM(*n);
}

This one won't generate a compiler error (well, it didn't for me) but
it's dangerous to cast the return value, which is a pointer-to-int, to
a pointer-to-long. Here's a better version of this typemap:

%typemap(out) int & {
$result = INT2NUM(*$1);
}
%typemap(in) int &{ //Ruby->C, From Ruby integer to C long
$1 = NUM2INT($input);
}

OK, this is the one that generated the compiler error you saw. Here's
a corrected version:

%typemap(in) int & (int tmp) {
tmp = NUM2INT($input);
$1 = &tmp;
}

Hope this helps,

Lyle
 
B

Ben Giddings

Takaaki said:
Do you know the answer to the other question? How to wrap a function
that modifies a structure you pass in?


Just use 'extern' as follows:

module MyLIB
extend Importable
dlload "...."
MyStruct = struct [
"int foo[3]",
]
extern "int get_data(void*)"
end

ptr = MyLIB::MyStruct.malloc()
MyLIB.get_data(ptr)


Thanks so much Takaaki, that works perfectly, I'm now wrapping a library
and doing some pretty impressive things, all in less than 100 lines of
Ruby code!

Ben
 
A

Asbjørn Reglund Thorsen

---259930559-66454694-1107591622=:11442
Content-Type: MULTIPART/MIXED; BOUNDARY="-259930559-66454694-1107591622=:11442"

This message is in MIME format. The first part should be readable text,
while the remaining parts are likely unreadable without MIME-aware tools.

---259930559-66454694-1107591622=:11442
Content-Type: TEXT/PLAIN; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: QUOTED-PRINTABLE

Thank you once again Lyle :) .

This one won't generate a compiler error (well, it didn't for me) but
it's dangerous to cast the return value, which is a pointer-to-int, to
a pointer-to-long. Here's a better version of this typemap:

%typemap(out) int & {
$result =3D INT2NUM(*$1);
}


OK, this is the one that generated the compiler error you saw. Here's
a corrected version:

%typemap(in) int & (int tmp) {
tmp =3D NUM2INT($input);
$1 =3D &tmp;
}

Hope this helps,

Lyle
---259930559-66454694-1107591622=:11442--
---259930559-66454694-1107591622=:11442--
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,879
Messages
2,569,939
Members
46,232
Latest member
DeniseMcVi

Latest Threads

Top