Here's my code which shows how to (in short) do a deep copy of a Tcl_Obj structure from C.
It stores any unknown type as string and the following in internal represenatation:
Here's the main code:
[deepcopy.h]
#ifndef DEEPCOPY_H #define DEEPCOPY_H 1 #include <tcl.h> void *Dc_GetTclObj(Tcl_Obj *obj); Tcl_Obj *Dc_NewTclObj(void *ptr); void Dc_FreeDcObj(void *ptr); unsigned long Dc_ObjSize(void *ptr); #endif
[deepcopyInt.h]
#ifndef DEEPCOPYINT_H #define DEEPCOPYINT_H 1 #define DCO_STRING 1 #define DCO_INTEGER 2 #define DCO_LONG 3 #define DCO_DOUBLE 4 #define DCO_LIST 5 #ifdef AOLSERVER #define dc_Malloc Ns_Alloc #define dc_Free Ns_Free #else #define dc_Malloc Tcl_Alloc #define dc_Free Tcl_Free #endif /* objhead */ struct dcObjHead { short type; unsigned long size; // including dcObjHead }; /* int object */ struct dcIntObj { struct dcObjHead head; int value; }; static struct dcObjHead *int_GetTclObj(Tcl_Obj *to); Tcl_Obj *int_NewTclObj(struct dcObjHead *o); static void int_Free(struct dcObjHead *o); /* long object */ struct dcLongObj { struct dcObjHead head; long value; }; static struct dcObjHead *long_GetTclObj(Tcl_Obj *to); Tcl_Obj *long_NewTclObj(struct dcObjHead *o); static void long_Free(struct dcObjHead *o); /* double object */ struct dcDoubleObj { struct dcObjHead head; double value; }; static struct dcObjHead *double_GetTclObj(Tcl_Obj *to); Tcl_Obj *double_NewTclObj(struct dcObjHead *o); static void double_Free(struct dcObjHead *o); /* string object */ struct dcStrObj { struct dcObjHead head; char string[1]; }; static struct dcObjHead *str_GetTclObj(Tcl_Obj *to); Tcl_Obj *str_NewTclObj(struct dcObjHead *o); static void str_Free(struct dcObjHead *o); /* list object */ struct dcListObj { struct dcObjHead head; int nelem; struct dcObjHead *list[1]; }; static struct dcObjHead *list_GetTclObj(Tcl_Obj *to); Tcl_Obj *list_NewTclObj(struct dcObjHead *o); static void list_Free(struct dcObjHead *o); #endif
[deepcopy.c]
#include <tcl.h> #include <deepcopy.h> #include <deepcopyInt.h> /* external API */ void *Dc_GetTclObj(Tcl_Obj *obj) { void *rc; char *otype = ""; if (obj->typePtr!=NULL) { otype = obj->typePtr->name; } if (!strcmp(otype,"int")) { rc = int_GetTclObj(obj); } else if (!strcmp(otype,"long")) { rc = long_GetTclObj(obj); } else if (!strcmp(otype,"double")) { rc = double_GetTclObj(obj); } else if (!strcmp(otype,"list")) { rc = list_GetTclObj(obj); } else { rc = str_GetTclObj(obj); } return rc; } Tcl_Obj *Dc_NewTclObj(void *ptr) { struct dcObjHead *oh = ptr; Tcl_Obj *rc = NULL; switch (oh->type) { case DCO_STRING: rc = str_NewTclObj(ptr); break; case DCO_LIST: rc = list_NewTclObj(ptr); break; case DCO_INTEGER: rc = int_NewTclObj(ptr); break; case DCO_DOUBLE: rc = double_NewTclObj(ptr); break; case DCO_LONG: rc = long_NewTclObj(ptr); break; } return rc; } void Dc_FreeDcObj(void *ptr) { struct dcObjHead *oh = ptr; switch (oh->type) { case DCO_STRING: str_Free(ptr); break; case DCO_LIST: list_Free(ptr); break; case DCO_INTEGER: int_Free(ptr); break; case DCO_LONG: long_Free(ptr); break; case DCO_DOUBLE: double_Free(ptr); break; } } unsigned long Dc_ObjSize(void *ptr) { struct dcObjHead *oh = ptr; return oh->size; } /* internal type representations */ static struct dcObjHead *str_GetTclObj(Tcl_Obj *to) { struct dcStrObj *rc; int strlen; char *str = Tcl_GetStringFromObj(to, &strlen); unsigned long size = strlen+1+sizeof(struct dcObjHead); if (rc=(struct dcStrObj *) dc_Malloc(size)) { memcpy(rc->string, str, strlen); rc->string[strlen] = '\0'; rc->head.type = DCO_STRING; rc->head.size = size; } return ((struct dcObjHead *) rc); } Tcl_Obj *str_NewTclObj(struct dcObjHead *o) { struct dcStrObj *so = (struct dcStrObj *) o; Tcl_Obj *rc = NULL; if (o->type==DCO_STRING) { rc = Tcl_NewStringObj(so->string, o->size-sizeof(struct dcObjHead)-1); } return rc; } static void str_Free(struct dcObjHead *o) { if (o->type==DCO_STRING) { dc_Free(o); } } static struct dcObjHead *int_GetTclObj(Tcl_Obj *to) { struct dcIntObj *rc = (struct dcIntObj *) dc_Malloc(sizeof(struct dcIntObj)); if (rc != NULL) { Tcl_GetIntFromObj(NULL, to, &rc->value); rc->head.type = DCO_INTEGER; rc->head.size = sizeof(struct dcIntObj); } return ((struct dcObjHead *) rc); } Tcl_Obj *int_NewTclObj(struct dcObjHead *o) { struct dcIntObj *so = (struct dcIntObj *) o; Tcl_Obj *rc = NULL; if (o->type==DCO_INTEGER) { rc = Tcl_NewIntObj(so->value); } return rc; } static void int_Free(struct dcObjHead *o) { if (o->type==DCO_INTEGER) { dc_Free((void *) o); } } static struct dcObjHead *long_GetTclObj(Tcl_Obj *to) { struct dcLongObj *rc = (struct dcLongObj *) dc_Malloc(sizeof(struct dcLongObj)); if (rc != NULL) { Tcl_GetLongFromObj(NULL, to, &rc->value); rc->head.type = DCO_LONG; rc->head.size = sizeof(struct dcLongObj); } return ((struct dcObjHead *) rc); } Tcl_Obj *long_NewTclObj(struct dcObjHead *o) { struct dcLongObj *so = (struct dcLongObj *) o; Tcl_Obj *rc = NULL; if (o->type==DCO_LONG) { rc = Tcl_NewLongObj(so->value); } return rc; } static void long_Free(struct dcObjHead *o) { if (o->type==DCO_LONG) { dc_Free((void *) o); } } static struct dcObjHead *double_GetTclObj(Tcl_Obj *to) { struct dcDoubleObj *rc = (struct dcDoubleObj *) dc_Malloc(sizeof(struct dcDoubleObj)); if (rc != NULL) { Tcl_GetDoubleFromObj(NULL, to, &rc->value); rc->head.type = DCO_DOUBLE; rc->head.size = sizeof(struct dcDoubleObj); } return ((struct dcObjHead *) rc); } Tcl_Obj *double_NewTclObj(struct dcObjHead *o) { struct dcDoubleObj *so = (struct dcDoubleObj *) o; Tcl_Obj *rc = NULL; if (o->type==DCO_DOUBLE) { rc = Tcl_NewDoubleObj(so->value); } return rc; } static void double_Free(struct dcObjHead *o) { if (o->type==DCO_DOUBLE) { dc_Free((void *) o); } } static struct dcObjHead *list_GetTclObj(Tcl_Obj *to) { Tcl_Obj *elem; struct dcListObj *rc; int size, llen, i; if (Tcl_ListObjLength(NULL,to,&llen) != TCL_OK) return NULL; size = sizeof(struct dcListObj)+(llen-1)*sizeof(struct dcListObj *); rc = (struct dcListObj *) dc_Malloc(size); if (rc != NULL) { rc->head.type = DCO_LIST; rc->nelem = llen; for (i=0 ; i<llen ; i++) { if (Tcl_ListObjIndex(NULL,to,i,&elem)!=TCL_OK) { rc->list[i] = NULL; } else { rc->list[i] = Dc_GetTclObj(elem); size += rc->list[i]->size; } } rc->head.size = size; } return ((struct dcObjHead *) rc); } Tcl_Obj *list_NewTclObj(struct dcObjHead *o) { struct dcListObj *so = (struct dcListObj *) o; Tcl_Obj *rc = NULL, **tbl; int llen,i; if (o->type==DCO_LIST) { llen = so->nelem; tbl = dc_Malloc(llen*sizeof(Tcl_Obj *)); if (tbl!=NULL) { for (i=0 ; i<llen ; i++) { tbl[i] = Dc_NewTclObj(so->list[i]); } rc = Tcl_NewListObj(llen,tbl); dc_Free(tbl); } } return rc; } static void list_Free(struct dcObjHead *o) { struct dcListObj *so = o; int i; if (o->type==DCO_LIST) { for (i=0 ; i<so->nelem ; i++) { Dc_FreeDcObj(so->list[i]); } dc_Free((void *) o); } }