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