/* EWL
 * Copyright © 1995-2007 Freescale Corporation.  All rights reserved.
 *
 * $Date: 2012/06/01 15:49:55 $
 * $Revision: 1.1 $
 */

/*
 *	Routines
 *	--------
 *		mblen
 *		mbtowc
 *		wctomb
 *		wctomb_s
 *		wcrtomb
 *		wcrtomb_s
 *		mbsrtowcs
 *		mbsrtowcs_s
 *		wcsrtombs
 *		wcsrtombs_s
 *		mbstowcs
 *		mbstowcs_s
 *		wcstombs
 *		wcstombs_s
 *		mbsinit
 */

#include <ansi_parms.h>
_MISRA_EXCEPTION_RULE_19_6()
#ifdef __STDC_WANT_LIB_EXT1__
/* enforce __STDC_WANT_LIB_EXT1__ support */
#undef __STDC_WANT_LIB_EXT1__
#endif
_MISRA_RESTORE()
#define __STDC_WANT_LIB_EXT1__ 1

#if _EWL_WIDE_CHAR

#include <ewl_misra_types.h>
#include <errno.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>

#include <locale_api.h>
#include <mbstring.h>
#include <ewl_thread_local_data.h>

int_t __unicode_to_UTF8(char_t * _EWL_RESTRICT s, wchar_t wchar)
{
	int_t    number_of_bytes;
	uint32_t wide_char;
	uchar_t	*target_ptr;
	uchar_t  first_byte_mark[6] = {0x00U, 0xc0U, 0xe0U, 0xf0U, 0xf8U, 0xfcU};

	if (!s) {          /* We are assuming UTF-8 encoding so return 0 */
		MISRA_EXCEPTION_RULE_14_7()
		return(0);
	}

	wide_char = (uint32_t)wchar;

	if (wide_char < 0x00000080UL) {
		number_of_bytes = 1;
	} else if (wide_char < 0x00000800UL) {
		number_of_bytes = 2;
	} else if (wide_char < 0x00010000UL) {
		number_of_bytes = 3;
	} else if (wide_char < 0x00200000UL) {
		number_of_bytes = 4;
	} else if (wide_char < 0x04000000UL) {
		number_of_bytes = 5;
	} else {
		number_of_bytes = 6;
	}

	target_ptr = (uchar_t *)s + number_of_bytes;

	switch (number_of_bytes)
	{				/* Note: the cases are meant to fall through! */
		case 6:
			*--target_ptr = (((uchar_t)wide_char & 0x003fu) | 0x80u);
			wide_char >>= 6;
			MISRA_EXCEPTION_RULE_15_2()
		case 5:
			*--target_ptr = (((uchar_t)wide_char & 0x003fu) | 0x80u);
			wide_char >>= 6;
			MISRA_EXCEPTION_RULE_15_2()
		case 4:
			*--target_ptr = (((uchar_t)wide_char & 0x003fu) | 0x80u);
			wide_char >>= 6;
			MISRA_EXCEPTION_RULE_15_2()
		case 3:
			*--target_ptr = (((uchar_t)wide_char & 0x003fu) | 0x80u);
			wide_char >>= 6;
			MISRA_EXCEPTION_RULE_15_2()
		case 2:
			*--target_ptr = (((uchar_t)wide_char & 0x003fu) | 0x80u);
			wide_char >>= 6;
			MISRA_EXCEPTION_RULE_15_2()
		case 1:
			*--target_ptr = ((uchar_t)wide_char | first_byte_mark[number_of_bytes - 1]);
			break;
		default: break;
	}

	return (number_of_bytes);
}

MISRA_ALLOW_POINTER_CASTS()

int_t __wctomb_noconv(char_t * s, wchar_t wchar)
{
	if (!s) {
		MISRA_EXCEPTION_RULE_14_7()
		return(0);
	}

	if (wchar > (wchar_t)255) {
		MISRA_EXCEPTION_RULE_14_7()
		return(-1);
	}

	*s = (char_t)wchar;

	return(1);
}

int_t _EWL_CDECL wctomb(char_t * s, wchar_t wchar)
{
#if defined(_EMBEDDED_WARRIOR_HAS_NO_LOCALE) && _EMBEDDED_WARRIOR_HAS_NO_LOCALE
	return __wctomb_noconv(s, wchar);
#else
	return(_EWL_LOCALDATA(_current_locale).ctype_cmpt_ptr->encode_wc(s, wchar));
#endif /* _EMBEDDED_WARRIOR_HAS_NO_LOCALE */
}

size_t _EWL_CDECL wcrtomb(char_t * _EWL_RESTRICT s, wchar_t wc, mbstate_t * _EWL_RESTRICT ps)
{
	#pragma unused(ps)
	MISRA_QUIET_UNUSED_ARGS()

	if (!s) {
		MISRA_EXCEPTION_RULE_14_7()
		return(1u);
	}

	return(size_t)__unicode_to_UTF8(s, wc);

	MISRA_EXCEPTION_RULE_16_7()
}

size_t _EWL_CDECL wcsrtombs(char_t * _EWL_RESTRICT dst, const wchar_t ** _EWL_RESTRICT src, size_t len, mbstate_t * _EWL_RESTRICT ps)
{

	size_t    chars_written = 0u;
	size_t    result;
	char_t    temp[MB_LEN_MAX];
	wchar_t * source;

	if (!*src) {
		MISRA_EXCEPTION_RULE_14_7()
		return (0u);
	}

	source = (wchar_t*)*src;
	while (chars_written <= len) {
		if (!*source) {
			if (dst != NULL) {
				*(dst + chars_written) = '\0';
				*src = NULL;
			}
			break;
		} else {
			result = wcrtomb(temp, *source++, ps);
			if ((chars_written + result) <= len) {
				strncpy(dst + chars_written, temp, result);
				chars_written += result;
				*src = source;
			} else {
		   		MISRA_EXCEPTION_RULE_14_6()
				break;
			}
		}
	}

	return(chars_written);
}

#endif  /*  _EWL_WIDE_CHAR  */
