Re: need a tiny help with my SWIG'd program



At Thu, 28 Feb 2008 18:55:10 +0200 Georgios Petasis <petasis@xxxxxxxxxxxxxxxxx> wrote:


O/H Georgios Petasis έγÏ?αÏ?ε:
O/H Mel έγÏ?αÏ?ε:
the C function i am calling requires a:
'char ** myvar"

what would I be passing as TCL var to this function ?

void junk(char **' myvar)

in tcl I would call something like:

junk <what should I put here>

many thanks for your help

It is not so easy :-)
char ** means an array of null terminated strings. There in nothing in
tcl that can be converted to this type. So, you have to add to your
header file some C code to generate such structures.

For example, in a similar situation I have added the following helper code:

#ifdef SWIG
%rename(String) array_string;
#endif
#if defined(ARRAY_STRING_CLASS)
class array_string {
char **array;
int _size;
public:
array_string(int size) {
_size=size;
array = (char **) Tcl_Alloc(sizeof(char*)*_size);
if (array) for(int i=0; i<_size;++i) array[i]=NULL;
}
void setitem(int i, char* value) {
if (!array || i < 0 || i >= _size) return;
if(array[i]) Tcl_Free(array[i]);
array[i]=Tcl_Alloc(sizeof(char)*(strlen(value)+2));
strcpy(array[i], value);
}
char *getitem(int i) {
if (!array || i<0 || i>=_size) return NULL;return array[i];
}
char** cast(void) {return array;}
~array_string() {
if (array) {
for(int i=0; i<_size; ++i) {
if (array[i]) Tcl_Free(array[i]);
}
Tcl_Free((char *)array);
}
}
};
#endif /* ARRAY_STRING_CLASS */

Them, from tcl you can do (assuming that you have enabled shadow classes):

String x 5
x setitem 0 "string 1"
x setitem 1 "string 2"
...
junk [x cast]
## delete x...
delete_String x

George


Of course, you could also try to convert a tcl list into this, but its
easier to do this from the tcl level than at the C level :-)
The ultimate solution will be to do tcl list -> char ** conversion as an
argument template, and just call your function with a tcl list as a
parameter. Perhaps there is some ready code if you search at google.

From my Model Railroad System (cmri.h):

#ifdef SWIG
/*
* Typemaps for handling the List class. This maps a Tcl list of
integers to
* a List class instance.
*/

%typedef List *ListP; // Help SWIG's pattern matching

/*
* Input method: convert a Tcl list (of integers) to a freshly allocated
List
* object.
*/

%typemap(tcl8,in) const List * {
Tcl_Obj **objvPtr;
int objcPtr,i;
if (Tcl_ListObjGetElements(interp,$input,&objcPtr,&objvPtr) !=
TCL_OK)
return(TCL_ERROR);
$1 = new List(objcPtr);
for (i = 0; i < objcPtr; i++) {
if (Tcl_GetIntFromObj(interp,objvPtr[i],&((*$1)[i])) !=
TCL_OK)
return(TCL_ERROR);
}
}

%typemap(tcl8,freearg) const List * {
delete $1;
}


/*
* Output (function result) method: convert the List object pointer to a
Tcl
* list. Free up the List object pointer. If the result was a NULL,
return
* an empty Tcl list.
*/

%typemap(tcl8,out) ListP {
int i, length;
if ($1 == NULL) length = 0;
else length = $1->Length();
Tcl_Obj * tcl_result = $result;
Tcl_SetListObj(tcl_result,0,NULL);
for (i = 0; i < length; i++) {
if
(Tcl_ListObjAppendElement(interp,tcl_result,Tcl_NewIntObj((*$1)[i])) !=
TCL_OK)
return TCL_ERROR;
}
if ($1 != NULL) delete $1;
}

#endif


