Ruby and Swig -- creating Pointers (typedef)

I have been using Swig for the first time since Lyle mentioned Phil
Tomson’s article in C/C++ Users Journal (http://www.cuj.com)

My goal is to use my company’s C/C++ API with Ruby.
I think it would add a great deal of flexibility to my current
programming.

I let Swig automatically create the wrapper for me (using the “truly
lazy way” interface…just pointing it to the header file.)

Amazingly, everything is working.
I’m able to load the shared library into Ruby.
I can see all the methods, constants, etc…

However, some of the methods I want to use require pointers.
Sorry for my ignorance, but I have only programmed in Java and Ruby…
so I don’t have any true exposure to C/C++ or the concept of pointers.

In the header file (API) I have are some typedef statments:

//
/* /
/
Global Data Types /
/
*/
/
/
typedef char CoolBoolean;
typedef char* CoolString;
typedef int CoolClientHandle;
typedef int CoolTableHandle;

Now I want use the following connect method.

//
/
/
/
Opening and Closing Connection /
/
/
/
/

extern DllDecl CoolReturnCode CoolConnect
PROTO((char			*srvHostName,
       int			serverNumber,
       CoolClientHandle		*handle));

How do I create a pointer of type “CoolClientHandle” in Ruby?
Am I thinking about this incorrectly?

I have read over the pointer documentation, however I have been unable
to make it work.

Any advice would be appreciated.

Thanks.

RubyQuestions wrote:

However, some of the methods I want to use require pointers.
Sorry for my ignorance, but I have only programmed in Java and Ruby…
so I don’t have any true exposure to C/C++ or the concept of pointers.

OK.

Now I want use the following connect method.

extern DllDecl CoolReturnCode CoolConnect

PROTO((char *srvHostName,
int serverNumber,
CoolClientHandle *handle));

How do I create a pointer of type “CoolClientHandle” in Ruby?
Am I thinking about this incorrectly?

One of the fun uses of pointers in C/C++ code is to allow you to return
values through the argument list. I don’t want to burden you with any
more information about this than is necessary, but suffice it to say
that given a pointer-typed argument like “CoolClientHandle *handle”,
SWIG can’t automatically determine whether that argument is an
input-only, output-only, or both input and output.

But I’m going to make an educated guess that for this function, the
first two arguments (srvHostName and serverNumber) are the inputs and
the last (handle) is actually its output. That is, in Ruby you’d want to
be able to call this method as:

 handle = CoolConnect(srvHostName, serverNumber)

You might also want to handle the function’s return type
(CoolReturnCode) in some special way as well. For example, if the return
value indicates that some kind of error occurred, you might want it to
raise a Ruby exception – but again, that decision is up to you.

I have read over the pointer documentation, however I have been unable
to make it work.

OK. I think the first thing to do is provide SWIG with a typemap to tell
it that the 3rd argument (handle) is actually an output of the function.
First, include the standard SWIG typemaps library by adding the line:

 %include typemaps.i

near the top of your SWIG interface file. Then, tell SWIG to apply one
of its standard typemaps for output-by-pointer to the handle argument by
adding this line to the interface file:

 %apply int *OUTPUT { CoolClientHandle *handle };

For example, my SWIG interface file looks like this:

 %module cool

 %{
 #include "cool.h"
 %}

 %include typemaps.i

 %apply int *OUTPUT { CoolClientHandle *handle };

 %include cool.h

Now re-run SWIG, etc. to rebuild your extension module. At this point,
you should find that calling CoolConnect() from Ruby returns an array of
with two values: the function’s actual result (i.e. a “CoolReturnCode”
value) and the handle, e.g.

 returnCode, handle = Cool.CoolConnect("myServer", 6667)

Any advice would be appreciated.

The next step, perhaps, would be to do something different with the
CoolReturnCode value (e.g. raising some kind of exception if it
indicates an error). But we’ll save that for the next lesson :wink:

Hope this helps,

Lyle

RubyQuestions@yahoo.com (RubyQuestions) wrote in message news:599e9746.0401121052.61a0520c@posting.google.com

I have been using Swig for the first time since Lyle mentioned Phil
Tomson’s article in C/C++ Users Journal (http://www.cuj.com)

My goal is to use my company’s C/C++ API with Ruby.
I think it would add a great deal of flexibility to my current
programming.

I let Swig automatically create the wrapper for me (using the “truly
lazy way” interface…just pointing it to the header file.)

Amazingly, everything is working.
I’m able to load the shared library into Ruby.
I can see all the methods, constants, etc…

However, some of the methods I want to use require pointers.
Sorry for my ignorance, but I have only programmed in Java and Ruby…
so I don’t have any true exposure to C/C++ or the concept of pointers.

In the header file (API) I have are some typedef statments:

//
/* /
/
Global Data Types /
/
*/
/
/
typedef char CoolBoolean;
typedef char* CoolString;
typedef int CoolClientHandle;
typedef int CoolTableHandle;

Now I want use the following connect method.

//
/
/
/
Opening and Closing Connection /
/
/
/
/

extern DllDecl CoolReturnCode CoolConnect

PROTO((char *srvHostName,
int serverNumber,
CoolClientHandle *handle));

How do I create a pointer of type “CoolClientHandle” in Ruby?
Am I thinking about this incorrectly?

I have read over the pointer documentation, however I have been unable
to make it work.

Any advice would be appreciated.

Thanks.

You need to include the typedefs in the declaration portion of the .i file
(or you need to include the .h file where the typedef is defined).

for example, let’s say you have the typedef in the file foo.h:

//foo.h
typedef int CoolClientHandle;
typedef int CoolTableHandle;
///end of file///

You need to include it in your .i file like:

%{
/this get’s put in your wrapper code/
#include “foo.h”
%}
/no you’ve got to tell SWIG about it/
typedef int CoolClientHandle;
typedef int CoolTableHandle; //yeah, I know it seems redundant

You should be able to pass in an integer from the Ruby side, swig will take
care of the pointer referencing/dereferencing.

If it’s still not working, please post your .i file.

Phil

In article c68ca8f2.0401121518.717a0dc5@posting.google.com,

RubyQuestions@yahoo.com (RubyQuestions) wrote in message
news:599e9746.0401121052.61a0520c@posting.google.com

I have been using Swig for the first time since Lyle mentioned Phil
Tomson’s article in C/C++ Users Journal (http://www.cuj.com)

My goal is to use my company’s C/C++ API with Ruby.
I think it would add a great deal of flexibility to my current
programming.

I let Swig automatically create the wrapper for me (using the “truly
lazy way” interface…just pointing it to the header file.)

Amazingly, everything is working.
I’m able to load the shared library into Ruby.
I can see all the methods, constants, etc…

However, some of the methods I want to use require pointers.
Sorry for my ignorance, but I have only programmed in Java and Ruby…
so I don’t have any true exposure to C/C++ or the concept of pointers.

In the header file (API) I have are some typedef statments:

//
/* /
/
Global Data Types /
/
*/
/
/
typedef char CoolBoolean;
typedef char* CoolString;
typedef int CoolClientHandle;
typedef int CoolTableHandle;

Now I want use the following connect method.

//
/
/
/
Opening and Closing Connection /
/
/
/
/

extern DllDecl CoolReturnCode CoolConnect

PROTO((char *srvHostName,
int serverNumber,
CoolClientHandle *handle));

How do I create a pointer of type “CoolClientHandle” in Ruby?
Am I thinking about this incorrectly?

I have read over the pointer documentation, however I have been unable
to make it work.

Any advice would be appreciated.

Thanks.

You need to include the typedefs in the declaration portion of the .i file
(or you need to include the .h file where the typedef is defined).

for example, let’s say you have the typedef in the file foo.h:

//foo.h
typedef int CoolClientHandle;
typedef int CoolTableHandle;
///end of file///

A couple of corrections:

You need to include it in your .i file like:

%{
/this get’s put in your wrapper code/
#include “foo.h”
%}
/now you’ve got to tell SWIG about it/
typedef int CoolClientHandle;
typedef int CoolTableHandle; //yeah, I know it seems redundant

It would be better if you just did:

%include “foo.h”

You should be able to pass in an integer from the Ruby side, swig will take
care of the pointer referencing/dereferencing.

See Lyle’s post on pointers being used as output parameters.

Phil

···

Phil Tomson intc_ctor@yahoo.com wrote:

Lyle and Phil,

Thanks for the advice…it worked perfectly.

changing the way the method passes back a “CoolClientHandle” value for
*handle…
%apply int *OUTPUT { CoolClientHandle *handle };

and then in Ruby grabbing the handle output worked…
returnCode, handle = Cool.CoolConnect(“myServer”, 6667)

However, I now ran into a “char*** problem”.

For example, I want to use the following method.

Here is what the header file looks like…

extern DllDecl CoolReturnCode CoolGetRelChildren
PROTO((CoolClientHandle		handle,
       char			*relName,
       int			*numChildren,
       char			***children));

I’m pretty sure that char ***children is suppose to give me an array
of strings.

Unfortunately, I can’t do “%apply char* *OUTPUT {char ***children}”.
How do I get an array or some other type of object pointer back (like
a struct with many values and variables).

Is this where I start to use “typemap(out)” definition or
"typemap(varout)"?

I hope this does not seem too basic.
Thank you for getting me up an running.

P.S. Where is the best starting place for someone with my background
(only using Java and Ruby) to start learning C?