/* 
   numbers.c
   Numeric subtypes and trickery

   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 <limits.h>
#include <math.h>

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

/* FIXME - right now, set only supports packing to ints, longs, and doubles.. */

/* mk, get and set a number with Datablk */
Datablk *dblk_mknum(const double anum)
{
  Datablk *myblk;
  DBLK_INIT(myblk,DBLK_T_NUM);
  dblk_setnum(anum,myblk);
  return myblk;
}

double dblk_getnum(const Datablk *ablk)
{
  double mynum;

  mynum = 0;
  /* FIXME - add senseable type conversion */
  if (ablk && (ablk->type == DBLK_T_NUM) && ablk->Data)
    {
#ifdef DBLK_DGR_PTR
     if (flag_state(ablk->flags[1],DBLK_F_NPTR))
       if (flag_state(ablk->flags[0],DBLK_F_INT))
	 mynum = (int)(ablk->Data);
       else if (flag_state(ablk->flags[0],DBLK_F_FLO))
	 mynum = (float)(ablk->Data);
     return mynum;
#endif
     if (flag_state(ablk->flags[0],DBLK_F_INT))
       mynum = *(int *)(ablk->Data);
     else if (flag_state(ablk->flags[0],DBLK_F_SHT))
       mynum = *(short *)(ablk->Data);
     else if (flag_state(ablk->flags[0],DBLK_F_CHR))
       mynum = *(char *)(ablk->Data);
     else if (flag_state(ablk->flags[0],DBLK_F_LON))
       mynum = *(long *)(ablk->Data);
     else if (flag_state(ablk->flags[0],DBLK_F_FLO))
       mynum = *(float *)(ablk->Data);
     else if (flag_state(ablk->flags[0],DBLK_F_DBL))
       mynum = *(double *)(ablk->Data);
   }
  return mynum;
}

int dblk_setnum(const double anum, Datablk *ablk)
{
  if (ablk)
    {
      if (ablk->Data)
	dblk_nullify(ablk);

      ablk->type = DBLK_T_NUM;
      /* if dangerous pointer conversion is eanbled, we use
	 this storage method by default for <int.
      */
      if (floor(anum) != anum)
	{
	  /* floating point */
	  /* FIXME - only doubles are supported! */
	      ablk->flags[0] = flag_set(ablk->flags[0],DBLK_F_DBL);
	      ablk->Data = (void *)malloc(sizeof(double));
 	      *(double *)ablk->Data = anum;
	}
      else
	{
	  /* integer */
	  if ((anum <= INT_MAX) && (anum >= INT_MIN))
	    {
	      ablk->flags[0] = flag_set(ablk->flags[0],DBLK_F_INT);
#ifdef DBLK_DGRPTR
	      ablk->Data = anum;
	      ablk->flags[1] = flag_set(ablk->flags[1],DBLK_F_NPTR);
#else
	      ablk->Data = (void *)malloc(sizeof(int));
	      *(int *)ablk->Data = anum;
#endif
	    }
	  else
	    {
	      /* LONG */
	      ablk->flags[0] = flag_set(ablk->flags[0],DBLK_F_LON);
	      ablk->Data = (void *)malloc(sizeof(long));
	      *(long *)ablk->Data = anum;	      
	    }
	}
    }
}





