Version 1 of Tcl_Obj Deep Copy

Updated 2002-08-11 09:20:09

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:

   *list (including sublists)
   *int/long/double

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;
        unsigned long size;
        int strlen;
        char *str;
        str=Tcl_GetStringFromObj(to,&strlen);
        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;
        if (rc=(struct dcIntObj *) dc_Malloc(sizeof(struct dcIntObj)))
        {
            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;
        if (rc=(struct dcLongObj *) dc_Malloc(sizeof(struct dcLongObj)))
        {
            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;
        if (rc=(struct dcDoubleObj *) dc_Malloc(sizeof(struct dcDoubleObj)))
        {
            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 *);
        if (rc=(struct dcListObj *) dc_Malloc(size))
        {
            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;
            if ((tbl=dc_Malloc(llen*sizeof(Tcl_Obj *)))!=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);
        }
    }