/*
 *   This program is is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or (at
 *   your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

/** Unix snprintf implementation
 *
 * Version 1.4
 *
 *	 1.4:
 *		*	integrate in FreeRADIUS's libradius:
 *		*	Fetched from: http://savannah.gnu.org/cgi-bin/viewcvs/mailutils/mailutils/lib/snprintf.c?rev=1.4
 *		*	Fetched from: http://savannah.gnu.org/cgi-bin/viewcvs/mailutils/mailutils/lib/snprintf.h?rev=1.4
 *		*	Replace config.h with autoconf.h
 *		*	Protect with HAVE_SNPRINTF and HAVE_VSNPRINTF
 *	 1.3:
 *		*	add #include <config.h> ifdef HAVE_CONFIG_H
 *		*	cosmetic change, when exponent is 0 print xxxE+00
 *	 instead of xxxE-00
 *	 1.2:
 *		*	put the program under LGPL.
 *
 *	 1.1:
 *		*	added changes from Miles Bader
 *		*	corrected a bug with %f
 *		*	added support for %#g
 *		*	added more comments :-)
 *	 1.0:
 *		*	supporting must ANSI syntaxic_sugars
 *	 0.0:
 *		*	support %s %c %d
 *
 * THANKS(for the patches and ideas):
 *		 Miles Bader
 *		 Cyrille Rustom
 *		 Jacek Slabocewiz
 *		 Mike Parker(mouse)
 *
 * @file src/lib/util/snprintf.h
 *
 * @copyright Alain Magloire: alainm@rcsm.ee.mcgill.ca
 */

RCSID("$Id: 3a2dff05c53f9800f37d39e8f34ec9f188535b16 $")

#include <freeradius-devel/util/snprintf.h>

#ifndef HAVE_VSNPRINTF

/*
 * Find the nth power of 10
 */
PRIVATE double
#ifdef __STDC__
pow_10(int n)
#else
pow_10(n)
int n;
#endif
{
	int i;
	double P;

	if (n < 0)
		for (i = 1, P = 1., n = -n ; i <= n ; i++) {P *= .1;}
	else
		for (i = 1, P = 1. ; i <= n ; i++) {P *= 10.0;}
	return P;
}

/*
 * Find the integral part of the log in base 10
 * Note: this not a real log10()
	 I just need and approximation(integerpart) of x in:
		10^x ~= r
 * log_10(200) = 2;
 * log_10(250) = 2;
 */
PRIVATE int
#ifdef __STDC__
log_10(double r)
#else
log_10(r)
double r;
#endif
{
	int i = 0;
	double result = 1.;

	if (r < 0.)
		r = -r;

	if (r < 1.) {
		while (result >= r) {result *= .1; i++;}
		return (-i);
	} else {
		while (result <= r) {result *= 10.; i++;}
		return (i - 1);
	}
}

/*
 * This function return the fraction part of a double
 * and set in ip the integral part.
 * In many ways it resemble the modf() found on most Un*x
 */
PRIVATE double
#ifdef __STDC__
integral(double real, double * ip)
#else
integral(real, ip)
double real;
double * ip;
#endif
{
	int j;
	double i, s, p;
	double real_integral = 0.;

/* take care of the obvious */
/* equal to zero ? */
	if (real == 0.) {
		*ip = 0.;
		return (0.);
	}

/* negative number ? */
	if (real < 0.)
		real = -real;

/* a fraction ? */
	if ( real < 1.) {
		*ip = 0.;
		return real;
	}
/* the real work :-) */
	for (j = log_10(real); j >= 0; j--) {
		p = pow_10(j);
		s = (real - real_integral)/p;
		i = 0.;
		while (i + 1. <= s) {i++;}
		real_integral += i*p;
	}
	*ip = real_integral;
	return (real - real_integral);
}

#define PRECISION 1.e-6
/*
 * return an ascii representation of the integral part of the number
 * and set fract to be an ascii representation of the fraction part
 * the container for the fraction and the integral part or statically
 * declare with fix size
 */
