blob: b087f36c6b6698d96e41c069425f5a7c9b8ab29c [file] [log] [blame]
/* object.swg
*
* Tcl8.x - Object oriented runtime functions
*/
typedef int (*swig_wrapper)(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST []);
typedef struct swig_method {
const char *name;
swig_wrapper method;
} swig_method;
typedef struct swig_attribute {
const char *name;
swig_wrapper getmethod;
swig_wrapper setmethod;
} swig_attribute;
typedef struct swig_class {
const char *name;
swig_type_info **type;
swig_wrapper constructor;
void (*destructor)(void *);
swig_method *methods;
swig_attribute *attributes;
} swig_class;
typedef struct swig_instance {
Tcl_Obj *thisptr;
void *thisvalue;
swig_class *classptr;
int destroy;
} swig_instance;
static void SwigObjectDelete(ClientData clientData) {
swig_instance *si = (swig_instance *) clientData;
if (si->destroy) {
if (si->classptr->destructor) {
(si->classptr->destructor)(si->thisvalue);
}
}
Tcl_DecrRefCount(si->thisptr);
free(si);
}
/* Function to invoke object methods given an instance */
static int
SwigMethodCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST _objv[])
{
char *method, *attrname;
swig_instance *inst = (swig_instance *) clientData;
swig_method *meth;
swig_attribute *attr;
Tcl_Obj *oldarg;
Tcl_Obj **objv;
int rcode;
objv = (Tcl_Obj **) _objv;
if (objc < 2) {
Tcl_SetResult(interp, (char *) "wrong # args.", TCL_STATIC);
return TCL_ERROR;
}
meth = inst->classptr->methods;
method = Tcl_GetStringFromObj(objv[1],NULL);
/* Check for methods */
while (meth && meth->name) {
if (strcmp(meth->name,method) == 0) {
oldarg = objv[1];
objv[1] = inst->thisptr;
Tcl_IncrRefCount(inst->thisptr);
rcode = (*meth->method)(clientData,interp,objc,objv);
objv[1] = oldarg;
Tcl_DecrRefCount(inst->thisptr);
return rcode;
}
meth++;
}
/* Check class methods for a match */
if (strcmp(method,"cget") == 0) {
if (objc < 3) {
Tcl_SetResult(interp, (char *) "wrong # args.", TCL_STATIC);
return TCL_ERROR;
}
attrname = Tcl_GetStringFromObj(objv[2],NULL);
attr = inst->classptr->attributes;
while (attr && attr->name) {
if ((strcmp(attr->name, attrname) == 0) && (attr->getmethod)) {
oldarg = objv[1];
objv[1] = inst->thisptr;
Tcl_IncrRefCount(inst->thisptr);
rcode = (*attr->getmethod)(clientData,interp,2, objv);
objv[1] = oldarg;
Tcl_DecrRefCount(inst->thisptr);
return rcode;
}
attr++;
}
if (strcmp(attrname, "-this") == 0) {
Tcl_SetObjResult(interp, Tcl_DuplicateObj(inst->thisptr));
return TCL_OK;
}
Tcl_SetResult(interp, (char *) "Invalid attribute.", TCL_STATIC);
return TCL_ERROR;
} else if (strcmp(method, "configure") == 0) {
int i;
if (objc < 4) {
Tcl_SetResult(interp, (char *) "wrong # args.", TCL_STATIC);
return TCL_ERROR;
}
i = 2;
while (i < objc) {
attrname = Tcl_GetStringFromObj(objv[i],NULL);
attr = inst->classptr->attributes;
while (attr && attr->name) {
if ((strcmp(attr->name, attrname) == 0) && (attr->setmethod)) {
oldarg = objv[i];
objv[i] = inst->thisptr;
Tcl_IncrRefCount(inst->thisptr);
rcode = (*attr->setmethod)(clientData,interp,3, &objv[i-1]);
objv[i] = oldarg;
Tcl_DecrRefCount(inst->thisptr);
if (rcode != TCL_OK) return rcode;
i+=2;
break;
}
attr++;
}
if (inst->classptr->attributes && !(attr->name)) {
Tcl_SetResult(interp, (char *) "Invalid attribute name.", TCL_STATIC);
return TCL_ERROR;
}
}
return TCL_OK;
} else {
Tcl_SetResult(interp, (char *) "Invalid method. Must be one of: configure cget ", TCL_STATIC);
meth = inst->classptr->methods;
while (meth && meth->name) {
Tcl_AppendElement(interp, (char *) meth->name);
meth++;
}
return TCL_ERROR;
}
}
/* Function to create objects */
static int
SwigObjectCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
{
Tcl_Obj *newObj = 0;
void *thisvalue = 0;
swig_instance *newinst = 0;
swig_class *classptr = (swig_class *) clientData;
swig_wrapper cons = 0;
char *name = 0;
int firstarg = 0;
int thisarg = 0;
int destroy = 1;
Tcl_CmdInfo ci;
if (!classptr) {
Tcl_SetResult(interp, (char *) "swig: internal runtime error. No class object defined.", TCL_STATIC);
return TCL_ERROR;
}
cons = classptr->constructor;
if (objc > 1) {
char *s = Tcl_GetStringFromObj(objv[1],NULL);
if (strcmp(s,"-this") == 0) {
thisarg = 2;
cons = 0;
} else if (strcmp(s,"-args") == 0) {
firstarg = 1;
} else if (objc == 2) {
firstarg = 1;
name = s;
} else if (objc >= 3) {
char *s1;
name = s;
s1 = Tcl_GetStringFromObj(objv[2],NULL);
if (strcmp(s1,"-this") == 0) {
thisarg = 3;
cons = 0;
} else {
firstarg = 1;
}
}
}
if (cons) {
int result;
result = (*cons)(0, interp, objc-firstarg, &objv[firstarg]);
if (result != TCL_OK) {
return result;
}
newObj = Tcl_DuplicateObj(Tcl_GetObjResult(interp));
if (!name) name = Tcl_GetStringFromObj(newObj,NULL);
} else if (thisarg > 0) {
if (thisarg < objc) {
destroy = 0;
newObj = Tcl_DuplicateObj(objv[thisarg]);
if (!name) name = Tcl_GetStringFromObj(newObj,NULL);
} else {
Tcl_SetResult(interp, (char *) "wrong # args.", TCL_STATIC);
return TCL_ERROR;
}
} else {
Tcl_SetResult(interp, (char *) "No constructor available.", TCL_STATIC);
return TCL_ERROR;
}
if (!Tcl_GetCommandInfo(interp,name,&ci)) {
if (SWIG_ConvertPtr(interp,newObj, (void **) &thisvalue, *(classptr->type)) == TCL_ERROR) {
Tcl_DecrRefCount(newObj);
return TCL_ERROR;
}
newinst = (swig_instance *) malloc(sizeof(swig_instance));
newinst->thisptr = newObj;
Tcl_IncrRefCount(newObj);
newinst->thisvalue = thisvalue;
newinst->classptr = classptr;
newinst->destroy = destroy;
Tcl_CreateObjCommand(interp,name, SwigMethodCmd, (ClientData) newinst, SwigObjectDelete);
return TCL_OK;
} else {
Tcl_SetResult(interp, (char *) "Object name already exists!", TCL_STATIC);
return TCL_ERROR;
}
}