/*******************************************/
/*                                         */
/*  File: tlfroms.c                        */
/*  Purpose: Format convering routines     */
/*                                         */
/*  Author: Sfiligoi Igor                  */
/*                                         */
/*  Last modified: 03.04.1996              */
/*                                         */
/*******************************************/

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include "tlforms.h"

#define EOS	'\0'

#define pow10(nrreal)	pow(10.0,nrreal)

#ifndef M_LN2
#define M_LN2	0.69314718055994530942
#endif

#ifndef M_LN8
#define M_LN8	2.0794415416798357
#endif

#ifndef M_LN16
#define M_LN16	2.7725887222397811
#endif

#ifndef M_LN64
#define M_LN64	4.1588830833596715
#endif


#define log2(nrreal)	(log(nrreal)/M_LN2)
#define log8(nrreal)	(log(nrreal)/M_LN8)
#define log16(nrreal)	(log(nrreal)/M_LN16)
#define log64(nrreal)	(log(nrreal)/M_LN64)

/*************************************************************************/
/*                          String to number                             */
/*************************************************************************/

/*************************** Natural numbers *****************************/

/* convert nat string in natural number */
/* must be in normal format */
/* returns TLF_OK iff no error */

int str2normnat(char *strnat,
                unsigned int *nrnat)
{
 unsigned int inat = 0;	/* internal nat */
 unsigned int i;

 if (strnat[0]==EOS)
	return TLF_EMPTY;	/* empty string not allowed */

 for (i=0; strnat[i]!=EOS; i++)
	{
	 if ((strnat[i]>='0') && (strnat[i]<='9'))
		inat = inat*10+(strnat[i]-'0');
	 else
		return TLF_ERROR;
	}
 *nrnat = inat;
 return TLF_OK;
}

/* convert nat string in natural number */
/* must be in binary format 0b format*/
/* returns TLF_OK iff no error */

int str2binary(char *strnat,
               unsigned int *nrnat)
{
 unsigned int inat = 0;	/* internal nat */
 unsigned int i;

 if (strnat[0]==EOS)
	return TLF_EMPTY;	/* empty string not allowed */

 for (i=0; strnat[i]!=EOS; i++)
	{
	 if ((strnat[i]>='0') && (strnat[i]<='1'))
		inat = inat*2+(strnat[i]-'0');
	 else
		return TLF_ERROR;
	}
 *nrnat = inat;
 return TLF_OK;
}

/* convert nat string in natural number */
/* must be in octal format 0o format*/
/* returns TLF_OK iff no error */

int str2octal(char *strnat,
              unsigned int *nrnat)
{
 unsigned int inat = 0;	/* internal nat */
 unsigned int i;

 if (strnat[0]==EOS)
	return TLF_EMPTY;	/* empty string not allowed */

 for (i=0; strnat[i]!=EOS; i++)
	{
	 if ((strnat[i]>='0') && (strnat[i]<='7'))
		inat = inat*8+(strnat[i]-'0');
	 else
		return TLF_ERROR;
	}
 *nrnat = inat;
 return TLF_OK;
}

/* convert nat string in natural number */
/* must be in hex format no 0x format*/
/* returns TLF_OK iff no error */

int str2hex(char *strnat,
            unsigned int *nrnat)
{
 unsigned int inat = 0;	/* internal nat */
 unsigned int i;

 if (strnat[0]==EOS)
	return TLF_EMPTY;	/* empty string not allowed */

 for (i=0; strnat[i]!=EOS; i++)
	{
	 if ((strnat[i]>='0') && (strnat[i]<='9'))
		inat = inat*16+(strnat[i]-'0');
	 else if ((strnat[i]>='a') && (strnat[i]<='f'))
			inat = inat*16+(10+strnat[i]-'a');
		 else if ((strnat[i]>='A') && (strnat[i]<='F'))
				inat = inat*16+(10+strnat[i]-'A');
			 else
				return TLF_ERROR;
	}
 *nrnat = inat;
 return TLF_OK;
}

/* convert nat string in natural number */
/* must be in compact format, no 0c prefix */
/* returns TLF_OK iff no error */

int str2compact(char *strnat,
                unsigned int *nrnat)
{
 unsigned int inat = 0;	/* internal nat */
 unsigned int i;

 if (strnat[0]==EOS)
	return TLF_EMPTY;	/* empty string not allowed */

 for (i=0; strnat[i]!=EOS; i++)
	{
	 if ((strnat[i]>='0') && (strnat[i]<='9'))
		inat = inat*64+(strnat[i]-'0');
	 else if ((strnat[i]>='a') && (strnat[i]<='z'))
			inat = inat*64+(10+strnat[i]-'a');
		 else if ((strnat[i]>='A') && (strnat[i]<='Z'))
				inat = inat*64+(36+strnat[i]-'A');
			 else if (strnat[i]>='_')
					inat = inat*64+62;
				 else if (strnat[i]>='^')
						inat = inat*64+63;
					 else
						return TLF_ERROR;
	}
 *nrnat = inat;
 return TLF_OK;
}

