#include <cutils/extensions.h>

int cutil_strcasecmp(const char* s1, const char* s2)
{
	const unsigned char* p1 = (const unsigned char*)s1;
	const unsigned char* p2 = (const unsigned char*)s2;
	unsigned char c1, c2;

	do
	{
		c1 = (unsigned char)tolower(*p1++);
		c2 = (unsigned char)tolower(*p2++);
		if (c1 == '\0')
			return c1 - c2;
	}
	while (c1 == c2);

	return c1 - c2;
}

int cutil_strncasecmp(const char* s1, const char* s2, size_t n)
{
	const unsigned char* p1 = (const unsigned char*)s1;
	const unsigned char* p2 = (const unsigned char*)s2;
	unsigned char c1, c2;

	if(n == 0)
		return 0;

	do
	{
		c1 = (unsigned char)tolower(*p1++);
		c2 = (unsigned char)tolower(*p2++);
		if (c1 == '\0')
			return c1 - c2;
	}
	while (c1 == c2 && --n);

	return c1 - c2;
}

size_t cutil_strnlen(const char* s, size_t maxlen)
{
	size_t len;

	for(len = 0; len < maxlen; len++, s++)
	{
		if (!*s)
			break;
	}
	return (len);
}

char* cutil_strndup(const char* s, size_t n)
{
	char* ret;
	size_t len = cutil_strnlen(s, n);

	len = CUTIL_MIN(len, n);

	ret = malloc(len+1);
	if(!ret)
		return NULL;
	memcpy(ret, s, len+1);

	return ret;
}

bool cutil_memmem(const void* haystack, size_t haystacklen, const void* needle, size_t needlelen, size_t* pos)
{
	size_t i, j;
	const byte* haystackb = haystack;
	const byte* needleb = needle;

	if(needlelen == 0)
		return true;

	if(HEDLEY_UNLIKELY((haystacklen == 0 && needlelen != 0 )|| haystacklen < needlelen))
		return false;
	//TODO: use memchr as base search
	for(i = 0; i < haystacklen; i++)
	{
		for(j = 0, *pos = i; j < needlelen && i < haystacklen; j++, i++)
		{
			if(haystackb[i] != needleb[j])
				break;
			else if(j == needlelen-1)
				return true;
		}
	}

	return false;
}

#if __STDC_VERSION__ >= 199901L
int cutil_asprintf(char** strp, const char* format, ...)
{
	va_list ap;
	size_t needed;
	int ret;

	va_start(ap, format);
	needed = (size_t)vsnprintf(NULL, 0, format, ap);
	va_end(ap);

	*strp = malloc(needed);

	if(!*strp)
		return -1;

	va_start(ap, format);
	ret = snprintf(*strp, needed, format, ap);
	va_end(ap);

	return ret;
}
#endif
