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