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