//	Zinc Application Framework - Z_REAL.CPP
//	COPYRIGHT (C) 1990-1999.  All Rights Reserved.
//	Zinc Software Incorporated.  Pleasant Grove, Utah  USA

#include <z_real.hpp>
#include <z_ctype.hpp>
#include <z_stdlib.hpp>
#include <z_stdarg.hpp>
#include <z_string.hpp>
#define ZAF_REAL_DATA_INFO
#include "gbl_def.cpp"

// ----- ZafRealData --------------------------------------------------------

ZafRealData::ZafRealData(void) :
	ZafFormatData(), value(0.0)
{
	// Check the printf binding.
	Bind();
}

ZafRealData::ZafRealData(double zValue) :
	ZafFormatData(), value(zValue)
{
	// Check the printf binding.
	Bind();
}

ZafRealData::ZafRealData(const ZafIChar *string, const ZafIChar *format) :
	ZafFormatData()
{
	// Check the printf binding.
	Bind();
	Sscanf(string, (format && format[0]) ? format : zafLocale->realStringInputFormat);
}

ZafRealData::ZafRealData(const ZafRealData &copy) :
	ZafFormatData(copy), value(copy.value)
{
	// Check the printf binding.
	Bind();
}

ZafRealData::~ZafRealData(void)
{
}

void ZafRealData::Bind(void)
{
	// Bind in the sprintf characters.
#if defined(ZAF_INDEPENDENT)
#	define bound zafRealData_bound
	extern bool bound;
#else
	static bool bound = false;
#endif
	if (!bound)
	{
		// Check for a valid locale.
		if (!zafLocale)
			ZafI18nData::I18nAllocate();

		// Set the lookup characters.
		bound = true;
/* START BLOCK COMMENT
**			ZafStandardArg::SetSprintf('e', ZafRealData::Format);
**			ZafStandardArg::SetSprintf('E', ZafRealData::Format);
**			ZafStandardArg::SetSprintf('f', ZafRealData::Format);
**			ZafStandardArg::SetSprintf('F', ZafRealData::Format);
**			ZafStandardArg::SetSprintf('g', ZafRealData::Format);
**			ZafStandardArg::SetSprintf('G', ZafRealData::Format);
**			ZafStandardArg::SetSscanf('e', ZafRealData::Parse);
**			ZafStandardArg::SetSscanf('E', ZafRealData::Parse);
**			ZafStandardArg::SetSscanf('f', ZafRealData::Parse);
**			ZafStandardArg::SetSscanf('F', ZafRealData::Parse);
**			ZafStandardArg::SetSscanf('g', ZafRealData::Parse);
**			ZafStandardArg::SetSscanf('G', ZafRealData::Parse);
END BLOCK COMMENT */
		ZafFormatData::SetSprintf('e', ZafRealData::Format);
		ZafFormatData::SetSprintf('E', ZafRealData::Format);
		ZafFormatData::SetSprintf('f', ZafRealData::Format);
		ZafFormatData::SetSprintf('F', ZafRealData::Format);
		ZafFormatData::SetSprintf('g', ZafRealData::Format);
		ZafFormatData::SetSprintf('G', ZafRealData::Format);
		ZafFormatData::SetSscanf('e', ZafRealData::Parse);
		ZafFormatData::SetSscanf('E', ZafRealData::Parse);
		ZafFormatData::SetSscanf('f', ZafRealData::Parse);
		ZafFormatData::SetSscanf('F', ZafRealData::Parse);
		ZafFormatData::SetSscanf('g', ZafRealData::Parse);
		ZafFormatData::SetSscanf('G', ZafRealData::Parse);
	}
}

void ZafRealData::Clear(void)
{
	// Reset the value.
	PushLevel();
	value = 0.0;
	SetError(ZAF_ERROR_NONE);
	PopLevel();
}

ZafData *ZafRealData::Duplicate(void)
{
	return (new ZafRealData(*this));
}

