/*
 * 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.
 */

/*
 * Copyright (c) 2012 ARM Ltd
 * All rights reserved.
 *
 * 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. The name of the company may not be used to endorse or promote
 *    products derived from this software without specific prior written
 *    permission.
 *
 * THIS SOFTWARE IS PROVIDED BY ARM LTD ``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 ARM LTD 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.
 */

#ifndef VFPRINTF_LOCAL
#define VFPRINTF_LOCAL

#ifndef NO_FLOATING_POINT
# define FLOATING_POINT
#endif

#define _NO_POS_ARGS
#undef _WANT_IO_C99_FORMATS

/* Currently a test is made to see if long double processing is warranted.
   This could be changed in the future should the _ldtoa_r code be
   preferred over _dtoa_r.  */
#define _NO_LONGDBL

#define _NO_LONGLONG

#define _PRINTF_FLOAT_TYPE double

#if defined (FLOATING_POINT)
# include <locale.h>
#endif
#ifdef FLOATING_POINT
# include <math.h>

/* For %La, an exponent of 15 bits occupies the exponent character, a
   sign, and up to 5 digits.  */
# define MAXEXPLEN		7
# define DEFPREC		6

extern char *_dtoa_r _PARAMS((struct _reent *, double, int,
			      int, int *, int *, char **));

# define _DTOA_R _dtoa_r
# define FREXP frexp

#endif /* FLOATING_POINT */

/* BUF must be big enough for the maximum %#llo (assuming long long is
   at most 64 bits, this would be 23 characters), the maximum
   multibyte character %C, and the maximum default precision of %La
   (assuming long double is at most 128 bits with 113 bits of
   mantissa, this would be 29 characters).  %e, %f, and %g use
   reentrant storage shared with mprec.  All other formats that use
   buf get by with fewer characters.  Making BUF slightly bigger
   reduces the need for malloc in %.*a and %S, when large precision or
   long strings are processed.
   The bigger size of 100 bytes is used on systems which allow number
   strings using the locale's grouping character.  Since that's a multibyte
   value, we should use a conservative value.
   */
#define	BUF		40

#define quad_t long
#define u_quad_t unsigned long

typedef quad_t * quad_ptr_t;
typedef _PTR     void_ptr_t;
typedef char *   char_ptr_t;
typedef long *   long_ptr_t;
typedef int  *   int_ptr_t;
typedef short *  short_ptr_t;

/*
 * Macros for converting digits to letters and vice versa
 */
#define	to_digit(c)	((c) - '0')
#define is_digit(c)	((unsigned)to_digit (c) <= 9)
#define	to_char(n)	((n) + '0')

/*
 * Flags used during conversion.
 */
#define	ALT		0x001		/* alternate form */
#define	LADJUST		0x002		/* left adjustment */
#define	ZEROPAD		0x004		/* zero (as opposed to blank) pad */
#define PLUSSGN		0x008		/* plus sign flag */
#define SPACESGN	0x010		/* space flag */
#define	HEXPREFIX	0x020		/* add 0x or 0X prefix */
#define	SHORTINT	0x040		/* short integer */
#define	LONGINT		0x080		/* long integer */
#define	LONGDBL		0x100		/* long double */
/* ifdef _NO_LONGLONG, make QUADINT equivalent to LONGINT, so
 * that %lld behaves the same as %ld, not as %d, as expected if:
 * sizeof (long long) = sizeof long > sizeof int  */
#define QUADINT		LONGINT
#define FPT		0x400		/* Floating point number */
/* define as 0, to make SARG and UARG occupy fewer instructions  */
# define CHARINT	0

/* Macros to support positional arguments */
#define GET_ARG(n, ap, type) (va_arg ((ap), type))

/*
 * To extend shorts properly, we need both signed and unsigned
 * argument extraction methods. Also they should be used in vfprintf_i.c
 * and vfprintf_float.c only, since ap is a pointer to va_list.
 */
#define	SARG(flags) \
	(flags&LONGINT ? GET_ARG (N, (*ap), long) : \
	    flags&SHORTINT ? (long)(short)GET_ARG (N, (*ap), int) : \
	    flags&CHARINT ? (long)(signed char)GET_ARG (N, (*ap), int) : \
	    (long)GET_ARG (N, (*ap), int))
#define	UARG(flags) \
	(flags&LONGINT ? GET_ARG (N, (*ap), u_long) : \
	    flags&SHORTINT ? (u_long)(u_short)GET_ARG (N, (*ap), int) : \
	    flags&CHARINT ? (u_long)(unsigned char)GET_ARG (N, (*ap), int) : \
	    (u_long)GET_ARG (N, (*ap), u_int))

/*
 * BEWARE, these `goto error' on error. And they are used
 * in more than one functions.
 *
 * Following macros are each referred about twice in printf for integer,
 * so it is not worth to rewrite them into functions. This situation may
 * change in the future.
 */
#define PRINT(ptr, len) {		\
	int temp_i = 0;			\
	while (temp_i < (len))		\
	{				\
		if (pfunc (data, (ptr)[temp_i], fp) == EOF) \
			goto error;	\
		temp_i++;		\
	}				\
}

#define PAD(howmany, ch) {		\
	int temp_i = 0;			\
	while (temp_i < (howmany))	\
	{				\
		if (pfunc (data, (ch), fp) == EOF) \
			goto error;	\
		temp_i++;		\
	}				\
}
#define PRINTANDPAD(p, ep, len, ch) {	\
	int temp_n = (ep) - (p);	\
	if (temp_n > (len))		\
		temp_n = (len);		\
	if (temp_n > 0)			\
		PRINT((p), temp_n);	\
	PAD((len) - (temp_n > 0 ? temp_n : 0), (ch)); \
}

/* All data needed to decode format string are kept in below struct. */
struct _prt_data_t
{
	int flags;			/* flags */
	int prec;			/* precision */
	int dprec;			/* decimal precision */
	int width;			/* width */
	int size;			/* size of converted field or string */
	int ret;			/* return value accumulator */
	char code;			/* current conversion specifier */
	char blank;			/* blank character */
	char zero;			/* zero character */
	char buf[BUF];			/* output buffer for non-floating point number. */
	char l_buf[3];			/* sign&hex_prefix, "+/-" and "0x/X" */
#ifdef FLOATING_POINT
	_PRINTF_FLOAT_TYPE _double_;			/* double value */
	char expstr[MAXEXPLEN];		/* buffer for exponent string */
	int lead;			/* sig figs before decimal or group sep */
#endif
};

extern int
_printf_common (struct _reent *data,
		struct _prt_data_t *pdata,
		int *realsz,
		FILE *fp,
		int (*pfunc)(struct _reent *, int, FILE *));

extern int
_printf_i (struct _reent *data, struct _prt_data_t *pdata, FILE *fp, 
	   int (*pfunc)(struct _reent *, int, FILE *), va_list *ap);

/* Make _printf_float weak symbol, so it won't be linked in if target program 
 * does not need it.  */
extern int 
_printf_float (struct _reent *data,
	       struct _prt_data_t *pdata,
	       FILE *fp,
	       int (*pfunc)(struct _reent *, int, FILE *),
	       va_list *ap) __attribute__ ((weak));
#endif
