]> ncurses.scripts.mit.edu Git - ncurses.git/blobdiff - ncurses/tinfo/tinfo_driver.c
ncurses 6.2 - patch 20210320
[ncurses.git] / ncurses / tinfo / tinfo_driver.c
index 785847bdc1ec034659a4c77e22a0137f18d9dcc1..c28d76415549dfa5ad65dd4c569cc1b440ec7856 100644 (file)
@@ -1,5 +1,6 @@
 /****************************************************************************
- * Copyright (c) 2008-2013,2014 Free Software Foundation, Inc.              *
+ * Copyright 2018-2019,2020 Thomas E. Dickey                                *
+ * Copyright 2008-2016,2017 Free Software Foundation, Inc.                  *
  *                                                                          *
  * Permission is hereby granted, free of charge, to any person obtaining a  *
  * copy of this software and associated documentation files (the            *
 
 /****************************************************************************
  *  Author: Juergen Pfeifer                                                 *
- *                                                                          *
+ *     and: Thomas E. Dickey                                                *
  ****************************************************************************/
 
 #include <curses.priv.h>
-#define CUR ((TERMINAL*)TCB)->type.
+#define CUR TerminalType((TERMINAL*)TCB).
 #include <tic.h>
+#include <termcap.h>           /* ospeed */
 
 #if HAVE_NANOSLEEP
 #include <time.h>
@@ -50,7 +52,7 @@
 # endif
 #endif
 
-MODULE_ID("$Id: tinfo_driver.c,v 1.37 2014/04/13 00:17:08 tom Exp $")
+MODULE_ID("$Id: tinfo_driver.c,v 1.71 2020/12/12 01:06:40 tom Exp $")
 
 /*
  * SCO defines TIOCGSIZE and the corresponding struct.  Other systems (SunOS,
@@ -113,6 +115,43 @@ drv_Name(TERMINAL_CONTROL_BLOCK * TCB)
     return "tinfo";
 }
 
+static void
+get_baudrate(TERMINAL *termp)
+{
+    int my_ospeed;
+    int result;
+    if (GET_TTY(termp->Filedes, &termp->Nttyb) == OK) {
+#ifdef TERMIOS
+       termp->Nttyb.c_oflag &= (unsigned) (~OFLAGS_TABS);
+#elif defined(EXP_WIN32_DRIVER)
+       /* noop */
+#else
+       termp->Nttyb.sg_flags &= (unsigned) (~XTABS);
+#endif
+    }
+#ifdef USE_OLD_TTY
+    result = (int) cfgetospeed(&(termp->Nttyb));
+    my_ospeed = (NCURSES_OSPEED) _nc_ospeed(result);
+#else /* !USE_OLD_TTY */
+#ifdef TERMIOS
+    my_ospeed = (NCURSES_OSPEED) cfgetospeed(&(termp->Nttyb));
+#elif defined(EXP_WIN32_DRIVER)
+    /* noop */
+    my_ospeed = 0;
+#else
+    my_ospeed = (NCURSES_OSPEED) termp->Nttyb.sg_ospeed;
+#endif
+    result = _nc_baudrate(my_ospeed);
+#endif
+    termp->_baudrate = result;
+    ospeed = (NCURSES_OSPEED) my_ospeed;
+}
+
+#undef SETUP_FAIL
+#define SETUP_FAIL FALSE
+
+#define NO_COPY {}
+
 static bool
 drv_CanHandle(TERMINAL_CONTROL_BLOCK * TCB, const char *tname, int *errret)
 {
@@ -121,7 +160,8 @@ drv_CanHandle(TERMINAL_CONTROL_BLOCK * TCB, const char *tname, int *errret)
     TERMINAL *termp;
     SCREEN *sp;
 
-    T((T_CALLED("tinfo::drv_CanHandle(%p)"), TCB));
+    START_TRACE();
+    T((T_CALLED("tinfo::drv_CanHandle(%p)"), (void *) TCB));
 
     assert(TCB != 0 && tname != 0);
     termp = (TERMINAL *) TCB;
@@ -129,17 +169,20 @@ drv_CanHandle(TERMINAL_CONTROL_BLOCK * TCB, const char *tname, int *errret)
     TCB->magic = TCBMAGIC;
 
 #if (NCURSES_USE_DATABASE || NCURSES_USE_TERMCAP)
-    status = _nc_setup_tinfo(tname, &termp->type);
+    status = _nc_setup_tinfo(tname, &TerminalType(termp));
+    T(("_nc_setup_tinfo returns %d", status));
 #else
+    T(("no database available"));
     status = TGETENT_NO;
 #endif
 
     /* try fallback list if entry on disk */
     if (status != TGETENT_YES) {
-       const TERMTYPE *fallback = _nc_fallback(tname);
+       const TERMTYPE2 *fallback = _nc_fallback2(tname);
 
        if (fallback) {
-           termp->type = *fallback;
+           T(("found fallback entry"));
+           TerminalType(termp) = *fallback;
            status = TGETENT_YES;
        }
     }
@@ -149,18 +192,41 @@ drv_CanHandle(TERMINAL_CONTROL_BLOCK * TCB, const char *tname, int *errret)
        if (status == TGETENT_ERR) {
            ret_error0(status, "terminals database is inaccessible\n");
        } else if (status == TGETENT_NO) {
-           ret_error1(status, "unknown terminal type.\n", tname);
+           ret_error1(status, "unknown terminal type.\n",
+                      tname, NO_COPY);
+       } else {
+           ret_error0(status, "unexpected return-code\n");
        }
     }
     result = TRUE;