/* convert nat string in natural number */
/* returns TLF_OK iff no error */

int str2nat(char *strnat,
            unsigned int *nrnat)
{
 if (strnat[0]==EOS)
	return TLF_EMPTY;	/* empty string not allowed */

 if (strnat[0]=='0')
	{ /* verify if a special format */
	 switch (strnat[1])
	 {
	  case EOS:	/* '0' => return 0 */
		*nrnat = 0;
		return TLF_OK;
		break;
	  case 'c':
	  case 'C':	/* compact format */
		return str2compact((strnat+2),nrnat);
		break;
	  case 'x':
	  case 'X':	/* hex format */
		return str2hex((strnat+2),nrnat);
		break;
	  case 'o':
	  case 'O':	/* octal format */
		return str2octal((strnat+2),nrnat);
		break;
	  case 'b':
	  case 'B':	/* binary format */
		return str2binary((strnat+2),nrnat);
		break;
	  default:	/* must be normal format */
		return str2normnat(strnat+1,nrnat);
		break;
	 }
	}
 else
	{ /* must be normal format */
	 return str2normnat(strnat,nrnat);
	}

 return TLF_ERROR;		/* this is only symbolic */
}

/*************************** Integer numbers *****************************/

/* convert integer string in integer number */
/* returns TLF_OK iff no error */ 

int str2integer(char *strint,
                int *nrinteger)
{
 unsigned int inat;
 int result;

 switch (strint[0])
 {
  case '-':
	result = str2nat((strint+1),&inat);
	if (result==TLF_OK)
		*nrinteger = -inat;
	break;
  case '+':
	result = str2nat((strint+1),&inat);
	if (result==TLF_OK)
		*nrinteger = inat;
	break;
  default:
	result = str2nat(strint,&inat);
	if (result==TLF_OK)
		*nrinteger = inat;
	break;
 }

 return result;
}

/***************************** Real numbers ******************************/

/* convert unsigned real string in unsigned real number */
/* in binary real format, no 0f... */
/* returns TLF_OK iff no error */

int str2bureal(char *strureal,
               double *nrureal)
{
 double iureal = 0.5;
 double fractexp = 0.25;
 int i;

 if (strureal[0]==EOS)
	return TLF_EMPTY;	/* empty string not allowed */

 for (i=0; (strureal[i]>='0') && (strureal[i]<='1') ; i++)
	{
	 iureal = iureal+(strureal[i]-'0')*fractexp;
	 fractexp*=0.5;
	}

 switch (strureal[i])
 {
  case EOS:	/* string terminated */
	*nrureal = iureal;
	return TLF_OK;
  case 'e':
  case 'E':	/* exponent 2^n */
	if (i==0)
		{ /* e... not valid */
		 return TLF_ERROR;
		}
	{
	 int exponent;
	 int result;

	 result = str2integer((strureal+i+1),&exponent);
	 if (result==TLF_OK)
		{
		 *nrureal = ldexp(iureal,exponent);
		}
	 return result;
	}
	break;
  default:
	return TLF_ERROR;
	break;
 }

 return TLF_ERROR;		/* this is only symbolic */
}

/* convert unsigned real string in unsigned real number */
/* returns TLF_OK iff no error */

