ncurses 5.0
[ncurses.git] / ncurses / base / lib_getstr.c
1 /****************************************************************************
2  * Copyright (c) 1998 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: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
31  *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
32  ****************************************************************************/
33
34
35 /*
36 **      lib_getstr.c
37 **
38 **      The routine wgetstr().
39 **
40 */
41
42 #include <curses.priv.h>
43 #include <term.h>
44
45 MODULE_ID("$Id: lib_getstr.c,v 1.20 1998/12/20 00:16:01 tom Exp $")
46
47 /*
48  * This wipes out the last character, no matter whether it was a tab, control
49  * or other character, and handles reverse wraparound.
50  */
51 static char *WipeOut(WINDOW *win, int y, int x, char *first, char *last, bool echoed)
52 {
53         if (last > first) {
54                 *--last = '\0';
55                 if (echoed) {
56                         int y1 = win->_cury;
57                         int x1 = win->_curx;
58
59                         wmove(win, y, x);
60                         waddstr(win, first);
61                         getyx(win, y, x);
62                         while (win->_cury < y1
63                            || (win->_cury == y1 && win->_curx < x1))
64                                 waddch(win, ' ');
65
66                         wmove(win, y, x);
67                 }
68         }
69         return last;
70 }
71
72 int wgetnstr(WINDOW *win, char *str, int maxlen)
73 {
74 TTY     buf;
75 bool    oldnl, oldecho, oldraw, oldcbreak;
76 char    erasec;
77 char    killc;
78 char    *oldstr;
79 int ch;
80 int     y, x;
81
82         T((T_CALLED("wgetnstr(%p,%p, %d)"), win, str, maxlen));
83
84         if (!win)
85           returnCode(ERR);
86
87         _nc_get_tty_mode(&buf);
88
89         oldnl = SP->_nl;
90         oldecho = SP->_echo;
91         oldraw = SP->_raw;
92         oldcbreak = SP->_cbreak;
93         nl();
94         noecho();
95         noraw();
96         cbreak();
97
98         erasec = erasechar();
99         killc = killchar();
100
101         oldstr = str;
102         getyx(win, y, x);
103
104         if (is_wintouched(win) || (win->_flags & _HASMOVED))
105                 wrefresh(win);
106
107         while ((ch = wgetch(win)) != ERR) {
108                 /*
109                  * Some terminals (the Wyse-50 is the most common) generate
110                  * a \n from the down-arrow key.  With this logic, it's the
111                  * user's choice whether to set kcud=\n for wgetch();
112                  * terminating *getstr() with \n should work either way.
113                  */
114                 if (ch == '\n'
115                  || ch == '\r'
116                  || ch == KEY_DOWN
117                  || ch == KEY_ENTER) {
118                         if (oldecho == TRUE
119                          && win->_cury == win->_maxy
120                          && win->_scroll)
121                                 wechochar(win, '\n');
122                         break;
123                 }
124                 if (ch == erasec || ch == KEY_LEFT || ch == KEY_BACKSPACE) {
125                         if (str > oldstr) {
126                                 str = WipeOut(win, y, x, oldstr, str, oldecho);
127                         }
128                 } else if (ch == killc) {
129                         while (str > oldstr) {
130                                 str = WipeOut(win, y, x, oldstr, str, oldecho);
131                         }
132                 } else if (ch >= KEY_MIN
133                            || (maxlen >= 0 && str - oldstr >= maxlen)) {
134                         beep();
135                 } else {
136                         *str++ = ch;
137                         if (oldecho == TRUE) {
138                                 int oldy = win->_cury;
139                                 if (waddch(win, ch) == ERR) {
140                                         /*
141                                          * We can't really use the lower-right
142                                          * corner for input, since it'll mess
143                                          * up bookkeeping for erases.
144                                          */
145                                         win->_flags &= ~_WRAPPED;
146                                         waddch(win, ' ');
147                                         str = WipeOut(win, y, x, oldstr, str, oldecho);
148                                         continue;
149                                 } else if (win->_flags & _WRAPPED) {
150                                         /*
151                                          * If the last waddch forced a wrap &
152                                          * scroll, adjust our reference point
153                                          * for erasures.
154                                          */
155                                         if (win->_scroll
156                                          && oldy == win->_maxy
157                                          && win->_cury == win->_maxy) {
158                                                 if (--y <= 0) {
159                                                         y = 0;
160                                                 }
161                                         }
162                                         win->_flags &= ~_WRAPPED;
163                                 }
164                                 wrefresh(win);
165                         }
166                 }
167         }
168
169         win->_curx = 0;
170         win->_flags &= ~_WRAPPED;
171         if (win->_cury < win->_maxy)
172                 win->_cury++;
173         wrefresh(win);
174
175         /* Restore with a single I/O call, to fix minor asymmetry between
176          * raw/noraw, etc.
177          */
178         SP->_nl = oldnl;
179         SP->_echo = oldecho;
180         SP->_raw = oldraw;
181         SP->_cbreak = oldcbreak;
182
183         _nc_set_tty_mode(&buf);
184
185         *str = '\0';
186         if (ch == ERR)
187                 returnCode(ERR);
188
189         T(("wgetnstr returns %s", _nc_visbuf(oldstr)));
190
191         returnCode(OK);
192 }