xref: /netbsd-src/lib/libcurses/addbytes.c (revision e124de36d8a3bb2fd90b77ec25eb7736f29ee44d)
1*e124de36Sblymn /*	$NetBSD: addbytes.c,v 1.32 2007/05/28 15:01:53 blymn Exp $	*/
2716747aaSmikel 
361f28255Scgd /*
4d29088daScgd  * Copyright (c) 1987, 1993, 1994
5019bbd13Scgd  *	The Regents of the University of California.  All rights reserved.
661f28255Scgd  *
761f28255Scgd  * Redistribution and use in source and binary forms, with or without
861f28255Scgd  * modification, are permitted provided that the following conditions
961f28255Scgd  * are met:
1061f28255Scgd  * 1. Redistributions of source code must retain the above copyright
1161f28255Scgd  *    notice, this list of conditions and the following disclaimer.
1261f28255Scgd  * 2. Redistributions in binary form must reproduce the above copyright
1361f28255Scgd  *    notice, this list of conditions and the following disclaimer in the
1461f28255Scgd  *    documentation and/or other materials provided with the distribution.
15eb7c1594Sagc  * 3. Neither the name of the University nor the names of its contributors
1661f28255Scgd  *    may be used to endorse or promote products derived from this software
1761f28255Scgd  *    without specific prior written permission.
1861f28255Scgd  *
1961f28255Scgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2061f28255Scgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2161f28255Scgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2261f28255Scgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2361f28255Scgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2461f28255Scgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2561f28255Scgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2661f28255Scgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2761f28255Scgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2861f28255Scgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2961f28255Scgd  * SUCH DAMAGE.
3061f28255Scgd  */
3161f28255Scgd 
32716747aaSmikel #include <sys/cdefs.h>
3361f28255Scgd #ifndef lint
34716747aaSmikel #if 0
35d29088daScgd static char sccsid[] = "@(#)addbytes.c	8.4 (Berkeley) 5/4/94";
36716747aaSmikel #else
37*e124de36Sblymn __RCSID("$NetBSD: addbytes.c,v 1.32 2007/05/28 15:01:53 blymn Exp $");
38716747aaSmikel #endif
3961f28255Scgd #endif				/* not lint */
4061f28255Scgd 
41*e124de36Sblymn #include <stdlib.h>
42d29088daScgd #include "curses.h"
4323464ee5Sblymn #include "curses_private.h"
448d259104Sblymn #ifdef DEBUG
458d259104Sblymn #include <assert.h>
468d259104Sblymn #endif
4761f28255Scgd 
48019bbd13Scgd #define	SYNCH_IN	{y = win->cury; x = win->curx;}
49019bbd13Scgd #define	SYNCH_OUT	{win->cury = y; win->curx = x;}
50*e124de36Sblymn #define	PSYNCH_IN	{*y = win->cury; *x = win->curx;}
51*e124de36Sblymn #define	PSYNCH_OUT	{win->cury = *y; win->curx = *x;}
5275de25bbSalm 
53aaf74682Sblymn #ifndef _CURSES_USE_MACROS
54aaf74682Sblymn 
55aaf74682Sblymn /*
56aaf74682Sblymn  * addbytes --
57aaf74682Sblymn  *      Add the character to the current position in stdscr.
58aaf74682Sblymn  */
59aaf74682Sblymn int
60aaf74682Sblymn addbytes(const char *bytes, int count)
61aaf74682Sblymn {
62aaf74682Sblymn 	return __waddbytes(stdscr, bytes, count, 0);
63aaf74682Sblymn }
64aaf74682Sblymn 
6561f28255Scgd /*
6662a3457dSmycroft  * waddbytes --
6762a3457dSmycroft  *      Add the character to the current position in the given window.
6861f28255Scgd  */
6962a3457dSmycroft int
70aaf74682Sblymn waddbytes(WINDOW *win, const char *bytes, int count)
71aaf74682Sblymn {
72aaf74682Sblymn 	return __waddbytes(win, bytes, count, 0);
73aaf74682Sblymn }
74aaf74682Sblymn 
75aaf74682Sblymn /*
76aaf74682Sblymn  * mvaddbytes --
77aaf74682Sblymn  *      Add the characters to stdscr at the location given.
78aaf74682Sblymn  */
79aaf74682Sblymn int
80aaf74682Sblymn mvaddbytes(int y, int x, const char *bytes, int count)
81aaf74682Sblymn {
82aaf74682Sblymn 	return mvwaddbytes(stdscr, y, x, bytes, count);
83aaf74682Sblymn }
84aaf74682Sblymn 
85aaf74682Sblymn /*
86aaf74682Sblymn  * mvwaddbytes --
87aaf74682Sblymn  *      Add the characters to the given window at the location given.
88aaf74682Sblymn  */
89aaf74682Sblymn int
90aaf74682Sblymn mvwaddbytes(WINDOW *win, int y, int x, const char *bytes, int count)
91aaf74682Sblymn {
92aaf74682Sblymn 	if (wmove(win, y, x) == ERR)
93aaf74682Sblymn 		return ERR;
94aaf74682Sblymn 
95aaf74682Sblymn 	return __waddbytes(win, bytes, count, 0);
96aaf74682Sblymn }
97aaf74682Sblymn 
98aaf74682Sblymn #endif
99aaf74682Sblymn 
100aaf74682Sblymn /*
101aaf74682Sblymn  * waddbytes --
102aaf74682Sblymn  *	Add the character to the current position in the given window.
103aaf74682Sblymn  */
104aaf74682Sblymn int
105aaf74682Sblymn __waddbytes(WINDOW *win, const char *bytes, int count, attr_t attr)
10661f28255Scgd {
107*e124de36Sblymn 	int		 x, y, err;
108019bbd13Scgd 	__LINE		*lp;
109*e124de36Sblymn #ifdef HAVE_WCHAR
110*e124de36Sblymn 	int		n;
111*e124de36Sblymn 	cchar_t		cc;
112*e124de36Sblymn 	wchar_t		wc;
113*e124de36Sblymn #else
114*e124de36Sblymn 	int		c;
115*e124de36Sblymn #endif
1168d259104Sblymn #ifdef DEBUG
1178d259104Sblymn 	int             i;
1188d259104Sblymn 
1198d259104Sblymn 	for (i = 0; i < win->maxy; i++) {
1208d259104Sblymn 		assert(win->lines[i]->sentinel == SENTINEL_VALUE);
1218d259104Sblymn 	}
122*e124de36Sblymn 
123*e124de36Sblymn 	__CTRACE(__CTRACE_INPUT, "ADDBYTES: add %d bytes\n", count);
1248d259104Sblymn #endif
12561f28255Scgd 
126*e124de36Sblymn 	err = OK;
12762a3457dSmycroft 	SYNCH_IN;
1288d259104Sblymn 	lp = win->lines[y];
12962a3457dSmycroft 
130*e124de36Sblymn 	while (count > 0) {
131*e124de36Sblymn #ifndef HAVE_WCHAR
132716747aaSmikel 		c = *bytes++;
13362a3457dSmycroft #ifdef DEBUG
1341f221324Sjdc 		__CTRACE(__CTRACE_INPUT, "ADDBYTES('%c', %x) at (%d, %d)\n",
1351f221324Sjdc 		    c, attr, y, x);
13662a3457dSmycroft #endif
137*e124de36Sblymn 		err = _cursesi_addbyte(win, &lp, &y, &x, c, attr);
138*e124de36Sblymn 		count--;
139*e124de36Sblymn #else
140*e124de36Sblymn 		/*
141*e124de36Sblymn 		 * For wide character support only, try and convert the
142*e124de36Sblymn 		 * given string into a wide character - we do this because
143*e124de36Sblymn 		 * this is how ncurses behaves (not that I think this is
144*e124de36Sblymn 		 * actually the correct thing to do but if we don't do it
145*e124de36Sblymn 		 * a lot of things that rely on this behaviour will break
146*e124de36Sblymn 		 * and we will be blamed).  If the conversion succeeds
147*e124de36Sblymn 		 * then we eat the n characters used to make the wide char
148*e124de36Sblymn 		 * from the string.
149*e124de36Sblymn 		 */
150*e124de36Sblymn 		n = mbtowc(&wc, bytes, count);
151*e124de36Sblymn 		if (n == 0)
152*e124de36Sblymn 			break;
153*e124de36Sblymn 		else if (n < 0) { /* not a valid conversion just eat a char */
154*e124de36Sblymn 			wc = *bytes;
155*e124de36Sblymn 			n = 1;
156*e124de36Sblymn 		}
157*e124de36Sblymn 
158*e124de36Sblymn 
159*e124de36Sblymn #ifdef DEBUG
160*e124de36Sblymn 	__CTRACE(__CTRACE_INPUT,
161*e124de36Sblymn 		 "ADDBYTES WIDE(0x%x [%s], %x) at (%d, %d), ate %d bytes\n",
162*e124de36Sblymn 		 (unsigned) wc, unctrl((unsigned) wc), attr, y, x, n);
163*e124de36Sblymn #endif
164*e124de36Sblymn 		cc.vals[0] = wc;
165*e124de36Sblymn 		cc.elements = 1;
166*e124de36Sblymn 		cc.attributes = attr;
167*e124de36Sblymn 		err = _cursesi_addwchar(win, &lp, &y, &x, &cc);
168*e124de36Sblymn 		bytes += n;
169*e124de36Sblymn 		count -= n;
170*e124de36Sblymn #endif
171*e124de36Sblymn 	}
172*e124de36Sblymn 
173*e124de36Sblymn 	SYNCH_OUT;
174*e124de36Sblymn 
175*e124de36Sblymn #ifdef DEBUG
176*e124de36Sblymn 	for (i = 0; i < win->maxy; i++) {
177*e124de36Sblymn 		assert(win->lines[i]->sentinel == SENTINEL_VALUE);
178*e124de36Sblymn 	}
179*e124de36Sblymn #endif
180*e124de36Sblymn 
181*e124de36Sblymn 	return (err);
182*e124de36Sblymn }
183*e124de36Sblymn 
184*e124de36Sblymn /*
185*e124de36Sblymn  * _cursesi_addbyte -
186*e124de36Sblymn  *	Internal function to add a byte and update the row and column
187*e124de36Sblymn  * positions as appropriate.  This function is only used in the narrow
188*e124de36Sblymn  * character version of curses.
189*e124de36Sblymn  */
190*e124de36Sblymn int
191*e124de36Sblymn _cursesi_addbyte(WINDOW *win, __LINE **lp, int *y, int *x, int c,
192*e124de36Sblymn 		 attr_t attr)
193*e124de36Sblymn {
194*e124de36Sblymn 	static char	 blanks[] = "        ";
195*e124de36Sblymn 	int		 newx;
196*e124de36Sblymn 	attr_t		 attributes;
197*e124de36Sblymn 
19861f28255Scgd 	switch (c) {
19961f28255Scgd 	case '\t':
200*e124de36Sblymn 		PSYNCH_OUT;
201*e124de36Sblymn 		if (waddbytes(win, blanks, 8 - (*x % 8)) == ERR)
20262a3457dSmycroft 			return (ERR);
203*e124de36Sblymn 		PSYNCH_IN;
20461f28255Scgd 		break;
20561f28255Scgd 
20661f28255Scgd 	default:
20762a3457dSmycroft #ifdef DEBUG
2081f221324Sjdc 		__CTRACE(__CTRACE_INPUT, "ADDBYTES(%p, %d, %d)\n",
209*e124de36Sblymn 			 win, *y, *x);
21061f28255Scgd #endif
211019bbd13Scgd 
212*e124de36Sblymn 		if ((*lp)->flags & __ISPASTEOL) {
213c7ba2828Sdsl 		  newline:
214*e124de36Sblymn 			*x = 0;
215*e124de36Sblymn 			(*lp)->flags &= ~__ISPASTEOL;
216*e124de36Sblymn 			if (*y == win->scr_b) {
2173f9388e3Sjdc #ifdef DEBUG
2181f221324Sjdc 				__CTRACE(__CTRACE_INPUT,
2191f221324Sjdc 					 "ADDBYTES - on bottom "
220c841017dSdsl 					 "of scrolling region\n");
2213f9388e3Sjdc #endif
222c841017dSdsl 				if (!(win->flags & __SCROLLOK))
223c841017dSdsl 					return ERR;
224*e124de36Sblymn 				PSYNCH_OUT;
22561f28255Scgd 				scroll(win);
226*e124de36Sblymn 				PSYNCH_IN;
227019bbd13Scgd 			} else {
228*e124de36Sblymn 				(*y)++;
229019bbd13Scgd 			}
230*e124de36Sblymn 			*lp = win->lines[*y];
231019bbd13Scgd 			if (c == '\n')
232019bbd13Scgd 				break;
233019bbd13Scgd 		}
234019bbd13Scgd 
23540add0b9Smycroft 		attributes = (win->wattr | attr) &
23640add0b9Smycroft 			(__ATTRIBUTES & ~__COLOR);
23740b39f92Sjdc 		if (attr & __COLOR)
23840b39f92Sjdc 			attributes |= attr & __COLOR;
23940b39f92Sjdc 		else if (win->wattr & __COLOR)
24040b39f92Sjdc 			attributes |= win->wattr & __COLOR;
24162a3457dSmycroft #ifdef DEBUG
2421f221324Sjdc 		__CTRACE(__CTRACE_INPUT,
2431f221324Sjdc 			 "ADDBYTES: 1: y = %d, x = %d, firstch = %d, "
244c841017dSdsl 			 "lastch = %d\n",
245*e124de36Sblymn 			 *y, *x, *win->lines[*y]->firstchp,
246*e124de36Sblymn 			 *win->lines[*y]->lastchp);
247019bbd13Scgd #endif
24802559eb6Sjdc 		/*
24902559eb6Sjdc 		 * Always update the change pointers.  Otherwise,
25002559eb6Sjdc 		 * we could end up not displaying 'blank' characters
25102559eb6Sjdc 		 * when overlapping windows are displayed.
25202559eb6Sjdc 		 */
253*e124de36Sblymn 		newx = *x + win->ch_off;
254*e124de36Sblymn 		(*lp)->flags |= __ISDIRTY;
2558e3f5589Sjdc 		/*
2568e3f5589Sjdc 		 * firstchp/lastchp are shared between
2578e3f5589Sjdc 		 * parent window and sub-window.
2588e3f5589Sjdc 		 */
259*e124de36Sblymn 		if (newx < *(*lp)->firstchp)
260*e124de36Sblymn 			*(*lp)->firstchp = newx;
261*e124de36Sblymn 		if (newx > *(*lp)->lastchp)
262*e124de36Sblymn 			*(*lp)->lastchp = newx;
263019bbd13Scgd #ifdef DEBUG
2641f221324Sjdc 		__CTRACE(__CTRACE_INPUT,
2651f221324Sjdc 			 "ADDBYTES: change gives f/l: %d/%d [%d/%d]\n",
266*e124de36Sblymn 			 *(*lp)->firstchp, *(*lp)->lastchp,
267*e124de36Sblymn 			 *(*lp)->firstchp - win->ch_off,
268*e124de36Sblymn 			 *(*lp)->lastchp - win->ch_off);
269019bbd13Scgd #endif
270978ab4adSjdc 		if (win->bch != ' ' && c == ' ')
271*e124de36Sblymn 			(*lp)->line[*x].ch = win->bch;
272978ab4adSjdc 		else
273*e124de36Sblymn 			(*lp)->line[*x].ch = c;
274*e124de36Sblymn 
275978ab4adSjdc 		if (attributes & __COLOR)
276*e124de36Sblymn 			(*lp)->line[*x].attr =
277978ab4adSjdc 				attributes | (win->battr & ~__COLOR);
278978ab4adSjdc 		else
279*e124de36Sblymn 			(*lp)->line[*x].attr = attributes | win->battr;
280*e124de36Sblymn 
281*e124de36Sblymn 		if (*x == win->maxx - 1)
282*e124de36Sblymn 			(*lp)->flags |= __ISPASTEOL;
283019bbd13Scgd 		else
284*e124de36Sblymn 			(*x)++;
285019bbd13Scgd #ifdef DEBUG
2861f221324Sjdc 		__CTRACE(__CTRACE_INPUT,
2871f221324Sjdc 			 "ADDBYTES: 2: y = %d, x = %d, firstch = %d, "
2881f221324Sjdc 			 "lastch = %d\n",
289*e124de36Sblymn 			 *y, *x, *win->lines[*y]->firstchp,
290*e124de36Sblymn 			 *win->lines[*y]->lastchp);
29161f28255Scgd #endif
29261f28255Scgd 		break;
29361f28255Scgd 	case '\n':
294*e124de36Sblymn 		PSYNCH_OUT;
29561f28255Scgd 		wclrtoeol(win);
296*e124de36Sblymn 		PSYNCH_IN;
29761f28255Scgd 		goto newline;
29861f28255Scgd 	case '\r':
299*e124de36Sblymn 		*x = 0;
300*e124de36Sblymn 		break;
30161f28255Scgd 	case '\b':
302*e124de36Sblymn 		if (--(*x) < 0)
303*e124de36Sblymn 			*x = 0;
30461f28255Scgd 		break;
30561f28255Scgd 	}
3068d259104Sblymn 
30762a3457dSmycroft 	return (OK);
30861f28255Scgd }
309*e124de36Sblymn 
310*e124de36Sblymn /*
311*e124de36Sblymn  * _cursesi_addwchar -
312*e124de36Sblymn  *	Internal function to add a wide character and update the row
313*e124de36Sblymn  * and column positions.
314*e124de36Sblymn  */
315*e124de36Sblymn int
316*e124de36Sblymn _cursesi_addwchar(WINDOW *win, __LINE **lnp, int *y, int *x,
317*e124de36Sblymn 		  const cchar_t *wch)
318*e124de36Sblymn {
319*e124de36Sblymn #ifndef HAVE_WCHAR
320*e124de36Sblymn 	return (ERR);
321*e124de36Sblymn #else
322*e124de36Sblymn 	int sx = 0, ex = 0, cw = 0, i = 0, newx = 0;
323*e124de36Sblymn 	__LDATA *lp = &win->lines[*y]->line[*x], *tp = NULL;
324*e124de36Sblymn 	nschar_t *np = NULL;
325*e124de36Sblymn 	cchar_t cc;
326*e124de36Sblymn 	attr_t attributes;
327*e124de36Sblymn 
328*e124de36Sblymn 	/* special characters handling */
329*e124de36Sblymn 	switch (wch->vals[0]) {
330*e124de36Sblymn 	case L'\b':
331*e124de36Sblymn 		if (--*x < 0)
332*e124de36Sblymn 			*x = 0;
333*e124de36Sblymn 		win->curx = *x;
334*e124de36Sblymn 		return OK;
335*e124de36Sblymn 	case L'\r':
336*e124de36Sblymn 		win->curx = 0;
337*e124de36Sblymn 		return OK;
338*e124de36Sblymn 	case L'\n':
339*e124de36Sblymn 		wclrtoeol(win);
340*e124de36Sblymn 		PSYNCH_IN;
341*e124de36Sblymn 		*x = 0;
342*e124de36Sblymn 		(*lnp)->flags &= ~__ISPASTEOL;
343*e124de36Sblymn 		if (*y == win->scr_b) {
344*e124de36Sblymn 			if (!(win->flags & __SCROLLOK))
345*e124de36Sblymn 				return ERR;
346*e124de36Sblymn 			PSYNCH_OUT;
347*e124de36Sblymn 			scroll(win);
348*e124de36Sblymn 			PSYNCH_IN;
349*e124de36Sblymn 		} else {
350*e124de36Sblymn 			(*y)++;
351*e124de36Sblymn 		}
352*e124de36Sblymn 		PSYNCH_OUT;
353*e124de36Sblymn 		return OK;
354*e124de36Sblymn 	case L'\t':
355*e124de36Sblymn 		cc.vals[0] = L' ';
356*e124de36Sblymn 		cc.elements = 1;
357*e124de36Sblymn 		cc.attributes = win->wattr;
358*e124de36Sblymn 		for (i = 0; i < 8 - (*x % 8); i++) {
359*e124de36Sblymn 			if (wadd_wch(win, &cc) == ERR)
360*e124de36Sblymn 				return ERR;
361*e124de36Sblymn 		}
362*e124de36Sblymn 		return OK;
363*e124de36Sblymn 	}
364*e124de36Sblymn 
365*e124de36Sblymn 	/* check for non-spacing character */
366*e124de36Sblymn 	if (!wcwidth(wch->vals[0])) {
367*e124de36Sblymn #ifdef DEBUG
368*e124de36Sblymn 		__CTRACE(__CTRACE_INPUT,
369*e124de36Sblymn 			 "_cursesi_addwchar: char '%c' is non-spacing\n",
370*e124de36Sblymn 			 wch->vals[0]);
371*e124de36Sblymn #endif /* DEBUG */
372*e124de36Sblymn 		cw = WCOL(*lp);
373*e124de36Sblymn 		if (cw < 0) {
374*e124de36Sblymn 			lp += cw;
375*e124de36Sblymn 			*x += cw;
376*e124de36Sblymn 		}
377*e124de36Sblymn 		for (i = 0; i < wch->elements; i++) {
378*e124de36Sblymn 			if (!(np = (nschar_t *) malloc(sizeof(nschar_t))))
379*e124de36Sblymn 				return ERR;;
380*e124de36Sblymn 			np->ch = wch->vals[i];
381*e124de36Sblymn 			np->next = lp->nsp;
382*e124de36Sblymn 			lp->nsp = np;
383*e124de36Sblymn 		}
384*e124de36Sblymn 		(*lnp)->flags |= __ISDIRTY;
385*e124de36Sblymn 		newx = *x + win->ch_off;
386*e124de36Sblymn 		if (newx < *(*lnp)->firstchp)
387*e124de36Sblymn 			*(*lnp)->firstchp = newx;
388*e124de36Sblymn 		if (newx > *(*lnp)->lastchp)
389*e124de36Sblymn 			*(*lnp)->lastchp = newx;
390*e124de36Sblymn 		__touchline(win, *y, *x, *x);
391*e124de36Sblymn 		return OK;
392*e124de36Sblymn 	}
393*e124de36Sblymn 	/* check for new line first */
394*e124de36Sblymn 	if ((*lnp)->flags & __ISPASTEOL) {
395*e124de36Sblymn 		*x = 0;
396*e124de36Sblymn 		(*lnp)->flags &= ~__ISPASTEOL;
397*e124de36Sblymn 		if (*y == win->scr_b) {
398*e124de36Sblymn 			if (!(win->flags & __SCROLLOK))
399*e124de36Sblymn 				return ERR;
400*e124de36Sblymn 			PSYNCH_OUT;
401*e124de36Sblymn 			scroll(win);
402*e124de36Sblymn 			PSYNCH_IN;
403*e124de36Sblymn 		} else {
404*e124de36Sblymn 			(*y)++;
405*e124de36Sblymn 		}
406*e124de36Sblymn 		(*lnp) = win->lines[*y];
407*e124de36Sblymn 		lp = &win->lines[*y]->line[*x];
408*e124de36Sblymn 	}
409*e124de36Sblymn 	/* clear out the current character */
410*e124de36Sblymn 	cw = WCOL(*lp);
411*e124de36Sblymn 	if (cw >= 0) {
412*e124de36Sblymn 		sx = *x;
413*e124de36Sblymn 	} else {
414*e124de36Sblymn 		for (sx = *x - 1; sx >= max(*x + cw, 0); sx--) {
415*e124de36Sblymn #ifdef DEBUG
416*e124de36Sblymn 			__CTRACE(__CTRACE_INPUT,
417*e124de36Sblymn 				 "_cursesi_addwchar: clear current char (%d,%d)\n",
418*e124de36Sblymn 				 *y, sx);
419*e124de36Sblymn #endif /* DEBUG */
420*e124de36Sblymn 			tp = &win->lines[*y]->line[sx];
421*e124de36Sblymn 			tp->ch = (wchar_t) btowc((int) win->bch);
422*e124de36Sblymn 			if (_cursesi_copy_nsp(win->bnsp, tp) == ERR)
423*e124de36Sblymn 				return ERR;
424*e124de36Sblymn 
425*e124de36Sblymn 			tp->attr = win->battr;
426*e124de36Sblymn 			SET_WCOL(*tp, 1);
427*e124de36Sblymn 		}
428*e124de36Sblymn 		sx = *x + cw;
429*e124de36Sblymn 		(*lnp)->flags |= __ISDIRTY;
430*e124de36Sblymn 		newx = sx + win->ch_off;
431*e124de36Sblymn 		if (newx < *(*lnp)->firstchp)
432*e124de36Sblymn 			*(*lnp)->firstchp = newx;
433*e124de36Sblymn 	}
434*e124de36Sblymn 
435*e124de36Sblymn 	/* check for enough space before the end of line */
436*e124de36Sblymn 	cw = wcwidth(wch->vals[0]);
437*e124de36Sblymn 	if (cw > win->maxx - *x) {
438*e124de36Sblymn #ifdef DEBUG
439*e124de36Sblymn 		__CTRACE(__CTRACE_INPUT,
440*e124de36Sblymn 			 "_cursesi_addwchar: clear EOL (%d,%d)\n",
441*e124de36Sblymn 			 *y, *x);
442*e124de36Sblymn #endif /* DEBUG */
443*e124de36Sblymn 		(*lnp)->flags |= __ISDIRTY;
444*e124de36Sblymn 		newx = *x + win->ch_off;
445*e124de36Sblymn 		if (newx < *(*lnp)->firstchp)
446*e124de36Sblymn 			*(*lnp)->firstchp = newx;
447*e124de36Sblymn 		for (tp = lp; *x < win->maxx; tp++, (*x)++) {
448*e124de36Sblymn 			tp->ch = (wchar_t) btowc((int) win->bch);
449*e124de36Sblymn 			if (_cursesi_copy_nsp(win->bnsp, tp) == ERR)
450*e124de36Sblymn 				return ERR;
451*e124de36Sblymn 			tp->attr = win->battr;
452*e124de36Sblymn 			SET_WCOL(*tp, 1);
453*e124de36Sblymn 		}
454*e124de36Sblymn 		newx = win->maxx - 1 + win->ch_off;
455*e124de36Sblymn 		if (newx > *(*lnp)->lastchp)
456*e124de36Sblymn 			*(*lnp)->lastchp = newx;
457*e124de36Sblymn 		__touchline(win, *y, sx, (int) win->maxx - 1);
458*e124de36Sblymn 		sx = *x = 0;
459*e124de36Sblymn 		if (*y == win->scr_b) {
460*e124de36Sblymn 			if (!(win->flags & __SCROLLOK))
461*e124de36Sblymn 				return ERR;
462*e124de36Sblymn 			PSYNCH_OUT;
463*e124de36Sblymn 			scroll(win);
464*e124de36Sblymn 			PSYNCH_IN;
465*e124de36Sblymn 		} else {
466*e124de36Sblymn 			(*y)++;
467*e124de36Sblymn 		}
468*e124de36Sblymn 		lp = &win->lines[*y]->line[0];
469*e124de36Sblymn 		(*lnp) = win->lines[*y];
470*e124de36Sblymn 	}
471*e124de36Sblymn 	win->cury = *y;
472*e124de36Sblymn 
473*e124de36Sblymn 	/* add spacing character */
474*e124de36Sblymn #ifdef DEBUG
475*e124de36Sblymn 	__CTRACE(__CTRACE_INPUT,
476*e124de36Sblymn 		 "_cursesi_addwchar: add character (%d,%d) 0x%x\n",
477*e124de36Sblymn 		 *y, *x, wch->vals[0]);
478*e124de36Sblymn #endif /* DEBUG */
479*e124de36Sblymn 	(*lnp)->flags |= __ISDIRTY;
480*e124de36Sblymn 	newx = *x + win->ch_off;
481*e124de36Sblymn 	if (newx < *(*lnp)->firstchp)
482*e124de36Sblymn 		*(*lnp)->firstchp = newx;
483*e124de36Sblymn 	if (lp->nsp) {
484*e124de36Sblymn 		__cursesi_free_nsp(lp->nsp);
485*e124de36Sblymn 		lp->nsp = NULL;
486*e124de36Sblymn 	}
487*e124de36Sblymn 
488*e124de36Sblymn 	lp->ch = wch->vals[0];
489*e124de36Sblymn 
490*e124de36Sblymn 	attributes = (win->wattr | wch->attributes)
491*e124de36Sblymn 		& (WA_ATTRIBUTES & ~__COLOR);
492*e124de36Sblymn 	if (wch->attributes & __COLOR)
493*e124de36Sblymn 		attributes |= wch->attributes & __COLOR;
494*e124de36Sblymn 	else if (win->wattr & __COLOR)
495*e124de36Sblymn 		attributes |= win->wattr & __COLOR;
496*e124de36Sblymn 	if (attributes & __COLOR)
497*e124de36Sblymn 		lp->attr = attributes | (win->battr & ~__COLOR);
498*e124de36Sblymn 	else
499*e124de36Sblymn 		lp->attr = attributes | win->battr;
500*e124de36Sblymn 
501*e124de36Sblymn 	SET_WCOL(*lp, cw);
502*e124de36Sblymn 
503*e124de36Sblymn #ifdef DEBUG
504*e124de36Sblymn 	__CTRACE(__CTRACE_INPUT,
505*e124de36Sblymn 		 "_cursesi_addwchar: add spacing char 0x%x, attr 0x%x\n",
506*e124de36Sblymn 		 lp->ch, lp->attr);
507*e124de36Sblymn #endif /* DEBUG */
508*e124de36Sblymn 
509*e124de36Sblymn 	if (wch->elements > 1) {
510*e124de36Sblymn 		for (i = 1; i < wch->elements; i++) {
511*e124de36Sblymn 			np = (nschar_t *)malloc(sizeof(nschar_t));
512*e124de36Sblymn 			if (!np)
513*e124de36Sblymn 				return ERR;;
514*e124de36Sblymn 			np->ch = wch->vals[i];
515*e124de36Sblymn 			np->next = lp->nsp;
516*e124de36Sblymn #ifdef DEBUG
517*e124de36Sblymn 			__CTRACE(__CTRACE_INPUT,
518*e124de36Sblymn 			    "_cursesi_addwchar: add non-spacing char 0x%x\n", np->ch);
519*e124de36Sblymn #endif /* DEBUG */
520*e124de36Sblymn 			lp->nsp = np;
521*e124de36Sblymn 		}
522*e124de36Sblymn 	}
523*e124de36Sblymn #ifdef DEBUG
524*e124de36Sblymn 	__CTRACE(__CTRACE_INPUT, "_cursesi_addwchar: non-spacing list header: %p\n",
525*e124de36Sblymn 	    lp->nsp);
526*e124de36Sblymn 	__CTRACE(__CTRACE_INPUT, "_cursesi_addwchar: add rest columns (%d:%d)\n",
527*e124de36Sblymn 		sx + 1, sx + cw - 1);
528*e124de36Sblymn #endif /* DEBUG */
529*e124de36Sblymn 	for (tp = lp + 1, *x = sx + 1; *x - sx <= cw - 1; tp++, (*x)++) {
530*e124de36Sblymn 		if (tp->nsp) {
531*e124de36Sblymn 			__cursesi_free_nsp(tp->nsp);
532*e124de36Sblymn 			tp->nsp = NULL;
533*e124de36Sblymn 		}
534*e124de36Sblymn 		tp->ch = wch->vals[0];
535*e124de36Sblymn 		tp->attr = lp->attr & WA_ATTRIBUTES;
536*e124de36Sblymn 		/* Mark as "continuation" cell */
537*e124de36Sblymn 		tp->attr |= __WCWIDTH;
538*e124de36Sblymn 	}
539*e124de36Sblymn 	if (*x == win->maxx) {
540*e124de36Sblymn 		(*lnp)->flags |= __ISPASTEOL;
541*e124de36Sblymn 		newx = win->maxx - 1 + win->ch_off;
542*e124de36Sblymn 		if (newx > *(*lnp)->lastchp)
543*e124de36Sblymn 			*(*lnp)->lastchp = newx;
544*e124de36Sblymn 		__touchline(win, *y, sx, (int) win->maxx - 1);
545*e124de36Sblymn 		win->curx = sx;
546*e124de36Sblymn 	} else {
547*e124de36Sblymn 		win->curx = *x;
548*e124de36Sblymn 
549*e124de36Sblymn 		/* clear the remining of the current characer */
550*e124de36Sblymn 		if (*x && *x < win->maxx) {
551*e124de36Sblymn 			ex = sx + cw;
552*e124de36Sblymn 			tp = &win->lines[*y]->line[ex];
553*e124de36Sblymn 			while (ex < win->maxx && WCOL(*tp) < 0) {
554*e124de36Sblymn #ifdef DEBUG
555*e124de36Sblymn 				__CTRACE(__CTRACE_INPUT,
556*e124de36Sblymn 					 "_cursesi_addwchar: clear "
557*e124de36Sblymn 					 "remaining of current char (%d,%d)nn",
558*e124de36Sblymn 					 *y, ex);
559*e124de36Sblymn #endif /* DEBUG */
560*e124de36Sblymn 				tp->ch = (wchar_t) btowc((int) win->bch);
561*e124de36Sblymn 				if (_cursesi_copy_nsp(win->bnsp, tp) == ERR)
562*e124de36Sblymn 					return ERR;
563*e124de36Sblymn 				tp->attr = win->battr;
564*e124de36Sblymn 				SET_WCOL(*tp, 1);
565*e124de36Sblymn 				tp++, ex++;
566*e124de36Sblymn 			}
567*e124de36Sblymn 			newx = ex - 1 + win->ch_off;
568*e124de36Sblymn 			if (newx > *(*lnp)->lastchp)
569*e124de36Sblymn 				*(*lnp)->lastchp = newx;
570*e124de36Sblymn 			__touchline(win, *y, sx, ex - 1);
571*e124de36Sblymn 		}
572*e124de36Sblymn 	}
573*e124de36Sblymn 
574*e124de36Sblymn #ifdef DEBUG
575*e124de36Sblymn 	__CTRACE(__CTRACE_INPUT, "add_wch: %d : 0x%x\n", lp->ch, lp->attr);
576*e124de36Sblymn #endif /* DEBUG */
577*e124de36Sblymn 	return OK;
578*e124de36Sblymn #endif
579*e124de36Sblymn }
580