#if !defined(lint) && defined(SCCSIDS)
static  char *sccsid = "@(#)xccs.multibyte.c 1.1 94/10/31 SMI";
#endif 

#include <stdio.h>
#include <sys/types.h>

#define CS377	0377
#define MASK	0x0000ffff
#define TOP1	0x80000000
#define TOP2	0x08000000


/*
 * mbtowc routines for the Xerox XCCS codeset standard
 */
int
_mbtowc_xccs(pwc, s, n)
	wchar_t *pwc;
	char *s;
	int n;
{
	static unsigned int CSselect = 0;
	static int CSlength = 1;
	wchar_t twchar = 0;

	/*
	 * If length is negative, return error
	 */
	if (n <= 0)
		return (-1);

	/*
	 * End of string ?
	 */
	if (*s == 0 && CSlength == 1)
		return (0);
	if (*s == 0 && *(s + 1) == 0 && CSlength == 2)
		return (0);

	/*
	 * Get a character
	 */
	if ((unsigned char)*s == CS377) {
		/*
		 * Switching code set
		 */
		++s;
		/*
		 * Change characteristics
		 */
		 if ((unsigned char)*s == CS377) {
			++s;
			/*
			 * two byte sequence
			 */
			 if (*s++ != 0)
				return (-1);
			 CSselect = 0;
			 CSlength = 2;
			 
		 }
		 else {
			/*
			 * Change CSselect
			 */
			 CSselect = (unsigned int)*s++;
			 CSlength = 1;
		}
	}

	/*
	 * Get a character and return
	 */
	 if (CSlength == 1) {
		twchar = CSselect;
	 }
	 else {
		twchar = *s++;
	 }
	 twchar = twchar << 8;
	 twchar = twchar | *s;
	 if (pwc)
		 *pwc = twchar & MASK;
	 /*
	  * Encode additional information
	  */
	 if (CSlength == 2)
		if (pwc)
			*pwc |= TOP1;
	 return (CSlength);
}

/*
 * wctomb routines
 */
int
_wctomb_xccs(s, pwc)
	char *s;
	wchar_t pwc;
{ 
	unsigned char upper, lower;
	char *old = s;
#ifdef DEBUG
	printf ("XCCS- xctomb\n");
#endif

	if (!s)
		return (0);

	/*
	 * Get lower and upper anyway
	 */
	lower = pwc & 0x00ff;
	upper = (pwc >> 8) & 0x00ff;
	if (lower == CS377 || upper == CS377)
		return (-1);
	if (pwc & TOP1) {	/* length == 2 */
		/*
		 * This was the marker.
		 * Emitt 3 additional characters.
		 */
		*s++ = CS377;
		*s++ = CS377;
		*s++ = 0;
		*s++ = upper;
		*s++ = lower;
	}
	else {
		/*
		 * This was the marker.
		 * Emitt 2 additional characters.
		 */
		*s++ = CS377;
		*s++ = upper;
		*s++ = lower;
	}
	return (s - old);
}


/*
 * mbstowcs routines
 */
size_t
_mbstowcs_xccs(pwc, s, n)
	wchar_t *pwc;
	char *s;
	int n;
{
	static unsigned int CSselect = 0;
	static int CSlength = 1;
	wchar_t twchar = 0;
	int cnt = 0;

	/*
	 * If length is negative, return error
	 */
	if (n <= 0)
		return (-1);

	/*
	 * End of string ?
	 */
	if (*s == 0 && CSlength == 1)
		return (0);
	if (*s == 0 && *(s + 1) == 0 && CSlength == 2)
		return (0);

	do {
		/*
		 * Check for an end of the string
		 */
		if (((*s == 0 && CSlength == 1)) ||
		   ((*s == 0 && *(s + 1) == 0 && CSlength == 2))) {
			*pwc = 0;
			++cnt;
			--n;
			break;
		}
		/*
		 * Get a character
		 */
		if ((unsigned char)*s == CS377) {
			++s;
			/*
			 * Change characterristics
			 */
			 if ((unsigned char)*s == CS377) {
				++s;
				/*
				 * two byte sequence
				 */
				 if (*s++ != 0)
					return (-1);
				 CSselect = 0;
				 CSlength = 2;
				 
			 }
			 else {
				/*
				 * Change CSselect
				 */
				 CSselect = (unsigned int)*s++;
				 CSlength = 1;
			}
		}

		/*
		 * Get a character and return
		 */
		 if (CSlength == 1) {
			twchar = CSselect;
		 }
		 else {
			twchar = *s++;
		 }
		 twchar = twchar << 8;
		 twchar = twchar | *s++;
		 *pwc = twchar & MASK;
		 if (CSlength == 2)
			*pwc |= TOP1;
		 ++pwc;
		 ++cnt;
		 --n;
	 } while (n >= 0);
	 return (cnt);
}


/*
 * wcstombs routines
 */
size_t
_wcstombs_xccs(s, pwc, n)
	char *s;
	wchar_t *pwc;
	int n;
{
	int cnt = 0;
	unsigned char lower, upper;
	int in_2byte = 0;
	int in_1byte = 0;
	int current = 0;

	if (n <= 0)
		return (-1);
	
	if (*pwc == 0)
		return (0);

	do {
		lower = *pwc & 0x00ff;
		upper = (*pwc >> 8) & 0x00ff;
		/*
		 * End of string ?
		 */
		if (lower == 0) {
			*s++ = 0;
			++cnt;
			--n;
			if (n == 0)
				break;
			*s++ = 0;
			++cnt;
			break;
		}
		if (lower == CS377 || upper == CS377)
			return (-1);
		if (*pwc & TOP1) {	/* length == 2 */
			if (in_2byte == 0) {
				/*
				 * This was the marker.
				 * Emitt 3 additional characters.
				 */
				*s++ = CS377; ++cnt; --n;
				*s++ = CS377; ++cnt; --n;
				*s++ = 0; ++cnt; --n;
				in_2byte = 1;
				in_1byte = 0;
			}
			*s++ = upper; ++cnt; --n;
			if (n == 0)
				break;
			*s++ = lower; ++cnt; --n;
			if (n == 0)
				break;
		}
		else {
			if ((in_1byte == 0 && in_2byte == 1) ||
			    (in_1byte == 1 && upper != current) ||
			    (in_1byte == 0 && in_2byte == 0 && upper != 0)) {
				/*
				 * This was the marker.
				 * Emitt 2 additional characters.
				 */
				*s++ = CS377; ++cnt; --n;
				if (n == 0)
					break;
				*s++ = upper; ++cnt; --n;
				if (n == 0)
					break;
				in_2byte = 0;
				in_1byte = 1;
				current = upper;
			}
			*s++ = lower; ++cnt; --n;
			if (n == 0)
				break;
		}
		++pwc;
	} while (n >= 0);
	return (cnt);
}
