xref: /openbsd-src/lib/libcurses/widechar/lib_get_wstr.c (revision c7ef0cfc17afcba97172c25e1e3a943e893bc632)
1*c7ef0cfcSnicm /* $OpenBSD: lib_get_wstr.c,v 1.2 2023/10/17 09:52:09 nicm Exp $ */
26bc6570dSnicm 
36bc6570dSnicm /****************************************************************************
4*c7ef0cfcSnicm  * Copyright 2018-2021,2023 Thomas E. Dickey                                *
5*c7ef0cfcSnicm  * Copyright 2002-2009,2011 Free Software Foundation, Inc.                  *
66bc6570dSnicm  *                                                                          *
76bc6570dSnicm  * Permission is hereby granted, free of charge, to any person obtaining a  *
86bc6570dSnicm  * copy of this software and associated documentation files (the            *
96bc6570dSnicm  * "Software"), to deal in the Software without restriction, including      *
106bc6570dSnicm  * without limitation the rights to use, copy, modify, merge, publish,      *
116bc6570dSnicm  * distribute, distribute with modifications, sublicense, and/or sell       *
126bc6570dSnicm  * copies of the Software, and to permit persons to whom the Software is    *
136bc6570dSnicm  * furnished to do so, subject to the following conditions:                 *
146bc6570dSnicm  *                                                                          *
156bc6570dSnicm  * The above copyright notice and this permission notice shall be included  *
166bc6570dSnicm  * in all copies or substantial portions of the Software.                   *
176bc6570dSnicm  *                                                                          *
186bc6570dSnicm  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
196bc6570dSnicm  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
206bc6570dSnicm  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
216bc6570dSnicm  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
226bc6570dSnicm  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
236bc6570dSnicm  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
246bc6570dSnicm  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
256bc6570dSnicm  *                                                                          *
266bc6570dSnicm  * Except as contained in this notice, the name(s) of the above copyright   *
276bc6570dSnicm  * holders shall not be used in advertising or otherwise to promote the     *
286bc6570dSnicm  * sale, use or other dealings in this Software without prior written       *
296bc6570dSnicm  * authorization.                                                           *
306bc6570dSnicm  ****************************************************************************/
316bc6570dSnicm 
326bc6570dSnicm /****************************************************************************
336bc6570dSnicm  *  Author: Thomas E. Dickey                                                *
346bc6570dSnicm  ****************************************************************************/
356bc6570dSnicm 
366bc6570dSnicm /*
376bc6570dSnicm **	lib_get_wstr.c
386bc6570dSnicm **
396bc6570dSnicm **	The routine wgetn_wstr().
406bc6570dSnicm **
416bc6570dSnicm */
426bc6570dSnicm 
436bc6570dSnicm #include <curses.priv.h>
446bc6570dSnicm 
45*c7ef0cfcSnicm MODULE_ID("$Id: lib_get_wstr.c,v 1.2 2023/10/17 09:52:09 nicm Exp $")
466bc6570dSnicm 
476bc6570dSnicm static int
wadd_wint(WINDOW * win,wint_t * src)486bc6570dSnicm wadd_wint(WINDOW *win, wint_t *src)
496bc6570dSnicm {
506bc6570dSnicm     cchar_t tmp;
516bc6570dSnicm     wchar_t wch[2];
526bc6570dSnicm 
536bc6570dSnicm     wch[0] = (wchar_t) (*src);
546bc6570dSnicm     wch[1] = 0;
55*c7ef0cfcSnicm     setcchar(&tmp, wch, A_NORMAL, (short) 0, NULL);
566bc6570dSnicm     return wadd_wch(win, &tmp);
576bc6570dSnicm }
586bc6570dSnicm 
596bc6570dSnicm /*
606bc6570dSnicm  * This wipes out the last character, no matter whether it was a tab, control
616bc6570dSnicm  * or other character, and handles reverse wraparound.
626bc6570dSnicm  */
636bc6570dSnicm static wint_t *
WipeOut(WINDOW * win,int y,int x,wint_t * first,wint_t * last,int echoed)64*c7ef0cfcSnicm WipeOut(WINDOW *win, int y, int x, wint_t *first, wint_t *last, int echoed)
656bc6570dSnicm {
666bc6570dSnicm     if (last > first) {
676bc6570dSnicm 	*--last = '\0';
686bc6570dSnicm 	if (echoed) {
696bc6570dSnicm 	    int y1 = win->_cury;
706bc6570dSnicm 	    int x1 = win->_curx;
716bc6570dSnicm 	    int n;
726bc6570dSnicm 
736bc6570dSnicm 	    wmove(win, y, x);
746bc6570dSnicm 	    for (n = 0; first[n] != 0; ++n) {
756bc6570dSnicm 		wadd_wint(win, first + n);
766bc6570dSnicm 	    }
776bc6570dSnicm 	    getyx(win, y, x);
786bc6570dSnicm 	    while (win->_cury < y1
796bc6570dSnicm 		   || (win->_cury == y1 && win->_curx < x1))
806bc6570dSnicm 		waddch(win, (chtype) ' ');
816bc6570dSnicm 
826bc6570dSnicm 	    wmove(win, y, x);
836bc6570dSnicm 	}
846bc6570dSnicm     }
856bc6570dSnicm     return last;
866bc6570dSnicm }
876bc6570dSnicm 
886bc6570dSnicm NCURSES_EXPORT(int)
wgetn_wstr(WINDOW * win,wint_t * str,int maxlen)896bc6570dSnicm wgetn_wstr(WINDOW *win, wint_t *str, int maxlen)
906bc6570dSnicm {
916bc6570dSnicm     SCREEN *sp = _nc_screen_of(win);
926bc6570dSnicm     TTY buf;
93*c7ef0cfcSnicm     TTY_FLAGS save_flags;
94*c7ef0cfcSnicm     wchar_t erasec = 0;
95*c7ef0cfcSnicm     wchar_t killc = 0;
966bc6570dSnicm     wint_t *oldstr = str;
976bc6570dSnicm     wint_t *tmpstr = str;
986bc6570dSnicm     wint_t ch;
996bc6570dSnicm     int y, x, code;
1006bc6570dSnicm 
101*c7ef0cfcSnicm     T((T_CALLED("wgetn_wstr(%p,%p, %d)"), (void *) win, (void *) str, maxlen));
1026bc6570dSnicm 
1036bc6570dSnicm     if (!win)
1046bc6570dSnicm 	returnCode(ERR);
1056bc6570dSnicm 
106*c7ef0cfcSnicm     maxlen = _nc_getstr_limit(maxlen);
107*c7ef0cfcSnicm 
1086bc6570dSnicm     _nc_get_tty_mode(&buf);
1096bc6570dSnicm 
110*c7ef0cfcSnicm     save_flags = sp->_tty_flags;
111*c7ef0cfcSnicm     NCURSES_SP_NAME(nl) (NCURSES_SP_ARG);
112*c7ef0cfcSnicm     NCURSES_SP_NAME(noecho) (NCURSES_SP_ARG);
113*c7ef0cfcSnicm     if (!save_flags._raw)
114*c7ef0cfcSnicm 	NCURSES_SP_NAME(cbreak) (NCURSES_SP_ARG);
1156bc6570dSnicm 
116*c7ef0cfcSnicm     NCURSES_SP_NAME(erasewchar) (NCURSES_SP_ARGx &erasec);
117*c7ef0cfcSnicm     NCURSES_SP_NAME(killwchar) (NCURSES_SP_ARGx &killc);
1186bc6570dSnicm 
1196bc6570dSnicm     getyx(win, y, x);
1206bc6570dSnicm 
1216bc6570dSnicm     if (is_wintouched(win) || (win->_flags & _HASMOVED))
1226bc6570dSnicm 	wrefresh(win);
1236bc6570dSnicm 
1246bc6570dSnicm     while ((code = wget_wch(win, &ch)) != ERR) {
1256bc6570dSnicm 	/*
1266bc6570dSnicm 	 * Map special characters into key-codes.
1276bc6570dSnicm 	 */
1286bc6570dSnicm 	if (ch == '\r')
1296bc6570dSnicm 	    ch = '\n';
1306bc6570dSnicm 	if (ch == '\n') {
1316bc6570dSnicm 	    code = KEY_CODE_YES;
1326bc6570dSnicm 	    ch = KEY_ENTER;
1336bc6570dSnicm 	}
134*c7ef0cfcSnicm 	if (ch != 0 && ch < KEY_MIN) {
135*c7ef0cfcSnicm 	    if (ch == (wint_t) erasec) {
1366bc6570dSnicm 		ch = KEY_BACKSPACE;
1376bc6570dSnicm 		code = KEY_CODE_YES;
1386bc6570dSnicm 	    }
139*c7ef0cfcSnicm 	    if (ch == (wint_t) killc) {
1406bc6570dSnicm 		ch = KEY_EOL;
1416bc6570dSnicm 		code = KEY_CODE_YES;
1426bc6570dSnicm 	    }
1436bc6570dSnicm 	}
1446bc6570dSnicm 	if (code == KEY_CODE_YES) {
1456bc6570dSnicm 	    /*
1466bc6570dSnicm 	     * Some terminals (the Wyse-50 is the most common) generate a \n
147*c7ef0cfcSnicm 	     * from the down-arrow key.  With this logic, it is the user's
1486bc6570dSnicm 	     * choice whether to set kcud=\n for wget_wch(); terminating
1496bc6570dSnicm 	     * *getn_wstr() with \n should work either way.
1506bc6570dSnicm 	     */
1516bc6570dSnicm 	    if (ch == KEY_DOWN || ch == KEY_ENTER) {
152*c7ef0cfcSnicm 		if (save_flags._echo == TRUE
1536bc6570dSnicm 		    && win->_cury == win->_maxy
1546bc6570dSnicm 		    && win->_scroll)
1556bc6570dSnicm 		    wechochar(win, (chtype) '\n');
1566bc6570dSnicm 		break;
1576bc6570dSnicm 	    }
1586bc6570dSnicm 	    if (ch == KEY_LEFT || ch == KEY_BACKSPACE) {
1596bc6570dSnicm 		if (tmpstr > oldstr) {
160*c7ef0cfcSnicm 		    tmpstr = WipeOut(win, y, x, oldstr, tmpstr, save_flags._echo);
1616bc6570dSnicm 		}
1626bc6570dSnicm 	    } else if (ch == KEY_EOL) {
1636bc6570dSnicm 		while (tmpstr > oldstr) {
164*c7ef0cfcSnicm 		    tmpstr = WipeOut(win, y, x, oldstr, tmpstr, save_flags._echo);
1656bc6570dSnicm 		}
1666bc6570dSnicm 	    } else {
1676bc6570dSnicm 		beep();
1686bc6570dSnicm 	    }
169*c7ef0cfcSnicm 	} else if (tmpstr - oldstr >= maxlen) {
1706bc6570dSnicm 	    beep();
1716bc6570dSnicm 	} else {
1726bc6570dSnicm 	    *tmpstr++ = ch;
1736bc6570dSnicm 	    *tmpstr = 0;
174*c7ef0cfcSnicm 	    if (save_flags._echo == TRUE) {
1756bc6570dSnicm 		int oldy = win->_cury;
1766bc6570dSnicm 
1776bc6570dSnicm 		if (wadd_wint(win, tmpstr - 1) == ERR) {
1786bc6570dSnicm 		    /*
1796bc6570dSnicm 		     * We can't really use the lower-right corner for input,
1806bc6570dSnicm 		     * since it'll mess up bookkeeping for erases.
1816bc6570dSnicm 		     */
1826bc6570dSnicm 		    win->_flags &= ~_WRAPPED;
1836bc6570dSnicm 		    waddch(win, (chtype) ' ');
184*c7ef0cfcSnicm 		    tmpstr = WipeOut(win, y, x, oldstr, tmpstr, save_flags._echo);
1856bc6570dSnicm 		    continue;
186*c7ef0cfcSnicm 		} else if (IS_WRAPPED(win)) {
1876bc6570dSnicm 		    /*
1886bc6570dSnicm 		     * If the last waddch forced a wrap & scroll, adjust our
1896bc6570dSnicm 		     * reference point for erasures.
1906bc6570dSnicm 		     */
1916bc6570dSnicm 		    if (win->_scroll
1926bc6570dSnicm 			&& oldy == win->_maxy
1936bc6570dSnicm 			&& win->_cury == win->_maxy) {
1946bc6570dSnicm 			if (--y <= 0) {
1956bc6570dSnicm 			    y = 0;
1966bc6570dSnicm 			}
1976bc6570dSnicm 		    }
1986bc6570dSnicm 		    win->_flags &= ~_WRAPPED;
1996bc6570dSnicm 		}
2006bc6570dSnicm 		wrefresh(win);
2016bc6570dSnicm 	    }
2026bc6570dSnicm 	}
2036bc6570dSnicm     }
2046bc6570dSnicm 
2056bc6570dSnicm     win->_curx = 0;
2066bc6570dSnicm     win->_flags &= ~_WRAPPED;
2076bc6570dSnicm     if (win->_cury < win->_maxy)
2086bc6570dSnicm 	win->_cury++;
2096bc6570dSnicm     wrefresh(win);
2106bc6570dSnicm 
2116bc6570dSnicm     /* Restore with a single I/O call, to fix minor asymmetry between
2126bc6570dSnicm      * raw/noraw, etc.
2136bc6570dSnicm      */
214*c7ef0cfcSnicm     sp->_tty_flags = save_flags;
2156bc6570dSnicm     (void) _nc_set_tty_mode(&buf);
2166bc6570dSnicm 
2176bc6570dSnicm     *tmpstr = 0;
2186bc6570dSnicm     if (code == ERR) {
2196bc6570dSnicm 	if (tmpstr == oldstr) {
2206bc6570dSnicm 	    *tmpstr++ = WEOF;
2216bc6570dSnicm 	    *tmpstr = 0;
2226bc6570dSnicm 	}
2236bc6570dSnicm 	returnCode(ERR);
2246bc6570dSnicm     }
2256bc6570dSnicm 
2266bc6570dSnicm     T(("wgetn_wstr returns %s", _nc_viswibuf(oldstr)));
2276bc6570dSnicm 
2286bc6570dSnicm     returnCode(OK);
2296bc6570dSnicm }
230