int str2ureal(char *strureal,
              double *nrureal)
{
 if (strureal[0]==EOS)
	return TLF_EMPTY;	/* empty string not allowed */

 if (strureal[0]=='0')
	{ /* verify if there are special formats */
	 switch (strureal[1])
	 {
	  case EOS: /* '0' => return 0 */
		*nrureal = 0;
		return TLF_OK;
		break;
	  case 'f':
	  case 'F':	/* binary real format */
		return str2bureal((strureal+2),nrureal);
		break;
	  case 'c':
	  case 'C':	/* compact format */
		{
		 unsigned int inat;
		 int result;

		 result = str2compact((strureal+2),&inat);
		 if (result==TLF_OK)
			 *nrureal = inat;
		 return result;
		}
		break;
	  case 'x':
	  case 'X':	/* hex format */
		{
		 unsigned int inat;
		 int result;

		 result = str2hex((strureal+2),&inat);
		 if (result==TLF_OK)
			 *nrureal = inat;
		 return result;
		}
		break;
	  case 'o':
	  case 'O':	/* octal format */
		{
		 unsigned int inat;
		 int result;

		 result = str2octal((strureal+2),&inat);
		 if (result==TLF_OK)
			 *nrureal = inat;
		 return result;
		}
		break;
	  case 'b':
	  case 'B':	/* binary format */
		{
		 unsigned int inat;
		 int result;

		 result = str2binary((strureal+2),&inat);
		 if (result==TLF_OK)
			 *nrureal = inat;
		 return result;
		}
		break;
	 } /* switch */
	}
 /* strureal is not in a special format */
 {
  double iureal = 0.0;	/* internal ureal */
  unsigned int i;

  /* integer part */
  for (i=0; (strureal[i]>='0') && (strureal[i]<='9') ; i++)
	{
	 iureal = iureal*10+(strureal[i]-'0');
	}

  switch (strureal[i])
  {
   case EOS:	/* string terminated */
	*nrureal = iureal;
	return TLF_OK;
   case '.':	/* continue with fract */
	{
	 double fractexp = 0.1;

	 for (i++; (strureal[i]>='0') && (strureal[i]<='9') ; i++)
		{
		 iureal = iureal+(strureal[i]-'0')*fractexp;
		 fractexp*=0.1;
		}
	}
	break;
   case 'e':
   case 'E':	/* exponent 10^n, do nothing here */
	break;
   default:
	return TLF_ERROR;
	break;
  }

  switch (strureal[i])
  {
   case EOS:	/* string terminated */
	if (i==1)
		{ /* . not valid */
		 return TLF_ERROR;
		}
	*nrureal = iureal;
	return TLF_OK;
   case 'e':
   case 'E':	/* exponent 10^n */
	if ((i==0) || ((i==1) && (strureal[0]=='.')))
		{ /* e... or .e... not valid */
		 return TLF_ERROR;
		}
	{
	 int exponent;
	 int result;

	 result = str2integer((strureal+i+1),&exponent);
	 if (result==TLF_OK)
		{
		 double rexp;
		 rexp = exponent;
		 *nrureal = iureal * pow10(rexp);
		}
	 return result;
	}
	break;
   default:
	return TLF_ERROR;
	break;
  }

 }

 return TLF_ERROR;		/* this is only symbolic */
}

/* convert real string in real number */
/* returns TLF_OK iff no error */

int str2real(char *strreal,
             double *nrreal)
{
 int result;

 switch (strreal[0])
 {
  case '-':
	result = str2ureal((strreal+1),nrreal);
	if (result==TLF_OK)
		*nrreal = - *nrreal;
	break;
  case '+':
	result = str2ureal((strreal+1),nrreal);
	break;
  default:
	result = str2ureal(strreal,nrreal);
	break;
 }

 return result;
}

/*************************** Intreal numbers *****************************/

/* convert unsigned intreal string in unsigned intreal number */
/* round to the nearest integer, if necessary */
/* returns TLF_OK iff no error */

int str2uintreal(char *struintreal,		/* IN  */
                 double *nruintreal)		/* OUT */
{
 int result;
 double nrureal;

 result = str2ureal(struintreal,&nrureal);

 if (result==TLF_OK)
 	 *nruintreal = floor(nrureal+0.5);	/* round */

 return result;
}

/* convert intreal string in intreal number */
/* returns TLF_OK iff no error */

int str2intreal(char *strintreal,		/* IN  */
                double *nrintreal)		/* OUT */
{
 int result;

 switch (strintreal[0])
 {
  case '-':
	result = str2uintreal((strintreal+1),nrintreal);
	if (result==TLF_OK)
		*nrintreal = - *nrintreal;
	break;
  case '+':
	result = str2uintreal((strintreal+1),nrintreal);
	break;
  default:
	result = str2uintreal(strintreal,nrintreal);
	break;
 }

 return result;
}


/*************************************************************************/
/*                          Number to String                             */
/*************************************************************************/

/*************************** Natural numbers *****************************/

/* convert natural number in normal format */
/* strnat must be allocated with enough space. */
/* i.e.: 11 bytes are enough for 32 bit */
/* returns number of digits */ 

int nat2str(unsigned int nrnat,		/* IN  */
            char *strnat)		/* OUT */
{
 int nrdigits;		/* nr. of digits */
 int i;
 double nrreal;
 
 if (nrnat==0)
 	{
 	 strnat[0]='0';
 	 strnat[1]=0;
 	 return 1;
 	}
 
 nrreal = nrnat;

 nrdigits = (int) (log10(nrreal))+1;

 for(i=nrdigits-1; i>=0; i--)
	{
	 strnat[i]='0' + (nrnat%10);
	 nrnat = nrnat/10;
	}
 strnat[nrdigits]=EOS;

 return nrdigits;
}

