/*
 * vsprintf - print formatted output without ellipsis on an array
 */
/* $Header$ */

//#include  "stdio.h"
//#include  <stdarg.h>

typedef unsigned size_t;

typedef struct
{
  char *_ptr;
  unsigned _count;
}__str;


#define va_start(v,l) __builtin_va_start(v,l)
#define va_end(v)	__builtin_va_end(v)
#define va_arg(v,l)	__builtin_va_arg(v,l)
#if !defined(__STRICT_ANSI__) || __STDC_VERSION__ + 0 >= 199900L
#define va_copy(d,s)	__builtin_va_copy(d,s)
#endif
#define __va_copy(d,s)	__builtin_va_copy(d,s)

typedef __builtin_va_list __gnuc_va_list;
typedef __gnuc_va_list va_list;

#define arg(x) va_arg (ap, u32)

#define	io_testflag(p,x)	((p)->_flags & (x))

char *_i_compute(unsigned long val, int base, char *s, int nrdigits);
char *_f_print(va_list *ap, int flags, char *s, char c, int precision);
void __cleanup(void);


void *calloc( size_t num, size_t size );
int memcmp(const void *s1, const void *s2, size_t n);
void * memcpy(void * _dest, const void *_src, size_t _n);
char * strcpy(char *to, const char *from);
char * strcat(char *s, const char *append);
int strcmp(const char *s1, const char *s2);
size_t strlen(const char *str);
char * strdup(const char *_s);
char * strchr(const char *s, int c);


#define	FL_LJUST	0x0001		/* left-justify field */
#define	FL_SIGN		0x0002		/* sign in signed conversions */
#define	FL_SPACE	0x0004		/* space in signed conversions */
#define	FL_ALT		0x0008		/* alternate form */
#define	FL_ZEROFILL	0x0010		/* fill with zero's */
#define	FL_SHORT	0x0020		/* optional h */
#define	FL_LONG		0x0040		/* optional l */
#define	FL_LONGDOUBLE	0x0080		/* optional L */
#define	FL_WIDTHSPEC	0x0100		/* field width is specified */
#define	FL_PRECSPEC	0x0200		/* precision is specified */
#define FL_SIGNEDCONV	0x0400		/* may contain a sign */
#define	FL_NOASSIGN	0x0800		/* do not assign (in scanf) */
#define FL_NOMORE 0x1000    /* all flags collected */

#define	_IOFBF		0x000
#define	_IOREAD		0x001
#define	_IOWRITE	0x002
#define	_IONBF		0x004
#define	_IOMYBUF	0x008
#define	_IOEOF		0x010
#define	_IOERR		0x020
#define	_IOLBF		0x040
#define	_IOREADING	0x080
#define	_IOWRITING	0x100
#define	_IOAPPEND	0x200
#define _IOFIFO		0x400

#define SGL_MAX      254  /*  standard definition */
#define	SGL_MIN		     1	/*	standard definition	*/
#define	DBL_MAX		  2046	/*	standard definition	*/
#define	DBL_MIN		     1	/*	standard definition	*/
#define EXT_MAX		 16383	/*	standard minimum	*/
#define EXT_MIN   -16382  /*  standard minimum  */
#include	<limits.h>

static char *cvt();
#define NDIGITS	128

unsigned char __dj_ctype_toupper[] = {
  0x00,
  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
  0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
  0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
  0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
  0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
  0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
  0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
  0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
  0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
  0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
  0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
  0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
  0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
  0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
  0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
  0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
  0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
  0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
  0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
  0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
  0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
  0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
  0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
  0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
  0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
  0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
  0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
  0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
  0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
  0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
  0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
  0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
};
#define toupper(c) (__dj_ctype_toupper[(int)(c)+1])

int (toupper)(int c)
{
  return toupper(c);
}

char *
_ecvt(value, ndigit, decpt, sign)
	double value;
	int ndigit, *decpt, *sign;
{
	return cvt(value, ndigit, decpt, sign, 1);
}

char *
_fcvt(value, ndigit, decpt, sign)
	double value;
	int ndigit, *decpt, *sign;
{
	return cvt(value, ndigit, decpt, sign, 0);
}

