xref: /netbsd-src/lib/libcurses/add_wchstr.c (revision 6348e3f32a4431b45d07e1da16fd7b12725a45e7)
1*6348e3f3Sblymn /*   $NetBSD: add_wchstr.c,v 1.15 2024/12/23 02:58:03 blymn Exp $ */
2fa0b432bSblymn 
3fa0b432bSblymn /*
4fa0b432bSblymn  * Copyright (c) 2005 The NetBSD Foundation Inc.
5fa0b432bSblymn  * All rights reserved.
6fa0b432bSblymn  *
7fa0b432bSblymn  * This code is derived from code donated to the NetBSD Foundation
8fa0b432bSblymn  * by Ruibiao Qiu <ruibiao@arl.wustl.edu,ruibiao@gmail.com>.
9fa0b432bSblymn  *
10fa0b432bSblymn  *
11fa0b432bSblymn  * Redistribution and use in source and binary forms, with or without
12fa0b432bSblymn  * modification, are permitted provided that the following conditions
13fa0b432bSblymn  * are met:
14fa0b432bSblymn  * 1. Redistributions of source code must retain the above copyright
15fa0b432bSblymn  *    notice, this list of conditions and the following disclaimer.
16fa0b432bSblymn  * 2. Redistributions in binary form must reproduce the above copyright
17fa0b432bSblymn  *    notice, this list of conditions and the following disclaimer in the
18fa0b432bSblymn  *    documentation and/or other materials provided with the distribution.
19fa0b432bSblymn  * 3. Neither the name of the NetBSD Foundation nor the names of its
20fa0b432bSblymn  *    contributors may be used to endorse or promote products derived
21fa0b432bSblymn  *    from this software without specific prior written permission.
22fa0b432bSblymn  *
23fa0b432bSblymn  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
24fa0b432bSblymn  * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
25fa0b432bSblymn  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
26fa0b432bSblymn  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27fa0b432bSblymn  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28fa0b432bSblymn  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29fa0b432bSblymn  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30fa0b432bSblymn  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31fa0b432bSblymn  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32fa0b432bSblymn  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33fa0b432bSblymn  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34fa0b432bSblymn  * SUCH DAMAGE.
35fa0b432bSblymn  */
36fa0b432bSblymn 
37fa0b432bSblymn #include <sys/cdefs.h>
38fa0b432bSblymn #ifndef lint
39*6348e3f3Sblymn __RCSID("$NetBSD: add_wchstr.c,v 1.15 2024/12/23 02:58:03 blymn Exp $");
40fa0b432bSblymn #endif				/* not lint */
41fa0b432bSblymn 
42fa0b432bSblymn #include <stdlib.h>
43fa0b432bSblymn 
44fa0b432bSblymn #include "curses.h"
45fa0b432bSblymn #include "curses_private.h"
46fa0b432bSblymn 
47fa0b432bSblymn /*
48fa0b432bSblymn  * add_wchstr --
49fa0b432bSblymn  *  Add a wide string to stdscr starting at (_cury, _curx).
50fa0b432bSblymn  */
51fa0b432bSblymn int
52fa0b432bSblymn add_wchstr(const cchar_t *wchstr)
53fa0b432bSblymn {
54fa0b432bSblymn 	return wadd_wchnstr(stdscr, wchstr, -1);
55fa0b432bSblymn }
56fa0b432bSblymn 
57fa0b432bSblymn 
58fa0b432bSblymn /*
59fa0b432bSblymn  * wadd_wchstr --
60fa0b432bSblymn  *      Add a string to the given window starting at (_cury, _curx).
61fa0b432bSblymn  */
62fa0b432bSblymn int
63fa0b432bSblymn wadd_wchstr(WINDOW *win, const cchar_t *wchstr)
64fa0b432bSblymn {
65fa0b432bSblymn 	return wadd_wchnstr(win, wchstr, -1);
66fa0b432bSblymn }
67fa0b432bSblymn 
68fa0b432bSblymn 
69fa0b432bSblymn /*
70fa0b432bSblymn  * add_wchnstr --
71fa0b432bSblymn  *      Add a string (at most n characters) to stdscr starting
72fa0b432bSblymn  *	at (_cury, _curx).  If n is negative, add the entire string.
73fa0b432bSblymn  */
74fa0b432bSblymn int
75fa0b432bSblymn add_wchnstr(const cchar_t *wchstr, int n)
76fa0b432bSblymn {
77fa0b432bSblymn 	return wadd_wchnstr(stdscr, wchstr, n);
78fa0b432bSblymn }
79fa0b432bSblymn 
80fa0b432bSblymn 
81fa0b432bSblymn /*
82fa0b432bSblymn  * mvadd_wchstr --
83fa0b432bSblymn  *      Add a string to stdscr starting at (y, x)
84fa0b432bSblymn  */
85fa0b432bSblymn int
86fa0b432bSblymn mvadd_wchstr(int y, int x, const cchar_t *wchstr)
87fa0b432bSblymn {
88fa0b432bSblymn 	return mvwadd_wchnstr(stdscr, y, x, wchstr, -1);
89fa0b432bSblymn }
90fa0b432bSblymn 
91fa0b432bSblymn 
92fa0b432bSblymn /*
93fa0b432bSblymn  * mvwadd_wchstr --
94fa0b432bSblymn  *      Add a string to the given window starting at (y, x)
95fa0b432bSblymn  */
96fa0b432bSblymn int
97fa0b432bSblymn mvwadd_wchstr(WINDOW *win, int y, int x, const cchar_t *wchstr)
98fa0b432bSblymn {
99fa0b432bSblymn 	return mvwadd_wchnstr(win, y, x, wchstr, -1);
100fa0b432bSblymn }
101fa0b432bSblymn 
102fa0b432bSblymn 
103fa0b432bSblymn /*
104fa0b432bSblymn  * mvadd_wchnstr --
105fa0b432bSblymn  *      Add a string of at most n characters to stdscr
106fa0b432bSblymn  *      starting at (y, x).
107fa0b432bSblymn  */
108fa0b432bSblymn int
109fa0b432bSblymn mvadd_wchnstr(int y, int x, const cchar_t *wchstr, int n)
110fa0b432bSblymn {
111fa0b432bSblymn 	return mvwadd_wchnstr(stdscr, y, x, wchstr, n);
112fa0b432bSblymn }
113fa0b432bSblymn 
114fa0b432bSblymn 
115fa0b432bSblymn /*
116fa0b432bSblymn  * mvwadd_wchnstr --
117fa0b432bSblymn  *      Add a string of at most n characters to the given window
118fa0b432bSblymn  *      starting at (y, x).
119fa0b432bSblymn  */
120fa0b432bSblymn int
121fa0b432bSblymn mvwadd_wchnstr(WINDOW *win, int y, int x, const cchar_t *wchstr, int n)
122fa0b432bSblymn {
1232a780e62Sblymn 	if (wmove(win, y, x) == ERR)
124fa0b432bSblymn 		return ERR;
125fa0b432bSblymn 
126fa0b432bSblymn 	return wadd_wchnstr(win, wchstr, n);
127fa0b432bSblymn }
128fa0b432bSblymn 
129fa0b432bSblymn 
130fa0b432bSblymn /*
131fa0b432bSblymn  * wadd_wchnstr --
132fa0b432bSblymn  *	Add a string (at most n wide characters) to the given window
133fa0b432bSblymn  *	starting at (_cury, _curx).  If n is -1, add the entire string.
134fa0b432bSblymn  */
135fa0b432bSblymn int
136fa0b432bSblymn wadd_wchnstr(WINDOW *win, const cchar_t *wchstr, int n)
137fa0b432bSblymn {
138fa0b432bSblymn 	const cchar_t *chp;
139fa0b432bSblymn 	wchar_t wc;
140fa0b432bSblymn 	int cw, x, y, sx, ex, newx, i, cnt;
141fa0b432bSblymn 	__LDATA *lp, *tp;
142fa0b432bSblymn 	nschar_t *np, *tnp;
143fa0b432bSblymn 	__LINE *lnp;
144fa0b432bSblymn 
145e124de36Sblymn 	__CTRACE(__CTRACE_INPUT,
146e124de36Sblymn 	    "wadd_wchnstr: win = %p, wchstr = %p, n = %d\n", win, wchstr, n);
147fa0b432bSblymn 
148*6348e3f3Sblymn 	if (__predict_false(win == NULL))
149*6348e3f3Sblymn 		return ERR;
150*6348e3f3Sblymn 
151fa0b432bSblymn 	if (!wchstr)
152fa0b432bSblymn 		return OK;
153fa0b432bSblymn 
154fa0b432bSblymn 	/* compute length of the cchar string */
155fa0b432bSblymn 	if (n < -1)
156fa0b432bSblymn 		return ERR;
157fa0b432bSblymn 	if (n >= 0)
158fa0b432bSblymn 		for (chp = wchstr, cnt = 0; n && chp->vals[0];
159fa0b432bSblymn 			n--, chp++, ++cnt);
160fa0b432bSblymn 	else
161fa0b432bSblymn 		for (chp = wchstr, cnt = 0; chp->vals[0]; chp++, ++cnt);
162e124de36Sblymn 	__CTRACE(__CTRACE_INPUT, "wadd_wchnstr: len=%d\n", cnt);
163fa0b432bSblymn 	chp = wchstr;
164fa0b432bSblymn 	x = win->curx;
165fa0b432bSblymn 	y = win->cury;
16643d5eb45Sroy 	lp = &win->alines[y]->line[x];
16743d5eb45Sroy 	lnp = win->alines[y];
168fa0b432bSblymn 
169f1942931Sblymn 	cw = (*lp).wcols;
170fa0b432bSblymn 	if (cw >= 0) {
171fa0b432bSblymn 		sx = x;
172fa0b432bSblymn 	} else {
173fa0b432bSblymn 		if (wcwidth(chp->vals[0])) {
174fa0b432bSblymn 			/* clear the partial character before cursor */
175fa0b432bSblymn 			for (tp = lp + cw; tp < lp; tp++) {
176301bf8ccSblymn 				tp->ch = win->bch;
177fa0b432bSblymn 				if (_cursesi_copy_nsp(win->bnsp, tp) == ERR)
178fa0b432bSblymn 					return ERR;
179fa0b432bSblymn 				tp->attr = win->battr;
180ee6c5161Sblymn 				tp->wcols = 1;
181ee6c5161Sblymn 				tp->cflags = CA_BACKGROUND;
182fa0b432bSblymn 				np = tp->nsp;
183fa0b432bSblymn 			}
184fa0b432bSblymn 		} else {
185fa0b432bSblymn 			/* move to the start of current char */
186fa0b432bSblymn 			lp += cw;
187fa0b432bSblymn 			x += cw;
188fa0b432bSblymn 		}
189fa0b432bSblymn 		sx = x + cw;
190fa0b432bSblymn 	}
191fa0b432bSblymn 	lnp->flags |= __ISDIRTY;
192fa0b432bSblymn 	newx = sx + win->ch_off;
193fa0b432bSblymn 	if (newx < *lnp->firstchp)
194fa0b432bSblymn 		*lnp->firstchp = newx;
195fa0b432bSblymn 
196fa0b432bSblymn 	/* add characters in the string */
197fa0b432bSblymn 	ex = x;
198fa0b432bSblymn 	while (cnt) {
199e124de36Sblymn 		x = ex;
200fa0b432bSblymn 		wc = chp->vals[0];
201e124de36Sblymn 		__CTRACE(__CTRACE_INPUT, "wadd_wchnstr: adding %x", wc);
202fa0b432bSblymn 		cw = wcwidth(wc);
203452834f2Sdrochner 		if (cw < 0)
204452834f2Sdrochner 			cw = 1;
205fa0b432bSblymn 		if (cw) {
206fa0b432bSblymn 			/* spacing character */
207e124de36Sblymn 			__CTRACE(__CTRACE_INPUT,
208e124de36Sblymn 			    " as a spacing char(width=%d)\n", cw);
209fa0b432bSblymn 			if (cw > win->maxx - ex) {
210fa0b432bSblymn 				/* clear to EOL */
211fa0b432bSblymn 				while (ex < win->maxx) {
212301bf8ccSblymn 					lp->ch = win->bch;
213fa0b432bSblymn 					if (_cursesi_copy_nsp(win->bnsp, lp)
214fa0b432bSblymn 					    == ERR)
215fa0b432bSblymn 						return ERR;
216fa0b432bSblymn 					lp->attr = win->battr;
217ee6c5161Sblymn 					lp->cflags = CA_BACKGROUND;
218f1942931Sblymn 					(*lp).wcols = 1;
219fa0b432bSblymn 					lp++, ex++;
220fa0b432bSblymn 				}
221fa0b432bSblymn 				ex = win->maxx - 1;
222fa0b432bSblymn 				break;
223fa0b432bSblymn 			}
224fa0b432bSblymn 			/* this could combine with the insertion of
225fa0b432bSblymn 			 * non-spacing char */
226fa0b432bSblymn 			np = lp->nsp;
227fa0b432bSblymn 			if (np) {
228fa0b432bSblymn 				while (np) {
229fa0b432bSblymn 					tnp = np->next;
230fa0b432bSblymn 					free(np);
231fa0b432bSblymn 					np = tnp;
232fa0b432bSblymn 				}
233fa0b432bSblymn 				lp->nsp = NULL;
234fa0b432bSblymn 			}
235fa0b432bSblymn 			lp->ch = chp->vals[0];
236fa0b432bSblymn 			lp->attr = chp->attributes & WA_ATTRIBUTES;
237a7d2c216Sblymn 			lp->cflags &= ~CA_BACKGROUND;
238f1942931Sblymn 			(*lp).wcols = cw;
239fa0b432bSblymn 			if (chp->elements > 1) {
240fa0b432bSblymn 				for (i = 1; i < chp->elements; i++) {
241fa0b432bSblymn 					np = (nschar_t *)
242fa0b432bSblymn 						malloc(sizeof(nschar_t));
243fa0b432bSblymn 					if (!np)
244fa0b432bSblymn 						return ERR;
245fa0b432bSblymn 					np->ch = chp->vals[i];
246fa0b432bSblymn 					np->next = lp->nsp;
247fa0b432bSblymn 					lp->nsp = np;
248fa0b432bSblymn 				}
249fa0b432bSblymn 			}
250fa0b432bSblymn 			lp++, ex++;
251e124de36Sblymn 			__CTRACE(__CTRACE_INPUT,
252e124de36Sblymn 			    "wadd_wchnstr: ex = %d, x = %d, cw = %d\n",
253e124de36Sblymn 			    ex, x, cw);
254fa0b432bSblymn 			while (ex - x <= cw - 1) {
255fa0b432bSblymn 				np = lp->nsp;
256fa0b432bSblymn 				if (np) {
257fa0b432bSblymn 					while (np) {
258fa0b432bSblymn 						tnp = np->next;
259fa0b432bSblymn 						free(np);
260fa0b432bSblymn 						np = tnp;
261fa0b432bSblymn 					}
262fa0b432bSblymn 					lp->nsp = NULL;
263fa0b432bSblymn 				}
264fa0b432bSblymn 				lp->ch = chp->vals[0];
265fa0b432bSblymn 				lp->attr = chp->attributes & WA_ATTRIBUTES;
266ee6c5161Sblymn 				lp->cflags &= ~CA_BACKGROUND;
267ee6c5161Sblymn 				lp->cflags |= CA_CONTINUATION;
268f1942931Sblymn 				(*lp).wcols = x - ex;
269fa0b432bSblymn 				lp++, ex++;
270fa0b432bSblymn 			}
271fa0b432bSblymn 		} else {
272fa0b432bSblymn 			/* non-spacing character */
273e124de36Sblymn 			__CTRACE(__CTRACE_INPUT,
274e124de36Sblymn 			    "wadd_wchnstr: as non-spacing char");
275fa0b432bSblymn 			for (i = 0; i < chp->elements; i++) {
2768a48cf66Schristos 				np = malloc(sizeof(nschar_t));
277fa0b432bSblymn 				if (!np)
278fa0b432bSblymn 					return ERR;
279fa0b432bSblymn 				np->ch = chp->vals[i];
280fa0b432bSblymn 				np->next = lp->nsp;
281fa0b432bSblymn 				lp->nsp = np;
282fa0b432bSblymn 			}
283fa0b432bSblymn 		}
284fa0b432bSblymn 		cnt--, chp++;
285fa0b432bSblymn 	}
286fa0b432bSblymn #ifdef DEBUG
287fa0b432bSblymn 	for (i = sx; i < ex; i++) {
288e124de36Sblymn 		__CTRACE(__CTRACE_INPUT, "wadd_wchnstr: (%d,%d)=(%x,%x,%p)\n",
28943d5eb45Sroy 		    win->cury, i, win->alines[win->cury]->line[i].ch,
29043d5eb45Sroy 		    win->alines[win->cury]->line[i].attr,
29143d5eb45Sroy 		    win->alines[win->cury]->line[i].nsp);
292fa0b432bSblymn 	}
293fa0b432bSblymn #endif /* DEBUG */
294fa0b432bSblymn 	lnp->flags |= __ISDIRTY;
295fa0b432bSblymn 	newx = ex + win->ch_off;
296fa0b432bSblymn 	if (newx > *lnp->lastchp)
297fa0b432bSblymn 		*lnp->lastchp = newx;
298fa0b432bSblymn 	__touchline(win, y, sx, ex);
299fa0b432bSblymn 
300fa0b432bSblymn 	return OK;
301fa0b432bSblymn }
302