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