+#if NCURSES_EXT_NUMBERS
+    _nc_export_termtype2(&termp->type, &TerminalType(termp));
+#endif
 #if !USE_REENTRANT
-    strncpy(ttytype, termp->type.term_names, (size_t) NAMESIZE - 1);
-    ttytype[NAMESIZE - 1] = '\0';
+    save_ttytype(termp);
 #endif
 
     if (command_character)
        _nc_tinfo_cmdch(termp, *command_character);
 
+    /*
+     * If an application calls setupterm() rather than initscr() or
+     * newterm(), we will not have the def_prog_mode() call in
+     * _nc_setupscreen().  Do it now anyway, so we can initialize the
+     * baudrate.
+     */
+    if (sp == 0 && NC_ISATTY(termp->Filedes)) {
+       get_baudrate(termp);
+    }
+#if NCURSES_EXT_NUMBERS
+#define cleanup_termtype() \
+    _nc_free_termtype2(&TerminalType(termp)); \
+    _nc_free_termtype(&termp->type)
+#else
+#define cleanup_termtype() \
+    _nc_free_termtype2(&TerminalType(termp))
+#endif
+
     if (generic_type) {
        /*
         * BSD 4.3's termcap contains mis-typed "gn" for wy99.  Do a sanity
@@ -169,13 +235,19 @@ drv_CanHandle(TERMINAL_CONTROL_BLOCK * TCB, const char *tname, int *errret)
        if ((VALID_STRING(cursor_address)
             || (VALID_STRING(cursor_down) && VALID_STRING(cursor_home)))
            && VALID_STRING(clear_screen)) {
-           ret_error1(TGETENT_YES, "terminal is not really generic.\n", tname);
+           cleanup_termtype();
+           ret_error1(TGETENT_YES, "terminal is not really generic.\n",
+                      tname, NO_COPY);
        } else {
-           ret_error1(TGETENT_NO, "I need something more specific.\n", tname);
+           cleanup_termtype();
+           ret_error1(TGETENT_NO, "I need something more specific.\n",
+                      tname, NO_COPY);
        }
     }
     if (hard_copy) {
-       ret_error1(TGETENT_YES, "I can't handle hardcopy terminals.\n", tname);
+       cleanup_termtype();
+       ret_error1(TGETENT_YES, "I can't handle hardcopy terminals.\n",
+                  tname, NO_COPY);
     }
 
     returnBool(result);
@@ -257,8 +329,8 @@ drv_defaultcolors(TERMINAL_CONTROL_BLOCK * TCB, int fg, int bg)
        sp->_has_sgr_39_49 = (NCURSES_SP_NAME(tigetflag) (NCURSES_SP_ARGx
                                                          "AX")
                              == TRUE);
-       sp->_default_fg = isDefaultColor(fg) ? COLOR_DEFAULT : (fg & C_MASK);
-       sp->_default_bg = isDefaultColor(bg) ? COLOR_DEFAULT : (bg & C_MASK);
+       sp->_default_fg = isDefaultColor(fg) ? COLOR_DEFAULT : fg;
+       sp->_default_bg = isDefaultColor(bg) ? COLOR_DEFAULT : bg;
        if (sp->_color_pairs != 0) {
            bool save = sp->_default_color;
            sp->_default_color = TRUE;
@@ -289,23 +361,23 @@ drv_setcolor(TERMINAL_CONTROL_BLOCK * TCB,
        if (set_a_foreground) {
            TPUTS_TRACE("set_a_foreground");
            NCURSES_SP_NAME(tputs) (NCURSES_SP_ARGx
-                                   TPARM_1(set_a_foreground, color), 1, outc);
+                                   TIPARM_1(set_a_foreground, color), 1, outc);
        } else {
            TPUTS_TRACE("set_foreground");
            NCURSES_SP_NAME(tputs) (NCURSES_SP_ARGx
-                                   TPARM_1(set_foreground,
-                                           toggled_colors(color)), 1, outc);
+                                   TIPARM_1(set_foreground,
+                                            toggled_colors(color)), 1, outc);
        }
     } else {
        if (set_a_background) {
            TPUTS_TRACE("set_a_background");
            NCURSES_SP_NAME(tputs) (NCURSES_SP_ARGx
-                                   TPARM_1(set_a_background, color), 1, outc);
+                                   TIPARM_1(set_a_background, color), 1, outc);
        } else {
            TPUTS_TRACE("set_background");
            NCURSES_SP_NAME(tputs) (NCURSES_SP_ARGx
-                                   TPARM_1(set_background,
-                                           toggled_colors(color)), 1, outc);
+                                   TIPARM_1(set_background,
+                                            toggled_colors(color)), 1, outc);
        }
     }
 }
@@ -354,18 +426,25 @@ drv_size(TERMINAL_CONTROL_BLOCK * TCB, int *linep, int *colp)
 
     if (sp) {
        useEnv = sp->_use_env;
-       useTioctl = sp->_use_tioctl;
+       useTioctl = sp->use_tioctl;
     } else {
        useEnv = _nc_prescreen.use_env;
        useTioctl = _nc_prescreen.use_tioctl;
     }
 
+#ifdef EXP_WIN32_DRIVER
+    /* If we are here, then Windows console is used in terminfo mode.
+       We need to figure out the size using the console API
+     */
+    _nc_console_size(linep, colp);
+    T(("screen size: winconsole lines = %d columns = %d", *linep, *colp));
+#else
     /* figure out the size of the screen */
     T(("screen size: terminfo lines = %d columns = %d", lines, columns));
 
     *linep = (int) lines;
     *colp = (int) columns;
-
+#endif
     if (useEnv || useTioctl) {
        int value;
 
@@ -385,7 +464,7 @@ drv_size(TERMINAL_CONTROL_BLOCK * TCB, int *linep, int *colp)
        /* try asking the OS */
        {
            TERMINAL *termp = (TERMINAL *) TCB;
-           if (isatty(termp->Filedes)) {
+           if (NC_ISATTY(termp->Filedes)) {
                STRUCT_WINSIZE size;
 
                errno = 0;
@@ -535,6 +614,8 @@ drv_mode(TERMINAL_CONTROL_BLOCK * TCB, int progFlag, int defFlag)
            if ((drv_sgmode(TCB, FALSE, &(_term->Nttyb)) == OK)) {
 #ifdef TERMIOS
                _term->Nttyb.c_oflag &= (unsigned) ~OFLAGS_TABS;
+#elif defined(EXP_WIN32_DRIVER)
+               /* noop */
 #else
                _term->Nttyb.sg_flags &= (unsigned) ~XTABS;
 #endif
@@ -560,6 +641,8 @@ drv_mode(TERMINAL_CONTROL_BLOCK * TCB, int progFlag, int defFlag)
 #ifdef TERMIOS
                if (_term->Ottyb.c_oflag & OFLAGS_TABS)
                    tab = back_tab = NULL;
+#elif defined(EXP_WIN32_DRIVER)
+               /* noop */
 #else
                if (_term->Ottyb.sg_flags & XTABS)
                    tab = back_tab = NULL;
@@ -671,7 +754,7 @@ drv_init(TERMINAL_CONTROL_BLOCK * TCB)
      * _nc_setupscreen().  Do it now anyway, so we can initialize the
      * baudrate.
      */
-    if (isatty(trm->Filedes)) {
+    if (NC_ISATTY(trm->Filedes)) {
        TCB->drv->td_mode(TCB, TRUE, TRUE);
     }
 }
@@ -697,10 +780,10 @@ drv_initpair(TERMINAL_CONTROL_BLOCK * TCB, int pair, int f, int b)
            tp[b].red, tp[b].green, tp[b].blue));
 
        NCURSES_PUTP2("initialize_pair",
-                     TPARM_7(initialize_pair,
-                             pair,
-                             tp[f].red, tp[f].green, tp[f].blue,
-                             tp[b].red, tp[b].green, tp[b].blue));
+                     TIPARM_7(initialize_pair,
+                              pair,
+                              tp[f].red, tp[f].green, tp[f].blue,
+                              tp[b].red, tp[b].green, tp[b].blue));
     }
 }
 
@@ -733,7 +816,7 @@ drv_initcolor(TERMINAL_CONTROL_BLOCK * TCB,
     AssertTCB();
     if (initialize_color != NULL) {
        NCURSES_PUTP2("initialize_color",
-                     TPARM_4(initialize_color, color, r, g, b));
+                     TIPARM_4(initialize_color, color, r, g, b));
     }
 }
 
