17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate  * m_cc.c
29*1da57d55SToomas Soome  *
307c478bd9Sstevel@tonic-gate  * XCurses Library
317c478bd9Sstevel@tonic-gate  *
327c478bd9Sstevel@tonic-gate  * Copyright 1990, 1995 by Mortice Kern Systems Inc.  All rights reserved.
337c478bd9Sstevel@tonic-gate  *
347c478bd9Sstevel@tonic-gate  */
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate #if M_RCSID
377c478bd9Sstevel@tonic-gate #ifndef lint
387c478bd9Sstevel@tonic-gate static char rcsID[] = "$Header: /rd/src/libc/xcurses/rcs/m_cc.c 1.8 1995/09/20 15:26:52 ant Exp $";
397c478bd9Sstevel@tonic-gate #endif
407c478bd9Sstevel@tonic-gate #endif
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate #include <private.h>
437c478bd9Sstevel@tonic-gate #include <errno.h>
447c478bd9Sstevel@tonic-gate #include <limits.h>
457c478bd9Sstevel@tonic-gate #include <string.h>
467c478bd9Sstevel@tonic-gate #include <m_wio.h>
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate typedef struct {
497c478bd9Sstevel@tonic-gate 	int max;
507c478bd9Sstevel@tonic-gate 	int used;
517c478bd9Sstevel@tonic-gate 	char *mbs;
527c478bd9Sstevel@tonic-gate } t_string;
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate static int
write_string(byte,sp)557c478bd9Sstevel@tonic-gate write_string(byte, sp)
567c478bd9Sstevel@tonic-gate int byte;
577c478bd9Sstevel@tonic-gate t_string *sp;
587c478bd9Sstevel@tonic-gate {
597c478bd9Sstevel@tonic-gate 	if (sp->max <= sp->used)
607c478bd9Sstevel@tonic-gate 		return EOF;
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate 	sp->mbs[sp->used++] = byte;
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate 	return byte;
657c478bd9Sstevel@tonic-gate }
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate /*
68*1da57d55SToomas Soome  * Convert a wint_t string into a multibyte string.
697c478bd9Sstevel@tonic-gate  *
70*1da57d55SToomas Soome  * The conversion stops at the end of string or the first WEOF.
717c478bd9Sstevel@tonic-gate  * Return the number of bytes successfully placed into mbs.
727c478bd9Sstevel@tonic-gate  */
737c478bd9Sstevel@tonic-gate int
wistombs(mbs,wis,n)747c478bd9Sstevel@tonic-gate wistombs(mbs, wis, n)
757c478bd9Sstevel@tonic-gate char *mbs;
767c478bd9Sstevel@tonic-gate const wint_t *wis;
777c478bd9Sstevel@tonic-gate int n;
787c478bd9Sstevel@tonic-gate {
797c478bd9Sstevel@tonic-gate 	int last;
807c478bd9Sstevel@tonic-gate 	t_string string = { 0 };
817c478bd9Sstevel@tonic-gate 	t_wide_io convert = { 0 };
82*1da57d55SToomas Soome 
837c478bd9Sstevel@tonic-gate 	string.max = n;
847c478bd9Sstevel@tonic-gate 	string.mbs = mbs;
857c478bd9Sstevel@tonic-gate 	convert.object = (void *) &string;
867c478bd9Sstevel@tonic-gate 	convert.put = (int (*)(int, void *)) write_string;
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate 	for (;; ++wis) {
897c478bd9Sstevel@tonic-gate 		/* In case of error, rewind string to the last character. */
907c478bd9Sstevel@tonic-gate 		last = string.used;
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate 		if (m_wio_put(*wis, &convert) < 0) {
937c478bd9Sstevel@tonic-gate 			string.used = last;
947c478bd9Sstevel@tonic-gate 			break;
957c478bd9Sstevel@tonic-gate 		}
967c478bd9Sstevel@tonic-gate 
97*1da57d55SToomas Soome 		/* Test for end of string AFTER trying to copy into the
98*1da57d55SToomas Soome 		 * buffer, because m_wio_put() has to handle state changes
997c478bd9Sstevel@tonic-gate 		 * back to the initial state on '\0' or WEOF.
1007c478bd9Sstevel@tonic-gate 		 */
1017c478bd9Sstevel@tonic-gate 		if (*wis == '\0' || *wis == WEOF)
1027c478bd9Sstevel@tonic-gate 			break;
1037c478bd9Sstevel@tonic-gate 	}
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate 	/* m_wio_put() does not write '\0', because the "stream"
1067c478bd9Sstevel@tonic-gate 	 * object is considered to be in "text" mode, which in the
1077c478bd9Sstevel@tonic-gate 	 * case of file I/O produces undefined results for systems
1087c478bd9Sstevel@tonic-gate 	 * using locking-shift character sets.
1097c478bd9Sstevel@tonic-gate 	 */
1107c478bd9Sstevel@tonic-gate 	string.mbs[string.used] = '\0';
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate 	return string.used;
1137c478bd9Sstevel@tonic-gate }
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate /*
1167c478bd9Sstevel@tonic-gate  * Convert a wint_t string (filled in by wgetn_wstr()) to a wchar_t string.
1177c478bd9Sstevel@tonic-gate  * The conversion stops at the end of string or the first WEOF.  Return the
1187c478bd9Sstevel@tonic-gate  * number of successfully copied characters.
1197c478bd9Sstevel@tonic-gate  *
1207c478bd9Sstevel@tonic-gate  * This routinue should be used when sizeof (wchar_t) < sizeof (wint_t).
1217c478bd9Sstevel@tonic-gate  */
1227c478bd9Sstevel@tonic-gate int
wistowcs(wcs,wis,n)1237c478bd9Sstevel@tonic-gate wistowcs(wcs, wis, n)
1247c478bd9Sstevel@tonic-gate wchar_t *wcs;
1257c478bd9Sstevel@tonic-gate const wint_t *wis;
1267c478bd9Sstevel@tonic-gate int n;
1277c478bd9Sstevel@tonic-gate {
1287c478bd9Sstevel@tonic-gate 	wchar_t *start;
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate 	if (n < 0)
1317c478bd9Sstevel@tonic-gate 		n = INT_MAX;
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate 	for (start = wcs; *wis != '\0' && 0 < n; ++wis, ++wcs, --n) {
1347c478bd9Sstevel@tonic-gate 		if (*wis == WEOF)
1357c478bd9Sstevel@tonic-gate 			break;
1367c478bd9Sstevel@tonic-gate 		*wcs = (wchar_t) *wis;
1377c478bd9Sstevel@tonic-gate 	}
1387c478bd9Sstevel@tonic-gate 	*wcs = '\0';
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate 	return (int) (wcs - start);
1417c478bd9Sstevel@tonic-gate }
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate /*
1447c478bd9Sstevel@tonic-gate  * Convert a chtype to a cchar_t.
1457c478bd9Sstevel@tonic-gate  */
1467c478bd9Sstevel@tonic-gate int
__m_chtype_cc(ch,cc)1477c478bd9Sstevel@tonic-gate __m_chtype_cc(ch, cc)
1487c478bd9Sstevel@tonic-gate chtype ch;
1497c478bd9Sstevel@tonic-gate cchar_t *cc;
1507c478bd9Sstevel@tonic-gate {
1517c478bd9Sstevel@tonic-gate 	char mb;
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate 	cc->_f = 1;
1547c478bd9Sstevel@tonic-gate         cc->_n = 1;
1557c478bd9Sstevel@tonic-gate 	mb = (char)(ch & A_CHARTEXT);
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate 	if (mbtowc(cc->_wc, &mb, 1) < 0)
1587c478bd9Sstevel@tonic-gate 		return ERR;
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate         cc->_co = (short) PAIR_NUMBER(ch);
1617c478bd9Sstevel@tonic-gate         cc->_at = (attr_t) ((ch & (A_ATTRIBUTES & ~A_COLOR)) >> 16);
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate 	return OK;
1647c478bd9Sstevel@tonic-gate }
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate /*
1677c478bd9Sstevel@tonic-gate  * Return a complex character as a chtype.
1687c478bd9Sstevel@tonic-gate  */
1697c478bd9Sstevel@tonic-gate chtype
__m_cc_chtype(cc)1707c478bd9Sstevel@tonic-gate __m_cc_chtype(cc)
1717c478bd9Sstevel@tonic-gate const cchar_t *cc;
1727c478bd9Sstevel@tonic-gate {
1737c478bd9Sstevel@tonic-gate 	chtype ch;
1747c478bd9Sstevel@tonic-gate 	unsigned char mb[MB_LEN_MAX];
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 	/* Is it a single-byte character? */
1777c478bd9Sstevel@tonic-gate 	if (cc->_n != 1 || wctomb((char *) mb, cc->_wc[0]) != 1)
1787c478bd9Sstevel@tonic-gate 		return (chtype) ERR;
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 	ch = ((chtype) cc->_at << 16) & ~A_COLOR;
1817c478bd9Sstevel@tonic-gate 	ch |= COLOR_PAIR(cc->_co) | mb[0];
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate 	return ch;
1847c478bd9Sstevel@tonic-gate }
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate /*
1877c478bd9Sstevel@tonic-gate  * Convert a complex character's "character" into a multibyte string.
1887c478bd9Sstevel@tonic-gate  * The attribute and colour are ignored.
1897c478bd9Sstevel@tonic-gate  *
190*1da57d55SToomas Soome  * If 0 < n, set a new multibyte string and convert the first character,
1917c478bd9Sstevel@tonic-gate  * returning either -1 on error or the number of bytes used to convert the
1927c478bd9Sstevel@tonic-gate  * character.
1937c478bd9Sstevel@tonic-gate  *
1947c478bd9Sstevel@tonic-gate  * If n == 0, continue appending to the current multibyte string and return
1957c478bd9Sstevel@tonic-gate  * a value as for 0 < n case.
1967c478bd9Sstevel@tonic-gate  *
197*1da57d55SToomas Soome  * If n < 0, return the accumulated byte length of the current multibyte
1987c478bd9Sstevel@tonic-gate  * string and do nothing else.
1997c478bd9Sstevel@tonic-gate  *
200*1da57d55SToomas Soome  * When converting a character, a null cchar_t pointer will force the initial
2017c478bd9Sstevel@tonic-gate  * shift state and append a '\0' to the multibyte string.  The return value
2027c478bd9Sstevel@tonic-gate  * will instead by the number of bytes used to shift to the initial state,
2037c478bd9Sstevel@tonic-gate  * and exclude the '\0'.
2047c478bd9Sstevel@tonic-gate  */
2057c478bd9Sstevel@tonic-gate int
__m_cc_mbs(cc,mbs,n)2067c478bd9Sstevel@tonic-gate __m_cc_mbs(cc, mbs, n)
2077c478bd9Sstevel@tonic-gate const cchar_t *cc;
2087c478bd9Sstevel@tonic-gate char *mbs;
2097c478bd9Sstevel@tonic-gate int n;
2107c478bd9Sstevel@tonic-gate {
2117c478bd9Sstevel@tonic-gate 	cchar_t *cp;
2127c478bd9Sstevel@tonic-gate 	int i, bytes, count, last;
2137c478bd9Sstevel@tonic-gate 	mbstate_t initial = { 0 };
2147c478bd9Sstevel@tonic-gate 	static t_string string = { 0 };
2157c478bd9Sstevel@tonic-gate 	static t_wide_io convert = { 0 };
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate 	if (n < 0) {
2187c478bd9Sstevel@tonic-gate 		/* Return total number of bytes written to multibyte string. */
2197c478bd9Sstevel@tonic-gate 		return string.used;
2207c478bd9Sstevel@tonic-gate 	} else if (0 < n) {
2217c478bd9Sstevel@tonic-gate 		/* Start a new conversion. */
2227c478bd9Sstevel@tonic-gate 		string.max = n;
2237c478bd9Sstevel@tonic-gate 		string.used = 0;
2247c478bd9Sstevel@tonic-gate 		string.mbs = mbs;
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate 		convert._state = initial;
2277c478bd9Sstevel@tonic-gate 		convert._next = convert._size = 0;
2287c478bd9Sstevel@tonic-gate 		convert.object = (void *) &string;
2297c478bd9Sstevel@tonic-gate 		convert.put = (int (*)(int, void *)) write_string;
2307c478bd9Sstevel@tonic-gate 	} /* else n == 0, continue appending to previous mbs. */
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate 	/* In case of error, rewind string to the last character. */
2337c478bd9Sstevel@tonic-gate 	last = string.used;
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 	if (cc == (cchar_t *) 0) {
2367c478bd9Sstevel@tonic-gate 		/* Force initial shift state. */
2377c478bd9Sstevel@tonic-gate 		if ((count = m_wio_put('\0', &convert)) < 0) {
2387c478bd9Sstevel@tonic-gate 			string.used = last;
2397c478bd9Sstevel@tonic-gate 			return -1;
2407c478bd9Sstevel@tonic-gate 		}
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate 		if (string.used < string.max)
2437c478bd9Sstevel@tonic-gate 			string.mbs[string.used++] = '\0';
2447c478bd9Sstevel@tonic-gate 	} else {
2457c478bd9Sstevel@tonic-gate 		for (count = i = 0; i < cc->_n; ++i, count += bytes)
2467c478bd9Sstevel@tonic-gate 			if ((bytes = m_wio_put(cc->_wc[i], &convert)) < 0) {
2477c478bd9Sstevel@tonic-gate 				string.used = last;
2487c478bd9Sstevel@tonic-gate 				return -1;
2497c478bd9Sstevel@tonic-gate 			}
2507c478bd9Sstevel@tonic-gate 	}
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate 	return count;
2537c478bd9Sstevel@tonic-gate }
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate /*
2567c478bd9Sstevel@tonic-gate  * Convert a stty character into a wchar_t.
2577c478bd9Sstevel@tonic-gate  */
2587c478bd9Sstevel@tonic-gate int
__m_tty_wc(index,wcp)2597c478bd9Sstevel@tonic-gate __m_tty_wc(index, wcp)
2607c478bd9Sstevel@tonic-gate int index;
2617c478bd9Sstevel@tonic-gate wchar_t *wcp;
2627c478bd9Sstevel@tonic-gate {
2637c478bd9Sstevel@tonic-gate 	char mb;
2647c478bd9Sstevel@tonic-gate 	int code;
2657c478bd9Sstevel@tonic-gate 
266*1da57d55SToomas Soome 	/* Refer to _shell instead of _prog, since _shell will
267*1da57d55SToomas Soome 	 * correctly reflect the user's prefered settings, whereas
268*1da57d55SToomas Soome 	 * _prog may not have been initialised if both input and
2697c478bd9Sstevel@tonic-gate 	 * output have been redirected.
2707c478bd9Sstevel@tonic-gate 	 */
2717c478bd9Sstevel@tonic-gate 	mb = cur_term->_shell.c_cc[index];
2727c478bd9Sstevel@tonic-gate 	code = mbtowc(wcp, &mb, 1) < 0 ? ERR : OK;
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate 	return code;
2757c478bd9Sstevel@tonic-gate }
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate /*
278*1da57d55SToomas Soome  * Build a cchar_t from the leading spacing and non-spacing characters
2797c478bd9Sstevel@tonic-gate  * in the multibyte character string.  Only one spacing character is copied
2807c478bd9Sstevel@tonic-gate  * from the multibyte character string.
2817c478bd9Sstevel@tonic-gate  *
2827c478bd9Sstevel@tonic-gate  * Return the number of characters copied from the string, or -1 on error.
2837c478bd9Sstevel@tonic-gate  */
2847c478bd9Sstevel@tonic-gate int
__m_mbs_cc(const char * mbs,attr_t at,short co,cchar_t * cc)2857c478bd9Sstevel@tonic-gate __m_mbs_cc(const char *mbs, attr_t at, short co, cchar_t *cc)
2867c478bd9Sstevel@tonic-gate {
2877c478bd9Sstevel@tonic-gate 	wchar_t wc;
2887c478bd9Sstevel@tonic-gate 	const char *start;
2897c478bd9Sstevel@tonic-gate 	int i, nbytes, width, have_one;
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate 	for (start = mbs, have_one = i = 0; *mbs != '\0'; mbs += nbytes, ++i) {
2927c478bd9Sstevel@tonic-gate 		if (sizeof cc->_wc <= i)
2937c478bd9Sstevel@tonic-gate 			/* Too many characters. */
2947c478bd9Sstevel@tonic-gate 			return -1;
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate 		if ((nbytes = mbtowc(&wc, mbs, UINT_MAX)) < 0)
2977c478bd9Sstevel@tonic-gate 			/* Invalid multibyte sequence. */
2987c478bd9Sstevel@tonic-gate 			return -1;
2997c478bd9Sstevel@tonic-gate 
3007c478bd9Sstevel@tonic-gate 		if (nbytes == 0)
3017c478bd9Sstevel@tonic-gate 			/* Remainder of string evaluates to the null byte. */
3027c478bd9Sstevel@tonic-gate 			break;
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 		if (iscntrl(*mbs))
3057c478bd9Sstevel@tonic-gate 			/* Treat control codes like a spacing character. */
3067c478bd9Sstevel@tonic-gate 			width = 1;
3077c478bd9Sstevel@tonic-gate 		else if ((width = wcwidth(wc)) < 0)
3087c478bd9Sstevel@tonic-gate 			return -1;
309*1da57d55SToomas Soome 
3107c478bd9Sstevel@tonic-gate 		/* Do we have a spacing character? */
3117c478bd9Sstevel@tonic-gate 		if (0 < width) {
3127c478bd9Sstevel@tonic-gate 			if (have_one)
3137c478bd9Sstevel@tonic-gate 				break;
3147c478bd9Sstevel@tonic-gate 			have_one = 1;
3157c478bd9Sstevel@tonic-gate 		}
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 		cc->_wc[i] = wc;
3187c478bd9Sstevel@tonic-gate 	}
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate         cc->_f = 1;
3217c478bd9Sstevel@tonic-gate 	cc->_n = i;
3227c478bd9Sstevel@tonic-gate         cc->_co = co;
3237c478bd9Sstevel@tonic-gate         cc->_at = at;
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 	(void) __m_cc_sort(cc);
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate 	return (int) (mbs - start);
3287c478bd9Sstevel@tonic-gate }
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate /*
331*1da57d55SToomas Soome  * Build a cchar_t from the leading spacing and non-spacing characters
3327c478bd9Sstevel@tonic-gate  * in the wide character string.  Only one spacinig character is copied
3337c478bd9Sstevel@tonic-gate  * from the wide character string.
3347c478bd9Sstevel@tonic-gate  *
3357c478bd9Sstevel@tonic-gate  * Return the number of characters copied from the string, or -1 on error.
3367c478bd9Sstevel@tonic-gate  */
3377c478bd9Sstevel@tonic-gate int
__m_wcs_cc(const wchar_t * wcs,attr_t at,short co,cchar_t * cc)3387c478bd9Sstevel@tonic-gate __m_wcs_cc(const wchar_t *wcs, attr_t at, short co, cchar_t *cc)
3397c478bd9Sstevel@tonic-gate {
3407c478bd9Sstevel@tonic-gate 	short i;
3417c478bd9Sstevel@tonic-gate 	int width, have_one;
3427c478bd9Sstevel@tonic-gate 	const wchar_t *start;
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate 	for (start = wcs, have_one = i = 0; *wcs != '\0'; ++wcs, ++i) {
3457c478bd9Sstevel@tonic-gate 		if (sizeof cc->_wc <= i)
3467c478bd9Sstevel@tonic-gate 			/* Too many characters. */
3477c478bd9Sstevel@tonic-gate 			return -1;
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate 		if ((width = wcwidth(*wcs)) < 0)
3507c478bd9Sstevel@tonic-gate 			return -1;
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 		if (0 < width) {
3537c478bd9Sstevel@tonic-gate 			if (have_one)
3547c478bd9Sstevel@tonic-gate 				break;
3557c478bd9Sstevel@tonic-gate 			have_one = 1;
3567c478bd9Sstevel@tonic-gate 		}
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate 		cc->_wc[i] = *wcs;
3597c478bd9Sstevel@tonic-gate 	}
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate         cc->_f = 1;
3627c478bd9Sstevel@tonic-gate 	cc->_n = i;
3637c478bd9Sstevel@tonic-gate         cc->_co = co;
3647c478bd9Sstevel@tonic-gate         cc->_at = at;
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate 	(void) __m_cc_sort(cc);
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate 	return (int) (wcs - start);
3697c478bd9Sstevel@tonic-gate }
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate /*
3727c478bd9Sstevel@tonic-gate  * Convert a single wide character into a complex character.
3737c478bd9Sstevel@tonic-gate  */
3747c478bd9Sstevel@tonic-gate int
__m_wc_cc(wint_t wc,cchar_t * cc)3757c478bd9Sstevel@tonic-gate __m_wc_cc(wint_t wc, cchar_t *cc)
3767c478bd9Sstevel@tonic-gate {
3777c478bd9Sstevel@tonic-gate 	wchar_t wcs[2];
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate 	if (wc == WEOF)
3807c478bd9Sstevel@tonic-gate 		return -1;
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate 	wcs[0] = (wchar_t)wc;
3837c478bd9Sstevel@tonic-gate 	wcs[1] = '\0';
3847c478bd9Sstevel@tonic-gate 	(void) __m_wcs_cc(wcs, WA_NORMAL, 0, cc);
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate 	return 0;
3877c478bd9Sstevel@tonic-gate }
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate /*
390*1da57d55SToomas Soome  * Sort a complex character into a spacing character followed
391*1da57d55SToomas Soome  * by any non-spacing characters in increasing order of oridinal
3927c478bd9Sstevel@tonic-gate  * values.  This facilitates both comparision and writting of
3937c478bd9Sstevel@tonic-gate  * complex characters.  More than one spacing character is
3947c478bd9Sstevel@tonic-gate  * considered an error.
3957c478bd9Sstevel@tonic-gate  *
3967c478bd9Sstevel@tonic-gate  * Return the spacing character's column width or -1 if more
3977c478bd9Sstevel@tonic-gate  * than one spacing character appears in cc.
3987c478bd9Sstevel@tonic-gate  */
3997c478bd9Sstevel@tonic-gate int
__m_cc_sort(cc)4007c478bd9Sstevel@tonic-gate __m_cc_sort(cc)
4017c478bd9Sstevel@tonic-gate cchar_t *cc;
4027c478bd9Sstevel@tonic-gate {
4037c478bd9Sstevel@tonic-gate 	wchar_t wc;
4047c478bd9Sstevel@tonic-gate 	int width, i, j, spacing;
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate 	/* Find spacing character and place in as first element. */
4077c478bd9Sstevel@tonic-gate 	for (width = spacing = i = 0; i < cc->_n; ++i) {
4087c478bd9Sstevel@tonic-gate 		j = wcwidth(cc->_wc[i]);
4097c478bd9Sstevel@tonic-gate 		if (0 < j) {
4107c478bd9Sstevel@tonic-gate 			/* More than one spacing character is an error. */
4117c478bd9Sstevel@tonic-gate 			if (0 < width)
4127c478bd9Sstevel@tonic-gate 				return -1;
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate 			wc = cc->_wc[0];
4157c478bd9Sstevel@tonic-gate 			cc->_wc[0] = cc->_wc[i];
4167c478bd9Sstevel@tonic-gate 			cc->_wc[i]  = wc;
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate 			spacing = 1;
4197c478bd9Sstevel@tonic-gate 			width = j;
4207c478bd9Sstevel@tonic-gate 			break;
4217c478bd9Sstevel@tonic-gate 		}
4227c478bd9Sstevel@tonic-gate 	}
4237c478bd9Sstevel@tonic-gate 
4247c478bd9Sstevel@tonic-gate 	/* Bubble sort small array. */
4257c478bd9Sstevel@tonic-gate 	for (i = spacing; i < cc->_n; ++i) {
4267c478bd9Sstevel@tonic-gate 		for (j = cc->_n - 1; i < j; --j) {
4277c478bd9Sstevel@tonic-gate 			if (cc->_wc[j-1] > cc->_wc[j]) {
4287c478bd9Sstevel@tonic-gate 				wc = cc->_wc[j];
4297c478bd9Sstevel@tonic-gate 				cc->_wc[j] = cc->_wc[j-1];
4307c478bd9Sstevel@tonic-gate 				cc->_wc[j-1]  = wc;
4317c478bd9Sstevel@tonic-gate 			}
4327c478bd9Sstevel@tonic-gate 		}
4337c478bd9Sstevel@tonic-gate 	}
434*1da57d55SToomas Soome 
4357c478bd9Sstevel@tonic-gate 	return width;
4367c478bd9Sstevel@tonic-gate }
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate /*
4397c478bd9Sstevel@tonic-gate  * Return width inn screen columns of the character.
4407c478bd9Sstevel@tonic-gate  */
4417c478bd9Sstevel@tonic-gate int
__m_cc_width(cc)4427c478bd9Sstevel@tonic-gate __m_cc_width(cc)
4437c478bd9Sstevel@tonic-gate const cchar_t *cc;
4447c478bd9Sstevel@tonic-gate {
4457c478bd9Sstevel@tonic-gate 	return wcwidth(cc->_wc[0]);
4467c478bd9Sstevel@tonic-gate }
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate /*
4497c478bd9Sstevel@tonic-gate  * Return the first column of a multi-column character, in window.
4507c478bd9Sstevel@tonic-gate  */
4517c478bd9Sstevel@tonic-gate int
__m_cc_first(w,y,x)4527c478bd9Sstevel@tonic-gate __m_cc_first(w, y, x)
4537c478bd9Sstevel@tonic-gate WINDOW *w;
4547c478bd9Sstevel@tonic-gate int y, x;
4557c478bd9Sstevel@tonic-gate {
4567c478bd9Sstevel@tonic-gate 	register cchar_t *lp;
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate 	for (lp = w->_line[y]; 0 < x; --x) {
4597c478bd9Sstevel@tonic-gate 		if (lp[x]._f)
4607c478bd9Sstevel@tonic-gate 			break;
4617c478bd9Sstevel@tonic-gate 	}
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate 	return x;
4647c478bd9Sstevel@tonic-gate }
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate /*
4677c478bd9Sstevel@tonic-gate  * Return the start of the next multi-column character, in window.
4687c478bd9Sstevel@tonic-gate  */
4697c478bd9Sstevel@tonic-gate int
__m_cc_next(w,y,x)4707c478bd9Sstevel@tonic-gate __m_cc_next(w, y, x)
4717c478bd9Sstevel@tonic-gate WINDOW *w;
4727c478bd9Sstevel@tonic-gate int y, x;
4737c478bd9Sstevel@tonic-gate {
4747c478bd9Sstevel@tonic-gate 	cchar_t *lp;
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate 	for (lp = w->_line[y]; ++x < w->_maxx; ) {
4777c478bd9Sstevel@tonic-gate 		if (lp[x]._f)
4787c478bd9Sstevel@tonic-gate 			break;
4797c478bd9Sstevel@tonic-gate 	}
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate 	return x;
4827c478bd9Sstevel@tonic-gate }
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate /*
4857c478bd9Sstevel@tonic-gate  * Return true if valid last column of a multi-column character.
4867c478bd9Sstevel@tonic-gate  */
4877c478bd9Sstevel@tonic-gate int
__m_cc_islast(w,y,x)4887c478bd9Sstevel@tonic-gate __m_cc_islast(w, y, x)
4897c478bd9Sstevel@tonic-gate WINDOW *w;
4907c478bd9Sstevel@tonic-gate int y, x;
4917c478bd9Sstevel@tonic-gate {
4927c478bd9Sstevel@tonic-gate 	int first, width;
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate 	first = __m_cc_first(w, y, x);
4957c478bd9Sstevel@tonic-gate 	width = __m_cc_width(&w->_line[y][x]);
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 	return first + width == x + 1;
4987c478bd9Sstevel@tonic-gate }
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate /*
5017c478bd9Sstevel@tonic-gate  * Replace the character at the current cursor location
5027c478bd9Sstevel@tonic-gate  * according to the column width of the character.  The
5037c478bd9Sstevel@tonic-gate  * cursor does not advance.
5047c478bd9Sstevel@tonic-gate  *
5057c478bd9Sstevel@tonic-gate  * Return -1 if the character won't fit on the line and the background
5067c478bd9Sstevel@tonic-gate  * was written in its place; else return the width of the character in
5077c478bd9Sstevel@tonic-gate  * screen columns.
5087c478bd9Sstevel@tonic-gate  */
5097c478bd9Sstevel@tonic-gate int
__m_cc_replace(w,y,x,cc,as_is)5107c478bd9Sstevel@tonic-gate __m_cc_replace(w, y, x, cc, as_is)
5117c478bd9Sstevel@tonic-gate WINDOW *w;
512*1da57d55SToomas Soome int y, x;
5137c478bd9Sstevel@tonic-gate const cchar_t *cc;
5147c478bd9Sstevel@tonic-gate int as_is;
5157c478bd9Sstevel@tonic-gate {
516*1da57d55SToomas Soome 	int i, width;
5177c478bd9Sstevel@tonic-gate 	cchar_t *cp, *np;
5187c478bd9Sstevel@tonic-gate 
5197c478bd9Sstevel@tonic-gate 	width = __m_cc_width(cc);
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate         /* If we try to write a broad character that would exceed the
5227c478bd9Sstevel@tonic-gate          * right margin, then write the background character instead.
523*1da57d55SToomas Soome          */
5247c478bd9Sstevel@tonic-gate 	if (0 < width && w->_maxx < x + width) {
5257c478bd9Sstevel@tonic-gate 		(void) __m_cc_erase(w, y, x, y, w->_maxx-1);
5267c478bd9Sstevel@tonic-gate 		return -1;
5277c478bd9Sstevel@tonic-gate 	}
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate 	/* Erase the region to be occupied by the new character.
5307c478bd9Sstevel@tonic-gate 	 * __m_cc_erase() will erase whole characters so that
5317c478bd9Sstevel@tonic-gate 	 * writing a multicolumn character that overwrites the
532*1da57d55SToomas Soome 	 * trailing and leading portions of two already existing
5337c478bd9Sstevel@tonic-gate 	 * multicolumn characters, erases the remaining portions.
5347c478bd9Sstevel@tonic-gate 	 */
5357c478bd9Sstevel@tonic-gate 	(void) __m_cc_erase(w, y, x, y, x + width - 1);
5367c478bd9Sstevel@tonic-gate 
5377c478bd9Sstevel@tonic-gate 	/* Write the first column of the character. */
5387c478bd9Sstevel@tonic-gate 	cp = &w->_line[y][x++];
5397c478bd9Sstevel@tonic-gate 	if (cc->_wc[0] == ' ' || cc->_wc[0] == M_MB_L(' ')) {
5407c478bd9Sstevel@tonic-gate 		*cp = w->_bg;
5417c478bd9Sstevel@tonic-gate 		cp->_at |= cc->_at;
5427c478bd9Sstevel@tonic-gate 		if (cc->_co != 0)
5437c478bd9Sstevel@tonic-gate 			cp->_co = cc->_co;
5447c478bd9Sstevel@tonic-gate 	} else {
5457c478bd9Sstevel@tonic-gate 		(void) __m_wacs_cc(cc, cp);
5467c478bd9Sstevel@tonic-gate 		if (cc->_co == 0)
5477c478bd9Sstevel@tonic-gate 			cp->_co = w->_fg._co;
5487c478bd9Sstevel@tonic-gate 	}
5497c478bd9Sstevel@tonic-gate 
5507c478bd9Sstevel@tonic-gate 	cp->_at |= w->_fg._at | w->_bg._at;
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate 	/* Mark this as the first column of the character. */
5537c478bd9Sstevel@tonic-gate 	cp->_f = 1;
5547c478bd9Sstevel@tonic-gate 
5557c478bd9Sstevel@tonic-gate 	/* Duplicate the character in every column the character occupies. */
5567c478bd9Sstevel@tonic-gate 	for (np = cp + 1, i = 1; i < width; ++i, ++x, ++np) {
5577c478bd9Sstevel@tonic-gate 		*np = *cp;
5587c478bd9Sstevel@tonic-gate 		np->_f = 0;
5597c478bd9Sstevel@tonic-gate 	}
5607c478bd9Sstevel@tonic-gate 
5617c478bd9Sstevel@tonic-gate 	return width;
5627c478bd9Sstevel@tonic-gate }
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate int
__m_do_scroll(WINDOW * w,int y,int x,int * yp,int * xp)5657c478bd9Sstevel@tonic-gate __m_do_scroll(WINDOW *w, int y, int x, int *yp, int *xp)
5667c478bd9Sstevel@tonic-gate {
5677c478bd9Sstevel@tonic-gate 	if (w->_maxx <= x)
5687c478bd9Sstevel@tonic-gate 		x = w->_maxx-1;
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate 	++y;
5717c478bd9Sstevel@tonic-gate 
5727c478bd9Sstevel@tonic-gate 	if (y == w->_bottom) {
5737c478bd9Sstevel@tonic-gate 		--y;
5747c478bd9Sstevel@tonic-gate 		if (w->_flags & W_CAN_SCROLL) {
5757c478bd9Sstevel@tonic-gate 			if (wscrl(w, 1) == ERR)
5767c478bd9Sstevel@tonic-gate 				return ERR;
5777c478bd9Sstevel@tonic-gate 			x = 0;
5787c478bd9Sstevel@tonic-gate 		}
5797c478bd9Sstevel@tonic-gate 	} else if (w->_maxy <= y) {
5807c478bd9Sstevel@tonic-gate 		y = w->_maxy-1;
5817c478bd9Sstevel@tonic-gate 	} else {
5827c478bd9Sstevel@tonic-gate 		/* The cursor wraps for any line (in and out of the scroll
583*1da57d55SToomas Soome 		 * region) except for the last line of the scroll region.
5847c478bd9Sstevel@tonic-gate 		 */
5857c478bd9Sstevel@tonic-gate 		x = 0;
5867c478bd9Sstevel@tonic-gate 	}
5877c478bd9Sstevel@tonic-gate 
5887c478bd9Sstevel@tonic-gate 	*yp = y;
5897c478bd9Sstevel@tonic-gate 	*xp = x;
5907c478bd9Sstevel@tonic-gate 
5917c478bd9Sstevel@tonic-gate 	return OK;
5927c478bd9Sstevel@tonic-gate }
5937c478bd9Sstevel@tonic-gate 
5947c478bd9Sstevel@tonic-gate /*
5957c478bd9Sstevel@tonic-gate  * Add the character at the current cursor location
596*1da57d55SToomas Soome  * according to the column width of the character.
5977c478bd9Sstevel@tonic-gate  * The cursor will be advanced.
5987c478bd9Sstevel@tonic-gate  *
5997c478bd9Sstevel@tonic-gate  * Return ERR if adding the character causes the
6007c478bd9Sstevel@tonic-gate  * screen to scroll, when it is disallowed.
6017c478bd9Sstevel@tonic-gate  */
6027c478bd9Sstevel@tonic-gate int
__m_cc_add(w,y,x,cc,as_is,yp,xp)6037c478bd9Sstevel@tonic-gate __m_cc_add(w, y, x, cc, as_is, yp, xp)
6047c478bd9Sstevel@tonic-gate WINDOW *w;
605*1da57d55SToomas Soome int y, x;
6067c478bd9Sstevel@tonic-gate const cchar_t *cc;
6077c478bd9Sstevel@tonic-gate int as_is, *yp, *xp;
6087c478bd9Sstevel@tonic-gate {
6097c478bd9Sstevel@tonic-gate 	int nx, width, code = ERR;
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate #ifdef M_CURSES_TRACE
6127c478bd9Sstevel@tonic-gate 	__m_trace(
613*1da57d55SToomas Soome 		"__m_cc_add(%p, %d, %d, %p, %d, %p, %p)",
6147c478bd9Sstevel@tonic-gate 		w, y, x, cc, as_is, yp, xp
6157c478bd9Sstevel@tonic-gate 	);
6167c478bd9Sstevel@tonic-gate #endif
6177c478bd9Sstevel@tonic-gate 
6187c478bd9Sstevel@tonic-gate 	switch (cc->_wc[0]) {
6197c478bd9Sstevel@tonic-gate 	case '\t':
6207c478bd9Sstevel@tonic-gate 		nx = x + (8 - (x & 07));
6217c478bd9Sstevel@tonic-gate 		if (__m_cc_erase(w, y, x, y, nx-1) == -1)
6227c478bd9Sstevel@tonic-gate 			goto error;
6237c478bd9Sstevel@tonic-gate 		x = nx;
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate 		if (w->_maxx <= x) {
6267c478bd9Sstevel@tonic-gate 			if (__m_do_scroll(w, y, x, &y, &x) == ERR)
6277c478bd9Sstevel@tonic-gate 				goto error;
6287c478bd9Sstevel@tonic-gate 		}
6297c478bd9Sstevel@tonic-gate 		break;
6307c478bd9Sstevel@tonic-gate 	case '\n':
6317c478bd9Sstevel@tonic-gate 		if (__m_cc_erase(w, y, x, y, w->_maxx-1) == -1)
6327c478bd9Sstevel@tonic-gate 			goto error;
633*1da57d55SToomas Soome 
6347c478bd9Sstevel@tonic-gate 		if (__m_do_scroll(w, y, x, &y, &x) == ERR)
6357c478bd9Sstevel@tonic-gate 			goto error;
6367c478bd9Sstevel@tonic-gate 		break;
6377c478bd9Sstevel@tonic-gate 	case '\r':
6387c478bd9Sstevel@tonic-gate 		x = 0;
6397c478bd9Sstevel@tonic-gate 		break;
6407c478bd9Sstevel@tonic-gate 	case '\b':
6417c478bd9Sstevel@tonic-gate 		if (0 < x)
6427c478bd9Sstevel@tonic-gate 			--x;
6437c478bd9Sstevel@tonic-gate 		break;
6447c478bd9Sstevel@tonic-gate 	default:
6457c478bd9Sstevel@tonic-gate 		width = __m_cc_replace(w, y, x, cc, as_is);
6467c478bd9Sstevel@tonic-gate 
6477c478bd9Sstevel@tonic-gate 		x += width;
6487c478bd9Sstevel@tonic-gate 
6497c478bd9Sstevel@tonic-gate 		if (width < 0 || w->_maxx <= x) {
6507c478bd9Sstevel@tonic-gate 			if (__m_do_scroll(w, y, x, &y, &x) == ERR)
6517c478bd9Sstevel@tonic-gate 				goto error;
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate 			if (width < 0)
6547c478bd9Sstevel@tonic-gate 				x += __m_cc_replace(w, y, x, cc, as_is);
6557c478bd9Sstevel@tonic-gate 		}
6567c478bd9Sstevel@tonic-gate 	}
6577c478bd9Sstevel@tonic-gate 
6587c478bd9Sstevel@tonic-gate 	code = OK;
6597c478bd9Sstevel@tonic-gate error:
6607c478bd9Sstevel@tonic-gate 	*yp = y;
6617c478bd9Sstevel@tonic-gate 	*xp = x;
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate 	return __m_return_code("__m_cc_add", code);
6647c478bd9Sstevel@tonic-gate }
6657c478bd9Sstevel@tonic-gate 
6667c478bd9Sstevel@tonic-gate /*
6677c478bd9Sstevel@tonic-gate  * Erase region from (y,x) to (ly, lx) inclusive.  The
6687c478bd9Sstevel@tonic-gate  * region is extended left and right in the case where
6697c478bd9Sstevel@tonic-gate  * the portions of a multicolumn characters are erased.
6707c478bd9Sstevel@tonic-gate  *
671*1da57d55SToomas Soome  * Return -1 if the region is not an integral multiple
6727c478bd9Sstevel@tonic-gate  * of the background character, else zero for success.
6737c478bd9Sstevel@tonic-gate  */
6747c478bd9Sstevel@tonic-gate int
__m_cc_erase(w,y,x,ly,lx)6757c478bd9Sstevel@tonic-gate __m_cc_erase(w, y, x, ly, lx)
6767c478bd9Sstevel@tonic-gate WINDOW *w;
6777c478bd9Sstevel@tonic-gate int y, x, ly, lx;
6787c478bd9Sstevel@tonic-gate {
6797c478bd9Sstevel@tonic-gate 	cchar_t *cp;
6807c478bd9Sstevel@tonic-gate 	int i, width;
6817c478bd9Sstevel@tonic-gate 
6827c478bd9Sstevel@tonic-gate 	if (ly < y)
6837c478bd9Sstevel@tonic-gate 		return -1;
6847c478bd9Sstevel@tonic-gate 
6857c478bd9Sstevel@tonic-gate 	if (w->_maxy <= ly)
6867c478bd9Sstevel@tonic-gate 		ly = w->_maxy - 1;
6877c478bd9Sstevel@tonic-gate 	if (w->_maxx <= lx)
6887c478bd9Sstevel@tonic-gate 		lx = w->_maxx - 1;
6897c478bd9Sstevel@tonic-gate 
690*1da57d55SToomas Soome 	/* Erase from first whole character (inclusive) to next
6917c478bd9Sstevel@tonic-gate 	 * character (exclusive).
6927c478bd9Sstevel@tonic-gate 	 */
6937c478bd9Sstevel@tonic-gate 	x = __m_cc_first(w, y, x);
6947c478bd9Sstevel@tonic-gate 	lx = __m_cc_next(w, ly, lx) - 1;
6957c478bd9Sstevel@tonic-gate 
696*1da57d55SToomas Soome 	/* Is the region to blank out an integral width of the
6977c478bd9Sstevel@tonic-gate 	 * background character?
6987c478bd9Sstevel@tonic-gate 	 */
6997c478bd9Sstevel@tonic-gate 	width = __m_cc_width(&w->_bg);
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate 	if (y < ly && (lx + 1) % width != 0)
7027c478bd9Sstevel@tonic-gate 		return -1;
7037c478bd9Sstevel@tonic-gate 	if ((lx - x + 1) % width != 0)
7047c478bd9Sstevel@tonic-gate 		return -1;
7057c478bd9Sstevel@tonic-gate 
7067c478bd9Sstevel@tonic-gate 	for (; y < ly; ++y, x = 0) {
7077c478bd9Sstevel@tonic-gate 		if (x < w->_first[y])
7087c478bd9Sstevel@tonic-gate 			w->_first[y] = (short) x;
709*1da57d55SToomas Soome 
7107c478bd9Sstevel@tonic-gate 		for (cp = w->_line[y], i = 0; x < w->_maxx; ++x, ++i) {
7117c478bd9Sstevel@tonic-gate 			cp[x] = w->_bg;
7127c478bd9Sstevel@tonic-gate 
7137c478bd9Sstevel@tonic-gate 			/* The start of each new character will be set true
7147c478bd9Sstevel@tonic-gate 			 * while internal columns of the character will be
7157c478bd9Sstevel@tonic-gate 			 * reset to false.
7167c478bd9Sstevel@tonic-gate 			 */
7177c478bd9Sstevel@tonic-gate 			cp[x]._f = (short) (i % width == 0);
7187c478bd9Sstevel@tonic-gate 		}
719*1da57d55SToomas Soome 
7207c478bd9Sstevel@tonic-gate 		if (w->_last[y] < x)
7217c478bd9Sstevel@tonic-gate 			w->_last[y] = (short) x;
7227c478bd9Sstevel@tonic-gate 	}
7237c478bd9Sstevel@tonic-gate 
7247c478bd9Sstevel@tonic-gate 	if (x < w->_first[y])
7257c478bd9Sstevel@tonic-gate 		w->_first[y] = (short) x;
7267c478bd9Sstevel@tonic-gate 
7277c478bd9Sstevel@tonic-gate 	for (cp = w->_line[y], i = 0; x <= lx; ++x, ++i) {
7287c478bd9Sstevel@tonic-gate 		cp[x] = w->_bg;
7297c478bd9Sstevel@tonic-gate 
7307c478bd9Sstevel@tonic-gate 		/* The start of each new character will be set true
7317c478bd9Sstevel@tonic-gate 		 * while internal columns of the character will be
7327c478bd9Sstevel@tonic-gate 		 * reset to false.
7337c478bd9Sstevel@tonic-gate 		 */
7347c478bd9Sstevel@tonic-gate 		cp[x]._f = (short) (i % width == 0);
7357c478bd9Sstevel@tonic-gate 	}
7367c478bd9Sstevel@tonic-gate 
7377c478bd9Sstevel@tonic-gate 	if (w->_last[y] < x)
7387c478bd9Sstevel@tonic-gate 		w->_last[y] = (short) x;
7397c478bd9Sstevel@tonic-gate 
7407c478bd9Sstevel@tonic-gate 	return 0;
7417c478bd9Sstevel@tonic-gate }
7427c478bd9Sstevel@tonic-gate 
7437c478bd9Sstevel@tonic-gate /*
7447c478bd9Sstevel@tonic-gate  * Expand the character to the left or right of the given position.
7457c478bd9Sstevel@tonic-gate  * Return the value returned by __m_cc_replace().
7467c478bd9Sstevel@tonic-gate  */
7477c478bd9Sstevel@tonic-gate int
__m_cc_expand(w,y,x,side)7487c478bd9Sstevel@tonic-gate __m_cc_expand(w, y, x, side)
7497c478bd9Sstevel@tonic-gate WINDOW *w;
7507c478bd9Sstevel@tonic-gate int y, x, side;
7517c478bd9Sstevel@tonic-gate {
7527c478bd9Sstevel@tonic-gate 	cchar_t cc;
7537c478bd9Sstevel@tonic-gate 	int dx, width;
7547c478bd9Sstevel@tonic-gate 
7557c478bd9Sstevel@tonic-gate 	width = __m_cc_width(&w->_line[y][x]);
7567c478bd9Sstevel@tonic-gate 
7577c478bd9Sstevel@tonic-gate 	if (side < 0)
7587c478bd9Sstevel@tonic-gate 		dx = __m_cc_next(w, y, x) - width;
7597c478bd9Sstevel@tonic-gate 	else if (0 < side)
7607c478bd9Sstevel@tonic-gate 		dx = __m_cc_first(w, y, x);
7617c478bd9Sstevel@tonic-gate 	else
7627c478bd9Sstevel@tonic-gate 		return -1;
7637c478bd9Sstevel@tonic-gate 
764*1da57d55SToomas Soome 	/* __m_cc_replace() will erase the region containing
7657c478bd9Sstevel@tonic-gate 	 * the character we want to expand.
7667c478bd9Sstevel@tonic-gate 	 */
7677c478bd9Sstevel@tonic-gate 	cc = w->_line[y][x];
7687c478bd9Sstevel@tonic-gate 
7697c478bd9Sstevel@tonic-gate 	return __m_cc_replace(w, y, dx, &cc, 0);
7707c478bd9Sstevel@tonic-gate }
7717c478bd9Sstevel@tonic-gate 
7727c478bd9Sstevel@tonic-gate /*
773*1da57d55SToomas Soome  * Return true if characters are equal.
7747c478bd9Sstevel@tonic-gate  *
7757c478bd9Sstevel@tonic-gate  * NOTE to guarantee correct results, make sure that both
7767c478bd9Sstevel@tonic-gate  * characters have been passed through __m_cc_sort().
7777c478bd9Sstevel@tonic-gate  */
7787c478bd9Sstevel@tonic-gate int
__m_cc_compare(c1,c2,exact)7797c478bd9Sstevel@tonic-gate __m_cc_compare(c1, c2, exact)
7807c478bd9Sstevel@tonic-gate const cchar_t *c1, *c2;
7817c478bd9Sstevel@tonic-gate int exact;
7827c478bd9Sstevel@tonic-gate {
7837c478bd9Sstevel@tonic-gate 	int i;
7847c478bd9Sstevel@tonic-gate 
7857c478bd9Sstevel@tonic-gate 	if (exact && c1->_f != c2->_f)
7867c478bd9Sstevel@tonic-gate 		return 0;
7877c478bd9Sstevel@tonic-gate 	if (c1->_n != c2->_n)
7887c478bd9Sstevel@tonic-gate 		return 0;
7897c478bd9Sstevel@tonic-gate 	if ((c1->_at & ~WA_COOKIE) != (c2->_at & ~WA_COOKIE))
7907c478bd9Sstevel@tonic-gate 		return 0;
7917c478bd9Sstevel@tonic-gate 	if (c1->_co != c2->_co)
7927c478bd9Sstevel@tonic-gate 		return 0;
7937c478bd9Sstevel@tonic-gate 
7947c478bd9Sstevel@tonic-gate 	for (i = 0; i < c1->_n; ++i)
7957c478bd9Sstevel@tonic-gate 		if (c1->_wc[i] != c2->_wc[i])
7967c478bd9Sstevel@tonic-gate 			return 0;
7977c478bd9Sstevel@tonic-gate 
7987c478bd9Sstevel@tonic-gate 	return 1;
7997c478bd9Sstevel@tonic-gate }
8007c478bd9Sstevel@tonic-gate 
8017c478bd9Sstevel@tonic-gate /*
8027c478bd9Sstevel@tonic-gate  * Write to the stream the character portion of a cchar_t.
8037c478bd9Sstevel@tonic-gate  */
8047c478bd9Sstevel@tonic-gate int
__m_cc_write(cc)8057c478bd9Sstevel@tonic-gate __m_cc_write(cc)
8067c478bd9Sstevel@tonic-gate const cchar_t *cc;
8077c478bd9Sstevel@tonic-gate {
8087c478bd9Sstevel@tonic-gate 	size_t i, j;
8097c478bd9Sstevel@tonic-gate 	char mb[MB_LEN_MAX];
8107c478bd9Sstevel@tonic-gate 
8117c478bd9Sstevel@tonic-gate 	errno = 0;
8127c478bd9Sstevel@tonic-gate 	for (i = 0; i < cc->_n; ++i) {
8137c478bd9Sstevel@tonic-gate 		j = wcrtomb(mb, cc->_wc[i], &__m_screen->_state);
8147c478bd9Sstevel@tonic-gate 		if (errno != 0)
8157c478bd9Sstevel@tonic-gate 			return EOF;
8167c478bd9Sstevel@tonic-gate 		if (fwrite(mb, sizeof *mb, j, __m_screen->_of) == 0)
8177c478bd9Sstevel@tonic-gate 			return EOF;
8187c478bd9Sstevel@tonic-gate 	}
8197c478bd9Sstevel@tonic-gate 
8207c478bd9Sstevel@tonic-gate 	return 0;
8217c478bd9Sstevel@tonic-gate }
822