int ZafRealData::FormattedText(ZafIChar *buffer, int maxLength, const ZafIChar *format) const
{
	// Format the text.
	return (Sprintf(buffer, maxLength, format ? format : zafLocale->realStringOutputFormat));
}

bool ZafRealData::IsA(ZafClassID compareID) const
{
	return ((compareID == classID) ? true : ZafFormatData::IsA(compareID));
}

bool ZafRealData::IsA(ZafClassName compareName) const
{
	return (!strcmp(compareName, className) ? true : ZafFormatData::IsA(compareName));
}

ZafError ZafRealData::SetReal(double tValue)
{
	// Reset the value.
	PushLevel();
	value = tValue;
	PopLevel();

	// Return success.
	return (ZAF_ERROR_NONE);
}

ZafError ZafRealData::SetReal(const ZafRealData &number)
{
	// Reset the value.
	PushLevel();
	value = number.value;
	PopLevel();

	// Return success.
	return (ZAF_ERROR_NONE);
}

ZafError ZafRealData::SetReal(const ZafIChar *buffer, const ZafIChar *format)
{
	// Reset the value.
	PushLevel();
	if (!buffer || !buffer[0])
		Clear();
	else if (!Sscanf(buffer, (format && format[0]) ? format : zafLocale->realStringInputFormat))
		SetError(ZAF_ERROR_INVALID);
	else
		SetError(ZAF_ERROR_NONE);
	PopLevel();

	// Return the error status.
	return (Error());
}

// ----- Operators ----------------------------------------------------------

ZafRealData ZafRealData::operator++(void)
{
	// Reset the value.
	PushLevel();
	*this += 1.0;
	PopLevel();

	// Return a reference pointer.
	return *this;
}

ZafRealData ZafRealData::operator++(int)
{
	// Reset the value.
	PushLevel();
	ZafRealData tmp = *this;
	*this += 1.0;
	PopLevel();

	// Return a temporary reference pointer.
	return tmp;
}

ZafRealData ZafRealData::operator--(void)
{
	// Reset the value.
	PushLevel();
	*this -= 1.0;
	PopLevel();

	// Return a reference pointer.
	return *this;
}

ZafRealData ZafRealData::operator--(int)
{
	// Reset the value.
	PushLevel();
	ZafRealData tmp = *this;
	*this -= 1.0;
	PopLevel();

	// Return a temporary reference pointer.
	return tmp;
}

ZafRealData &ZafRealData::operator=(ZafRealData &tValue)
{
	// Reset the value.
	PushLevel();
	value = tValue.value;
	PopLevel();

	// Return a reference pointer.
	return (*this);
}

ZafRealData &ZafRealData::operator=(double tValue)
{
	// Reset the value.
	PushLevel();
	value = tValue;
	PopLevel();

	// Return a reference pointer.
	return (*this);
}

ZafRealData &ZafRealData::operator+=(double tValue)
{
	// Reset the value.
	PushLevel();
	value += tValue;
	PopLevel();

	// Return a reference pointer.
	return (*this);
}

ZafRealData &ZafRealData::operator-=(double tValue)
{
	// Reset the value.
	PushLevel();
	value -= tValue;
	PopLevel();

	// Return a reference pointer.
	return (*this);
}

ZafRealData &ZafRealData::operator*=(double tValue)
{
	// Reset the value.
	PushLevel();
	value *= tValue;
	PopLevel();

	// Return a reference pointer.
	return (*this);
}

ZafRealData &ZafRealData::operator/=(double tValue)
{
	// Reset the value.
	PushLevel();
	value /= tValue;
	PopLevel();

	// Return a reference pointer.
	return (*this);
}

// ----- sprintf/sscanf functions -------------------------------------------