static struct powers_of_10 {
	double pval;
	double rpval;
	int exp;
} p10[] = {
	1.0e32, 1.0e-32, 32,
	1.0e16, 1.0e-16, 16,
	1.0e8, 1.0e-8, 8,
	1.0e4, 1.0e-4, 4,
	1.0e2, 1.0e-2, 2,
	1.0e1, 1.0e-1, 1,
	1.0e0, 1.0e0, 0
};

static char *
cvt(value, ndigit, decpt, sign, ecvtflag)
	double value;
	int ndigit, *decpt, *sign;
{
	static char buf[NDIGITS+1];
	register char *p = buf;
	register char *pe;

	if (ndigit < 0) ndigit = 0;
	if (ndigit > NDIGITS) ndigit = NDIGITS;
	pe = &buf[ndigit];
	buf[0] = '\0';

	*sign = 0;
	if (value < 0) {
		*sign = 1;
		value = -value;
	}

	*decpt = 0;
	if (value >= DBL_MAX) {
		value = DBL_MAX;
	}
	if (value != 0.0) {
		register struct powers_of_10 *pp = &p10[0];

		if (value >= 10.0) do {
			while (value >= pp->pval) {
				value *= pp->rpval;
				*decpt += pp->exp;
			}
		} while ((++pp)->exp > 0);

		pp = &p10[0];
		if (value < 1.0) do {
			while (value * pp->pval < 10.0) {
				value *= pp->pval;
				*decpt -= pp->exp;
			}
		} while ((++pp)->exp > 0);

		(*decpt)++;	/* because now value in [1.0, 10.0) */
	}
	if (! ecvtflag) {
		/* for fcvt() we need ndigit digits behind the dot */
		pe += *decpt;
		if (pe > &buf[NDIGITS]) pe = &buf[NDIGITS];
	}
	while (p <= pe) {
		*p++ = (int)value + '0';
		value = 10.0 * (value - (int)value);
	}
	if (pe >= buf) {
		p = pe;
		*p += 5;	/* round of at the end */
		while (*p > '9') {
			*p = '0';
			if (p > buf) ++*--p;
			else {
				*p = '1';
				++*decpt;
				if (! ecvtflag) {
					/* maybe add another digit at the end,
					   because the point was shifted right
					*/
					if (pe > buf) *pe = '0';
					pe++;
				}
			}
		}
		*pe = '\0';
	}
	return buf;
}


int _fp_hook = 1;

static char *
_pfloat(double r, register char *s, int n, int flags)
{
	register char *s1;
	int sign, dp;
	register int i;

	s1 = _fcvt(r, n, &dp, &sign);
	if (sign)
		*s++ = '-';
	else if (flags & FL_SIGN)
		*s++ = '+';
	else if (flags & FL_SPACE)
		*s++ = ' ';

	if (dp<=0)
		*s++ = '0';
	for (i=dp; i>0; i--)
		if (*s1) *s++ = *s1++;
		else *s++ = '0';
	if (((i=n) > 0) || (flags & FL_ALT))
		*s++ = '.';
	while (++dp <= 0) {
		if (--i<0)
			break;
		*s++ = '0';
	}
	while (--i >= 0)
		if (*s1) *s++ = *s1++;
		else *s++ = '0';
	return s;
}

static char *
_pscien(double r, register char *s, int n, int flags)
{
	int sign, dp;
	register char *s1;

	s1 = _ecvt(r, n + 1, &dp, &sign);
	if (sign)
		*s++ = '-';
	else if (flags & FL_SIGN)
		*s++ = '+';
	else if (flags & FL_SPACE)
		*s++ = ' ';

	*s++ = *s1++;
	if ((n > 0) || (flags & FL_ALT))
		*s++ = '.';
	while (--n >= 0)
		if (*s1) *s++ = *s1++;
		else *s++ = '0';
	*s++ = 'e';
	if ( r != 0 ) --dp ;
	if ( dp<0 ) {
		*s++ = '-' ; dp= -dp ;
	} else {
		*s++ = '+' ;
	}
	if (dp >= 100) {
		*s++ = '0' + (dp / 100);
		dp %= 100;
	}
	*s++ = '0' + (dp/10);
	*s++ = '0' + (dp%10);
	return s;
}

#define	NDIGINEXP(exp)		(((exp) >= 100 || (exp) <= -100) ? 3 : 2)
#define	LOW_EXP			-4
#define	USE_EXP(exp, ndigits)	(((exp) < LOW_EXP + 1) || (exp >= ndigits + 1))

