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