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 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 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 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 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 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 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 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 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