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