PRIVATE char *
#ifdef __STDC__
numtoa(double number, int base, int precision, char ** fract)
#else
numtoa(number, base, precision, fract)
double number;
int base;
int precision;
char ** fract;
#endif
{
	register int i, j;
	double ip, fp; /* integer and fraction part */
	double fraction;
	int digits = MAX_INT - 1;
	static char integral_part[MAX_INT];
	static char fraction_part[MAX_FRACT];
	double sign;
	int ch;

/* taking care of the obvious case: 0.0 */
	if (number == 0.) {
		integral_part[0] = '0';
		integral_part[1] = '\0';
		fraction_part[0] = '0';
		fraction_part[1] = '\0';
		return integral_part;
	}

/* for negative numbers */
	if ((sign = number) < 0.) {
		number = -number;
		digits--; /* sign consume one digit */
	}

	fraction = integral(number, &ip);
	number = ip;
/* do the integral part */
	if ( ip == 0.) {
		integral_part[0] = '0';
		i = 1;
	} else {
		for ( i = 0; i < digits && number != 0.; ++i) {
			number /= base;
			fp = integral(number, &ip);
			ch = (int)((fp + PRECISION)*base); /* force to round */
			integral_part[i] = (ch <= 9) ? ch + '0' : ch + 'a' - 10;
			if (! isxdigit(integral_part[i])) /* bail out overflow !! */
	break;
			number = ip;
		 }
	}

/* Oh No !! out of bound, ho well fill it up ! */
	if (number != 0.)
		for (i = 0; i < digits; ++i)
			integral_part[i] = '9';

/* put the sign ? */
	if (sign < 0.)
		integral_part[i++] = '-';

	integral_part[i] = '\0';

/* reverse every thing */
	for ( i--, j = 0; j < i; j++, i--)
		SWAP_INT(integral_part[i], integral_part[j]);

/* the fractionnal part */
	for (i=0, fp=fraction; precision > 0 && i < MAX_FRACT ; i++, precision--	) {
		fraction_part[i] = (int)((fp + PRECISION)*10. + '0');
		if (! isdigit(fraction_part[i])) /* underflow ? */
			break;
		fp = (fp*10.0) - (double)(long)((fp + PRECISION)*10.);
	}
	fraction_part[i] = '\0';

	if (fract != (char **)0)
		*fract = fraction_part;

	return integral_part;

}

/* for %d and friends, it puts in holder
 * the representation with the right padding
 */
PRIVATE void
#ifdef __STDC__
float64(struct DATA *p, double d)
#else
float64(p, d)
struct DATA *p;
double d;
#endif
{
	char *tmp;

	tmp = itoa(d);
	p->width -= strlen(tmp);
	PAD_RIGHT(p);
	PUT_PLUS(d, p);
	PUT_SPACE(d, p);
	while (*tmp) { /* the integral */
		PUT_CHAR(*tmp, p);
		tmp++;
	}
	PAD_LEFT(p);
}

/* for %o octal representation */
PRIVATE void
#ifdef __STDC__
octal(struct DATA *p, double d)
#else
octal(p, d)
struct DATA *p;
double d;
#endif
{
	char *tmp;

	tmp = otoa(d);
	p->width -= strlen(tmp);
	PAD_RIGHT(p);
	if (p->square == FOUND) /* had prefix '0' for octal */
		PUT_CHAR('0', p);
	while (*tmp) { /* octal */
		PUT_CHAR(*tmp, p);
		tmp++;
	}
	PAD_LEFT(p);
}

/* for %x %X hexadecimal representation */
PRIVATE void
#ifdef __STDC__
hexa(struct DATA *p, double d)
#else
hexa(p, d)
struct DATA *p;
double d;
#endif
{
	char *tmp;

	tmp = htoa(d);
	p->width -= strlen(tmp);
	PAD_RIGHT(p);
	if (p->square == FOUND) { /* prefix '0x' for hexa */
		PUT_CHAR('0', p); PUT_CHAR(*p->pf, p);
	}
	while (*tmp) { /* hexa */
		PUT_CHAR((*p->pf == 'X' ? toupper((uint8_t) *tmp) : *tmp), p);
		tmp++;
	}
	PAD_LEFT(p);
}

/* %s strings */
PRIVATE void
#ifdef __STDC__
strings(struct DATA *p, char *tmp)
#else
strings(p, tmp)
struct DATA *p;
char *tmp;
#endif
{
	int i;

	i = strlen(tmp);
	if (p->precision != NOT_FOUND) /* the smallest number */
		i = (i < p->precision ? i : p->precision);
	p->width -= i;
	PAD_RIGHT(p);
	while (i-- > 0) { /* put the string */
		PUT_CHAR(*tmp, p);
		tmp++;
	}
	PAD_LEFT(p);
}

