user597225
user597225

Reputation:

How to create a TCL function with optional arguments using SWIG?

I have a simple c/c++ app that has an optional TCL interpreter with the function wrappers generated using SWIG. For several of the functions all the arguments are optional. How is this typically handled? I'd like to support a TCL command like this, where any of the arguments are optional but the C function takes fixed arguments:

 //TCL command
 get_list [options] filename
   -opt1
   -opt2
   -opt3 arg1 
   -opt4 arg2
   filename

//C function
static signed get_list(bool         opt1,
                       bool         opt2,
                       char       * arg1,
                       objectType * arg2,
                       char       * fileName)

Currently I have something like this:

static pList * get_list(char    * arg1=NULL,
                        char    * arg2=NULL, 
                        char    * arg3=NULL,  
                        tObject * arg4=NULL)

This has many problems such as enforcing the object pointer is always the last argument. The SWIG documentation talks at length about C functions with variable arguments using "..." but I don't think this is what I need. I'd like the C function arguments to be fixed.

Upvotes: 2

Views: 912

Answers (1)

Donal Fellows
Donal Fellows

Reputation: 137687

The easiest method is to wrap a Tcl procedure around the outside, like this:

rename get_list original.get_list
proc get_list args {
    if {[llength $args] == 0 || [llength $args] % 2 == 0} {
        error "wrong # args: ...";   # Do a proper error message here!
    }
    # Handle the required argument
    set filename [lindex $args end]
    # Initialize the defaults
    array set opts {
        -opt1 false
        -opt2 false
        -opt3 ""
        -opt4 ""
    }
    # Merge in the supplied options
    foreach {opt val} [lrange $args 0 end-1] {
        if {![info exist opts($opt)]} {
            error "unrecognized option \"$opt\""
        }
        set opts($opt) $value
    }
    # Hand off to C level...
    original.get_list $opts(-opt1) $opts(-opt2) $opts(-opt3) $opts(-opt4) $filename
}

If you've got Tcl 8.6, that last handoff is best done with tailcall so the rewriting code is cut out of the Tcl stack. It's not vital though, as SWIGged code rarely resolves names of Tcl commands and variables.

Upvotes: 2

Related Questions