//	The rest of this file is modified from a version of vfprintf.c obtained
//	from the Berkeley Source Tree administered by The Regents of the
//	University of California (the "Regents")
//
//	Modifications made by Zinc are:
//	  COPYRIGHT (C) 1994-1999.  All Rights Reserved.
//	  Zinc Software Incorporated.  Pleasant Grove, Utah  USA
//
//	Permission from the Regents is conditioned on inclusion of the following
//	notice from the Regents which applies only to vfprintf.c:
//
//	  Copyright (c) 1990 The Regents of the University of California.
//	  All rights reserved.
//
//	  This code is derived from software contributed to Berkeley by
//	  Chris Torek.
//
//	  Redistribution and use in source and binary forms, with or without
//	  modification, are permitted provided that the following conditions
//	  are met:
//	  1. Redistributions of source code must retain the above copyright
//	     notice, this list of conditions and the following disclaimer.
//	  2. Redistributions in binary form must reproduce the above copyright
//	     notice, this list of conditions and the following disclaimer in the
//	     documentation and/or other materials provided with the distribution.
//	  3. All advertising materials mentioning features or use of this software
//	     must display the following acknowledgement:
//	       This product includes software developed by the University of
//	       California, Berkeley and its contributors.
//	  4. Neither the name of the University nor the names of its contributors
//	     may be used to endorse or promote products derived from this software
//	     without specific prior written permission.
//
//	  THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
//	  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
//	  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
//	  ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
//	  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
//	  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
//	  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
//	  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
//	  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
//	  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
//	  SUCH DAMAGE.

#include <math.h>

#define MAXEXP		4
#define MAXFRACT	24
#define	BUF		350
#define	DEFPREC		6
// For floating point number (always in Arabic numerals)
#define to_char(n)	((n) + '0')
#define to_digit(c)	((c) - '0')

#define LENGTHOF(x)	((int)(sizeof(x)/sizeof((x)[0])))

static int IsInf(double x)
{
	union
	{
		short ints[4];
		double x;
	} convert;

	convert.x = x;
	if ((convert.ints[3] & 0x7fff) == 0x7ff0 &&
	    convert.ints[2] == 0 && convert.ints[1] == 0 &&
	    convert.ints[0] == 0)
		return (convert.ints[3] & 0x8000 ? -1 : 1);
	return (0);
}

static int IsNan(double x)
{
	union
	{
		short ints[4];
		double x;
	} convert;

	convert.x = x;
	return ((convert.ints[3] & 0x7fff) == 0x7ff0 &&
		(convert.ints[2] != 0 || convert.ints[1] != 0 ||
		 convert.ints[0] != 0));
}

static ZafIChar *exponent(ZafIChar *p, int exp, int fmtch)
{
	ZafIChar *t;
	ZafIChar expbuf[MAXEXP];

	*p++ = (ZafIChar)fmtch;
	if (exp < 0)
	{
		exp = -exp;
		*p++ = '-';
	}
	else
		*p++ = '+';
	t = expbuf + MAXEXP;
	if (exp > 9)
	{
		do {
			*--t = (ZafIChar)to_char(exp % 10);
		} while ((exp /= 10) > 9);
		*--t = (ZafIChar)to_char(exp);
		for (; t < expbuf + MAXEXP; *p++ = *t++)
			;
	}
	else
	{
		*p++ = '0';
		*p++ = (ZafIChar)to_char(exp);
	}
	return (p);
}

static ZafIChar *round(double fract, int *exp, ZafIChar *start, ZafIChar *end,
	ZafIChar ch, int *signp, const ZafIChar *decimalSeparator)
{
	double tmp;

	if (fract)
		(void)modf(fract * 10, &tmp);
	else
		tmp = to_digit(ch);
	if (tmp > 4)
		for (;; --end)
		{
			if (strneq(end, decimalSeparator, (int)strlen(decimalSeparator)) == 0)
				end -= strlen(decimalSeparator);
			(*end)++;
			if (*end <= '9')
				break;
			*end = '0';
			if (end == start)
			{
				if (exp)	/* e/E; increment exponent */
				{
					*end = '1';
					++*exp;
				}
				else
				{		/* f; add extra digit */
					*--end = '1';
					--start;
				}
				break;
			}
		}
	/* ``"%.3f", (double)-0.0004'' gives you a negative 0. */
	else if (*signp)
		for (;; --end)
		{
			if (strneq(end, decimalSeparator, (int)strlen(decimalSeparator)) == 0)
				end -= strlen(decimalSeparator);
			if (*end != '0')
				break;
			if (end == start)
				*signp = 0;
		}
	return (start);
}