/* convert natural number in binary format */
/* strnat must be allocated with enough space. */
/* i.e.: 33 bytes are enough for 32 bit */
/* returns number of digits */ 

int binary2str(unsigned int nrnat,	/* IN  */
               char *strnat)		/* OUT */
{
 int nrdigits;		/* nr. of digits */
 int i;
 double nrreal;
 
 if (nrnat==0)
 	{
 	 strnat[0]='0';
 	 strnat[1]=0;
 	 return 1;
 	}
 
 nrreal = nrnat;

 nrdigits = (int) log2(nrreal)+1;

 for(i=nrdigits-1; i>=0; i--)
	{
	 strnat[i]='0' + (nrnat&1);
	 nrnat = nrnat>>1;	/* /2 */
	}
 strnat[nrdigits]=EOS;

 return nrdigits;
}

/* convert natural number in octal format */
/* strnat must be allocated with enough space. */
/* i.e.: 12 bytes are enough for 32 bit */
/* returns number of digits */ 

int octal2str(unsigned int nrnat,	/* IN  */
              char *strnat)		/* OUT */
{
 int nrdigits;		/* nr. of digits */
 int i;
 double nrreal;
 
 if (nrnat==0)
 	{
 	 strnat[0]='0';
 	 strnat[1]=0;
 	 return 1;
 	}
 
 nrreal = nrnat;

 nrdigits = (int) log8(nrreal)+1;

 for(i=nrdigits-1; i>=0; i--)
	{
	 strnat[i]='0' + (nrnat&7);
	 nrnat = nrnat>>3;	/* /8 */
	}
 strnat[nrdigits]=EOS;

 return nrdigits;
}

/* convert natural number in hex format */
/* strnat must be allocated with enough space. */
/* i.e.: 9 bytes are enough for 32 bit */
/* returns number of digits */ 

int hex2str(unsigned int nrnat,	/* IN  */
            char *strnat)		/* OUT */
{
 int nrdigits;		/* nr. of digits */
 int i;
 double nrreal;
 
 if (nrnat==0)
 	{
 	 strnat[0]='0';
 	 strnat[1]=0;
 	 return 1;
 	}
 
 nrreal = nrnat;

 nrdigits = (int) log16(nrreal)+1;

 for(i=nrdigits-1; i>=0; i--)
	{
	 char digit;

	 digit = nrnat&15;

	 if (digit<10)
		strnat[i]='0' + digit;
	 else
		strnat[i]='a' + (digit-10);
	 nrnat = nrnat>>4;	/* /16 */
	}
 strnat[nrdigits]=EOS;

 return nrdigits;
}

/* convert natural number in compact format */
/* strnat must be allocated with enough space. */
/* i.e.: 7 bytes are enough for 32 bit */
/* returns number of digits */ 

int compact2str(unsigned int nrnat,	/* IN  */
                char *strnat)		/* OUT */
{
 int nrdigits;		/* nr. of digits */
 int i;
 double nrreal;
 
 if (nrnat==0)
 	{
 	 strnat[0]='0';
 	 strnat[1]=0;
 	 return 1;
 	}
 
 nrreal = nrnat;

 nrdigits = (int) log64(nrreal)+1;

 for(i=nrdigits-1; i>=0; i--)
	{
	 char digit;

	 digit = nrnat&63;

	 if (digit<10)
		strnat[i]='0' + digit;
	 else if (digit<36)
			strnat[i]='a' + (digit-10);
		else if (digit<62)
				strnat[i]='A' + (digit-36);
			else if (digit==62)
					strnat[i] = '_';
				else
					strnat[i] = '^';
	 nrnat = nrnat>>6;	/* /64 */
	}
 strnat[nrdigits]=EOS;

 return nrdigits;
}

/*************************** Integer numbers *****************************/

/* convert integer number in normal format */
/* strint must be allocated with enough space. */
/* i.e.: 12 bytes are enough for 32 bit */
/* returns number of digits */ 

int int2str(int nrint,			/* IN  */
            char *strint)		/* OUT */
{
 if (nrint<0)
	{
	 strint[0] = '-';
	 return 1+nat2str(-nrint,(strint+1));
	}
 else
	return nat2str(nrint,strint);
}

/***************************** Real numbers ******************************/

/* convert unsigned real number in scientific format */
/* if maxfract<=0, maxfract = TLF_MAXFRACT */
/* strreal must be allocated with enough space.(maxfract+7) */
/* returns number of digits */ 

