Version 0 of Tcl_Obj Deep Copy

Updated 2002-08-11 09:16:57

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.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);
      }
  }
  /* }}} */