Ruby/DL and functions that modify a pointer

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

Ben Giddings wrote:

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/cvsweb.cgi/~checkout~/ruby/ext/dl/lib/dl/struct.rb?rev=1.8.2.4;content-type=text%2Fplain;only_with_tag=ruby_1_8

···

--
Takaaki Tateishi <ttate@ttsky.net>

Takaaki Tateishi wrote:

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/cvsweb.cgi/~checkout~/ruby/ext/dl/lib/dl/struct.rb?rev=1.8.2.4;content-type=text%2Fplain;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

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 ?

Ben Giddings wrote:

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)

···

--
Takaaki Tateishi <ttate@ttsky.net>

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

···

On Fri, 4 Feb 2005 16:30:32 +0900, Asbjørn Reglund Thorsen <asbjoert@ifi.uio.no> wrote:

Takaaki Tateishi wrote:

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

Thank you once again Lyle :slight_smile: .

···

On Fri, 4 Feb 2005, Lyle Johnson wrote:

On Fri, 4 Feb 2005 16:30:32 +0900, Asbjørn Reglund Thorsen > <asbjoert@ifi.uio.no> wrote:

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