static char *
_gcvt(double value, int ndigit, char *s, int flags)
{
	int sign, dp;
	register char *s1, *s2;
	register int i;
	register int nndigit = ndigit;

	s1 = _ecvt(value, ndigit, &dp, &sign);
	s2 = s;
	if (sign) *s2++ = '-';
	else if (flags & FL_SIGN)
		*s2++ = '+';
	else if (flags & FL_SPACE)
		*s2++ = ' ';

	if (!(flags & FL_ALT))
		for (i = nndigit - 1; i > 0 && s1[i] == '0'; i--)
			nndigit--;

	if (USE_EXP(dp,ndigit))	{
		/* Use E format */
		dp--;
		*s2++ = *s1++;
		if ((nndigit > 1) || (flags & FL_ALT)) *s2++ = '.';
		while (--nndigit > 0) *s2++ = *s1++;
		*s2++ = 'e';
		if (dp < 0) {
			*s2++ = '-';
			dp = -dp;
		}
		else	 *s2++ = '+';
		s2 += NDIGINEXP(dp);
		*s2 = 0;
		for (i = NDIGINEXP(dp); i > 0; i--) {
			*--s2 = dp % 10 + '0';
			dp /= 10;
		}
		return s;
	}
	/* Use f format */
	if (dp <= 0) {
		if (*s1 != '0')	{
			/* otherwise the whole number is 0 */
			*s2++ = '0';
			*s2++ = '.';
		}
		while (dp < 0) {
			dp++;
			*s2++ = '0';
		}
	}
	for (i = 1; i <= nndigit; i++) {
		*s2++ = *s1++;
		if (i == dp) *s2++ = '.';
	}
	if (i <= dp) {
		while (i++ <= dp) *s2++ = '0';
		*s2++ = '.';
	}
	if ((s2[-1]=='.') && !(flags & FL_ALT)) s2--;
	*s2 = '\0';
	return s;
}

char *
_f_print(va_list *ap, int flags, char *s, char c, int precision)
{
	register char *old_s = s;
  double ld_val;

 // if (flags & FL_LONGDOUBLE) ld_val = va_arg(*ap, double);
//  else
   ld_val = (double) va_arg(*ap, double);

	switch(c) {
	case 'f':
		s = _pfloat(ld_val, s, precision, flags);
		break;
	case 'e':
	case 'E':
		s = _pscien(ld_val, s, precision , flags);
		break;
	case 'g':
	case 'G':
		s = _gcvt(ld_val, precision, s, flags);
		s += strlen(s);
		break;
	}
	if ( c == 'E' || c == 'G') {
		while (*old_s && *old_s != 'e') old_s++;
		if (*old_s == 'e') *old_s = 'E';
	}
	return s;
}

//#endif  /* NOFLOAT */
/* $Header$ */

//#include <stdlib.h>
//#include "../ansi/ext_fmt.h"

//void _str_ext_cvt(const char *s, char **ss, struct EXTEND *e);
//double _ext_dbl_cvt(struct EXTEND *e);

//double
//strtod(const char *p, char **pp)
//{
//  struct EXTEND e;

//  _str_ext_cvt(p, pp, &e);
//  return _ext_dbl_cvt(&e);
//}

#define BUFSIZ    4096
#define	NULL		((void *)0)
#define	EOF		(-1)


/* gnum() is used to get the width and precision fields of a format. */
static const char *
gnum(register const char *f, int *ip, va_list *app)
{
	register int	i, c;

	if (*f == '*') {
		*ip = va_arg((*app), int);
		f++;
	} else {
		i = 0;
		while ((c = *f - '0') >= 0 && c <= 9) {
			i = i*10 + c;
			f++;
		}
		*ip = i;
	}
	return f;
}

#if	_EM_WSIZE == _EM_PSIZE
#define set_pointer(flags)				/* nothing */
#elif	_EM_LSIZE == _EM_PSIZE
#define set_pointer(flags)	(flags |= FL_LONG)
#else
#error garbage pointer size
#define set_pointer(flags)		/* compilation might continue */
#endif

