tinfo_driver.c revision 262617
1/**************************************************************************** 2 * Copyright (c) 2008-2009,2010 Free Software Foundation, Inc. * 3 * * 4 * Permission is hereby granted, free of charge, to any person obtaining a * 5 * copy of this software and associated documentation files (the * 6 * "Software"), to deal in the Software without restriction, including * 7 * without limitation the rights to use, copy, modify, merge, publish, * 8 * distribute, distribute with modifications, sublicense, and/or sell * 9 * copies of the Software, and to permit persons to whom the Software is * 10 * furnished to do so, subject to the following conditions: * 11 * * 12 * The above copyright notice and this permission notice shall be included * 13 * in all copies or substantial portions of the Software. * 14 * * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 18 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 21 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 22 * * 23 * Except as contained in this notice, the name(s) of the above copyright * 24 * holders shall not be used in advertising or otherwise to promote the * 25 * sale, use or other dealings in this Software without prior written * 26 * authorization. * 27 ****************************************************************************/ 28 29/**************************************************************************** 30 * Author: Juergen Pfeifer * 31 * * 32 ****************************************************************************/ 33 34#include <curses.priv.h> 35#define CUR ((TERMINAL*)TCB)->type. 36#include <tic.h> 37 38#if HAVE_NANOSLEEP 39#include <time.h> 40#if HAVE_SYS_TIME_H 41#include <sys/time.h> /* needed for MacOS X DP3 */ 42#endif 43#endif 44 45#if HAVE_SIZECHANGE 46# if !defined(sun) || !TERMIOS 47# if HAVE_SYS_IOCTL_H 48# include <sys/ioctl.h> 49# endif 50# endif 51#endif 52 53MODULE_ID("$Id: tinfo_driver.c,v 1.13 2010/12/20 01:47:09 tom Exp $") 54 55/* 56 * SCO defines TIOCGSIZE and the corresponding struct. Other systems (SunOS, 57 * Solaris, IRIX) define TIOCGWINSZ and struct winsize. 58 */ 59#ifdef TIOCGSIZE 60# define IOCTL_WINSIZE TIOCGSIZE 61# define STRUCT_WINSIZE struct ttysize 62# define WINSIZE_ROWS(n) (int)n.ts_lines 63# define WINSIZE_COLS(n) (int)n.ts_cols 64#else 65# ifdef TIOCGWINSZ 66# define IOCTL_WINSIZE TIOCGWINSZ 67# define STRUCT_WINSIZE struct winsize 68# define WINSIZE_ROWS(n) (int)n.ws_row 69# define WINSIZE_COLS(n) (int)n.ws_col 70# endif 71#endif 72 73/* 74 * These should be screen structure members. They need to be globals for 75 * historical reasons. So we assign them in start_color() and also in 76 * set_term()'s screen-switching logic. 77 */ 78#if USE_REENTRANT 79NCURSES_EXPORT(int) 80NCURSES_PUBLIC_VAR(COLOR_PAIRS) (void) 81{ 82 return CURRENT_SCREEN ? CURRENT_SCREEN->_pair_count : -1; 83} 84NCURSES_EXPORT(int) 85NCURSES_PUBLIC_VAR(COLORS) (void) 86{ 87 return CURRENT_SCREEN ? CURRENT_SCREEN->_color_count : -1; 88} 89#else 90NCURSES_EXPORT_VAR(int) COLOR_PAIRS = 0; 91NCURSES_EXPORT_VAR(int) COLORS = 0; 92#endif 93 94#define TCBMAGIC NCDRV_MAGIC(NCDRV_TINFO) 95#define AssertTCB() assert(TCB!=0 && TCB->magic==TCBMAGIC) 96#define SetSP() assert(TCB->csp!=0); sp = TCB->csp 97 98/* 99 * This routine needs to do all the work to make curscr look 100 * like newscr. 101 */ 102static int 103drv_doupdate(TERMINAL_CONTROL_BLOCK * TCB) 104{ 105 AssertTCB(); 106 return TINFO_DOUPDATE(TCB->csp); 107} 108 109#define ret_error(code, fmt, arg) if (errret) {\ 110 *errret = code;\ 111 return(FALSE); \ 112 } else {\ 113 fprintf(stderr, fmt, arg);\ 114 exit(EXIT_FAILURE);\ 115 } 116 117#define ret_error0(code, msg) if (errret) {\ 118 *errret = code;\ 119 return(FALSE);\ 120 } else {\ 121 fprintf(stderr, msg);\ 122 exit(EXIT_FAILURE);\ 123 } 124 125static bool 126drv_CanHandle(TERMINAL_CONTROL_BLOCK * TCB, const char *tname, int *errret) 127{ 128 bool result = FALSE; 129 int status; 130 TERMINAL *termp; 131 SCREEN *sp; 132 133 assert(TCB != 0 && tname != 0); 134 termp = (TERMINAL *) TCB; 135 sp = TCB->csp; 136 TCB->magic = TCBMAGIC; 137 138#if (USE_DATABASE || USE_TERMCAP) 139 status = _nc_setup_tinfo(tname, &termp->type); 140#else 141 status = TGETENT_NO; 142#endif 143 144 /* try fallback list if entry on disk */ 145 if (status != TGETENT_YES) { 146 const TERMTYPE *fallback = _nc_fallback(tname); 147 148 if (fallback) { 149 termp->type = *fallback; 150 status = TGETENT_YES; 151 } 152 } 153 154 if (status != TGETENT_YES) { 155 NCURSES_SP_NAME(del_curterm) (NCURSES_SP_ARGx termp); 156 if (status == TGETENT_ERR) { 157 ret_error0(status, "terminals database is inaccessible\n"); 158 } else if (status == TGETENT_NO) { 159 ret_error(status, "'%s': unknown terminal type.\n", tname); 160 } 161 } 162 result = TRUE; 163#if !USE_REENTRANT 164 strncpy(ttytype, termp->type.term_names, NAMESIZE - 1); 165 ttytype[NAMESIZE - 1] = '\0'; 166#endif 167 168 if (command_character) 169 _nc_tinfo_cmdch(termp, *command_character); 170 171 if (generic_type) { 172 ret_error(TGETENT_NO, "'%s': I need something more specific.\n", tname); 173 } 174 if (hard_copy) { 175 ret_error(TGETENT_YES, "'%s': I can't handle hardcopy terminals.\n", tname); 176 } 177 178 return result; 179} 180 181static int 182drv_dobeepflash(TERMINAL_CONTROL_BLOCK * TCB, bool beepFlag) 183{ 184 SCREEN *sp; 185 int res = ERR; 186 187 AssertTCB(); 188 SetSP(); 189 190 /* FIXME: should make sure that we are not in altchar mode */ 191 if (beepFlag) { 192 if (bell) { 193 res = NCURSES_SP_NAME(_nc_putp) (NCURSES_SP_ARGx "bell", bell); 194 NCURSES_SP_NAME(_nc_flush) (sp); 195 } else if (flash_screen) { 196 res = NCURSES_SP_NAME(_nc_putp) (NCURSES_SP_ARGx 197 "flash_screen", 198 flash_screen); 199 NCURSES_SP_NAME(_nc_flush) (sp); 200 } 201 } else { 202 if (flash_screen) { 203 res = NCURSES_SP_NAME(_nc_putp) (NCURSES_SP_ARGx 204 "flash_screen", 205 flash_screen); 206 NCURSES_SP_NAME(_nc_flush) (sp); 207 } else if (bell) { 208 res = NCURSES_SP_NAME(_nc_putp) (NCURSES_SP_ARGx "bell", bell); 209 NCURSES_SP_NAME(_nc_flush) (sp); 210 } 211 } 212 return res; 213} 214 215/* 216 * SVr4 curses is known to interchange color codes (1,4) and (3,6), possibly 217 * to maintain compatibility with a pre-ANSI scheme. The same scheme is 218 * also used in the FreeBSD syscons. 219 */ 220static int 221toggled_colors(int c) 222{ 223 if (c < 16) { 224 static const int table[] = 225 {0, 4, 2, 6, 1, 5, 3, 7, 226 8, 12, 10, 14, 9, 13, 11, 15}; 227 c = table[c]; 228 } 229 return c; 230} 231 232static int 233drv_print(TERMINAL_CONTROL_BLOCK * TCB, char *data, int len) 234{ 235 SCREEN *sp; 236 237 AssertTCB(); 238 SetSP(); 239#if NCURSES_EXT_FUNCS 240 return NCURSES_SP_NAME(mcprint) (TCB->csp, data, len); 241#else 242 return ERR; 243#endif 244} 245 246static int 247drv_defaultcolors(TERMINAL_CONTROL_BLOCK * TCB, int fg, int bg) 248{ 249 SCREEN *sp; 250 int code = ERR; 251 252 AssertTCB(); 253 SetSP(); 254 255 if (sp != 0 && orig_pair && orig_colors && (initialize_pair != 0)) { 256#if NCURSES_EXT_FUNCS 257 sp->_default_color = isDefaultColor(fg) || isDefaultColor(bg); 258 sp->_has_sgr_39_49 = (NCURSES_SP_NAME(tigetflag) (NCURSES_SP_ARGx 259 "AX") 260 == TRUE); 261 sp->_default_fg = isDefaultColor(fg) ? COLOR_DEFAULT : (fg & C_MASK); 262 sp->_default_bg = isDefaultColor(bg) ? COLOR_DEFAULT : (bg & C_MASK); 263 if (sp->_color_pairs != 0) { 264 bool save = sp->_default_color; 265 sp->_default_color = TRUE; 266 NCURSES_SP_NAME(init_pair) (NCURSES_SP_ARGx 267 0, 268 (short)fg, 269 (short)bg); 270 sp->_default_color = save; 271 } 272#endif 273 code = OK; 274 } 275 return (code); 276} 277 278static void 279drv_setcolor(TERMINAL_CONTROL_BLOCK * TCB, 280 bool fore, 281 int color, 282 NCURSES_SP_OUTC outc) 283{ 284 SCREEN *sp; 285 286 AssertTCB(); 287 SetSP(); 288 289 if (fore) { 290 if (set_a_foreground) { 291 TPUTS_TRACE("set_a_foreground"); 292 NCURSES_SP_NAME(tputs) (NCURSES_SP_ARGx 293 TPARM_1(set_a_foreground, color), 1, outc); 294 } else { 295 TPUTS_TRACE("set_foreground"); 296 NCURSES_SP_NAME(tputs) (NCURSES_SP_ARGx 297 TPARM_1(set_foreground, 298 toggled_colors(color)), 1, outc); 299 } 300 } else { 301 if (set_a_background) { 302 TPUTS_TRACE("set_a_background"); 303 NCURSES_SP_NAME(tputs) (NCURSES_SP_ARGx 304 TPARM_1(set_a_background, color), 1, outc); 305 } else { 306 TPUTS_TRACE("set_background"); 307 NCURSES_SP_NAME(tputs) (NCURSES_SP_ARGx 308 TPARM_1(set_background, 309 toggled_colors(color)), 1, outc); 310 } 311 } 312} 313 314static bool 315drv_rescol(TERMINAL_CONTROL_BLOCK * TCB) 316{ 317 bool result = FALSE; 318 SCREEN *sp; 319 320 AssertTCB(); 321 SetSP(); 322 323 if (orig_pair != 0) { 324 NCURSES_SP_NAME(_nc_putp) (NCURSES_SP_ARGx "orig_pair", orig_pair); 325 result = TRUE; 326 } 327 return result; 328} 329 330static bool 331drv_rescolors(TERMINAL_CONTROL_BLOCK * TCB) 332{ 333 int result = FALSE; 334 SCREEN *sp; 335 336 AssertTCB(); 337 SetSP(); 338 339 if (orig_colors != 0) { 340 NCURSES_SP_NAME(_nc_putp) (NCURSES_SP_ARGx "orig_colors", orig_colors); 341 result = TRUE; 342 } 343 return result; 344} 345 346static int 347drv_size(TERMINAL_CONTROL_BLOCK * TCB, int *linep, int *colp) 348{ 349 SCREEN *sp; 350 bool useEnv = TRUE; 351 352 AssertTCB(); 353 sp = TCB->csp; /* can be null here */ 354 355 if (sp) { 356 useEnv = sp->_use_env; 357 } else 358 useEnv = _nc_prescreen.use_env; 359 360 /* figure out the size of the screen */ 361 T(("screen size: terminfo lines = %d columns = %d", lines, columns)); 362 363 *linep = (int) lines; 364 *colp = (int) columns; 365 366 if (useEnv) { 367 int value; 368 369#ifdef __EMX__ 370 { 371 int screendata[2]; 372 _scrsize(screendata); 373 *colp = screendata[0]; 374 *linep = screendata[1]; 375 T(("EMX screen size: environment LINES = %d COLUMNS = %d", 376 *linep, *colp)); 377 } 378#endif 379#if HAVE_SIZECHANGE 380 /* try asking the OS */ 381 { 382 TERMINAL *termp = (TERMINAL *) TCB; 383 if (isatty(termp->Filedes)) { 384 STRUCT_WINSIZE size; 385 386 errno = 0; 387 do { 388 if (ioctl(termp->Filedes, IOCTL_WINSIZE, &size) >= 0) { 389 *linep = ((sp != 0 && sp->_filtered) 390 ? 1 391 : WINSIZE_ROWS(size)); 392 *colp = WINSIZE_COLS(size); 393 T(("SYS screen size: environment LINES = %d COLUMNS = %d", 394 *linep, *colp)); 395 break; 396 } 397 } while 398 (errno == EINTR); 399 } 400 } 401#endif /* HAVE_SIZECHANGE */ 402 403 /* 404 * Finally, look for environment variables. 405 * 406 * Solaris lets users override either dimension with an environment 407 * variable. 408 */ 409 if ((value = _nc_getenv_num("LINES")) > 0) { 410 *linep = value; 411 T(("screen size: environment LINES = %d", *linep)); 412 } 413 if ((value = _nc_getenv_num("COLUMNS")) > 0) { 414 *colp = value; 415 T(("screen size: environment COLUMNS = %d", *colp)); 416 } 417 418 /* if we can't get dynamic info about the size, use static */ 419 if (*linep <= 0) { 420 *linep = (int) lines; 421 } 422 if (*colp <= 0) { 423 *colp = (int) columns; 424 } 425 426 /* the ultimate fallback, assume fixed 24x80 size */ 427 if (*linep <= 0) { 428 *linep = 24; 429 } 430 if (*colp <= 0) { 431 *colp = 80; 432 } 433 434 /* 435 * Put the derived values back in the screen-size caps, so 436 * tigetnum() and tgetnum() will do the right thing. 437 */ 438 lines = (short) (*linep); 439 columns = (short) (*colp); 440 } 441 442 T(("screen size is %dx%d", *linep, *colp)); 443 return OK; 444} 445 446static int 447drv_getsize(TERMINAL_CONTROL_BLOCK * TCB, int *l, int *c) 448{ 449 AssertTCB(); 450 assert(l != 0 && c != 0); 451 *l = lines; 452 *c = columns; 453 return OK; 454} 455 456static int 457drv_setsize(TERMINAL_CONTROL_BLOCK * TCB, int l, int c) 458{ 459 AssertTCB(); 460 lines = (short) l; 461 columns = (short) c; 462 return OK; 463} 464 465static int 466drv_sgmode(TERMINAL_CONTROL_BLOCK * TCB, bool setFlag, TTY * buf) 467{ 468 SCREEN *sp = TCB->csp; 469 TERMINAL *_term = (TERMINAL *) TCB; 470 int result = OK; 471 472 AssertTCB(); 473 if (setFlag) { 474 for (;;) { 475 if (SET_TTY(_term->Filedes, buf) != 0) { 476 if (errno == EINTR) 477 continue; 478 if (errno == ENOTTY) { 479 if (sp) 480 sp->_notty = TRUE; 481 } 482 result = ERR; 483 } 484 break; 485 } 486 } else { 487 for (;;) { 488 if (GET_TTY(_term->Filedes, buf) != 0) { 489 if (errno == EINTR) 490 continue; 491 result = ERR; 492 } 493 break; 494 } 495 } 496 return result; 497} 498 499static int 500drv_mode(TERMINAL_CONTROL_BLOCK * TCB, bool progFlag, bool defFlag) 501{ 502 SCREEN *sp; 503 TERMINAL *_term = (TERMINAL *) TCB; 504 int code = ERR; 505 506 AssertTCB(); 507 sp = TCB->csp; 508 509 if (progFlag) /* prog mode */ 510 { 511 if (defFlag) { 512 /* def_prog_mode */ 513 /* 514 * Turn off the XTABS bit in the tty structure if it was on. 515 */ 516 if ((drv_sgmode(TCB, FALSE, &(_term->Nttyb)) == OK)) { 517#ifdef TERMIOS 518 _term->Nttyb.c_oflag &= (unsigned) ~OFLAGS_TABS; 519#else 520 _term->Nttyb.sg_flags &= (unsigned) ~XTABS; 521#endif 522 code = OK; 523 } 524 } else { 525 /* reset_prog_mode */ 526 if (drv_sgmode(TCB, TRUE, &(_term->Nttyb)) == OK) { 527 if (sp) { 528 if (sp->_keypad_on) 529 _nc_keypad(sp, TRUE); 530 NC_BUFFERED(sp, TRUE); 531 } 532 code = OK; 533 } 534 } 535 } else { /* shell mode */ 536 if (defFlag) { 537 /* def_shell_mode */ 538 /* 539 * If XTABS was on, remove the tab and backtab capabilities. 540 */ 541 if (drv_sgmode(TCB, FALSE, &(_term->Ottyb)) == OK) { 542#ifdef TERMIOS 543 if (_term->Ottyb.c_oflag & OFLAGS_TABS) 544 tab = back_tab = NULL; 545#else 546 if (_term->Ottyb.sg_flags & XTABS) 547 tab = back_tab = NULL; 548#endif 549 code = OK; 550 } 551 } else { 552 /* reset_shell_mode */ 553 if (sp) { 554 _nc_keypad(sp, FALSE); 555 NCURSES_SP_NAME(_nc_flush) (sp); 556 NC_BUFFERED(sp, FALSE); 557 } 558 code = drv_sgmode(TCB, TRUE, &(_term->Ottyb)); 559 } 560 } 561 return (code); 562} 563 564static void 565drv_wrap(SCREEN *sp) 566{ 567 if (sp) { 568 sp->_mouse_wrap(sp); 569 NCURSES_SP_NAME(_nc_screen_wrap) (sp); 570 NCURSES_SP_NAME(_nc_mvcur_wrap) (sp); /* wrap up cursor addressing */ 571 } 572} 573 574static void 575drv_release(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED) 576{ 577} 578 579# define SGR0_TEST(mode) (mode != 0) && (exit_attribute_mode == 0 || strcmp(mode, exit_attribute_mode)) 580 581static void 582drv_screen_init(SCREEN *sp) 583{ 584 TERMINAL_CONTROL_BLOCK *TCB = TCBOf(sp); 585 586 AssertTCB(); 587 588 /* 589 * Check for mismatched graphic-rendition capabilities. Most SVr4 590 * terminfo trees contain entries that have rmul or rmso equated to 591 * sgr0 (Solaris curses copes with those entries). We do this only 592 * for curses, since many termcap applications assume that 593 * smso/rmso and smul/rmul are paired, and will not function 594 * properly if we remove rmso or rmul. Curses applications 595 * shouldn't be looking at this detail. 596 */ 597 sp->_use_rmso = SGR0_TEST(exit_standout_mode); 598 sp->_use_rmul = SGR0_TEST(exit_underline_mode); 599 600 /* 601 * Check whether we can optimize scrolling under dumb terminals in 602 * case we do not have any of these capabilities, scrolling 603 * optimization will be useless. 604 */ 605 sp->_scrolling = ((scroll_forward && scroll_reverse) || 606 ((parm_rindex || 607 parm_insert_line || 608 insert_line) && 609 (parm_index || 610 parm_delete_line || 611 delete_line))); 612 613 NCURSES_SP_NAME(baudrate) (sp); 614 615 NCURSES_SP_NAME(_nc_mvcur_init) (sp); 616 /* initialize terminal to a sane state */ 617 NCURSES_SP_NAME(_nc_screen_init) (sp); 618} 619 620static void 621drv_init(TERMINAL_CONTROL_BLOCK * TCB) 622{ 623 SCREEN *sp; 624 TERMINAL *trm; 625 626 AssertTCB(); 627 628 trm = (TERMINAL *) TCB; 629 sp = TCB->csp; 630 631 TCB->info.initcolor = initialize_color; 632 TCB->info.canchange = can_change; 633 TCB->info.hascolor = ((VALID_NUMERIC(max_colors) && VALID_NUMERIC(max_pairs) 634 && (((set_foreground != NULL) 635 && (set_background != NULL)) 636 || ((set_a_foreground != NULL) 637 && (set_a_background != NULL)) 638 || set_color_pair)) ? TRUE : FALSE); 639 640 TCB->info.caninit = !(exit_ca_mode && non_rev_rmcup); 641 642 TCB->info.maxpairs = VALID_NUMERIC(max_pairs) ? max_pairs : 0; 643 TCB->info.maxcolors = VALID_NUMERIC(max_colors) ? max_colors : 0; 644 TCB->info.numlabels = VALID_NUMERIC(num_labels) ? num_labels : 0; 645 TCB->info.labelwidth = VALID_NUMERIC(label_width) ? label_width : 0; 646 TCB->info.labelheight = VALID_NUMERIC(label_height) ? label_height : 0; 647 TCB->info.nocolorvideo = VALID_NUMERIC(no_color_video) ? no_color_video 648 : 0; 649 TCB->info.tabsize = VALID_NUMERIC(init_tabs) ? (int) init_tabs : 8; 650 651 TCB->info.defaultPalette = hue_lightness_saturation ? _nc_hls_palette : _nc_cga_palette; 652 653 /* 654 * If an application calls setupterm() rather than initscr() or 655 * newterm(), we will not have the def_prog_mode() call in 656 * _nc_setupscreen(). Do it now anyway, so we can initialize the 657 * baudrate. 658 */ 659 if (isatty(trm->Filedes)) { 660 TCB->drv->mode(TCB, TRUE, TRUE); 661 } 662} 663 664#define MAX_PALETTE 8 665#define InPalette(n) ((n) >= 0 && (n) < MAX_PALETTE) 666 667static void 668drv_initpair(TERMINAL_CONTROL_BLOCK * TCB, short pair, short f, short b) 669{ 670 SCREEN *sp; 671 672 AssertTCB(); 673 SetSP(); 674 675 if ((initialize_pair != NULL) && InPalette(f) && InPalette(b)) { 676 const color_t *tp = InfoOf(sp).defaultPalette; 677 678 TR(TRACE_ATTRS, 679 ("initializing pair: pair = %d, fg=(%d,%d,%d), bg=(%d,%d,%d)", 680 pair, 681 tp[f].red, tp[f].green, tp[f].blue, 682 tp[b].red, tp[b].green, tp[b].blue)); 683 684 NCURSES_SP_NAME(_nc_putp) (NCURSES_SP_ARGx 685 "initialize_pair", 686 TPARM_7(initialize_pair, 687 pair, 688 tp[f].red, tp[f].green, tp[f].blue, 689 tp[b].red, tp[b].green, tp[b].blue)); 690 } 691} 692 693static int 694default_fg(SCREEN *sp) 695{ 696#if NCURSES_EXT_FUNCS 697 return (sp != 0) ? sp->_default_fg : COLOR_WHITE; 698#else 699 return COLOR_WHITE; 700#endif 701} 702 703static int 704default_bg(SCREEN *sp) 705{ 706#if NCURSES_EXT_FUNCS 707 return sp != 0 ? sp->_default_bg : COLOR_BLACK; 708#else 709 return COLOR_BLACK; 710#endif 711} 712 713static void 714drv_initcolor(TERMINAL_CONTROL_BLOCK * TCB, 715 short color, short r, short g, short b) 716{ 717 SCREEN *sp = TCB->csp; 718 719 AssertTCB(); 720 if (initialize_color != NULL) { 721 NCURSES_SP_NAME(_nc_putp) (NCURSES_SP_ARGx 722 "initialize_color", 723 TPARM_4(initialize_color, color, r, g, b)); 724 } 725} 726 727static void 728drv_do_color(TERMINAL_CONTROL_BLOCK * TCB, 729 short old_pair, 730 short pair, 731 bool reverse, 732 NCURSES_SP_OUTC outc) 733{ 734 SCREEN *sp = TCB->csp; 735 NCURSES_COLOR_T fg = COLOR_DEFAULT; 736 NCURSES_COLOR_T bg = COLOR_DEFAULT; 737 NCURSES_COLOR_T old_fg, old_bg; 738 739 AssertTCB(); 740 if (sp == 0) 741 return; 742 743 if (pair < 0 || pair >= COLOR_PAIRS) { 744 return; 745 } else if (pair != 0) { 746 if (set_color_pair) { 747 TPUTS_TRACE("set_color_pair"); 748 NCURSES_SP_NAME(tputs) (NCURSES_SP_ARGx 749 TPARM_1(set_color_pair, pair), 1, outc); 750 return; 751 } else if (sp != 0) { 752 NCURSES_SP_NAME(pair_content) (NCURSES_SP_ARGx 753 (short) pair, 754 &fg, 755 &bg); 756 } 757 } 758 759 if (old_pair >= 0 760 && sp != 0 761 && NCURSES_SP_NAME(pair_content) (NCURSES_SP_ARGx 762 old_pair, 763 &old_fg, 764 &old_bg) !=ERR) { 765 if ((isDefaultColor(fg) && !isDefaultColor(old_fg)) 766 || (isDefaultColor(bg) && !isDefaultColor(old_bg))) { 767#if NCURSES_EXT_FUNCS 768 /* 769 * A minor optimization - but extension. If "AX" is specified in 770 * the terminal description, treat it as screen's indicator of ECMA 771 * SGR 39 and SGR 49, and assume the two sequences are independent. 772 */ 773 if (sp->_has_sgr_39_49 774 && isDefaultColor(old_bg) 775 && !isDefaultColor(old_fg)) { 776 NCURSES_SP_NAME(tputs) (NCURSES_SP_ARGx "\033[39m", 1, outc); 777 } else if (sp->_has_sgr_39_49 778 && isDefaultColor(old_fg) 779 && !isDefaultColor(old_bg)) { 780 NCURSES_SP_NAME(tputs) (NCURSES_SP_ARGx "\033[49m", 1, outc); 781 } else 782#endif 783 drv_rescol(TCB); 784 } 785 } else { 786 drv_rescol(TCB); 787 if (old_pair < 0) 788 return; 789 } 790 791#if NCURSES_EXT_FUNCS 792 if (isDefaultColor(fg)) 793 fg = (NCURSES_COLOR_T) default_fg(sp); 794 if (isDefaultColor(bg)) 795 bg = (NCURSES_COLOR_T) default_bg(sp); 796#endif 797 798 if (reverse) { 799 NCURSES_COLOR_T xx = fg; 800 fg = bg; 801 bg = xx; 802 } 803 804 TR(TRACE_ATTRS, ("setting colors: pair = %d, fg = %d, bg = %d", pair, 805 fg, bg)); 806 807 if (!isDefaultColor(fg)) { 808 drv_setcolor(TCB, TRUE, fg, outc); 809 } 810 if (!isDefaultColor(bg)) { 811 drv_setcolor(TCB, FALSE, bg, outc); 812 } 813} 814 815#define xterm_kmous "\033[M" 816static void 817init_xterm_mouse(SCREEN *sp) 818{ 819 sp->_mouse_type = M_XTERM; 820 sp->_mouse_xtermcap = NCURSES_SP_NAME(tigetstr) (NCURSES_SP_ARGx "XM"); 821 if (!VALID_STRING(sp->_mouse_xtermcap)) 822 sp->_mouse_xtermcap = "\033[?1000%?%p1%{1}%=%th%el%;"; 823} 824 825static void 826drv_initmouse(TERMINAL_CONTROL_BLOCK * TCB) 827{ 828 SCREEN *sp; 829 830 AssertTCB(); 831 SetSP(); 832 833 /* we know how to recognize mouse events under "xterm" */ 834 if (sp != 0) { 835 if (key_mouse != 0) { 836 if (!strcmp(key_mouse, xterm_kmous) 837 || strstr(TerminalOf(sp)->type.term_names, "xterm") != 0) { 838 init_xterm_mouse(sp); 839 } 840 } else if (strstr(TerminalOf(sp)->type.term_names, "xterm") != 0) { 841 if (_nc_add_to_try(&(sp->_keytry), xterm_kmous, KEY_MOUSE) == OK) 842 init_xterm_mouse(sp); 843 } 844 } 845} 846 847static int 848drv_testmouse(TERMINAL_CONTROL_BLOCK * TCB, int delay) 849{ 850 int rc = 0; 851 SCREEN *sp; 852 853 AssertTCB(); 854 SetSP(); 855 856#if USE_SYSMOUSE 857 if ((sp->_mouse_type == M_SYSMOUSE) 858 && (sp->_sysmouse_head < sp->_sysmouse_tail)) { 859 rc = TW_MOUSE; 860 } else 861#endif 862 { 863 rc = TCBOf(sp)->drv->twait(TCBOf(sp), 864 TWAIT_MASK, 865 delay, 866 (int *) 0 867 EVENTLIST_2nd(evl)); 868#if USE_SYSMOUSE 869 if ((sp->_mouse_type == M_SYSMOUSE) 870 && (sp->_sysmouse_head < sp->_sysmouse_tail) 871 && (rc == 0) 872 && (errno == EINTR)) { 873 rc |= TW_MOUSE; 874 } 875#endif 876 } 877 return rc; 878} 879 880static int 881drv_mvcur(TERMINAL_CONTROL_BLOCK * TCB, int yold, int xold, int ynew, int xnew) 882{ 883 SCREEN *sp = TCB->csp; 884 AssertTCB(); 885 return TINFO_MVCUR(sp, yold, xold, ynew, xnew); 886} 887 888static void 889drv_hwlabel(TERMINAL_CONTROL_BLOCK * TCB, int labnum, char *text) 890{ 891 SCREEN *sp = TCB->csp; 892 893 AssertTCB(); 894 if (labnum > 0 && labnum <= num_labels) { 895 NCURSES_SP_NAME(_nc_putp) (NCURSES_SP_ARGx 896 "plab_norm", 897 TPARM_2(plab_norm, labnum, text)); 898 } 899} 900 901static void 902drv_hwlabelOnOff(TERMINAL_CONTROL_BLOCK * TCB, bool OnFlag) 903{ 904 SCREEN *sp = TCB->csp; 905 906 AssertTCB(); 907 if (OnFlag) { 908 NCURSES_SP_NAME(_nc_putp) (NCURSES_SP_ARGx "label_on", label_on); 909 } else { 910 NCURSES_SP_NAME(_nc_putp) (NCURSES_SP_ARGx "label_off", label_off); 911 } 912} 913 914static chtype 915drv_conattr(TERMINAL_CONTROL_BLOCK * TCB) 916{ 917 SCREEN *sp = TCB->csp; 918 chtype attrs = A_NORMAL; 919 920 AssertTCB(); 921 if (enter_alt_charset_mode) 922 attrs |= A_ALTCHARSET; 923 924 if (enter_blink_mode) 925 attrs |= A_BLINK; 926 927 if (enter_bold_mode) 928 attrs |= A_BOLD; 929 930 if (enter_dim_mode) 931 attrs |= A_DIM; 932 933 if (enter_reverse_mode) 934 attrs |= A_REVERSE; 935 936 if (enter_standout_mode) 937 attrs |= A_STANDOUT; 938 939 if (enter_protected_mode) 940 attrs |= A_PROTECT; 941 942 if (enter_secure_mode) 943 attrs |= A_INVIS; 944 945 if (enter_underline_mode) 946 attrs |= A_UNDERLINE; 947 948 if (sp && sp->_coloron) 949 attrs |= A_COLOR; 950 951 return (attrs); 952} 953 954static void 955drv_setfilter(TERMINAL_CONTROL_BLOCK * TCB) 956{ 957 AssertTCB(); 958 959 clear_screen = 0; 960 cursor_down = parm_down_cursor = 0; 961 cursor_address = 0; 962 cursor_up = parm_up_cursor = 0; 963 row_address = 0; 964 cursor_home = carriage_return; 965} 966 967static void 968drv_initacs(TERMINAL_CONTROL_BLOCK * TCB, chtype *real_map, chtype *fake_map) 969{ 970 SCREEN *sp = TCB->csp; 971 972 AssertTCB(); 973 assert(sp != 0); 974 if (ena_acs != NULL) { 975 NCURSES_SP_NAME(_nc_putp) (NCURSES_SP_ARGx "ena_acs", ena_acs); 976 } 977#if NCURSES_EXT_FUNCS 978 /* 979 * Linux console "supports" the "PC ROM" character set by the coincidence 980 * that smpch/rmpch and smacs/rmacs have the same values. ncurses has 981 * no codepage support (see SCO Merge for an example). Outside of the 982 * values defined in acsc, there are no definitions for the "PC ROM" 983 * character set (assumed by some applications to be codepage 437), but we 984 * allow those applications to use those codepoints. 985 * 986 * test/blue.c uses this feature. 987 */ 988#define PCH_KLUDGE(a,b) (a != 0 && b != 0 && !strcmp(a,b)) 989 if (PCH_KLUDGE(enter_pc_charset_mode, enter_alt_charset_mode) && 990 PCH_KLUDGE(exit_pc_charset_mode, exit_alt_charset_mode)) { 991 size_t i; 992 for (i = 1; i < ACS_LEN; ++i) { 993 if (real_map[i] == 0) { 994 real_map[i] = i; 995 if (real_map != fake_map) { 996 if (sp != 0) 997 sp->_screen_acs_map[i] = TRUE; 998 } 999 } 1000 } 1001 } 1002#endif 1003 1004 if (acs_chars != NULL) { 1005 size_t i = 0; 1006 size_t length = strlen(acs_chars); 1007 1008 while (i + 1 < length) { 1009 if (acs_chars[i] != 0 && UChar(acs_chars[i]) < ACS_LEN) { 1010 real_map[UChar(acs_chars[i])] = UChar(acs_chars[i + 1]) | A_ALTCHARSET; 1011 if (sp != 0) 1012 sp->_screen_acs_map[UChar(acs_chars[i])] = TRUE; 1013 } 1014 i += 2; 1015 } 1016 } 1017#ifdef TRACE 1018 /* Show the equivalent mapping, noting if it does not match the 1019 * given attribute, whether by re-ordering or duplication. 1020 */ 1021 if (USE_TRACEF(TRACE_CALLS)) { 1022 size_t n, m; 1023 char show[ACS_LEN * 2 + 1]; 1024 for (n = 1, m = 0; n < ACS_LEN; n++) { 1025 if (real_map[n] != 0) { 1026 show[m++] = (char) n; 1027 show[m++] = (char) ChCharOf(real_map[n]); 1028 } 1029 } 1030 show[m] = 0; 1031 if (acs_chars == NULL || strcmp(acs_chars, show)) 1032 _tracef("%s acs_chars %s", 1033 (acs_chars == NULL) ? "NULL" : "READ", 1034 _nc_visbuf(acs_chars)); 1035 _tracef("%s acs_chars %s", 1036 (acs_chars == NULL) 1037 ? "NULL" 1038 : (strcmp(acs_chars, show) 1039 ? "DIFF" 1040 : "SAME"), 1041 _nc_visbuf(show)); 1042 1043 _nc_unlock_global(tracef); 1044 } 1045#endif /* TRACE */ 1046} 1047 1048#define ENSURE_TINFO(sp) (TCBOf(sp)->drv->isTerminfo) 1049 1050NCURSES_EXPORT(void) 1051_nc_cookie_init(SCREEN *sp) 1052{ 1053 bool support_cookies = USE_XMC_SUPPORT; 1054 TERMINAL_CONTROL_BLOCK *TCB = (TERMINAL_CONTROL_BLOCK *) (sp->_term); 1055 1056 if (sp == 0 || !ENSURE_TINFO(sp)) 1057 return; 1058 1059#if USE_XMC_SUPPORT 1060 /* 1061 * If we have no magic-cookie support compiled-in, or if it is suppressed 1062 * in the environment, reset the support-flag. 1063 */ 1064 if (magic_cookie_glitch >= 0) { 1065 if (getenv("NCURSES_NO_MAGIC_COOKIE") != 0) { 1066 support_cookies = FALSE; 1067 } 1068 } 1069#endif 1070 1071 if (!support_cookies && magic_cookie_glitch >= 0) { 1072 T(("will disable attributes to work w/o magic cookies")); 1073 } 1074 1075 if (magic_cookie_glitch > 0) { /* tvi, wyse */ 1076 1077 sp->_xmc_triggers = sp->_ok_attributes & ( 1078 A_STANDOUT | 1079 A_UNDERLINE | 1080 A_REVERSE | 1081 A_BLINK | 1082 A_DIM | 1083 A_BOLD | 1084 A_INVIS | 1085 A_PROTECT 1086 ); 1087#if 0 1088 /* 1089 * We "should" treat colors as an attribute. The wyse350 (and its 1090 * clones) appear to be the only ones that have both colors and magic 1091 * cookies. 1092 */ 1093 if (has_colors()) { 1094 sp->_xmc_triggers |= A_COLOR; 1095 } 1096#endif 1097 sp->_xmc_suppress = sp->_xmc_triggers & (chtype) ~(A_BOLD); 1098 1099 T(("magic cookie attributes %s", _traceattr(sp->_xmc_suppress))); 1100 /* 1101 * Supporting line-drawing may be possible. But make the regular 1102 * video attributes work first. 1103 */ 1104 acs_chars = ABSENT_STRING; 1105 ena_acs = ABSENT_STRING; 1106 enter_alt_charset_mode = ABSENT_STRING; 1107 exit_alt_charset_mode = ABSENT_STRING; 1108#if USE_XMC_SUPPORT 1109 /* 1110 * To keep the cookie support simple, suppress all of the optimization 1111 * hooks except for clear_screen and the cursor addressing. 1112 */ 1113 if (support_cookies) { 1114 clr_eol = ABSENT_STRING; 1115 clr_eos = ABSENT_STRING; 1116 set_attributes = ABSENT_STRING; 1117 } 1118#endif 1119 } else if (magic_cookie_glitch == 0) { /* hpterm */ 1120 } 1121 1122 /* 1123 * If magic cookies are not supported, cancel the strings that set 1124 * video attributes. 1125 */ 1126 if (!support_cookies && magic_cookie_glitch >= 0) { 1127 magic_cookie_glitch = ABSENT_NUMERIC; 1128 set_attributes = ABSENT_STRING; 1129 enter_blink_mode = ABSENT_STRING; 1130 enter_bold_mode = ABSENT_STRING; 1131 enter_dim_mode = ABSENT_STRING; 1132 enter_reverse_mode = ABSENT_STRING; 1133 enter_standout_mode = ABSENT_STRING; 1134 enter_underline_mode = ABSENT_STRING; 1135 } 1136 1137 /* initialize normal acs before wide, since we use mapping in the latter */ 1138#if !USE_WIDEC_SUPPORT 1139 if (_nc_unicode_locale() && _nc_locale_breaks_acs(sp->_term)) { 1140 acs_chars = NULL; 1141 ena_acs = NULL; 1142 enter_alt_charset_mode = NULL; 1143 exit_alt_charset_mode = NULL; 1144 set_attributes = NULL; 1145 } 1146#endif 1147} 1148 1149static int 1150drv_twait(TERMINAL_CONTROL_BLOCK * TCB, 1151 int mode, 1152 int milliseconds, 1153 int *timeleft 1154 EVENTLIST_2nd(_nc_eventlist * evl)) 1155{ 1156 SCREEN *sp; 1157 1158 AssertTCB(); 1159 SetSP(); 1160 1161 return _nc_timed_wait(sp, mode, milliseconds, timeleft EVENTLIST_2nd(evl)); 1162} 1163 1164static int 1165drv_read(TERMINAL_CONTROL_BLOCK * TCB, int *buf) 1166{ 1167 SCREEN *sp; 1168 unsigned char c2 = 0; 1169 int n; 1170 1171 AssertTCB(); 1172 assert(buf); 1173 SetSP(); 1174 1175# if USE_PTHREADS_EINTR 1176 if ((pthread_self) && (pthread_kill) && (pthread_equal)) 1177 _nc_globals.read_thread = pthread_self(); 1178# endif 1179 n = read(sp->_ifd, &c2, 1); 1180#if USE_PTHREADS_EINTR 1181 _nc_globals.read_thread = 0; 1182#endif 1183 *buf = (int) c2; 1184 return n; 1185} 1186 1187static int 1188drv_nap(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int ms) 1189{ 1190#if HAVE_NANOSLEEP 1191 { 1192 struct timespec request, remaining; 1193 request.tv_sec = ms / 1000; 1194 request.tv_nsec = (ms % 1000) * 1000000; 1195 while (nanosleep(&request, &remaining) == -1 1196 && errno == EINTR) { 1197 request = remaining; 1198 } 1199 } 1200#else 1201 _nc_timed_wait(0, 0, ms, (int *) 0 EVENTLIST_2nd(0)); 1202#endif 1203 return OK; 1204} 1205 1206static int 1207__nc_putp(SCREEN *sp, const char *name GCC_UNUSED, const char *value) 1208{ 1209 int rc = ERR; 1210 1211 if (value) { 1212 rc = NCURSES_SP_NAME(_nc_putp) (NCURSES_SP_ARGx name, value); 1213 } 1214 return rc; 1215} 1216 1217static int 1218__nc_putp_flush(SCREEN *sp, const char *name, const char *value) 1219{ 1220 int rc = __nc_putp(sp, name, value); 1221 if (rc != ERR) { 1222 NCURSES_SP_NAME(_nc_flush) (sp); 1223 } 1224 return rc; 1225} 1226 1227static int 1228drv_kpad(TERMINAL_CONTROL_BLOCK * TCB, bool flag) 1229{ 1230 int ret = ERR; 1231 SCREEN *sp; 1232 1233 AssertTCB(); 1234 1235 sp = TCB->csp; 1236 1237 if (sp) { 1238 if (flag) { 1239 (void) __nc_putp_flush(sp, "keypad_xmit", keypad_xmit); 1240 } else if (!flag && keypad_local) { 1241 (void) __nc_putp_flush(sp, "keypad_local", keypad_local); 1242 } 1243 if (flag && !sp->_tried) { 1244 _nc_init_keytry(sp); 1245 sp->_tried = TRUE; 1246 } 1247 ret = OK; 1248 } 1249 1250 return ret; 1251} 1252 1253static int 1254drv_keyok(TERMINAL_CONTROL_BLOCK * TCB, int c, bool flag) 1255{ 1256 SCREEN *sp; 1257 int code = ERR; 1258 int count = 0; 1259 char *s; 1260 1261 AssertTCB(); 1262 SetSP(); 1263 1264 if (c >= 0) { 1265 unsigned ch = (unsigned) c; 1266 if (flag) { 1267 while ((s = _nc_expand_try(sp->_key_ok, ch, &count, 0)) != 0 1268 && _nc_remove_key(&(sp->_key_ok), ch)) { 1269 code = _nc_add_to_try(&(sp->_keytry), s, ch); 1270 free(s); 1271 count = 0; 1272 if (code != OK) 1273 break; 1274 } 1275 } else { 1276 while ((s = _nc_expand_try(sp->_keytry, ch, &count, 0)) != 0 1277 && _nc_remove_key(&(sp->_keytry), ch)) { 1278 code = _nc_add_to_try(&(sp->_key_ok), s, ch); 1279 free(s); 1280 count = 0; 1281 if (code != OK) 1282 break; 1283 } 1284 } 1285 } 1286 return (code); 1287} 1288 1289static bool 1290drv_kyExist(TERMINAL_CONTROL_BLOCK * TCB, int key) 1291{ 1292 bool res = FALSE; 1293 1294 AssertTCB(); 1295 if (TCB->csp) 1296 res = TINFO_HAS_KEY(TCB->csp, key) == 0 ? FALSE : TRUE; 1297 1298 return res; 1299} 1300 1301NCURSES_EXPORT_VAR (TERM_DRIVER) _nc_TINFO_DRIVER = { 1302 TRUE, 1303 drv_CanHandle, /* CanHandle */ 1304 drv_init, /* init */ 1305 drv_release, /* release */ 1306 drv_size, /* size */ 1307 drv_sgmode, /* sgmode */ 1308 drv_conattr, /* conattr */ 1309 drv_mvcur, /* hwcur */ 1310 drv_mode, /* mode */ 1311 drv_rescol, /* rescol */ 1312 drv_rescolors, /* rescolors */ 1313 drv_setcolor, /* color */ 1314 drv_dobeepflash, /* doBeepOrFlash */ 1315 drv_initpair, /* initpair */ 1316 drv_initcolor, /* initcolor */ 1317 drv_do_color, /* docolor */ 1318 drv_initmouse, /* initmouse */ 1319 drv_testmouse, /* testmouse */ 1320 drv_setfilter, /* setfilter */ 1321 drv_hwlabel, /* hwlabel */ 1322 drv_hwlabelOnOff, /* hwlabelOnOff */ 1323 drv_doupdate, /* update */ 1324 drv_defaultcolors, /* defaultcolors */ 1325 drv_print, /* print */ 1326 drv_getsize, /* getsize */ 1327 drv_setsize, /* setsize */ 1328 drv_initacs, /* initacs */ 1329 drv_screen_init, /* scinit */ 1330 drv_wrap, /* scexit */ 1331 drv_twait, /* twait */ 1332 drv_read, /* read */ 1333 drv_nap, /* nap */ 1334 drv_kpad, /* kpad */ 1335 drv_keyok, /* kyOk */ 1336 drv_kyExist /* kyExist */ 1337}; 1338