|
From: Rob M. <rob...@vi...> - 2006-12-21 03:47:33
|
William S Fulton wrote:
> Rob McCready wrote:
>> Rob McCready wrote:
>>> David Beazley wrote:
>>>> On Dec 19, 2006, at 4:11 PM, Rob McCready wrote:
>>>>
>>>>> Hello,
>>>>>
>>>>> I am using SWIG with a fairly large C API that uses return codes on many
>>>>> functions the general structure is like this:
>>>>>
>>>>> typedef int api_result;
>>>>> const api_result success = 0;
>>>>> const api_result error_type_1 = {some value};
>>>>> const api_result error_type_2 = {some other value};
>>>>>
>>>>> api_result foo1(int bar);
>>>>> api_result foo2(double baz);
>>>>>
>>>>> ... and so on. I would like this to turn into something like this
>>>>> post-SWIG:
>>>>>
>>>>> void foo1_wrapper(int bar)
>>>>> {
>>>>> api_result result = foo1(bar);
>>>>> if(result)
>>>>> {
>>>>> throw_appropriate_exception(result);
>>>>> }
>>>>> }
>>>>>
>>>>> So I want to get rid of those return codes in the SWIG-generated
>>>>> interface and instead use them in the wrapper functions to generate
>>>>> exceptions. I can see how to do the latter part (generating exceptions
>>>>> from the return code), but is there any way to nuke the return codes
>>>>> from the SWIG interface? Obviously I could write a custom wrapper for
>>>>> each function that doesn't return the code, but that's way too much work.
>>>>>
>>>> You might try using something like
>>>>
>>>> %typemap(out) api_result = void;
>>>>
>>>> My memory is a little rusty so I hope the syntax for that is correct.
>>>> However, the general idea is to simply apply the rules that have been
>>>> written for void to the result. If that doesn't work, you could write a
>>>> typemap
>>>>
>>>> %typemap(out) api_result {
>>>>
>>>> }
>>>>
>>>> That simply discards the result. You'd have to supply the appropriate
>>>> code to return a NULL value to the target language.
>>> Unfortunately, neither of those actually changes the return type of the
>>> function in the target language. They let me munge the value returned by
>>> the native call, but they don't change
>>>
>>> api_result foo()
>>>
>>> to
>>>
>>> void foo() // throws exceptions
>>>
>>> It's looking to me like this is not possible (short of writing a custom
>>> helper function for each API function), and I'll have to just live with
>>> the return type.
>>>
>> Hmmmm...I just found one way to do this that is a huge kludge, but it
>> may end up working.
>>
>> I just change the following for SWIG processing:
>>
>> typedef void api_result; // should be int
>>
>> %feature("except") {
>> api_result result = $action
>> if(result) {
>> // ...take appropriate action
>> }
>> }
>>
>> This generates the following wrapper code for "api_result foo()":
>>
>> // in C#
>> public static void foo() {
>> DepictPINVOKE.foo();
>> }
>>
>> // in C
>> SWIGEXPORT void SWIGSTDCALL CSharp_foo() {
>> {
>> api_result result = foo();
>> if(result) {
>> // ...take appropriate action
>> }
>> }
>> {
>> return NULL;
>> }
>> }
>>
>> ...which is pretty much what I want. What would be really nice now would
>> be if I could do something like:
>>
>> %feature("except") api_result {
>> api_result result = $action
>> if(result) {
>> // ...take appropriate action
>> }
>> }
>>
>> ...so that the exception handler was only applied to functions that
>> return api_result. There doesn't seem to be any way to do that, but I
>> could manually rearrange the functions in the .i file so that only the
>> api_result functions use this handler.
>>
>
> Below contains the typemaps you need for api_result plus an example. The
> typemaps are really just a copy of the void typemaps from csharp.swg
> plus the mods you want in the out typemap.
>
> William
>
> /* File : example.i */
> %module example
>
> %typemap(ctype) api_result "void"
> %typemap(imtype) api_result "void"
> %typemap(cstype) api_result "void"
> %typemap(out, canthrow=1) api_result {
> if ($1) {
> char error_message[32];
> sprintf(error_message, "error: %d", $1);
> SWIG_CSharpSetPendingException(SWIG_CSharpApplicationException,
> error_message);
> return;
> }
> }
> %typemap(csout, excode=SWIGEXCODE) api_result {
> $imcall;$excode
> }
>
> // As api_result is now a void, the following can't wrapped as types
> // so just ignore.
> %ignore success;
> %ignore error_type_1;
> %ignore error_type_2;
>
> %inline %{
> typedef int api_result;
> const api_result success = 0;
> const api_result error_type_1 = 1;
> const api_result error_type_2 = 2;
>
> api_result foo1(int bar) { return success; }
> api_result foo2(double baz) { return error_type_1; }
> %}
Awesome! Worked like a charm. Thanks very much.
Rob
|