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