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