static int cvt(double number, int prec, int flags, int *signp, int fmtch,
	ZafIChar *startp, ZafIChar *endp, const ZafIChar *decimalSeparator)
{
	ZafIChar *p, *t;
	double fract;
	int dotrim, expcnt, gformat;
	double integer, tmp;

	expcnt = gformat = 0;
	if (number < 0)
	{
		number = -number;
		*signp = 1;
	}
	else
		*signp = 0;

	fract = modf(number, &integer);

	/* get an extra slot for rounding. */
	t = ++startp;

	/*
	 * get integer portion of number; put into the end of the buffer; the
	 * .01 is added for modf(356.0 / 10, &integer) returning .59999999...
	 */
	for (p = endp - 1; integer && p >= startp; ++expcnt)
	{
		tmp = modf(integer / 10, &integer);
		*p-- = (ZafIChar)to_char((int)((tmp + .01) * 10));
	}
	switch (fmtch)
	{
	case 'f':
	case 'F':
		/* reverse integer into beginning of buffer */
		if (expcnt)
			for (; ++p < endp; *t++ = *p)
				;
		else
			*t++ = '0';
		/*
		 * if precision required or alternate flag set, add in a
		 * decimal point.
		 */
		if (prec || flags & ZAF_ALT)
		{
			strcpy(t, decimalSeparator);
			t += strlen(decimalSeparator);
		}
		/* if requires more precision and some fraction left */
		if (fract)
		{
			if (prec)
				do {
					fract = modf(fract * 10, &tmp);
					*t++ = (ZafIChar)to_char((int)tmp);
				} while (--prec && fract);
			if (fract)
				startp = round(fract, ZAF_NULLP(int), startp,
				    t - 1, (ZafIChar)0, signp, decimalSeparator);
		}
		for (; prec--; *t++ = '0')
			;
		break;
	case 'e':
	case 'E':
eformat:	if (expcnt)
		{
			*t++ = *++p;
			if (prec || flags & ZAF_ALT)
			{
				strcpy(t, decimalSeparator);
				t += strlen(decimalSeparator);
			}
			/* if requires more precision and some integer left */
			for (; prec && ++p < endp; --prec)
				*t++ = *p;
			/*
			 * if done precision and more of the integer component,
			 * round using it; adjust fract so we don't re-round
			 * later.
			 */
			if (!prec && ++p < endp)
			{
				fract = 0;
				startp = round((double)0, &expcnt, startp,
				    t - 1, *p, signp, decimalSeparator);
			}
			/* adjust expcnt for digit in front of decimal */
			--expcnt;
		}
		/* until first fractional digit, decrement exponent */
		else if (fract)
		{
			/* adjust expcnt for digit in front of decimal */
			for (expcnt = -1;; --expcnt)
			{
				fract = modf(fract * 10, &tmp);
				if (tmp)
					break;
			}
			*t++ = (ZafIChar)to_char((int)tmp);
			if (prec || flags & ZAF_ALT)
			{
				strcpy(t, decimalSeparator);
				t += strlen(decimalSeparator);
			}
		}
		else
		{
			*t++ = '0';
			if (prec || flags & ZAF_ALT)
			{
				strcpy(t, decimalSeparator);
				t += strlen(decimalSeparator);
			}
		}
		/* if requires more precision and some fraction left */
		if (fract)
		{
			if (prec)
				do {
					fract = modf(fract * 10, &tmp);
					*t++ = (ZafIChar)to_char((int)tmp);
				} while (--prec && fract);
			if (fract)
				startp = round(fract, &expcnt, startp,
				    t - 1, (ZafIChar)0, signp, decimalSeparator);
		}
		/* if requires more precision */
		for (; prec--; *t++ = '0')
			;

		/* unless alternate flag, trim any g/G format trailing 0's */
		if (gformat && !(flags & ZAF_ALT))
		{
			while (t > startp && *--t == '0')
				;
			int len = (int)strlen(decimalSeparator);
			if (strneq(&t[-len+1], decimalSeparator, len) == 0)
				t -= len;
			++t;
		}
		t = exponent(t, expcnt, fmtch);
		break;
	case 'g':
	case 'G':
		/* a precision of 0 is treated as a precision of 1. */
		if (!prec)
			++prec;
		/*
		 * ``The style used depends on the value converted; style e
		 * will be used only if the exponent resulting from the
		 * conversion is less than -4 or greater than the precision.''
		 *	-- ANSI X3J11
		 */
		if (expcnt > prec || !expcnt && fract && fract < .0001)
		{
			/*
			 * g/G format counts "significant digits, not digits of
			 * precision; for the e/E format, this just causes an
			 * off-by-one problem, i.e. g/G considers the digit
			 * before the decimal point significant and e/E doesn't
			 * count it as precision.
			 */
			--prec;
			fmtch -= 2;		/* G->E, g->e */
			gformat = 1;
			goto eformat;
		}
		/*
		 * reverse integer into beginning of buffer,
		 * note, decrement precision
		 */
		if (expcnt)
			for (; ++p < endp; *t++ = *p, --prec)
				;
		else
			*t++ = '0';
		/*
		 * if precision required or alternate flag set, add in a
		 * decimal point.  If no digits yet, add in leading 0.
		 */
		if (prec || flags & ZAF_ALT)
		{
			dotrim = 1;
			strcpy(t, decimalSeparator);
			t += strlen(decimalSeparator);
		}
		else
			dotrim = 0;
		/* if requires more precision and some fraction left */
		if (fract)
		{
			if (prec)
			{
				do {
					fract = modf(fract * 10, &tmp);
					*t++ = (ZafIChar)to_char((int)tmp);
					if (expcnt)
						prec--;
				} while(!tmp && prec);
				while (--prec > 0 && fract)
				{
					fract = modf(fract * 10, &tmp);
					*t++ = (ZafIChar)to_char((int)tmp);
				}
			}
			if (fract)
				startp = round(fract, ZAF_NULLP(int), startp,
				    t - 1, (ZafIChar)0, signp, decimalSeparator);
		}
		/* alternate format, adds 0's for precision, else trim 0's */
		if (flags & ZAF_ALT)
			for (; prec--; *t++ = '0')
				;
		else if (dotrim)
		{
			while (t > startp && *--t == '0')
				;
			int len = (int)strlen(decimalSeparator);
			if (strneq(&t[-len+1], decimalSeparator, len) == 0)
				t -= len;
			++t;
		}
	}

	*t = '\0';

	return (int)(t - startp + 1);
}

