150276Speter/****************************************************************************
2184989Srafan * Copyright (c) 1998-2006,2008 Free Software Foundation, Inc.              *
350276Speter *                                                                          *
450276Speter * Permission is hereby granted, free of charge, to any person obtaining a  *
550276Speter * copy of this software and associated documentation files (the            *
650276Speter * "Software"), to deal in the Software without restriction, including      *
750276Speter * without limitation the rights to use, copy, modify, merge, publish,      *
850276Speter * distribute, distribute with modifications, sublicense, and/or sell       *
950276Speter * copies of the Software, and to permit persons to whom the Software is    *
1050276Speter * furnished to do so, subject to the following conditions:                 *
1150276Speter *                                                                          *
1250276Speter * The above copyright notice and this permission notice shall be included  *
1350276Speter * in all copies or substantial portions of the Software.                   *
1450276Speter *                                                                          *
1550276Speter * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
1650276Speter * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
1750276Speter * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
1850276Speter * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
1950276Speter * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
2050276Speter * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
2150276Speter * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
2250276Speter *                                                                          *
2350276Speter * Except as contained in this notice, the name(s) of the above copyright   *
2450276Speter * holders shall not be used in advertising or otherwise to promote the     *
2550276Speter * sale, use or other dealings in this Software without prior written       *
2650276Speter * authorization.                                                           *
2750276Speter ****************************************************************************/
2850276Speter
2950276Speter/****************************************************************************
3050276Speter *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
3150276Speter *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
3250276Speter ****************************************************************************/
3350276Speter
3450276Speter/*
3550276Speter**	lib_getstr.c
3650276Speter**
3750276Speter**	The routine wgetstr().
3850276Speter**
3950276Speter*/
4050276Speter
4150276Speter#include <curses.priv.h>
4250276Speter#include <term.h>
4350276Speter
44184989SrafanMODULE_ID("$Id: lib_getstr.c,v 1.27 2008/08/16 19:20:04 tom Exp $")
4550276Speter
4650276Speter/*
4750276Speter * This wipes out the last character, no matter whether it was a tab, control
4850276Speter * or other character, and handles reverse wraparound.
4950276Speter */
5076726Speterstatic char *
5176726SpeterWipeOut(WINDOW *win, int y, int x, char *first, char *last, bool echoed)
5250276Speter{
5376726Speter    if (last > first) {
5476726Speter	*--last = '\0';
5576726Speter	if (echoed) {
5676726Speter	    int y1 = win->_cury;
5776726Speter	    int x1 = win->_curx;
5850276Speter
5976726Speter	    wmove(win, y, x);
6076726Speter	    waddstr(win, first);
6176726Speter	    getyx(win, y, x);
6276726Speter	    while (win->_cury < y1
6376726Speter		   || (win->_cury == y1 && win->_curx < x1))
6476726Speter		waddch(win, (chtype) ' ');
6550276Speter
6676726Speter	    wmove(win, y, x);
6750276Speter	}
6876726Speter    }
6976726Speter    return last;
7050276Speter}
7150276Speter
7276726SpeterNCURSES_EXPORT(int)
73166124Srafanwgetnstr_events(WINDOW *win,
74166124Srafan		char *str,
75166124Srafan		int maxlen,
76166124Srafan		EVENTLIST_1st(_nc_eventlist * evl))
7750276Speter{
78184989Srafan    SCREEN *sp = _nc_screen_of(win);
7976726Speter    TTY buf;
8076726Speter    bool oldnl, oldecho, oldraw, oldcbreak;
8176726Speter    char erasec;
8276726Speter    char killc;
8376726Speter    char *oldstr;
8476726Speter    int ch;
8576726Speter    int y, x;
8650276Speter
8776726Speter    T((T_CALLED("wgetnstr(%p,%p, %d)"), win, str, maxlen));
8850276Speter
8976726Speter    if (!win)
9076726Speter	returnCode(ERR);
9150276Speter
9276726Speter    _nc_get_tty_mode(&buf);
9350276Speter
94184989Srafan    oldnl = sp->_nl;
95184989Srafan    oldecho = sp->_echo;
96184989Srafan    oldraw = sp->_raw;
97184989Srafan    oldcbreak = sp->_cbreak;
9876726Speter    nl();
9976726Speter    noecho();
10076726Speter    noraw();
10176726Speter    cbreak();
10250276Speter
10376726Speter    erasec = erasechar();
10476726Speter    killc = killchar();
10550276Speter
10676726Speter    oldstr = str;
10776726Speter    getyx(win, y, x);
10850276Speter
10976726Speter    if (is_wintouched(win) || (win->_flags & _HASMOVED))
11076726Speter	wrefresh(win);
11150276Speter
112166124Srafan    while ((ch = wgetch_events(win, evl)) != ERR) {
11376726Speter	/*
11476726Speter	 * Some terminals (the Wyse-50 is the most common) generate
11576726Speter	 * a \n from the down-arrow key.  With this logic, it's the
11676726Speter	 * user's choice whether to set kcud=\n for wgetch();
11776726Speter	 * terminating *getstr() with \n should work either way.
11876726Speter	 */
11976726Speter	if (ch == '\n'
12076726Speter	    || ch == '\r'
12176726Speter	    || ch == KEY_DOWN
12276726Speter	    || ch == KEY_ENTER) {
12376726Speter	    if (oldecho == TRUE
12476726Speter		&& win->_cury == win->_maxy
12576726Speter		&& win->_scroll)
12676726Speter		wechochar(win, (chtype) '\n');
12776726Speter	    break;
12876726Speter	}
129166124Srafan#ifdef KEY_EVENT
130166124Srafan	if (ch == KEY_EVENT)
131166124Srafan	    break;
132166124Srafan#endif
133166124Srafan#ifdef KEY_RESIZE
134166124Srafan	if (ch == KEY_RESIZE)
135166124Srafan	    break;
136166124Srafan#endif
13776726Speter	if (ch == erasec || ch == KEY_LEFT || ch == KEY_BACKSPACE) {
13876726Speter	    if (str > oldstr) {
13976726Speter		str = WipeOut(win, y, x, oldstr, str, oldecho);
14076726Speter	    }
14176726Speter	} else if (ch == killc) {
14276726Speter	    while (str > oldstr) {
14376726Speter		str = WipeOut(win, y, x, oldstr, str, oldecho);
14476726Speter	    }
14576726Speter	} else if (ch >= KEY_MIN
14676726Speter		   || (maxlen >= 0 && str - oldstr >= maxlen)) {
14776726Speter	    beep();
14876726Speter	} else {
149184989Srafan	    *str++ = (char) ch;
15076726Speter	    if (oldecho == TRUE) {
15176726Speter		int oldy = win->_cury;
15276726Speter		if (waddch(win, (chtype) ch) == ERR) {
15376726Speter		    /*
15476726Speter		     * We can't really use the lower-right
15576726Speter		     * corner for input, since it'll mess
15676726Speter		     * up bookkeeping for erases.
15776726Speter		     */
15876726Speter		    win->_flags &= ~_WRAPPED;
15976726Speter		    waddch(win, (chtype) ' ');
16076726Speter		    str = WipeOut(win, y, x, oldstr, str, oldecho);
16176726Speter		    continue;
16276726Speter		} else if (win->_flags & _WRAPPED) {
16376726Speter		    /*
16476726Speter		     * If the last waddch forced a wrap &
16576726Speter		     * scroll, adjust our reference point
16676726Speter		     * for erasures.
16776726Speter		     */
16876726Speter		    if (win->_scroll
16976726Speter			&& oldy == win->_maxy
17076726Speter			&& win->_cury == win->_maxy) {
17176726Speter			if (--y <= 0) {
17276726Speter			    y = 0;
17350276Speter			}
17476726Speter		    }
17576726Speter		    win->_flags &= ~_WRAPPED;
17650276Speter		}
17776726Speter		wrefresh(win);
17876726Speter	    }
17950276Speter	}
18076726Speter    }
18150276Speter
18276726Speter    win->_curx = 0;
18376726Speter    win->_flags &= ~_WRAPPED;
18476726Speter    if (win->_cury < win->_maxy)
18576726Speter	win->_cury++;
18676726Speter    wrefresh(win);
18750276Speter
18876726Speter    /* Restore with a single I/O call, to fix minor asymmetry between
18976726Speter     * raw/noraw, etc.
19076726Speter     */
191184989Srafan    sp->_nl = oldnl;
192184989Srafan    sp->_echo = oldecho;
193184989Srafan    sp->_raw = oldraw;
194184989Srafan    sp->_cbreak = oldcbreak;
19550276Speter
19676726Speter    _nc_set_tty_mode(&buf);
19750276Speter
19876726Speter    *str = '\0';
19976726Speter    if (ch == ERR)
200166124Srafan	returnCode(ch);
20150276Speter
20276726Speter    T(("wgetnstr returns %s", _nc_visbuf(oldstr)));
20350276Speter
204166124Srafan#ifdef KEY_EVENT
205166124Srafan    if (ch == KEY_EVENT)
206166124Srafan	returnCode(ch);
207166124Srafan#endif
208166124Srafan#ifdef KEY_RESIZE
209166124Srafan    if (ch == KEY_RESIZE)
210166124Srafan	returnCode(ch);
211166124Srafan#endif
212166124Srafan
21376726Speter    returnCode(OK);
21450276Speter}
215166124Srafan
216166124Srafan#ifdef NCURSES_WGETCH_EVENTS
217166124SrafanNCURSES_EXPORT(int)
218166124Srafanwgetnstr(WINDOW *win, char *str, int maxlen)
219166124Srafan{
220166124Srafan    returnCode(wgetnstr_events(win,
221166124Srafan			       str,
222166124Srafan			       maxlen,
223166124Srafan			       EVENTLIST_1st((_nc_eventlist *) 0)));
224166124Srafan}
225166124Srafan#endif
226