1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate /* 30*7c478bd9Sstevel@tonic-gate * m_cc.c 31*7c478bd9Sstevel@tonic-gate * 32*7c478bd9Sstevel@tonic-gate * XCurses Library 33*7c478bd9Sstevel@tonic-gate * 34*7c478bd9Sstevel@tonic-gate * Copyright 1990, 1995 by Mortice Kern Systems Inc. All rights reserved. 35*7c478bd9Sstevel@tonic-gate * 36*7c478bd9Sstevel@tonic-gate */ 37*7c478bd9Sstevel@tonic-gate 38*7c478bd9Sstevel@tonic-gate #if M_RCSID 39*7c478bd9Sstevel@tonic-gate #ifndef lint 40*7c478bd9Sstevel@tonic-gate static char rcsID[] = "$Header: /rd/src/libc/xcurses/rcs/m_cc.c 1.8 1995/09/20 15:26:52 ant Exp $"; 41*7c478bd9Sstevel@tonic-gate #endif 42*7c478bd9Sstevel@tonic-gate #endif 43*7c478bd9Sstevel@tonic-gate 44*7c478bd9Sstevel@tonic-gate #include <private.h> 45*7c478bd9Sstevel@tonic-gate #include <errno.h> 46*7c478bd9Sstevel@tonic-gate #include <limits.h> 47*7c478bd9Sstevel@tonic-gate #include <string.h> 48*7c478bd9Sstevel@tonic-gate #include <m_wio.h> 49*7c478bd9Sstevel@tonic-gate 50*7c478bd9Sstevel@tonic-gate typedef struct { 51*7c478bd9Sstevel@tonic-gate int max; 52*7c478bd9Sstevel@tonic-gate int used; 53*7c478bd9Sstevel@tonic-gate char *mbs; 54*7c478bd9Sstevel@tonic-gate } t_string; 55*7c478bd9Sstevel@tonic-gate 56*7c478bd9Sstevel@tonic-gate static int 57*7c478bd9Sstevel@tonic-gate write_string(byte, sp) 58*7c478bd9Sstevel@tonic-gate int byte; 59*7c478bd9Sstevel@tonic-gate t_string *sp; 60*7c478bd9Sstevel@tonic-gate { 61*7c478bd9Sstevel@tonic-gate if (sp->max <= sp->used) 62*7c478bd9Sstevel@tonic-gate return EOF; 63*7c478bd9Sstevel@tonic-gate 64*7c478bd9Sstevel@tonic-gate sp->mbs[sp->used++] = byte; 65*7c478bd9Sstevel@tonic-gate 66*7c478bd9Sstevel@tonic-gate return byte; 67*7c478bd9Sstevel@tonic-gate } 68*7c478bd9Sstevel@tonic-gate 69*7c478bd9Sstevel@tonic-gate /* 70*7c478bd9Sstevel@tonic-gate * Convert a wint_t string into a multibyte string. 71*7c478bd9Sstevel@tonic-gate * 72*7c478bd9Sstevel@tonic-gate * The conversion stops at the end of string or the first WEOF. 73*7c478bd9Sstevel@tonic-gate * Return the number of bytes successfully placed into mbs. 74*7c478bd9Sstevel@tonic-gate */ 75*7c478bd9Sstevel@tonic-gate int 76*7c478bd9Sstevel@tonic-gate wistombs(mbs, wis, n) 77*7c478bd9Sstevel@tonic-gate char *mbs; 78*7c478bd9Sstevel@tonic-gate const wint_t *wis; 79*7c478bd9Sstevel@tonic-gate int n; 80*7c478bd9Sstevel@tonic-gate { 81*7c478bd9Sstevel@tonic-gate int last; 82*7c478bd9Sstevel@tonic-gate t_string string = { 0 }; 83*7c478bd9Sstevel@tonic-gate t_wide_io convert = { 0 }; 84*7c478bd9Sstevel@tonic-gate 85*7c478bd9Sstevel@tonic-gate string.max = n; 86*7c478bd9Sstevel@tonic-gate string.mbs = mbs; 87*7c478bd9Sstevel@tonic-gate convert.object = (void *) &string; 88*7c478bd9Sstevel@tonic-gate convert.put = (int (*)(int, void *)) write_string; 89*7c478bd9Sstevel@tonic-gate 90*7c478bd9Sstevel@tonic-gate for (;; ++wis) { 91*7c478bd9Sstevel@tonic-gate /* In case of error, rewind string to the last character. */ 92*7c478bd9Sstevel@tonic-gate last = string.used; 93*7c478bd9Sstevel@tonic-gate 94*7c478bd9Sstevel@tonic-gate if (m_wio_put(*wis, &convert) < 0) { 95*7c478bd9Sstevel@tonic-gate string.used = last; 96*7c478bd9Sstevel@tonic-gate break; 97*7c478bd9Sstevel@tonic-gate } 98*7c478bd9Sstevel@tonic-gate 99*7c478bd9Sstevel@tonic-gate /* Test for end of string AFTER trying to copy into the 100*7c478bd9Sstevel@tonic-gate * buffer, because m_wio_put() has to handle state changes 101*7c478bd9Sstevel@tonic-gate * back to the initial state on '\0' or WEOF. 102*7c478bd9Sstevel@tonic-gate */ 103*7c478bd9Sstevel@tonic-gate if (*wis == '\0' || *wis == WEOF) 104*7c478bd9Sstevel@tonic-gate break; 105*7c478bd9Sstevel@tonic-gate } 106*7c478bd9Sstevel@tonic-gate 107*7c478bd9Sstevel@tonic-gate /* m_wio_put() does not write '\0', because the "stream" 108*7c478bd9Sstevel@tonic-gate * object is considered to be in "text" mode, which in the 109*7c478bd9Sstevel@tonic-gate * case of file I/O produces undefined results for systems 110*7c478bd9Sstevel@tonic-gate * using locking-shift character sets. 111*7c478bd9Sstevel@tonic-gate */ 112*7c478bd9Sstevel@tonic-gate string.mbs[string.used] = '\0'; 113*7c478bd9Sstevel@tonic-gate 114*7c478bd9Sstevel@tonic-gate return string.used; 115*7c478bd9Sstevel@tonic-gate } 116*7c478bd9Sstevel@tonic-gate 117*7c478bd9Sstevel@tonic-gate /* 118*7c478bd9Sstevel@tonic-gate * Convert a wint_t string (filled in by wgetn_wstr()) to a wchar_t string. 119*7c478bd9Sstevel@tonic-gate * The conversion stops at the end of string or the first WEOF. Return the 120*7c478bd9Sstevel@tonic-gate * number of successfully copied characters. 121*7c478bd9Sstevel@tonic-gate * 122*7c478bd9Sstevel@tonic-gate * This routinue should be used when sizeof (wchar_t) < sizeof (wint_t). 123*7c478bd9Sstevel@tonic-gate */ 124*7c478bd9Sstevel@tonic-gate int 125*7c478bd9Sstevel@tonic-gate wistowcs(wcs, wis, n) 126*7c478bd9Sstevel@tonic-gate wchar_t *wcs; 127*7c478bd9Sstevel@tonic-gate const wint_t *wis; 128*7c478bd9Sstevel@tonic-gate int n; 129*7c478bd9Sstevel@tonic-gate { 130*7c478bd9Sstevel@tonic-gate wchar_t *start; 131*7c478bd9Sstevel@tonic-gate 132*7c478bd9Sstevel@tonic-gate if (n < 0) 133*7c478bd9Sstevel@tonic-gate n = INT_MAX; 134*7c478bd9Sstevel@tonic-gate 135*7c478bd9Sstevel@tonic-gate for (start = wcs; *wis != '\0' && 0 < n; ++wis, ++wcs, --n) { 136*7c478bd9Sstevel@tonic-gate if (*wis == WEOF) 137*7c478bd9Sstevel@tonic-gate break; 138*7c478bd9Sstevel@tonic-gate *wcs = (wchar_t) *wis; 139*7c478bd9Sstevel@tonic-gate } 140*7c478bd9Sstevel@tonic-gate *wcs = '\0'; 141*7c478bd9Sstevel@tonic-gate 142*7c478bd9Sstevel@tonic-gate return (int) (wcs - start); 143*7c478bd9Sstevel@tonic-gate } 144*7c478bd9Sstevel@tonic-gate 145*7c478bd9Sstevel@tonic-gate /* 146*7c478bd9Sstevel@tonic-gate * Convert a chtype to a cchar_t. 147*7c478bd9Sstevel@tonic-gate */ 148*7c478bd9Sstevel@tonic-gate int 149*7c478bd9Sstevel@tonic-gate __m_chtype_cc(ch, cc) 150*7c478bd9Sstevel@tonic-gate chtype ch; 151*7c478bd9Sstevel@tonic-gate cchar_t *cc; 152*7c478bd9Sstevel@tonic-gate { 153*7c478bd9Sstevel@tonic-gate char mb; 154*7c478bd9Sstevel@tonic-gate 155*7c478bd9Sstevel@tonic-gate cc->_f = 1; 156*7c478bd9Sstevel@tonic-gate cc->_n = 1; 157*7c478bd9Sstevel@tonic-gate mb = (char)(ch & A_CHARTEXT); 158*7c478bd9Sstevel@tonic-gate 159*7c478bd9Sstevel@tonic-gate if (mbtowc(cc->_wc, &mb, 1) < 0) 160*7c478bd9Sstevel@tonic-gate return ERR; 161*7c478bd9Sstevel@tonic-gate 162*7c478bd9Sstevel@tonic-gate cc->_co = (short) PAIR_NUMBER(ch); 163*7c478bd9Sstevel@tonic-gate cc->_at = (attr_t) ((ch & (A_ATTRIBUTES & ~A_COLOR)) >> 16); 164*7c478bd9Sstevel@tonic-gate 165*7c478bd9Sstevel@tonic-gate return OK; 166*7c478bd9Sstevel@tonic-gate } 167*7c478bd9Sstevel@tonic-gate 168*7c478bd9Sstevel@tonic-gate /* 169*7c478bd9Sstevel@tonic-gate * Return a complex character as a chtype. 170*7c478bd9Sstevel@tonic-gate */ 171*7c478bd9Sstevel@tonic-gate chtype 172*7c478bd9Sstevel@tonic-gate __m_cc_chtype(cc) 173*7c478bd9Sstevel@tonic-gate const cchar_t *cc; 174*7c478bd9Sstevel@tonic-gate { 175*7c478bd9Sstevel@tonic-gate chtype ch; 176*7c478bd9Sstevel@tonic-gate unsigned char mb[MB_LEN_MAX]; 177*7c478bd9Sstevel@tonic-gate 178*7c478bd9Sstevel@tonic-gate /* Is it a single-byte character? */ 179*7c478bd9Sstevel@tonic-gate if (cc->_n != 1 || wctomb((char *) mb, cc->_wc[0]) != 1) 180*7c478bd9Sstevel@tonic-gate return (chtype) ERR; 181*7c478bd9Sstevel@tonic-gate 182*7c478bd9Sstevel@tonic-gate ch = ((chtype) cc->_at << 16) & ~A_COLOR; 183*7c478bd9Sstevel@tonic-gate ch |= COLOR_PAIR(cc->_co) | mb[0]; 184*7c478bd9Sstevel@tonic-gate 185*7c478bd9Sstevel@tonic-gate return ch; 186*7c478bd9Sstevel@tonic-gate } 187*7c478bd9Sstevel@tonic-gate 188*7c478bd9Sstevel@tonic-gate /* 189*7c478bd9Sstevel@tonic-gate * Convert a complex character's "character" into a multibyte string. 190*7c478bd9Sstevel@tonic-gate * The attribute and colour are ignored. 191*7c478bd9Sstevel@tonic-gate * 192*7c478bd9Sstevel@tonic-gate * If 0 < n, set a new multibyte string and convert the first character, 193*7c478bd9Sstevel@tonic-gate * returning either -1 on error or the number of bytes used to convert the 194*7c478bd9Sstevel@tonic-gate * character. 195*7c478bd9Sstevel@tonic-gate * 196*7c478bd9Sstevel@tonic-gate * If n == 0, continue appending to the current multibyte string and return 197*7c478bd9Sstevel@tonic-gate * a value as for 0 < n case. 198*7c478bd9Sstevel@tonic-gate * 199*7c478bd9Sstevel@tonic-gate * If n < 0, return the accumulated byte length of the current multibyte 200*7c478bd9Sstevel@tonic-gate * string and do nothing else. 201*7c478bd9Sstevel@tonic-gate * 202*7c478bd9Sstevel@tonic-gate * When converting a character, a null cchar_t pointer will force the initial 203*7c478bd9Sstevel@tonic-gate * shift state and append a '\0' to the multibyte string. The return value 204*7c478bd9Sstevel@tonic-gate * will instead by the number of bytes used to shift to the initial state, 205*7c478bd9Sstevel@tonic-gate * and exclude the '\0'. 206*7c478bd9Sstevel@tonic-gate */ 207*7c478bd9Sstevel@tonic-gate int 208*7c478bd9Sstevel@tonic-gate __m_cc_mbs(cc, mbs, n) 209*7c478bd9Sstevel@tonic-gate const cchar_t *cc; 210*7c478bd9Sstevel@tonic-gate char *mbs; 211*7c478bd9Sstevel@tonic-gate int n; 212*7c478bd9Sstevel@tonic-gate { 213*7c478bd9Sstevel@tonic-gate cchar_t *cp; 214*7c478bd9Sstevel@tonic-gate int i, bytes, count, last; 215*7c478bd9Sstevel@tonic-gate mbstate_t initial = { 0 }; 216*7c478bd9Sstevel@tonic-gate static t_string string = { 0 }; 217*7c478bd9Sstevel@tonic-gate static t_wide_io convert = { 0 }; 218*7c478bd9Sstevel@tonic-gate 219*7c478bd9Sstevel@tonic-gate if (n < 0) { 220*7c478bd9Sstevel@tonic-gate /* Return total number of bytes written to multibyte string. */ 221*7c478bd9Sstevel@tonic-gate return string.used; 222*7c478bd9Sstevel@tonic-gate } else if (0 < n) { 223*7c478bd9Sstevel@tonic-gate /* Start a new conversion. */ 224*7c478bd9Sstevel@tonic-gate string.max = n; 225*7c478bd9Sstevel@tonic-gate string.used = 0; 226*7c478bd9Sstevel@tonic-gate string.mbs = mbs; 227*7c478bd9Sstevel@tonic-gate 228*7c478bd9Sstevel@tonic-gate convert._state = initial; 229*7c478bd9Sstevel@tonic-gate convert._next = convert._size = 0; 230*7c478bd9Sstevel@tonic-gate convert.object = (void *) &string; 231*7c478bd9Sstevel@tonic-gate convert.put = (int (*)(int, void *)) write_string; 232*7c478bd9Sstevel@tonic-gate } /* else n == 0, continue appending to previous mbs. */ 233*7c478bd9Sstevel@tonic-gate 234*7c478bd9Sstevel@tonic-gate /* In case of error, rewind string to the last character. */ 235*7c478bd9Sstevel@tonic-gate last = string.used; 236*7c478bd9Sstevel@tonic-gate 237*7c478bd9Sstevel@tonic-gate if (cc == (cchar_t *) 0) { 238*7c478bd9Sstevel@tonic-gate /* Force initial shift state. */ 239*7c478bd9Sstevel@tonic-gate if ((count = m_wio_put('\0', &convert)) < 0) { 240*7c478bd9Sstevel@tonic-gate string.used = last; 241*7c478bd9Sstevel@tonic-gate return -1; 242*7c478bd9Sstevel@tonic-gate } 243*7c478bd9Sstevel@tonic-gate 244*7c478bd9Sstevel@tonic-gate if (string.used < string.max) 245*7c478bd9Sstevel@tonic-gate string.mbs[string.used++] = '\0'; 246*7c478bd9Sstevel@tonic-gate } else { 247*7c478bd9Sstevel@tonic-gate for (count = i = 0; i < cc->_n; ++i, count += bytes) 248*7c478bd9Sstevel@tonic-gate if ((bytes = m_wio_put(cc->_wc[i], &convert)) < 0) { 249*7c478bd9Sstevel@tonic-gate string.used = last; 250*7c478bd9Sstevel@tonic-gate return -1; 251*7c478bd9Sstevel@tonic-gate } 252*7c478bd9Sstevel@tonic-gate } 253*7c478bd9Sstevel@tonic-gate 254*7c478bd9Sstevel@tonic-gate return count; 255*7c478bd9Sstevel@tonic-gate } 256*7c478bd9Sstevel@tonic-gate 257*7c478bd9Sstevel@tonic-gate /* 258*7c478bd9Sstevel@tonic-gate * Convert a stty character into a wchar_t. 259*7c478bd9Sstevel@tonic-gate */ 260*7c478bd9Sstevel@tonic-gate int 261*7c478bd9Sstevel@tonic-gate __m_tty_wc(index, wcp) 262*7c478bd9Sstevel@tonic-gate int index; 263*7c478bd9Sstevel@tonic-gate wchar_t *wcp; 264*7c478bd9Sstevel@tonic-gate { 265*7c478bd9Sstevel@tonic-gate char mb; 266*7c478bd9Sstevel@tonic-gate int code; 267*7c478bd9Sstevel@tonic-gate 268*7c478bd9Sstevel@tonic-gate /* Refer to _shell instead of _prog, since _shell will 269*7c478bd9Sstevel@tonic-gate * correctly reflect the user's prefered settings, whereas 270*7c478bd9Sstevel@tonic-gate * _prog may not have been initialised if both input and 271*7c478bd9Sstevel@tonic-gate * output have been redirected. 272*7c478bd9Sstevel@tonic-gate */ 273*7c478bd9Sstevel@tonic-gate mb = cur_term->_shell.c_cc[index]; 274*7c478bd9Sstevel@tonic-gate code = mbtowc(wcp, &mb, 1) < 0 ? ERR : OK; 275*7c478bd9Sstevel@tonic-gate 276*7c478bd9Sstevel@tonic-gate return code; 277*7c478bd9Sstevel@tonic-gate } 278*7c478bd9Sstevel@tonic-gate 279*7c478bd9Sstevel@tonic-gate /* 280*7c478bd9Sstevel@tonic-gate * Build a cchar_t from the leading spacing and non-spacing characters 281*7c478bd9Sstevel@tonic-gate * in the multibyte character string. Only one spacing character is copied 282*7c478bd9Sstevel@tonic-gate * from the multibyte character string. 283*7c478bd9Sstevel@tonic-gate * 284*7c478bd9Sstevel@tonic-gate * Return the number of characters copied from the string, or -1 on error. 285*7c478bd9Sstevel@tonic-gate */ 286*7c478bd9Sstevel@tonic-gate int 287*7c478bd9Sstevel@tonic-gate __m_mbs_cc(const char *mbs, attr_t at, short co, cchar_t *cc) 288*7c478bd9Sstevel@tonic-gate { 289*7c478bd9Sstevel@tonic-gate wchar_t wc; 290*7c478bd9Sstevel@tonic-gate const char *start; 291*7c478bd9Sstevel@tonic-gate int i, nbytes, width, have_one; 292*7c478bd9Sstevel@tonic-gate 293*7c478bd9Sstevel@tonic-gate for (start = mbs, have_one = i = 0; *mbs != '\0'; mbs += nbytes, ++i) { 294*7c478bd9Sstevel@tonic-gate if (sizeof cc->_wc <= i) 295*7c478bd9Sstevel@tonic-gate /* Too many characters. */ 296*7c478bd9Sstevel@tonic-gate return -1; 297*7c478bd9Sstevel@tonic-gate 298*7c478bd9Sstevel@tonic-gate if ((nbytes = mbtowc(&wc, mbs, UINT_MAX)) < 0) 299*7c478bd9Sstevel@tonic-gate /* Invalid multibyte sequence. */ 300*7c478bd9Sstevel@tonic-gate return -1; 301*7c478bd9Sstevel@tonic-gate 302*7c478bd9Sstevel@tonic-gate if (nbytes == 0) 303*7c478bd9Sstevel@tonic-gate /* Remainder of string evaluates to the null byte. */ 304*7c478bd9Sstevel@tonic-gate break; 305*7c478bd9Sstevel@tonic-gate 306*7c478bd9Sstevel@tonic-gate if (iscntrl(*mbs)) 307*7c478bd9Sstevel@tonic-gate /* Treat control codes like a spacing character. */ 308*7c478bd9Sstevel@tonic-gate width = 1; 309*7c478bd9Sstevel@tonic-gate else if ((width = wcwidth(wc)) < 0) 310*7c478bd9Sstevel@tonic-gate return -1; 311*7c478bd9Sstevel@tonic-gate 312*7c478bd9Sstevel@tonic-gate /* Do we have a spacing character? */ 313*7c478bd9Sstevel@tonic-gate if (0 < width) { 314*7c478bd9Sstevel@tonic-gate if (have_one) 315*7c478bd9Sstevel@tonic-gate break; 316*7c478bd9Sstevel@tonic-gate have_one = 1; 317*7c478bd9Sstevel@tonic-gate } 318*7c478bd9Sstevel@tonic-gate 319*7c478bd9Sstevel@tonic-gate cc->_wc[i] = wc; 320*7c478bd9Sstevel@tonic-gate } 321*7c478bd9Sstevel@tonic-gate 322*7c478bd9Sstevel@tonic-gate cc->_f = 1; 323*7c478bd9Sstevel@tonic-gate cc->_n = i; 324*7c478bd9Sstevel@tonic-gate cc->_co = co; 325*7c478bd9Sstevel@tonic-gate cc->_at = at; 326*7c478bd9Sstevel@tonic-gate 327*7c478bd9Sstevel@tonic-gate (void) __m_cc_sort(cc); 328*7c478bd9Sstevel@tonic-gate 329*7c478bd9Sstevel@tonic-gate return (int) (mbs - start); 330*7c478bd9Sstevel@tonic-gate } 331*7c478bd9Sstevel@tonic-gate 332*7c478bd9Sstevel@tonic-gate /* 333*7c478bd9Sstevel@tonic-gate * Build a cchar_t from the leading spacing and non-spacing characters 334*7c478bd9Sstevel@tonic-gate * in the wide character string. Only one spacinig character is copied 335*7c478bd9Sstevel@tonic-gate * from the wide character string. 336*7c478bd9Sstevel@tonic-gate * 337*7c478bd9Sstevel@tonic-gate * Return the number of characters copied from the string, or -1 on error. 338*7c478bd9Sstevel@tonic-gate */ 339*7c478bd9Sstevel@tonic-gate int 340*7c478bd9Sstevel@tonic-gate __m_wcs_cc(const wchar_t *wcs, attr_t at, short co, cchar_t *cc) 341*7c478bd9Sstevel@tonic-gate { 342*7c478bd9Sstevel@tonic-gate short i; 343*7c478bd9Sstevel@tonic-gate int width, have_one; 344*7c478bd9Sstevel@tonic-gate const wchar_t *start; 345*7c478bd9Sstevel@tonic-gate 346*7c478bd9Sstevel@tonic-gate for (start = wcs, have_one = i = 0; *wcs != '\0'; ++wcs, ++i) { 347*7c478bd9Sstevel@tonic-gate if (sizeof cc->_wc <= i) 348*7c478bd9Sstevel@tonic-gate /* Too many characters. */ 349*7c478bd9Sstevel@tonic-gate return -1; 350*7c478bd9Sstevel@tonic-gate 351*7c478bd9Sstevel@tonic-gate if ((width = wcwidth(*wcs)) < 0) 352*7c478bd9Sstevel@tonic-gate return -1; 353*7c478bd9Sstevel@tonic-gate 354*7c478bd9Sstevel@tonic-gate if (0 < width) { 355*7c478bd9Sstevel@tonic-gate if (have_one) 356*7c478bd9Sstevel@tonic-gate break; 357*7c478bd9Sstevel@tonic-gate have_one = 1; 358*7c478bd9Sstevel@tonic-gate } 359*7c478bd9Sstevel@tonic-gate 360*7c478bd9Sstevel@tonic-gate cc->_wc[i] = *wcs; 361*7c478bd9Sstevel@tonic-gate } 362*7c478bd9Sstevel@tonic-gate 363*7c478bd9Sstevel@tonic-gate cc->_f = 1; 364*7c478bd9Sstevel@tonic-gate cc->_n = i; 365*7c478bd9Sstevel@tonic-gate cc->_co = co; 366*7c478bd9Sstevel@tonic-gate cc->_at = at; 367*7c478bd9Sstevel@tonic-gate 368*7c478bd9Sstevel@tonic-gate (void) __m_cc_sort(cc); 369*7c478bd9Sstevel@tonic-gate 370*7c478bd9Sstevel@tonic-gate return (int) (wcs - start); 371*7c478bd9Sstevel@tonic-gate } 372*7c478bd9Sstevel@tonic-gate 373*7c478bd9Sstevel@tonic-gate /* 374*7c478bd9Sstevel@tonic-gate * Convert a single wide character into a complex character. 375*7c478bd9Sstevel@tonic-gate */ 376*7c478bd9Sstevel@tonic-gate int 377*7c478bd9Sstevel@tonic-gate __m_wc_cc(wint_t wc, cchar_t *cc) 378*7c478bd9Sstevel@tonic-gate { 379*7c478bd9Sstevel@tonic-gate wchar_t wcs[2]; 380*7c478bd9Sstevel@tonic-gate 381*7c478bd9Sstevel@tonic-gate if (wc == WEOF) 382*7c478bd9Sstevel@tonic-gate return -1; 383*7c478bd9Sstevel@tonic-gate 384*7c478bd9Sstevel@tonic-gate wcs[0] = (wchar_t)wc; 385*7c478bd9Sstevel@tonic-gate wcs[1] = '\0'; 386*7c478bd9Sstevel@tonic-gate (void) __m_wcs_cc(wcs, WA_NORMAL, 0, cc); 387*7c478bd9Sstevel@tonic-gate 388*7c478bd9Sstevel@tonic-gate return 0; 389*7c478bd9Sstevel@tonic-gate } 390*7c478bd9Sstevel@tonic-gate 391*7c478bd9Sstevel@tonic-gate /* 392*7c478bd9Sstevel@tonic-gate * Sort a complex character into a spacing character followed 393*7c478bd9Sstevel@tonic-gate * by any non-spacing characters in increasing order of oridinal 394*7c478bd9Sstevel@tonic-gate * values. This facilitates both comparision and writting of 395*7c478bd9Sstevel@tonic-gate * complex characters. More than one spacing character is 396*7c478bd9Sstevel@tonic-gate * considered an error. 397*7c478bd9Sstevel@tonic-gate * 398*7c478bd9Sstevel@tonic-gate * Return the spacing character's column width or -1 if more 399*7c478bd9Sstevel@tonic-gate * than one spacing character appears in cc. 400*7c478bd9Sstevel@tonic-gate */ 401*7c478bd9Sstevel@tonic-gate int 402*7c478bd9Sstevel@tonic-gate __m_cc_sort(cc) 403*7c478bd9Sstevel@tonic-gate cchar_t *cc; 404*7c478bd9Sstevel@tonic-gate { 405*7c478bd9Sstevel@tonic-gate wchar_t wc; 406*7c478bd9Sstevel@tonic-gate int width, i, j, spacing; 407*7c478bd9Sstevel@tonic-gate 408*7c478bd9Sstevel@tonic-gate /* Find spacing character and place in as first element. */ 409*7c478bd9Sstevel@tonic-gate for (width = spacing = i = 0; i < cc->_n; ++i) { 410*7c478bd9Sstevel@tonic-gate j = wcwidth(cc->_wc[i]); 411*7c478bd9Sstevel@tonic-gate if (0 < j) { 412*7c478bd9Sstevel@tonic-gate /* More than one spacing character is an error. */ 413*7c478bd9Sstevel@tonic-gate if (0 < width) 414*7c478bd9Sstevel@tonic-gate return -1; 415*7c478bd9Sstevel@tonic-gate 416*7c478bd9Sstevel@tonic-gate wc = cc->_wc[0]; 417*7c478bd9Sstevel@tonic-gate cc->_wc[0] = cc->_wc[i]; 418*7c478bd9Sstevel@tonic-gate cc->_wc[i] = wc; 419*7c478bd9Sstevel@tonic-gate 420*7c478bd9Sstevel@tonic-gate spacing = 1; 421*7c478bd9Sstevel@tonic-gate width = j; 422*7c478bd9Sstevel@tonic-gate break; 423*7c478bd9Sstevel@tonic-gate } 424*7c478bd9Sstevel@tonic-gate } 425*7c478bd9Sstevel@tonic-gate 426*7c478bd9Sstevel@tonic-gate /* Bubble sort small array. */ 427*7c478bd9Sstevel@tonic-gate for (i = spacing; i < cc->_n; ++i) { 428*7c478bd9Sstevel@tonic-gate for (j = cc->_n - 1; i < j; --j) { 429*7c478bd9Sstevel@tonic-gate if (cc->_wc[j-1] > cc->_wc[j]) { 430*7c478bd9Sstevel@tonic-gate wc = cc->_wc[j]; 431*7c478bd9Sstevel@tonic-gate cc->_wc[j] = cc->_wc[j-1]; 432*7c478bd9Sstevel@tonic-gate cc->_wc[j-1] = wc; 433*7c478bd9Sstevel@tonic-gate } 434*7c478bd9Sstevel@tonic-gate } 435*7c478bd9Sstevel@tonic-gate } 436*7c478bd9Sstevel@tonic-gate 437*7c478bd9Sstevel@tonic-gate return width; 438*7c478bd9Sstevel@tonic-gate } 439*7c478bd9Sstevel@tonic-gate 440*7c478bd9Sstevel@tonic-gate /* 441*7c478bd9Sstevel@tonic-gate * Return width inn screen columns of the character. 442*7c478bd9Sstevel@tonic-gate */ 443*7c478bd9Sstevel@tonic-gate int 444*7c478bd9Sstevel@tonic-gate __m_cc_width(cc) 445*7c478bd9Sstevel@tonic-gate const cchar_t *cc; 446*7c478bd9Sstevel@tonic-gate { 447*7c478bd9Sstevel@tonic-gate return wcwidth(cc->_wc[0]); 448*7c478bd9Sstevel@tonic-gate } 449*7c478bd9Sstevel@tonic-gate 450*7c478bd9Sstevel@tonic-gate /* 451*7c478bd9Sstevel@tonic-gate * Return the first column of a multi-column character, in window. 452*7c478bd9Sstevel@tonic-gate */ 453*7c478bd9Sstevel@tonic-gate int 454*7c478bd9Sstevel@tonic-gate __m_cc_first(w, y, x) 455*7c478bd9Sstevel@tonic-gate WINDOW *w; 456*7c478bd9Sstevel@tonic-gate int y, x; 457*7c478bd9Sstevel@tonic-gate { 458*7c478bd9Sstevel@tonic-gate register cchar_t *lp; 459*7c478bd9Sstevel@tonic-gate 460*7c478bd9Sstevel@tonic-gate for (lp = w->_line[y]; 0 < x; --x) { 461*7c478bd9Sstevel@tonic-gate if (lp[x]._f) 462*7c478bd9Sstevel@tonic-gate break; 463*7c478bd9Sstevel@tonic-gate } 464*7c478bd9Sstevel@tonic-gate 465*7c478bd9Sstevel@tonic-gate return x; 466*7c478bd9Sstevel@tonic-gate } 467*7c478bd9Sstevel@tonic-gate 468*7c478bd9Sstevel@tonic-gate /* 469*7c478bd9Sstevel@tonic-gate * Return the start of the next multi-column character, in window. 470*7c478bd9Sstevel@tonic-gate */ 471*7c478bd9Sstevel@tonic-gate int 472*7c478bd9Sstevel@tonic-gate __m_cc_next(w, y, x) 473*7c478bd9Sstevel@tonic-gate WINDOW *w; 474*7c478bd9Sstevel@tonic-gate int y, x; 475*7c478bd9Sstevel@tonic-gate { 476*7c478bd9Sstevel@tonic-gate cchar_t *lp; 477*7c478bd9Sstevel@tonic-gate 478*7c478bd9Sstevel@tonic-gate for (lp = w->_line[y]; ++x < w->_maxx; ) { 479*7c478bd9Sstevel@tonic-gate if (lp[x]._f) 480*7c478bd9Sstevel@tonic-gate break; 481*7c478bd9Sstevel@tonic-gate } 482*7c478bd9Sstevel@tonic-gate 483*7c478bd9Sstevel@tonic-gate return x; 484*7c478bd9Sstevel@tonic-gate } 485*7c478bd9Sstevel@tonic-gate 486*7c478bd9Sstevel@tonic-gate /* 487*7c478bd9Sstevel@tonic-gate * Return true if valid last column of a multi-column character. 488*7c478bd9Sstevel@tonic-gate */ 489*7c478bd9Sstevel@tonic-gate int 490*7c478bd9Sstevel@tonic-gate __m_cc_islast(w, y, x) 491*7c478bd9Sstevel@tonic-gate WINDOW *w; 492*7c478bd9Sstevel@tonic-gate int y, x; 493*7c478bd9Sstevel@tonic-gate { 494*7c478bd9Sstevel@tonic-gate int first, width; 495*7c478bd9Sstevel@tonic-gate 496*7c478bd9Sstevel@tonic-gate first = __m_cc_first(w, y, x); 497*7c478bd9Sstevel@tonic-gate width = __m_cc_width(&w->_line[y][x]); 498*7c478bd9Sstevel@tonic-gate 499*7c478bd9Sstevel@tonic-gate return first + width == x + 1; 500*7c478bd9Sstevel@tonic-gate } 501*7c478bd9Sstevel@tonic-gate 502*7c478bd9Sstevel@tonic-gate /* 503*7c478bd9Sstevel@tonic-gate * Replace the character at the current cursor location 504*7c478bd9Sstevel@tonic-gate * according to the column width of the character. The 505*7c478bd9Sstevel@tonic-gate * cursor does not advance. 506*7c478bd9Sstevel@tonic-gate * 507*7c478bd9Sstevel@tonic-gate * Return -1 if the character won't fit on the line and the background 508*7c478bd9Sstevel@tonic-gate * was written in its place; else return the width of the character in 509*7c478bd9Sstevel@tonic-gate * screen columns. 510*7c478bd9Sstevel@tonic-gate */ 511*7c478bd9Sstevel@tonic-gate int 512*7c478bd9Sstevel@tonic-gate __m_cc_replace(w, y, x, cc, as_is) 513*7c478bd9Sstevel@tonic-gate WINDOW *w; 514*7c478bd9Sstevel@tonic-gate int y, x; 515*7c478bd9Sstevel@tonic-gate const cchar_t *cc; 516*7c478bd9Sstevel@tonic-gate int as_is; 517*7c478bd9Sstevel@tonic-gate { 518*7c478bd9Sstevel@tonic-gate int i, width; 519*7c478bd9Sstevel@tonic-gate cchar_t *cp, *np; 520*7c478bd9Sstevel@tonic-gate 521*7c478bd9Sstevel@tonic-gate width = __m_cc_width(cc); 522*7c478bd9Sstevel@tonic-gate 523*7c478bd9Sstevel@tonic-gate /* If we try to write a broad character that would exceed the 524*7c478bd9Sstevel@tonic-gate * right margin, then write the background character instead. 525*7c478bd9Sstevel@tonic-gate */ 526*7c478bd9Sstevel@tonic-gate if (0 < width && w->_maxx < x + width) { 527*7c478bd9Sstevel@tonic-gate (void) __m_cc_erase(w, y, x, y, w->_maxx-1); 528*7c478bd9Sstevel@tonic-gate return -1; 529*7c478bd9Sstevel@tonic-gate } 530*7c478bd9Sstevel@tonic-gate 531*7c478bd9Sstevel@tonic-gate /* Erase the region to be occupied by the new character. 532*7c478bd9Sstevel@tonic-gate * __m_cc_erase() will erase whole characters so that 533*7c478bd9Sstevel@tonic-gate * writing a multicolumn character that overwrites the 534*7c478bd9Sstevel@tonic-gate * trailing and leading portions of two already existing 535*7c478bd9Sstevel@tonic-gate * multicolumn characters, erases the remaining portions. 536*7c478bd9Sstevel@tonic-gate */ 537*7c478bd9Sstevel@tonic-gate (void) __m_cc_erase(w, y, x, y, x + width - 1); 538*7c478bd9Sstevel@tonic-gate 539*7c478bd9Sstevel@tonic-gate /* Write the first column of the character. */ 540*7c478bd9Sstevel@tonic-gate cp = &w->_line[y][x++]; 541*7c478bd9Sstevel@tonic-gate if (cc->_wc[0] == ' ' || cc->_wc[0] == M_MB_L(' ')) { 542*7c478bd9Sstevel@tonic-gate *cp = w->_bg; 543*7c478bd9Sstevel@tonic-gate cp->_at |= cc->_at; 544*7c478bd9Sstevel@tonic-gate if (cc->_co != 0) 545*7c478bd9Sstevel@tonic-gate cp->_co = cc->_co; 546*7c478bd9Sstevel@tonic-gate } else { 547*7c478bd9Sstevel@tonic-gate (void) __m_wacs_cc(cc, cp); 548*7c478bd9Sstevel@tonic-gate if (cc->_co == 0) 549*7c478bd9Sstevel@tonic-gate cp->_co = w->_fg._co; 550*7c478bd9Sstevel@tonic-gate } 551*7c478bd9Sstevel@tonic-gate 552*7c478bd9Sstevel@tonic-gate cp->_at |= w->_fg._at | w->_bg._at; 553*7c478bd9Sstevel@tonic-gate 554*7c478bd9Sstevel@tonic-gate /* Mark this as the first column of the character. */ 555*7c478bd9Sstevel@tonic-gate cp->_f = 1; 556*7c478bd9Sstevel@tonic-gate 557*7c478bd9Sstevel@tonic-gate /* Duplicate the character in every column the character occupies. */ 558*7c478bd9Sstevel@tonic-gate for (np = cp + 1, i = 1; i < width; ++i, ++x, ++np) { 559*7c478bd9Sstevel@tonic-gate *np = *cp; 560*7c478bd9Sstevel@tonic-gate np->_f = 0; 561*7c478bd9Sstevel@tonic-gate } 562*7c478bd9Sstevel@tonic-gate 563*7c478bd9Sstevel@tonic-gate return width; 564*7c478bd9Sstevel@tonic-gate } 565*7c478bd9Sstevel@tonic-gate 566*7c478bd9Sstevel@tonic-gate int 567*7c478bd9Sstevel@tonic-gate __m_do_scroll(WINDOW *w, int y, int x, int *yp, int *xp) 568*7c478bd9Sstevel@tonic-gate { 569*7c478bd9Sstevel@tonic-gate if (w->_maxx <= x) 570*7c478bd9Sstevel@tonic-gate x = w->_maxx-1; 571*7c478bd9Sstevel@tonic-gate 572*7c478bd9Sstevel@tonic-gate ++y; 573*7c478bd9Sstevel@tonic-gate 574*7c478bd9Sstevel@tonic-gate if (y == w->_bottom) { 575*7c478bd9Sstevel@tonic-gate --y; 576*7c478bd9Sstevel@tonic-gate if (w->_flags & W_CAN_SCROLL) { 577*7c478bd9Sstevel@tonic-gate if (wscrl(w, 1) == ERR) 578*7c478bd9Sstevel@tonic-gate return ERR; 579*7c478bd9Sstevel@tonic-gate x = 0; 580*7c478bd9Sstevel@tonic-gate } 581*7c478bd9Sstevel@tonic-gate } else if (w->_maxy <= y) { 582*7c478bd9Sstevel@tonic-gate y = w->_maxy-1; 583*7c478bd9Sstevel@tonic-gate } else { 584*7c478bd9Sstevel@tonic-gate /* The cursor wraps for any line (in and out of the scroll 585*7c478bd9Sstevel@tonic-gate * region) except for the last line of the scroll region. 586*7c478bd9Sstevel@tonic-gate */ 587*7c478bd9Sstevel@tonic-gate x = 0; 588*7c478bd9Sstevel@tonic-gate } 589*7c478bd9Sstevel@tonic-gate 590*7c478bd9Sstevel@tonic-gate *yp = y; 591*7c478bd9Sstevel@tonic-gate *xp = x; 592*7c478bd9Sstevel@tonic-gate 593*7c478bd9Sstevel@tonic-gate return OK; 594*7c478bd9Sstevel@tonic-gate } 595*7c478bd9Sstevel@tonic-gate 596*7c478bd9Sstevel@tonic-gate /* 597*7c478bd9Sstevel@tonic-gate * Add the character at the current cursor location 598*7c478bd9Sstevel@tonic-gate * according to the column width of the character. 599*7c478bd9Sstevel@tonic-gate * The cursor will be advanced. 600*7c478bd9Sstevel@tonic-gate * 601*7c478bd9Sstevel@tonic-gate * Return ERR if adding the character causes the 602*7c478bd9Sstevel@tonic-gate * screen to scroll, when it is disallowed. 603*7c478bd9Sstevel@tonic-gate */ 604*7c478bd9Sstevel@tonic-gate int 605*7c478bd9Sstevel@tonic-gate __m_cc_add(w, y, x, cc, as_is, yp, xp) 606*7c478bd9Sstevel@tonic-gate WINDOW *w; 607*7c478bd9Sstevel@tonic-gate int y, x; 608*7c478bd9Sstevel@tonic-gate const cchar_t *cc; 609*7c478bd9Sstevel@tonic-gate int as_is, *yp, *xp; 610*7c478bd9Sstevel@tonic-gate { 611*7c478bd9Sstevel@tonic-gate int nx, width, code = ERR; 612*7c478bd9Sstevel@tonic-gate 613*7c478bd9Sstevel@tonic-gate #ifdef M_CURSES_TRACE 614*7c478bd9Sstevel@tonic-gate __m_trace( 615*7c478bd9Sstevel@tonic-gate "__m_cc_add(%p, %d, %d, %p, %d, %p, %p)", 616*7c478bd9Sstevel@tonic-gate w, y, x, cc, as_is, yp, xp 617*7c478bd9Sstevel@tonic-gate ); 618*7c478bd9Sstevel@tonic-gate #endif 619*7c478bd9Sstevel@tonic-gate 620*7c478bd9Sstevel@tonic-gate switch (cc->_wc[0]) { 621*7c478bd9Sstevel@tonic-gate case '\t': 622*7c478bd9Sstevel@tonic-gate nx = x + (8 - (x & 07)); 623*7c478bd9Sstevel@tonic-gate if (__m_cc_erase(w, y, x, y, nx-1) == -1) 624*7c478bd9Sstevel@tonic-gate goto error; 625*7c478bd9Sstevel@tonic-gate x = nx; 626*7c478bd9Sstevel@tonic-gate 627*7c478bd9Sstevel@tonic-gate if (w->_maxx <= x) { 628*7c478bd9Sstevel@tonic-gate if (__m_do_scroll(w, y, x, &y, &x) == ERR) 629*7c478bd9Sstevel@tonic-gate goto error; 630*7c478bd9Sstevel@tonic-gate } 631*7c478bd9Sstevel@tonic-gate break; 632*7c478bd9Sstevel@tonic-gate case '\n': 633*7c478bd9Sstevel@tonic-gate if (__m_cc_erase(w, y, x, y, w->_maxx-1) == -1) 634*7c478bd9Sstevel@tonic-gate goto error; 635*7c478bd9Sstevel@tonic-gate 636*7c478bd9Sstevel@tonic-gate if (__m_do_scroll(w, y, x, &y, &x) == ERR) 637*7c478bd9Sstevel@tonic-gate goto error; 638*7c478bd9Sstevel@tonic-gate break; 639*7c478bd9Sstevel@tonic-gate case '\r': 640*7c478bd9Sstevel@tonic-gate x = 0; 641*7c478bd9Sstevel@tonic-gate break; 642*7c478bd9Sstevel@tonic-gate case '\b': 643*7c478bd9Sstevel@tonic-gate if (0 < x) 644*7c478bd9Sstevel@tonic-gate --x; 645*7c478bd9Sstevel@tonic-gate break; 646*7c478bd9Sstevel@tonic-gate default: 647*7c478bd9Sstevel@tonic-gate width = __m_cc_replace(w, y, x, cc, as_is); 648*7c478bd9Sstevel@tonic-gate 649*7c478bd9Sstevel@tonic-gate x += width; 650*7c478bd9Sstevel@tonic-gate 651*7c478bd9Sstevel@tonic-gate if (width < 0 || w->_maxx <= x) { 652*7c478bd9Sstevel@tonic-gate if (__m_do_scroll(w, y, x, &y, &x) == ERR) 653*7c478bd9Sstevel@tonic-gate goto error; 654*7c478bd9Sstevel@tonic-gate 655*7c478bd9Sstevel@tonic-gate if (width < 0) 656*7c478bd9Sstevel@tonic-gate x += __m_cc_replace(w, y, x, cc, as_is); 657*7c478bd9Sstevel@tonic-gate } 658*7c478bd9Sstevel@tonic-gate } 659*7c478bd9Sstevel@tonic-gate 660*7c478bd9Sstevel@tonic-gate code = OK; 661*7c478bd9Sstevel@tonic-gate error: 662*7c478bd9Sstevel@tonic-gate *yp = y; 663*7c478bd9Sstevel@tonic-gate *xp = x; 664*7c478bd9Sstevel@tonic-gate 665*7c478bd9Sstevel@tonic-gate return __m_return_code("__m_cc_add", code); 666*7c478bd9Sstevel@tonic-gate } 667*7c478bd9Sstevel@tonic-gate 668*7c478bd9Sstevel@tonic-gate /* 669*7c478bd9Sstevel@tonic-gate * Erase region from (y,x) to (ly, lx) inclusive. The 670*7c478bd9Sstevel@tonic-gate * region is extended left and right in the case where 671*7c478bd9Sstevel@tonic-gate * the portions of a multicolumn characters are erased. 672*7c478bd9Sstevel@tonic-gate * 673*7c478bd9Sstevel@tonic-gate * Return -1 if the region is not an integral multiple 674*7c478bd9Sstevel@tonic-gate * of the background character, else zero for success. 675*7c478bd9Sstevel@tonic-gate */ 676*7c478bd9Sstevel@tonic-gate int 677*7c478bd9Sstevel@tonic-gate __m_cc_erase(w, y, x, ly, lx) 678*7c478bd9Sstevel@tonic-gate WINDOW *w; 679*7c478bd9Sstevel@tonic-gate int y, x, ly, lx; 680*7c478bd9Sstevel@tonic-gate { 681*7c478bd9Sstevel@tonic-gate cchar_t *cp; 682*7c478bd9Sstevel@tonic-gate int i, width; 683*7c478bd9Sstevel@tonic-gate 684*7c478bd9Sstevel@tonic-gate if (ly < y) 685*7c478bd9Sstevel@tonic-gate return -1; 686*7c478bd9Sstevel@tonic-gate 687*7c478bd9Sstevel@tonic-gate if (w->_maxy <= ly) 688*7c478bd9Sstevel@tonic-gate ly = w->_maxy - 1; 689*7c478bd9Sstevel@tonic-gate if (w->_maxx <= lx) 690*7c478bd9Sstevel@tonic-gate lx = w->_maxx - 1; 691*7c478bd9Sstevel@tonic-gate 692*7c478bd9Sstevel@tonic-gate /* Erase from first whole character (inclusive) to next 693*7c478bd9Sstevel@tonic-gate * character (exclusive). 694*7c478bd9Sstevel@tonic-gate */ 695*7c478bd9Sstevel@tonic-gate x = __m_cc_first(w, y, x); 696*7c478bd9Sstevel@tonic-gate lx = __m_cc_next(w, ly, lx) - 1; 697*7c478bd9Sstevel@tonic-gate 698*7c478bd9Sstevel@tonic-gate /* Is the region to blank out an integral width of the 699*7c478bd9Sstevel@tonic-gate * background character? 700*7c478bd9Sstevel@tonic-gate */ 701*7c478bd9Sstevel@tonic-gate width = __m_cc_width(&w->_bg); 702*7c478bd9Sstevel@tonic-gate 703*7c478bd9Sstevel@tonic-gate if (y < ly && (lx + 1) % width != 0) 704*7c478bd9Sstevel@tonic-gate return -1; 705*7c478bd9Sstevel@tonic-gate if ((lx - x + 1) % width != 0) 706*7c478bd9Sstevel@tonic-gate return -1; 707*7c478bd9Sstevel@tonic-gate 708*7c478bd9Sstevel@tonic-gate for (; y < ly; ++y, x = 0) { 709*7c478bd9Sstevel@tonic-gate if (x < w->_first[y]) 710*7c478bd9Sstevel@tonic-gate w->_first[y] = (short) x; 711*7c478bd9Sstevel@tonic-gate 712*7c478bd9Sstevel@tonic-gate for (cp = w->_line[y], i = 0; x < w->_maxx; ++x, ++i) { 713*7c478bd9Sstevel@tonic-gate cp[x] = w->_bg; 714*7c478bd9Sstevel@tonic-gate 715*7c478bd9Sstevel@tonic-gate /* The start of each new character will be set true 716*7c478bd9Sstevel@tonic-gate * while internal columns of the character will be 717*7c478bd9Sstevel@tonic-gate * reset to false. 718*7c478bd9Sstevel@tonic-gate */ 719*7c478bd9Sstevel@tonic-gate cp[x]._f = (short) (i % width == 0); 720*7c478bd9Sstevel@tonic-gate } 721*7c478bd9Sstevel@tonic-gate 722*7c478bd9Sstevel@tonic-gate if (w->_last[y] < x) 723*7c478bd9Sstevel@tonic-gate w->_last[y] = (short) x; 724*7c478bd9Sstevel@tonic-gate } 725*7c478bd9Sstevel@tonic-gate 726*7c478bd9Sstevel@tonic-gate if (x < w->_first[y]) 727*7c478bd9Sstevel@tonic-gate w->_first[y] = (short) x; 728*7c478bd9Sstevel@tonic-gate 729*7c478bd9Sstevel@tonic-gate for (cp = w->_line[y], i = 0; x <= lx; ++x, ++i) { 730*7c478bd9Sstevel@tonic-gate cp[x] = w->_bg; 731*7c478bd9Sstevel@tonic-gate 732*7c478bd9Sstevel@tonic-gate /* The start of each new character will be set true 733*7c478bd9Sstevel@tonic-gate * while internal columns of the character will be 734*7c478bd9Sstevel@tonic-gate * reset to false. 735*7c478bd9Sstevel@tonic-gate */ 736*7c478bd9Sstevel@tonic-gate cp[x]._f = (short) (i % width == 0); 737*7c478bd9Sstevel@tonic-gate } 738*7c478bd9Sstevel@tonic-gate 739*7c478bd9Sstevel@tonic-gate if (w->_last[y] < x) 740*7c478bd9Sstevel@tonic-gate w->_last[y] = (short) x; 741*7c478bd9Sstevel@tonic-gate 742*7c478bd9Sstevel@tonic-gate return 0; 743*7c478bd9Sstevel@tonic-gate } 744*7c478bd9Sstevel@tonic-gate 745*7c478bd9Sstevel@tonic-gate /* 746*7c478bd9Sstevel@tonic-gate * Expand the character to the left or right of the given position. 747*7c478bd9Sstevel@tonic-gate * Return the value returned by __m_cc_replace(). 748*7c478bd9Sstevel@tonic-gate */ 749*7c478bd9Sstevel@tonic-gate int 750*7c478bd9Sstevel@tonic-gate __m_cc_expand(w, y, x, side) 751*7c478bd9Sstevel@tonic-gate WINDOW *w; 752*7c478bd9Sstevel@tonic-gate int y, x, side; 753*7c478bd9Sstevel@tonic-gate { 754*7c478bd9Sstevel@tonic-gate cchar_t cc; 755*7c478bd9Sstevel@tonic-gate int dx, width; 756*7c478bd9Sstevel@tonic-gate 757*7c478bd9Sstevel@tonic-gate width = __m_cc_width(&w->_line[y][x]); 758*7c478bd9Sstevel@tonic-gate 759*7c478bd9Sstevel@tonic-gate if (side < 0) 760*7c478bd9Sstevel@tonic-gate dx = __m_cc_next(w, y, x) - width; 761*7c478bd9Sstevel@tonic-gate else if (0 < side) 762*7c478bd9Sstevel@tonic-gate dx = __m_cc_first(w, y, x); 763*7c478bd9Sstevel@tonic-gate else 764*7c478bd9Sstevel@tonic-gate return -1; 765*7c478bd9Sstevel@tonic-gate 766*7c478bd9Sstevel@tonic-gate /* __m_cc_replace() will erase the region containing 767*7c478bd9Sstevel@tonic-gate * the character we want to expand. 768*7c478bd9Sstevel@tonic-gate */ 769*7c478bd9Sstevel@tonic-gate cc = w->_line[y][x]; 770*7c478bd9Sstevel@tonic-gate 771*7c478bd9Sstevel@tonic-gate return __m_cc_replace(w, y, dx, &cc, 0); 772*7c478bd9Sstevel@tonic-gate } 773*7c478bd9Sstevel@tonic-gate 774*7c478bd9Sstevel@tonic-gate /* 775*7c478bd9Sstevel@tonic-gate * Return true if characters are equal. 776*7c478bd9Sstevel@tonic-gate * 777*7c478bd9Sstevel@tonic-gate * NOTE to guarantee correct results, make sure that both 778*7c478bd9Sstevel@tonic-gate * characters have been passed through __m_cc_sort(). 779*7c478bd9Sstevel@tonic-gate */ 780*7c478bd9Sstevel@tonic-gate int 781*7c478bd9Sstevel@tonic-gate __m_cc_compare(c1, c2, exact) 782*7c478bd9Sstevel@tonic-gate const cchar_t *c1, *c2; 783*7c478bd9Sstevel@tonic-gate int exact; 784*7c478bd9Sstevel@tonic-gate { 785*7c478bd9Sstevel@tonic-gate int i; 786*7c478bd9Sstevel@tonic-gate 787*7c478bd9Sstevel@tonic-gate if (exact && c1->_f != c2->_f) 788*7c478bd9Sstevel@tonic-gate return 0; 789*7c478bd9Sstevel@tonic-gate if (c1->_n != c2->_n) 790*7c478bd9Sstevel@tonic-gate return 0; 791*7c478bd9Sstevel@tonic-gate if ((c1->_at & ~WA_COOKIE) != (c2->_at & ~WA_COOKIE)) 792*7c478bd9Sstevel@tonic-gate return 0; 793*7c478bd9Sstevel@tonic-gate if (c1->_co != c2->_co) 794*7c478bd9Sstevel@tonic-gate return 0; 795*7c478bd9Sstevel@tonic-gate 796*7c478bd9Sstevel@tonic-gate for (i = 0; i < c1->_n; ++i) 797*7c478bd9Sstevel@tonic-gate if (c1->_wc[i] != c2->_wc[i]) 798*7c478bd9Sstevel@tonic-gate return 0; 799*7c478bd9Sstevel@tonic-gate 800*7c478bd9Sstevel@tonic-gate return 1; 801*7c478bd9Sstevel@tonic-gate } 802*7c478bd9Sstevel@tonic-gate 803*7c478bd9Sstevel@tonic-gate /* 804*7c478bd9Sstevel@tonic-gate * Write to the stream the character portion of a cchar_t. 805*7c478bd9Sstevel@tonic-gate */ 806*7c478bd9Sstevel@tonic-gate int 807*7c478bd9Sstevel@tonic-gate __m_cc_write(cc) 808*7c478bd9Sstevel@tonic-gate const cchar_t *cc; 809*7c478bd9Sstevel@tonic-gate { 810*7c478bd9Sstevel@tonic-gate size_t i, j; 811*7c478bd9Sstevel@tonic-gate char mb[MB_LEN_MAX]; 812*7c478bd9Sstevel@tonic-gate 813*7c478bd9Sstevel@tonic-gate errno = 0; 814*7c478bd9Sstevel@tonic-gate for (i = 0; i < cc->_n; ++i) { 815*7c478bd9Sstevel@tonic-gate j = wcrtomb(mb, cc->_wc[i], &__m_screen->_state); 816*7c478bd9Sstevel@tonic-gate if (errno != 0) 817*7c478bd9Sstevel@tonic-gate return EOF; 818*7c478bd9Sstevel@tonic-gate if (fwrite(mb, sizeof *mb, j, __m_screen->_of) == 0) 819*7c478bd9Sstevel@tonic-gate return EOF; 820*7c478bd9Sstevel@tonic-gate } 821*7c478bd9Sstevel@tonic-gate 822*7c478bd9Sstevel@tonic-gate return 0; 823*7c478bd9Sstevel@tonic-gate } 824