int ureal2str(double nrreal,		/* IN  */
              int maxfract,		/* IN  */
              char *strreal)		/* OUT */
{
 int exponent;
 double fract;
 int i,lasti;

 if (nrreal==0.0)
	{ /* 0.0 has a special format */
	 strreal[0]='0';
	 strreal[1]=EOS;

	 return 1;
	}

 if (maxfract<=0)
	maxfract = TLF_MAXFRACT;

 exponent = (int) floor(log10(nrreal)+1.0);
 {
  double rexp;
  rexp = exponent;
  fract = nrreal/pow10(rexp);	/* fract = .ddddddd */
 }

 strreal[0] = '.';
 for (i=1; i<=maxfract; i++)
	{
	 double rnat;

	 fract = modf(fract*10,&rnat);
	 strreal[i] = '0' + (int) rnat;
	}
 lasti = i-1;

 /* round up, if necessary */
 if (fract>=0.5)
	{ /* round up */

	 for (i--;strreal[i]=='9';i--)
		{ /* 9 => 10 */
		 strreal[i] = '0';
		}
	 if (i>0)
		{ /* increase digit */
		 strreal[i]++;
		}
	 else
		{ /* .9999 => .1e+1 */
		 strreal[1]='1';
		 lasti = 1;
		 exponent++;
		}
	}

 /* delete trailing zeroes */
 for (;strreal[lasti] == '0'; lasti--);
 i=lasti+1;

 if (exponent!=0)
	{ /* add exponent */
	 strreal[i] = 'e';
	 i++;
	 return i+int2str(exponent,(strreal+i));
	}
 else
	{
	 strreal[i] = EOS;
	 return i;
	}
}

/* convert real number in scientific format */
/* if maxfract<=0, maxfract = TLF_MAXFRACT */
/* strreal must be allocated with enough space.(maxfract+7) */
/* returns number of digits */ 

int real2str(double nrreal,		/* IN  */
             int maxfract,		/* IN  */
             char *strreal)		/* OUT */
{
 if (nrreal<0.0)
	{
	 strreal[0] = '-';
	 return 1+ureal2str(-nrreal,maxfract,(strreal+1));
	}
 else
	return ureal2str(nrreal,maxfract,strreal);
}

/* convert unsigned real number in fixed format */
/* if maxint<=0, do not limit int length */
/* if maxfract<0, maxfract = TLF_MAXFRACT,
   else if ==0, set to 1 */
/* strreal must be allocated with enough space.(maxint+1+maxfract+5+1) */
/* returns number of digits */ 

int fureal2str(double nrreal,		/* IN  */
               int maxint,		/* IN  */
               int maxfract,		/* IN  */
               char *strreal)		/* OUT */
{
 double maxint10;

 if (nrreal==0.0)
	{ /* 0.0 has a special format */
	 strreal[0]='0';
	 strreal[1]=EOS;

	 return 1;
	}

 if (maxfract<0)
	maxfract = TLF_MAXFRACT;
 else if (maxfract==0)
	maxfract = 1;

 {
  double tmp;
  tmp=maxint;
  maxint10 = pow10(tmp);
 }
 if ((maxint>0) && (maxint10<=nrreal))
	{ /* integer part too large */
	 int exponent;
	 double fract;
	 int i,lasti;

	 exponent = (int) floor(log10(nrreal));
	 {
	  double rexp;
	  rexp = exponent;
	  fract = nrreal/pow10(rexp);	/* fract = n.ddddd */
	 }

	 for ( i=0; i<maxint; i++ )
		{
		 double rnat;

		 fract = modf(fract,&rnat)*10.0;
		 strreal[i] = '0' + (int) rnat;
		}
	 lasti = i-1;

	 /* round up, if necessary */
	 if (fract>=5.0)
		{ /* round up */

		 for (i--;(i>=0)&&(strreal[i]=='9');i--)
			{ /* 9 => 10 */
			 strreal[i] = '0';
			}
		 if (i>=0)
			{ /* increase digit */
			 strreal[i]++;
			}
		 else
			{ /* 9999 => 1000e+1 */
			 int j;
			 strreal[0]='1';
			 for (j=1; j<=lasti; j++)
				strreal[j]='0';
			 exponent++;
			}
		}

	 i = lasti + 1;
	 /* add exponent */
	 strreal[i] = 'e';
	 i++;
	 return i+int2str(exponent-maxint+1,(strreal+i));
	}
 else
	{ /* integer part small enough */
	 int exponent;
	 double fract;
	 int j,i,lasti;

	 exponent = (int) floor(log10(nrreal));
	 if (exponent>=0)
	 	{ /* integer part present */
		 {
		  double rexp;
		  rexp = exponent;
		  fract = nrreal/pow10(rexp);	/* fract = n.ddddd */
		 }

		 /* integer part */
		 for ( i=0; i<=exponent; i++ )
			{
			 double rnat;

			 fract = modf(fract,&rnat)*10.0;
			 strreal[i] = '0' + (int) rnat;
			}
		}
	 else
	 	{
	 	 strreal[0]='0';
	 	 i=1;
	 	 fract = nrreal*10;	/* int part not present */
	 	}
	 strreal[i]='.';
	 i++;
	 /* fract part */
	 for ( j=1; j<=maxfract; j++ )
		{
		 double rnat;

		 fract = modf(fract,&rnat)*10.0;
		 strreal[i] = '0' + (int) rnat;
		 i++;
		}
	 lasti = i-1;

	 /* round up, if necessary */
	 if (fract>=5.0)
		{ /* round up */

		 for (i--;strreal[i]=='9';i--)
			{ /* 9 => 10 */
			 strreal[i] = '0';
			}
		 if (strreal[i]!='.')
			{
			 strreal[i]++;
			}
		 else
			{ /* continue before . */
			 for (i--;(i>=0)&&(strreal[i]=='9');i--)
				{ /* 9 => 10 */
				 strreal[i] = '0';
				}
			 if (i>=0)
				{ /* increase digit */
				 strreal[i]++;
				}
			 else
				{ /* 9999.999 => 10000.000 */
				 if (maxint10>=(nrreal*10.0))
					{ /* integer part too large */
					 int j;
					 strreal[0]='1';
					 for (j=1; j<=maxint; j++)
						strreal[j]='0';
					 strreal[j]='e';
					 strreal[j+1]='1';
					 strreal[j+2]=EOS;
					 return j+1;		/* EXIT */
					}
				 else
					{
					 int j;
					 for (j=lasti; j>=0; j--)
						strreal[j+1]=strreal[j];
					 strreal[0]='1';
					 lasti++;
					}
				}
			}
		}

	 /* delete trailing zeroes */
	 for (;strreal[lasti] == '0'; lasti--);
	 /* must be at least one nr. after . */
	 i = lasti;
	 if (strreal[i]=='.')
		i++;
	 i++;
	 strreal[i] = EOS;
	 return i;
	}
}

