#include <9pm/u.h>
#include <9pm/libc.h>

static int
to64(uchar *b, int ilen, char *buf, int olen)
{
	return enc64(buf, olen, b, ilen);
}

static int
to32(uchar *b, int ilen, char *buf, int olen)
{
	return enc32(buf, olen, b, ilen);
}

static char set16[] = "0123456789ABCDEF";

static int
to16(uchar *b, int ilen, char *buf, int olen)
{
	uint c;
	char *out, *eout;

	USED(olen);
	out = buf;
	eout = buf + 2*ilen;
	while(out < eout){
		c = *b++;
		*out++ = set16[c>>4];
		*out++ = set16[c&0xf];
	}

	*out = 0;
	return 0;
}

int
encodeconv(va_list *arg, Fconv *f)
{
	char *out;
	char *buf;
	int len;
	int ilen;
	int rv;
	uchar *b;
	char obuf[64];	// rsc optimization

	if(f->f2 < 1)
		goto error;

	b = va_arg(*arg, uchar*);

	ilen = f->f2;
	switch(f->chr){
	case '<':
		len = (8*ilen+4)/5 + 3;
		break;
	case '[':
		len = (8*ilen+5)/6 + 4;
		break;
	case 'H':
		len = 2*ilen + 1;
		break;
	default:
		goto error;
	}

	if(len > sizeof(obuf)){
		buf = malloc(len);
		if(buf == nil)
			goto error;
	} else
		buf = obuf;

	// convert
	out = buf;
	switch(f->chr){
	case '<':
		rv = to32(b, ilen, out, len);
		break;
	case '[':
		rv = to64(b, ilen, out, len);
		break;
	case 'H':
		rv = to16(b, ilen, out, len);
		break;
	default:
		rv = -1;
		break;
	}
	if(rv < 0)
		goto error;

	// stuff in the slot
	f->f2 = -1000;
	strconv(buf, f);

	if(buf != obuf)
		free(buf);
	return sizeof(uchar*);

error:
	f->f2 = -1000;
	strconv("*", f);
	return sizeof(uchar*);
}
