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-1999 by Sun Microsystems, Inc. 24 * All rights reserved. 25 */ 26 27 /* LINTLIBRARY */ 28 29 /* 30 * newterm.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 const rcsID[] = 41 "$Header: /team/ps/sun_xcurses/archive/local_changes/xcurses/src/lib/" 42 "libxcurses/src/libc/xcurses/rcs/newterm.c 1.13 1998/06/04 19:55:52 " 43 "cbates Exp $"; 44 #endif 45 #endif 46 47 #include <sys/isa_defs.h> 48 #include <private.h> 49 #include <m_wio.h> 50 #include <errno.h> 51 #include <signal.h> 52 #include <stdlib.h> 53 #include <string.h> 54 55 int LINES, COLS; 56 int COLORS, COLOR_PAIRS; 57 58 WINDOW *curscr; 59 WINDOW *stdscr; 60 SCREEN *__m_screen; 61 62 static short assume_one_line = FALSE; 63 64 /* 65 * Assume terminal has only one screen line by restricting those 66 * capabilities that assume more than one line. This function must 67 * be called before initscr() or newterm(). 68 * 69 * This flag will reset after initscr() or newterm() so that subsequent 70 * calls to newterm(), without a preceding call to filter(), will load 71 * an unmodified terminal. THIS IS NOT HISTORICAL PRACTICE, BUT DEEMED 72 * USEFUL. 73 */ 74 void 75 filter(void) 76 { 77 assume_one_line = TRUE; 78 } 79 80 /* 81 * SIGTSTP Handler. 82 */ 83 /* ARGSUSED */ 84 void 85 tstp(int signo) 86 { 87 #ifdef SIGTSTP 88 /* 89 * Only permit SIGTSTP if the curent process is the process 90 * group leader. If the process is not the current group 91 * leader, then suspending the current process will suspend 92 * other members of the process group, such as the parent 93 * process. 94 */ 95 if (getpid() == getpgrp()) { 96 (void) endwin(); 97 98 #ifdef SIG_UNBLOCK 99 { 100 sigset_t unblock; 101 102 (void) sigemptyset(&unblock); 103 (void) sigaddset(&unblock, SIGTSTP); 104 (void) sigprocmask(SIG_UNBLOCK, &unblock, 105 (sigset_t *) 0); 106 } 107 #endif /* SIG_UNBLOCK */ 108 (void) signal(SIGTSTP, SIG_DFL); 109 (void) kill(0, SIGTSTP); 110 } else { 111 (void) beep(); 112 } 113 114 (void) signal(SIGTSTP, tstp); 115 (void) wrefresh(curscr); 116 #else /* no SIGTSTP */ 117 (void) beep(); 118 #endif /* SIGTSTP */ 119 } 120 121 int __m_slk_format = -1; 122 123 /* 124 * Do real soft label key initialisation once setupterm() have been called 125 * to load the current terminal. Determine whether the terminal supplies 126 * soft label keys, or whether we have to fake it by using the last line 127 * of a terminal screen. 128 */ 129 /* ARGSUSED */ 130 int 131 __m_slk_init(SCREEN *sp, int style) 132 { 133 int code; 134 135 code = ERR; 136 137 (void) memset(&sp->_slk, 0, sizeof (sp->_slk)); 138 139 /* Does the terminal have a method to program the soft label key? */ 140 if (plab_norm != NULL || pkey_plab != NULL) { 141 code = OK; 142 goto done; 143 } 144 145 /* We have to fake it. */ 146 if (lines < 2) 147 goto done; 148 149 sp->_slk._w = subwin(sp->_newscr, 1, 0, lines-1, 0); 150 if (sp->_slk._w == NULL) 151 goto done; 152 153 /* Test suite seems to expect this */ 154 (void) wattrset(sp->_slk._w, A_DIM|A_REVERSE); 155 (void) ripoffline(-1, 0); 156 code = OK; 157 done: 158 return (code); 159 } 160 161 /* 162 * The XCurses specification is unclear how ripoffline() would 163 * affect newterm(). We assume that it can't be used with newterm() 164 * and that it only affects initscr(), which is responsible for 165 * creating stdscr. 166 */ 167 t_rip rip = { 0 }; 168 169 /* 170 * If line is positive (1), one line is removed from the beginning of 171 * stdscr; else if line is negative (-1), one line is removed from the end. 172 */ 173 int 174 ripoffline(int line, int (*init)(WINDOW *, int)) 175 { 176 int i; 177 178 i = rip.top - rip.bottom; 179 180 if (line != 0 && i < M_CURSES_MAX_RIPOFFLINE) { 181 rip.line[i].init = init; 182 if (line < 0) 183 rip.line[i].dy = --rip.bottom; 184 else 185 rip.line[i].dy = rip.top++; 186 } 187 188 return (OK); 189 } 190 191 /* 192 * Create a new terminal screen. Used if a program is going to be sending 193 * output to more than one terminal. It returns a SCREEN* for the terminal. 194 * The parameters are a terminal name, output FILE*, and input FILE*. If 195 * the terminal name is null then $TERM is used. The program must also 196 * call endwin() for each terminal being used before exiting from curses. 197 * If newterm() is called more than once for the same terminal, the first 198 * terminal referred to must be the last one for which endwin() is called. 199 */ 200 SCREEN * 201 newterm(char *term, FILE *out_fp, FILE *in_fp) 202 { 203 WINDOW *w; 204 t_wide_io *wio; 205 SCREEN *sp, *osp; 206 int i, n, y, errret; 207 208 /* 209 * Input stream should be unbuffered so that m_tfgetc() works 210 * correctly on BSD and SUN systems. 211 */ 212 (void) setvbuf(in_fp, (char *) 0, _IONBF, BUFSIZ); 213 #if 0 214 /* 215 * Not sure whether we really want to concern ourselves with the output 216 * buffer scheme. Might be best to leave it upto the application to 217 * deal with buffer schemes and when to perform flushes. 218 * 219 * MKS Vi uses MKS Curses and so must support the ability to switch in 220 * and out of Curses mode when switching from Vi to Ex and back. 221 * Problem is that in Vi mode you would prefer full buffered output to 222 * give updates a smoother appearance and Ex mode you require line 223 * buffered in order to see prompts and messages. 224 */ 225 (void) setvbuf(out_fp, (char *) 0, _IOLBF, BUFSIZ); 226 #endif 227 errno = 0; 228 229 if (__m_setupterm(term, fileno(in_fp), fileno(out_fp), &errret) 230 == ERR) { 231 switch (errret) { 232 case -1: 233 errno = ENOMEM; 234 break; 235 case 2: 236 errno = ENAMETOOLONG; 237 break; 238 case 0: 239 default: 240 errno = ENOENT; 241 break; 242 } 243 goto error1; 244 } 245 246 if (__m_doupdate_init()) 247 goto error1; 248 249 if ((sp = (SCREEN *) calloc(1, sizeof (*sp))) == NULL) 250 goto error1; 251 252 sp->_kfd = -1; 253 sp->_if = in_fp; 254 sp->_of = out_fp; 255 sp->_term = cur_term; 256 257 sp->_unget._size = __m_decode_init((t_decode **) &sp->_decode); 258 259 /* 260 * Maximum length of a multbyte key sequence, including 261 * multibyte characters and terminal function keys. 262 */ 263 if (sp->_unget._size < (M_TYPEAHEAD_SIZE + MB_LEN_MAX)) 264 sp->_unget._size = M_TYPEAHEAD_SIZE + MB_LEN_MAX; 265 266 sp->_unget._stack = calloc((size_t) sp->_unget._size, 267 sizeof (*sp->_unget._stack)); 268 if (sp->_unget._stack == NULL) 269 goto error2; 270 271 if ((wio = (t_wide_io *) calloc(1, sizeof (*wio))) == NULL) 272 goto error2; 273 274 /* Setup wide input for XCurses. */ 275 wio->get = (int (*)(void *)) wgetch; 276 wio->unget = __xc_ungetc; 277 wio->reset = __xc_clearerr; 278 wio->iserror = __xc_ferror; 279 wio->iseof = __xc_feof; 280 sp->_in = wio; 281 282 if (assume_one_line) { 283 /* Assume only one line. */ 284 lines = 1; 285 286 /* Disable capabilities that assume more than one line. */ 287 clear_screen = clr_eos = cursor_up = cursor_down = NULL; 288 cursor_home = cursor_to_ll = cursor_address = NULL; 289 row_address = parm_up_cursor = parm_down_cursor = NULL; 290 291 /* Re-evaluate the cursor motion costs. */ 292 __m_mvcur_cost(); 293 294 /* Reset flag for subsequent calls to newterm(). */ 295 assume_one_line = FALSE; 296 } 297 298 if ((sp->_curscr = newwin(lines, columns, 0, 0)) == NULL) 299 goto error2; 300 301 if ((sp->_newscr = newwin(lines, columns, 0, 0)) == NULL) 302 goto error2; 303 304 #if defined(_LP64) 305 sp->_hash = (unsigned int *) calloc(lines, sizeof (*sp->_hash)); 306 #else 307 sp->_hash = (unsigned long *) calloc(lines, sizeof (*sp->_hash)); 308 #endif 309 if (sp->_hash == NULL) 310 goto error2; 311 312 if (0 <= __m_slk_format && __m_slk_init(sp, __m_slk_format) == ERR) { 313 goto error2; 314 } 315 316 /* 317 * doupdate() will perform the final screen preparations like 318 * enter_ca_mode, reset_prog_mode() (to assert the termios 319 * changes), etc. 320 */ 321 sp->_flags |= S_ENDWIN; 322 323 #ifdef SIGTSTP 324 (void) signal(SIGTSTP, tstp); 325 #endif 326 /* Assert that __m_screen is set to the new terminal. */ 327 osp = set_term(sp); 328 329 /* Disable echo in tty driver, Curses does software echo. */ 330 PTERMIOS(_prog)->c_lflag &= ~ECHO; 331 332 /* Enable mappnig of cr -> nl on input and nl -> crlf on output. */ 333 PTERMIOS(_prog)->c_iflag |= ICRNL; 334 PTERMIOS(_prog)->c_oflag |= OPOST; 335 #ifdef ONLCR 336 PTERMIOS(_prog)->c_oflag |= ONLCR; 337 #endif 338 cur_term->_flags |= __TERM_NL_IS_CRLF; 339 340 #ifdef TAB0 341 /* Use real tabs. */ 342 PTERMIOS(_prog)->c_oflag &= ~(TAB1|TAB2|TAB3); 343 #endif 344 345 /* 346 * Default to 'cbreak' mode as per 347 * test /tset/CAPIxcurses/fcbreak/fcbreak1{4} 348 */ 349 cur_term->_flags &= ~__TERM_HALF_DELAY; 350 351 /* 352 * Default to 'idcok' mode as per 353 * test /tset/CAPIxcurses/fidcok/fidcok1{3} 354 */ 355 __m_screen->_flags |= S_INS_DEL_CHAR; 356 357 PTERMIOS(_prog)->c_cc[VMIN] = 1; 358 PTERMIOS(_prog)->c_cc[VTIME] = 0; 359 PTERMIOS(_prog)->c_lflag &= ~ICANON; 360 361 (void) __m_tty_set_prog_mode(); 362 (void) __m_set_echo(1); 363 (void) typeahead(fileno(in_fp)); 364 365 (void) __m_slk_clear(1); 366 367 n = rip.top - rip.bottom; 368 if (stdscr == NULL) { 369 stdscr = newwin(lines - n, 0, rip.top, 0); 370 if (stdscr == NULL) 371 goto error3; 372 } 373 /* 374 * Create and initialise ripped off line windows. 375 * It is the application's responsiblity to free the 376 * windows when the application terminates. 377 */ 378 for (i = 0; i < n; ++i) { 379 if (rip.line[i].created) 380 continue; 381 y = rip.line[i].dy; 382 if (y < 0) 383 y += lines; 384 385 w = newwin(1, 0, y, 0); 386 if (rip.line[i].init != (int (*)(WINDOW *, int)) 0) 387 (void) (*rip.line[i].init)(w, columns); 388 rip.line[i].created = 1; 389 } 390 LINES = stdscr->_maxy = sp->_curscr->_maxy - n; 391 392 return (sp); 393 error3: 394 (void) set_term(osp); 395 error2: 396 delscreen(sp); 397 error1: 398 return (NULL); 399 } 400 401 /* 402 * Free storage associated with a screen structure. 403 * NOTE endwin() does not do this. 404 */ 405 void 406 delscreen(SCREEN *sp) 407 { 408 if (sp != NULL) { 409 if (sp->_slk._w != NULL) 410 (void) delwin(sp->_slk._w); 411 412 (void) delwin(sp->_newscr); 413 (void) delwin(sp->_curscr); 414 (void) del_curterm(sp->_term); 415 416 __m_decode_free((t_decode **) &sp->_decode); 417 418 if (sp->_hash != NULL) 419 free(sp->_hash); 420 421 if (sp->_unget._stack != NULL) 422 free(sp->_unget._stack); 423 424 if (sp->_in != NULL) 425 free(sp->_in); 426 427 free(sp); 428 } 429 } 430 431 /* 432 * Switch current terminal for Curses layer. 433 */ 434 SCREEN * 435 set_term(SCREEN *screen) 436 { 437 SCREEN *osp = __m_screen; 438 439 if (screen != NULL) { 440 (void) set_curterm(screen->_term); 441 curscr = screen->_curscr; 442 __m_screen = screen; 443 444 LINES = lines; 445 COLS = columns; 446 COLORS = max_colors; 447 COLOR_PAIRS = max_pairs; 448 } 449 450 return (osp); 451 } 452 453 int 454 typeahead(int fd) 455 { 456 __m_screen->_flags &= ~S_ISATTY; 457 if (fd != -1) { 458 if (isatty(fd)) { 459 __m_screen->_kfd = fd; 460 __m_screen->_flags |= S_ISATTY; 461 } else { 462 __m_screen->_kfd = -1; 463 } 464 } 465 466 return (OK); 467 } 468 469 int 470 __m_set_echo(int bf) 471 { 472 int old; 473 474 old = (__m_screen->_flags & S_ECHO) == S_ECHO; 475 476 __m_screen->_flags &= ~S_ECHO; 477 if (bf) 478 __m_screen->_flags |= S_ECHO; 479 480 return (old); 481 } 482