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