/* convert real number in fixed format */
/* if maxint<=0, do not limit int length */
/* if maxfract<0, maxfract = TLF_MAXFRACT,
   else if ==0, set to 1 */
/* strreal must be allocated with enough space.(maxint+1+maxfract+5+1) */
/* returns number of digits */ 

int freal2str(double nrreal,		/* IN  */
              int maxint,		/* IN  */
              int maxfract,		/* IN  */
              char *strreal)		/* OUT */
{
 if (nrreal<0.0)
	{
	 strreal[0] = '-';
	 return 1+fureal2str(-nrreal,maxint,maxfract,(strreal+1));
	}
 else
	return fureal2str(nrreal,maxint,maxfract,strreal);
}

/* convert unsigned real number in binary real format prefixed by 0f*/
/* strreal must be allocated with enough space. */
/* i.e.: 72 bytes are enough for 64-bit double */
/* returns number of digits */ 

int bureal2str(double nrreal,		/* IN  */
               char *strreal)		/* OUT */
{
 int exponent;
 double fract;
 int i;

 if (nrreal==0.0)
	{ /* 0.0 has a special format */
	 strreal[0]='0';
	 strreal[1]=EOS;

	 return 1;
	}

 strreal[0]='0';
 strreal[1]='f';

 fract = frexp(nrreal,&exponent);
 fract =fract*2.0-1.0;

 fract *= 2.0;		/* init fract for the for */

 for (i=2;fract>0.0;i++)
	{ /* calc fract part */
	 if (fract>=1.0)
		{
		 strreal[i]='1';
		 fract -= 1.0;
		}
	 else
		strreal[i] = '0';
	 fract *= 2.0;
	}
 if (i==2)
	{ /* 0.5 case */
	 strreal[2] = '0';
	 i++;
	}

 if (exponent!=0)
	{ /* add exponent */
	 strreal[i] = 'e';
	 i++;
	 return i+int2str(exponent,(strreal+i));
	}
 else
	{
	 strreal[i] = EOS;
	 return i;
	}
}

/* convert real number in binary real format prefixed by 0f*/
/* strreal must be allocated with enough space. */
/* i.e.: 72 bytes are enough for 64-bit double */
/* returns number of digits */ 

int breal2str(double nrreal,		/* IN  */
              char *strreal)		/* OUT */
{
 if (nrreal<0.0)
	{
	 strreal[0] = '-';
	 return 1+bureal2str(-nrreal,(strreal+1));
	}
 else
	return bureal2str(nrreal,strreal);
}

/*************************** Intreal numbers *****************************/

/* convert real number in integer format */
/* if maxlength<=0, return full integer,
   else if <6, set to 6 */ 
