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