/* print an ordinal number */
static char *
o_print(va_list *ap, int flags, char *s, char c, int precision, int is_signed)
{
	long signed_val;
	unsigned long unsigned_val;
	char *old_s = s;
	int base;

	switch (flags & (FL_SHORT | FL_LONG)) {
	case FL_SHORT:
		if (is_signed) {
			signed_val = (short) va_arg(*ap, int);
		} else {
			unsigned_val = (unsigned short) va_arg(*ap, unsigned);
		}
		break;
	case FL_LONG:
		if (is_signed) {
			signed_val = va_arg(*ap, long);
		} else {
			unsigned_val = va_arg(*ap, unsigned long);
		}
		break;
	default:
		if (is_signed) {
			signed_val = va_arg(*ap, int);
		} else {
			unsigned_val = va_arg(*ap, unsigned int);
		}
		break;
	}

	if (is_signed) {
		if (signed_val < 0) {
			*s++ = '-';
			signed_val = -signed_val;
		} else if (flags & FL_SIGN) *s++ = '+';
		else if (flags & FL_SPACE) *s++ = ' ';
		unsigned_val = signed_val;
	}
	if ((flags & FL_ALT) && (c == 'o')) *s++ = '0';
	if (!unsigned_val && c != 'p') {
		 if (!precision)
			return s;
	} else if (((flags & FL_ALT) && (c == 'x' || c == 'X'))
		    || c == 'p') {
		*s++ = '0';
		*s++ = (c == 'X' ? 'X' : 'x');
	}

	switch (c) {
	case 'b':	base = 2;	break;
	case 'o':	base = 8;	break;
	case 'd':
	case 'i':
	case 'u':	base = 10;	break;
	case 'x':
	case 'X':
	case 'p':	base = 16;	break;
	}

	s = _i_compute(unsigned_val, base, s, precision);

	if (c == 'X')
		while (old_s != s) {
			*old_s = toupper(*old_s);
			old_s++;
		}

	return s;
}


#define putc(c, p)  (--(p)->_count >= 0 ?  (int) (*(p)->_ptr++ = (c)) : EOF)