static ZafIChar _inf[] = { ' ', 'I', 'n', 'f', 0 };
static ZafIChar _nan[] = { 'N', 'a', 'N', 0 };

#define	PRINT(ptr, len) strncpy(buffer, ptr, (size_t)len), buffer += len;
#define	PAD(howmany, with) { \
	n = (howmany); \
	while (n > 0) { \
		*(buffer)++ = with; \
		n--; \
	} \
}

static ZafIChar _realSpaceString[] 	= { ' ', 0 };
static ZafIChar _realBlankString[] 	= { 0 };

void ZafRealData::Format(va_list *argList, ZafIChar **ptrBuffer,
	ZafIChar fmtch, int flags, int width, int prec)
{
	ZafIChar *buffer = *ptrBuffer;
	double _double;
	if (flags & ZAF_OBJ)
	{
		ZafRealData *tmp = va_arg(*argList, ZafRealData *);
		_double = tmp->value;
	}
	else if (flags & ZAF_LONGDBL)
		_double = (double)va_arg(*argList, long double);
	else
		_double = va_arg(*argList, double);

	int fpprec = 0;		/* `extra' floating precision in [eEfgG] */
	if (IsNan(_double))
	{
		strcpy(buffer, _nan);
		buffer += strlen(_nan);
		*ptrBuffer = buffer;
		return;
	}
	int softsign = (_double < 0);
	// do this before tricky precision changes
	if (IsInf(_double))
	{
		_inf[0] = (softsign) ? '-' : '+';
		strcpy(buffer, _inf);
		buffer += strlen(_inf);
		*ptrBuffer = buffer;
		return;
	}
	const ZafIChar *ps1, *pc, *ps, *ps2;
	const ZafIChar *ss2, *ss, *sc, *ss1;
	const ZafIChar *pt;
	const ZafIChar *t;
	//*** const ZafIChar *cm;
	//*** const char *gp; int oldgp;
	ps1 = pc = ps = ps2 = ss1 = sc = ss = ss2 = pt = _realBlankString;
	if (flags & ZAF_CURRENCYx)
	{
		pt = zafLocale->monDecimalSeparator;
		//*** cm = zafLocale->monThousandsSeparator;
		//*** gp = zafLocale->monGrouping;
		if (softsign)
		{
			if (zafLocale->negCurrencyPrecedes)
			{
				pc = zafLocale->currencySymbol;
				if (zafLocale->negSpaceSeparation)
					ps = _realSpaceString;
			}
			else
			{
				sc = zafLocale->currencySymbol;
				if (zafLocale->negSpaceSeparation)
					ss = _realSpaceString;
			}
		}
		else
		{
			if (zafLocale->posCurrencyPrecedes)
			{
				pc = zafLocale->currencySymbol;
				if (zafLocale->posSpaceSeparation)
					ps = _realSpaceString;
			}
			else
			{
				sc = zafLocale->currencySymbol;
				if (zafLocale->posSpaceSeparation)
					ss = _realSpaceString;
			}
		}
	}
	else
	{
		pt = zafLocale->decimalSeparator;
		//*** cm = zafLocale->thousandsSeparator;
		//*** gp = zafLocale->grouping;
	}

	/*
	 * don't do unrealistic precision; just pad it with
	 * zeroes later, so buffer size stays rational.
	 */
	if (prec > MAXFRACT)
	{
		if (fmtch != 'g' && fmtch != 'G' || (flags & ZAF_ALT))
			fpprec = prec - MAXFRACT;
		prec = MAXFRACT;
	}
	else if (prec == -1)
		prec = DEFPREC;
	/*
	 * cvt may have to round up before the "start" of
	 * its buffer, i.e. ``intf("%.2f", (double)9.999);'';
	 * if the first character is still NUL, it didn't.
	 * softsign avoids negative 0 if _double < 0 but
	 * no significant digits will be shown.
	 */
	ZafIChar buf[350];
	ZafIChar *cp = buf;
	*cp = '\0';
	// cvt counts the teminating '\0'. Keep size from counting the terminating
	// '\0'.
	int size = cvt(_double, prec, flags, &softsign, fmtch,
		       cp, buf + LENGTHOF(buf), pt) - 1;
	if (*cp == '\0')
		cp++;

	int fieldsz = size + fpprec;
	int i;
	if (softsign)
	{
		i = zafLocale->negSignPrecedes;
		t = zafLocale->negativeSign;
		if (flags & ZAF_CREDIT)
			i = 0;
	}
	else
	{
		i = zafLocale->posSignPrecedes;
		if (flags & ZAF_PLUS)
			t = zafLocale->positiveSign;
		else
			t = _realBlankString;
	}
	switch (i)
	{
	case 0:
		if (softsign)
		{
			ps1 = zafLocale->creditLeftParen;
			ss1 = zafLocale->creditRightParen;
		}
		else
		{
			ps1 = ps2 = _realSpaceString;
		}
		break;
	case 1:
		ps1 = t;
		break;
	case 2:
		ss1 = t;
		break;
	case 3:
		ps2 = t;
		break;
	case 4:
		ss2 = t;
		break;
	}
	fieldsz = (int)(fieldsz + strlen(ps1) + strlen(ps2) + strlen(ss1) + strlen(ss2));

	int n;	// Scratch for PAD();
	/* right-adjusting blank padding */
	if ((flags & (ZAF_LADJUST | ZAF_ZEROPAD)) == 0)
		PAD(width - fieldsz, ' ');
	// prefix
	PRINT(ps1, strlen(ps1));
	PRINT(pc, strlen(pc));
	PRINT(ps, strlen(ps));
	PRINT(ps2, strlen(ps2));
	/* right-adjusting zero padding */
	if ((flags & (ZAF_LADJUST | ZAF_ZEROPAD)) == ZAF_ZEROPAD)
		PAD(width - fieldsz, '0');
	/* the string or number proper */
	PRINT(cp, size);
	/* trailing f.p. zeroes */
	PAD(fpprec, '0');
	/* left-adjusting padding (always blank) */
	if (flags & ZAF_LADJUST)
		PAD(width - fieldsz, ' ');
	// postfix
	PRINT(ss2, strlen(ss2));
	PRINT(ss, strlen(ss));
	PRINT(sc, strlen(sc));
	PRINT(ss1, strlen(ss1));
	*buffer = 0;
	*ptrBuffer = buffer;
}

