/* 
   generic.c
   Non type specific functions.

   Datablk is a library that provides a "typeless" type for
   programmable systems.

   (C) Copyright 1998 by Nicholas Rusnov
*/

#include <stdlib.h>
#include <stdio.h>
#include <memory.h>

#include "flags.h"
#include "datablk.h"

/* free the Data fork of ablk in a sane way */
int dblk_nullify(Datablk *ablk)
{
  if (ablk)
    {
      switch (ablk->type) /* some types require special handling. */
	{
	case DBLK_T_ERR:
	  if (((DBLK_Err *)ablk->Data)->Message)
	    {
	      free(((DBLK_Err *)ablk->Data)->Message);
	    }
	  break;
	case DBLK_T_LIST:
	  dblk_nullify((Datablk *)ablk->Data);
	  break;
	default:
	}
#ifdef DBLK_DGR_PTR
      if (!flag_state(myblk->flags[1],DBLK_F_NPTR))
#endif
	free(ablk->Data);
      memset(ablk->flags,0,sizeof(flagset)*2);
      ablk->Data = 0;
      ablk->type = 0;
    }
}

/* Destroy a Datablk and all its children, contents and misc hangers on */
int dblk_destroy(Datablk *ablk)
{
  if (ablk)
    {
      dblk_nullify(ablk);
      if (ablk->tail) /* this takes care of agument lists and arrays */
	dblk_destroy(ablk->tail);	  
    }
  return;
}

/* Returns the type of ablk */
int dblk_typeof(const Datablk *ablk)
{
  if (ablk)
    return ablk->type;
  else
    return -1;
}



/* allocates a copy of an existing datablk
   (recursively copies the whole tree)
 */
Datablk *dblk_mkclone(const Datablk *ablk)
{
  Datablk *myblk = 0;
  if (ablk)
    {
      myblk = (Datablk *)malloc(sizeof(Datablk));
      memset(myblk,0,sizeof(Datablk));
      dblk_mkcopy(ablk, myblk);
    }
  return myblk;
}

/* does all the work of copying. */
int dblk_mkcopy(const Datablk *origblk, Datablk *ablk)
{
  double tmpnum;
  if (origblk)
    {
      if (ablk->Data)
	dblk_nullify(ablk);

      ablk->type = origblk->type;
      ablk->flags[0] = origblk->flags[0];
      ablk->flags[1] = origblk->flags[1];
      ablk->Data = origblk->Data;
      if (ablk->Data)
	{	
	  switch (ablk->type)
	    {
	    case DBLK_T_ERR:
	      DBLK_INIT_ERR(((DBLK_Err *)ablk->Data),((DBLK_Err *)origblk->Data)->Code,((DBLK_Err *)origblk->Data)->Message);
	      break;
	    case DBLK_T_OBJR:
	      DBLK_INIT_OBR(((DBLK_ObRef *)ablk->Data),((DBLK_ObRef *)origblk->Data)->Domain,((DBLK_ObRef *)origblk->Data)->Object);
	      break;
	    case DBLK_T_NUM: /* support the number packing system */
	      dblk_setnum(dblk_getnum(origblk),ablk);
	      break;
	    case DBLK_T_STR:
	      ablk->Data = (void *)malloc(strlen((char *)origblk->Data)+1);	  
	      strcpy((char *)ablk->Data,(char *)origblk->Data);
	      break;
	    case DBLK_T_OBJI: /* FIXME - impliment object instances */
	      break;	  
	    case DBLK_T_LIST: 
	      ablk->Data = (void *)dblk_mkclone((Datablk *)origblk->Data);
	      break;	  
	    }
	}
    }
  else
    return 0;
}

/* allocates a copy of an existing datablk (recursivly-follows tail)*/
Datablk *dblk_mkrclone(const Datablk *ablk)
{
  Datablk *myblk = 0;
  if (ablk)
    {
      myblk = (Datablk *)malloc(sizeof(Datablk));
      memset(myblk,0,sizeof(Datablk));
      dblk_mkrcopy(ablk, myblk);
    }
  return myblk;
}

int dblk_mkrcopy(const Datablk *origblk,Datablk *ablk)
{
  if (origblk)
    {
      dblk_mkcopy(origblk,ablk);

      if ((origblk->type == DBLK_T_LIST) && (origblk->Data))
	{
	  dblk_mkrcopy((const Datablk *)origblk->Data,(Datablk *)ablk->Data);
	}
      
      if (origblk->tail)
	{
	  ablk->tail = (void *)dblk_mkrclone((Datablk *)origblk->tail);
	}
    }
}

