1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright (c) 1995, by Sun Microsystems, Inc.
24 * All rights reserved.
25 */
26
27 /*
28 * wgetn_ws.c
29 *
30 * XCurses Library
31 *
32 * Copyright 1990, 1995 by Mortice Kern Systems Inc. All rights reserved.
33 *
34 */
35
36 #ifdef M_RCSID
37 #ifndef lint
38 static char rcsID[] = "$Header: /rd/src/libc/xcurses/rcs/wgetn_ws.c 1.3 1995/10/02 15:07:23 ant Exp $";
39 #endif
40 #endif
41
42 #include <private.h>
43 #include <limits.h>
44 #include <stdlib.h>
45 #include <m_wio.h>
46
47 static wint_t fld_key;
48 static int fld_echo; /* Software echo flag. */
49 static int fld_index; /* Number of characters in fld_buffer. */
50 static int fld_bytes; /* fld_index expressed in bytes. */
51 static int fld_mb; /* Field is a multibyte character string. */
52 static wint_t *fld_buffer; /* Wide character buffer. */
53 static int fld_maxlength; /* Character length of buffer. */
54 static WINDOW *fld_window;
55 static int fld_row, fld_col; /* Start of field in fld_window. */
56
57 STATIC int fld_done(void);
58 STATIC int fld_erase(void);
59 STATIC int fld_kill(void);
60 STATIC int fld_insert(void);
61
62 typedef struct t_key_entry {
63 int type;
64 wint_t code;
65 int (*func)(void);
66 } t_key_entry;
67
68 #define ERASE_KEY 0
69 #define KILL_KEY 1
70 #define EOF_KEY 2
71 #define EOL_KEY 3
72
73 static t_key_entry key_table[] = {
74 { OK, 0, fld_erase },
75 { OK, 0, fld_kill },
76 { OK, 0, fld_done },
77 { OK, 0, fld_done },
78 { OK, '\n', fld_done },
79 { OK, WEOF, fld_done },
80 { KEY_CODE_YES, KEY_LEFT, fld_erase },
81 { KEY_CODE_YES, KEY_BACKSPACE, fld_erase },
82 { ERR, 0, fld_insert }
83 };
84
85 /*f
86 * The effect of wgetnstr() is as though a series of calls to wgetch()
87 * were made, until a <newline> or <return> are received. The
88 * resulting value is placed in the area pointed to by the character
89 * pointer 's'. wgetnstr() reads at most n characters, thus
90 * preventing a possible overflow of the input buffer. The user's
91 * erase and kill characters are interpreted.
92 *
93 * If n < 0, wgetnstr() will read until a <newline> or <return> is
94 * entered. To accept functions keys, keypad() must be set for the
95 * window.
96 */
97 int
__m_wgetn_wstr(w,s,n,mb_flag)98 __m_wgetn_wstr(w, s, n, mb_flag)
99 WINDOW *w;
100 void *s;
101 int n, mb_flag;
102 {
103 int type;
104 wchar_t wc;
105 t_key_entry *k;
106 struct termios saved;
107
108 #ifdef M_CURSES_TRACE
109 __m_trace("__m_wgetn_wstr(%p, %p, %d, %d)", w, s, n, mb_flag);
110 #endif
111
112 fld_window = w;
113 fld_index = 0;
114 fld_bytes = 0;
115 fld_mb = mb_flag;
116
117 /* Read at most N bytes from the field. */
118 fld_maxlength = n < 0 ? LINE_MAX : n;
119
120 /* Make sure there is enough to hold the largest characater. */
121 if (fld_mb && fld_maxlength < MB_CUR_MAX)
122 return __m_return_code("wgetn_wstr", ERR);
123
124 if (mb_flag) {
125 /* Create a wint_t buffer, which makes it easier to
126 * handle erasing characters from the line.
127 */
128 fld_buffer = (wint_t *) calloc(
129 fld_maxlength+1, sizeof *fld_buffer
130 );
131 if (fld_buffer == (wint_t *) 0)
132 return __m_return_code("wgetn_wstr", ERR);
133 } else {
134 fld_buffer = (wint_t *) s;
135 }
136
137 (void) __m_tty_wc(VEOL, &wc);
138 key_table[EOL_KEY].code = (wint_t) wc;
139 (void) __m_tty_wc(VEOF, &wc);
140 key_table[EOF_KEY].code = (wint_t) wc;
141 (void) __m_tty_wc(VKILL, &wc);
142 key_table[KILL_KEY].code = (wint_t) wc;
143 (void) __m_tty_wc(VERASE, &wc);
144 key_table[ERASE_KEY].code = (wint_t) wc;
145
146 getyx(fld_window, fld_row, fld_col);
147
148 /* We remember if the user specified echo on or off, then disable it
149 * so that wgetch() doesn't perform any echoing before we've had a
150 * chance to process the key. fld_insert() will handle the necessary
151 * echoing of characters.
152 */
153 fld_echo = __m_set_echo(0);
154 saved = cur_term->_prog;
155 (void) cbreak();
156
157 for (;;) {
158 type = wget_wch(fld_window, &fld_key);
159
160 for (k = key_table; k->type != ERR; ++k)
161 if (k->type == type && k->code == fld_key)
162 break;
163
164 if (k->func != (int (*)(void)) 0 && !(*k->func)()) {
165 /* If the edit function returned false then quit. */
166 fld_buffer[fld_index] = '\0';
167 break;
168 }
169 }
170
171 /* Restore the I/O settings. */
172 (void) __m_set_echo(fld_echo);
173 (void) __m_tty_set(&saved);
174
175 if (mb_flag) {
176 (void) wistombs((char *) s, fld_buffer, fld_maxlength+1);
177 free(fld_buffer);
178 }
179
180 return __m_return_code("__m_wgetn_wstr", OK);
181 }
182
183 STATIC int
wint_len(wc)184 wint_len(wc)
185 wint_t wc;
186 {
187 int len;
188 char mb[MB_LEN_MAX];
189
190 if (wc == WEOF)
191 return 0;
192
193 len = wctomb(mb, (wchar_t) wc);
194
195 return len < 0 ? 0 : len;
196 }
197
198 STATIC int
fld_done()199 fld_done()
200 {
201 return 0;
202 }
203
204 STATIC int
fld_erase()205 fld_erase()
206 {
207 int x, y, width;
208
209 if (fld_index <= 0)
210 return 1;
211
212 width = wcwidth(fld_buffer[--fld_index]);
213 fld_bytes -= wint_len(fld_buffer[fld_index]);
214 fld_buffer[fld_index] = '\0';
215 getyx(fld_window, y, x);
216
217 if (0 < x) {
218 /* Rubout previous character. */
219 x -= width;
220 } else if (0 < y) {
221 /* Reverse line wrap. */
222 --y;
223 x = fld_window->_maxx - 1;
224
225 /* Find end of previous character, skipping any background
226 * character that may have been written by auto-wrap.
227 */
228 while (fld_buffer[fld_index] != fld_window->_line[y][x]._wc[0])
229 --x;
230
231 /* Find first column of character. */
232 x = __m_cc_first(fld_window, y, x);
233 }
234
235 (void) __m_cc_erase(fld_window, y, x, y, x);
236
237 fld_window->_cury = y;
238 fld_window->_curx = x;
239
240 return 1;
241 }
242
243 STATIC int
fld_kill()244 fld_kill()
245 {
246 int y, x;
247
248 getyx(fld_window, y, x);
249 (void) __m_cc_erase(fld_window, fld_row, fld_col, y, x);
250
251 fld_window->_cury = fld_row;
252 fld_window->_curx = fld_col;
253 fld_index = fld_bytes = 0;
254 fld_buffer[0] = '\0';
255
256 return 1;
257 }
258
259 STATIC int
fld_insert()260 fld_insert()
261 {
262 cchar_t cc;
263 t_wide_io *wio;
264
265 if (fld_maxlength < fld_index)
266 /* Completely full, terminate input. */
267 return 0;
268
269 wio = (t_wide_io *) __m_screen->_in;
270
271 /* Don't exceed the byte length for the field.
272 *
273 * m_wio_get() called by wget_wch(), records the
274 * number of bytes converted, when _next == _size.
275 *
276 * wget_wch() makes sure that _next == _size by
277 * pushing invalid multibyte characters on to an
278 * input stack.
279 */
280 if (fld_mb && fld_maxlength < fld_bytes + wio->_size) {
281 /* Is there still room for single-byte characters? */
282 if (fld_bytes < fld_maxlength) {
283 (void) beep();
284 return 1;
285 }
286
287 /* Completely full, terminate input. */
288 return 0;
289 }
290
291 if (0 <= fld_key) {
292 fld_buffer[fld_index++] = fld_key;
293 fld_bytes += wio->_size;
294
295 if (fld_echo) {
296 (void) __m_wc_cc(fld_key, &cc);
297 (void) wadd_wch(fld_window, &cc);
298 }
299 } else {
300 (void) beep();
301 }
302
303 return 1;
304 }
305
306 int
wgetnstr(w,s,n)307 wgetnstr(w, s, n)
308 WINDOW *w;
309 char *s;
310 int n;
311 {
312 int code;
313
314 #ifdef M_CURSES_TRACE
315 __m_trace("wgetnstr(%p, %p, %d)", w, s, n);
316 #endif
317
318 code = __m_wgetn_wstr(w, (void *) s, n, 1);
319
320 return __m_return_code("wgetnstr", code);
321 }
322
323 int
wgetn_wstr(w,s,n)324 wgetn_wstr(w, s, n)
325 WINDOW *w;
326 wint_t *s;
327 int n;
328 {
329 int code;
330
331 #ifdef M_CURSES_TRACE
332 __m_trace("wgetn_wstr(%p, %p, %d)", w, s, n);
333 #endif
334
335 code = __m_wgetn_wstr(w, (void *) s, n, 0);
336
337 return __m_return_code("wgetn_wstr", code);
338 }
339