/* $Copyright:	$
 * Copyright (c) 1984, 1985, 1986, 1987, 1988, 1989, 1990 
 * Sequent Computer Systems, Inc.   All rights reserved.
 *  
 * This software is furnished under a license and may be used
 * only in accordance with the terms of that license and with the
 * inclusion of the above copyright notice.   This software may not
 * be provided or otherwise made available to, or used by, any
 * other person.  No title to or ownership of the software is
 * hereby transferred.
*/

/*	Copyright (c) 1986 AT&T	*/
/*	  All Rights Reserved  	*/

/*	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T	*/
/*	The copyright notice above does not evidence any   	*/
/*	actual or intended publication of such source code.	*/



#ident	"$Header: wsntostr.c 1.2 90/04/21 $@(#)libw-port:wstring/wsntostr.c	1.0"

/*
 * Wsntostr transforms process codes in wchar_t string "s2"
 * into EUC, and transfers those to character string "s1", until
 * "n" characters or the wchar_t type NULL character have been
 * processed.
 */

#include "shlib.h"
#include <widec.h>
#include <errno.h>
#include <euc.h>
#include "libw_pcode.h"
#define NULL	0

extern int  _cswidth[];
extern void _xgetwidth();
extern eucwidth_t _eucwidth;
#define pcw _eucwidth._pcw	/* use for checking wchar_t is 2 or 4 bytes	*/

char *
_wsntostr(s1, s2, n, p)
register char *s1;
wchar_t *s2;
register int n;
wchar_t **p;
{
	register size, ssch, i, u;
	char *os1 = s1;

	if (! *_cswidth)
		_xgetwidth(); /* get character width */

	u = (pcw == sizeof(unsigned short)) ? 8 : 7;

	while (n > 0) { /* at most n characters */
		if (! (*s2)) { /* end if NULL wchar_t */
			*s1 = '\0';
			break;
		}
		/*
		 * "Switch" on a pattern of "00", "11", "01",
		 * or "10", depending on high bits of low two
		 * bytes of Proces Code.
		 */
		if (pcw == sizeof(unsigned short))
		switch (*s2 & EUCMASK) {
			case P00: /* Code Set 0 */
				*s1++ = *s2++;
				n--;
				continue;
			case P11: /* Cose Set 1 */
				ssch = 0;
				size = _cswidth[1];
				break;
			case P01: /* Code Set 2 */
				if (control1(*s2)) { /* control character 1 */
					*s1++ = *s2++;
					n--;
					continue;
				}
				ssch = SS2;
				size = _cswidth[2] + 1;
				break;
			case P10: /* Code Set 3 */
				ssch = SS3;
				size = _cswidth[3] + 1;
		}
		else
		switch (*s2 & F_EUCMASK) {
			case F_P00: /* Code Set 0 */
				*s1++ = *s2++;
				n--;
				continue;
			case F_P11: /* Cose Set 1 */
				ssch = 0;
				size = _cswidth[1];
				break;
			case F_P01: /* Code Set 2 */
				if (control1(*s2)) { /* control character 1 */
					*s1++ = *s2++;
					n--;
					continue;
				}
				ssch = SS2;
				size = _cswidth[2] + 1;
				break;
			case F_P10: /* Code Set 3 */
				ssch = SS3;
				size = _cswidth[3] + 1;
		}
		if ((n -= size) >= 0) {
			if (ssch)
				size--;
			/*
			 * Error checking for Process Code
			 * in supplementary code set
			 */
			if (size == 0) { /* EUC size is zero */
				if (p != 0)
					*p = s2;
				*s1 = '\0';
				errno = EILSEQ;
				return(NULL);
			}
			i = size;
			while (i--) { /* Check each bytes */
				if ( controlc(*s2 >> (i * u)) ) {
					if (p != 0)
						*p = s2;
					*s1 = '\0';
					errno = EILSEQ;
					return(NULL);
				}
			}
			/*
			 * Output Single Shift character if necessary
			 */
			if (ssch)
				*s1++ = ssch;

			/*
			 * Output bytes from highest order to 
			 * lowest order, masking the high order
			 * bits of the process code to ON.
			 */
			while (size--) {
				*s1++ = *s2 >> (size * u) | 0x80;
			}
			s2++;
		}
		else {
			*s1 = '\0';
			break;
		}
	}
	if (p != 0)
		*p = s2; /* next address of wchar_t string */
	return(os1);
}
