Home | History | Annotate | Line # | Download | only in libcurses
addbytes.c revision 1.50
      1 /*	$NetBSD: addbytes.c,v 1.50 2019/05/12 02:29:00 blymn Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1987, 1993, 1994
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. Neither the name of the University nor the names of its contributors
     16  *    may be used to endorse or promote products derived from this software
     17  *    without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29  * SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 #ifndef lint
     34 #if 0
     35 static char sccsid[] = "@(#)addbytes.c	8.4 (Berkeley) 5/4/94";
     36 #else
     37 __RCSID("$NetBSD: addbytes.c,v 1.50 2019/05/12 02:29:00 blymn Exp $");
     38 #endif
     39 #endif				/* not lint */
     40 
     41 #include <stdlib.h>
     42 #include <string.h>
     43 #include "curses.h"
     44 #include "curses_private.h"
     45 #ifdef DEBUG
     46 #include <assert.h>
     47 #endif
     48 
     49 #define	SYNCH_IN	{y = win->cury; x = win->curx;}
     50 #define	SYNCH_OUT	{win->cury = y; win->curx = x;}
     51 #define	PSYNCH_IN	{*y = win->cury; *x = win->curx;}
     52 #define	PSYNCH_OUT	{win->cury = *y; win->curx = *x;}
     53 
     54 #ifndef _CURSES_USE_MACROS
     55 
     56 /*
     57  * addbytes --
     58  *      Add the character to the current position in stdscr.
     59  */
     60 int
     61 addbytes(const char *bytes, int count)
     62 {
     63 
     64 	return _cursesi_waddbytes(stdscr, bytes, count, 0, 1);
     65 }
     66 
     67 /*
     68  * waddbytes --
     69  *      Add the character to the current position in the given window.
     70  */
     71 int
     72 waddbytes(WINDOW *win, const char *bytes, int count)
     73 {
     74 
     75 	return _cursesi_waddbytes(win, bytes, count, 0, 1);
     76 }
     77 
     78 /*
     79  * mvaddbytes --
     80  *      Add the characters to stdscr at the location given.
     81  */
     82 int
     83 mvaddbytes(int y, int x, const char *bytes, int count)
     84 {
     85 
     86 	return mvwaddbytes(stdscr, y, x, bytes, count);
     87 }
     88 
     89 /*
     90  * mvwaddbytes --
     91  *      Add the characters to the given window at the location given.
     92  */
     93 int
     94 mvwaddbytes(WINDOW *win, int y, int x, const char *bytes, int count)
     95 {
     96 
     97 	if (wmove(win, y, x) == ERR)
     98 		return ERR;
     99 
    100 	return _cursesi_waddbytes(win, bytes, count, 0, 1);
    101 }
    102 
    103 #endif
    104 
    105 int
    106 __waddbytes(WINDOW *win, const char *bytes, int count, attr_t attr)
    107 {
    108 
    109 	return _cursesi_waddbytes(win, bytes, count, attr, 1);
    110 }
    111 
    112 /*
    113  * _cursesi_waddbytes --
    114  *	Add the character to the current position in the given window.
    115  * if char_interp is non-zero then character interpretation is done on
    116  * the byte (i.e. \n to newline, \r to carriage return, \b to backspace
    117  * and so on).
    118  */
    119 int
    120 _cursesi_waddbytes(WINDOW *win, const char *bytes, int count, attr_t attr,
    121 	    int char_interp)
    122 {
    123 	int		x, y, err;
    124 	__LINE		*lp;
    125 #ifdef HAVE_WCHAR
    126 	int		n;
    127 	cchar_t		cc;
    128 	wchar_t		wc;
    129 	mbstate_t	st;
    130 #else
    131 	int		c;
    132 #endif
    133 #ifdef DEBUG
    134 	int             i;
    135 
    136 	for (i = 0; i < win->maxy; i++) {
    137 		assert(win->alines[i]->sentinel == SENTINEL_VALUE);
    138 	}
    139 
    140 	__CTRACE(__CTRACE_INPUT, "ADDBYTES: add %d bytes\n", count);
    141 #endif
    142 
    143 	err = OK;
    144 	SYNCH_IN;
    145 	lp = win->alines[y];
    146 
    147 #ifdef HAVE_WCHAR
    148 	(void)memset(&st, 0, sizeof(st));
    149 #endif
    150 	while (count > 0) {
    151 #ifndef HAVE_WCHAR
    152 		c = *bytes++;
    153 #ifdef DEBUG
    154 		__CTRACE(__CTRACE_INPUT, "ADDBYTES('%c', %x) at (%d, %d)\n",
    155 		    c, attr, y, x);
    156 #endif
    157 		err = _cursesi_addbyte(win, &lp, &y, &x, c, attr, char_interp);
    158 		count--;
    159 #else
    160 		/*
    161 		 * For wide-character support only, try and convert the
    162 		 * given string into a wide character - we do this because
    163 		 * this is how ncurses behaves (not that I think this is
    164 		 * actually the correct thing to do but if we don't do it
    165 		 * a lot of things that rely on this behaviour will break
    166 		 * and we will be blamed).  If the conversion succeeds
    167 		 * then we eat the n characters used to make the wide char
    168 		 * from the string.
    169 		 */
    170 		n = (int)mbrtowc(&wc, bytes, (size_t)count, &st);
    171 		if (n < 0) {
    172 			/* not a valid conversion just eat a char */
    173 			wc = *bytes;
    174 			n = 1;
    175 			(void)memset(&st, 0, sizeof(st));
    176 		} else if (wc == 0) {
    177 			break;
    178 		}
    179 #ifdef DEBUG
    180 	__CTRACE(__CTRACE_INPUT,
    181 		 "ADDBYTES WIDE(0x%x [%s], %x) at (%d, %d), ate %d bytes\n",
    182 		 (unsigned)wc, unctrl((unsigned)wc), attr, y, x, n);
    183 #endif
    184 		cc.vals[0] = wc;
    185 		cc.elements = 1;
    186 		cc.attributes = attr;
    187 		err = _cursesi_addwchar(win, &lp, &y, &x, &cc, char_interp);
    188 		bytes += n;
    189 		count -= n;
    190 #endif
    191 	}
    192 
    193 	SYNCH_OUT;
    194 
    195 #ifdef DEBUG
    196 	for (i = 0; i < win->maxy; i++) {
    197 		assert(win->alines[i]->sentinel == SENTINEL_VALUE);
    198 	}
    199 #endif
    200 
    201 	return (err);
    202 }
    203 
    204 /*
    205  * _cursesi_addbyte -
    206  *	Internal function to add a byte and update the row and column
    207  * positions as appropriate.  If char_interp is non-zero then
    208  * character interpretation is done on the byte.  This function is
    209  * only used in the narrow character version of curses.
    210  */
    211 int
    212 _cursesi_addbyte(WINDOW *win, __LINE **lp, int *y, int *x, int c,
    213 		 attr_t attr, int char_interp)
    214 {
    215 	static char	 blank[] = " ";
    216 	int		 tabsize;
    217 	int		 newx, i;
    218 	attr_t		 attributes;
    219 
    220 	if (char_interp) {
    221 		switch (c) {
    222 		case '\t':
    223 			tabsize = win->screen->TABSIZE;
    224 			PSYNCH_OUT;
    225 			newx = tabsize - (*x % tabsize);
    226 			for (i = 0; i < newx; i++) {
    227 				if (waddbytes(win, blank, 1) == ERR)
    228 					return ERR;
    229 				(*x)++;
    230 			}
    231 			PSYNCH_IN;
    232 			return OK;
    233 
    234 		case '\n':
    235 			PSYNCH_OUT;
    236 			wclrtoeol(win);
    237 			PSYNCH_IN;
    238 			(*lp)->flags |= __ISPASTEOL;
    239 			break;
    240 
    241 		case '\r':
    242 			*x = 0;
    243 			win->curx = *x;
    244 			return OK;
    245 
    246 		case '\b':
    247 			if (--(*x) < 0)
    248 				*x = 0;
    249 			win->curx = *x;
    250 			return OK;
    251 		}
    252 	}
    253 
    254 #ifdef DEBUG
    255 	__CTRACE(__CTRACE_INPUT, "ADDBYTES(%p, %d, %d)\n", win, *y, *x);
    256 #endif
    257 
    258 	if (char_interp && ((*lp)->flags & __ISPASTEOL)) {
    259 		*x = 0;
    260 		(*lp)->flags &= ~__ISPASTEOL;
    261 		if (*y == win->scr_b) {
    262 #ifdef DEBUG
    263 			__CTRACE(__CTRACE_INPUT,
    264 				 "ADDBYTES - on bottom "
    265 				 "of scrolling region\n");
    266 #endif
    267 			if (!(win->flags & __SCROLLOK))
    268 				return ERR;
    269 			PSYNCH_OUT;
    270 			scroll(win);
    271 			PSYNCH_IN;
    272 		} else {
    273 			(*y)++;
    274 		}
    275 		*lp = win->alines[*y];
    276 		if (c == '\n')
    277 			return OK;
    278 	}
    279 
    280 #ifdef DEBUG
    281 	__CTRACE(__CTRACE_INPUT,
    282 		 "ADDBYTES: 1: y = %d, x = %d, firstch = %d, lastch = %d\n",
    283 		 *y, *x, *win->alines[*y]->firstchp,
    284 		 *win->alines[*y]->lastchp);
    285 #endif
    286 
    287 	attributes = (win->wattr | attr) & (__ATTRIBUTES & ~__COLOR);
    288 	if (attr & __COLOR)
    289 		attributes |= attr & __COLOR;
    290 	else if (win->wattr & __COLOR)
    291 		attributes |= win->wattr & __COLOR;
    292 
    293 	/*
    294 	 * Always update the change pointers.  Otherwise,
    295 	 * we could end up not displaying 'blank' characters
    296 	 * when overlapping windows are displayed.
    297 	 */
    298 	newx = *x + win->ch_off;
    299 	(*lp)->flags |= __ISDIRTY;
    300 	/*
    301 	 * firstchp/lastchp are shared between
    302 	 * parent window and sub-window.
    303 	 */
    304 	if (newx < *(*lp)->firstchp)
    305 		*(*lp)->firstchp = newx;
    306 	if (newx > *(*lp)->lastchp)
    307 		*(*lp)->lastchp = newx;
    308 #ifdef DEBUG
    309 	__CTRACE(__CTRACE_INPUT, "ADDBYTES: change gives f/l: %d/%d [%d/%d]\n",
    310 		 *(*lp)->firstchp, *(*lp)->lastchp,
    311 		 *(*lp)->firstchp - win->ch_off,
    312 		 *(*lp)->lastchp - win->ch_off);
    313 #endif
    314 	if (win->bch != ' ' && c == ' ')
    315 		(*lp)->line[*x].ch = win->bch;
    316 	else
    317 		(*lp)->line[*x].ch = c;
    318 
    319 	if (attributes & __COLOR)
    320 		(*lp)->line[*x].attr =
    321 			attributes | (win->battr & ~__COLOR);
    322 	else
    323 		(*lp)->line[*x].attr = attributes | win->battr;
    324 
    325 	if (*x == win->maxx - 1)
    326 		(*lp)->flags |= __ISPASTEOL;
    327 	else
    328 		(*x)++;
    329 
    330 #ifdef DEBUG
    331 	__CTRACE(__CTRACE_INPUT,
    332 		 "ADDBYTES: 2: y = %d, x = %d, firstch = %d, lastch = %d\n",
    333 		 *y, *x, *win->alines[*y]->firstchp,
    334 		 *win->alines[*y]->lastchp);
    335 #endif
    336 	__sync(win);
    337 	return OK;
    338 }
    339 
    340 /*
    341  * _cursesi_addwchar -
    342  *	Internal function to add a wide character and update the row
    343  * and column positions.
    344  */
    345 int
    346 _cursesi_addwchar(WINDOW *win, __LINE **lnp, int *y, int *x,
    347 		  const cchar_t *wch, int char_interp)
    348 {
    349 #ifndef HAVE_WCHAR
    350 	return ERR;
    351 #else
    352 	int sx = 0, ex = 0, cw = 0, i = 0, newx = 0, tabsize;
    353 	__LDATA *lp = &win->alines[*y]->line[*x], *tp = NULL;
    354 	nschar_t *np = NULL;
    355 	cchar_t cc;
    356 	attr_t attributes;
    357 
    358 	if (char_interp) {
    359 		/* special characters handling */
    360 		switch (wch->vals[0]) {
    361 		case L'\b':
    362 			if (--*x < 0)
    363 				*x = 0;
    364 			win->curx = *x;
    365 			return OK;
    366 		case L'\r':
    367 			*x = 0;
    368 			win->curx = *x;
    369 			return OK;
    370 		case L'\n':
    371 			wclrtoeol(win);
    372 			PSYNCH_IN;
    373 			*x = 0;
    374 			(*lnp)->flags &= ~__ISPASTEOL;
    375 			if (*y == win->scr_b) {
    376 				if (!(win->flags & __SCROLLOK))
    377 					return ERR;
    378 				PSYNCH_OUT;
    379 				scroll(win);
    380 				PSYNCH_IN;
    381 			} else {
    382 				(*y)++;
    383 			}
    384 			PSYNCH_OUT;
    385 			return OK;
    386 		case L'\t':
    387 			cc.vals[0] = L' ';
    388 			cc.elements = 1;
    389 			cc.attributes = win->wattr;
    390 			tabsize = win->screen->TABSIZE;
    391 			newx = tabsize - (*x % tabsize);
    392 			for (i = 0; i < newx; i++) {
    393 				if (wadd_wch(win, &cc) == ERR)
    394 					return ERR;
    395 				(*x)++;
    396 			}
    397 			return OK;
    398 		}
    399 	}
    400 
    401 	/* check for non-spacing character */
    402 	if (!wcwidth(wch->vals[0])) {
    403 #ifdef DEBUG
    404 		__CTRACE(__CTRACE_INPUT,
    405 			 "_cursesi_addwchar: char '%c' is non-spacing\n",
    406 			 wch->vals[0]);
    407 #endif /* DEBUG */
    408 		cw = WCOL(*lp);
    409 		if (cw < 0) {
    410 			lp += cw;
    411 			*x += cw;
    412 		}
    413 		for (i = 0; i < wch->elements; i++) {
    414 			if (!(np = (nschar_t *) malloc(sizeof(nschar_t))))
    415 				return ERR;;
    416 			np->ch = wch->vals[i];
    417 			np->next = lp->nsp;
    418 			lp->nsp = np;
    419 		}
    420 		(*lnp)->flags |= __ISDIRTY;
    421 		newx = *x + win->ch_off;
    422 		if (newx < *(*lnp)->firstchp)
    423 			*(*lnp)->firstchp = newx;
    424 		if (newx > *(*lnp)->lastchp)
    425 			*(*lnp)->lastchp = newx;
    426 		__touchline(win, *y, *x, *x);
    427 		return OK;
    428 	}
    429 	/* check for new line first */
    430 	if (char_interp && ((*lnp)->flags & __ISPASTEOL)) {
    431 		*x = 0;
    432 		(*lnp)->flags &= ~__ISPASTEOL;
    433 		if (*y == win->scr_b) {
    434 			if (!(win->flags & __SCROLLOK))
    435 				return ERR;
    436 			PSYNCH_OUT;
    437 			scroll(win);
    438 			PSYNCH_IN;
    439 		} else {
    440 			(*y)++;
    441 		}
    442 		(*lnp) = win->alines[*y];
    443 		lp = &win->alines[*y]->line[*x];
    444 	}
    445 	/* clear out the current character */
    446 	cw = WCOL(*lp);
    447 	if (cw >= 0) {
    448 		sx = *x;
    449 	} else {
    450 		for (sx = *x - 1; sx >= max(*x + cw, 0); sx--) {
    451 #ifdef DEBUG
    452 			__CTRACE(__CTRACE_INPUT,
    453 				 "_cursesi_addwchar: clear current char (%d,%d)\n",
    454 				 *y, sx);
    455 #endif /* DEBUG */
    456 			tp = &win->alines[*y]->line[sx];
    457 			tp->ch = (wchar_t) btowc((int) win->bch);
    458 			if (_cursesi_copy_nsp(win->bnsp, tp) == ERR)
    459 				return ERR;
    460 
    461 			tp->attr = win->battr;
    462 			SET_WCOL(*tp, 1);
    463 		}
    464 		sx = *x + cw;
    465 		(*lnp)->flags |= __ISDIRTY;
    466 		newx = sx + win->ch_off;
    467 		if (newx < *(*lnp)->firstchp)
    468 			*(*lnp)->firstchp = newx;
    469 	}
    470 
    471 	/* check for enough space before the end of line */
    472 	cw = wcwidth(wch->vals[0]);
    473 	if (cw < 0)
    474 		cw = 1;
    475 
    476 	if (cw > win->maxx - *x) {
    477 #ifdef DEBUG
    478 		__CTRACE(__CTRACE_INPUT,
    479 			 "_cursesi_addwchar: clear EOL (%d,%d)\n",
    480 			 *y, *x);
    481 #endif /* DEBUG */
    482 		(*lnp)->flags |= __ISDIRTY;
    483 		newx = *x + win->ch_off;
    484 		if (newx < *(*lnp)->firstchp)
    485 			*(*lnp)->firstchp = newx;
    486 		for (tp = lp; *x < win->maxx; tp++, (*x)++) {
    487 			tp->ch = (wchar_t) btowc((int) win->bch);
    488 			if (_cursesi_copy_nsp(win->bnsp, tp) == ERR)
    489 				return ERR;
    490 			tp->attr = win->battr;
    491 			SET_WCOL(*tp, 1);
    492 		}
    493 		newx = win->maxx - 1 + win->ch_off;
    494 		if (newx > *(*lnp)->lastchp)
    495 			*(*lnp)->lastchp = newx;
    496 		__touchline(win, *y, sx, (int) win->maxx - 1);
    497 		sx = *x = 0;
    498 		if (*y == win->scr_b) {
    499 			if (!(win->flags & __SCROLLOK))
    500 				return ERR;
    501 			PSYNCH_OUT;
    502 			scroll(win);
    503 			PSYNCH_IN;
    504 		} else {
    505 			(*y)++;
    506 		}
    507 		lp = &win->alines[*y]->line[0];
    508 		(*lnp) = win->alines[*y];
    509 	}
    510 	win->cury = *y;
    511 
    512 	/* add spacing character */
    513 #ifdef DEBUG
    514 	__CTRACE(__CTRACE_INPUT,
    515 		 "_cursesi_addwchar: add character (%d,%d) 0x%x\n",
    516 		 *y, *x, wch->vals[0]);
    517 #endif /* DEBUG */
    518 	(*lnp)->flags |= __ISDIRTY;
    519 	newx = *x + win->ch_off;
    520 	if (newx < *(*lnp)->firstchp)
    521 		*(*lnp)->firstchp = newx;
    522 	if (lp->nsp) {
    523 		__cursesi_free_nsp(lp->nsp);
    524 		lp->nsp = NULL;
    525 	}
    526 
    527 	lp->ch = wch->vals[0];
    528 
    529 	attributes = (win->wattr | wch->attributes)
    530 		& (WA_ATTRIBUTES & ~__COLOR);
    531 	if (wch->attributes & __COLOR)
    532 		attributes |= wch->attributes & __COLOR;
    533 	else if (win->wattr & __COLOR)
    534 		attributes |= win->wattr & __COLOR;
    535 	if (attributes & __COLOR)
    536 		lp->attr = attributes | (win->battr & ~__COLOR);
    537 	else
    538 		lp->attr = attributes | win->battr;
    539 
    540 	SET_WCOL(*lp, cw);
    541 
    542 #ifdef DEBUG
    543 	__CTRACE(__CTRACE_INPUT,
    544 		 "_cursesi_addwchar: add spacing char 0x%x, attr 0x%x\n",
    545 		 lp->ch, lp->attr);
    546 #endif /* DEBUG */
    547 
    548 	if (wch->elements > 1) {
    549 		for (i = 1; i < wch->elements; i++) {
    550 			np = malloc(sizeof(nschar_t));
    551 			if (!np)
    552 				return ERR;;
    553 			np->ch = wch->vals[i];
    554 			np->next = lp->nsp;
    555 #ifdef DEBUG
    556 			__CTRACE(__CTRACE_INPUT,
    557 			    "_cursesi_addwchar: add non-spacing char 0x%x\n", np->ch);
    558 #endif /* DEBUG */
    559 			lp->nsp = np;
    560 		}
    561 	}
    562 #ifdef DEBUG
    563 	__CTRACE(__CTRACE_INPUT, "_cursesi_addwchar: non-spacing list header: %p\n",
    564 	    lp->nsp);
    565 	__CTRACE(__CTRACE_INPUT, "_cursesi_addwchar: add rest columns (%d:%d)\n",
    566 		sx + 1, sx + cw - 1);
    567 	__CTRACE(__CTRACE_INPUT, "_cursesi_addwchar: *x = %d, win->maxx = %d\n", *x, win->maxx);
    568 #endif /* DEBUG */
    569 	for (tp = lp + 1, *x = sx + 1; *x - sx <= cw - 1; tp++, (*x)++) {
    570 		if (tp->nsp) {
    571 			__cursesi_free_nsp(tp->nsp);
    572 			tp->nsp = NULL;
    573 		}
    574 		tp->ch = wch->vals[0];
    575 		tp->attr = lp->attr & WA_ATTRIBUTES;
    576 		/* Mark as "continuation" cell */
    577 		tp->attr |= __WCWIDTH;
    578 	}
    579 
    580 	if (*x == win->maxx) {
    581 #ifdef DEBUG
    582 	__CTRACE(__CTRACE_INPUT, "_cursesi_addwchar: do line wrap\n");
    583 #endif /* DEBUG */
    584 		newx = win->maxx - 1 + win->ch_off;
    585 		if (newx > *(*lnp)->lastchp)
    586 			*(*lnp)->lastchp = newx;
    587 		__touchline(win, *y, sx, (int) win->maxx - 1);
    588 		*x = sx = 0;
    589 		if (*y == win->scr_b) {
    590 			if (!(win->flags & __SCROLLOK))
    591 				return ERR;
    592 			PSYNCH_OUT;
    593 			scroll(win);
    594 			PSYNCH_IN;
    595 		} else {
    596 			(*y)++;
    597 		}
    598 		lp = &win->alines[*y]->line[0];
    599 		(*lnp) = win->alines[*y];
    600 		win->curx = *x;
    601 		win->cury = *y;
    602 	} else {
    603 		win->curx = *x;
    604 
    605 		/* clear the remining of the current characer */
    606 		if (*x && *x < win->maxx) {
    607 			ex = sx + cw;
    608 			tp = &win->alines[*y]->line[ex];
    609 			while (ex < win->maxx && WCOL(*tp) < 0) {
    610 #ifdef DEBUG
    611 				__CTRACE(__CTRACE_INPUT,
    612 				    "_cursesi_addwchar: clear "
    613 				    "remaining of current char (%d,%d)nn",
    614 				    *y, ex);
    615 #endif /* DEBUG */
    616 				tp->ch = (wchar_t) btowc((int) win->bch);
    617 				if (_cursesi_copy_nsp(win->bnsp, tp) == ERR)
    618 					return ERR;
    619 				tp->attr = win->battr;
    620 				SET_WCOL(*tp, 1);
    621 				tp++, ex++;
    622 			}
    623 			newx = ex - 1 + win->ch_off;
    624 			if (newx > *(*lnp)->lastchp)
    625 				*(*lnp)->lastchp = newx;
    626 			__touchline(win, *y, sx, ex - 1);
    627 		}
    628 	}
    629 
    630 #ifdef DEBUG
    631 	__CTRACE(__CTRACE_INPUT, "_cursesi_addwchar: %d : 0x%x\n", lp->ch, lp->attr);
    632 	__CTRACE(__CTRACE_INPUT, "_cursesi_addwchar: *x = %d, *y = %d, win->maxx = %d\n", *x, *y, win->maxx);
    633 #endif /* DEBUG */
    634 	__sync(win);
    635 	return OK;
    636 #endif
    637 }
    638