int ZafRealData::Parse(va_list *argList, ZafIChar **ptrBuffer,
	ZafIChar fmtch, int flags, int width, const ZafIChar **fmt)
{
	if (fmtch == 'E')
		flags |= ZAF_LONGVAL;
	else if (fmtch == 'F')
		flags |= ZAF_LONGVAL;
	ZafIChar *buffer = *ptrBuffer;
	ZafIChar buf[BUF];		// buffer for numeric conversions
	/* scan a floating point number as if by strtod */
	if (width == 0 || width > LENGTHOF(buf) - 1)
		width = LENGTHOF(buf) - 1;
	flags |= ZAF_SIGNOK | ZAF_NDIGITS | ZAF_DPTOK | ZAF_EXPOK;
	if ((flags & ZAF_NOSKIP) == 0)
		while (isspace(*buffer))
			buffer++;
	bool sign = false;
	bool paren = false;
	if (*buffer == '(')
	{
		sign = true;
		paren = true;
		buffer++;
	}
	ZafIChar *p;
	for (p = buf; width; width--)
	{
		ZafIChar c = *buffer++;
		/*
		 * This code mimicks the integer conversion
		 * code, but is much simpler.
		 */

		size_t length;
		length = strlen(zafLocale->decimalSeparator);
		if (length > 0 && zafLocale && strncmp(&buffer[-1], zafLocale->decimalSeparator,
			length) == 0)
		{
			buffer += length - 1;
			c = '.';
		}

		length = strlen(zafLocale->positiveSign);
		if (length > 0 && zafLocale && strncmp(&buffer[-1], zafLocale->positiveSign,
			length) == 0)
		{
			buffer += length - 1;
			c = '+';
		}

		length = strlen(zafLocale->negativeSign);
		if (length > 0 && zafLocale && strncmp(&buffer[-1], zafLocale->negativeSign,
			length) == 0)
		{
			buffer += length - 1;
			c = '-';
		}

		switch (c)
		{
		case '0': case '1': case '2': case '3':
		case '4': case '5': case '6': case '7':
		case '8': case '9':
			flags &= ~(ZAF_SIGNOK | ZAF_NDIGITS);
			goto fok;
		case '+': case '-':
			if (flags & ZAF_SIGNOK)
			{
				flags &= ~ZAF_SIGNOK;
				goto fok;
			}
			break;
		case '.':
			if (flags & ZAF_DPTOK)
			{
				flags &= ~(ZAF_SIGNOK | ZAF_DPTOK);
				goto fok;
			}
			break;
		case 'e': case 'E':
			/* no exponent without some digits */
			if ((flags & (ZAF_NDIGITS | ZAF_EXPOK)) == ZAF_EXPOK)
			{
				flags = (flags & ~(ZAF_EXPOK | ZAF_DPTOK)) | ZAF_SIGNOK | ZAF_NDIGITS;
				goto fok;
			}
			break;
		}
		/*
		 * If we got here, c is not a legal character
		 * for a number.  Stop accumulating digits.
		 */
		if (!c || isspace(c) || c == **fmt)
			break;
		else if (c == ')' && paren)
		{
			buffer++;
			break;
		}
		else
			return (-1);
fok:
		*p++ = c;
	}
	/*
	 * If no digits, might be missing exponent digits
	 * (just give back the exponent) or might be missing
	 * regular digits, but had sign and/or decimal point.
	 */
	if (flags & ZAF_NDIGITS)
	{
		if (flags & ZAF_EXPOK)
		{
			/* no digits at all */
//			while (p > buf)
//				*--buffer = *(ZafIChar *)--p;
//			*ptrBuffer = buffer;
			return -1;
		}
		/* just a bad exponent (e and maybe sign) */
		ZafIChar c = *(ZafIChar *)--p;
		if (c != 'e' && c != 'E')
		{
			*--buffer = c;	/* sign */
			c = *(ZafIChar *)--p;
		}
		*--buffer = c;
	}
	if ((flags & ZAF_SUPPRESS) == 0)
	{
		double res;
		*p = 0;
		res = atof(buf);
		if (sign && paren)
			res = -res;
		if (flags & ZAF_OBJ)
		{
			ZafRealData *tmp = va_arg(*argList, ZafRealData *);
			tmp->value = res;
		}
		else if (flags & ZAF_LONGVAL)
			*va_arg(*argList, double *) = res;
		else
			*va_arg(*argList, float *) = (float)res;
		*ptrBuffer = buffer;
		return 1;
	}
	*ptrBuffer = buffer;
	return 0;
}

