#include <../source/TAL/objbase.h>
#include <../source/PAL/dataman.h>
#include <../source/PAL/fsops.h>
#include <ctype.h>

/*
 *	We declare guard string quite large because default text 
 *	'[NULL]' can later be replaced by:
 *	1. Explicit call: strcpy(dbs(NULL),"New text");
 *	2. Implicit: due to caller bugs.
 */

#ifdef	CHECKED_BUILD
static char libv_string_guard[STRING_GUARD_SIZE];
#endif

char_p	V_GLOBAL
dbs(char_p string_which_can_be_NULL)
{
#ifdef	CHECKED_BUILD
	if(string_which_can_be_NULL)
		return string_which_can_be_NULL;
	else
	{
		/* Avoid infinite recursion if TRASHED_BUFFER_SIZE==0 */
		strCopy(libv_string_guard,"[NULL]",STRING_GUARD_SIZE);
		return libv_string_guard;
	}
#else
	return string_which_can_be_NULL;
#endif	/* CHECKED_BUILD */
}

/*
 *	strCopy - analog to strncpy.
 *	Differences:
 *	1. Third parameter is AMOUNT OF MEMORY allocated for 'dst'.
 *	2. 'Dst' will be ALWAYS terminated by null-character ('\0').
 *	3. Strings 'dst' and 'src' can be overlapped.
 *	4. Ifdef CHECHED_BUILD and dst==NULL, default static buffer returned.
 */
char_p V_GLOBAL
strCopy(char_p dst,char_p src,int dest_storage_length)
{
	int len;
	if(!dst || !src || dest_storage_length<=0)
	{
#ifdef	CHECKED_BUILD
		conlPrintf(LOG_ERROR,
			"strCopy('%s','%s',%d): incorrect parameters.\n",dbs(dst),
			dbs(src),dest_storage_length);
#endif	/* CHECKED_BUILD */
		if(dst && dest_storage_length>0)
			dst[0]=0;
		return dbs(dst);
	}
	len=strlen(src);
	if(len>=dest_storage_length)
		len=dest_storage_length-1;
	memmove(dst,src,len);
	dst[len]=0;
	return dst;
}

/*
 *	strCat - analog to strncat.
 *	Differences:
 *	1. Strings 'dst' and 'src' can be overlapped.
 *	2. Ifdef CHECHED_BUILD and dst==NULL, default static buffer returned.
 */
char_p	V_GLOBAL
strCat(char_p dst,char_p src,int max_chars_to_be_added)
{
	if(!dst || !src || max_chars_to_be_added<=0)
	{
#ifdef	CHECKED_BUILD
		conlPrintf(LOG_ERROR,
			"strCat('%s','%s',%d): incorrect parameters.\n",dbs(dst),
			dbs(src),max_chars_to_be_added);
#endif	/* CHECKED_BUILD */
		return dbs(dst);
	}
	return strCopy(dst+strlen(dst),src,max_chars_to_be_added);
}

/*
 *	Strips leading whitespace from string. Returns str.
 *	Note. Ifdef CHECHED_BUILD and str==NULL, default static buffer returned.
 */
char_p	V_GLOBAL
strStripLead(char_p str)
{
	char *ptr;
	if(!str)
	{
#ifdef	CHECKED_BUILD
		conlPrintf(LOG_ERROR,
			"strStripLead('%s'): incorrect parameter.\n",dbs(str));
#endif	/* CHECKED_BUILD */
		return dbs(str);
	}
	ptr=str;
	while(*ptr && *ptr<' ')
		ptr++;
	if(ptr != str)
		memmove(str,ptr,strlen(ptr)+1);
	return str;
}

/*
 *	Strips trailing whitespace from string. Returns str.
 *	Note. Ifdef CHECHED_BUILD and str==NULL, default static buffer returned.
 */
char_p	V_GLOBAL
strStripTrail(char_p str)
{
	char *ptr;
	if(!str)
	{
#ifdef	CHECKED_BUILD
		conlPrintf(LOG_ERROR,
			"strStripTrail('%s'): incorrect parameter.\n",dbs(str));
#endif	/* CHECKED_BUILD */
		return dbs(str);
	}
	ptr=str+strlen(str)-1;
	for(;ptr>str && *ptr<' ';ptr--)
		*ptr=0;
	return str;
}

/*
 *	Strips both leading and trailing whitespace. Returns str.
 *	Note. Ifdef CHECHED_BUILD and str==NULL, default static buffer returned.
 */
char_p	V_GLOBAL
strStripLT(char_p str)
{
	if(!str)
	{
#ifdef	CHECKED_BUILD
		conlPrintf(LOG_ERROR,
			"strStripLT('%s'): incorrect parameter.\n",dbs(str));
#endif	/* CHECKED_BUILD */
		return dbs(str);
	}
	strStripLead(str);
	strStripTrail(str);
	return str;
}

/*
 *	Optionally converts dos path to unix path and appends '/' at end
 *	if no one; result+\0 either feet in _MAX_PATH, or NULL returned.
 */
