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