/* strreal must be allocated with enough space.(maxlength+1) */
/* returns number of digits */ 

int uintreal2str(double nrintreal,		/* IN  */
                 int maxlength,			/* IN  */
                 char *strintreal)		/* OUT */
{
 int exponent;
 double fract;

 if (nrintreal==0.0)
	{ /* 0.0 has a special format */
	 strintreal[0]='0';
	 strintreal[1]=EOS;

	 return 1;
	}

 if ((maxlength>0) && (maxlength<6))
	maxlength = 6;

 exponent = (int) floor(log10(nrintreal)+1.0);	/* == nr of digits */
 {
  double rexp;
  rexp = exponent-1;
  fract = nrintreal/pow10(rexp);		/* fract = n.ddddd */
 }

 if ((maxlength<=0) || (maxlength>=exponent))
	{ /* write all digits */
	 int i,lasti;

	 for ( i=0; i<exponent; i++)
		{
		 double rnat;

		 fract = modf(fract,&rnat)*10.0;
		 strintreal[i] = '0' + (int) rnat;
		}
	 lasti=i-1;

	 /* round up, if necessary (needed, because a real nr. */
	 if (fract>=5.0)
		{ /* round up */

		 for (i--;(i>=0)&&(strintreal[i]=='9');i--)
			{ /* 9 => 10 */
			 strintreal[i] = '0';
			}
		 if (i>=0)
			{ /* increase digit */
			 strintreal[i]++;
			}
		 else
		 	if ((maxlength<=0) || (maxlength>(lasti+1)))
				{ /* 9999 => 10000 */
				 int j;
				 strintreal[0]='1';
				 lasti++;	/* extend +1 char */
				 for (j=1; j<=lasti; j++)
					strintreal[j]='0';
				}
			else
				{ /* 99999 => 10e4 */
				 int j;
				 strintreal[0]='1';
				 lasti--;
				 for (j=1; j<=(lasti-2); j++)
					strintreal[j]='0';
				 strintreal[lasti-1]='e';
				 strintreal[lasti]='4';
				}
		}
	 i=lasti+1;
	 strintreal[i] = EOS;
	 return i;
	}
 else
	{ /* not all the digits can be used */
	 int i,lasti;

	 for ( i=0; i<maxlength-4; i++)
		{
		 double rnat;

		 fract = modf(fract,&rnat)*10.0;
		 strintreal[i] = '0' + (int) rnat;
		}
	 lasti = i-1;

	 /* round up, if necessary */
	 if (fract>=5.0)
		{ /* round up */

		 for (i--;(i>=0)&&(strintreal[i]=='9');i--)
			{ /* 9 => 10 */
			 strintreal[i] = '0';
			}
		 if (i>=0)
			{ /* increase digit */
			 strintreal[i]++;
			}
		 else
			{ /* 9999 => 1000e+1 */
			 int j;
			 strintreal[0]='1';
			 for (j=1; j<=lasti; j++)
				strintreal[j]='0';
			 exponent++;
			}
		}

	 i = lasti + 1;
	 /* add exponent */
	 strintreal[i] = 'e';
	 i++;
	 return i+int2str(exponent-maxlength+4,(strintreal+i)); 
	}
}

/* convert real number in integer format */
/* if maxlength<=0, return full integer,
   else if <6, set to 6 */ 
/* strreal must be allocated with enough space.(maxlength+1) */
/* returns number of digits */ 

int intreal2str(double nrintreal,		/* IN  */
                int maxlength,			/* IN  */
                char *strintreal)		/* OUT */
{
 if ((maxlength>0) && (maxlength<6))
	maxlength = 6;

 if (nrintreal<0.0)
	{
	 strintreal[0] = '-';
	 if (maxlength<=0)
		 return 1+uintreal2str(-nrintreal,maxlength,(strintreal+1));
	 else
		 return 1+uintreal2str(-nrintreal,maxlength-1,(strintreal+1));
	}
 else
	return uintreal2str(nrintreal,maxlength,strintreal);
}

/*************************************************************************/
/*                          String to Boolean                            */
/*************************************************************************/

/* convert Boolean string in boolean(char) */
/* returns TLF_OK iff no error */

