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