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