int str2bool(char *strbool,	/* IN  */
             char *bool)	/* OUT */
{
 int result;
 unsigned int nrnat;

 if (strbool[0]==EOS)
	return TLF_EMPTY;	/* empty string not allowed */

 /* try natural format */
 result = str2nat(strbool,&nrnat);

 if (result==TLF_OK)
	{ /* interpret nat as boolean */
	 *bool = (nrnat>0);
	}
 else if (strbool[1]==EOS)
		{ /* one letter string */
		 if ((strbool[0]=='t') || (strbool[0]=='T'))
			{ /* true */
			 *bool = 1;
			 result=TLF_OK;
			}
		 else if ((strbool[0]=='f') || (strbool[0]=='F'))
				{ /* false */
				 *bool = 0;
				 result=TLF_OK;
				}
			else
				result = TLF_ERROR;	/* not a boolean */

		}
	else
		{
		 if (((strbool[0]=='t') || (strbool[0]=='T')) &&
		     ((strbool[1]=='r') || (strbool[1]=='R')) &&
		     ((strbool[2]=='u') || (strbool[2]=='U')) &&
		     ((strbool[3]=='e') || (strbool[3]=='E')) &&
		     (strbool[4]==EOS))
			{ /*true*/
			 *bool = 1;
			 result=TLF_OK;
			}
		 else if (((strbool[0]=='f') || (strbool[0]=='F')) &&
		          ((strbool[1]=='a') || (strbool[1]=='A')) &&
		          ((strbool[2]=='l') || (strbool[2]=='L')) &&
		          ((strbool[3]=='s') || (strbool[3]=='S')) &&
		          ((strbool[4]=='e') || (strbool[4]=='E')) &&
		          (strbool[5]==EOS))
				{ /* false */
				 *bool = 0;
				 result=TLF_OK;
				}
			else
				result = TLF_ERROR;	/* not a boolean */

		}
 return result;  
}

/*************************************************************************/
/*                          Boolean to String                            */
/*************************************************************************/

/* convert Boolean nr. to True/False */
/* use C style boolean (False==0, true>0 */
/* strbool must be allocated with enough space.(6 chars) */

void bool2str(char bool,	/* IN  */
              char *strbool)	/* OUT */
{
 if (bool)
	 strcpy(strbool,"True");
 else
	 strcpy(strbool,"False");
 return;
}

/* convert Boolean nr. to T/F */
/* use C style boolean (False==0, true>0 */
/* strbool must be allocated with enough space.(2 chars) */

void cbool2str(char bool,	/* IN  */
               char *strbool)	/* OUT */
{
 if (bool)
	 strcpy(strbool,"T");
 else
	 strcpy(strbool,"F");
 return;
}

/* convert Boolean nr. to 1/0 */
/* use C style boolean (False==0, true>0 */
/* strbool must be allocated with enough space.(2 chars) */

void nbool2str(char bool,	/* IN  */
               char *strbool)	/* OUT */
{
 if (bool)
	 strcpy(strbool,"1");
 else
	 strcpy(strbool,"0");
 return;
}

/*************************************************************************/
/*                          String to Pointer                            */
/*************************************************************************/

/* convert pointer string in void * */
/* must be a string returned by pointer2str */
/* returns TLF_OK iff no error */

int str2pointer(char *strpoint,	/* IN  */
                void * *data)	/* OUT */
{
 sscanf(strpoint,"%p",data);
 return TLF_OK;
}

/*************************************************************************/
/*                          Pointer to String                            */
/*************************************************************************/

/* convert void * in pointer string */
/* strbool must be allocated with enough space. */
/* returns number of digits */ 

int pointer2str(void *data,		/* IN  */
                char *strpoint)		/* OUT */
{
 sprintf(strpoint,"%p",data);
 return strlen(strpoint);
}

/*************************************************************************/
/*                          String to C String                           */
/*************************************************************************/

/* convert a string to a c string */
/* allocates new space, must be freed by the user*/

char *str2cstr(char *oldstr)
{
 char *newstr;
 int i,j;
 
 newstr = (char *) malloc(strlen(oldstr)*4+1);	/* worst case */

 j=0;
 for (i=0; oldstr[i]!=EOS; i++)
 	{
 	 if (oldstr[i]>=32)
 		{
 		 newstr[j]=oldstr[i];
 		 j++;
 		}
 	 else if (oldstr[i]=='\t')
 	 	{
 	 	 newstr[j]='\\';
 	 	 newstr[j+1]='t';
 	 	 j+=2;
 	 	}
 	      else if (oldstr[i]=='\n')
 	      		{
 	      		 newstr[j]='\\';
 	      		 newstr[j+1]='n';
 	      		 j+=2;
 	      		}
 	      	    else
 	      	    	{
 	      	    	 newstr[j]='\\';
 	      	    	 newstr[j+1]='0'+(oldstr[i]>>6);
 	      	    	 newstr[j+2]='0'+((oldstr[i]>>3)&7);
 	      	    	 newstr[j+3]='0'+(oldstr[i]&7);
 			 j+=4;
 	      	    	}
 	}
 newstr[j]=EOS;
 
 return newstr;
}