char_p	V_GLOBAL
strAppendSlash(char_p path_to_check)
{
	char_p ptr;
	int len;
	if(!path_to_check)
	{
#ifdef	CHECKED_BUILD
		conlPuts(LOG_ERROR,
			"strAppendSlash('[null]'): incorrect parameter.\n");
#endif	/* CHECKED_BUILD */
		return NULL;
	}
	len=-1;
	for(ptr=path_to_check;*ptr;ptr++)
		if(*ptr=='\\')
		{
			len=strlen(path_to_check);
			break;
		}
	if(len==-1)
		len=ptr-path_to_check;
	if(len>=_MAX_PATH)
	{
#ifdef	CHECKED_BUILD
		conlPrintf(LOG_ERROR,
			"strAppendSlash('%s'): path too long.\n",path_to_check);
#endif	/* CHECKED_BUILD */
		return NULL;
	}
	if(!len || path_to_check[len-1]!='/')
	{
		if(len>(_MAX_PATH-1))
		{
#ifdef		CHECKED_BUILD
			conlPrintf(LOG_ERROR,
				"strAppendSlash('%s'): path too long to append '/'.\n",
				path_to_check);
#endif		/* CHECKED_BUILD */
		}
		path_to_check[len]='/';
		path_to_check[len+1]=0;
	}
	return path_to_check;
}

/*
 *	Returns integer value of given hexadecimal number.
 */
u32_t	V_GLOBAL
strHexToDigit(char *str,char *errchar)
{
	char buf[16],*ptr=buf;
	u32_t sum=0,e=1,mult;
	if(!str)
	{
#ifdef	CHECKED_BUILD
		conlPuts(LOG_ERROR,
			"strNexToDigit(NULL): incorrect parameter.\n");
#endif	/* CHECKED_BUILD */
		if(errchar)
			*errchar='0';
		return MAXLONG;
	}
	if(str[0]=='0' && (str[1]=='x' || str[1]=='X'))
		str+=2;	/* skip prefix */
	for(;*str;ptr++,str++)
	{
		if(!isxdigit(*str))
			if(errchar)
				*errchar=*str;
		if(*str>='a' && *str<='f')
			*ptr=(char)(*str-'a'+'A');
		else
			*ptr=*str;
	}
	ptr--;
	while(ptr>=buf)
	{
		mult=*ptr < '9' ? *ptr-'0' : 10 + *ptr-'A';
		sum+=mult * e;
		e<<=4;
		ptr--;
	}
	if(errchar)
		*errchar=0;
	return sum;
}

/*
 *	Duplicates given string, returns memAlloc()'ed block.
 */
char_p	V_GLOBAL
strDup(char *src)
{
	u32_t len, mem_size;
	char *ret;
	if(!src)
	{
#ifdef	CHECKED_BUILD
		conlPuts(LOG_ERROR,
			"strDup(NULL): incorrect parameter.\n");
#endif	/* CHECKED_BUILD */
		return NULL;
	}
	if(!*src)
	{
#ifdef	CHECKED_BUILD
		conlPuts(LOG_WARNING,
			"strDup(""): nothing to duplicate.\n");
#endif	/* CHECKED_BUILD */
	}
	len=strlen(src)+1;
	mem_size=INT_ALIGN(len);
	ret=(char*)memAlloc(mem_size);
	memCopy(ret,src,len);
	return ret;
}

/*
 * In-place converts string to lower case.
 * TODO: use locale to do this !
 */
char_p	V_GLOBAL
strLower(char *str)
{
	char *ptr;
	if(!str)
	{
#ifdef	CHECKED_BUILD
		conlPuts(LOG_ERROR,
			"strLower(NULL): incorrect parameter.\n");
#endif	/* CHECKED_BUILD */
		return NULL;
	}
	for(ptr=str;*ptr;ptr++)
		*ptr = (char)tolower(*ptr);
	return str;
}

#ifdef		__WATCOMC__

int	strcasecmp(const char *s1,const char *s2)
{
	char c1, c2;
	if(!s1 || !s2)
		return -1;
	for(;*s1 && *s2;s1++, s2++)
	{
		c1=tolower(*s1);
		c2=tolower(*s2);
		if(c1 < c2)
			return -1;
		else
			if(c1 > c2)
				return 1;
	}
	if(!*s1 && !*s2)
		return 0;
	return *s1 ? -1 : 1;
}

int strncasecmp(const char *s1,const char *s2,size_t n)
{
	char c1, c2;
	if(!s1 || !s2)
		return -1;
	if(!s1 || !s2)
		return -1;
	for(;*s1 && *s2 && n;s1++, s2++, n--)
	{
		c1=tolower(*s1);
		c2=tolower(*s2);
		if(c1 < c2)
			return -1;
		else
			if(c1 > c2)
				return 1;
	}
	if(!*s1 && !*s2)
		return 0;
	return *s1 ? -1 : 1;
}

#endif	/* __WATCOMC__ */