/* %f or %g	floating point representation */
PRIVATE void
#ifdef __STDC__
floating(struct DATA *p, double d)
#else
floating(p, d)
struct DATA *p;
double d;
#endif
{
	char *tmp, *tmp2;
	int i;

	DEF_PREC(p);
	d = ROUND(d, p);
	tmp = dtoa(d, p->precision, &tmp2);
	/* calculate the padding. 1 for the dot */
	p->width = p->width -
			((d > 0. && p->justify == RIGHT) ? 1:0) -
			((p->space == FOUND) ? 1:0) -
			strlen(tmp) - p->precision - 1;
	PAD_RIGHT(p);
	PUT_PLUS(d, p);
	PUT_SPACE(d, p);
	while (*tmp) { /* the integral */
		PUT_CHAR(*tmp, p);
		tmp++;
	}
	if (p->precision != 0 || p->square == FOUND)
		PUT_CHAR('.', p);	/* put the '.' */
	if (*p->pf == 'g' || *p->pf == 'G') /* smash the trailing zeros */
		for (i = strlen(tmp2) - 1; i >= 0 && tmp2[i] == '0'; i--)
			 tmp2[i] = '\0';
	for (; *tmp2; tmp2++)
		PUT_CHAR(*tmp2, p); /* the fraction */

	PAD_LEFT(p);
}

/* %e %E %g exponent representation */
PRIVATE void
#ifdef __STDC__
exponent(struct DATA *p, double d)
#else
exponent(p, d)
struct DATA *p;
double d;
#endif
{
	char *tmp, *tmp2;
	int j, i;

	DEF_PREC(p);
	j = log_10(d);
	d = d / pow_10(j);	/* get the Mantissa */
	d = ROUND(d, p);
	tmp = dtoa(d, p->precision, &tmp2);
	/* 1 for unit, 1 for the '.', 1 for 'e|E',
	 * 1 for '+|-', 3 for 'exp' */
	/* calculate how much padding need */
	p->width = p->width -
			 ((d > 0. && p->justify == RIGHT) ? 1:0) -
			 ((p->space == FOUND) ? 1:0) - p->precision - 7;
	PAD_RIGHT(p);
	PUT_PLUS(d, p);
	PUT_SPACE(d, p);
	while (*tmp) {/* the integral */
		PUT_CHAR(*tmp, p);
		tmp++;
	}
	if (p->precision != 0 || p->square == FOUND)
		PUT_CHAR('.', p);	/* the '.' */
	if (*p->pf == 'g' || *p->pf == 'G') /* smash the trailing zeros */
		for (i = strlen(tmp2) - 1; i >= 0 && tmp2[i] == '0'; i--)
			 tmp2[i] = '\0';
	for (; *tmp2; tmp2++)
		PUT_CHAR(*tmp2, p); /* the fraction */

	if (*p->pf == 'g' || *p->pf == 'e') { /* the exponent put the 'e|E' */
		PUT_CHAR('e', p);
	} else
		PUT_CHAR('E', p);
	if (j >= 0) {	/* the sign of the exp */
		PUT_CHAR('+', p);
	} else {
		PUT_CHAR('-', p);
		j = -j;
	}
	tmp = itoa((double)j);
	if (j < 9) {	/* need to pad the exponent with 0 '000' */
		PUT_CHAR('0', p); PUT_CHAR('0', p);
	} else if (j < 99)
		PUT_CHAR('0', p);
	while (*tmp) { /* the exponent */
		PUT_CHAR(*tmp, p);
		tmp++;
	}
	PAD_LEFT(p);
}

