1/****************************************************************************
2 * Copyright (c) 2002-2004,2008 Free Software Foundation, Inc.              *
3 *                                                                          *
4 * Permission is hereby granted, free of charge, to any person obtaining a  *
5 * copy of this software and associated documentation files (the            *
6 * "Software"), to deal in the Software without restriction, including      *
7 * without limitation the rights to use, copy, modify, merge, publish,      *
8 * distribute, distribute with modifications, sublicense, and/or sell       *
9 * copies of the Software, and to permit persons to whom the Software is    *
10 * furnished to do so, subject to the following conditions:                 *
11 *                                                                          *
12 * The above copyright notice and this permission notice shall be included  *
13 * in all copies or substantial portions of the Software.                   *
14 *                                                                          *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
18 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
21 * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
22 *                                                                          *
23 * Except as contained in this notice, the name(s) of the above copyright   *
24 * holders shall not be used in advertising or otherwise to promote the     *
25 * sale, use or other dealings in this Software without prior written       *
26 * authorization.                                                           *
27 ****************************************************************************/
28
29/****************************************************************************
30 *  Author: Thomas E. Dickey                                                *
31 ****************************************************************************/
32
33/*
34**	lib_get_wstr.c
35**
36**	The routine wgetn_wstr().
37**
38*/
39
40#include <curses.priv.h>
41#include <term.h>
42
43MODULE_ID("$Id: lib_get_wstr.c,v 1.10 2008/08/16 19:25:33 tom Exp $")
44
45static int
46wadd_wint(WINDOW *win, wint_t *src)
47{
48    cchar_t tmp;
49    wchar_t wch[2];
50
51    wch[0] = (wchar_t) (*src);
52    wch[1] = 0;
53    setcchar(&tmp, wch, A_NORMAL, 0, NULL);
54    return wadd_wch(win, &tmp);
55}
56
57/*
58 * This wipes out the last character, no matter whether it was a tab, control
59 * or other character, and handles reverse wraparound.
60 */
61static wint_t *
62WipeOut(WINDOW *win, int y, int x, wint_t *first, wint_t *last, bool echoed)
63{
64    if (last > first) {
65	*--last = '\0';
66	if (echoed) {
67	    int y1 = win->_cury;
68	    int x1 = win->_curx;
69	    int n;
70
71	    wmove(win, y, x);
72	    for (n = 0; first[n] != 0; ++n) {
73		wadd_wint(win, first + n);
74	    }
75	    getyx(win, y, x);
76	    while (win->_cury < y1
77		   || (win->_cury == y1 && win->_curx < x1))
78		waddch(win, (chtype) ' ');
79
80	    wmove(win, y, x);
81	}
82    }
83    return last;
84}
85
86NCURSES_EXPORT(int)
87wgetn_wstr(WINDOW *win, wint_t *str, int maxlen)
88{
89    SCREEN *sp = _nc_screen_of(win);
90    TTY buf;
91    bool oldnl, oldecho, oldraw, oldcbreak;
92    wint_t erasec;
93    wint_t killc;
94    wint_t *oldstr = str;
95    wint_t *tmpstr = str;
96    wint_t ch;
97    int y, x, code;
98
99    T((T_CALLED("wgetn_wstr(%p,%p, %d)"), win, str, maxlen));
100
101    if (!win)
102	returnCode(ERR);
103
104    _nc_get_tty_mode(&buf);
105
106    oldnl = sp->_nl;
107    oldecho = sp->_echo;
108    oldraw = sp->_raw;
109    oldcbreak = sp->_cbreak;
110    nl();
111    noecho();
112    noraw();
113    cbreak();
114
115    erasec = (wint_t) erasechar();
116    killc = (wint_t) killchar();
117
118    getyx(win, y, x);
119
120    if (is_wintouched(win) || (win->_flags & _HASMOVED))
121	wrefresh(win);
122
123    while ((code = wget_wch(win, &ch)) != ERR) {
124	/*
125	 * Map special characters into key-codes.
126	 */
127	if (ch == '\r')
128	    ch = '\n';
129	if (ch == '\n') {
130	    code = KEY_CODE_YES;
131	    ch = KEY_ENTER;
132	}
133	if (ch < KEY_MIN) {
134	    if (ch == erasec) {
135		ch = KEY_BACKSPACE;
136		code = KEY_CODE_YES;
137	    }
138	    if (ch == killc) {
139		ch = KEY_EOL;
140		code = KEY_CODE_YES;
141	    }
142	}
143	if (code == KEY_CODE_YES) {
144	    /*
145	     * Some terminals (the Wyse-50 is the most common) generate a \n
146	     * from the down-arrow key.  With this logic, it's the user's
147	     * choice whether to set kcud=\n for wget_wch(); terminating
148	     * *getn_wstr() with \n should work either way.
149	     */
150	    if (ch == KEY_DOWN || ch == KEY_ENTER) {
151		if (oldecho == TRUE
152		    && win->_cury == win->_maxy
153		    && win->_scroll)
154		    wechochar(win, (chtype) '\n');
155		break;
156	    }
157	    if (ch == KEY_LEFT || ch == KEY_BACKSPACE) {
158		if (tmpstr > oldstr) {
159		    tmpstr = WipeOut(win, y, x, oldstr, tmpstr, oldecho);
160		}
161	    } else if (ch == KEY_EOL) {
162		while (tmpstr > oldstr) {
163		    tmpstr = WipeOut(win, y, x, oldstr, tmpstr, oldecho);
164		}
165	    } else {
166		beep();
167	    }
168	} else if (maxlen >= 0 && tmpstr - oldstr >= maxlen) {
169	    beep();
170	} else {
171	    *tmpstr++ = ch;
172	    *tmpstr = 0;
173	    if (oldecho == TRUE) {
174		int oldy = win->_cury;
175
176		if (wadd_wint(win, tmpstr - 1) == ERR) {
177		    /*
178		     * We can't really use the lower-right corner for input,
179		     * since it'll mess up bookkeeping for erases.
180		     */
181		    win->_flags &= ~_WRAPPED;
182		    waddch(win, (chtype) ' ');
183		    tmpstr = WipeOut(win, y, x, oldstr, tmpstr, oldecho);
184		    continue;
185		} else if (win->_flags & _WRAPPED) {
186		    /*
187		     * If the last waddch forced a wrap & scroll, adjust our
188		     * reference point for erasures.
189		     */
190		    if (win->_scroll
191			&& oldy == win->_maxy
192			&& win->_cury == win->_maxy) {
193			if (--y <= 0) {
194			    y = 0;
195			}
196		    }
197		    win->_flags &= ~_WRAPPED;
198		}
199		wrefresh(win);
200	    }
201	}
202    }
203
204    win->_curx = 0;
205    win->_flags &= ~_WRAPPED;
206    if (win->_cury < win->_maxy)
207	win->_cury++;
208    wrefresh(win);
209
210    /* Restore with a single I/O call, to fix minor asymmetry between
211     * raw/noraw, etc.
212     */
213    sp->_nl = oldnl;
214    sp->_echo = oldecho;
215    sp->_raw = oldraw;
216    sp->_cbreak = oldcbreak;
217
218    (void) _nc_set_tty_mode(&buf);
219
220    *tmpstr = 0;
221    if (code == ERR) {
222	if (tmpstr == oldstr) {
223	    *tmpstr++ = WEOF;
224	    *tmpstr = 0;
225	}
226	returnCode(ERR);
227    }
228
229    T(("wgetn_wstr returns %s", _nc_viswibuf(oldstr)));
230
231    returnCode(OK);
232}
233