int
_doprnt(register const char *fmt, va_list ap, __str *stream)
{
	register char	*s;
	register int	j;
	int		i, c, width, precision, zfill, flags, between_fill;
	int		nrchars=0;
	const char	*oldfmt;
  char    *s1, buf[512];

  while (c = *fmt++)
  {
    if (c != '%')
    {
      if (c == '\n')
      {
				if (putc('\r', stream) == EOF)
					return nrchars ? -nrchars : -1;
				nrchars++;
      }
			if (putc(c, stream) == EOF)
				return nrchars ? -nrchars : -1;
			nrchars++;
			continue;
		}
		flags = 0;
		do {
			switch(*fmt) {
			case '-':	flags |= FL_LJUST;	break;
			case '+':	flags |= FL_SIGN;	break;
			case ' ':	flags |= FL_SPACE;	break;
			case '#':	flags |= FL_ALT;	break;
			case '0':	flags |= FL_ZEROFILL;	break;
			default:	flags |= FL_NOMORE;	continue;
			}
			fmt++;
		} while(!(flags & FL_NOMORE));

		oldfmt = fmt;
		fmt = gnum(fmt, &width, &ap);
		if (fmt != oldfmt) flags |= FL_WIDTHSPEC;

		if (*fmt == '.') {
			fmt++; oldfmt = fmt;
			fmt = gnum(fmt, &precision, &ap);
			if (precision >= 0) flags |= FL_PRECSPEC;
		}

		if ((flags & FL_WIDTHSPEC) && width < 0) {
			width = -width;
			flags |= FL_LJUST;
		}
		if (!(flags & FL_WIDTHSPEC)) width = 0;

		if (flags & FL_SIGN) flags &= ~FL_SPACE;

		if (flags & FL_LJUST) flags &= ~FL_ZEROFILL;


		s = s1 = buf;

		switch (*fmt) {
		case 'h':	flags |= FL_SHORT; fmt++; break;
		case 'l':	flags |= FL_LONG; fmt++; break;
		case 'L':	flags |= FL_LONGDOUBLE; fmt++; break;
		}

		switch (c = *fmt++) {
		default:
      if (c == '\n') {
				if (putc('\r', stream) == EOF)
					return nrchars ? -nrchars : -1;
				nrchars++;
			}
			if (putc(c, stream) == EOF)
				return nrchars ? -nrchars : -1;
			nrchars++;
			continue;
		case 'n':
			if (flags & FL_SHORT)
				*va_arg(ap, short *) = (short) nrchars;
			else if (flags & FL_LONG)
				*va_arg(ap, long *) = (long) nrchars;
			else
				*va_arg(ap, int *) = (int) nrchars;
			continue;
		case 's':
			s1 = va_arg(ap, char *);
			if (s1 == NULL)
				s1 = "(null)";
			s = s1;
			while (precision || !(flags & FL_PRECSPEC)) {
				if (*s == '\0')
					break;
				s++;
				precision--;
			}
			break;
		case 'p':
			set_pointer(flags);
			/* fallthrough */
		case 'b':
		case 'o':
		case 'u':
		case 'x':
		case 'X':
			if (!(flags & FL_PRECSPEC)) precision = 1;
			else if (c != 'p') flags &= ~FL_ZEROFILL;
			s = o_print(&ap, flags, s, c, precision, 0);
			break;
		case 'd':
		case 'i':
			flags |= FL_SIGNEDCONV;
			if (!(flags & FL_PRECSPEC)) precision = 1;
			else flags &= ~FL_ZEROFILL;
			s = o_print(&ap, flags, s, c, precision, 1);
			break;
		case 'c':
			*s++ = va_arg(ap, int);
			break;

		case 'G':
		case 'g':
			if ((flags & FL_PRECSPEC) && (precision == 0))
				precision = 1;
		case 'f':
		case 'E':
		case 'e':
			if (!(flags & FL_PRECSPEC))
				precision = 6;

			if (precision >= sizeof(buf))
				precision = sizeof(buf) - 1;

			flags |= FL_SIGNEDCONV;
			s = _f_print(&ap, flags, s, c, precision);
			break;
    case 'r':
			ap = va_arg(ap, va_list);
			fmt = va_arg(ap, char *);
			continue;
		}
		zfill = ' ';
		if (flags & FL_ZEROFILL) zfill = '0';
		j = s - s1;

		/* between_fill is true under the following conditions:
		 * 1- the fill character is '0'
		 * and
		 * 2a- the number is of the form 0x... or 0X...
		 * or
		 * 2b- the number contains a sign or space
		 */
		between_fill = 0;
		if ((flags & FL_ZEROFILL)
		    && (((c == 'x' || c == 'X') && (flags & FL_ALT) && j > 1)
			|| (c == 'p')
			|| ((flags & FL_SIGNEDCONV)
			    && ( *s1 == '+' || *s1 == '-' || *s1 == ' '))))
			between_fill++;

		if ((i = width - j) > 0)
			if (!(flags & FL_LJUST)) {	/* right justify */
				nrchars += i;
				if (between_fill) {
				    if (flags & FL_SIGNEDCONV) {
					j--; nrchars++;
					if (putc(*s1++, stream) == EOF)
						return nrchars ? -nrchars : -1;
				    } else {
					j -= 2; nrchars += 2;
					if ((putc(*s1++, stream) == EOF)
					    || (putc(*s1++, stream) == EOF))
						return nrchars ? -nrchars : -1;
				    }
				}
				do {
					if (putc(zfill, stream) == EOF)
						return nrchars ? -nrchars : -1;
				} while (--i);
			}

		nrchars += j;
		while (--j >= 0) {
			if (putc(*s1++, stream) == EOF)
				return nrchars ? -nrchars : -1;
		}

		if (i > 0) nrchars += i;
		while (--i >= 0)
			if (putc(zfill, stream) == EOF)
				return nrchars ? -nrchars : -1;
	}
	return nrchars;
}

int
vsnprintf(char *s, size_t n, const char *format, va_list arg)
{
	int retval;
  __str tmp_stream;

  //tmp_stream._buf    = (unsigned char *) s;
	tmp_stream._ptr    = (unsigned char *) s;
	tmp_stream._count  = n-1;

	retval = _doprnt(format, arg, &tmp_stream);
	tmp_stream._count  = 1;
	putc('\0',&tmp_stream);

	return retval;
}

int
vsprintf(char *s, const char *format, va_list arg)
{
	return vsnprintf(s, INT_MAX, format, arg);
}