Jim Freeze wrote:
Ok, I have been reading the swig docs and I have
a few questions. Other than the code above looking
totally greek to me, the swig manual does its
best to convince me that I never want to write
a typemap. So, why do we have to write a typemap
for something so common as char **? Is it because
I said that I wanted to call dbInit as:
dbInit(n, “some string”)
instead of
dbInit(n, [“some string”])?
We should probably add a standard typemap for converting a Ruby Array of
Strings to a char ** (like the one I showed). Your case is a little
unusual in that the first argument is a pointer-to-int, instead of just
an int, but that’s not too much of a problem.
But after taking another look at what I sent you, it doesn’t do quite
what you asked for. (It also had a few bugs). For Ruby, it’s sort-of
redundant to pass in both the length of the Array and the Array itself,
unless you wanted to specifically limit the number of elements used in
the array (e.g. “Here’s an array with 100 elements, but only do
something with the first 15 of them”). The typemap I was shooting for
just expects a single argument (an Array). I’ve further modified it so
that it accepts either a single String, or an Array of Strings:
%typemap(in) (int *pnArgs, String *pString) (int count, int i, VALUE
tmp) {
if (TYPE($input) == T_STRING) {
count = 1;
$1 = &count;
$2 = (String *) malloc(sizeof(String));
$2[0] = StringValuePtr($input);
} else if (TYPE($input) == T_ARRAY) {
count = RARRAY($input)->len;
$1 = &count;
$2 = (String ) malloc(countsizeof(String));
for (i = 0; i < count; i++) {
tmp = rb_ary_entry($input, i);
$2[i] = StringValuePtr(tmp);
}
}
}
%typemap(freearg) String *pString {
free((void *) $1);
}
Second question, do I need to learn how to write typemaps?
For some fairly simple interfaces, you may not need to know how to write
typemaps. But almost anything involving pointers usually requires at
least some knowledge of how typemaps work. This also entails knowing
something about Ruby’s C API (e.g. the code above that deals with
grabbing elements out of a Ruby Array).
Note that even if you weren’t using SWIG, the fundamental problems don’t
go away. If you want wrapper code to interface between Ruby and C/C++,
someone’s got to write it
For me, the big advantage of using SWIG is
that for large interfaces, most of the tedious parts of generating that
wrapper code are taken care of. As I said in my presentation at
RubyConf, though, for small interfaces SWIG may be overkill and you may
be better off just writing the wrapper code yourself, by hand. I will
certainly not try to convince anyone that there isn’t a learning curve
associated with using SWIG 
Third question, what is the $1 and $2 in the above typemap.
The first part of the typemap declaration:
%typemap(in) (int *pnArgs, String *pString) {
...
}
shows what kinds of argument patterns (in function declarations) that
SWIG is going to try to match for this typemap. In other words, if it
sees any functions that have the arguments “int *pnArgs” and “String
*pString”, with those names, in that order, it’s a match. So each of
these functions would use that typemap:
void dbInit(int *pnArgs, String *pString);
void foo(float x, int *pnArgs, String *pString, long y, double z);
but these wouldn’t match:
void goo(int *pnArgs);
void boo(String *pString);
void loo(String *pString, int *pnArgs);
void bar(int *pnArgs, float y, String *pString);
Inside the typemap code, then, $1 refers to the first value matched (the
int * value) and $2 refers to the second one (the String * value). I
think this is covered in the typemaps section of the SWIG/Ruby docs:
http://www.swig.org/Doc1.3/Ruby.html
as well as the (more comprehensive) chapter on SWIG typemaps:
http://www.swig.org/Doc1.3/Typemaps.html
Hope this helps,
Lyle