/*
 *	This is NOT stunningly portable, but works
 *	for pretty dumb non ANSI compilers and is
 *	tight.	Adjust the sizes to taste.
 *
 *	Illegal format strings will break it. Only the
 *	following simple subset is supported
 *
 *	%x	-	hex
 *	%d	-	decimal
 *	%s	-	string
 *	%c	-	char
 *
 *	And the h/l length specifiers for %d/%x
 *
 *		Alan Cox.
 */

#include <linuxmt/types.h>
#include <linuxmt/fcntl.h>

/*
 *	Just to make it work for now
 */
 
int cur_console = 0; 

extern void bios_charout();

static void con_write(con,buf,len,flag)
char *buf;
{
	while(len--)
		bios_charout(*buf++);
}
 
/************************************************************************/

/*
 *	Output a number
 */
 
static void numout(ptr,len,base)
char *ptr;
int len;
int base;
{
	unsigned long v;
	char buf[9];	/* Largest value must fit in this */
	char *bp=&buf[7];
	bp[1]=0;
	if(len==2)
		v=*(unsigned short *)ptr;
	else
		v=*(unsigned long *)ptr;
	
	while(v)
	{
		*bp--="0123456789ABCDEF"[v%base];
		v/=base;
	}
	
	bp++;
	con_write(cur_console,bp,buf-bp+sizeof(buf),O_NDELAY);
}

void printk(fmt,a1)
char *fmt;
int a1;
{
	char *p=(char *)&a1;
	char c;
	while(c=*fmt++)
	{
		if(c!='%')
			con_write(cur_console,&c,1,O_NDELAY);
		else
		{
			int len=2;
			c=*fmt++;
			if(c=='h')
				c=*fmt++;
			else if(c=='l')
			{
				len=4;
				c=*fmt++;
			}
			
			switch(c)				
			{
				case 'x':
					numout(p,len,16);
					p+=len;
					break;
				case 'd':
					numout(p,len,10);
					p+=len;
					break;
				case 's':
				{
					char *cp=*((char **)p);
					p+=sizeof(char *);
					while(*cp)
						con_write(cur_console,cp++,1,O_NDELAY);
					break;
				}
				case 'c':
					con_write(cur_console,p++,1,O_NDELAY);
					break;
				default:
					con_write(cur_console,"?",1,O_NDELAY);
			}
		}
	}
}

void panic(error)
char *error;
{
	printk("panic: %s\n", error);
#asm
	cli
#endasm		
	while(1);
}