@@ -745,9 +828,9 @@ drv_do_color(TERMINAL_CONTROL_BLOCK * TCB,
             NCURSES_SP_OUTC outc)
 {
     SCREEN *sp = TCB->csp;
-    NCURSES_COLOR_T fg = COLOR_DEFAULT;
-    NCURSES_COLOR_T bg = COLOR_DEFAULT;
-    NCURSES_COLOR_T old_fg, old_bg;
+    int fg = COLOR_DEFAULT;
+    int bg = COLOR_DEFAULT;
+    int old_fg, old_bg;
 
     AssertTCB();
     if (sp == 0)
@@ -759,22 +842,16 @@ drv_do_color(TERMINAL_CONTROL_BLOCK * TCB,
        if (set_color_pair) {
            TPUTS_TRACE("set_color_pair");
            NCURSES_SP_NAME(tputs) (NCURSES_SP_ARGx
-                                   TPARM_1(set_color_pair, pair), 1, outc);
+                                   TIPARM_1(set_color_pair, pair), 1, outc);
            return;
        } else if (sp != 0) {
-           NCURSES_SP_NAME(pair_content) (NCURSES_SP_ARGx
-                                          (short) pair,
-                                          &fg,
-                                          &bg);
+           _nc_pair_content(SP_PARM, pair, &fg, &bg);
        }
     }
 
     if (old_pair >= 0
        && sp != 0
-       && NCURSES_SP_NAME(pair_content) (NCURSES_SP_ARGx
-                                         (short) old_pair,
-                                         &old_fg,
-                                         &old_bg) !=ERR) {
+       && _nc_pair_content(SP_PARM, old_pair, &old_fg, &old_bg) != ERR) {
        if ((isDefaultColor(fg) && !isDefaultColor(old_fg))
            || (isDefaultColor(bg) && !isDefaultColor(old_bg))) {
 #if NCURSES_EXT_FUNCS
@@ -803,13 +880,13 @@ drv_do_color(TERMINAL_CONTROL_BLOCK * TCB,
 
 #if NCURSES_EXT_FUNCS
     if (isDefaultColor(fg))
-       fg = (NCURSES_COLOR_T) default_fg(sp);
+       fg = default_fg(sp);
     if (isDefaultColor(bg))
-       bg = (NCURSES_COLOR_T) default_bg(sp);
+       bg = default_bg(sp);
 #endif
 
     if (reverse) {
-       NCURSES_COLOR_T xx = fg;
+       int xx = fg;
        fg = bg;
        bg = xx;
     }
@@ -845,12 +922,9 @@ drv_initmouse(TERMINAL_CONTROL_BLOCK * TCB)
 
     /* we know how to recognize mouse events under "xterm" */
     if (sp != 0) {
-       if (key_mouse != 0) {
-           if (!strcmp(key_mouse, xterm_kmous)
-               || strstr(TerminalOf(sp)->type.term_names, "xterm") != 0) {
-               init_xterm_mouse(sp);
-           }
-       } else if (strstr(TerminalOf(sp)->type.term_names, "xterm") != 0) {
+       if (NonEmpty(key_mouse)) {
+           init_xterm_mouse(sp);
+       } else if (strstr(SP_TERMTYPE term_names, "xterm") != 0) {
            if (_nc_add_to_try(&(sp->_keytry), xterm_kmous, KEY_MOUSE) == OK)
                init_xterm_mouse(sp);
        }
@@ -875,11 +949,18 @@ drv_testmouse(TERMINAL_CONTROL_BLOCK * TCB,
     } else
 #endif
     {
+#ifdef EXP_WIN32_DRIVER
+       rc = _nc_console_testmouse(sp,
+                                  _nc_console_handle(sp->_ifd),
+                                  delay
+                                  EVENTLIST_2nd(evl));
+#else
        rc = TCBOf(sp)->drv->td_twait(TCBOf(sp),
                                      TWAIT_MASK,
                                      delay,
                                      (int *) 0
                                      EVENTLIST_2nd(evl));
+#endif
 #if USE_SYSMOUSE
        if ((sp->_mouse_type == M_SYSMOUSE)
            && (sp->_sysmouse_head < sp->_sysmouse_tail)
@@ -975,12 +1056,18 @@ drv_setfilter(TERMINAL_CONTROL_BLOCK * TCB)
 {
     AssertTCB();
 
-    clear_screen = 0;
-    cursor_down = parm_down_cursor = 0;
-    cursor_address = 0;
-    cursor_up = parm_up_cursor = 0;
-    row_address = 0;
-    cursor_home = carriage_return;
+    /* *INDENT-EQLS* */
+    clear_screen     = ABSENT_STRING;
+    cursor_address   = ABSENT_STRING;
+    cursor_down      = ABSENT_STRING;
+    cursor_up        = ABSENT_STRING;
+    parm_down_cursor = ABSENT_STRING;
+    parm_up_cursor   = ABSENT_STRING;
+    row_address      = ABSENT_STRING;
+    cursor_home      = carriage_return;
+
+    if (back_color_erase)
+       clr_eos = ABSENT_STRING;
 }
 
 static void
@@ -1027,8 +1114,13 @@ drv_initacs(TERMINAL_CONTROL_BLOCK * TCB, chtype *real_map, chtype *fake_map)
        while (i + 1 < length) {
            if (acs_chars[i] != 0 && UChar(acs_chars[i]) < ACS_LEN) {
                real_map[UChar(acs_chars[i])] = UChar(acs_chars[i + 1]) | A_ALTCHARSET;
-               if (sp != 0)
+               T(("#%d real_map[%s] = %s",
+                  (int) i,
+                  _tracechar(UChar(acs_chars[i])),
+                  _tracechtype(real_map[UChar(acs_chars[i])])));
+               if (sp != 0) {
                    sp->_screen_acs_map[UChar(acs_chars[i])] = TRUE;
+               }
            }
            i += 2;
        }
@@ -1058,7 +1150,6 @@ drv_initacs(TERMINAL_CONTROL_BLOCK * TCB, chtype *real_map, chtype *fake_map)
                   ? "DIFF"
                   : "SAME"),
                _nc_visbuf(show));
-
        _nc_unlock_global(tracef);
     }
 #endif /* TRACE */
@@ -1167,16 +1258,25 @@ drv_twait(TERMINAL_CONTROL_BLOCK * TCB,
 
     AssertTCB();
     SetSP();
-
+#ifdef EXP_WIN32_DRIVER
+    return _nc_console_twait(sp,
+                            _nc_console_handle(sp->_ifd),
+                            mode,
+                            milliseconds,
+                            timeleft EVENTLIST_2nd(evl));
+#else
     return _nc_timed_wait(sp, mode, milliseconds, timeleft EVENTLIST_2nd(evl));
+#endif
 }
 
 static int
 drv_read(TERMINAL_CONTROL_BLOCK * TCB, int *buf)
 {
     SCREEN *sp;
-    unsigned char c2 = 0;
     int n;
+#ifndef EXP_WIN32_DRIVER
+    unsigned char c2 = 0;
+#endif
 
     AssertTCB();
     assert(buf);
@@ -1186,11 +1286,19 @@ drv_read(TERMINAL_CONTROL_BLOCK * TCB, int *buf)
     if ((pthread_self) && (pthread_kill) && (pthread_equal))
        _nc_globals.read_thread = pthread_self();
 # endif
-    n = read(sp->_ifd, &c2, (size_t) 1);
+#ifdef EXP_WIN32_DRIVER
+    n = _nc_console_read(sp,
+                        _nc_console_handle(sp->_ifd),
+                        buf);
+#else
+    n = (int) read(sp->_ifd, &c2, (size_t) 1);
+#endif
 #if USE_PTHREADS_EINTR
     _nc_globals.read_thread = 0;
 #endif
+#ifndef EXP_WIN32_DRIVER
     *buf = (int) c2;
+#endif
     return n;
 }
 
@@ -1207,6 +1315,8 @@ drv_nap(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int ms)
            request = remaining;
        }
     }
+#elif defined(EXP_WIN32_DRIVER)
+    Sleep((DWORD) ms);
 #else
     _nc_timed_wait(0, 0, ms, (int *) 0 EVENTLIST_2nd(0));
 #endif
@@ -1275,29 +1385,64 @@ drv_keyok(TERMINAL_CONTROL_BLOCK * TCB, int c, int flag)
        unsigned ch = (unsigned) c;
        if (flag) {
            while ((s = _nc_expand_try(sp->_key_ok,
-                                      ch, &count, (size_t) 0)) != 0
-                  && _nc_remove_key(&(sp->_key_ok), ch)) {
-               code = _nc_add_to_try(&(sp->_keytry), s, ch);
-               free(s);
-               count = 0;
-               if (code != OK)
-                   break;
+                                      ch, &count, (size_t) 0)) != 0) {
+               if (_nc_remove_key(&(sp->_key_ok), ch)) {
+                   code = _nc_add_to_try(&(sp->_keytry), s, ch);
+                   free(s);
+                   count = 0;
+                   if (code != OK)
+                       break;
+               } else {
+                   free(s);
+               }
            }
        } else {
            while ((s = _nc_expand_try(sp->_keytry,
-                                      ch, &count, (size_t) 0)) != 0
-                  && _nc_remove_key(&(sp->_keytry), ch)) {
-               code = _nc_add_to_try(&(sp->_key_ok), s, ch);
-               free(s);
-               count = 0;
-               if (code != OK)
-                   break;
+                                      ch, &count, (size_t) 0)) != 0) {
+               if (_nc_remove_key(&(sp->_keytry), ch)) {
+                   code = _nc_add_to_try(&(sp->_key_ok), s, ch);
+                   free(s);
+                   count = 0;
+                   if (code != OK)
+                       break;
+               } else {
+                   free(s);
+               }
            }
        }
     }
     return (code);
 }
 
