//-----------------------------------------------
//-・ス@MicroMonitor-PC				-
//-	・スt・スH・ス[・ス}・スb・スg・スo・スヘ擾ソス・ス・ス			-
//-	printf・スフサ・スu・スZ・スb・スg・スナゑソス・ス・スA・ス・ス・ス・ス		-
//-	・スt・ス・ス・スフ出・スヘゑソスs・スネゑソス			-
//-						-
//-  Copyright(c) by M.Kuwano(PastelMagic)	-
//-	All Rights Reserved			-
//-----------------------------------------------
// xprint for Hi-TechC modify by K.I 090517
// - Add outfunc parameter.
// - Correct DWORD output probrem.
// - Add 'S'option for output RAM string
//-----------------------------------------------

#include "ctype.h"
#include "cstdef.h"
#include <stdlib.h>
#include <stdarg.h>

static void (*print_chr)(unsigned char c);	//// for xprintf by K.I
////extern void print_chr(unsigned char c);


union	DATAS {
	float		fdat;
	unsigned long	dword;
	unsigned int	word[2];
	unsigned char	byte[4];
};

unsigned int param[4];
static union DATAS udat;
static unsigned char tbuf[24];	////



unsigned int slen(const unsigned char	*s)
{
	unsigned int	len;
	for (len=0; *s; len++,s++)
		;
	return(len);
}


void print_str(const unsigned char *c)
{
	char x;
	while(*c) {
		x = *c;
		print_chr(*c++);
	}
}

void print_strx(unsigned char *c)	//// add for RAM string by K.I
{
	char x;
	while(*c) {
		x = *c;
		print_chr(*c++);
	}
}

void print_pads(
	int		width,
	unsigned int	padchar)
{
	while(width-- > 0)
		print_chr(padchar);
}

void print_val(unsigned int	width,
	  unsigned int  padchar,
	  unsigned int  base,
	  union	DATAS	data)
{
	unsigned int	datwidth;
	unsigned char	*p;
	
	p = tbuf;
    if (data.word[0]) {		////							/* ・スR・スQ・スr・スb・スg・スf・ス[・ス^			*/
		for (datwidth=0; data.dword>0; datwidth++) {
			if ((*p = (unsigned char )((data.dword % base) + '0')) > '9')
				*p += (unsigned char)('A'-'0'-10);
			  	p++;
			data.dword /= base;
		}
	}
	else {													/* ・スP・スU・スr・スb・スg・スf・ス[・ス^			*/
		for (datwidth=0; data.word[1]>0; datwidth++) { ////
			if ((*p = (unsigned char )((data.word[1] % base) + '0')) > '9')	////
				*p += (unsigned char)('A'-'0'-10);
			p++;
			data.word[1] /= base;	////
		}
	}
	if (datwidth == 0) {
		*p++ = '0';
		datwidth = 1;
	}
	print_pads(width-datwidth,padchar);
	while(datwidth--)
		print_chr(*--p);
}

void fmtout(
	const unsigned char	*string,
	unsigned int	*param)
{
	unsigned char padchar;
	unsigned char *cp;
	float *fp;
	unsigned int	width,longflag;
	int	status;
	
	while(*string) {
		if (*string == LF) {
			print_chr(CR);
			print_chr(LF);
			string++;
			continue;
		}
		if (*string != '%') {
			print_chr(*string++);
			continue;
		}
		string++;
		padchar = *string;
		if (padchar == '0')
			string++;
		else	padchar = ' ';
		for (width = 0; isdigit(*string); width = width*10+(*string++ - '0'))
			;
		if (!width)
			width++;
		if (longflag = (*string == 'L') || (*string == 'l')) {
				string++;
				udat.word[0] = *param++;	////
		} else	udat.word[0] = 0;			////
		switch(*string) {
			case	'b':
			case	'B':	udat.word[1] = *param++;	////
					print_val(width,padchar,2,udat);
					break;
			case	'o':
			case	'O':	udat.word[1] = *param++;	////
					print_val(width,padchar,8,udat);
					break;
			case	'u':
			case	'U':	udat.word[1] = *param++;	////
					print_val(width,padchar,10,udat);
					break;
			case	'd':
			case	'D':	udat.word[1] = *param++;	////
					print_val(width,padchar,10,udat);
					break;
			case	'x':
			case	'X':	udat.word[1] = *param++;	////
					print_val(width,padchar,16,udat);
					break;
			case	'f':	if (width == 1)
						width = 15;	// ftoa ・スフバ・スb・スt・ス@・スT・スC・スY
					fp = (float *)param;
					udat.fdat = *fp;
					fp++;	////
					param = (unsigned int *)fp;
					cp = ftoa(udat.fdat, &status);
					if (status != 0) break;
					while(*cp != EOS) {
						if (!width) break;
						print_chr(*cp++);
						width--;
					}
					while(width--)
						print_chr(padchar);
					break;
			case	'c':	print_pads(width-1,' ');
					print_chr(*param++);	////
					break;
			case	's':	width -= slen((const unsigned char *)(*param));
					print_pads(width,' ');
					print_str((const unsigned char *)(*param));
					param++;	////
					break;
			case	'S':	width -= slen((unsigned char *)(*param));	//// add 'S'option for RAM string by K.I
					print_pads(width,' ');
					print_strx((unsigned char *)(*param));
					param++;	////
					break;
			default:	print_chr('%');
					print_chr(*string);
					break;
		}
		string++;
	}
}

//// xprintf by K.I
void xprintf( void(*outfunc)(unsigned char c), const unsigned char *string, ...)
////void printf( const unsigned char *string, ...)
{
	va_list arg;
	print_chr = outfunc;	//// add outfunc for xprintf by K.I
	va_start(arg, string);
	fmtout(string, arg[0]);
}