#ifndef SWIG
/** @memo A C++ mapping for a Tcl list.
* @doc Re-sizable (manually only). Used to pass lists of integers
(such as
* port values) to and from the low-level code, where these values are
* encoded and decoded to/from the serial interface
* cards.
*/
class List {
public:
/** @memo Constructor.
* @doc Construct a vector of a specific number of elements.
* @param l The number of elements to allocate.
*/
List(int l=0);
/** @memo Destructor.
* @doc Free up memory.
*/
~List();
/** The Length() member function returns the length of the
vector.
*/
int Length() const {return length;}
/** Read/write indexing accessor. Returns a reference to the
* $i^{th}$ element.
* @param i The index to access.
*/
int & operator [](int i);
/** @memo Read only indexing accessor.
* @doc Returns the value of the $i^{th}$ element.
* @param i The index to access.
*/
int operator [](int i) const;
/** The Resize() member function re-sizes the vector. If the
vector
* is shortened, elements off the end are discarded.
* @param l The number of elements to allocate.
*/
void Resize(int l);
private:
/** Length of the allocated vector.
*/
int length;
/** Vector of elements.
*/
int *elements;
};

/** Pointer typedef.
*/
typedef List *ListP;
#endif

Note: this is for a list of integers, but the principle is the same. I
also have code doing something similar with C++ (STL) string vectors:

#include <string>
#include <vector>
typedef vector<string> stringVector;

/*
* Type map for stringVector: convert from a Tcl list on input.
*/

/*
* On input: allocate a stringVector and fill it from the input list argument.
*/
%typemap(tcl8,in) const stringVector * {
Tcl_Obj **objvPtr;
int objcPtr,i;
if (Tcl_ListObjGetElements(interp,$input,&objcPtr,&objvPtr) != TCL_OK)
return(TCL_ERROR);
$1 = new stringVector;
#ifdef DEBUG
cerr << "*** Passing list of " << objcPtr << " strings as a stringVector" << endl;
#endif
for (i = 0; i < objcPtr; i++) {
$1->push_back(string(Tcl_GetString(objvPtr[i])));
}
}

/*
* Free allocated space.
*/

%typemap(tcl8,freearg) const stringVector * {
delete $1;
}

%typemap(tcl8,in) const stringVector {
Tcl_Obj **objvPtr;
int objcPtr,i;
if (Tcl_ListObjGetElements(interp,$input,&objcPtr,&objvPtr) != TCL_OK)
return(TCL_ERROR);
#ifdef DEBUG
cerr << "*** Passing list of " << objcPtr << " strings as a doubleVector" << endl;
#endif
for (i = 0; i < objcPtr; i++) {
$1.push_back(string(Tcl_GetString(objvPtr[i])));
}
}

Again, the concept is straight forward and it should be easy to adapt to
a 'char **'.


George


--
Robert Heller -- Get the Deepwoods Software FireFox Toolbar!
Deepwoods Software -- Linux Installation and Administration
http://www.deepsoft.com/ -- Web Hosting, with CGI and Database
heller@xxxxxxxxxxxx -- Contract Programming: C/C++, Tcl/Tk

.



Relevant Pages

  • Re: Obstacles for Tcl/Tk commercial application development ?
    ... Whenever there was a problem in a Tcl program, it was not related to the type system and would have occurred in any static language as well - but eventually much worse. ... "Simple typos" will come back to you as soon as you run your procedure the first time for testing. ... int fun { ...
    (comp.lang.tcl)
  • Re: Best way to pass c++ pointer to tcl
    ... straightforward with simple types like int, long, etc., but I do not ... Creating and Using Tcl Handles in C Extensions: ... So my Ext_Init allocates a struct like: ... The performance with this method is superior to a hash table, ...
    (comp.lang.tcl)
  • history access via tcls C API?
    ... The access to the tcl command history is only possible by using tcl ... And the history command does not return normal tcl values, like lists, ... int Tcl_HistoryAddEventObj ...
    (comp.lang.tcl)
  • embed Tcl and Tk into existing C code
    ... I began from embedding Tcl by trying out the following code in MS ... main (int argc, char *argv) ... from the successful compilation of the original tcl distribution) ... here are the compilation & linking options ...
    (comp.lang.tcl)
  • Re: need a tiny help with my SWIGd program
    ... what would I be passing as TCL var to this function? ... junk ... char ** means an array of null terminated strings. ... x setitem 0 "string 1" ...
    (comp.lang.tcl)