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