xref: /netbsd-src/lib/libcurses/get_wstr.c (revision 6348e3f32a4431b45d07e1da16fd7b12725a45e7)
1*6348e3f3Sblymn /*   $NetBSD: get_wstr.c,v 1.12 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: get_wstr.c,v 1.12 2024/12/23 02:58:03 blymn Exp $");
40fa0b432bSblymn #endif						  /* not lint */
41fa0b432bSblymn 
42fa0b432bSblymn #include "curses.h"
43fa0b432bSblymn #include "curses_private.h"
44fa0b432bSblymn 
45619b7f0eSjdc /* prototypes for private functions */
46619b7f0eSjdc static int __wgetn_wstr(WINDOW *, wchar_t *, int);
47619b7f0eSjdc 
48fa0b432bSblymn /*
49fa0b432bSblymn  * getn_wstr --
50fa0b432bSblymn  *	Get a string (of maximum n) characters from stdscr starting at
51fa0b432bSblymn  *	(cury, curx).
52fa0b432bSblymn  */
53fa0b432bSblymn int
54fa0b432bSblymn getn_wstr(wchar_t *wstr, int n)
55fa0b432bSblymn {
56fa0b432bSblymn 	return wgetn_wstr(stdscr, wstr, n);
57fa0b432bSblymn }
58fa0b432bSblymn 
59fa0b432bSblymn /*
60fa0b432bSblymn  * get_wstr --
61fa0b432bSblymn  *	Get a string from stdscr starting at (cury, curx).
62fa0b432bSblymn  */
63fa0b432bSblymn __warn_references(get_wstr,
6454391ee9Srillig 	"warning: this program uses get_wstr(), which is unsafe.")
65fa0b432bSblymn int
66fa0b432bSblymn get_wstr(wchar_t *wstr)
67fa0b432bSblymn {
68fa0b432bSblymn 	return wget_wstr(stdscr, wstr);
69fa0b432bSblymn }
70fa0b432bSblymn 
71fa0b432bSblymn /*
72fa0b432bSblymn  * mvgetn_wstr --
73fa0b432bSblymn  *  Get a string (of maximum n) characters from stdscr starting at (y, x).
74fa0b432bSblymn  */
75fa0b432bSblymn int
76fa0b432bSblymn mvgetn_wstr(int y, int x, wchar_t *wstr, int n)
77fa0b432bSblymn {
78fa0b432bSblymn 	return mvwgetn_wstr(stdscr, y, x, wstr, n);
79fa0b432bSblymn }
80fa0b432bSblymn 
81fa0b432bSblymn /*
82fa0b432bSblymn  * mvget_wstr --
83fa0b432bSblymn  *	  Get a string from stdscr starting at (y, x).
84fa0b432bSblymn  */
85fa0b432bSblymn __warn_references(mvget_wstr,
8654391ee9Srillig 	"warning: this program uses mvget_wstr(), which is unsafe.")
87fa0b432bSblymn int
88fa0b432bSblymn mvget_wstr(int y, int x, wchar_t *wstr)
89fa0b432bSblymn {
90fa0b432bSblymn 	return mvwget_wstr(stdscr, y, x, wstr);
91fa0b432bSblymn }
92fa0b432bSblymn 
93fa0b432bSblymn /*
94fa0b432bSblymn  * mvwgetn_wstr --
95fa0b432bSblymn  *  Get a string (of maximum n) characters from the given window starting
96fa0b432bSblymn  *	at (y, x).
97fa0b432bSblymn  */
98fa0b432bSblymn int
99fa0b432bSblymn mvwgetn_wstr(WINDOW *win, int y, int x, wchar_t *wstr, int n)
100fa0b432bSblymn {
1012a780e62Sblymn 	if (wmove(win, y, x) == ERR)
102fa0b432bSblymn 		return ERR;
103fa0b432bSblymn 
104fa0b432bSblymn 	return wgetn_wstr(win, wstr, n);
105fa0b432bSblymn }
106fa0b432bSblymn 
107fa0b432bSblymn /*
108fa0b432bSblymn  * mvwget_wstr --
109fa0b432bSblymn  *	  Get a string from the given window starting at (y, x).
110fa0b432bSblymn  */
111fa0b432bSblymn __warn_references(mvget_wstr,
11254391ee9Srillig 	"warning: this program uses mvget_wstr(), which is unsafe.")
113fa0b432bSblymn int
114fa0b432bSblymn mvwget_wstr(WINDOW *win, int y, int x, wchar_t *wstr)
115fa0b432bSblymn {
1162a780e62Sblymn 	if (wmove(win, y, x) == ERR)
117fa0b432bSblymn 		return ERR;
118fa0b432bSblymn 
119fa0b432bSblymn 	return wget_wstr(win, wstr);
120fa0b432bSblymn }
121fa0b432bSblymn 
122fa0b432bSblymn /*
123fa0b432bSblymn  * wget_wstr --
124fa0b432bSblymn  *	Get a string starting at (cury, curx).
125fa0b432bSblymn  */
126fa0b432bSblymn __warn_references(wget_wstr,
12754391ee9Srillig 	"warning: this program uses wget_wstr(), which is unsafe.")
128fa0b432bSblymn int
129fa0b432bSblymn wget_wstr(WINDOW *win, wchar_t *wstr)
130fa0b432bSblymn {
131fa0b432bSblymn 	return __wgetn_wstr(win, wstr, -1);
132fa0b432bSblymn }
133fa0b432bSblymn 
134fa0b432bSblymn /*
135fa0b432bSblymn  * wgetn_wstr --
136fa0b432bSblymn  *	Get a string starting at (cury, curx).
137fa0b432bSblymn  *	Note that n <  2 means that we return ERR (SUSv2 specification).
138fa0b432bSblymn  */
139fa0b432bSblymn int
140fa0b432bSblymn wgetn_wstr(WINDOW *win, wchar_t *wstr, int n)
141fa0b432bSblymn {
142fa0b432bSblymn 	if (n < 1)
14350a63ac8Sroy 		return ERR;
144fa0b432bSblymn 	if (n == 1) {
145fa0b432bSblymn 		wstr[0] = L'\0';
14650a63ac8Sroy 		return ERR;
147fa0b432bSblymn 	}
148fa0b432bSblymn 	return __wgetn_wstr(win, wstr, n);
149fa0b432bSblymn }
150fa0b432bSblymn 
151fa0b432bSblymn /*
152fa0b432bSblymn  * __wgetn_wstr --
153fa0b432bSblymn  *	The actual implementation.
154fa0b432bSblymn  *	Note that we include a trailing L'\0' for safety, so str will contain
155fa0b432bSblymn  *	at most n - 1 other characters.
156fa0b432bSblymn  */
157fa0b432bSblymn int
158fa0b432bSblymn __wgetn_wstr(WINDOW *win, wchar_t *wstr, int n)
159fa0b432bSblymn {
160fa0b432bSblymn 	wchar_t *ostr, ec, kc, sc[ 2 ];
161e124de36Sblymn 	int oldx, remain;
162fa0b432bSblymn 	wint_t wc;
163fa0b432bSblymn 	cchar_t cc;
164fa0b432bSblymn 
165*6348e3f3Sblymn 	if (__predict_false(win == NULL))
166*6348e3f3Sblymn 		return ERR;
167*6348e3f3Sblymn 
168fa0b432bSblymn 	ostr = wstr;
169fa0b432bSblymn 	if (erasewchar(&ec) == ERR)
170fa0b432bSblymn 		return ERR;
171fa0b432bSblymn 	if (killwchar(&kc) == ERR)
172fa0b432bSblymn 		return ERR;
173301bf8ccSblymn 	sc[0] = win->bch;
174fa0b432bSblymn 	sc[1] = L'\0';
175fa0b432bSblymn 	setcchar(&cc, sc, win->wattr, 0, NULL);
176fa0b432bSblymn 	oldx = win->curx;
177fa0b432bSblymn 	remain = n - 1;
178fa0b432bSblymn 
179e124de36Sblymn 	while (wget_wch(win, &wc) != ERR
180fa0b432bSblymn 	       && wc != L'\n' && wc != L'\r') {
181e124de36Sblymn 		__CTRACE(__CTRACE_INPUT,
182e124de36Sblymn 		    "__wgetn_wstr: win %p, char 0x%x, remain %d\n",
183fa0b432bSblymn 		    win, wc, remain);
184fa0b432bSblymn 		*wstr = wc;
185fa0b432bSblymn 		touchline(win, win->cury, 1);
186fa0b432bSblymn 		if (wc == ec || wc == KEY_BACKSPACE || wc == KEY_LEFT) {
187fa0b432bSblymn 			*wstr = L'\0';
188fa0b432bSblymn 			if (wstr != ostr) {
189fa0b432bSblymn 				if ((wchar_t)wc == ec) {
190fa0b432bSblymn 					mvwadd_wch(win, win->cury,
191fa0b432bSblymn 						win->curx, &cc);
1922a780e62Sblymn 					wmove(win, win->cury, win->curx - 1);
193fa0b432bSblymn 				}
194fa0b432bSblymn 				if (wc == KEY_BACKSPACE || wc == KEY_LEFT) {
195fa0b432bSblymn 					/* getch() displays the key sequence */
196fa0b432bSblymn 					mvwadd_wch(win, win->cury,
197fa0b432bSblymn 						win->curx - 1, &cc);
198fa0b432bSblymn 					mvwadd_wch(win, win->cury,
199fa0b432bSblymn 						win->curx - 2, &cc);
2002a780e62Sblymn 					wmove(win, win->cury, win->curx - 1);
201fa0b432bSblymn 				}
202fa0b432bSblymn 				wstr--;
203fa0b432bSblymn 				if (n != -1) {
204fa0b432bSblymn 					/* We're counting chars */
205fa0b432bSblymn 					remain++;
206fa0b432bSblymn 				}
207fa0b432bSblymn 			} else { /* str == ostr */
208fa0b432bSblymn 				if (wc == KEY_BACKSPACE || wc == KEY_LEFT)
209fa0b432bSblymn 					/* getch() displays the other keys */
210fa0b432bSblymn 					mvwadd_wch(win, win->cury,
211fa0b432bSblymn 						win->curx - 1, &cc);
2122a780e62Sblymn 				wmove(win, win->cury, oldx);
213fa0b432bSblymn 			}
214fa0b432bSblymn 		} else if (wc == kc) {
215fa0b432bSblymn 			*wstr = L'\0';
216fa0b432bSblymn 			if (wstr != ostr) {
217fa0b432bSblymn 				/* getch() displays the kill character */
218fa0b432bSblymn 				mvwadd_wch(win, win->cury, win->curx - 1, &cc);
219fa0b432bSblymn 				/* Clear the characters from screen and str */
220fa0b432bSblymn 				while (wstr != ostr) {
221fa0b432bSblymn 					mvwadd_wch(win, win->cury,
222fa0b432bSblymn 						win->curx - 1, &cc);
2232a780e62Sblymn 					wmove(win, win->cury, win->curx - 1);
224fa0b432bSblymn 					wstr--;
225fa0b432bSblymn 					if (n != -1)
226fa0b432bSblymn 						/* We're counting chars */
227fa0b432bSblymn 						remain++;
228fa0b432bSblymn 				}
229fa0b432bSblymn 				mvwadd_wch(win, win->cury, win->curx - 1, &cc);
2302a780e62Sblymn 				wmove(win, win->cury, win->curx - 1);
231fa0b432bSblymn 			} else
232fa0b432bSblymn 				/* getch() displays the kill character */
233fa0b432bSblymn 				mvwadd_wch( win, win->cury, oldx, &cc );
2342a780e62Sblymn 			wmove(win, win->cury, oldx);
235fa0b432bSblymn 		} else if (wc >= KEY_MIN && wc <= KEY_MAX) {
236fa0b432bSblymn 			/* get_wch() displays these characters */
237fa0b432bSblymn 			mvwadd_wch( win, win->cury, win->curx - 1, &cc );
2382a780e62Sblymn 			wmove(win, win->cury, win->curx - 1);
239fa0b432bSblymn 		} else {
240fa0b432bSblymn 			if (remain) {
241fa0b432bSblymn 				wstr++;
242fa0b432bSblymn 				remain--;
243fa0b432bSblymn 			} else {
244fa0b432bSblymn 				mvwadd_wch(win, win->cury, win->curx - 1, &cc);
2452a780e62Sblymn 				wmove(win, win->cury, win->curx - 1);
246fa0b432bSblymn 			}
247fa0b432bSblymn 		}
248fa0b432bSblymn 	}
249fa0b432bSblymn 
250fa0b432bSblymn 	if (wc == ERR) {
251fa0b432bSblymn 		*wstr = L'\0';
252fa0b432bSblymn 		return ERR;
253fa0b432bSblymn 	}
254fa0b432bSblymn 	*wstr = L'\0';
255fa0b432bSblymn 	return OK;
256fa0b432bSblymn }
257