xref: /minix3/lib/libcurses/addbytes.c (revision 84d9c625bfea59e274550651111ae9edfdc40fbd)
1*84d9c625SLionel Sambuc /*	$NetBSD: addbytes.c,v 1.42 2013/11/10 03:14:16 christos Exp $	*/
251ffecc1SBen Gras 
351ffecc1SBen Gras /*
451ffecc1SBen Gras  * Copyright (c) 1987, 1993, 1994
551ffecc1SBen Gras  *	The Regents of the University of California.  All rights reserved.
651ffecc1SBen Gras  *
751ffecc1SBen Gras  * Redistribution and use in source and binary forms, with or without
851ffecc1SBen Gras  * modification, are permitted provided that the following conditions
951ffecc1SBen Gras  * are met:
1051ffecc1SBen Gras  * 1. Redistributions of source code must retain the above copyright
1151ffecc1SBen Gras  *    notice, this list of conditions and the following disclaimer.
1251ffecc1SBen Gras  * 2. Redistributions in binary form must reproduce the above copyright
1351ffecc1SBen Gras  *    notice, this list of conditions and the following disclaimer in the
1451ffecc1SBen Gras  *    documentation and/or other materials provided with the distribution.
1551ffecc1SBen Gras  * 3. Neither the name of the University nor the names of its contributors
1651ffecc1SBen Gras  *    may be used to endorse or promote products derived from this software
1751ffecc1SBen Gras  *    without specific prior written permission.
1851ffecc1SBen Gras  *
1951ffecc1SBen Gras  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2051ffecc1SBen Gras  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2151ffecc1SBen Gras  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2251ffecc1SBen Gras  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2351ffecc1SBen Gras  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2451ffecc1SBen Gras  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2551ffecc1SBen Gras  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2651ffecc1SBen Gras  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2751ffecc1SBen Gras  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2851ffecc1SBen Gras  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2951ffecc1SBen Gras  * SUCH DAMAGE.
3051ffecc1SBen Gras  */
3151ffecc1SBen Gras 
3251ffecc1SBen Gras #include <sys/cdefs.h>
3351ffecc1SBen Gras #ifndef lint
3451ffecc1SBen Gras #if 0
3551ffecc1SBen Gras static char sccsid[] = "@(#)addbytes.c	8.4 (Berkeley) 5/4/94";
3651ffecc1SBen Gras #else
37*84d9c625SLionel Sambuc __RCSID("$NetBSD: addbytes.c,v 1.42 2013/11/10 03:14:16 christos Exp $");
3851ffecc1SBen Gras #endif
3951ffecc1SBen Gras #endif				/* not lint */
4051ffecc1SBen Gras 
4151ffecc1SBen Gras #include <stdlib.h>
4251ffecc1SBen Gras #include <string.h>
4351ffecc1SBen Gras #include "curses.h"
4451ffecc1SBen Gras #include "curses_private.h"
4551ffecc1SBen Gras #ifdef DEBUG
4651ffecc1SBen Gras #include <assert.h>
4751ffecc1SBen Gras #endif
4851ffecc1SBen Gras 
4951ffecc1SBen Gras #define	SYNCH_IN	{y = win->cury; x = win->curx;}
5051ffecc1SBen Gras #define	SYNCH_OUT	{win->cury = y; win->curx = x;}
5151ffecc1SBen Gras #define	PSYNCH_IN	{*y = win->cury; *x = win->curx;}
5251ffecc1SBen Gras #define	PSYNCH_OUT	{win->cury = *y; win->curx = *x;}
5351ffecc1SBen Gras 
5451ffecc1SBen Gras #ifndef _CURSES_USE_MACROS
5551ffecc1SBen Gras 
5651ffecc1SBen Gras /*
5751ffecc1SBen Gras  * addbytes --
5851ffecc1SBen Gras  *      Add the character to the current position in stdscr.
5951ffecc1SBen Gras  */
6051ffecc1SBen Gras int
addbytes(const char * bytes,int count)6151ffecc1SBen Gras addbytes(const char *bytes, int count)
6251ffecc1SBen Gras {
63*84d9c625SLionel Sambuc 	return _cursesi_waddbytes(stdscr, bytes, count, 0, 1);
6451ffecc1SBen Gras }
6551ffecc1SBen Gras 
6651ffecc1SBen Gras /*
6751ffecc1SBen Gras  * waddbytes --
6851ffecc1SBen Gras  *      Add the character to the current position in the given window.
6951ffecc1SBen Gras  */
7051ffecc1SBen Gras int
waddbytes(WINDOW * win,const char * bytes,int count)7151ffecc1SBen Gras waddbytes(WINDOW *win, const char *bytes, int count)
7251ffecc1SBen Gras {
73*84d9c625SLionel Sambuc 	return _cursesi_waddbytes(win, bytes, count, 0, 1);
7451ffecc1SBen Gras }
7551ffecc1SBen Gras 
7651ffecc1SBen Gras /*
7751ffecc1SBen Gras  * mvaddbytes --
7851ffecc1SBen Gras  *      Add the characters to stdscr at the location given.
7951ffecc1SBen Gras  */
8051ffecc1SBen Gras int
mvaddbytes(int y,int x,const char * bytes,int count)8151ffecc1SBen Gras mvaddbytes(int y, int x, const char *bytes, int count)
8251ffecc1SBen Gras {
8351ffecc1SBen Gras 	return mvwaddbytes(stdscr, y, x, bytes, count);
8451ffecc1SBen Gras }
8551ffecc1SBen Gras 
8651ffecc1SBen Gras /*
8751ffecc1SBen Gras  * mvwaddbytes --
8851ffecc1SBen Gras  *      Add the characters to the given window at the location given.
8951ffecc1SBen Gras  */
9051ffecc1SBen Gras int
mvwaddbytes(WINDOW * win,int y,int x,const char * bytes,int count)9151ffecc1SBen Gras mvwaddbytes(WINDOW *win, int y, int x, const char *bytes, int count)
9251ffecc1SBen Gras {
9351ffecc1SBen Gras 	if (wmove(win, y, x) == ERR)
9451ffecc1SBen Gras 		return ERR;
9551ffecc1SBen Gras 
96*84d9c625SLionel Sambuc 	return _cursesi_waddbytes(win, bytes, count, 0, 1);
9751ffecc1SBen Gras }
9851ffecc1SBen Gras 
9951ffecc1SBen Gras #endif
10051ffecc1SBen Gras 
10151ffecc1SBen Gras int
__waddbytes(WINDOW * win,const char * bytes,int count,attr_t attr)10251ffecc1SBen Gras __waddbytes(WINDOW *win, const char *bytes, int count, attr_t attr)
10351ffecc1SBen Gras {
104*84d9c625SLionel Sambuc 	return _cursesi_waddbytes(win, bytes, count, attr, 1);
105*84d9c625SLionel Sambuc }
106*84d9c625SLionel Sambuc 
107*84d9c625SLionel Sambuc /*
108*84d9c625SLionel Sambuc  * _cursesi_waddbytes --
109*84d9c625SLionel Sambuc  *	Add the character to the current position in the given window.
110*84d9c625SLionel Sambuc  * if char_interp is non-zero then character interpretation is done on
111*84d9c625SLionel Sambuc  * the byte (i.e. \n to newline, \r to carriage return, \b to backspace
112*84d9c625SLionel Sambuc  * and so on).
113*84d9c625SLionel Sambuc  */
114*84d9c625SLionel Sambuc int
_cursesi_waddbytes(WINDOW * win,const char * bytes,int count,attr_t attr,int char_interp)115*84d9c625SLionel Sambuc _cursesi_waddbytes(WINDOW *win, const char *bytes, int count, attr_t attr,
116*84d9c625SLionel Sambuc 	    int char_interp)
117*84d9c625SLionel Sambuc {
11851ffecc1SBen Gras 	int		x, y, err;
11951ffecc1SBen Gras 	__LINE		*lp;
12051ffecc1SBen Gras #ifdef HAVE_WCHAR
12151ffecc1SBen Gras 	int		n;
12251ffecc1SBen Gras 	cchar_t		cc;
12351ffecc1SBen Gras 	wchar_t		wc;
12451ffecc1SBen Gras 	mbstate_t	st;
12551ffecc1SBen Gras #else
12651ffecc1SBen Gras 	int		c;
12751ffecc1SBen Gras #endif
12851ffecc1SBen Gras #ifdef DEBUG
12951ffecc1SBen Gras 	int             i;
13051ffecc1SBen Gras 
13151ffecc1SBen Gras 	for (i = 0; i < win->maxy; i++) {
13251ffecc1SBen Gras 		assert(win->alines[i]->sentinel == SENTINEL_VALUE);
13351ffecc1SBen Gras 	}
13451ffecc1SBen Gras 
13551ffecc1SBen Gras 	__CTRACE(__CTRACE_INPUT, "ADDBYTES: add %d bytes\n", count);
13651ffecc1SBen Gras #endif
13751ffecc1SBen Gras 
13851ffecc1SBen Gras 	err = OK;
13951ffecc1SBen Gras 	SYNCH_IN;
14051ffecc1SBen Gras 	lp = win->alines[y];
14151ffecc1SBen Gras 
14251ffecc1SBen Gras #ifdef HAVE_WCHAR
14351ffecc1SBen Gras 	(void)memset(&st, 0, sizeof(st));
14451ffecc1SBen Gras #endif
14551ffecc1SBen Gras 	while (count > 0) {
14651ffecc1SBen Gras #ifndef HAVE_WCHAR
14751ffecc1SBen Gras 		c = *bytes++;
14851ffecc1SBen Gras #ifdef DEBUG
14951ffecc1SBen Gras 		__CTRACE(__CTRACE_INPUT, "ADDBYTES('%c', %x) at (%d, %d)\n",
15051ffecc1SBen Gras 		    c, attr, y, x);
15151ffecc1SBen Gras #endif
152*84d9c625SLionel Sambuc 		err = _cursesi_addbyte(win, &lp, &y, &x, c, attr, char_interp);
15351ffecc1SBen Gras 		count--;
15451ffecc1SBen Gras #else
15551ffecc1SBen Gras 		/*
15651ffecc1SBen Gras 		 * For wide-character support only, try and convert the
15751ffecc1SBen Gras 		 * given string into a wide character - we do this because
15851ffecc1SBen Gras 		 * this is how ncurses behaves (not that I think this is
15951ffecc1SBen Gras 		 * actually the correct thing to do but if we don't do it
16051ffecc1SBen Gras 		 * a lot of things that rely on this behaviour will break
16151ffecc1SBen Gras 		 * and we will be blamed).  If the conversion succeeds
16251ffecc1SBen Gras 		 * then we eat the n characters used to make the wide char
16351ffecc1SBen Gras 		 * from the string.
16451ffecc1SBen Gras 		 */
16551ffecc1SBen Gras 		n = (int)mbrtowc(&wc, bytes, (size_t)count, &st);
16651ffecc1SBen Gras 		if (n < 0) {
16751ffecc1SBen Gras 			/* not a valid conversion just eat a char */
16851ffecc1SBen Gras 			wc = *bytes;
16951ffecc1SBen Gras 			n = 1;
170ee8602a4SBen Gras 			(void)memset(&st, 0, sizeof(st));
17151ffecc1SBen Gras 		} else if (wc == 0) {
17251ffecc1SBen Gras 			break;
17351ffecc1SBen Gras 		}
17451ffecc1SBen Gras #ifdef DEBUG
17551ffecc1SBen Gras 	__CTRACE(__CTRACE_INPUT,
17651ffecc1SBen Gras 		 "ADDBYTES WIDE(0x%x [%s], %x) at (%d, %d), ate %d bytes\n",
17751ffecc1SBen Gras 		 (unsigned) wc, unctrl((unsigned) wc), attr, y, x, n);
17851ffecc1SBen Gras #endif
17951ffecc1SBen Gras 		cc.vals[0] = wc;
18051ffecc1SBen Gras 		cc.elements = 1;
18151ffecc1SBen Gras 		cc.attributes = attr;
182*84d9c625SLionel Sambuc 		err = _cursesi_addwchar(win, &lp, &y, &x, &cc, char_interp);
18351ffecc1SBen Gras 		bytes += n;
18451ffecc1SBen Gras 		count -= n;
18551ffecc1SBen Gras #endif
18651ffecc1SBen Gras 	}
18751ffecc1SBen Gras 
18851ffecc1SBen Gras 	SYNCH_OUT;
18951ffecc1SBen Gras 
19051ffecc1SBen Gras #ifdef DEBUG
19151ffecc1SBen Gras 	for (i = 0; i < win->maxy; i++) {
19251ffecc1SBen Gras 		assert(win->alines[i]->sentinel == SENTINEL_VALUE);
19351ffecc1SBen Gras 	}
19451ffecc1SBen Gras #endif
19551ffecc1SBen Gras 
19651ffecc1SBen Gras 	return (err);
19751ffecc1SBen Gras }
19851ffecc1SBen Gras 
19951ffecc1SBen Gras /*
20051ffecc1SBen Gras  * _cursesi_addbyte -
20151ffecc1SBen Gras  *	Internal function to add a byte and update the row and column
20251ffecc1SBen Gras  * positions as appropriate.  This function is only used in the narrow
203*84d9c625SLionel Sambuc  * character version of curses.  If update_cursor is non-zero then character
204*84d9c625SLionel Sambuc  * interpretation.
20551ffecc1SBen Gras  */
20651ffecc1SBen Gras int
_cursesi_addbyte(WINDOW * win,__LINE ** lp,int * y,int * x,int c,attr_t attr,int char_interp)20751ffecc1SBen Gras _cursesi_addbyte(WINDOW *win, __LINE **lp, int *y, int *x, int c,
208*84d9c625SLionel Sambuc 		 attr_t attr, int char_interp)
20951ffecc1SBen Gras {
210*84d9c625SLionel Sambuc 	static char	 blank[] = " ";
211*84d9c625SLionel Sambuc 	int		 tabsize;
212*84d9c625SLionel Sambuc 	int		 newx, i;
21351ffecc1SBen Gras 	attr_t		 attributes;
21451ffecc1SBen Gras 
215*84d9c625SLionel Sambuc 	if (char_interp) {
21651ffecc1SBen Gras 		switch (c) {
21751ffecc1SBen Gras 		case '\t':
218*84d9c625SLionel Sambuc 			tabsize = win->screen->TABSIZE;
21951ffecc1SBen Gras 			PSYNCH_OUT;
220*84d9c625SLionel Sambuc 			for (i = 0; i < (tabsize - (*x % tabsize)); i++) {
221*84d9c625SLionel Sambuc 				if (waddbytes(win, blank, 1) == ERR)
22251ffecc1SBen Gras 					return (ERR);
223*84d9c625SLionel Sambuc 			}
22451ffecc1SBen Gras 			PSYNCH_IN;
225*84d9c625SLionel Sambuc 			return (OK);
226*84d9c625SLionel Sambuc 
227*84d9c625SLionel Sambuc 		case '\n':
228*84d9c625SLionel Sambuc 			PSYNCH_OUT;
229*84d9c625SLionel Sambuc 			wclrtoeol(win);
230*84d9c625SLionel Sambuc 			PSYNCH_IN;
231*84d9c625SLionel Sambuc 			(*lp)->flags |= __ISPASTEOL;
23251ffecc1SBen Gras 			break;
23351ffecc1SBen Gras 
234*84d9c625SLionel Sambuc 		case '\r':
235*84d9c625SLionel Sambuc 			*x = 0;
236*84d9c625SLionel Sambuc 			win->curx = *x;
237*84d9c625SLionel Sambuc 			return (OK);
238*84d9c625SLionel Sambuc 
239*84d9c625SLionel Sambuc 		case '\b':
240*84d9c625SLionel Sambuc 			if (--(*x) < 0)
241*84d9c625SLionel Sambuc 				*x = 0;
242*84d9c625SLionel Sambuc 			win->curx = *x;
243*84d9c625SLionel Sambuc 			return (OK);
244*84d9c625SLionel Sambuc 		}
245*84d9c625SLionel Sambuc 	}
246*84d9c625SLionel Sambuc 
24751ffecc1SBen Gras #ifdef DEBUG
248*84d9c625SLionel Sambuc 	__CTRACE(__CTRACE_INPUT, "ADDBYTES(%p, %d, %d)\n", win, *y, *x);
24951ffecc1SBen Gras #endif
25051ffecc1SBen Gras 
251*84d9c625SLionel Sambuc 	if (char_interp && ((*lp)->flags & __ISPASTEOL)) {
25251ffecc1SBen Gras 		*x = 0;
25351ffecc1SBen Gras 		(*lp)->flags &= ~__ISPASTEOL;
25451ffecc1SBen Gras 		if (*y == win->scr_b) {
25551ffecc1SBen Gras #ifdef DEBUG
25651ffecc1SBen Gras 			__CTRACE(__CTRACE_INPUT,
25751ffecc1SBen Gras 				 "ADDBYTES - on bottom "
25851ffecc1SBen Gras 				 "of scrolling region\n");
25951ffecc1SBen Gras #endif
26051ffecc1SBen Gras 			if (!(win->flags & __SCROLLOK))
26151ffecc1SBen Gras 				return ERR;
26251ffecc1SBen Gras 			PSYNCH_OUT;
26351ffecc1SBen Gras 			scroll(win);
26451ffecc1SBen Gras 			PSYNCH_IN;
26551ffecc1SBen Gras 		} else {
26651ffecc1SBen Gras 			(*y)++;
26751ffecc1SBen Gras 		}
26851ffecc1SBen Gras 		*lp = win->alines[*y];
26951ffecc1SBen Gras 		if (c == '\n')
270*84d9c625SLionel Sambuc 			return (OK);
27151ffecc1SBen Gras 	}
27251ffecc1SBen Gras 
273*84d9c625SLionel Sambuc #ifdef DEBUG
274*84d9c625SLionel Sambuc 	__CTRACE(__CTRACE_INPUT,
275*84d9c625SLionel Sambuc 		 "ADDBYTES: 1: y = %d, x = %d, firstch = %d, lastch = %d\n",
276*84d9c625SLionel Sambuc 		 *y, *x, *win->alines[*y]->firstchp,
277*84d9c625SLionel Sambuc 		 *win->alines[*y]->lastchp);
278*84d9c625SLionel Sambuc #endif
279*84d9c625SLionel Sambuc 
280*84d9c625SLionel Sambuc 	attributes = (win->wattr | attr) & (__ATTRIBUTES & ~__COLOR);
28151ffecc1SBen Gras 	if (attr & __COLOR)
28251ffecc1SBen Gras 		attributes |= attr & __COLOR;
28351ffecc1SBen Gras 	else if (win->wattr & __COLOR)
28451ffecc1SBen Gras 		attributes |= win->wattr & __COLOR;
285*84d9c625SLionel Sambuc 
28651ffecc1SBen Gras 	/*
28751ffecc1SBen Gras 	 * Always update the change pointers.  Otherwise,
28851ffecc1SBen Gras 	 * we could end up not displaying 'blank' characters
28951ffecc1SBen Gras 	 * when overlapping windows are displayed.
29051ffecc1SBen Gras 	 */
29151ffecc1SBen Gras 	newx = *x + win->ch_off;
29251ffecc1SBen Gras 	(*lp)->flags |= __ISDIRTY;
29351ffecc1SBen Gras 	/*
29451ffecc1SBen Gras 	 * firstchp/lastchp are shared between
29551ffecc1SBen Gras 	 * parent window and sub-window.
29651ffecc1SBen Gras 	 */
29751ffecc1SBen Gras 	if (newx < *(*lp)->firstchp)
29851ffecc1SBen Gras 		*(*lp)->firstchp = newx;
29951ffecc1SBen Gras 	if (newx > *(*lp)->lastchp)
30051ffecc1SBen Gras 		*(*lp)->lastchp = newx;
30151ffecc1SBen Gras #ifdef DEBUG
302*84d9c625SLionel Sambuc 	__CTRACE(__CTRACE_INPUT, "ADDBYTES: change gives f/l: %d/%d [%d/%d]\n",
30351ffecc1SBen Gras 		 *(*lp)->firstchp, *(*lp)->lastchp,
30451ffecc1SBen Gras 		 *(*lp)->firstchp - win->ch_off,
30551ffecc1SBen Gras 		 *(*lp)->lastchp - win->ch_off);
30651ffecc1SBen Gras #endif
30751ffecc1SBen Gras 	if (win->bch != ' ' && c == ' ')
30851ffecc1SBen Gras 		(*lp)->line[*x].ch = win->bch;
30951ffecc1SBen Gras 	else
31051ffecc1SBen Gras 		(*lp)->line[*x].ch = c;
31151ffecc1SBen Gras 
31251ffecc1SBen Gras 	if (attributes & __COLOR)
31351ffecc1SBen Gras 		(*lp)->line[*x].attr =
31451ffecc1SBen Gras 			attributes | (win->battr & ~__COLOR);
31551ffecc1SBen Gras 	else
31651ffecc1SBen Gras 		(*lp)->line[*x].attr = attributes | win->battr;
31751ffecc1SBen Gras 
31851ffecc1SBen Gras 	if (*x == win->maxx - 1)
31951ffecc1SBen Gras 		(*lp)->flags |= __ISPASTEOL;
32051ffecc1SBen Gras 	else
32151ffecc1SBen Gras 		(*x)++;
322*84d9c625SLionel Sambuc 
32351ffecc1SBen Gras #ifdef DEBUG
32451ffecc1SBen Gras 	__CTRACE(__CTRACE_INPUT,
325*84d9c625SLionel Sambuc 		 "ADDBYTES: 2: y = %d, x = %d, firstch = %d, lastch = %d\n",
32651ffecc1SBen Gras 		 *y, *x, *win->alines[*y]->firstchp,
32751ffecc1SBen Gras 		 *win->alines[*y]->lastchp);
32851ffecc1SBen Gras #endif
32951ffecc1SBen Gras 	return (OK);
33051ffecc1SBen Gras }
33151ffecc1SBen Gras 
33251ffecc1SBen Gras /*
33351ffecc1SBen Gras  * _cursesi_addwchar -
33451ffecc1SBen Gras  *	Internal function to add a wide character and update the row
33551ffecc1SBen Gras  * and column positions.
33651ffecc1SBen Gras  */
33751ffecc1SBen Gras int
_cursesi_addwchar(WINDOW * win,__LINE ** lnp,int * y,int * x,const cchar_t * wch,int char_interp)33851ffecc1SBen Gras _cursesi_addwchar(WINDOW *win, __LINE **lnp, int *y, int *x,
339*84d9c625SLionel Sambuc 		  const cchar_t *wch, int char_interp)
34051ffecc1SBen Gras {
34151ffecc1SBen Gras #ifndef HAVE_WCHAR
34251ffecc1SBen Gras 	return (ERR);
34351ffecc1SBen Gras #else
344*84d9c625SLionel Sambuc 	int sx = 0, ex = 0, cw = 0, i = 0, newx = 0, tabsize;
34551ffecc1SBen Gras 	__LDATA *lp = &win->alines[*y]->line[*x], *tp = NULL;
34651ffecc1SBen Gras 	nschar_t *np = NULL;
34751ffecc1SBen Gras 	cchar_t cc;
34851ffecc1SBen Gras 	attr_t attributes;
34951ffecc1SBen Gras 
350*84d9c625SLionel Sambuc 	if (char_interp) {
35151ffecc1SBen Gras 		/* special characters handling */
35251ffecc1SBen Gras 		switch (wch->vals[0]) {
35351ffecc1SBen Gras 		case L'\b':
35451ffecc1SBen Gras 			if (--*x < 0)
35551ffecc1SBen Gras 				*x = 0;
35651ffecc1SBen Gras 			win->curx = *x;
35751ffecc1SBen Gras 			return OK;
35851ffecc1SBen Gras 		case L'\r':
35951ffecc1SBen Gras 			*x = 0;
360*84d9c625SLionel Sambuc 			win->curx = *x;
36151ffecc1SBen Gras 			return OK;
36251ffecc1SBen Gras 		case L'\n':
36351ffecc1SBen Gras 			wclrtoeol(win);
36451ffecc1SBen Gras 			PSYNCH_IN;
36551ffecc1SBen Gras 			*x = 0;
36651ffecc1SBen Gras 			(*lnp)->flags &= ~__ISPASTEOL;
36751ffecc1SBen Gras 			if (*y == win->scr_b) {
36851ffecc1SBen Gras 				if (!(win->flags & __SCROLLOK))
36951ffecc1SBen Gras 					return ERR;
37051ffecc1SBen Gras 				PSYNCH_OUT;
37151ffecc1SBen Gras 				scroll(win);
37251ffecc1SBen Gras 				PSYNCH_IN;
37351ffecc1SBen Gras 			} else {
37451ffecc1SBen Gras 				(*y)++;
37551ffecc1SBen Gras 			}
37651ffecc1SBen Gras 			PSYNCH_OUT;
37751ffecc1SBen Gras 			return OK;
37851ffecc1SBen Gras 		case L'\t':
37951ffecc1SBen Gras 			cc.vals[0] = L' ';
38051ffecc1SBen Gras 			cc.elements = 1;
38151ffecc1SBen Gras 			cc.attributes = win->wattr;
382*84d9c625SLionel Sambuc 			tabsize = win->screen->TABSIZE;
383*84d9c625SLionel Sambuc 			for (i = 0; i < tabsize - (*x % tabsize); i++) {
38451ffecc1SBen Gras 				if (wadd_wch(win, &cc) == ERR)
38551ffecc1SBen Gras 					return ERR;
38651ffecc1SBen Gras 			}
38751ffecc1SBen Gras 			return OK;
38851ffecc1SBen Gras 		}
389*84d9c625SLionel Sambuc 	}
39051ffecc1SBen Gras 
39151ffecc1SBen Gras 	/* check for non-spacing character */
39251ffecc1SBen Gras 	if (!wcwidth(wch->vals[0])) {
39351ffecc1SBen Gras #ifdef DEBUG
39451ffecc1SBen Gras 		__CTRACE(__CTRACE_INPUT,
39551ffecc1SBen Gras 			 "_cursesi_addwchar: char '%c' is non-spacing\n",
39651ffecc1SBen Gras 			 wch->vals[0]);
39751ffecc1SBen Gras #endif /* DEBUG */
39851ffecc1SBen Gras 		cw = WCOL(*lp);
39951ffecc1SBen Gras 		if (cw < 0) {
40051ffecc1SBen Gras 			lp += cw;
40151ffecc1SBen Gras 			*x += cw;
40251ffecc1SBen Gras 		}
40351ffecc1SBen Gras 		for (i = 0; i < wch->elements; i++) {
40451ffecc1SBen Gras 			if (!(np = (nschar_t *) malloc(sizeof(nschar_t))))
40551ffecc1SBen Gras 				return ERR;;
40651ffecc1SBen Gras 			np->ch = wch->vals[i];
40751ffecc1SBen Gras 			np->next = lp->nsp;
40851ffecc1SBen Gras 			lp->nsp = np;
40951ffecc1SBen Gras 		}
41051ffecc1SBen Gras 		(*lnp)->flags |= __ISDIRTY;
41151ffecc1SBen Gras 		newx = *x + win->ch_off;
41251ffecc1SBen Gras 		if (newx < *(*lnp)->firstchp)
41351ffecc1SBen Gras 			*(*lnp)->firstchp = newx;
41451ffecc1SBen Gras 		if (newx > *(*lnp)->lastchp)
41551ffecc1SBen Gras 			*(*lnp)->lastchp = newx;
41651ffecc1SBen Gras 		__touchline(win, *y, *x, *x);
41751ffecc1SBen Gras 		return OK;
41851ffecc1SBen Gras 	}
41951ffecc1SBen Gras 	/* check for new line first */
420*84d9c625SLionel Sambuc 	if (char_interp && ((*lnp)->flags & __ISPASTEOL)) {
42151ffecc1SBen Gras 		*x = 0;
42251ffecc1SBen Gras 		(*lnp)->flags &= ~__ISPASTEOL;
42351ffecc1SBen Gras 		if (*y == win->scr_b) {
42451ffecc1SBen Gras 			if (!(win->flags & __SCROLLOK))
42551ffecc1SBen Gras 				return ERR;
42651ffecc1SBen Gras 			PSYNCH_OUT;
42751ffecc1SBen Gras 			scroll(win);
42851ffecc1SBen Gras 			PSYNCH_IN;
42951ffecc1SBen Gras 		} else {
43051ffecc1SBen Gras 			(*y)++;
43151ffecc1SBen Gras 		}
43251ffecc1SBen Gras 		(*lnp) = win->alines[*y];
43351ffecc1SBen Gras 		lp = &win->alines[*y]->line[*x];
43451ffecc1SBen Gras 	}
43551ffecc1SBen Gras 	/* clear out the current character */
43651ffecc1SBen Gras 	cw = WCOL(*lp);
43751ffecc1SBen Gras 	if (cw >= 0) {
43851ffecc1SBen Gras 		sx = *x;
43951ffecc1SBen Gras 	} else {
44051ffecc1SBen Gras 		for (sx = *x - 1; sx >= max(*x + cw, 0); sx--) {
44151ffecc1SBen Gras #ifdef DEBUG
44251ffecc1SBen Gras 			__CTRACE(__CTRACE_INPUT,
44351ffecc1SBen Gras 				 "_cursesi_addwchar: clear current char (%d,%d)\n",
44451ffecc1SBen Gras 				 *y, sx);
44551ffecc1SBen Gras #endif /* DEBUG */
44651ffecc1SBen Gras 			tp = &win->alines[*y]->line[sx];
44751ffecc1SBen Gras 			tp->ch = (wchar_t) btowc((int) win->bch);
44851ffecc1SBen Gras 			if (_cursesi_copy_nsp(win->bnsp, tp) == ERR)
44951ffecc1SBen Gras 				return ERR;
45051ffecc1SBen Gras 
45151ffecc1SBen Gras 			tp->attr = win->battr;
45251ffecc1SBen Gras 			SET_WCOL(*tp, 1);
45351ffecc1SBen Gras 		}
45451ffecc1SBen Gras 		sx = *x + cw;
45551ffecc1SBen Gras 		(*lnp)->flags |= __ISDIRTY;
45651ffecc1SBen Gras 		newx = sx + win->ch_off;
45751ffecc1SBen Gras 		if (newx < *(*lnp)->firstchp)
45851ffecc1SBen Gras 			*(*lnp)->firstchp = newx;
45951ffecc1SBen Gras 	}
46051ffecc1SBen Gras 
46151ffecc1SBen Gras 	/* check for enough space before the end of line */
46251ffecc1SBen Gras 	cw = wcwidth(wch->vals[0]);
46351ffecc1SBen Gras 	if (cw < 0)
46451ffecc1SBen Gras 		cw = 1;
465*84d9c625SLionel Sambuc 
46651ffecc1SBen Gras 	if (cw > win->maxx - *x) {
46751ffecc1SBen Gras #ifdef DEBUG
46851ffecc1SBen Gras 		__CTRACE(__CTRACE_INPUT,
46951ffecc1SBen Gras 			 "_cursesi_addwchar: clear EOL (%d,%d)\n",
47051ffecc1SBen Gras 			 *y, *x);
47151ffecc1SBen Gras #endif /* DEBUG */
47251ffecc1SBen Gras 		(*lnp)->flags |= __ISDIRTY;
47351ffecc1SBen Gras 		newx = *x + win->ch_off;
47451ffecc1SBen Gras 		if (newx < *(*lnp)->firstchp)
47551ffecc1SBen Gras 			*(*lnp)->firstchp = newx;
47651ffecc1SBen Gras 		for (tp = lp; *x < win->maxx; tp++, (*x)++) {
47751ffecc1SBen Gras 			tp->ch = (wchar_t) btowc((int) win->bch);
47851ffecc1SBen Gras 			if (_cursesi_copy_nsp(win->bnsp, tp) == ERR)
47951ffecc1SBen Gras 				return ERR;
48051ffecc1SBen Gras 			tp->attr = win->battr;
48151ffecc1SBen Gras 			SET_WCOL(*tp, 1);
48251ffecc1SBen Gras 		}
48351ffecc1SBen Gras 		newx = win->maxx - 1 + win->ch_off;
48451ffecc1SBen Gras 		if (newx > *(*lnp)->lastchp)
48551ffecc1SBen Gras 			*(*lnp)->lastchp = newx;
48651ffecc1SBen Gras 		__touchline(win, *y, sx, (int) win->maxx - 1);
48751ffecc1SBen Gras 		sx = *x = 0;
48851ffecc1SBen Gras 		if (*y == win->scr_b) {
48951ffecc1SBen Gras 			if (!(win->flags & __SCROLLOK))
49051ffecc1SBen Gras 				return ERR;
49151ffecc1SBen Gras 			PSYNCH_OUT;
49251ffecc1SBen Gras 			scroll(win);
49351ffecc1SBen Gras 			PSYNCH_IN;
49451ffecc1SBen Gras 		} else {
49551ffecc1SBen Gras 			(*y)++;
49651ffecc1SBen Gras 		}
49751ffecc1SBen Gras 		lp = &win->alines[*y]->line[0];
49851ffecc1SBen Gras 		(*lnp) = win->alines[*y];
49951ffecc1SBen Gras 	}
50051ffecc1SBen Gras 	win->cury = *y;
50151ffecc1SBen Gras 
50251ffecc1SBen Gras 	/* add spacing character */
50351ffecc1SBen Gras #ifdef DEBUG
50451ffecc1SBen Gras 	__CTRACE(__CTRACE_INPUT,
50551ffecc1SBen Gras 		 "_cursesi_addwchar: add character (%d,%d) 0x%x\n",
50651ffecc1SBen Gras 		 *y, *x, wch->vals[0]);
50751ffecc1SBen Gras #endif /* DEBUG */
50851ffecc1SBen Gras 	(*lnp)->flags |= __ISDIRTY;
50951ffecc1SBen Gras 	newx = *x + win->ch_off;
51051ffecc1SBen Gras 	if (newx < *(*lnp)->firstchp)
51151ffecc1SBen Gras 		*(*lnp)->firstchp = newx;
51251ffecc1SBen Gras 	if (lp->nsp) {
51351ffecc1SBen Gras 		__cursesi_free_nsp(lp->nsp);
51451ffecc1SBen Gras 		lp->nsp = NULL;
51551ffecc1SBen Gras 	}
51651ffecc1SBen Gras 
51751ffecc1SBen Gras 	lp->ch = wch->vals[0];
51851ffecc1SBen Gras 
51951ffecc1SBen Gras 	attributes = (win->wattr | wch->attributes)
52051ffecc1SBen Gras 		& (WA_ATTRIBUTES & ~__COLOR);
52151ffecc1SBen Gras 	if (wch->attributes & __COLOR)
52251ffecc1SBen Gras 		attributes |= wch->attributes & __COLOR;
52351ffecc1SBen Gras 	else if (win->wattr & __COLOR)
52451ffecc1SBen Gras 		attributes |= win->wattr & __COLOR;
52551ffecc1SBen Gras 	if (attributes & __COLOR)
52651ffecc1SBen Gras 		lp->attr = attributes | (win->battr & ~__COLOR);
52751ffecc1SBen Gras 	else
52851ffecc1SBen Gras 		lp->attr = attributes | win->battr;
52951ffecc1SBen Gras 
53051ffecc1SBen Gras 	SET_WCOL(*lp, cw);
53151ffecc1SBen Gras 
53251ffecc1SBen Gras #ifdef DEBUG
53351ffecc1SBen Gras 	__CTRACE(__CTRACE_INPUT,
53451ffecc1SBen Gras 		 "_cursesi_addwchar: add spacing char 0x%x, attr 0x%x\n",
53551ffecc1SBen Gras 		 lp->ch, lp->attr);
53651ffecc1SBen Gras #endif /* DEBUG */
53751ffecc1SBen Gras 
53851ffecc1SBen Gras 	if (wch->elements > 1) {
53951ffecc1SBen Gras 		for (i = 1; i < wch->elements; i++) {
54051ffecc1SBen Gras 			np = (nschar_t *)malloc(sizeof(nschar_t));
54151ffecc1SBen Gras 			if (!np)
54251ffecc1SBen Gras 				return ERR;;
54351ffecc1SBen Gras 			np->ch = wch->vals[i];
54451ffecc1SBen Gras 			np->next = lp->nsp;
54551ffecc1SBen Gras #ifdef DEBUG
54651ffecc1SBen Gras 			__CTRACE(__CTRACE_INPUT,
54751ffecc1SBen Gras 			    "_cursesi_addwchar: add non-spacing char 0x%x\n", np->ch);
54851ffecc1SBen Gras #endif /* DEBUG */
54951ffecc1SBen Gras 			lp->nsp = np;
55051ffecc1SBen Gras 		}
55151ffecc1SBen Gras 	}
55251ffecc1SBen Gras #ifdef DEBUG
55351ffecc1SBen Gras 	__CTRACE(__CTRACE_INPUT, "_cursesi_addwchar: non-spacing list header: %p\n",
55451ffecc1SBen Gras 	    lp->nsp);
55551ffecc1SBen Gras 	__CTRACE(__CTRACE_INPUT, "_cursesi_addwchar: add rest columns (%d:%d)\n",
55651ffecc1SBen Gras 		sx + 1, sx + cw - 1);
55751ffecc1SBen Gras #endif /* DEBUG */
55851ffecc1SBen Gras 	for (tp = lp + 1, *x = sx + 1; *x - sx <= cw - 1; tp++, (*x)++) {
55951ffecc1SBen Gras 		if (tp->nsp) {
56051ffecc1SBen Gras 			__cursesi_free_nsp(tp->nsp);
56151ffecc1SBen Gras 			tp->nsp = NULL;
56251ffecc1SBen Gras 		}
56351ffecc1SBen Gras 		tp->ch = wch->vals[0];
56451ffecc1SBen Gras 		tp->attr = lp->attr & WA_ATTRIBUTES;
56551ffecc1SBen Gras 		/* Mark as "continuation" cell */
56651ffecc1SBen Gras 		tp->attr |= __WCWIDTH;
56751ffecc1SBen Gras 	}
568*84d9c625SLionel Sambuc 
56951ffecc1SBen Gras 	if (*x == win->maxx) {
57051ffecc1SBen Gras 		(*lnp)->flags |= __ISPASTEOL;
57151ffecc1SBen Gras 		newx = win->maxx - 1 + win->ch_off;
57251ffecc1SBen Gras 		if (newx > *(*lnp)->lastchp)
57351ffecc1SBen Gras 			*(*lnp)->lastchp = newx;
57451ffecc1SBen Gras 		__touchline(win, *y, sx, (int) win->maxx - 1);
57551ffecc1SBen Gras 		win->curx = sx;
57651ffecc1SBen Gras 	} else {
57751ffecc1SBen Gras 		win->curx = *x;
57851ffecc1SBen Gras 
57951ffecc1SBen Gras 		/* clear the remining of the current characer */
58051ffecc1SBen Gras 		if (*x && *x < win->maxx) {
58151ffecc1SBen Gras 			ex = sx + cw;
58251ffecc1SBen Gras 			tp = &win->alines[*y]->line[ex];
58351ffecc1SBen Gras 			while (ex < win->maxx && WCOL(*tp) < 0) {
58451ffecc1SBen Gras #ifdef DEBUG
58551ffecc1SBen Gras 				__CTRACE(__CTRACE_INPUT,
58651ffecc1SBen Gras 				 	"_cursesi_addwchar: clear "
58751ffecc1SBen Gras 				 	"remaining of current char (%d,%d)nn",
58851ffecc1SBen Gras 				 	*y, ex);
58951ffecc1SBen Gras #endif /* DEBUG */
59051ffecc1SBen Gras 				tp->ch = (wchar_t) btowc((int) win->bch);
59151ffecc1SBen Gras 				if (_cursesi_copy_nsp(win->bnsp, tp) == ERR)
59251ffecc1SBen Gras 					return ERR;
59351ffecc1SBen Gras 				tp->attr = win->battr;
59451ffecc1SBen Gras 				SET_WCOL(*tp, 1);
59551ffecc1SBen Gras 				tp++, ex++;
59651ffecc1SBen Gras 			}
59751ffecc1SBen Gras 			newx = ex - 1 + win->ch_off;
59851ffecc1SBen Gras 			if (newx > *(*lnp)->lastchp)
59951ffecc1SBen Gras 				*(*lnp)->lastchp = newx;
60051ffecc1SBen Gras 			__touchline(win, *y, sx, ex - 1);
60151ffecc1SBen Gras 		}
60251ffecc1SBen Gras 	}
60351ffecc1SBen Gras 
60451ffecc1SBen Gras #ifdef DEBUG
60551ffecc1SBen Gras 	__CTRACE(__CTRACE_INPUT, "add_wch: %d : 0x%x\n", lp->ch, lp->attr);
60651ffecc1SBen Gras #endif /* DEBUG */
60751ffecc1SBen Gras 	return OK;
60851ffecc1SBen Gras #endif
60951ffecc1SBen Gras }
610