/* initialize the conversion specifiers */
PRIVATE void
#ifdef __STDC__
conv_flag(char * s, struct DATA * p)
#else
conv_flag(s, p)
char * s;
struct DATA * p;
#endif
{
	char number[MAX_FIELD/2];
	int i;

	/* reset the flags.	*/
	p->precision = p->width = NOT_FOUND;
	p->star_w = p->star_p = NOT_FOUND;
	p->square = p->space = NOT_FOUND;
	p->a_long = p->justify = NOT_FOUND;
	p->a_longlong = NOT_FOUND;
	p->pad = ' ';

	for(;s && *s ;s++) {
		switch (*s) {
			case ' ': p->space = FOUND; break;
			case '#': p->square = FOUND; break;
			case '*': if (p->width == NOT_FOUND)
			p->width = p->star_w = FOUND;
		else
			p->precision = p->star_p = FOUND;
		break;
			case '+': p->justify = RIGHT; break;
			case '-': p->justify = LEFT; break;
			case '.': if (p->width == NOT_FOUND)
			p->width = 0;
		break;
			case '0': p->pad = '0'; break;
			case '1': case '2': case '3':
			case '4': case '5': case '6':
			case '7': case '8': case '9':		 /* gob all the digits */
	for (i = 0; isdigit((uint8_t) *s); i++, s++)
		if (i < MAX_FIELD/2 - 1)
			number[i] = *s;
	number[i] = '\0';
	if (p->width == NOT_FOUND)
		p->width = atoi(number);
	else
		p->precision = atoi(number);
	s--;	 /* went to far go back */
	break;
		}
	}
}

PUBLIC int
#ifdef __STDC__
vsnprintf(char *string, size_t length, char const * format, va_list args)
#else
vsnprintf(string, length, format, args)
char *string;
size_t length;
char * format;
va_list args;
#endif
{
	struct DATA data;
	char conv_field[MAX_FIELD];
	double d; /* temporary holder */
	int state;
	int i;

	data.length = length - 1; /* leave room for '\0' */
	data.holder = string;
	data.pf = format;
	data.counter = 0;


/* sanity check, the string must be > 1 */
	if (length < 1)
		return -1;


	for (; *data.pf && (data.counter < data.length); data.pf++) {
		if ( *data.pf == '%' ) { /* we got a magic % cookie */
			conv_flag((char *)0, &data); /* initialise format flags */
			for (state = 1; *data.pf && state;) {
	switch (*(++data.pf)) {
		case '\0': /* a NULL here ? ? bail out */
			*data.holder = '\0';
			return data.counter;
			break;
		case 'f':	/* float, double */
			STAR_ARGS(&data);
			if (data.a_long == FOUND)
				 d = va_arg(args, LONG_DOUBLE);
			else
				 d = va_arg(args, double);
			floating(&data, d);
			state = 0;
			break;
		case 'g':
		case 'G':
			STAR_ARGS(&data);
			DEF_PREC(&data);
			if (data.a_long == FOUND)
				 d = va_arg(args, LONG_DOUBLE);
			else
				 d = va_arg(args, double);
			i = log_10(d);
			/*
			 * for '%g|%G' ANSI: use f if exponent
			 * is in the range or [-4,p] exclusively
			 * else use %e|%E
			 */
			if (-4 < i && i < data.precision)
				floating(&data, d);
			else
				exponent(&data, d);
			state = 0;
			break;
		case 'e':
		case 'E':	/* Exponent double */
			STAR_ARGS(&data);
			if (data.a_long == FOUND)
				 d = va_arg(args, LONG_DOUBLE);
			else
				 d = va_arg(args, double);
			exponent(&data, d);
			state = 0;
			break;
		case 'u':	/* unsigned float64 */
			STAR_ARGS(&data);
			if (data.a_longlong == FOUND)
				d = va_arg(args, unsigned LONG_LONG);
			else if (data.a_long == FOUND)
				d = va_arg(args, unsigned long);
			else
				d = va_arg(args, unsigned int);
			float64(&data, d);
			state = 0;
			break;
		case 'd':	/* float64 */
			STAR_ARGS(&data);
			if (data.a_longlong == FOUND)
				d = va_arg(args, LONG_LONG);
			else if (data.a_long == FOUND)
				d = va_arg(args, long);
			else
				d = va_arg(args, int);
			float64(&data, d);
			state = 0;
			break;
		case 'o':	/* octal */
			STAR_ARGS(&data);
			if (data.a_longlong == FOUND)
				d = va_arg(args, LONG_LONG);
			else if (data.a_long == FOUND)
				d = va_arg(args, long);
			else
				d = va_arg(args, int);
			octal(&data, d);
			state = 0;
			break;
		case 'x':
		case 'X':	/* hexadecimal */
			STAR_ARGS(&data);
			if (data.a_longlong == FOUND)
				d = va_arg(args, LONG_LONG);
			else if (data.a_long == FOUND)
				d = va_arg(args, long);
			else
				d = va_arg(args, int);
			hexa(&data, d);
			state = 0;
			break;
		case 'c': /* character */
			d = va_arg(args, int);
			PUT_CHAR(d, &data);
			state = 0;
			break;
		case 's':	/* string */
			STAR_ARGS(&data);
			strings(&data, va_arg(args, char *));
			state = 0;
			break;
		case 'n':
			*(va_arg(args, int *)) = data.counter; /* what's the count ? */
			state = 0;
			break;
		case 'q':
			data.a_longlong = FOUND;
			break;
		case 'L':
		case 'l':
			if (data.a_long == FOUND)
				data.a_longlong = FOUND;
			else
				data.a_long = FOUND;
			break;
		case 'h':
			break;
		case '%':	/* nothing just % */
			PUT_CHAR('%', &data);
			state = 0;
			break;
		case '#': case ' ': case '+': case '*':
		case '-': case '.': case '0': case '1':
		case '2': case '3': case '4': case '5':
		case '6': case '7': case '8': case '9':
		 /* initialize width and precision */
			for (i = 0; isflag(*data.pf); i++, data.pf++)
				if (i < MAX_FIELD - 1)
		conv_field[i] = *data.pf;
			conv_field[i] = '\0';
			conv_flag(conv_field, &data);
			data.pf--;	 /* went to far go back */
			break;
		default:
			/* is this an error ? maybe bail out */
			state = 0;
			break;
	} /* end switch */
			} /* end of for state */
		} else { /* not % */
			PUT_CHAR(*data.pf, &data);	/* add the char the string */
		}
	}

	*data.holder = '\0'; /* the end ye ! */

	return data.counter;
}

