xref: /minix3/lib/libcurses/ins_wstr.c (revision 84d9c625bfea59e274550651111ae9edfdc40fbd)
1*84d9c625SLionel Sambuc /*   $NetBSD: ins_wstr.c,v 1.7 2013/10/16 19:59:29 roy Exp $ */
251ffecc1SBen Gras 
351ffecc1SBen Gras /*
451ffecc1SBen Gras  * Copyright (c) 2005 The NetBSD Foundation Inc.
551ffecc1SBen Gras  * All rights reserved.
651ffecc1SBen Gras  *
751ffecc1SBen Gras  * This code is derived from code donated to the NetBSD Foundation
851ffecc1SBen Gras  * by Ruibiao Qiu <ruibiao@arl.wustl.edu,ruibiao@gmail.com>.
951ffecc1SBen Gras  *
1051ffecc1SBen Gras  *
1151ffecc1SBen Gras  * Redistribution and use in source and binary forms, with or without
1251ffecc1SBen Gras  * modification, are permitted provided that the following conditions
1351ffecc1SBen Gras  * are met:
1451ffecc1SBen Gras  * 1. Redistributions of source code must retain the above copyright
1551ffecc1SBen Gras  *	notice, this list of conditions and the following disclaimer.
1651ffecc1SBen Gras  * 2. Redistributions in binary form must reproduce the above copyright
1751ffecc1SBen Gras  *	notice, this list of conditions and the following disclaimer in the
1851ffecc1SBen Gras  *	documentation and/or other materials provided with the distribution.
1951ffecc1SBen Gras  * 3. Neither the name of the NetBSD Foundation nor the names of its
2051ffecc1SBen Gras  *	contributors may be used to endorse or promote products derived
2151ffecc1SBen Gras  *	from this software without specific prior written permission.
2251ffecc1SBen Gras  *
2351ffecc1SBen Gras  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
2451ffecc1SBen Gras  * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
2551ffecc1SBen Gras  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
2651ffecc1SBen Gras  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2751ffecc1SBen Gras  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2851ffecc1SBen Gras  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2951ffecc1SBen Gras  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3051ffecc1SBen Gras  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3151ffecc1SBen Gras  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3251ffecc1SBen Gras  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3351ffecc1SBen Gras  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3451ffecc1SBen Gras  * SUCH DAMAGE.
3551ffecc1SBen Gras  */
3651ffecc1SBen Gras 
3751ffecc1SBen Gras #include <sys/cdefs.h>
3851ffecc1SBen Gras #ifndef lint
39*84d9c625SLionel Sambuc __RCSID("$NetBSD: ins_wstr.c,v 1.7 2013/10/16 19:59:29 roy Exp $");
4051ffecc1SBen Gras #endif						  /* not lint */
4151ffecc1SBen Gras 
4251ffecc1SBen Gras #include <string.h>
4351ffecc1SBen Gras #include <stdlib.h>
4451ffecc1SBen Gras 
4551ffecc1SBen Gras #include "curses.h"
4651ffecc1SBen Gras #include "curses_private.h"
4751ffecc1SBen Gras 
4851ffecc1SBen Gras /*
4951ffecc1SBen Gras  * ins_wstr --
5051ffecc1SBen Gras  *	insert a multi-character wide-character string into the current window
5151ffecc1SBen Gras  */
5251ffecc1SBen Gras int
ins_wstr(const wchar_t * wstr)5351ffecc1SBen Gras ins_wstr(const wchar_t *wstr)
5451ffecc1SBen Gras {
5551ffecc1SBen Gras 	return wins_wstr(stdscr, wstr);
5651ffecc1SBen Gras }
5751ffecc1SBen Gras 
5851ffecc1SBen Gras /*
5951ffecc1SBen Gras  * ins_nwstr --
6051ffecc1SBen Gras  *	insert a multi-character wide-character string into the current window
6151ffecc1SBen Gras  *	with at most n characters
6251ffecc1SBen Gras  */
6351ffecc1SBen Gras int
ins_nwstr(const wchar_t * wstr,int n)6451ffecc1SBen Gras ins_nwstr(const wchar_t *wstr, int n)
6551ffecc1SBen Gras {
6651ffecc1SBen Gras 	return wins_nwstr(stdscr, wstr, n);
6751ffecc1SBen Gras }
6851ffecc1SBen Gras 
6951ffecc1SBen Gras /*
7051ffecc1SBen Gras  * mvins_wstr --
7151ffecc1SBen Gras  *	  Do an insert-string on the line at (y, x).
7251ffecc1SBen Gras  */
7351ffecc1SBen Gras int
mvins_wstr(int y,int x,const wchar_t * wstr)7451ffecc1SBen Gras mvins_wstr(int y, int x, const wchar_t *wstr)
7551ffecc1SBen Gras {
7651ffecc1SBen Gras 	return mvwins_wstr(stdscr, y, x, wstr);
7751ffecc1SBen Gras }
7851ffecc1SBen Gras 
7951ffecc1SBen Gras /*
8051ffecc1SBen Gras  * mvins_nwstr --
8151ffecc1SBen Gras  *	  Do an insert-n-string on the line at (y, x).
8251ffecc1SBen Gras  */
8351ffecc1SBen Gras int
mvins_nwstr(int y,int x,const wchar_t * wstr,int n)8451ffecc1SBen Gras mvins_nwstr(int y, int x, const wchar_t *wstr, int n)
8551ffecc1SBen Gras {
8651ffecc1SBen Gras 	return mvwins_nwstr(stdscr, y, x, wstr, n);
8751ffecc1SBen Gras }
8851ffecc1SBen Gras 
8951ffecc1SBen Gras /*
9051ffecc1SBen Gras  * mvwins_wstr --
9151ffecc1SBen Gras  *	  Do an insert-string on the line at (y, x) in the given window.
9251ffecc1SBen Gras  */
9351ffecc1SBen Gras int
mvwins_wstr(WINDOW * win,int y,int x,const wchar_t * wstr)9451ffecc1SBen Gras mvwins_wstr(WINDOW *win, int y, int x, const wchar_t *wstr)
9551ffecc1SBen Gras {
9651ffecc1SBen Gras 	if (wmove(win, y, x) == ERR)
9751ffecc1SBen Gras 		return ERR;
9851ffecc1SBen Gras 
9951ffecc1SBen Gras 	return wins_wstr(stdscr, wstr);
10051ffecc1SBen Gras }
10151ffecc1SBen Gras 
10251ffecc1SBen Gras /*
10351ffecc1SBen Gras  * mvwins_nwstr --
10451ffecc1SBen Gras  *	  Do an insert-n-string on the line at (y, x) in the given window.
10551ffecc1SBen Gras  */
10651ffecc1SBen Gras int
mvwins_nwstr(WINDOW * win,int y,int x,const wchar_t * wstr,int n)10751ffecc1SBen Gras mvwins_nwstr(WINDOW *win, int y, int x, const wchar_t *wstr, int n)
10851ffecc1SBen Gras {
10951ffecc1SBen Gras 	if (wmove(win, y, x) == ERR)
11051ffecc1SBen Gras 		return ERR;
11151ffecc1SBen Gras 
11251ffecc1SBen Gras 	return wins_nwstr(stdscr, wstr, n);
11351ffecc1SBen Gras }
11451ffecc1SBen Gras 
11551ffecc1SBen Gras 
11651ffecc1SBen Gras /*
11751ffecc1SBen Gras  * wins_wstr --
11851ffecc1SBen Gras  *	Do an insert-string on the line, leaving (cury, curx) unchanged.
11951ffecc1SBen Gras  */
12051ffecc1SBen Gras int
wins_wstr(WINDOW * win,const wchar_t * wstr)12151ffecc1SBen Gras wins_wstr(WINDOW *win, const wchar_t *wstr)
12251ffecc1SBen Gras {
12351ffecc1SBen Gras 	return wins_nwstr(win, wstr, -1);
12451ffecc1SBen Gras }
12551ffecc1SBen Gras 
12651ffecc1SBen Gras /*
12751ffecc1SBen Gras  * wins_nwstr --
12851ffecc1SBen Gras  *	Do an insert-n-string on the line, leaving (cury, curx) unchanged.
12951ffecc1SBen Gras  */
13051ffecc1SBen Gras int
wins_nwstr(WINDOW * win,const wchar_t * wstr,int n)13151ffecc1SBen Gras wins_nwstr(WINDOW *win, const wchar_t *wstr, int n)
13251ffecc1SBen Gras {
13351ffecc1SBen Gras #ifndef HAVE_WCHAR
13451ffecc1SBen Gras 	return ERR;
13551ffecc1SBen Gras #else
13651ffecc1SBen Gras 	__LDATA	 *start, *temp1, *temp2;
13751ffecc1SBen Gras 	__LINE	  *lnp;
13851ffecc1SBen Gras 	const wchar_t *scp;
139*84d9c625SLionel Sambuc 	int width, len, sx, x, y, cw, pcw, newx, tabsize;
14051ffecc1SBen Gras 	nschar_t *np;
14151ffecc1SBen Gras 	wchar_t ws[] = L"		";
14251ffecc1SBen Gras 
14351ffecc1SBen Gras 	/* check for leading non-spacing character */
14451ffecc1SBen Gras 	if (!wstr)
14551ffecc1SBen Gras 		return OK;
14651ffecc1SBen Gras 	cw = wcwidth(*wstr);
14751ffecc1SBen Gras 	if (cw < 0)
14851ffecc1SBen Gras 		cw = 1;
14951ffecc1SBen Gras 	if (!cw)
15051ffecc1SBen Gras 		return ERR;
15151ffecc1SBen Gras 
15251ffecc1SBen Gras 	scp = wstr + 1;
15351ffecc1SBen Gras 	width = cw;
15451ffecc1SBen Gras 	len = 1;
15551ffecc1SBen Gras 	n--;
15651ffecc1SBen Gras 	while (*scp) {
15751ffecc1SBen Gras 		int w;
15851ffecc1SBen Gras 		if (!n)
15951ffecc1SBen Gras 			break;
16051ffecc1SBen Gras 		w = wcwidth(*scp);
16151ffecc1SBen Gras 		if (w < 0)
16251ffecc1SBen Gras 			w = 1;
16351ffecc1SBen Gras 		n--, len++, width += w;
16451ffecc1SBen Gras 		scp++;
16551ffecc1SBen Gras 	}
16651ffecc1SBen Gras #ifdef DEBUG
16751ffecc1SBen Gras 	__CTRACE(__CTRACE_INPUT, "wins_nwstr: width=%d,len=%d\n", width, len);
16851ffecc1SBen Gras #endif /* DEBUG */
16951ffecc1SBen Gras 
17051ffecc1SBen Gras 	if (cw > win->maxx - win->curx + 1)
17151ffecc1SBen Gras 		return ERR;
17251ffecc1SBen Gras 	start = &win->alines[win->cury]->line[win->curx];
17351ffecc1SBen Gras 	sx = win->curx;
17451ffecc1SBen Gras 	lnp = win->alines[win->cury];
17551ffecc1SBen Gras 	pcw = WCOL(*start);
17651ffecc1SBen Gras 	if (pcw < 0) {
17751ffecc1SBen Gras 		sx += pcw;
17851ffecc1SBen Gras 		start += pcw;
17951ffecc1SBen Gras 	}
18051ffecc1SBen Gras #ifdef DEBUG
18151ffecc1SBen Gras 	__CTRACE(__CTRACE_INPUT, "wins_nwstr: start@(%d)\n", sx);
18251ffecc1SBen Gras #endif /* DEBUG */
18351ffecc1SBen Gras 	pcw = WCOL(*start);
18451ffecc1SBen Gras 	lnp->flags |= __ISDIRTY;
18551ffecc1SBen Gras 	newx = sx + win->ch_off;
18651ffecc1SBen Gras 	if (newx < *lnp->firstchp)
18751ffecc1SBen Gras 		*lnp->firstchp = newx;
18851ffecc1SBen Gras #ifdef DEBUG
18951ffecc1SBen Gras 	{
19051ffecc1SBen Gras 		__CTRACE(__CTRACE_INPUT, "========before=======\n");
19151ffecc1SBen Gras 		for (x = 0; x < win->maxx; x++)
19251ffecc1SBen Gras 			__CTRACE(__CTRACE_INPUT,
19351ffecc1SBen Gras 			    "wins_nwstr: (%d,%d)=(%x,%x,%p)\n",
19451ffecc1SBen Gras 			    (int) win->cury, x,
19551ffecc1SBen Gras 			    win->alines[win->cury]->line[x].ch,
19651ffecc1SBen Gras 			    win->alines[win->cury]->line[x].attr,
19751ffecc1SBen Gras 			    win->alines[win->cury]->line[x].nsp);
19851ffecc1SBen Gras 	}
19951ffecc1SBen Gras #endif /* DEBUG */
20051ffecc1SBen Gras 
20151ffecc1SBen Gras 	/* shift all complete characters */
20251ffecc1SBen Gras 	if (sx + width + pcw <= win->maxx) {
20351ffecc1SBen Gras #ifdef DEBUG
20451ffecc1SBen Gras 		__CTRACE(__CTRACE_INPUT, "wins_nwstr: shift all characters\n");
20551ffecc1SBen Gras #endif /* DEBUG */
20651ffecc1SBen Gras 		temp1 = &win->alines[win->cury]->line[win->maxx - 1];
20751ffecc1SBen Gras 		temp2 = temp1 - width;
20851ffecc1SBen Gras 		pcw = WCOL(*(temp2 + 1));
20951ffecc1SBen Gras 		if (pcw < 0) {
21051ffecc1SBen Gras #ifdef DEBUG
21151ffecc1SBen Gras 			__CTRACE(__CTRACE_INPUT,
21251ffecc1SBen Gras 			    "wins_nwstr: clear from %d to EOL(%d)\n",
21351ffecc1SBen Gras 			    win->maxx + pcw, win->maxx - 1);
21451ffecc1SBen Gras #endif /* DEBUG */
21551ffecc1SBen Gras 			temp2 += pcw;
21651ffecc1SBen Gras 			while (temp1 > temp2 + width) {
21751ffecc1SBen Gras 				temp1->ch = (wchar_t)btowc((int) win->bch);
21851ffecc1SBen Gras 				if (_cursesi_copy_nsp(win->bnsp, temp1) == ERR)
21951ffecc1SBen Gras 					return ERR;
22051ffecc1SBen Gras 				temp1->attr = win->battr;
22151ffecc1SBen Gras 				SET_WCOL(*temp1, 1);
22251ffecc1SBen Gras #ifdef DEBUG
22351ffecc1SBen Gras 				__CTRACE(__CTRACE_INPUT,
22451ffecc1SBen Gras 				    "wins_nwstr: empty cell(%p)\n", temp1);
22551ffecc1SBen Gras #endif /* DEBUG */
22651ffecc1SBen Gras 				temp1--;
22751ffecc1SBen Gras 			}
22851ffecc1SBen Gras 		}
22951ffecc1SBen Gras 		while (temp2 >= start) {
23051ffecc1SBen Gras 			(void)memcpy(temp1, temp2, sizeof(__LDATA));
23151ffecc1SBen Gras 			temp1--, temp2--;
23251ffecc1SBen Gras 		}
23351ffecc1SBen Gras #ifdef DEBUG
23451ffecc1SBen Gras 		{
23551ffecc1SBen Gras 			__CTRACE(__CTRACE_INPUT, "=====after shift====\n");
23651ffecc1SBen Gras 			for (x = 0; x < win->maxx; x++)
23751ffecc1SBen Gras 				__CTRACE(__CTRACE_INPUT,
23851ffecc1SBen Gras 				    "wins_nwstr: (%d,%d)=(%x,%x,%p)\n",
23951ffecc1SBen Gras 				    (int) win->cury, x,
24051ffecc1SBen Gras 				    win->alines[win->cury]->line[x].ch,
24151ffecc1SBen Gras 				    win->alines[win->cury]->line[x].attr,
24251ffecc1SBen Gras 				    win->alines[win->cury]->line[x].nsp);
24351ffecc1SBen Gras 		}
24451ffecc1SBen Gras #endif /* DEBUG */
24551ffecc1SBen Gras 	}
24651ffecc1SBen Gras 
24751ffecc1SBen Gras 	/* update string columns */
24851ffecc1SBen Gras 	x = win->curx;
24951ffecc1SBen Gras 	y = win->cury;
25051ffecc1SBen Gras 	for (scp = wstr, temp1 = start; len; len--, scp++) {
25151ffecc1SBen Gras 		switch (*scp) {
25251ffecc1SBen Gras 			case L'\b':
25351ffecc1SBen Gras 				if (--x < 0)
25451ffecc1SBen Gras 					x = 0;
25551ffecc1SBen Gras 				win->curx = x;
25651ffecc1SBen Gras 				continue;;
25751ffecc1SBen Gras 			case L'\r':
25851ffecc1SBen Gras 				win->curx = 0;
25951ffecc1SBen Gras 				continue;
26051ffecc1SBen Gras 			case L'\n':
26151ffecc1SBen Gras 				wclrtoeol(win);
26251ffecc1SBen Gras 				if (y == win->scr_b) {
26351ffecc1SBen Gras 					if (!(win->flags & __SCROLLOK))
26451ffecc1SBen Gras 						return ERR;
26551ffecc1SBen Gras 					scroll(win);
26651ffecc1SBen Gras 				}
26751ffecc1SBen Gras 				continue;
26851ffecc1SBen Gras 			case L'\t':
269*84d9c625SLionel Sambuc 				tabsize = win->screen->TABSIZE;
27051ffecc1SBen Gras 				if (wins_nwstr(win, ws,
271*84d9c625SLionel Sambuc 				    min(win->maxx - x, tabsize - (x % tabsize)))
27251ffecc1SBen Gras 				    == ERR)
27351ffecc1SBen Gras 					return ERR;
27451ffecc1SBen Gras 				continue;
27551ffecc1SBen Gras 		}
27651ffecc1SBen Gras 		cw = wcwidth(*scp);
27751ffecc1SBen Gras 		if (cw < 0)
27851ffecc1SBen Gras 			cw = 1;
27951ffecc1SBen Gras 		if (cw) {
28051ffecc1SBen Gras 			/* 1st column */
28151ffecc1SBen Gras 			temp1->ch = (wchar_t)*scp;
28251ffecc1SBen Gras 			temp1->attr = win->wattr;
28351ffecc1SBen Gras 			SET_WCOL(*temp1, cw);
28451ffecc1SBen Gras 			temp1->nsp = NULL;
28551ffecc1SBen Gras #ifdef DEBUG
28651ffecc1SBen Gras 			__CTRACE(__CTRACE_INPUT,
28751ffecc1SBen Gras 			    "wins_nwstr: add spacing char(%x)\n", temp1->ch);
28851ffecc1SBen Gras #endif /* DEBUG */
28951ffecc1SBen Gras 			temp2 = temp1++;
29051ffecc1SBen Gras 			if (cw > 1) {
29151ffecc1SBen Gras 				x = -1;
29251ffecc1SBen Gras 				while (temp1 < temp2 + cw) {
29351ffecc1SBen Gras 					/* the rest columns */
29451ffecc1SBen Gras 					temp1->ch = (wchar_t)*scp;
29551ffecc1SBen Gras 					temp1->attr = win->wattr;
29651ffecc1SBen Gras 					temp1->nsp = NULL;
29751ffecc1SBen Gras 					SET_WCOL(*temp1, x);
29851ffecc1SBen Gras 					temp1++, x--;
29951ffecc1SBen Gras 				}
30051ffecc1SBen Gras 				temp1--;
30151ffecc1SBen Gras 			}
30251ffecc1SBen Gras 		} else {
30351ffecc1SBen Gras 			/* non-spacing character */
30451ffecc1SBen Gras 			np = (nschar_t *)malloc(sizeof(nschar_t));
30551ffecc1SBen Gras 			if (!np)
30651ffecc1SBen Gras 				return ERR;
30751ffecc1SBen Gras 			np->ch = *scp;
30851ffecc1SBen Gras 			np->next = temp1->nsp;
30951ffecc1SBen Gras 			temp1->nsp = np;
31051ffecc1SBen Gras #ifdef DEBUG
31151ffecc1SBen Gras 			__CTRACE(__CTRACE_INPUT,
31251ffecc1SBen Gras 			    "wins_nstr: add non-spacing char(%x)\n", np->ch);
31351ffecc1SBen Gras #endif /* DEBUG */
31451ffecc1SBen Gras 		}
31551ffecc1SBen Gras 	}
31651ffecc1SBen Gras #ifdef DEBUG
31751ffecc1SBen Gras 	{
31851ffecc1SBen Gras 		__CTRACE(__CTRACE_INPUT, "========after=======\n");
31951ffecc1SBen Gras 		for (x = 0; x < win->maxx; x++)
32051ffecc1SBen Gras 			__CTRACE(__CTRACE_INPUT,
32151ffecc1SBen Gras 			    "wins_nwstr: (%d,%d)=(%x,%x,%p)\n",
32251ffecc1SBen Gras 			    (int) win->cury, x,
32351ffecc1SBen Gras 			    win->alines[win->cury]->line[x].ch,
32451ffecc1SBen Gras 			    win->alines[win->cury]->line[x].attr,
32551ffecc1SBen Gras 			    win->alines[win->cury]->line[x].nsp);
32651ffecc1SBen Gras 	}
32751ffecc1SBen Gras #endif /* DEBUG */
32851ffecc1SBen Gras 	newx = win->maxx - 1 + win->ch_off;
32951ffecc1SBen Gras 	if (newx > *lnp->lastchp)
33051ffecc1SBen Gras 		*lnp->lastchp = newx;
33151ffecc1SBen Gras 	__touchline(win, (int) win->cury, sx, (int) win->maxx - 1);
33251ffecc1SBen Gras 	return OK;
33351ffecc1SBen Gras #endif /* HAVE_WCHAR */
33451ffecc1SBen Gras }
335