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