#endif /* HAVE_VSNPRINTF */

#ifndef HAVE_SNPRINTF

PUBLIC int
#if __STDC__
snprintf(char *string, size_t length, char const * format, ...)
#else
snprintf(string, length, format, va_alist)
char *string;
size_t length;
char * format;
va_dcl
#endif
{
	int rval;
	va_list args;

#if __STDC__
	va_start(args, format);
#else
	va_start(args);
#endif

	rval = vsnprintf (string, length, format, args);

	va_end(args);

	return rval;
}

#endif /* HAVE_SNPRINTF */


#ifdef DRIVER

#include <stdio.h>

/* set of small tests for snprintf() */
int main()
{
	char holder[100];
	int i;

/*
	printf("Suite of test for snprintf:\n");
	printf("a_format\n");
	printf("printf() format\n");
	printf("snprintf() format\n\n");
*/
/* Checking the field widths */

	printf("/%%d/, 336\n");
	snprintf(holder, sizeof holder, "/%d/\n", 336);
	printf("/%d/\n", 336);
	printf("%s\n", holder);

	printf("/%%2d/, 336\n");
	snprintf(holder, sizeof holder, "/%2d/\n", 336);
	printf("/%2d/\n", 336);
	printf("%s\n", holder);

	printf("/%%10d/, 336\n");
	snprintf(holder, sizeof holder, "/%10d/\n", 336);
	printf("/%10d/\n", 336);
	printf("%s\n", holder);

	printf("/%%-10d/, 336\n");
	snprintf(holder, sizeof holder, "/%-10d/\n", 336);
	printf("/%-10d/\n", 336);
	printf("%s\n", holder);

/* long long	*/

	printf("/%%lld/, 336\n");
	snprintf(holder, sizeof holder, "/%lld/\n", (LONG_LONG)336);
	printf("/%lld/\n", (LONG_LONG)336);
	printf("%s\n", holder);

	printf("/%%2qd/, 336\n");
	snprintf(holder, sizeof holder, "/%2qd/\n", (LONG_LONG)336);
	printf("/%2qd/\n", (LONG_LONG)336);
	printf("%s\n", holder);

/* floating points */

	printf("/%%f/, 1234.56\n");
	snprintf(holder, sizeof holder, "/%f/\n", 1234.56);
	printf("/%f/\n", 1234.56);
	printf("%s\n", holder);

	printf("/%%e/, 1234.56\n");
	snprintf(holder, sizeof holder, "/%e/\n", 1234.56);
	printf("/%e/\n", 1234.56);
	printf("%s\n", holder);

	printf("/%%4.2f/, 1234.56\n");
	snprintf(holder, sizeof holder, "/%4.2f/\n", 1234.56);
	printf("/%4.2f/\n", 1234.56);
	printf("%s\n", holder);

	printf("/%%3.1f/, 1234.56\n");
	snprintf(holder, sizeof holder, "/%3.1f/\n", 1234.56);
	printf("/%3.1f/\n", 1234.56);
	printf("%s\n", holder);

	printf("/%%10.3f/, 1234.56\n");
	snprintf(holder, sizeof holder, "/%10.3f/\n", 1234.56);
	printf("/%10.3f/\n", 1234.56);
	printf("%s\n", holder);

	printf("/%%10.3e/, 1234.56\n");
	snprintf(holder, sizeof holder, "/%10.3e/\n", 1234.56);
	printf("/%10.3e/\n", 1234.56);
	printf("%s\n", holder);

	printf("/%%+4.2f/, 1234.56\n");
	snprintf(holder, sizeof holder, "/%+4.2f/\n", 1234.56);
	printf("/%+4.2f/\n", 1234.56);
	printf("%s\n", holder);

	printf("/%%010.2f/, 1234.56\n");
	snprintf(holder, sizeof holder, "/%010.2f/\n", 1234.56);
	printf("/%010.2f/\n", 1234.56);
	printf("%s\n", holder);

#define BLURB "Outstanding acting !"
/* strings precisions */

	printf("/%%2s/, \"%s\"\n", BLURB);
	snprintf(holder, sizeof holder, "/%2s/\n", BLURB);
	printf("/%2s/\n", BLURB);
	printf("%s\n", holder);

	printf("/%%22s/ %s\n", BLURB);
	snprintf(holder, sizeof holder, "/%22s/\n", BLURB);
	printf("/%22s/\n", BLURB);
	printf("%s\n", holder);

	printf("/%%22.5s/ %s\n", BLURB);
	snprintf(holder, sizeof holder, "/%22.5s/\n", BLURB);
	printf("/%22.5s/\n", BLURB);
	printf("%s\n", holder);

	printf("/%%-22.5s/ %s\n", BLURB);
	snprintf(holder, sizeof holder, "/%-22.5s/\n", BLURB);
	printf("/%-22.5s/\n", BLURB);
	printf("%s\n", holder);

/* see some flags */

	printf("%%x %%X %%#x, 31, 31, 31\n");
	snprintf(holder, sizeof holder, "%x %X %#x\n", 31, 31, 31);
	printf("%x %X %#x\n", 31, 31, 31);
	printf("%s\n", holder);

	printf("**%%d**%% d**%% d**, 42, 42, -42\n");
	snprintf(holder, sizeof holder, "**%d**% d**% d**\n", 42, 42, -42);
	printf("**%d**% d**% d**\n", 42, 42, -42);
	printf("%s\n", holder);

/* other flags */

	printf("/%%g/, 31.4\n");
	snprintf(holder, sizeof holder, "/%g/\n", 31.4);
	printf("/%g/\n", 31.4);
	printf("%s\n", holder);

	printf("/%%.6g/, 31.4\n");
	snprintf(holder, sizeof holder, "/%.6g/\n", 31.4);
	printf("/%.6g/\n", 31.4);
	printf("%s\n", holder);

	printf("/%%.1G/, 31.4\n");
	snprintf(holder, sizeof holder, "/%.1G/\n", 31.4);
	printf("/%.1G/\n", 31.4);
	printf("%s\n", holder);

	printf("abc%%n\n");
	printf("abc%n", &i); printf("%d\n", i);
	snprintf(holder, sizeof holder, "abc%n", &i);
	printf("%s", holder); printf("%d\n\n", i);

	printf("%%*.*s --> 10.10\n");
	snprintf(holder, sizeof holder, "%*.*s\n", 10, 10, BLURB);
	printf("%*.*s\n", 10, 10, BLURB);
	printf("%s\n", holder);

	printf("%%%%%%%%\n");
	snprintf(holder, sizeof holder, "%%%%\n");
	printf("%%%%\n");
	printf("%s\n", holder);

#define BIG "Hello this is a too big string for the buffer"
/*	printf("A buffer to small of 10, trying to put this:\n");*/
	printf("<%%>, %s\n", BIG);
	i = snprintf(holder, 10, "%s\n", BIG);
	printf("<%s>\n", BIG);
	printf("<%s>\n", holder);

	return 0;
}
#endif /* !DRIVER */
