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
5*759f6fc9Srm * Common Development and Distribution License (the "License").
6*759f6fc9Srm * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
22*759f6fc9Srm * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
237c478bd9Sstevel@tonic-gate * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate */
257c478bd9Sstevel@tonic-gate
267c478bd9Sstevel@tonic-gate /* LINTLIBRARY */
277c478bd9Sstevel@tonic-gate
287c478bd9Sstevel@tonic-gate /*
297c478bd9Sstevel@tonic-gate * m_cc.c
307c478bd9Sstevel@tonic-gate *
317c478bd9Sstevel@tonic-gate * XCurses Library
327c478bd9Sstevel@tonic-gate *
337c478bd9Sstevel@tonic-gate * Copyright 1990, 1995 by Mortice Kern Systems Inc. All rights reserved.
347c478bd9Sstevel@tonic-gate *
357c478bd9Sstevel@tonic-gate */
367c478bd9Sstevel@tonic-gate
377c478bd9Sstevel@tonic-gate #if M_RCSID
387c478bd9Sstevel@tonic-gate #ifndef lint
397c478bd9Sstevel@tonic-gate static char rcsID[] =
407c478bd9Sstevel@tonic-gate "$Header: /team/ps/sun_xcurses/archive/local_changes/xcurses/src/lib/"
417c478bd9Sstevel@tonic-gate "libxcurses/src/libc/xcurses/rcs/m_cc.c 1.40 1998/06/12 12:45:39 "
427c478bd9Sstevel@tonic-gate "cbates Exp $";
437c478bd9Sstevel@tonic-gate #endif
447c478bd9Sstevel@tonic-gate #endif
457c478bd9Sstevel@tonic-gate
467c478bd9Sstevel@tonic-gate #include <private.h>
477c478bd9Sstevel@tonic-gate #include <limits.h>
487c478bd9Sstevel@tonic-gate #include <m_wio.h>
497c478bd9Sstevel@tonic-gate #include <string.h>
507c478bd9Sstevel@tonic-gate
517c478bd9Sstevel@tonic-gate typedef struct {
527c478bd9Sstevel@tonic-gate int max;
537c478bd9Sstevel@tonic-gate int used;
547c478bd9Sstevel@tonic-gate char *mbs;
557c478bd9Sstevel@tonic-gate } t_string;
567c478bd9Sstevel@tonic-gate
577c478bd9Sstevel@tonic-gate static int
write_string(int byte,t_string * sp)587c478bd9Sstevel@tonic-gate write_string(int byte, t_string *sp)
597c478bd9Sstevel@tonic-gate {
607c478bd9Sstevel@tonic-gate if (sp->max <= sp->used)
617c478bd9Sstevel@tonic-gate return (EOF);
627c478bd9Sstevel@tonic-gate
637c478bd9Sstevel@tonic-gate sp->mbs[sp->used++] = (char)byte;
647c478bd9Sstevel@tonic-gate
657c478bd9Sstevel@tonic-gate return (byte);
667c478bd9Sstevel@tonic-gate }
677c478bd9Sstevel@tonic-gate
687c478bd9Sstevel@tonic-gate /*
697c478bd9Sstevel@tonic-gate * Convert a wint_t string into a multibyte string.
707c478bd9Sstevel@tonic-gate *
717c478bd9Sstevel@tonic-gate * The conversion stops at the end of string or the first WEOF.
727c478bd9Sstevel@tonic-gate * Return the number of bytes successfully placed into mbs.
737c478bd9Sstevel@tonic-gate */
747c478bd9Sstevel@tonic-gate int
wistombs(char * mbs,const wint_t * wis,int n)757c478bd9Sstevel@tonic-gate wistombs(char *mbs, const wint_t *wis, int n)
767c478bd9Sstevel@tonic-gate {
777c478bd9Sstevel@tonic-gate int last;
787c478bd9Sstevel@tonic-gate t_string string = { 0 };
797c478bd9Sstevel@tonic-gate t_wide_io convert = { 0 };
807c478bd9Sstevel@tonic-gate
817c478bd9Sstevel@tonic-gate string.max = n;
827c478bd9Sstevel@tonic-gate string.mbs = mbs;
837c478bd9Sstevel@tonic-gate convert.object = (void *) &string;
847c478bd9Sstevel@tonic-gate convert.put = (int (*)(int, void *)) write_string;
857c478bd9Sstevel@tonic-gate
867c478bd9Sstevel@tonic-gate for (; ; ++wis) {
877c478bd9Sstevel@tonic-gate /* In case of error, rewind string to the last character. */
887c478bd9Sstevel@tonic-gate last = string.used;
897c478bd9Sstevel@tonic-gate
907c478bd9Sstevel@tonic-gate if (m_wio_put(*wis, &convert) < 0) {
917c478bd9Sstevel@tonic-gate string.used = last;
927c478bd9Sstevel@tonic-gate break;
937c478bd9Sstevel@tonic-gate }
947c478bd9Sstevel@tonic-gate
957c478bd9Sstevel@tonic-gate /*
967c478bd9Sstevel@tonic-gate * Test for end of string AFTER trying to copy into the
977c478bd9Sstevel@tonic-gate * buffer, because m_wio_put() has to handle state changes
987c478bd9Sstevel@tonic-gate * back to the initial state on '\0' or WEOF.
997c478bd9Sstevel@tonic-gate */
1007c478bd9Sstevel@tonic-gate if (*wis == '\0' || *wis == WEOF)
1017c478bd9Sstevel@tonic-gate break;
1027c478bd9Sstevel@tonic-gate }
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(wchar_t * wcs,const wint_t * wis,int n)1237c478bd9Sstevel@tonic-gate wistowcs(wchar_t *wcs, const wint_t *wis, int n)
1247c478bd9Sstevel@tonic-gate {
1257c478bd9Sstevel@tonic-gate wchar_t *start;
1267c478bd9Sstevel@tonic-gate
1277c478bd9Sstevel@tonic-gate if (n < 0)
1287c478bd9Sstevel@tonic-gate n = INT_MAX;
1297c478bd9Sstevel@tonic-gate
1307c478bd9Sstevel@tonic-gate for (start = wcs; *wis != '\0' && 0 < n; ++wis, ++wcs, --n) {
1317c478bd9Sstevel@tonic-gate if (*wis == WEOF)
1327c478bd9Sstevel@tonic-gate break;
1337c478bd9Sstevel@tonic-gate *wcs = (wchar_t)*wis;
1347c478bd9Sstevel@tonic-gate }
1357c478bd9Sstevel@tonic-gate *wcs = '\0';
1367c478bd9Sstevel@tonic-gate
1377c478bd9Sstevel@tonic-gate /* (wcs - start) should be enough small to fit in "int" */
1387c478bd9Sstevel@tonic-gate return ((int)(wcs - start));
1397c478bd9Sstevel@tonic-gate }
1407c478bd9Sstevel@tonic-gate
1417c478bd9Sstevel@tonic-gate void
__m_touch_locs(WINDOW * w,int row,int firstCol,int lastCol)1427c478bd9Sstevel@tonic-gate __m_touch_locs(WINDOW *w, int row, int firstCol, int lastCol)
1437c478bd9Sstevel@tonic-gate {
1447c478bd9Sstevel@tonic-gate if (w) {
1457c478bd9Sstevel@tonic-gate if (firstCol < w->_first[row])
1467c478bd9Sstevel@tonic-gate w->_first[row] = (short)firstCol;
1477c478bd9Sstevel@tonic-gate if (lastCol > w->_last[row])
1487c478bd9Sstevel@tonic-gate w->_last[row] = (short)lastCol;
1497c478bd9Sstevel@tonic-gate }
1507c478bd9Sstevel@tonic-gate }
1517c478bd9Sstevel@tonic-gate
1527c478bd9Sstevel@tonic-gate /*
1537c478bd9Sstevel@tonic-gate * Convert a chtype to a cchar_t.
1547c478bd9Sstevel@tonic-gate */
1557c478bd9Sstevel@tonic-gate int
__m_chtype_cc(chtype ch,cchar_t * cc)1567c478bd9Sstevel@tonic-gate __m_chtype_cc(chtype ch, cchar_t *cc)
1577c478bd9Sstevel@tonic-gate {
1587c478bd9Sstevel@tonic-gate char mb;
1597c478bd9Sstevel@tonic-gate
1607c478bd9Sstevel@tonic-gate cc->_f = 1;
1617c478bd9Sstevel@tonic-gate cc->_n = 1;
1627c478bd9Sstevel@tonic-gate mb = (char)(ch & A_CHARTEXT);
1637c478bd9Sstevel@tonic-gate
1647c478bd9Sstevel@tonic-gate cc->_co = (short)PAIR_NUMBER((int)ch);
1657c478bd9Sstevel@tonic-gate cc->_at = (attr_t)((ch & (A_ATTRIBUTES & ~A_COLOR)) >> 16);
1667c478bd9Sstevel@tonic-gate
1677c478bd9Sstevel@tonic-gate if (mb == 0)
1687c478bd9Sstevel@tonic-gate cc->_wc[0] = cc->_wc[1] = 0;
1697c478bd9Sstevel@tonic-gate else if (mbtowc(cc->_wc, &mb, 1) < 0) {
1707c478bd9Sstevel@tonic-gate return (ERR);
1717c478bd9Sstevel@tonic-gate }
1727c478bd9Sstevel@tonic-gate return (OK);
1737c478bd9Sstevel@tonic-gate }
1747c478bd9Sstevel@tonic-gate
1757c478bd9Sstevel@tonic-gate /*
1767c478bd9Sstevel@tonic-gate * Return a complex character as a chtype.
1777c478bd9Sstevel@tonic-gate */
1787c478bd9Sstevel@tonic-gate chtype
__m_cc_chtype(const cchar_t * cc)1797c478bd9Sstevel@tonic-gate __m_cc_chtype(const cchar_t *cc)
1807c478bd9Sstevel@tonic-gate {
1817c478bd9Sstevel@tonic-gate chtype ch;
1827c478bd9Sstevel@tonic-gate unsigned char mb[MB_LEN_MAX];
1837c478bd9Sstevel@tonic-gate
1847c478bd9Sstevel@tonic-gate /* Is it a single-byte character? */
1857c478bd9Sstevel@tonic-gate if (cc->_n != 1 || wctomb((char *)mb, cc->_wc[0]) != 1)
1867c478bd9Sstevel@tonic-gate return ((chtype) ERR);
1877c478bd9Sstevel@tonic-gate
1887c478bd9Sstevel@tonic-gate ch = ((chtype) cc->_at << 16) & ~A_COLOR;
1897c478bd9Sstevel@tonic-gate ch |= COLOR_PAIR(cc->_co) | mb[0];
1907c478bd9Sstevel@tonic-gate
1917c478bd9Sstevel@tonic-gate return (ch);
1927c478bd9Sstevel@tonic-gate }
1937c478bd9Sstevel@tonic-gate
1947c478bd9Sstevel@tonic-gate /*
1957c478bd9Sstevel@tonic-gate * Convert a complex character's "character" into a multibyte string.
1967c478bd9Sstevel@tonic-gate * The attribute and colour are ignored.
1977c478bd9Sstevel@tonic-gate *
1987c478bd9Sstevel@tonic-gate * If 0 < n, set a new multibyte string and convert the first character,
1997c478bd9Sstevel@tonic-gate * returning either -1 on error or the number of bytes used to convert the
2007c478bd9Sstevel@tonic-gate * character.
2017c478bd9Sstevel@tonic-gate *
2027c478bd9Sstevel@tonic-gate * If n == 0, continue appending to the current multibyte string and return
2037c478bd9Sstevel@tonic-gate * a value as for 0 < n case.
2047c478bd9Sstevel@tonic-gate *
2057c478bd9Sstevel@tonic-gate * If n < 0, return the accumulated byte length of the current multibyte
2067c478bd9Sstevel@tonic-gate * string and do nothing else.
2077c478bd9Sstevel@tonic-gate *
2087c478bd9Sstevel@tonic-gate * When converting a character, a null cchar_t pointer will force the initial
2097c478bd9Sstevel@tonic-gate * shift state and append a '\0' to the multibyte string. The return value
2107c478bd9Sstevel@tonic-gate * will instead by the number of bytes used to shift to the initial state,
2117c478bd9Sstevel@tonic-gate * and exclude the '\0'.
2127c478bd9Sstevel@tonic-gate */
2137c478bd9Sstevel@tonic-gate int
__m_cc_mbs(const cchar_t * cc,char * mbs,int n)2147c478bd9Sstevel@tonic-gate __m_cc_mbs(const cchar_t *cc, char *mbs, int n)
2157c478bd9Sstevel@tonic-gate {
2167c478bd9Sstevel@tonic-gate int i, bytes, count, last;
2177c478bd9Sstevel@tonic-gate static t_string string = { 0 };
2187c478bd9Sstevel@tonic-gate static t_wide_io convert = { 0 };
2197c478bd9Sstevel@tonic-gate
2207c478bd9Sstevel@tonic-gate if (n < 0) {
2217c478bd9Sstevel@tonic-gate /* Return total number of bytes written to multibyte string. */
2227c478bd9Sstevel@tonic-gate return (string.used);
2237c478bd9Sstevel@tonic-gate } else if (0 < n) {
2247c478bd9Sstevel@tonic-gate /* Start a new conversion. */
2257c478bd9Sstevel@tonic-gate string.max = n;
2267c478bd9Sstevel@tonic-gate string.used = 0;
2277c478bd9Sstevel@tonic-gate string.mbs = mbs;
2287c478bd9Sstevel@tonic-gate
2297c478bd9Sstevel@tonic-gate convert._next = convert._size = 0;
2307c478bd9Sstevel@tonic-gate convert.object = (void *) &string;
2317c478bd9Sstevel@tonic-gate convert.put = (int (*)(int, void *)) write_string;
2327c478bd9Sstevel@tonic-gate } /* else n == 0, continue appending to previous mbs. */
2337c478bd9Sstevel@tonic-gate
2347c478bd9Sstevel@tonic-gate /* In case of error, rewind string to the last character. */
2357c478bd9Sstevel@tonic-gate last = string.used;
2367c478bd9Sstevel@tonic-gate
2377c478bd9Sstevel@tonic-gate if (cc == NULL) {
2387c478bd9Sstevel@tonic-gate /* Force initial shift state. */
2397c478bd9Sstevel@tonic-gate if ((count = m_wio_put('\0', &convert)) < 0) {
2407c478bd9Sstevel@tonic-gate string.used = last;
2417c478bd9Sstevel@tonic-gate return (-1);
2427c478bd9Sstevel@tonic-gate }
2437c478bd9Sstevel@tonic-gate
2447c478bd9Sstevel@tonic-gate if (string.used < string.max)
2457c478bd9Sstevel@tonic-gate string.mbs[string.used++] = '\0';
2467c478bd9Sstevel@tonic-gate } else {
2477c478bd9Sstevel@tonic-gate for (count = i = 0; i < cc->_n; ++i, count += bytes)
2487c478bd9Sstevel@tonic-gate if ((bytes = m_wio_put(cc->_wc[i], &convert)) < 0) {
2497c478bd9Sstevel@tonic-gate string.used = last;
2507c478bd9Sstevel@tonic-gate return (-1);
2517c478bd9Sstevel@tonic-gate }
2527c478bd9Sstevel@tonic-gate }
2537c478bd9Sstevel@tonic-gate
2547c478bd9Sstevel@tonic-gate return (count);
2557c478bd9Sstevel@tonic-gate }
2567c478bd9Sstevel@tonic-gate
2577c478bd9Sstevel@tonic-gate /*
2587c478bd9Sstevel@tonic-gate * Convert a stty character into a wchar_t.
2597c478bd9Sstevel@tonic-gate */
2607c478bd9Sstevel@tonic-gate int
__m_tty_wc(int index,wchar_t * wcp)2617c478bd9Sstevel@tonic-gate __m_tty_wc(int index, wchar_t *wcp)
2627c478bd9Sstevel@tonic-gate {
2637c478bd9Sstevel@tonic-gate char mb;
2647c478bd9Sstevel@tonic-gate int code;
2657c478bd9Sstevel@tonic-gate
2667c478bd9Sstevel@tonic-gate /*
2677c478bd9Sstevel@tonic-gate * Refer to _shell instead of _prog, since _shell will
2687c478bd9Sstevel@tonic-gate * correctly reflect the user's prefered settings, whereas
2697c478bd9Sstevel@tonic-gate * _prog may not have been initialised if both input and
2707c478bd9Sstevel@tonic-gate * output have been redirected.
2717c478bd9Sstevel@tonic-gate */
2727c478bd9Sstevel@tonic-gate mb = (char)PTERMIOS(_shell)->c_cc[index];
2737c478bd9Sstevel@tonic-gate if (mb)
2747c478bd9Sstevel@tonic-gate code = mbtowc(wcp, &mb, 1) < 0 ? ERR : OK;
2757c478bd9Sstevel@tonic-gate else
2767c478bd9Sstevel@tonic-gate code = ERR;
2777c478bd9Sstevel@tonic-gate
2787c478bd9Sstevel@tonic-gate return (code);
2797c478bd9Sstevel@tonic-gate }
2807c478bd9Sstevel@tonic-gate
2817c478bd9Sstevel@tonic-gate /*
2827c478bd9Sstevel@tonic-gate * Build a cchar_t from the leading spacing and non-spacing characters
2837c478bd9Sstevel@tonic-gate * in the multibyte character string. Only one spacing character is copied
2847c478bd9Sstevel@tonic-gate * from the multibyte character string.
2857c478bd9Sstevel@tonic-gate *
2867c478bd9Sstevel@tonic-gate * Return the number of characters copied from the string, or -1 on error.
2877c478bd9Sstevel@tonic-gate */
2887c478bd9Sstevel@tonic-gate int
__m_mbs_cc(const char * mbs,attr_t at,short co,cchar_t * cc)2897c478bd9Sstevel@tonic-gate __m_mbs_cc(const char *mbs, attr_t at, short co, cchar_t *cc)
2907c478bd9Sstevel@tonic-gate {
2917c478bd9Sstevel@tonic-gate wchar_t wc;
2927c478bd9Sstevel@tonic-gate const char *start;
2937c478bd9Sstevel@tonic-gate int i, nbytes, width, have_one;
2947c478bd9Sstevel@tonic-gate
2957c478bd9Sstevel@tonic-gate for (start = mbs, have_one = i = 0; *mbs != '\0'; mbs += nbytes, ++i) {
2967c478bd9Sstevel@tonic-gate if (sizeof (cc->_wc) <= i)
2977c478bd9Sstevel@tonic-gate /* Too many characters. */
2987c478bd9Sstevel@tonic-gate return (-1);
2997c478bd9Sstevel@tonic-gate
3007c478bd9Sstevel@tonic-gate if ((nbytes = mbtowc(&wc, mbs, UINT_MAX)) < 0)
3017c478bd9Sstevel@tonic-gate /* Invalid multibyte sequence. */
3027c478bd9Sstevel@tonic-gate return (-1);
3037c478bd9Sstevel@tonic-gate
3047c478bd9Sstevel@tonic-gate if (nbytes == 0)
3057c478bd9Sstevel@tonic-gate /* Remainder of string evaluates to the null byte. */
3067c478bd9Sstevel@tonic-gate break;
3077c478bd9Sstevel@tonic-gate
3087c478bd9Sstevel@tonic-gate if (iscntrl(*mbs))
3097c478bd9Sstevel@tonic-gate /* Treat control codes like a spacing character. */
3107c478bd9Sstevel@tonic-gate width = 1;
3117c478bd9Sstevel@tonic-gate else
3127c478bd9Sstevel@tonic-gate width = wcwidth(wc);
3137c478bd9Sstevel@tonic-gate
3147c478bd9Sstevel@tonic-gate /* Do we have a spacing character? */
3157c478bd9Sstevel@tonic-gate if (0 < width) {
3167c478bd9Sstevel@tonic-gate if (have_one)
3177c478bd9Sstevel@tonic-gate break;
3187c478bd9Sstevel@tonic-gate have_one = 1;
3197c478bd9Sstevel@tonic-gate }
3207c478bd9Sstevel@tonic-gate
3217c478bd9Sstevel@tonic-gate cc->_wc[i] = wc;
3227c478bd9Sstevel@tonic-gate }
3237c478bd9Sstevel@tonic-gate
3247c478bd9Sstevel@tonic-gate cc->_f = 1;
3257c478bd9Sstevel@tonic-gate cc->_n = (short)i;
3267c478bd9Sstevel@tonic-gate cc->_co = co;
3277c478bd9Sstevel@tonic-gate cc->_at = at;
3287c478bd9Sstevel@tonic-gate
3297c478bd9Sstevel@tonic-gate (void) __m_cc_sort(cc);
3307c478bd9Sstevel@tonic-gate
3317c478bd9Sstevel@tonic-gate /* (mbs - start) should be enough small to fit in "int" */
3327c478bd9Sstevel@tonic-gate return ((int)(mbs - start));
3337c478bd9Sstevel@tonic-gate }
3347c478bd9Sstevel@tonic-gate
3357c478bd9Sstevel@tonic-gate /*
3367c478bd9Sstevel@tonic-gate * Build a cchar_t from the leading spacing and non-spacing characters
3377c478bd9Sstevel@tonic-gate * in the wide character string. Only one spacinig character is copied
3387c478bd9Sstevel@tonic-gate * from the wide character string.
3397c478bd9Sstevel@tonic-gate *
3407c478bd9Sstevel@tonic-gate * Return the number of characters copied from the string, or -1 on error.
3417c478bd9Sstevel@tonic-gate */
3427c478bd9Sstevel@tonic-gate int
__m_wcs_cc(const wchar_t * wcs,attr_t at,short co,cchar_t * cc)3437c478bd9Sstevel@tonic-gate __m_wcs_cc(const wchar_t *wcs, attr_t at, short co, cchar_t *cc)
3447c478bd9Sstevel@tonic-gate {
3457c478bd9Sstevel@tonic-gate short i;
3467c478bd9Sstevel@tonic-gate const wchar_t *start;
3477c478bd9Sstevel@tonic-gate
3487c478bd9Sstevel@tonic-gate for (start = wcs, i = 0; *wcs != '\0'; ++wcs, ++i) {
3497c478bd9Sstevel@tonic-gate if (sizeof (cc->_wc) <= i) {
3507c478bd9Sstevel@tonic-gate /* Too many characters. */
3517c478bd9Sstevel@tonic-gate return (-1);
3527c478bd9Sstevel@tonic-gate }
3537c478bd9Sstevel@tonic-gate
3547c478bd9Sstevel@tonic-gate if (wcwidth(*wcs) > 0) {
3557c478bd9Sstevel@tonic-gate if (i != 0)
3567c478bd9Sstevel@tonic-gate break;
3577c478bd9Sstevel@tonic-gate } else if ((*wcs == L'\n') || (*wcs == L'\t') ||
3587c478bd9Sstevel@tonic-gate (*wcs == L'\b') || (*wcs == L'\r')) {
3597c478bd9Sstevel@tonic-gate if (i != 0)
3607c478bd9Sstevel@tonic-gate break;
3617c478bd9Sstevel@tonic-gate cc->_wc[i++] = *wcs++;
3627c478bd9Sstevel@tonic-gate break;
3637c478bd9Sstevel@tonic-gate }
3647c478bd9Sstevel@tonic-gate
3657c478bd9Sstevel@tonic-gate cc->_wc[i] = *wcs;
3667c478bd9Sstevel@tonic-gate }
3677c478bd9Sstevel@tonic-gate
3687c478bd9Sstevel@tonic-gate cc->_f = 1;
3697c478bd9Sstevel@tonic-gate cc->_n = i;
3707c478bd9Sstevel@tonic-gate cc->_co = co;
3717c478bd9Sstevel@tonic-gate cc->_at = at;
3727c478bd9Sstevel@tonic-gate
3737c478bd9Sstevel@tonic-gate /* (wcs - start) should be enough small to fit in "int" */
3747c478bd9Sstevel@tonic-gate return ((int)(wcs - start));
3757c478bd9Sstevel@tonic-gate }
3767c478bd9Sstevel@tonic-gate
3777c478bd9Sstevel@tonic-gate /*
3787c478bd9Sstevel@tonic-gate * Convert a single wide character into a complex character.
3797c478bd9Sstevel@tonic-gate */
3807c478bd9Sstevel@tonic-gate int
__m_wc_cc(wint_t wc,cchar_t * cc)3817c478bd9Sstevel@tonic-gate __m_wc_cc(wint_t wc, cchar_t *cc)
3827c478bd9Sstevel@tonic-gate {
3837c478bd9Sstevel@tonic-gate wchar_t wcs[2];
3847c478bd9Sstevel@tonic-gate
3857c478bd9Sstevel@tonic-gate if (wc == WEOF)
3867c478bd9Sstevel@tonic-gate return (-1);
3877c478bd9Sstevel@tonic-gate
3887c478bd9Sstevel@tonic-gate if (wc == 0) {
3897c478bd9Sstevel@tonic-gate /*
3907c478bd9Sstevel@tonic-gate * converting a null character to a complex character.
3917c478bd9Sstevel@tonic-gate * __m_wcs_cc assumes that the string is empty, so
3927c478bd9Sstevel@tonic-gate * just do it here.
3937c478bd9Sstevel@tonic-gate */
3947c478bd9Sstevel@tonic-gate cc->_f = 1;
3957c478bd9Sstevel@tonic-gate cc->_n = 1;
3967c478bd9Sstevel@tonic-gate cc->_co = 0;
3977c478bd9Sstevel@tonic-gate cc->_at = WA_NORMAL;
3987c478bd9Sstevel@tonic-gate cc->_wc[0] = 0;
3997c478bd9Sstevel@tonic-gate cc->_wc[1] = 0;
4007c478bd9Sstevel@tonic-gate } else {
4017c478bd9Sstevel@tonic-gate /* A real character */
4027c478bd9Sstevel@tonic-gate wcs[0] = (wchar_t)wc;
4037c478bd9Sstevel@tonic-gate wcs[1] = '\0';
4047c478bd9Sstevel@tonic-gate (void) __m_wcs_cc(wcs, WA_NORMAL, 0, cc);
4057c478bd9Sstevel@tonic-gate }
4067c478bd9Sstevel@tonic-gate
4077c478bd9Sstevel@tonic-gate return (0);
4087c478bd9Sstevel@tonic-gate }
4097c478bd9Sstevel@tonic-gate
4107c478bd9Sstevel@tonic-gate /*
4117c478bd9Sstevel@tonic-gate * Sort a complex character into a spacing character followed
4127c478bd9Sstevel@tonic-gate * by any non-spacing characters in increasing order of oridinal
4137c478bd9Sstevel@tonic-gate * values. This facilitates both comparision and writting of
4147c478bd9Sstevel@tonic-gate * complex characters. More than one spacing character is
4157c478bd9Sstevel@tonic-gate * considered an error.
4167c478bd9Sstevel@tonic-gate *
4177c478bd9Sstevel@tonic-gate * Return the spacing character's column width or -1 if more
4187c478bd9Sstevel@tonic-gate * than one spacing character appears in cc.
4197c478bd9Sstevel@tonic-gate */
4207c478bd9Sstevel@tonic-gate int
__m_cc_sort(cchar_t * cc)4217c478bd9Sstevel@tonic-gate __m_cc_sort(cchar_t *cc)
4227c478bd9Sstevel@tonic-gate {
4237c478bd9Sstevel@tonic-gate wchar_t wc;
4247c478bd9Sstevel@tonic-gate int width, i, j, spacing;
4257c478bd9Sstevel@tonic-gate
4267c478bd9Sstevel@tonic-gate /* Find spacing character and place in as first element. */
4277c478bd9Sstevel@tonic-gate for (width = spacing = i = 0; i < cc->_n; ++i) {
4287c478bd9Sstevel@tonic-gate j = wcwidth(cc->_wc[i]);
4297c478bd9Sstevel@tonic-gate if (0 < j) {
4307c478bd9Sstevel@tonic-gate /* More than one spacing character is an error. */
4317c478bd9Sstevel@tonic-gate if (0 < width)
4327c478bd9Sstevel@tonic-gate return (-1);
4337c478bd9Sstevel@tonic-gate
4347c478bd9Sstevel@tonic-gate wc = cc->_wc[0];
4357c478bd9Sstevel@tonic-gate cc->_wc[0] = cc->_wc[i];
4367c478bd9Sstevel@tonic-gate cc->_wc[i] = wc;
4377c478bd9Sstevel@tonic-gate
4387c478bd9Sstevel@tonic-gate spacing = 1;
4397c478bd9Sstevel@tonic-gate width = j;
4407c478bd9Sstevel@tonic-gate break;
4417c478bd9Sstevel@tonic-gate }
4427c478bd9Sstevel@tonic-gate }
4437c478bd9Sstevel@tonic-gate
4447c478bd9Sstevel@tonic-gate /* Bubble sort small array. */
4457c478bd9Sstevel@tonic-gate for (i = spacing; i < cc->_n; ++i) {
4467c478bd9Sstevel@tonic-gate for (j = cc->_n - 1; i < j; --j) {
4477c478bd9Sstevel@tonic-gate if (cc->_wc[j-1] > cc->_wc[j]) {
4487c478bd9Sstevel@tonic-gate wc = cc->_wc[j];
4497c478bd9Sstevel@tonic-gate cc->_wc[j] = cc->_wc[j-1];
4507c478bd9Sstevel@tonic-gate cc->_wc[j-1] = wc;
4517c478bd9Sstevel@tonic-gate }
4527c478bd9Sstevel@tonic-gate }
4537c478bd9Sstevel@tonic-gate }
4547c478bd9Sstevel@tonic-gate
4557c478bd9Sstevel@tonic-gate return (width);
4567c478bd9Sstevel@tonic-gate }
4577c478bd9Sstevel@tonic-gate
4587c478bd9Sstevel@tonic-gate /*
4597c478bd9Sstevel@tonic-gate * Return the first column of a multi-column character, in window.
4607c478bd9Sstevel@tonic-gate */
4617c478bd9Sstevel@tonic-gate int
__m_cc_first(WINDOW * w,int y,int x)4627c478bd9Sstevel@tonic-gate __m_cc_first(WINDOW *w, int y, int x)
4637c478bd9Sstevel@tonic-gate {
4647c478bd9Sstevel@tonic-gate cchar_t *lp;
4657c478bd9Sstevel@tonic-gate
4667c478bd9Sstevel@tonic-gate for (lp = w->_line[y]; 0 < x; --x) {
4677c478bd9Sstevel@tonic-gate if (lp[x]._f)
4687c478bd9Sstevel@tonic-gate break;
4697c478bd9Sstevel@tonic-gate }
4707c478bd9Sstevel@tonic-gate
4717c478bd9Sstevel@tonic-gate return (x);
4727c478bd9Sstevel@tonic-gate }
4737c478bd9Sstevel@tonic-gate
4747c478bd9Sstevel@tonic-gate /*
4757c478bd9Sstevel@tonic-gate * Return the start of the next multi-column character, in window.
4767c478bd9Sstevel@tonic-gate */
4777c478bd9Sstevel@tonic-gate int
__m_cc_next(WINDOW * w,int y,int x)4787c478bd9Sstevel@tonic-gate __m_cc_next(WINDOW *w, int y, int x)
4797c478bd9Sstevel@tonic-gate {
4807c478bd9Sstevel@tonic-gate cchar_t *lp;
4817c478bd9Sstevel@tonic-gate
4827c478bd9Sstevel@tonic-gate for (lp = w->_line[y]; ++x < w->_maxx; ) {
4837c478bd9Sstevel@tonic-gate if (lp[x]._f)
4847c478bd9Sstevel@tonic-gate break;
4857c478bd9Sstevel@tonic-gate }
4867c478bd9Sstevel@tonic-gate
4877c478bd9Sstevel@tonic-gate return (x);
4887c478bd9Sstevel@tonic-gate }
4897c478bd9Sstevel@tonic-gate
4907c478bd9Sstevel@tonic-gate /*
4917c478bd9Sstevel@tonic-gate * Return true if valid last column of a multi-column character.
4927c478bd9Sstevel@tonic-gate */
4937c478bd9Sstevel@tonic-gate int
__m_cc_islast(WINDOW * w,int y,int x)4947c478bd9Sstevel@tonic-gate __m_cc_islast(WINDOW *w, int y, int x)
4957c478bd9Sstevel@tonic-gate {
4967c478bd9Sstevel@tonic-gate int first, width;
4977c478bd9Sstevel@tonic-gate
4987c478bd9Sstevel@tonic-gate first = __m_cc_first(w, y, x);
4997c478bd9Sstevel@tonic-gate width = __m_cc_width(&w->_line[y][x]);
5007c478bd9Sstevel@tonic-gate
5017c478bd9Sstevel@tonic-gate return ((first + width) == (x + 1));
5027c478bd9Sstevel@tonic-gate }
5037c478bd9Sstevel@tonic-gate
5047c478bd9Sstevel@tonic-gate /*
5057c478bd9Sstevel@tonic-gate * Replace the character at the current cursor location
5067c478bd9Sstevel@tonic-gate * according to the column width of the character. The
5077c478bd9Sstevel@tonic-gate * cursor does not advance.
5087c478bd9Sstevel@tonic-gate *
5097c478bd9Sstevel@tonic-gate * Return -1 if the character won't fit on the line and the background
5107c478bd9Sstevel@tonic-gate * was written in its place; else return the width of the character in
5117c478bd9Sstevel@tonic-gate * screen columns.
5127c478bd9Sstevel@tonic-gate */
5137c478bd9Sstevel@tonic-gate /* ARGSUSED */
5147c478bd9Sstevel@tonic-gate int
__m_cc_replace(WINDOW * w,int y,int x,const cchar_t * cc,int as_is)5157c478bd9Sstevel@tonic-gate __m_cc_replace(WINDOW *w, int y, int x,
5167c478bd9Sstevel@tonic-gate const cchar_t *cc, int as_is)
5177c478bd9Sstevel@tonic-gate {
5187c478bd9Sstevel@tonic-gate int i, width;
5197c478bd9Sstevel@tonic-gate cchar_t *cp, *np;
5207c478bd9Sstevel@tonic-gate
5217c478bd9Sstevel@tonic-gate width = __m_cc_width(cc);
5227c478bd9Sstevel@tonic-gate
5237c478bd9Sstevel@tonic-gate if (width <= 0)
5247c478bd9Sstevel@tonic-gate return (__m_cc_modify(w, y, x, cc));
5257c478bd9Sstevel@tonic-gate
5267c478bd9Sstevel@tonic-gate /*
5277c478bd9Sstevel@tonic-gate * If we try to write a broad character that would exceed the
5287c478bd9Sstevel@tonic-gate * right margin, then write the background character instead.
5297c478bd9Sstevel@tonic-gate */
5307c478bd9Sstevel@tonic-gate if (0 < width && w->_maxx < x + width) {
5317c478bd9Sstevel@tonic-gate (void) __m_cc_erase(w, y, x, y, w->_maxx-1);
5327c478bd9Sstevel@tonic-gate return (-1);
5337c478bd9Sstevel@tonic-gate }
5347c478bd9Sstevel@tonic-gate
5357c478bd9Sstevel@tonic-gate /*
5367c478bd9Sstevel@tonic-gate * Erase the region to be occupied by the new character.
5377c478bd9Sstevel@tonic-gate * __m_cc_erase() will erase whole characters so that
5387c478bd9Sstevel@tonic-gate * writing a multicolumn character that overwrites the
5397c478bd9Sstevel@tonic-gate * trailing and leading portions of two already existing
5407c478bd9Sstevel@tonic-gate * multicolumn characters, erases the remaining portions.
5417c478bd9Sstevel@tonic-gate */
5427c478bd9Sstevel@tonic-gate (void) __m_cc_erase(w, y, x, y, x + width - 1);
5437c478bd9Sstevel@tonic-gate
5447c478bd9Sstevel@tonic-gate /* Write the first column of the character. */
5457c478bd9Sstevel@tonic-gate cp = &w->_line[y][x++];
5467c478bd9Sstevel@tonic-gate if (cc->_wc[0] == L' ') {
5477c478bd9Sstevel@tonic-gate *cp = w->_bg;
5487c478bd9Sstevel@tonic-gate cp->_at = cc->_at | w->_fg._at;
5497c478bd9Sstevel@tonic-gate /*
5507c478bd9Sstevel@tonic-gate * This method fixes:
5517c478bd9Sstevel@tonic-gate * /tset/CAPIxcurses/fmvwaddchs/fmvwaddchs1{3}
5527c478bd9Sstevel@tonic-gate * /tset/CAPIxcurses/fwins_wch/fwins_wch1{5}
5537c478bd9Sstevel@tonic-gate */
5547c478bd9Sstevel@tonic-gate cp->_co = (cc->_co) ? cc->_co : w->_fg._co;
5557c478bd9Sstevel@tonic-gate } else {
5567c478bd9Sstevel@tonic-gate if (__m_wacs_cc(cc, cp)) {
5577c478bd9Sstevel@tonic-gate /*
5587c478bd9Sstevel@tonic-gate * __m_wacs_cc says ALTCHARSET should be cleared
5597c478bd9Sstevel@tonic-gate * ... Takes priority
5607c478bd9Sstevel@tonic-gate */
5617c478bd9Sstevel@tonic-gate cp->_at = (cc->_at | w->_fg._at) & ~WA_ALTCHARSET;
5627c478bd9Sstevel@tonic-gate } else {
5637c478bd9Sstevel@tonic-gate cp->_at = cc->_at | w->_fg._at;
5647c478bd9Sstevel@tonic-gate }
5657c478bd9Sstevel@tonic-gate cp->_co = (cc->_co) ? cc->_co : w->_fg._co;
5667c478bd9Sstevel@tonic-gate }
5677c478bd9Sstevel@tonic-gate
5687c478bd9Sstevel@tonic-gate /* Mark this as the first column of the character. */
5697c478bd9Sstevel@tonic-gate cp->_f = 1;
5707c478bd9Sstevel@tonic-gate
5717c478bd9Sstevel@tonic-gate /* Duplicate the character in every column the character occupies. */
5727c478bd9Sstevel@tonic-gate for (np = cp + 1, i = 1; i < width; ++i, ++x, ++np) {
5737c478bd9Sstevel@tonic-gate *np = *cp;
5747c478bd9Sstevel@tonic-gate np->_f = 0;
5757c478bd9Sstevel@tonic-gate }
5767c478bd9Sstevel@tonic-gate
5777c478bd9Sstevel@tonic-gate return (width);
5787c478bd9Sstevel@tonic-gate }
5797c478bd9Sstevel@tonic-gate
5807c478bd9Sstevel@tonic-gate int
__m_do_scroll(WINDOW * w,int y,int x,int * yp,int * xp)5817c478bd9Sstevel@tonic-gate __m_do_scroll(WINDOW *w, int y, int x, int *yp, int *xp)
5827c478bd9Sstevel@tonic-gate {
5837c478bd9Sstevel@tonic-gate int code = OK;
5847c478bd9Sstevel@tonic-gate if (w->_maxx <= x)
5857c478bd9Sstevel@tonic-gate x = w->_maxx - 1;
5867c478bd9Sstevel@tonic-gate
5877c478bd9Sstevel@tonic-gate ++y;
5887c478bd9Sstevel@tonic-gate
5897c478bd9Sstevel@tonic-gate if (y == w->_bottom) {
5907c478bd9Sstevel@tonic-gate --y;
5917c478bd9Sstevel@tonic-gate if (w->_flags & W_CAN_SCROLL) {
5927c478bd9Sstevel@tonic-gate if (wscrl(w, 1) == ERR)
5937c478bd9Sstevel@tonic-gate return (ERR);
5947c478bd9Sstevel@tonic-gate x = 0;
5957c478bd9Sstevel@tonic-gate /* Test suite seems to want this */
5967c478bd9Sstevel@tonic-gate w->_flags |= W_FLUSH;
5977c478bd9Sstevel@tonic-gate } else {
5987c478bd9Sstevel@tonic-gate #ifdef BREAKS
5997c478bd9Sstevel@tonic-gate w->_curx = x; /* Cheezy doing it here */
6007c478bd9Sstevel@tonic-gate w->_cury = y;
6017c478bd9Sstevel@tonic-gate #endif /* BREAKS */
6027c478bd9Sstevel@tonic-gate code = ERR; /* No scrolling allowed */
6037c478bd9Sstevel@tonic-gate }
6047c478bd9Sstevel@tonic-gate } else if (w->_maxy <= y) {
6057c478bd9Sstevel@tonic-gate y = w->_maxy - 1;
6067c478bd9Sstevel@tonic-gate } else {
6077c478bd9Sstevel@tonic-gate /*
6087c478bd9Sstevel@tonic-gate * The cursor wraps for any line (in and out of the scroll
6097c478bd9Sstevel@tonic-gate * region) except for the last line of the scroll region.
6107c478bd9Sstevel@tonic-gate */
6117c478bd9Sstevel@tonic-gate x = 0;
6127c478bd9Sstevel@tonic-gate }
6137c478bd9Sstevel@tonic-gate
6147c478bd9Sstevel@tonic-gate *yp = y;
6157c478bd9Sstevel@tonic-gate *xp = x;
6167c478bd9Sstevel@tonic-gate
6177c478bd9Sstevel@tonic-gate return (code);
6187c478bd9Sstevel@tonic-gate }
6197c478bd9Sstevel@tonic-gate
6207c478bd9Sstevel@tonic-gate /*
6217c478bd9Sstevel@tonic-gate * Add the character at the current cursor location
6227c478bd9Sstevel@tonic-gate * according to the column width of the character.
6237c478bd9Sstevel@tonic-gate * The cursor will be advanced.
6247c478bd9Sstevel@tonic-gate * Wrapping is done.
6257c478bd9Sstevel@tonic-gate *
6267c478bd9Sstevel@tonic-gate * Return ERR if adding the character causes the
6277c478bd9Sstevel@tonic-gate * screen to scroll, when it is disallowed.
6287c478bd9Sstevel@tonic-gate */
6297c478bd9Sstevel@tonic-gate int
__m_cc_add(WINDOW * w,int y,int x,const cchar_t * cc,int as_is,int * yp,int * xp)6307c478bd9Sstevel@tonic-gate __m_cc_add(WINDOW *w, int y, int x,
6317c478bd9Sstevel@tonic-gate const cchar_t *cc, int as_is, int *yp, int *xp)
6327c478bd9Sstevel@tonic-gate {
6337c478bd9Sstevel@tonic-gate int nx, width, code = ERR;
6347c478bd9Sstevel@tonic-gate
6357c478bd9Sstevel@tonic-gate switch (cc->_wc[0]) {
6367c478bd9Sstevel@tonic-gate case L'\t':
6377c478bd9Sstevel@tonic-gate nx = x + (8 - (x & 07));
6387c478bd9Sstevel@tonic-gate if (nx >= w->_maxx) {
6397c478bd9Sstevel@tonic-gate /* This fixes (scroll-disabled) */
6407c478bd9Sstevel@tonic-gate /* /tset/CAPIxcurses/fwaddch/fwaddch1{4} but */
6417c478bd9Sstevel@tonic-gate /* what does it break? */
6427c478bd9Sstevel@tonic-gate nx = w->_maxx;
6437c478bd9Sstevel@tonic-gate }
6447c478bd9Sstevel@tonic-gate if (__m_cc_erase(w, y, x, y, nx-1) == -1)
6457c478bd9Sstevel@tonic-gate goto error;
6467c478bd9Sstevel@tonic-gate x = nx;
6477c478bd9Sstevel@tonic-gate
6487c478bd9Sstevel@tonic-gate if (w->_maxx <= x) {
6497c478bd9Sstevel@tonic-gate if (__m_do_scroll(w, y, x, &y, &x) == ERR)
6507c478bd9Sstevel@tonic-gate goto error;
6517c478bd9Sstevel@tonic-gate }
6527c478bd9Sstevel@tonic-gate break;
6537c478bd9Sstevel@tonic-gate case L'\n':
6547c478bd9Sstevel@tonic-gate if (__m_cc_erase(w, y, x, y, w->_maxx-1) == -1)
6557c478bd9Sstevel@tonic-gate goto error;
6567c478bd9Sstevel@tonic-gate
6577c478bd9Sstevel@tonic-gate if (__m_do_scroll(w, y, x, &y, &x) == ERR)
6587c478bd9Sstevel@tonic-gate goto error;
6597c478bd9Sstevel@tonic-gate break;
6607c478bd9Sstevel@tonic-gate case L'\r':
6617c478bd9Sstevel@tonic-gate x = 0;
6627c478bd9Sstevel@tonic-gate break;
6637c478bd9Sstevel@tonic-gate case L'\b':
6647c478bd9Sstevel@tonic-gate if (0 < x)
6657c478bd9Sstevel@tonic-gate --x;
6667c478bd9Sstevel@tonic-gate else
6677c478bd9Sstevel@tonic-gate (void) beep();
6687c478bd9Sstevel@tonic-gate break;
6697c478bd9Sstevel@tonic-gate default:
6707c478bd9Sstevel@tonic-gate width = __m_cc_replace(w, y, x, cc, as_is);
6717c478bd9Sstevel@tonic-gate
6727c478bd9Sstevel@tonic-gate x += width;
6737c478bd9Sstevel@tonic-gate
6747c478bd9Sstevel@tonic-gate if (width < 0 || w->_maxx <= x) {
6757c478bd9Sstevel@tonic-gate if (__m_do_scroll(w, y, x, &y, &x) == ERR) {
6767c478bd9Sstevel@tonic-gate goto error;
6777c478bd9Sstevel@tonic-gate }
6787c478bd9Sstevel@tonic-gate
6797c478bd9Sstevel@tonic-gate if (width < 0)
6807c478bd9Sstevel@tonic-gate x += __m_cc_replace(w, y, x, cc, as_is);
6817c478bd9Sstevel@tonic-gate }
6827c478bd9Sstevel@tonic-gate }
6837c478bd9Sstevel@tonic-gate
6847c478bd9Sstevel@tonic-gate code = OK;
6857c478bd9Sstevel@tonic-gate error:
6867c478bd9Sstevel@tonic-gate *yp = y;
6877c478bd9Sstevel@tonic-gate *xp = x;
6887c478bd9Sstevel@tonic-gate
6897c478bd9Sstevel@tonic-gate return (code);
6907c478bd9Sstevel@tonic-gate }
6917c478bd9Sstevel@tonic-gate
6927c478bd9Sstevel@tonic-gate /*
6937c478bd9Sstevel@tonic-gate * Stripped version of __m_cc_add which does much less special character
6947c478bd9Sstevel@tonic-gate * processing. Functions such as waddchnstr() are not supposed to do
6957c478bd9Sstevel@tonic-gate * any special character processing but what does one do when a '\n'
6967c478bd9Sstevel@tonic-gate * is sent? The test suite expects a new line to start...
6977c478bd9Sstevel@tonic-gate *
6987c478bd9Sstevel@tonic-gate * Return ERR if adding the character causes the
6997c478bd9Sstevel@tonic-gate * screen to scroll, when it is disallowed.
7007c478bd9Sstevel@tonic-gate */
7017c478bd9Sstevel@tonic-gate int
__m_cc_add_k(WINDOW * w,int y,int x,const cchar_t * cc,int as_is,int * yp,int * xp)7027c478bd9Sstevel@tonic-gate __m_cc_add_k(WINDOW *w, int y, int x,
7037c478bd9Sstevel@tonic-gate const cchar_t *cc, int as_is, int *yp, int *xp)
7047c478bd9Sstevel@tonic-gate {
7057c478bd9Sstevel@tonic-gate int width, code = ERR;
7067c478bd9Sstevel@tonic-gate
7077c478bd9Sstevel@tonic-gate switch (cc->_wc[0]) {
7087c478bd9Sstevel@tonic-gate case L'\n':
7097c478bd9Sstevel@tonic-gate if (__m_cc_erase(w, y, x, y, w->_maxx-1) == -1)
7107c478bd9Sstevel@tonic-gate goto error;
7117c478bd9Sstevel@tonic-gate
7127c478bd9Sstevel@tonic-gate if (__m_do_scroll(w, y, x, &y, &x) == ERR)
7137c478bd9Sstevel@tonic-gate goto error;
7147c478bd9Sstevel@tonic-gate break;
7157c478bd9Sstevel@tonic-gate default:
7167c478bd9Sstevel@tonic-gate width = __m_cc_replace(w, y, x, cc, as_is);
7177c478bd9Sstevel@tonic-gate x += width;
7187c478bd9Sstevel@tonic-gate }
7197c478bd9Sstevel@tonic-gate
7207c478bd9Sstevel@tonic-gate code = OK;
7217c478bd9Sstevel@tonic-gate error:
7227c478bd9Sstevel@tonic-gate *yp = y;
7237c478bd9Sstevel@tonic-gate *xp = x;
7247c478bd9Sstevel@tonic-gate
7257c478bd9Sstevel@tonic-gate return (code);
7267c478bd9Sstevel@tonic-gate }
7277c478bd9Sstevel@tonic-gate
7287c478bd9Sstevel@tonic-gate /*
7297c478bd9Sstevel@tonic-gate * Append non-spacing characters to the a spacing character at (y, x).
7307c478bd9Sstevel@tonic-gate * Return -1 on error, else 0.
7317c478bd9Sstevel@tonic-gate */
7327c478bd9Sstevel@tonic-gate int
__m_cc_modify(WINDOW * w,int y,int x,const cchar_t * cc)7337c478bd9Sstevel@tonic-gate __m_cc_modify(WINDOW *w, int y, int x, const cchar_t *cc)
7347c478bd9Sstevel@tonic-gate {
7357c478bd9Sstevel@tonic-gate cchar_t *cp, tch;
7367c478bd9Sstevel@tonic-gate int i, j, width;
7377c478bd9Sstevel@tonic-gate
7387c478bd9Sstevel@tonic-gate x = __m_cc_first(w, y, x);
7397c478bd9Sstevel@tonic-gate cp = &w->_line[y][x];
7407c478bd9Sstevel@tonic-gate
7417c478bd9Sstevel@tonic-gate /* Is there enough room for the non-spacing characters. */
7427c478bd9Sstevel@tonic-gate if (_M_CCHAR_MAX < cp->_n + cc->_n)
7437c478bd9Sstevel@tonic-gate return (-1);
7447c478bd9Sstevel@tonic-gate
7457c478bd9Sstevel@tonic-gate for (i = cp->_n, j = 0; j < cc->_n; ++i, ++j)
7467c478bd9Sstevel@tonic-gate cp->_wc[i] = cc->_wc[j];
7477c478bd9Sstevel@tonic-gate cp->_n = (short)i;
7487c478bd9Sstevel@tonic-gate
7497c478bd9Sstevel@tonic-gate width = __m_cc_width(cp);
7507c478bd9Sstevel@tonic-gate
7517c478bd9Sstevel@tonic-gate __m_touch_locs(w, y, x, x + width);
7527c478bd9Sstevel@tonic-gate
7537c478bd9Sstevel@tonic-gate /* Assert that the modified spacing character is sorted. */
7547c478bd9Sstevel@tonic-gate (void) __m_cc_sort(cp);
7557c478bd9Sstevel@tonic-gate
7567c478bd9Sstevel@tonic-gate /* Dulicate in every column occupied by the spacing character. */
7577c478bd9Sstevel@tonic-gate while (0 < --width) {
7587c478bd9Sstevel@tonic-gate tch = *cp;
7597c478bd9Sstevel@tonic-gate cp[1] = tch;
7607c478bd9Sstevel@tonic-gate cp++;
7617c478bd9Sstevel@tonic-gate }
7627c478bd9Sstevel@tonic-gate
7637c478bd9Sstevel@tonic-gate return (0);
7647c478bd9Sstevel@tonic-gate }
7657c478bd9Sstevel@tonic-gate
7667c478bd9Sstevel@tonic-gate static void
__m_cc_erase_in_line(WINDOW * w,int y,int x,int lx,int bgWidth)7677c478bd9Sstevel@tonic-gate __m_cc_erase_in_line(WINDOW *w, int y, int x, int lx, int bgWidth)
7687c478bd9Sstevel@tonic-gate {
7697c478bd9Sstevel@tonic-gate cchar_t *cp;
7707c478bd9Sstevel@tonic-gate int i;
7717c478bd9Sstevel@tonic-gate
7727c478bd9Sstevel@tonic-gate if (x < w->_first[y])
7737c478bd9Sstevel@tonic-gate w->_first[y] = (short)x;
7747c478bd9Sstevel@tonic-gate
7757c478bd9Sstevel@tonic-gate for (cp = w->_line[y], i = 0; x <= lx; ++x, ++i) {
7767c478bd9Sstevel@tonic-gate cp[x] = w->_bg;
7777c478bd9Sstevel@tonic-gate /*
7787c478bd9Sstevel@tonic-gate * The start of each new character will be set true
7797c478bd9Sstevel@tonic-gate * while internal columns of the character will be
7807c478bd9Sstevel@tonic-gate * reset to false.
7817c478bd9Sstevel@tonic-gate */
7827c478bd9Sstevel@tonic-gate cp[x]._f = (short)(i % bgWidth == 0);
7837c478bd9Sstevel@tonic-gate }
7847c478bd9Sstevel@tonic-gate if (w->_last[y] < x)
7857c478bd9Sstevel@tonic-gate w->_last[y] = (short)x;
7867c478bd9Sstevel@tonic-gate }
7877c478bd9Sstevel@tonic-gate
7887c478bd9Sstevel@tonic-gate /* Window has a parent. Handle width chars overlapping with parent */
7897c478bd9Sstevel@tonic-gate static void
__m_cc_erase_in_line_sub(WINDOW * w,int y,int x,int lx,int bgWidth,int parentBGWidth)7907c478bd9Sstevel@tonic-gate __m_cc_erase_in_line_sub(WINDOW *w, int y, int x,
7917c478bd9Sstevel@tonic-gate int lx, int bgWidth, int parentBGWidth)
7927c478bd9Sstevel@tonic-gate {
7937c478bd9Sstevel@tonic-gate cchar_t *cp;
7947c478bd9Sstevel@tonic-gate int i;
7957c478bd9Sstevel@tonic-gate int xi;
7967c478bd9Sstevel@tonic-gate int wmin, wmax;
7977c478bd9Sstevel@tonic-gate int wlx;
7987c478bd9Sstevel@tonic-gate WINDOW *parent = w->_parent;
799*759f6fc9Srm int parentY = w->_begy + y - parent->_begy;
800*759f6fc9Srm int dx = w->_begx - parent->_begx;
8017c478bd9Sstevel@tonic-gate
8027c478bd9Sstevel@tonic-gate /* Switch to parent context and calculate limits */
803*759f6fc9Srm xi = x = __m_cc_first(parent, parentY, dx + x);
804*759f6fc9Srm wlx = lx = __m_cc_next(parent, parentY, dx + lx) - 1;
805*759f6fc9Srm if (wlx >= dx + w->_maxx) wlx = dx + w->_maxx - 1;
8067c478bd9Sstevel@tonic-gate
8077c478bd9Sstevel@tonic-gate for (cp = parent->_line[parentY]; x <= lx; ) {
808*759f6fc9Srm if ((x < dx) || (x >= (dx + w->_maxx))) {
8097c478bd9Sstevel@tonic-gate /* Outside target window */
8107c478bd9Sstevel@tonic-gate for (i = 0; x <= lx && i <= parentBGWidth; x++, i++) {
8117c478bd9Sstevel@tonic-gate cp[x] = parent->_bg;
8127c478bd9Sstevel@tonic-gate cp[x]._f = (i == 0);
8137c478bd9Sstevel@tonic-gate }
8147c478bd9Sstevel@tonic-gate } else {
8157c478bd9Sstevel@tonic-gate /* Inside target window */
8167c478bd9Sstevel@tonic-gate for (i = 0; x <= wlx; x++, i++) {
8177c478bd9Sstevel@tonic-gate cp[x] = w->_bg;
8187c478bd9Sstevel@tonic-gate cp[x]._f = (short)(i % bgWidth == 0);
8197c478bd9Sstevel@tonic-gate }
8207c478bd9Sstevel@tonic-gate }
8217c478bd9Sstevel@tonic-gate }
822*759f6fc9Srm wmax = x - dx; /* Defaults */
823*759f6fc9Srm wmin = xi - dx;
824*759f6fc9Srm if ((xi < dx) || (x >= dx + w->_maxx)) {
8257c478bd9Sstevel@tonic-gate /* Overlaps parent. Must touch parent and child */
8267c478bd9Sstevel@tonic-gate int pmin, pmax;
8277c478bd9Sstevel@tonic-gate
828*759f6fc9Srm pmax = dx; /* Defaults */
829*759f6fc9Srm pmin = dx + w->_maxx;
830*759f6fc9Srm if (xi < dx) {
8317c478bd9Sstevel@tonic-gate wmin = 0;
8327c478bd9Sstevel@tonic-gate pmin = xi;
8337c478bd9Sstevel@tonic-gate }
834*759f6fc9Srm if (x >= dx + w->_maxx) {
8357c478bd9Sstevel@tonic-gate /* Ends right of target window */
8367c478bd9Sstevel@tonic-gate wmax = w->_maxx;
8377c478bd9Sstevel@tonic-gate pmax = x;
8387c478bd9Sstevel@tonic-gate }
8397c478bd9Sstevel@tonic-gate if (pmin < parent->_first[parentY])
8407c478bd9Sstevel@tonic-gate parent->_first[parentY] = (short)pmin;
8417c478bd9Sstevel@tonic-gate if (pmax > parent->_last[parentY])
8427c478bd9Sstevel@tonic-gate parent->_last[parentY] = (short)pmax;
8437c478bd9Sstevel@tonic-gate }
8447c478bd9Sstevel@tonic-gate if (wmin < w->_first[y])
8457c478bd9Sstevel@tonic-gate w->_first[y] = (short)wmin;
8467c478bd9Sstevel@tonic-gate if (wmax > w->_last[y])
8477c478bd9Sstevel@tonic-gate w->_last[y] = (short)wmax;
8487c478bd9Sstevel@tonic-gate }
8497c478bd9Sstevel@tonic-gate
8507c478bd9Sstevel@tonic-gate /*
8517c478bd9Sstevel@tonic-gate * Erase region from (y,x) to (ly, lx) inclusive. The
8527c478bd9Sstevel@tonic-gate * region is extended left and right in the case where
8537c478bd9Sstevel@tonic-gate * the portions of a multicolumn characters are erased.
8547c478bd9Sstevel@tonic-gate *
8557c478bd9Sstevel@tonic-gate * Return -1 if the region is not an integral multiple
8567c478bd9Sstevel@tonic-gate * of the background character, else zero for success.
8577c478bd9Sstevel@tonic-gate */
8587c478bd9Sstevel@tonic-gate int
__m_cc_erase(WINDOW * w,int y,int x,int ly,int lx)8597c478bd9Sstevel@tonic-gate __m_cc_erase(WINDOW *w, int y, int x, int ly, int lx)
8607c478bd9Sstevel@tonic-gate {
8617c478bd9Sstevel@tonic-gate int bgWidth;
8627c478bd9Sstevel@tonic-gate
8637c478bd9Sstevel@tonic-gate if (ly < y)
8647c478bd9Sstevel@tonic-gate return (-1);
8657c478bd9Sstevel@tonic-gate
8667c478bd9Sstevel@tonic-gate if (w->_maxy <= ly)
8677c478bd9Sstevel@tonic-gate ly = w->_maxy - 1;
8687c478bd9Sstevel@tonic-gate
8697c478bd9Sstevel@tonic-gate /*
8707c478bd9Sstevel@tonic-gate * Is the region to blank out an integral width of the
8717c478bd9Sstevel@tonic-gate * background character?
8727c478bd9Sstevel@tonic-gate */
8737c478bd9Sstevel@tonic-gate bgWidth = __m_cc_width(&w->_bg);
8747c478bd9Sstevel@tonic-gate
8757c478bd9Sstevel@tonic-gate if (bgWidth <= 0)
8767c478bd9Sstevel@tonic-gate return (-1);
8777c478bd9Sstevel@tonic-gate
8787c478bd9Sstevel@tonic-gate /*
8797c478bd9Sstevel@tonic-gate * Erase Pattern will look like:
8807c478bd9Sstevel@tonic-gate * EEEEEEE|
8817c478bd9Sstevel@tonic-gate * EEEEEEEEEEEEEEE|
8827c478bd9Sstevel@tonic-gate * EEEEEEEEEEE |
8837c478bd9Sstevel@tonic-gate */
8847c478bd9Sstevel@tonic-gate if (w->_parent) {
8857c478bd9Sstevel@tonic-gate /*
8867c478bd9Sstevel@tonic-gate * Use slower alg. for subwindows.
8877c478bd9Sstevel@tonic-gate * They might erase stuff in parent-context
8887c478bd9Sstevel@tonic-gate */
8897c478bd9Sstevel@tonic-gate int parentBGWidth = __m_cc_width(&w->_parent->_bg);
8907c478bd9Sstevel@tonic-gate for (; y < ly; ++y, x = 0) {
8917c478bd9Sstevel@tonic-gate __m_cc_erase_in_line_sub(w, y, x, w->_maxx-1,
8927c478bd9Sstevel@tonic-gate bgWidth, parentBGWidth);
8937c478bd9Sstevel@tonic-gate }
8947c478bd9Sstevel@tonic-gate __m_cc_erase_in_line_sub(w, y, x, lx, bgWidth, parentBGWidth);
8957c478bd9Sstevel@tonic-gate } else {
8967c478bd9Sstevel@tonic-gate /* Root windows - no need to work in parent context at all */
8977c478bd9Sstevel@tonic-gate if (w->_maxx <= lx)
8987c478bd9Sstevel@tonic-gate lx = w->_maxx - 1;
8997c478bd9Sstevel@tonic-gate
9007c478bd9Sstevel@tonic-gate /*
9017c478bd9Sstevel@tonic-gate * Erase from first whole character (inclusive) to next
9027c478bd9Sstevel@tonic-gate * character (exclusive).
9037c478bd9Sstevel@tonic-gate */
9047c478bd9Sstevel@tonic-gate x = __m_cc_first(w, y, x);
9057c478bd9Sstevel@tonic-gate lx = __m_cc_next(w, ly, lx) - 1;
9067c478bd9Sstevel@tonic-gate
9077c478bd9Sstevel@tonic-gate for (; y < ly; ++y, x = 0) {
9087c478bd9Sstevel@tonic-gate __m_cc_erase_in_line(w, y, x, w->_maxx-1, bgWidth);
9097c478bd9Sstevel@tonic-gate }
9107c478bd9Sstevel@tonic-gate __m_cc_erase_in_line(w, y, x, lx, bgWidth);
9117c478bd9Sstevel@tonic-gate }
9127c478bd9Sstevel@tonic-gate return (0);
9137c478bd9Sstevel@tonic-gate }
9147c478bd9Sstevel@tonic-gate
9157c478bd9Sstevel@tonic-gate /*
9167c478bd9Sstevel@tonic-gate * Expand the character to the left or right of the given position.
9177c478bd9Sstevel@tonic-gate * Return the value returned by __m_cc_replace().
9187c478bd9Sstevel@tonic-gate */
9197c478bd9Sstevel@tonic-gate int
__m_cc_expand(WINDOW * w,int y,int x,int side)9207c478bd9Sstevel@tonic-gate __m_cc_expand(WINDOW *w, int y, int x, int side)
9217c478bd9Sstevel@tonic-gate {
9227c478bd9Sstevel@tonic-gate cchar_t cc;
9237c478bd9Sstevel@tonic-gate int dx, width;
9247c478bd9Sstevel@tonic-gate
9257c478bd9Sstevel@tonic-gate width = __m_cc_width(&w->_line[y][x]);
9267c478bd9Sstevel@tonic-gate
9277c478bd9Sstevel@tonic-gate if (side < 0)
9287c478bd9Sstevel@tonic-gate dx = __m_cc_next(w, y, x) - width;
9297c478bd9Sstevel@tonic-gate else if (0 < side)
9307c478bd9Sstevel@tonic-gate dx = __m_cc_first(w, y, x);
9317c478bd9Sstevel@tonic-gate else
9327c478bd9Sstevel@tonic-gate return (-1);
9337c478bd9Sstevel@tonic-gate
9347c478bd9Sstevel@tonic-gate /*
9357c478bd9Sstevel@tonic-gate * __m_cc_replace() will erase the region containing
9367c478bd9Sstevel@tonic-gate * the character we want to expand.
9377c478bd9Sstevel@tonic-gate */
9387c478bd9Sstevel@tonic-gate cc = w->_line[y][x];
9397c478bd9Sstevel@tonic-gate
9407c478bd9Sstevel@tonic-gate return (__m_cc_replace(w, y, dx, &cc, 0));
9417c478bd9Sstevel@tonic-gate }
9427c478bd9Sstevel@tonic-gate
9437c478bd9Sstevel@tonic-gate /* Revised version of __m_cc_compare() to compare only the char parts */
9447c478bd9Sstevel@tonic-gate
9457c478bd9Sstevel@tonic-gate int
__m_cc_equal(const cchar_t * c1,const cchar_t * c2)9467c478bd9Sstevel@tonic-gate __m_cc_equal(const cchar_t *c1, const cchar_t *c2)
9477c478bd9Sstevel@tonic-gate {
9487c478bd9Sstevel@tonic-gate int i;
9497c478bd9Sstevel@tonic-gate
9507c478bd9Sstevel@tonic-gate if (c1->_f != c2->_f)
9517c478bd9Sstevel@tonic-gate return (0);
9527c478bd9Sstevel@tonic-gate if (c1->_n != c2->_n)
9537c478bd9Sstevel@tonic-gate return (0);
9547c478bd9Sstevel@tonic-gate for (i = 0; i < c1->_n; ++i)
9557c478bd9Sstevel@tonic-gate if (c1->_wc[i] != c2->_wc[i])
9567c478bd9Sstevel@tonic-gate return (0);
9577c478bd9Sstevel@tonic-gate return (1);
9587c478bd9Sstevel@tonic-gate }
9597c478bd9Sstevel@tonic-gate
9607c478bd9Sstevel@tonic-gate /*
9617c478bd9Sstevel@tonic-gate * Return true if characters are equal.
9627c478bd9Sstevel@tonic-gate *
9637c478bd9Sstevel@tonic-gate * NOTE to guarantee correct results, make sure that both
9647c478bd9Sstevel@tonic-gate * characters have been passed through __m_cc_sort().
9657c478bd9Sstevel@tonic-gate */
9667c478bd9Sstevel@tonic-gate int
__m_cc_compare(const cchar_t * c1,const cchar_t * c2,int exact)9677c478bd9Sstevel@tonic-gate __m_cc_compare(const cchar_t *c1, const cchar_t *c2, int exact)
9687c478bd9Sstevel@tonic-gate {
9697c478bd9Sstevel@tonic-gate int i;
9707c478bd9Sstevel@tonic-gate
9717c478bd9Sstevel@tonic-gate if (exact && c1->_f != c2->_f)
9727c478bd9Sstevel@tonic-gate return (0);
9737c478bd9Sstevel@tonic-gate if (c1->_n != c2->_n)
9747c478bd9Sstevel@tonic-gate return (0);
9757c478bd9Sstevel@tonic-gate if ((c1->_at & ~WA_COOKIE) != (c2->_at & ~WA_COOKIE))
9767c478bd9Sstevel@tonic-gate return (0);
9777c478bd9Sstevel@tonic-gate if (c1->_co != c2->_co)
9787c478bd9Sstevel@tonic-gate return (0);
9797c478bd9Sstevel@tonic-gate
9807c478bd9Sstevel@tonic-gate for (i = 0; i < c1->_n; ++i)
9817c478bd9Sstevel@tonic-gate if (c1->_wc[i] != c2->_wc[i])
9827c478bd9Sstevel@tonic-gate return (0);
9837c478bd9Sstevel@tonic-gate
9847c478bd9Sstevel@tonic-gate return (1);
9857c478bd9Sstevel@tonic-gate }
9867c478bd9Sstevel@tonic-gate
9877c478bd9Sstevel@tonic-gate /*
9887c478bd9Sstevel@tonic-gate * Write to the stream the character portion of a cchar_t.
9897c478bd9Sstevel@tonic-gate */
9907c478bd9Sstevel@tonic-gate int
__m_cc_write(const cchar_t * cc)9917c478bd9Sstevel@tonic-gate __m_cc_write(const cchar_t *cc)
9927c478bd9Sstevel@tonic-gate {
9937c478bd9Sstevel@tonic-gate int j;
9947c478bd9Sstevel@tonic-gate size_t i;
9957c478bd9Sstevel@tonic-gate char mb[MB_LEN_MAX];
9967c478bd9Sstevel@tonic-gate /*
9977c478bd9Sstevel@tonic-gate * 4131273 UNIX98: xcurses library renders complex characters incorrectly
9987c478bd9Sstevel@tonic-gate */
9997c478bd9Sstevel@tonic-gate int backed_up = 0;
10007c478bd9Sstevel@tonic-gate
10017c478bd9Sstevel@tonic-gate for (i = 0; i < cc->_n; ++i) {
10027c478bd9Sstevel@tonic-gate j = wctomb(mb, cc->_wc[i]);
10037c478bd9Sstevel@tonic-gate if (j == -1)
10047c478bd9Sstevel@tonic-gate return (EOF);
10057c478bd9Sstevel@tonic-gate if (i == 1) {
10067c478bd9Sstevel@tonic-gate /*
10077c478bd9Sstevel@tonic-gate * Move cursor back where it was
10087c478bd9Sstevel@tonic-gate */
10097c478bd9Sstevel@tonic-gate if (fwrite(cursor_left, 1, strlen(cursor_left),
10107c478bd9Sstevel@tonic-gate __m_screen->_of) == 0) {
10117c478bd9Sstevel@tonic-gate return (EOF);
10127c478bd9Sstevel@tonic-gate }
10137c478bd9Sstevel@tonic-gate backed_up = 1;
10147c478bd9Sstevel@tonic-gate }
10157c478bd9Sstevel@tonic-gate if (fwrite(mb, sizeof (*mb), (size_t)j, __m_screen->_of) == 0) {
10167c478bd9Sstevel@tonic-gate return (EOF);
10177c478bd9Sstevel@tonic-gate }
10187c478bd9Sstevel@tonic-gate }
10197c478bd9Sstevel@tonic-gate if (backed_up) {
10207c478bd9Sstevel@tonic-gate /*
10217c478bd9Sstevel@tonic-gate * Move cursor back where it was
10227c478bd9Sstevel@tonic-gate */
10237c478bd9Sstevel@tonic-gate if (fwrite(cursor_right, 1, strlen(cursor_right),
10247c478bd9Sstevel@tonic-gate __m_screen->_of) == 0) {
10257c478bd9Sstevel@tonic-gate return (EOF);
10267c478bd9Sstevel@tonic-gate }
10277c478bd9Sstevel@tonic-gate }
10287c478bd9Sstevel@tonic-gate
10297c478bd9Sstevel@tonic-gate __m_screen->_flags |= W_FLUSH;
10307c478bd9Sstevel@tonic-gate return (0);
10317c478bd9Sstevel@tonic-gate }
1032