/*
 * fconv.c -- abs, cset, integer, numeric, proc, real, string.
 */

#include "..\h\config.h"
#include "..\h\rt.h"
#include "rproto.h"


/*
 * abs(x) - absolute value of x.
 */
FncDcl(abs,1)
   {
   switch (cvnum(&Arg1)) {
      /*
       * If Arg1 is convertible to a numeric, turn Arg0 into
       *  a descriptor for the appropriate type and value.  If the
       *  conversion fails, produce an error.  This code assumes that
       *  n = -n is always valid, which is not necessarily correct.
       */
      case T_Integer:
         MakeInt(Abs(IntVal(Arg1)), &Arg0);
         break;

      case T_Real:
         makereal(BlkLoc(Arg1)->realblk.realval, &Arg0);
         if (BlkLoc(Arg0)->realblk.realval < 0.0)
            BlkLoc(Arg0)->realblk.realval = -BlkLoc(Arg0)->realblk.realval;
         break;

#ifdef LargeInts
     case T_Bignum:
	 cpbignum(&Arg1, &Arg0);
	 BlkLoc(Arg0)->bignumblk.sign = 0;
	 break;
#endif					/* LargeInts */

      default:
         RunErr(102, &Arg1);
      }
   Return;
   }


/*
 * cset(x) - convert x to cset.
 */

FncDcl(cset,1)
   {
   register int i;
   register struct b_cset *bp;
   int *cs, csbuf[CsetSize];

   if (blkreq((word)sizeof(struct b_cset)) == Error) 
      RunErr(0, NULL);

   if (Arg1.dword == D_Cset)
      /*
       * Arg1 already a cset, just return it.
       */
      Arg0 = Arg1;
   else if (cvcset(&Arg1, &cs, csbuf) != CvtFail) {
      /*
       * Arg1 was convertible to cset and the result resides in csbuf.
       *  Allocate *  a cset, make Arg0 a descriptor for it and copy the
       *  bits from csbuf into it.
       */
      Arg0.dword = D_Cset;
      bp = alccset();
      BlkLoc(Arg0) =  (union block *) bp;
      for (i = 0; i < CsetSize; i++)
         bp->bits[i] = cs[i];
      }
   else			/* Not a cset nor convertible to one. */
      Fail;
   Return;
   }


/*
 * integer(x) - convert x to integer.
 */

FncDcl(integer,1)
   {

#ifdef LargeInts
   switch (cvnum(&Arg1)) {

      case T_Integer:
      case T_Bignum:
	 Arg0 = Arg1;
	 break;

      case T_Real:
	 if (realtobig(&Arg1, &Arg0) == Error)  /* alcbignum failed */
	    RunErr(0, NULL);
	 break;
#else					/* LargeInts */
   switch (cvint(&Arg1)) {

      case T_Integer:
         Arg0 = Arg1;
         break;
#endif					/* LargeInts */

      default:
         Fail;
      }
   Return;
   }

/*
 * numeric(x) - convert x to numeric type.
 */
FncDcl(numeric,1)
   {
   switch (cvnum(&Arg1)) {

      case T_Integer:

#ifdef LargeInts
      case T_Bignum:
#endif					/* LargeInts */

      case T_Real:
	 Arg0 = Arg1;
         break;

      default:
         Fail;
      }
   Return;
   }


/*
 * proc(x,i) - convert x to a procedure if possible; use i to
 *  resolve ambiguous string names.
 */
FncDcl(proc,2)
   {
   char sbuf[MaxCvtLen];
   long i;
   
   /*
    * If Arg1 is already a proc, just return it in Arg0.
    */
   Arg0 = Arg1;
   if (Arg0.dword == D_Proc)
      Return;
   if (cvstr(&Arg0, sbuf) == CvtFail)
      Fail;
   /*
    * Arg2 defaults to 1.
    */
   if (defshort(&Arg2, 1) == Error) 
      RunErr(0, NULL);

   i = IntVal(Arg2);

   if (i < 1 || i > 3)
      RunErr(205, &Arg2);

   /*
    * Attempt to convert Arg0 to a procedure descriptor using args to
    *  discriminate between procedures with the same names.  Fail if
    *  the conversion isn't successful.
    */
   if (strprc(&Arg0,i) == CvtFail)
      Fail;

   Return;
   }


/*
 * real(x) - convert x to real.
 */

FncDcl(real,1)
   {
   /*
    * If Arg1 is already a real, just return it.  Otherwise convert it and
    *  return it, failing if the conversion is unsuccessful.
    */
   if (Arg1.dword == D_Real)
      Arg0 = Arg1;
   else if (cvreal(&Arg1) == T_Real)
      Arg0 = Arg1;
   else
      Fail;
   Return;
   }

/*
 * string(x) - convert x to string.
 */

FncDcl(string,1)
   {
   char sbuf[MaxCvtLen];

   Arg0 = Arg1;
   switch (cvstr(&Arg0, sbuf)) {

      /*
       * If Arg1 is not a string, allocate it and return it; if it is a
       *  string, just return it; fail otherwise.
       */
      case Cvt:
	 /*
          * Allocate converted string
          */
         if (strreq(StrLen(Arg0)) == Error) 
            RunErr(0, NULL);
         StrLoc(Arg0) = alcstr(StrLoc(Arg0), StrLen(Arg0));

      case NoCvt:
         Return;

      default:
         Fail;
      }
   }