// ----- Persistent functions -----------------------------------------------
#if defined(USE_ZAF_PERSISTENCE)
static ZafIChar _persistentFormat[] = ZAF_ITEXT("%f");

ZafRealData::ZafRealData(const ZafIChar *name, ZafDataPersistence &persist) :
	ZafFormatData(name, persist.PushLevel(className, classID, ZAF_PERSIST_FILE))
{
	Bind();

	// Read the data.
	if (persist.Error() == ZAF_ERROR_NONE)
		ZafRealData::ReadData(persist);

	persist.PopLevel();
	if (persist.Error() != ZAF_ERROR_NONE)
		SetError(persist.Error());
}

ZafElement *ZafRealData::Read(const ZafIChar *name, ZafDataPersistence &persist)
{
	return (new ZafRealData(name, persist));
}

void ZafRealData::ReadData(ZafDataPersistence &persist)
{
	// Read the data.
	ZafIChar *realString;
	ZafFile *file = persist.CurrentFile();
	*file >> &realString;
	ZafLocaleData *saveLocale = zafLocale;
	zafLocale = zafLocale->canonicalLocale;
	SetReal(realString, _persistentFormat);
	zafLocale = saveLocale;
	delete []realString;
}

void ZafRealData::Write(ZafDataPersistence &persist)
{
	// Write the object.
	ZafFormatData::Write(persist.PushLevel(className, classID, ZAF_PERSIST_FILE));
	if (persist.Error() == ZAF_ERROR_NONE)
		ZafRealData::WriteData(persist);
	persist.PopLevel();
	if (persist.Error() != ZAF_ERROR_NONE)
		SetError(persist.Error());
}

void ZafRealData::WriteData(ZafDataPersistence &persist)
{
	// Write the data.
	ZafIChar realString[32];
	ZafLocaleData *saveLocale = zafLocale;
	zafLocale = zafLocale->canonicalLocale;
	FormattedText(realString, 32, _persistentFormat);
	zafLocale = saveLocale;
	ZafFile *file = persist.CurrentFile();
	*file << realString;
}
#endif
