"Richard J. Kuhns" <rjk / grauel.com> wrote in message
news:85zo1oh02r.fsf / moriarity.grauel.com...
> Greetings.  I've written some C code and a SWIG interface file that I can
> use to access a third-party database library that I'm currently using with
> TCL and, more recently, Python.  I've also recently discovered Ruby, and I
> like what I've seen -- it looks to me like Ruby started with most of the
> features I want and like that Python is currently struggling to
> achieve. I'm afraid TCL isn't in the running any more :).  My only problem
> is a time constraint; if I want to be able to potentially use Ruby instead
> of Python I've got to start soon (within the week, actually).  I'm hoping
I
> can get either answers to two questions, or pointers to online
> documentation.  I know I could figure the answers out myself eventually,
> but I'm hoping to shorten the cycle so I can demonstrate some code written
> in Ruby.

For general documentation on the Ruby programming language itself (as well
as some information on the C API for extensions), see "Programming Ruby":

    http://www.rubycentral.com/book/index.html

This is also included in the Pragmatic Programmers' Windows installer for
Ruby, if you used that.

> OK, without further ado, here's what I need.
>
> First, a SWIG typemap to convert a (Ruby) list of stings into a char **.
> The SWIG documentation includes such a typemap for (at least) TCL, Python,
> and Perl, but not for Ruby.

Be sure to use the latest development version of SWIG that you can get your
hands on. The last official release was SWIG 1.3.11, but there were of
course some bugs in there. If it's an option, you may also want to check-out
the CVS sources for SWIG which should include more recent bug fixes for the
Ruby (and other) language modules.

But anyways... this pair of typemaps should do the trick:

%typemap(ruby, in) char** {
    long i;
    long size;

    /* Make sure it's an array */
    Check_Type($input, T_ARRAY);
    size = RARRAY($input)->len;
    $1 = (char **) malloc((size + 1)*sizeof(char *));
    for (i = 0; i < size; i++) {
        VALUE o = rb_ary_entry($input, i);
        Check_Type(o, T_STRING);
        $1[i] = STR2CSTR(o);
    }
    $1[i] = 0;
}

%typemap(ruby, freearg) char** {
    free((void *) $1);
}

> Second, I can't use a dynamically loaded module; it has to be static.
Yes,
> it's extremely annoying, but I have no choice.  The copy protection scheme
> used by the third-party library involves "branding" the executable, and
> their "branding" program won't touch either a shared object or a binary
> that doesn't have their library included.  I've already wasted several
days
> trying to find a way around it :(.

I have not ever done this (statically build an extension into Ruby). I know
that part of this procedure includes adding the directory name for the
extension to the ext/Setup file (under the Ruby source code tree) but maybe
someone else can provide more guidance.

> Oh yes, if it makes any difference, I'm running FreeBSD 4.5 and RedHat
7.1.

That shouldn't be a problem.

Hope this helps,

Lyle