/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */

#include <stdarg.h>
#include "format.h"

/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
int format(int (* copyfunc)(void *, char *, int), void *cfarg, int len, char *fmt, va_list args)
{
	int	res,
		written,
		n,
		val;

	char	*ptr,
		*optr,
		buf[64];



#define FALSE 0
#define TRUE (!FALSE)
	
	int	width;


	char	c;
	int 	signed_flag,
		long_flag;

	int	int_val;
	unsigned int
		uint_val;
	long	long_val;
	unsigned long 
		ulong_val;


	written = 0;
	while (*fmt)
	{
		while ((*fmt) && (*fmt != '%'))
		{
			res = (*copyfunc)(cfarg, fmt, 1);
			if (res != 1)
			{	goto finish;
			}

			written += res;
			fmt++;
		}

	
		signed_flag = TRUE;
		long_flag = FALSE;
		
		if (*fmt == '%')
		{
			fmt++;

			width = 0;
			while ((*fmt > '0') && (*fmt < '9'))
			{
				width *= 10;
				width += (*fmt - '0');

				fmt++;
			}

			if (*fmt == 'l')
			{	long_flag = TRUE;
				fmt++;
			}


			switch (*fmt)
			{
				case 'c':
					c = (char)(va_arg(args, int));

					res = (*copyfunc)(cfarg, &c, 1);
					if (res != 1)
					{	goto finish;
					}

					written += res;
					break;

				case 's':
					ptr = (char *)(va_arg(args, int));

					optr = ptr;
					n    = 0;

					while(*ptr++)
					{	n++;
					}

					res = (*copyfunc)(cfarg, optr, n);
					if (res != n)
					{	goto finish;
					}

					written += res;
					break;

/* %d    int               */
/* %ld   long int          */
/* %u    unsigned int      */
/* %lu   unsigned long int */

				case 'u':
					signed_flag = FALSE;
				case 'd':
					optr = &buf[64];


					if (long_flag)
					{
						if (signed_flag)
						{	long_val = va_arg(args, long);

							do
							{	*--optr = '0' + (long_val % 10);
								long_val = long_val / 10;
	
							} while (long_val);
						}
						else
						{	ulong_val = (unsigned long)va_arg(args, long);

							do
							{	*--optr = '0' + (ulong_val % 10);
								ulong_val = ulong_val / 10;
	
							} while (ulong_val);
						}
					}
					else
					{
						if (signed_flag)
						{	int_val = va_arg(args, int);
						
							do
							{	*--optr = '0' + (int_val % 10);
								int_val = int_val / 10;
	
							} while (int_val);
						}
						else
						{	uint_val = (unsigned int)va_arg(args, int);

							do
							{	*--optr = '0' + (uint_val % 10);
								uint_val = uint_val / 10;
	
							} while (uint_val);
						}
					}
	
					res = (*copyfunc)(cfarg, optr, (&buf[64] - optr));
					if (res != (&buf[64] - optr))
					{	goto finish;
					}

					written += res;
					break;

				case '%':

					res = (*copyfunc)(cfarg, "%", 1);
					if (res != 1)
					{	goto finish;
					}

					written += res;
					break;

				default:

			}

			fmt++;
		}
	}

	res = (*copyfunc)(cfarg, "", 1);
	if (res != 1)
	{	goto finish;
	}

finish:
	written += res;
	return written;
}

