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