#include <stdio.h>
#include "libsys.h"
#include "xcpt.h"

/* 10 digits + 1 sign + 1 trailing nul */
static char itoa_buf[12];

char *itoa(int i)
{
	char *pos = itoa_buf + sizeof(itoa_buf) - 1;
	unsigned int u;
	int negative = 0;

	if (i < 0)
	{
		negative = 1;
		u = ((unsigned int)(-(1+i))) + 1;
	}
	else
	{
		u = i;
	}

	*pos = 0;

	do
	{
		*--pos = '0' + (u % 10);
		u /= 10;
	} while (u);

	if (negative)
	{
		*--pos = '-';
	}

	return pos;
}

int syscalls_handler(struct xcptcontext * xcp)
{
	int syscall_code;
	char *pStr, buf[33];

	syscall_code = xcp->regs[2];

	switch(syscall_code)
	{
		case 1:		// print integer
		sputs(itoa(xcp->regs[4]));
		break;

		case 4:		// print string
		pStr = (char*)xcp->regs[4];
		sputs(pStr);
		break;

		case 5:		// read integer
		pStr = fgets(buf, sizeof(buf), stdin);
		xcp->regs[2] = atoi(pStr);
		break;

		case 8:		// read string
		pStr = (char*)xcp->regs[4];
		fgets(pStr, xcp->regs[5], stdin);
		break;

		case 10:		// exit
		_exit(0);
		break;

		default:
		sputs("\nUnknown syscall (");print_word(syscall_code);sputs(") at ");print_word(xcp->epc);sputs("\n");
		break;
	}

	xcp->epc += 4;	// set return address to instruction after syscall

	return 0;
}

void syscalls_init(void)
{
	xcpt_register(Syscall, syscalls_handler);
}