+static int
+drv_cursorSet(TERMINAL_CONTROL_BLOCK * TCB, int vis)
+{
+    SCREEN *sp;
+    int code = ERR;
+
+    AssertTCB();
+    SetSP();
+
+    T((T_CALLED("tinfo:drv_cursorSet(%p,%d)"), (void *) SP_PARM, vis));
+
+    if (SP_PARM != 0 && IsTermInfo(SP_PARM)) {
+       switch (vis) {
+       case 2:
+           code = NCURSES_PUTP2_FLUSH("cursor_visible", cursor_visible);
+           break;
+       case 1:
+           code = NCURSES_PUTP2_FLUSH("cursor_normal", cursor_normal);
+           break;
+       case 0:
+           code = NCURSES_PUTP2_FLUSH("cursor_invisible", cursor_invisible);
+           break;
+       }
+    } else {
+       code = ERR;
+    }
+    returnCode(code);
+}
+
 static bool
 drv_kyExist(TERMINAL_CONTROL_BLOCK * TCB, int key)
 {
@@ -1346,5 +1491,69 @@ NCURSES_EXPORT_VAR (TERM_DRIVER) _nc_TINFO_DRIVER = {
        drv_nap,                /* nap */
        drv_kpad,               /* kpad */
        drv_keyok,              /* kyOk */
-       drv_kyExist             /* kyExist */
+       drv_kyExist,            /* kyExist */
+       drv_cursorSet           /* cursorSet */
 };
+
+#ifdef EXP_WIN32_DRIVER
+/*
+ * The terminfo driver is mandatory and must always be present.
+ * So this is the natural place for the driver initialisation
+ * logic.
+ */
+
+typedef struct DriverEntry {
+    const char *name;
+    TERM_DRIVER *driver;
+} DRIVER_ENTRY;
+
+static DRIVER_ENTRY DriverTable[] =
+{
+#ifdef _NC_WINDOWS
+    {"win32console", &_nc_WIN_DRIVER},
+#endif
+    {"tinfo", &_nc_TINFO_DRIVER}       /* must be last */
+};
+
+NCURSES_EXPORT(int)
+_nc_get_driver(TERMINAL_CONTROL_BLOCK * TCB, const char *name, int *errret)
+{
+    int code = ERR;
+    size_t i;
+    TERM_DRIVER *res = (TERM_DRIVER *) 0;
+    TERM_DRIVER *use = 0;
+
+    T((T_CALLED("_nc_get_driver(%p, %s, %p)"),
+       (void *) TCB, NonNull(name), (void *) errret));
+
+    assert(TCB != 0);
+
+    for (i = 0; i < SIZEOF(DriverTable); i++) {
+       res = DriverTable[i].driver;
+#ifdef _NC_WINDOWS
+       if ((i + 1) == SIZEOF(DriverTable)) {
+           /* For Windows >= 10.0.17763 Windows Console interface implements 
+              virtual Terminal functionality.
+              If on Windows td_CanHandle returned FALSE although the terminal
+              name is empty, we default to ms-terminal as tinfo TERM type.
+            */
+           if (name == 0 || *name == 0 || (strcmp(name, "unknown") == 0)) {
+               name = MS_TERMINAL;
+               T(("Set TERM=%s", name));
+           }
+       }
+#endif
+       if (strcmp(DriverTable[i].name, res->td_name(TCB)) == 0) {
+           if (res->td_CanHandle(TCB, name, errret)) {
+               use = res;
+               break;
+           }
+       }
+    }
+    if (use != 0) {
+       TCB->drv = use;
+       code = OK;
+    }
+    returnCode(code);
+}
+#endif /* EXP_WIN32_DRIVER */