diff options
author | Baptiste Daroussin <bapt@FreeBSD.org> | 2021-02-25 17:22:00 +0000 |
---|---|---|
committer | Baptiste Daroussin <bapt@FreeBSD.org> | 2021-02-25 17:22:00 +0000 |
commit | bf0ab54638a5ef969749f6ceae30e864f9556ea8 (patch) | |
tree | 11690c2184e55d37bcd3c7fd13f3d0d9d20dbcb0 /ncurses/tinfo | |
parent | 72c3fc31f590566e93496732d6fa769cd353e270 (diff) | |
download | src-vendor/ncurses.tar.gz src-vendor/ncurses.zip |
Vendor import ncurses 6.2-20210220vendor/ncurses/6.2-20210220vendor/ncurses
Diffstat (limited to 'ncurses/tinfo')
26 files changed, 1992 insertions, 205 deletions
diff --git a/ncurses/tinfo/MKcaptab.sh b/ncurses/tinfo/MKcaptab.sh index c800023d105a..c800023d105a 100644..100755 --- a/ncurses/tinfo/MKcaptab.sh +++ b/ncurses/tinfo/MKcaptab.sh diff --git a/ncurses/tinfo/MKfallback.sh b/ncurses/tinfo/MKfallback.sh index 319ab066c885..64c65f197e0d 100755 --- a/ncurses/tinfo/MKfallback.sh +++ b/ncurses/tinfo/MKfallback.sh @@ -27,7 +27,7 @@ # use or other dealings in this Software without prior written # # authorization. # ############################################################################## -# $Id: MKfallback.sh,v 1.24 2020/02/08 21:52:37 tom Exp $ +# $Id: MKfallback.sh,v 1.25 2020/08/16 15:58:44 tom Exp $ # # MKfallback.sh -- create fallback table for entry reads # @@ -44,12 +44,14 @@ terminfo_src=$1 shift tic_path=$1 +test -z "$tic_path" && tic_path=tic shift infocmp_path=$1 +test -z "$infocmp_path" && infocmp_path=infocmp shift -case $tic_path in #(vi +case "$tic_path" in #(vi /*) tic_head=`echo "$tic_path" | sed -e 's,/[^/]*$,,'` PATH=$tic_head:$PATH @@ -67,7 +69,7 @@ if test $# != 0 ; then TERMINFO_DIRS=$TERMINFO:$terminfo_dir export TERMINFO_DIRS - $tic_path -x $terminfo_src >&2 + "$tic_path" -x "$terminfo_src" >&2 else tmp_info= fi @@ -90,10 +92,10 @@ then /* fallback entries for: $* */ EOF - for x in $* + for x in "$@" do echo "/* $x */" - $infocmp_path -E $x | sed -e 's/\<short\>/NCURSES_INT2/g' + "$infocmp_path" -E "$x" | sed -e 's/\<short\>/NCURSES_INT2/g' done cat <<EOF @@ -101,10 +103,10 @@ static const TERMTYPE2 fallbacks[$#] = { EOF comma="" - for x in $* + for x in "$@" do echo "$comma /* $x */" - $infocmp_path -e $x + "$infocmp_path" -e "$x" comma="," done diff --git a/ncurses/tinfo/access.c b/ncurses/tinfo/access.c index c69707feb2c6..15593688266e 100644 --- a/ncurses/tinfo/access.c +++ b/ncurses/tinfo/access.c @@ -37,10 +37,16 @@ #include <tic.h> -MODULE_ID("$Id: access.c,v 1.25 2020/02/02 23:34:34 tom Exp $") +MODULE_ID("$Id: access.c,v 1.27 2020/08/29 16:22:03 juergen Exp $") #define LOWERCASE(c) ((isalpha(UChar(c)) && isupper(UChar(c))) ? tolower(UChar(c)) : (c)) +#ifdef _NC_MSC +# define ACCESS(FN, MODE) access((FN), (MODE)&(R_OK|W_OK)) +#else +# define ACCESS access +#endif + NCURSES_EXPORT(char *) _nc_rootname(char *path) { @@ -112,7 +118,7 @@ _nc_access(const char *path, int mode) if (path == 0) { result = -1; - } else if (access(path, mode) < 0) { + } else if (ACCESS(path, mode) < 0) { if ((mode & W_OK) != 0 && errno == ENOENT && strlen(path) < PATH_MAX) { @@ -127,7 +133,7 @@ _nc_access(const char *path, int mode) if (head == leaf) _nc_STRCPY(head, ".", sizeof(head)); - result = access(head, R_OK | W_OK | X_OK); + result = ACCESS(head, R_OK | W_OK | X_OK); } else { result = -1; } diff --git a/ncurses/tinfo/captoinfo.c b/ncurses/tinfo/captoinfo.c index 8b3b83d18239..de0133b386c6 100644 --- a/ncurses/tinfo/captoinfo.c +++ b/ncurses/tinfo/captoinfo.c @@ -98,7 +98,7 @@ #include <ctype.h> #include <tic.h> -MODULE_ID("$Id: captoinfo.c,v 1.98 2020/02/02 23:34:34 tom Exp $") +MODULE_ID("$Id: captoinfo.c,v 1.100 2020/07/08 21:39:54 tom Exp $") #if 0 #define DEBUG_THIS(p) DEBUG(9, p) @@ -216,12 +216,15 @@ cvtchar(register const char *sp) } break; case '^': + len = 2; c = UChar(*++sp); - if (c == '?') + if (c == '?') { c = 127; - else + } else if (c == '\0') { + len = 1; + } else { c &= 0x1f; - len = 2; + } break; default: c = UChar(*sp); @@ -636,7 +639,7 @@ _nc_infotocap(const char *cap GCC_UNUSED, const char *str, int const parameteriz /* we may have to move some trailing mandatory padding up front */ padding = str + strlen(str) - 1; if (padding > str && *padding == '>') { - if (*--padding == '/') + if (padding > (str + 1) && *--padding == '/') --padding; while (isdigit(UChar(*padding)) || *padding == '.' || *padding == '*') padding--; diff --git a/ncurses/tinfo/comp_parse.c b/ncurses/tinfo/comp_parse.c index ab25d5b1f03d..2a89a866c374 100644 --- a/ncurses/tinfo/comp_parse.c +++ b/ncurses/tinfo/comp_parse.c @@ -48,10 +48,10 @@ #include <tic.h> -MODULE_ID("$Id: comp_parse.c,v 1.109 2020/02/02 23:34:34 tom Exp $") +MODULE_ID("$Id: comp_parse.c,v 1.110 2020/02/29 15:46:00 anonymous.maarten Exp $") static void sanity_check2(TERMTYPE2 *, bool); -NCURSES_IMPEXP void NCURSES_API(*_nc_check_termtype2) (TERMTYPE2 *, bool) = sanity_check2; +NCURSES_IMPEXP void (NCURSES_API *_nc_check_termtype2) (TERMTYPE2 *, bool) = sanity_check2; static void fixup_acsc(TERMTYPE2 *, int); diff --git a/ncurses/tinfo/doalloc.c b/ncurses/tinfo/doalloc.c index f0c8141ad05e..0bda12cae8be 100644 --- a/ncurses/tinfo/doalloc.c +++ b/ncurses/tinfo/doalloc.c @@ -40,9 +40,9 @@ #include <curses.priv.h> -MODULE_ID("$Id: doalloc.c,v 1.12 2020/02/02 23:34:34 tom Exp $") +MODULE_ID("$Id: doalloc.c,v 1.13 2020/08/30 00:27:15 tom Exp $") -NCURSES_EXPORT(void *) +void * _nc_doalloc(void *oldp, size_t amount) { void *newp; diff --git a/ncurses/tinfo/lib_baudrate.c b/ncurses/tinfo/lib_baudrate.c index 4f72de50f652..311c41ac97fa 100644 --- a/ncurses/tinfo/lib_baudrate.c +++ b/ncurses/tinfo/lib_baudrate.c @@ -84,7 +84,7 @@ #undef USE_OLD_TTY #endif /* USE_OLD_TTY */ -MODULE_ID("$Id: lib_baudrate.c,v 1.44 2020/02/02 23:34:34 tom Exp $") +MODULE_ID("$Id: lib_baudrate.c,v 1.45 2020/09/05 21:15:32 tom Exp $") /* * int @@ -99,6 +99,7 @@ struct speed { int actual_speed; /* the actual speed */ }; +#if !defined(EXP_WIN32_DRIVER) #define DATA(number) { B##number, number } static struct speed const speeds[] = @@ -188,10 +189,16 @@ static struct speed const speeds[] = #endif #endif }; +#endif /* !EXP_WIN32_DRIVER */ NCURSES_EXPORT(int) _nc_baudrate(int OSpeed) { +#if defined(EXP_WIN32_DRIVER) + /* On Windows this is a noop */ + (void) OSpeed; + return (OK); +#else #if !USE_REENTRANT static int last_OSpeed; static int last_baudrate; @@ -230,13 +237,16 @@ _nc_baudrate(int OSpeed) #endif } return (result); +#endif /* !EXP_WIN32_DRIVER */ } NCURSES_EXPORT(int) _nc_ospeed(int BaudRate) { int result = 1; - +#if defined(EXP_WIN32_DRIVER) + (void) BaudRate; +#else if (BaudRate >= 0) { unsigned i; @@ -247,6 +257,7 @@ _nc_ospeed(int BaudRate) } } } +#endif return (result); } @@ -257,6 +268,9 @@ NCURSES_SP_NAME(baudrate) (NCURSES_SP_DCL0) T((T_CALLED("baudrate(%p)"), (void *) SP_PARM)); +#if defined(EXP_WIN32_DRIVER) + result = OK; +#else /* * In debugging, allow the environment symbol to override when we're * redirecting to a file, so we can construct repeatable test-cases @@ -290,7 +304,7 @@ NCURSES_SP_NAME(baudrate) (NCURSES_SP_DCL0) } else { result = ERR; } - +#endif /* !EXP_WIN32_DRIVER */ returnCode(result); } diff --git a/ncurses/tinfo/lib_cur_term.c b/ncurses/tinfo/lib_cur_term.c index 4a90335d5e33..0373aebb11b9 100644 --- a/ncurses/tinfo/lib_cur_term.c +++ b/ncurses/tinfo/lib_cur_term.c @@ -39,8 +39,9 @@ #include <curses.priv.h> #include <termcap.h> /* ospeed */ +#include <tic.h> /* VALID_STRING */ -MODULE_ID("$Id: lib_cur_term.c,v 1.42 2020/02/02 23:34:34 tom Exp $") +MODULE_ID("$Id: lib_cur_term.c,v 1.43 2020/10/24 18:54:32 tom Exp $") #undef CUR #define CUR TerminalType(termp). @@ -99,13 +100,13 @@ NCURSES_SP_NAME(set_curterm) (NCURSES_SP_DCLx TERMINAL *termp) if (TCB->drv && TCB->drv->isTerminfo && TerminalType(termp).Strings) { - PC = (char) ((pad_char != NULL) ? pad_char[0] : 0); + PC = (char) (VALID_STRING(pad_char) ? pad_char[0] : 0); } TCB->csp = SP_PARM; #else ospeed = (NCURSES_OSPEED) _nc_ospeed(termp->_baudrate); if (TerminalType(termp).Strings) { - PC = (char) ((pad_char != NULL) ? pad_char[0] : 0); + PC = (char) (VALID_STRING(pad_char) ? pad_char[0] : 0); } #endif #if !USE_REENTRANT diff --git a/ncurses/tinfo/lib_data.c b/ncurses/tinfo/lib_data.c index bf3e554df70d..39274f4e7c39 100644 --- a/ncurses/tinfo/lib_data.c +++ b/ncurses/tinfo/lib_data.c @@ -43,7 +43,7 @@ #include <curses.priv.h> -MODULE_ID("$Id: lib_data.c,v 1.80 2020/02/02 23:34:34 tom Exp $") +MODULE_ID("$Id: lib_data.c,v 1.81 2020/06/13 22:01:14 tom Exp $") /* * OS/2's native linker complains if we don't initialize public data when @@ -155,6 +155,11 @@ NCURSES_EXPORT_VAR(NCURSES_GLOBALS) _nc_globals = { 0, /* dbd_time */ { { 0, 0 } }, /* dbd_vars */ +#if HAVE_TSEARCH + NULL, /* cached_tparm */ + 0, /* count_tparm */ +#endif /* HAVE_TSEARCH */ + #ifdef USE_TERM_DRIVER 0, /* term_driver */ #endif diff --git a/ncurses/tinfo/lib_kernel.c b/ncurses/tinfo/lib_kernel.c index 482657add7cf..d5b021b80728 100644 --- a/ncurses/tinfo/lib_kernel.c +++ b/ncurses/tinfo/lib_kernel.c @@ -49,8 +49,9 @@ #include <curses.priv.h> -MODULE_ID("$Id: lib_kernel.c,v 1.32 2020/02/02 23:34:34 tom Exp $") +MODULE_ID("$Id: lib_kernel.c,v 1.34 2020/11/21 22:05:58 tom Exp $") +#ifdef TERMIOS static int _nc_vdisable(void) { @@ -71,6 +72,7 @@ _nc_vdisable(void) #endif return value; } +#endif /* TERMIOS */ /* * erasechar() @@ -92,6 +94,8 @@ NCURSES_SP_NAME(erasechar) (NCURSES_SP_DCL0) result = termp->Ottyb.c_cc[VERASE]; if (result == _nc_vdisable()) result = ERR; +#elif defined(EXP_WIN32_DRIVER) + result = ERR; #else result = termp->Ottyb.sg_erase; #endif @@ -127,6 +131,8 @@ NCURSES_SP_NAME(killchar) (NCURSES_SP_DCL0) result = termp->Ottyb.c_cc[VKILL]; if (result == _nc_vdisable()) result = ERR; +#elif defined(EXP_WIN32_DRIVER) + result = ERR; #else result = termp->Ottyb.sg_kill; #endif @@ -162,7 +168,11 @@ NCURSES_SP_NAME(flushinp) (NCURSES_SP_DCL0) #else errno = 0; do { +#if defined(EXP_WIN32_DRIVER) + _nc_console_flush(_nc_console_fd2handle(termp->Filedes)); +#else ioctl(termp->Filedes, TIOCFLUSH, 0); +#endif } while (errno == EINTR); #endif diff --git a/ncurses/tinfo/lib_napms.c b/ncurses/tinfo/lib_napms.c index 99dacd722928..3a9fc3168784 100644 --- a/ncurses/tinfo/lib_napms.c +++ b/ncurses/tinfo/lib_napms.c @@ -52,7 +52,7 @@ #endif #endif -MODULE_ID("$Id: lib_napms.c,v 1.26 2020/02/02 23:34:34 tom Exp $") +MODULE_ID("$Id: lib_napms.c,v 1.27 2020/08/15 19:45:23 tom Exp $") NCURSES_EXPORT(int) NCURSES_SP_NAME(napms) (NCURSES_SP_DCLx int ms) @@ -75,6 +75,8 @@ NCURSES_SP_NAME(napms) (NCURSES_SP_DCLx int ms) request = remaining; } } +#elif defined(_NC_WINDOWS) + Sleep((DWORD) ms); #else _nc_timed_wait(0, 0, ms, (int *) 0 EVENTLIST_2nd(0)); #endif diff --git a/ncurses/tinfo/lib_options.c b/ncurses/tinfo/lib_options.c index 784e06c17fa1..017a34aac6e7 100644 --- a/ncurses/tinfo/lib_options.c +++ b/ncurses/tinfo/lib_options.c @@ -1,5 +1,5 @@ /**************************************************************************** - * Copyright 2020 Thomas E. Dickey * + * Copyright 2020,2021 Thomas E. Dickey * * Copyright 1998-2014,2017 Free Software Foundation, Inc. * * * * Permission is hereby granted, free of charge, to any person obtaining a * @@ -47,7 +47,7 @@ #define CUR SP_TERMTYPE #endif -MODULE_ID("$Id: lib_options.c,v 1.81 2020/02/02 23:34:34 tom Exp $") +MODULE_ID("$Id: lib_options.c,v 1.82 2021/02/14 00:17:35 tom Exp $") NCURSES_EXPORT(int) idlok(WINDOW *win, bool flag) @@ -361,7 +361,7 @@ _nc_keypad(SCREEN *sp, int flag) #else if (flag) { (void) NCURSES_PUTP2_FLUSH("keypad_xmit", keypad_xmit); - } else if (!flag && keypad_local) { + } else if (keypad_local) { (void) NCURSES_PUTP2_FLUSH("keypad_local", keypad_local); } diff --git a/ncurses/tinfo/lib_print.c b/ncurses/tinfo/lib_print.c index eb9214925a92..4accdf6786ea 100644 --- a/ncurses/tinfo/lib_print.c +++ b/ncurses/tinfo/lib_print.c @@ -40,7 +40,7 @@ #define CUR SP_TERMTYPE #endif -MODULE_ID("$Id: lib_print.c,v 1.25 2020/02/02 23:34:34 tom Exp $") +MODULE_ID("$Id: lib_print.c,v 1.28 2020/08/29 16:22:03 juergen Exp $") NCURSES_EXPORT(int) NCURSES_SP_NAME(mcprint) (NCURSES_SP_DCLx char *data, int len) @@ -60,7 +60,7 @@ NCURSES_SP_NAME(mcprint) (NCURSES_SP_DCLx char *data, int len) } if (prtr_non) { - switchon = TPARM_1(prtr_non, len); + switchon = TIPARM_1(prtr_non, len); onsize = strlen(switchon); offsize = 0; } else { @@ -96,7 +96,7 @@ NCURSES_SP_NAME(mcprint) (NCURSES_SP_DCLx char *data, int len) * kernel will ship the contiguous clist items from the last write * immediately. */ -#ifndef _WIN32 +#ifndef _NC_WINDOWS (void) sleep(0); #endif free(mybuf); diff --git a/ncurses/tinfo/lib_raw.c b/ncurses/tinfo/lib_raw.c index a691a266b703..1e47f3b6fbfb 100644 --- a/ncurses/tinfo/lib_raw.c +++ b/ncurses/tinfo/lib_raw.c @@ -50,7 +50,7 @@ #include <curses.priv.h> -MODULE_ID("$Id: lib_raw.c,v 1.24 2020/02/02 23:34:34 tom Exp $") +MODULE_ID("$Id: lib_raw.c,v 1.26 2020/11/21 22:07:48 tom Exp $") #if HAVE_SYS_TERMIO_H #include <sys/termio.h> /* needed for ISC */ @@ -97,6 +97,8 @@ NCURSES_SP_NAME(raw) (NCURSES_SP_DCL0) buf.c_iflag &= (unsigned) ~(COOKED_INPUT); buf.c_cc[VMIN] = 1; buf.c_cc[VTIME] = 0; +#elif defined(EXP_WIN32_DRIVER) + buf.dwFlagIn &= (unsigned long) ~CONMODE_NORAW; #else buf.sg_flags |= RAW; #endif @@ -152,6 +154,9 @@ NCURSES_SP_NAME(cbreak) (NCURSES_SP_DCL0) buf.c_lflag |= ISIG; buf.c_cc[VMIN] = 1; buf.c_cc[VTIME] = 0; +#elif defined(EXP_WIN32_DRIVER) + buf.dwFlagIn |= CONMODE_NORAW; + buf.dwFlagIn &= (unsigned long) ~CONMODE_NOCBREAK; #else buf.sg_flags |= CBREAK; #endif @@ -231,6 +236,8 @@ NCURSES_SP_NAME(noraw) (NCURSES_SP_DCL0) buf.c_lflag |= ISIG | ICANON | (termp->Ottyb.c_lflag & IEXTEN); buf.c_iflag |= COOKED_INPUT; +#elif defined(EXP_WIN32_DRIVER) + buf.dwFlagIn |= CONMODE_NORAW; #else buf.sg_flags &= ~(RAW | CBREAK); #endif @@ -283,6 +290,8 @@ NCURSES_SP_NAME(nocbreak) (NCURSES_SP_DCL0) #ifdef TERMIOS buf.c_lflag |= ICANON; buf.c_iflag |= ICRNL; +#elif defined(EXP_WIN32_DRIVER) + buf.dwFlagIn |= (CONMODE_NOCBREAK | CONMODE_NORAW); #else buf.sg_flags &= ~CBREAK; #endif diff --git a/ncurses/tinfo/lib_setup.c b/ncurses/tinfo/lib_setup.c index a6527bfd0967..976227effade 100644 --- a/ncurses/tinfo/lib_setup.c +++ b/ncurses/tinfo/lib_setup.c @@ -49,7 +49,7 @@ #include <locale.h> #endif -MODULE_ID("$Id: lib_setup.c,v 1.207 2020/02/02 23:34:34 tom Exp $") +MODULE_ID("$Id: lib_setup.c,v 1.212 2020/09/09 19:43:00 juergen Exp $") /**************************************************************************** * @@ -305,11 +305,19 @@ _nc_get_screensize(SCREEN *sp, bool useEnv = _nc_prescreen.use_env; bool 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 NCURSES_SP_FUNCS if (sp) { @@ -566,7 +574,7 @@ NCURSES_EXPORT(int) _nc_unicode_locale(void) { int result = 0; -#if defined(_WIN32) && USE_WIDEC_SUPPORT +#if defined(_NC_WINDOWS) && USE_WIDEC_SUPPORT result = 1; #elif HAVE_LANGINFO_CODESET char *env = nl_langinfo(CODESET); @@ -655,13 +663,20 @@ TINFO_SETUP_TERM(TERMINAL **tp, if (tname == 0) { tname = getenv("TERM"); - if (tname == 0 || *tname == '\0') { -#ifdef USE_TERM_DRIVER +#if defined(EXP_WIN32_DRIVER) + if (!VALID_TERM_ENV(tname, NO_TERMINAL)) { + T(("Failure with TERM=%s", NonNull(tname))); + ret_error0(TGETENT_ERR, "TERM environment variable not set.\n"); + } +#elif defined(USE_TERM_DRIVER) + if (!NonEmpty(tname)) tname = "unknown"; #else + if (!NonEmpty(tname)) { + T(("Failure with TERM=%s", NonNull(tname))); ret_error0(TGETENT_ERR, "TERM environment variable not set.\n"); -#endif } +#endif } myname = strdup(tname); @@ -680,6 +695,10 @@ TINFO_SETUP_TERM(TERMINAL **tp, */ if (Filedes == STDOUT_FILENO && !NC_ISATTY(Filedes)) Filedes = STDERR_FILENO; +#if defined(EXP_WIN32_DRIVER) + if (Filedes != STDERR_FILENO && NC_ISATTY(Filedes)) + _setmode(Filedes, _O_BINARY); +#endif /* * Check if we have already initialized to use this terminal. If so, we diff --git a/ncurses/tinfo/lib_tgoto.c b/ncurses/tinfo/lib_tgoto.c index 8e240856f823..9cf5e100ce87 100644 --- a/ncurses/tinfo/lib_tgoto.c +++ b/ncurses/tinfo/lib_tgoto.c @@ -36,7 +36,7 @@ #include <ctype.h> #include <termcap.h> -MODULE_ID("$Id: lib_tgoto.c,v 1.19 2020/02/02 23:34:34 tom Exp $") +MODULE_ID("$Id: lib_tgoto.c,v 1.21 2020/05/27 23:55:56 tom Exp $") #if !PURE_TERMINFO static bool @@ -207,6 +207,6 @@ tgoto(const char *string, int x, int y) result = tgoto_internal(string, x, y); else #endif - result = TPARM_2(string, y, x); + result = TIPARM_2(string, y, x); returnPtr(result); } diff --git a/ncurses/tinfo/lib_tparm.c b/ncurses/tinfo/lib_tparm.c index 400cd31996f8..b8104eabcd5e 100644 --- a/ncurses/tinfo/lib_tparm.c +++ b/ncurses/tinfo/lib_tparm.c @@ -1,5 +1,5 @@ /**************************************************************************** - * Copyright 2018-2019,2020 Thomas E. Dickey * + * Copyright 2018-2020,2021 Thomas E. Dickey * * Copyright 1998-2016,2017 Free Software Foundation, Inc. * * * * Permission is hereby granted, free of charge, to any person obtaining a * @@ -38,12 +38,22 @@ * */ +#define entry _ncu_entry +#define ENTRY _ncu_ENTRY + #include <curses.priv.h> +#undef entry +#undef ENTRY + +#if HAVE_TSEARCH +#include <search.h> +#endif + #include <ctype.h> #include <tic.h> -MODULE_ID("$Id: lib_tparm.c,v 1.108 2020/02/02 23:34:34 tom Exp $") +MODULE_ID("$Id: lib_tparm.c,v 1.129 2021/02/14 00:09:49 tom Exp $") /* * char * @@ -110,17 +120,81 @@ NCURSES_EXPORT_VAR(int) _nc_tparm_err = 0; #define TPS(var) _nc_prescreen.tparm_state.var #define popcount _nc_popcount /* workaround for NetBSD 6.0 defect */ +#define isUPPER(c) ((c) >= 'A' && (c) <= 'Z') +#define isLOWER(c) ((c) >= 'a' && (c) <= 'z') +#define tc_BUMP() if (level < 0 && number < 2) number++ + +typedef struct { + const char *format; /* format-string can be used as cache-key */ + int tparm_type; /* bit-set for each string-parameter */ + int num_actual; + int num_parsed; + int num_popped; + TPARM_ARG param[NUM_PARM]; + char *p_is_s[NUM_PARM]; +} TPARM_DATA; + +#if HAVE_TSEARCH +#define MyCache _nc_globals.cached_tparm +#define MyCount _nc_globals.count_tparm #if NO_LEAKS +static int which_tparm; +static TPARM_DATA **delete_tparm; +#endif +#endif /* HAVE_TSEARCH */ + +static char dummy[] = ""; /* avoid const-cast */ + +#if HAVE_TSEARCH +static int +cmp_format(const void *p, const void *q) +{ + const char *a = *(char *const *) p; + const char *b = *(char *const *) q; + return strcmp(a, b); +} +#endif + +#if NO_LEAKS +#if HAVE_TSEARCH +static void +visit_nodes(const void *nodep, const VISIT which, const int depth) +{ + (void) depth; + if (which == preorder || which == leaf) { + delete_tparm[which_tparm] = *(TPARM_DATA **) nodep; + which_tparm++; + } +} +#endif + NCURSES_EXPORT(void) _nc_free_tparm(void) { - if (TPS(out_buff) != 0) { - FreeAndNull(TPS(out_buff)); - TPS(out_size) = 0; - TPS(out_used) = 0; - FreeAndNull(TPS(fmt_buff)); - TPS(fmt_size) = 0; +#if HAVE_TSEARCH + if (MyCount != 0) { + delete_tparm = typeMalloc(TPARM_DATA *, MyCount); + which_tparm = 0; + twalk(MyCache, visit_nodes); + for (which_tparm = 0; which_tparm < MyCount; ++which_tparm) { + TPARM_DATA *ptr = delete_tparm[which_tparm]; + tdelete(ptr, &MyCache, cmp_format); + free((char *) ptr->format); + free(ptr); + } + which_tparm = 0; + twalk(MyCache, visit_nodes); + FreeAndNull(delete_tparm); + MyCount = 0; + which_tparm = 0; } +#endif + FreeAndNull(TPS(out_buff)); + TPS(out_size) = 0; + TPS(out_used) = 0; + + FreeAndNull(TPS(fmt_buff)); + TPS(fmt_size) = 0; } #endif @@ -137,10 +211,7 @@ get_space(size_t need) static NCURSES_INLINE void save_text(const char *fmt, const char *s, int len) { - size_t s_len = strlen(s); - if (len > (int) s_len) - s_len = (size_t) len; - + size_t s_len = (size_t) len + strlen(s) + strlen(fmt); get_space(s_len + 1); _nc_SPRINTF(TPS(out_buff) + TPS(out_used), @@ -152,10 +223,8 @@ save_text(const char *fmt, const char *s, int len) static NCURSES_INLINE void save_number(const char *fmt, int number, int len) { - if (len < 30) - len = 30; /* actually log10(MAX_INT)+1 */ - - get_space((size_t) len + 1); + size_t s_len = (size_t) len + 30 + strlen(fmt); + get_space(s_len + 1); _nc_SPRINTF(TPS(out_buff) + TPS(out_used), _nc_SLIMIT(TPS(out_size) - TPS(out_used)) @@ -216,7 +285,6 @@ spush(char *x) static NCURSES_INLINE char * spop(void) { - static char dummy[] = ""; /* avoid const-cast */ char *result = dummy; if (TPS(stack_ptr) > 0) { TPS(stack_ptr)--; @@ -325,10 +393,6 @@ parse_format(const char *s, char *format, int *len) return s; } -#define isUPPER(c) ((c) >= 'A' && (c) <= 'Z') -#define isLOWER(c) ((c) >= 'a' && (c) <= 'z') -#define tc_BUMP() if (level < 0 && number < 2) number++ - /* * Analyze the string to see how many parameters we need from the varargs list, * and what their types are. We will only accept string parameters if they @@ -341,7 +405,7 @@ parse_format(const char *s, char *format, int *len) * may be cases that we cannot see the explicit parameter numbers. */ NCURSES_EXPORT(int) -_nc_tparm_analyze(const char *string, char *p_is_s[NUM_PARM], int *popcount) +_nc_tparm_analyze(const char *string, char **p_is_s, int *popcount) { size_t len2; int i; @@ -350,7 +414,6 @@ _nc_tparm_analyze(const char *string, char *p_is_s[NUM_PARM], int *popcount) int number = 0; int level = -1; const char *cp = string; - static char dummy[] = ""; if (cp == 0) return 0; @@ -469,106 +532,179 @@ _nc_tparm_analyze(const char *string, char *p_is_s[NUM_PARM], int *popcount) return number; } -static NCURSES_INLINE char * -tparam_internal(int use_TPARM_ARG, const char *string, va_list ap) +/* + * Analyze the capability string, finding the number of parameters and their + * types. + * + * TODO: cache the result so that this is done once per capability per term. + */ +static int +tparm_setup(const char *string, TPARM_DATA * result) { - char *p_is_s[NUM_PARM]; - TPARM_ARG param[NUM_PARM]; - int popcount = 0; - int number; - int num_args; - int len; - int level; - int x, y; - int i; - const char *cp = string; - size_t len2; - bool termcap_hack; - bool incremented_two; + int rc = OK; - if (cp == NULL) { + TPS(out_used) = 0; + memset(result, 0, sizeof(*result)); + + if (string == NULL) { TR(TRACE_CALLS, ("%s: format is null", TPS(tname))); - return NULL; - } + rc = ERR; + } else { +#if HAVE_TSEARCH + TPARM_DATA *fs; + void *ft; + + result->format = string; + if ((ft = tfind(result, &MyCache, cmp_format)) != 0) { + fs = *(TPARM_DATA **) ft; + *result = *fs; + } else +#endif + { + /* + * Find the highest parameter-number referred to in the format + * string. Use this value to limit the number of arguments copied + * from the variable-length argument list. + */ + result->num_parsed = _nc_tparm_analyze(string, + result->p_is_s, + &(result->num_popped)); + if (TPS(fmt_buff) == 0) { + TR(TRACE_CALLS, ("%s: error in analysis", TPS(tname))); + rc = ERR; + } else { + int n; - TPS(out_used) = 0; - len2 = strlen(cp); - - /* - * Find the highest parameter-number referred to in the format string. - * Use this value to limit the number of arguments copied from the - * variable-length argument list. - */ - number = _nc_tparm_analyze(cp, p_is_s, &popcount); - if (TPS(fmt_buff) == 0) { - TR(TRACE_CALLS, ("%s: error in analysis", TPS(tname))); - return NULL; + if (result->num_parsed > NUM_PARM) + result->num_parsed = NUM_PARM; + if (result->num_popped > NUM_PARM) + result->num_popped = NUM_PARM; + result->num_actual = max(result->num_popped, result->num_parsed); + + for (n = 0; n < result->num_actual; ++n) { + if (result->p_is_s[n]) + result->tparm_type |= (1 << n); + } +#if HAVE_TSEARCH + if ((fs = typeCalloc(TPARM_DATA, 1)) != 0) { + *fs = *result; + if ((fs->format = strdup(string)) != 0) { + if (tsearch(fs, &MyCache, cmp_format) != 0) { + ++MyCount; + } else { + rc = ERR; + } + } else { + rc = ERR; + } + } else { + rc = ERR; + } +#endif + } + } } - incremented_two = FALSE; + return rc; +} - if (number > NUM_PARM) - number = NUM_PARM; - if (popcount > NUM_PARM) - popcount = NUM_PARM; - num_args = max(popcount, number); +/* + * A few caps (such as plab_norm) have string-valued parms. We'll have to + * assume that the caller knows the difference, since a char* and an int may + * not be the same size on the stack. The normal prototype for tparm uses 9 + * long's, which is consistent with our va_arg() usage. + */ +static void +tparm_copy_valist(TPARM_DATA * data, int use_TPARM_ARG, va_list ap) +{ + int i; - for (i = 0; i < num_args; i++) { - /* - * A few caps (such as plab_norm) have string-valued parms. - * We'll have to assume that the caller knows the difference, since - * a char* and an int may not be the same size on the stack. The - * normal prototype for this uses 9 long's, which is consistent with - * our va_arg() usage. - */ - if (p_is_s[i] != 0) { - p_is_s[i] = va_arg(ap, char *); - param[i] = 0; + for (i = 0; i < data->num_actual; i++) { + if (data->p_is_s[i] != 0) { + char *value = va_arg(ap, char *); + if (value == 0) + value = dummy; + data->p_is_s[i] = value; + data->param[i] = 0; } else if (use_TPARM_ARG) { - param[i] = va_arg(ap, TPARM_ARG); + data->param[i] = va_arg(ap, TPARM_ARG); } else { - param[i] = (TPARM_ARG) va_arg(ap, int); + data->param[i] = (TPARM_ARG) va_arg(ap, int); } } +} + +/* + * This is a termcap compatibility hack. If there are no explicit pop + * operations in the string, load the stack in such a way that successive pops + * will grab successive parameters. That will make the expansion of (for + * example) \E[%d;%dH work correctly in termcap style, which means tparam() + * will expand termcap strings OK. + */ +static bool +tparm_tc_compat(TPARM_DATA * data) +{ + bool termcap_hack = FALSE; - /* - * This is a termcap compatibility hack. If there are no explicit pop - * operations in the string, load the stack in such a way that - * successive pops will grab successive parameters. That will make - * the expansion of (for example) \E[%d;%dH work correctly in termcap - * style, which means tparam() will expand termcap strings OK. - */ TPS(stack_ptr) = 0; - termcap_hack = FALSE; - if (popcount == 0) { + + if (data->num_popped == 0) { + int i; + termcap_hack = TRUE; - for (i = number - 1; i >= 0; i--) { - if (p_is_s[i]) - spush(p_is_s[i]); + for (i = data->num_parsed - 1; i >= 0; i--) { + if (data->p_is_s[i]) + spush(data->p_is_s[i]); else - npush((int) param[i]); + npush((int) data->param[i]); } } + return termcap_hack; +} + #ifdef TRACE +static void +tparm_trace_call(const char *string, TPARM_DATA * data) +{ if (USE_TRACEF(TRACE_CALLS)) { - for (i = 0; i < num_args; i++) { - if (p_is_s[i] != 0) { - save_text(", %s", _nc_visbuf(p_is_s[i]), 0); - } else if ((long) param[i] > MAX_OF_TYPE(NCURSES_INT2) || - (long) param[i] < 0) { + int i; + for (i = 0; i < data->num_actual; i++) { + if (data->p_is_s[i] != 0) { + save_text(", %s", _nc_visbuf(data->p_is_s[i]), 0); + } else if ((long) data->param[i] > MAX_OF_TYPE(NCURSES_INT2) || + (long) data->param[i] < 0) { _tracef("BUG: problem with tparm parameter #%d of %d", - i + 1, num_args); + i + 1, data->num_actual); break; } else { - save_number(", %d", (int) param[i], 0); + save_number(", %d", (int) data->param[i], 0); } } - _tracef(T_CALLED("%s(%s%s)"), TPS(tname), _nc_visbuf(cp), TPS(out_buff)); + _tracef(T_CALLED("%s(%s%s)"), TPS(tname), _nc_visbuf(string), TPS(out_buff)); TPS(out_used) = 0; _nc_unlock_global(tracef); } +} + +#else +#define tparm_trace_call(string, data) /* nothing */ #endif /* TRACE */ +static NCURSES_INLINE char * +tparam_internal(const char *string, TPARM_DATA * data) +{ + int number; + int len; + int level; + int x, y; + int i; + const char *cp = string; + size_t len2 = strlen(cp); + bool incremented_two = FALSE; + bool termcap_hack = tparm_tc_compat(data); + + tparm_trace_call(string, data); + while ((cp - string) < (int) len2) { if (*cp != '%') { save_char(UChar(*cp)); @@ -619,10 +755,10 @@ tparam_internal(int use_TPARM_ARG, const char *string, va_list ap) cp++; i = (UChar(*cp) - '1'); if (i >= 0 && i < NUM_PARM) { - if (p_is_s[i]) { - spush(p_is_s[i]); + if (data->p_is_s[i]) { + spush(data->p_is_s[i]); } else { - npush((int) param[i]); + npush((int) data->param[i]); } } break; @@ -751,15 +887,15 @@ tparam_internal(int use_TPARM_ARG, const char *string, va_list ap) */ if (!incremented_two) { incremented_two = TRUE; - if (p_is_s[0] == 0) { - param[0]++; + if (data->p_is_s[0] == 0) { + data->param[0]++; if (termcap_hack) - TPS(stack)[0].data.num = (int) param[0]; + TPS(stack)[0].data.num = (int) data->param[0]; } - if (p_is_s[1] == 0) { - param[1]++; + if (data->p_is_s[1] == 0) { + data->param[1]++; if (termcap_hack) - TPS(stack)[1].data.num = (int) param[1]; + TPS(stack)[1].data.num = (int) data->param[1]; } } break; @@ -830,61 +966,130 @@ tparam_internal(int use_TPARM_ARG, const char *string, va_list ap) get_space((size_t) 1); TPS(out_buff)[TPS(out_used)] = '\0'; + if (TPS(stack_ptr) && !_nc_tparm_err) { + DEBUG(2, ("tparm: stack has %d item%s on return", + TPS(stack_ptr), + TPS(stack_ptr) == 1 ? "" : "s")); + _nc_tparm_err++; + } + T((T_RETURN("%s"), _nc_visbuf(TPS(out_buff)))); return (TPS(out_buff)); } #if NCURSES_TPARM_VARARGS -#define tparm_varargs tparm -#else -#define tparm_proto tparm -#endif NCURSES_EXPORT(char *) -tparm_varargs(const char *string, ...) +tparm(const char *string, ...) { + TPARM_DATA myData; va_list ap; - char *result; + char *result = NULL; _nc_tparm_err = 0; - va_start(ap, string); #ifdef TRACE TPS(tname) = "tparm"; #endif /* TRACE */ - result = tparam_internal(TRUE, string, ap); - va_end(ap); + + if (tparm_setup(string, &myData) == OK) { + + va_start(ap, string); + tparm_copy_valist(&myData, TRUE, ap); + va_end(ap); + + result = tparam_internal(string, &myData); + } return result; } -#if !NCURSES_TPARM_VARARGS +#else /* !NCURSES_TPARM_VARARGS */ + NCURSES_EXPORT(char *) -tparm_proto(const char *string, - TPARM_ARG a1, - TPARM_ARG a2, - TPARM_ARG a3, - TPARM_ARG a4, - TPARM_ARG a5, - TPARM_ARG a6, - TPARM_ARG a7, - TPARM_ARG a8, - TPARM_ARG a9) +tparm(const char *string, + TPARM_ARG a1, + TPARM_ARG a2, + TPARM_ARG a3, + TPARM_ARG a4, + TPARM_ARG a5, + TPARM_ARG a6, + TPARM_ARG a7, + TPARM_ARG a8, + TPARM_ARG a9) { - return tparm_varargs(string, a1, a2, a3, a4, a5, a6, a7, a8, a9); + TPARM_DATA myData; + char *result = NULL; + + _nc_tparm_err = 0; +#ifdef TRACE + TPS(tname) = "tparm"; +#endif /* TRACE */ + + if (tparm_setup(string, &myData) == OK) { + + myData.param[0] = a1; + myData.param[1] = a2; + myData.param[2] = a3; + myData.param[3] = a4; + myData.param[4] = a5; + myData.param[5] = a6; + myData.param[6] = a7; + myData.param[7] = a8; + myData.param[8] = a9; + + result = tparam_internal(string, &myData); + } + return result; } + #endif /* NCURSES_TPARM_VARARGS */ NCURSES_EXPORT(char *) tiparm(const char *string, ...) { + TPARM_DATA myData; va_list ap; - char *result; + char *result = NULL; _nc_tparm_err = 0; - va_start(ap, string); #ifdef TRACE TPS(tname) = "tiparm"; #endif /* TRACE */ - result = tparam_internal(FALSE, string, ap); - va_end(ap); + + if (tparm_setup(string, &myData) == OK) { + + va_start(ap, string); + tparm_copy_valist(&myData, FALSE, ap); + va_end(ap); + + result = tparam_internal(string, &myData); + } + return result; +} + +/* + * The internal-use flavor ensures that the parameters are numbers, not strings + */ +NCURSES_EXPORT(char *) +_nc_tiparm(int expected, const char *string, ...) +{ + TPARM_DATA myData; + va_list ap; + char *result = NULL; + + _nc_tparm_err = 0; +#ifdef TRACE + TPS(tname) = "_nc_tiparm"; +#endif /* TRACE */ + + if (tparm_setup(string, &myData) == OK + && myData.num_actual <= expected + && myData.tparm_type == 0) { + + va_start(ap, string); + tparm_copy_valist(&myData, FALSE, ap); + va_end(ap); + + result = tparam_internal(string, &myData); + } return result; } diff --git a/ncurses/tinfo/lib_tputs.c b/ncurses/tinfo/lib_tputs.c index bfde26efd980..3eb19d2d9662 100644 --- a/ncurses/tinfo/lib_tputs.c +++ b/ncurses/tinfo/lib_tputs.c @@ -52,7 +52,7 @@ #include <termcap.h> /* ospeed */ #include <tic.h> -MODULE_ID("$Id: lib_tputs.c,v 1.103 2020/02/02 23:34:34 tom Exp $") +MODULE_ID("$Id: lib_tputs.c,v 1.106 2020/11/29 00:40:08 tom Exp $") NCURSES_EXPORT_VAR(char) PC = 0; /* used by termcap library */ NCURSES_EXPORT_VAR(NCURSES_OSPEED) ospeed = 0; /* used by termcap library */ @@ -120,16 +120,21 @@ delay_output(int ms) NCURSES_EXPORT(void) NCURSES_SP_NAME(_nc_flush) (NCURSES_SP_DCL0) { + T((T_CALLED("_nc_flush(%p)"), (void *) SP_PARM)); if (SP_PARM != 0 && SP_PARM->_ofd >= 0) { + TR(TRACE_CHARPUT, ("ofd:%d inuse:%lu buffer:%p", + SP_PARM->_ofd, + (unsigned long) SP_PARM->out_inuse, + SP_PARM->out_buffer)); if (SP_PARM->out_inuse) { char *buf = SP_PARM->out_buffer; size_t amount = SP->out_inuse; SP->out_inuse = 0; - TR(TRACE_CHARPUT, ("flushing %ld bytes", (unsigned long) amount)); + TR(TRACE_CHARPUT, ("flushing %ld/%ld bytes", + (unsigned long) amount, _nc_outchars)); while (amount) { ssize_t res = write(SP_PARM->_ofd, buf, amount); - if (res > 0) { /* if the write was incomplete, try again */ amount -= (size_t) res; @@ -142,10 +147,15 @@ NCURSES_SP_NAME(_nc_flush) (NCURSES_SP_DCL0) break; /* an error we can not recover from */ } } + } else if (SP_PARM->out_buffer == 0) { + TR(TRACE_CHARPUT, ("flushing stdout")); + fflush(stdout); } } else { + TR(TRACE_CHARPUT, ("flushing stdout")); fflush(stdout); } + returnVoid; } #if NCURSES_SP_FUNCS diff --git a/ncurses/tinfo/lib_ttyflags.c b/ncurses/tinfo/lib_ttyflags.c index bfcd64af58b1..6363a805be9c 100644 --- a/ncurses/tinfo/lib_ttyflags.c +++ b/ncurses/tinfo/lib_ttyflags.c @@ -42,7 +42,7 @@ #define CUR SP_TERMTYPE #endif -MODULE_ID("$Id: lib_ttyflags.c,v 1.34 2020/02/02 23:34:34 tom Exp $") +MODULE_ID("$Id: lib_ttyflags.c,v 1.36 2020/09/05 22:54:47 tom Exp $") NCURSES_EXPORT(int) NCURSES_SP_NAME(_nc_get_tty_mode) (NCURSES_SP_DCLx TTY * buf) @@ -156,6 +156,8 @@ NCURSES_SP_NAME(def_shell_mode) (NCURSES_SP_DCL0) #ifdef TERMIOS if (termp->Ottyb.c_oflag & OFLAGS_TABS) tab = back_tab = NULL; +#elif defined(EXP_WIN32_DRIVER) + /* noop */ #else if (termp->Ottyb.sg_flags & XTABS) tab = back_tab = NULL; @@ -193,6 +195,8 @@ NCURSES_SP_NAME(def_prog_mode) (NCURSES_SP_DCL0) if (_nc_get_tty_mode(&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 diff --git a/ncurses/tinfo/lib_win32con.c b/ncurses/tinfo/lib_win32con.c new file mode 100644 index 000000000000..3c0fe8160734 --- /dev/null +++ b/ncurses/tinfo/lib_win32con.c @@ -0,0 +1,1256 @@ +/**************************************************************************** + * Copyright 2020 Thomas E. Dickey * + * Copyright 1998-2009,2010 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 * + * "Software"), to deal in the Software without restriction, including * + * without limitation the rights to use, copy, modify, merge, publish, * + * distribute, distribute with modifications, sublicense, and/or sell * + * copies of the Software, and to permit persons to whom the Software is * + * furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included * + * in all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * + * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + * * + * Except as contained in this notice, the name(s) of the above copyright * + * holders shall not be used in advertising or otherwise to promote the * + * sale, use or other dealings in this Software without prior written * + * authorization. * + ****************************************************************************/ + +/**************************************************************************** + * Author: Juergen Pfeifer * + * and: Thomas E. Dickey * + ****************************************************************************/ + +/* + * TODO - GetMousePos(POINT * result) from ntconio.c + */ + +#include <curses.priv.h> + +MODULE_ID("$Id: lib_win32con.c,v 1.6 2020/11/21 23:44:58 tom Exp $") + +#ifdef _NC_WINDOWS + +#ifdef _NC_MINGW +#include <wchar.h> +#else +#include <tchar.h> +#endif + +#include <io.h> + +#if USE_WIDEC_SUPPORT +#define write_screen WriteConsoleOutputW +#define read_screen ReadConsoleOutputW +#else +#define write_screen WriteConsoleOutput +#define read_screen ReadConsoleOutput +#endif + +static BOOL IsConsoleHandle(HANDLE hdl); +static bool save_original_screen(void); +static bool restore_original_screen(void) GCC_UNUSED; +static bool read_screen_data(void); +static int Adjust(int milliseconds, int diff); +static int decode_mouse(SCREEN *sp, int mask); +static bool handle_mouse(SCREEN *sp, MOUSE_EVENT_RECORD mer); +static int rkeycompare(const void *el1, const void *el2); +static int keycompare(const void *el1, const void *el2); +static int MapKey(WORD vKey); +static int AnsiKey(WORD vKey); + +static ULONGLONG tdiff(FILETIME fstart, FILETIME fend); + +#define GenMap(vKey,key) MAKELONG(key, vKey) +static const LONG keylist[] = +{ + GenMap(VK_PRIOR, KEY_PPAGE), + GenMap(VK_NEXT, KEY_NPAGE), + GenMap(VK_END, KEY_END), + GenMap(VK_HOME, KEY_HOME), + GenMap(VK_LEFT, KEY_LEFT), + GenMap(VK_UP, KEY_UP), + GenMap(VK_RIGHT, KEY_RIGHT), + GenMap(VK_DOWN, KEY_DOWN), + GenMap(VK_DELETE, KEY_DC), + GenMap(VK_INSERT, KEY_IC) +}; +static const LONG ansi_keys[] = +{ + GenMap(VK_PRIOR, 'I'), + GenMap(VK_NEXT, 'Q'), + GenMap(VK_END, 'O'), + GenMap(VK_HOME, 'H'), + GenMap(VK_LEFT, 'K'), + GenMap(VK_UP, 'H'), + GenMap(VK_RIGHT, 'M'), + GenMap(VK_DOWN, 'P'), + GenMap(VK_DELETE, 'S'), + GenMap(VK_INSERT, 'R') +}; +#define array_length(a) (sizeof(a)/sizeof(a[0])) +#define N_INI ((int)array_length(keylist)) +#define FKEYS 24 +#define MAPSIZE (FKEYS + N_INI) + +/* A process can only have a single console, so it's safe + to maintain all the information about it in a single + static structure. + */ +NCURSES_EXPORT_VAR(ConsoleInfo) _nc_CONSOLE; +static bool console_initialized = FALSE; + +#define EnsureInit() (void)(console_initialized ? TRUE : _nc_console_checkinit(TRUE, TRUE)) + +#define REQUIRED_MAX_V (DWORD)10 +#define REQUIRED_MIN_V (DWORD)0 +#define REQUIRED_BUILD (DWORD)17763 +/* + This function returns 0 if the Windows version has no support for + the modern Console interface, otherwise it returns 1 + */ +NCURSES_EXPORT(int) +_nc_console_vt_supported(void) +{ + OSVERSIONINFO osvi; + int res = 0; + + T((T_CALLED("lib_win32con::_nc_console_vt_supported"))); + ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + + GetVersionEx(&osvi); + T(("GetVersionEx returnedMajor=%ld, Minor=%ld, Build=%ld", + osvi.dwMajorVersion, + osvi.dwMinorVersion, + osvi.dwBuildNumber)); + if (osvi.dwMajorVersion >= REQUIRED_MAX_V) { + if (osvi.dwMajorVersion == REQUIRED_MAX_V) { + if (((osvi.dwMinorVersion == REQUIRED_MIN_V) && + (osvi.dwBuildNumber >= REQUIRED_BUILD)) || + ((osvi.dwMinorVersion > REQUIRED_MIN_V))) + res = 1; + } else + res = 1; + } + returnCode(res); +} + +NCURSES_EXPORT(void) +_nc_console_size(int* Lines, int* Cols) +{ + EnsureInit(); + if (Lines != NULL && Cols != NULL) { + if (WINCONSOLE.buffered) { + *Lines = (int) (WINCONSOLE.SBI.dwSize.Y); + *Cols = (int) (WINCONSOLE.SBI.dwSize.X); + } else { + *Lines = (int) (WINCONSOLE.SBI.srWindow.Bottom + 1 - + WINCONSOLE.SBI.srWindow.Top); + *Cols = (int) (WINCONSOLE.SBI.srWindow.Right + 1 - + WINCONSOLE.SBI.srWindow.Left); + } + } +} + +/* Convert a file descriptor into a HANDLE + That's not necessarily a console HANDLE +*/ +NCURSES_EXPORT(HANDLE) +_nc_console_handle(int fd) +{ + intptr_t value = _get_osfhandle(fd); + return (HANDLE) value; +} + +/* Validate that a HANDLE is actually a + console HANDLE +*/ +static BOOL +IsConsoleHandle(HANDLE hdl) +{ + DWORD dwFlag = 0; + BOOL result = FALSE; + + T((T_CALLED("lib_win32con::IsConsoleHandle(HANDLE=%p"), hdl)); + + EnsureInit(); + + if (!GetConsoleMode(hdl, &dwFlag)) { + T(("GetConsoleMode failed")); + } else { + result = TRUE; + } + + returnBool(result); +} + +/* This is used when running in terminfo mode to discover, + whether or not the "terminal" is actually a Windows + Console. It's the responsibility of the console to deal + with the terminal escape sequences that are sent by + terminfo. + */ +NCURSES_EXPORT(int) +_nc_console_test(int fd) +{ + int code = 0; + HANDLE hdl = INVALID_HANDLE_VALUE; + T((T_CALLED("lib_win32con::_nc_console_test(%d)"), fd)); + hdl = _nc_console_handle(fd); + code = (int) IsConsoleHandle(hdl); + returnCode(code); +} + +#define OutHandle() ((WINCONSOLE.isTermInfoConsole || WINCONSOLE.progMode) ? WINCONSOLE.hdl : WINCONSOLE.out) + +NCURSES_EXPORT(void) +_nc_console_selectActiveHandle(void) +{ + if (WINCONSOLE.lastOut != WINCONSOLE.hdl) { + WINCONSOLE.lastOut = WINCONSOLE.hdl; + SetConsoleActiveScreenBuffer(WINCONSOLE.lastOut); + } +} + +NCURSES_EXPORT(HANDLE) +_nc_console_fd2handle(int fd) +{ + HANDLE hdl = _nc_console_handle(fd); + if (hdl==WINCONSOLE.inp) { + T(("lib_win32con:validateHandle %d -> WINCONSOLE.inp", fd)); + } else if (hdl==WINCONSOLE.hdl) { + T(("lib_win32con:validateHandle %d -> WINCONSOLE.hdl", fd)); + } else if (hdl==WINCONSOLE.out) { + T(("lib_win32con:validateHandle %d -> WINCONSOLE.out", fd)); + } else { + T(("lib_win32con:validateHandle %d maps to unknown HANDLE", fd)); + hdl = INVALID_HANDLE_VALUE; + } +#if 1 + assert(hdl != INVALID_HANDLE_VALUE); +#endif + if (hdl != INVALID_HANDLE_VALUE) { + if (hdl != WINCONSOLE.inp && (!WINCONSOLE.isTermInfoConsole && WINCONSOLE.progMode)) { + if (hdl==WINCONSOLE.out && hdl!=WINCONSOLE.hdl) { + T(("lib_win32con:validateHandle forcing WINCONSOLE.out -> WINCONSOLE.hdl")); + hdl = WINCONSOLE.hdl; + } + } + } + return hdl; +} + +NCURSES_EXPORT(int) +_nc_console_setmode(HANDLE hdl, const TTY *arg) +{ + DWORD dwFlag = 0; + int code = ERR; + HANDLE alt; + + if (arg) { +#ifdef TRACE + TTY TRCTTY; +#define TRCTTYOUT(flag) TRCTTY.dwFlagOut = flag +#define TRCTTYIN(flag) TRCTTY.dwFlagIn = flag +#else +#define TRCTTYOUT(flag) +#define TRCTTYIN(flag) +#endif + T(("lib_win32con:_nc_console_setmode %s", _nc_trace_ttymode(arg))); + if (hdl==WINCONSOLE.inp) { + dwFlag = arg->dwFlagIn | ENABLE_MOUSE_INPUT | VT_FLAG_IN; + if (WINCONSOLE.isTermInfoConsole) + dwFlag |= (VT_FLAG_IN); + else + dwFlag &= (DWORD) ~(VT_FLAG_IN); + TRCTTYIN(dwFlag); + SetConsoleMode(hdl, dwFlag); + + alt = OutHandle(); + dwFlag = arg->dwFlagOut; + if (WINCONSOLE.isTermInfoConsole) + dwFlag |= (VT_FLAG_OUT); + else + dwFlag |= (VT_FLAG_OUT); + TRCTTYOUT(dwFlag); + SetConsoleMode(alt, dwFlag); + } else { + dwFlag = arg->dwFlagOut; + if (WINCONSOLE.isTermInfoConsole) + dwFlag |= (VT_FLAG_OUT); + else + dwFlag |= (VT_FLAG_OUT); + TRCTTYOUT(dwFlag); + SetConsoleMode(hdl, dwFlag); + + alt = WINCONSOLE.inp; + dwFlag = arg->dwFlagIn | ENABLE_MOUSE_INPUT; + if (WINCONSOLE.isTermInfoConsole) + dwFlag |= (VT_FLAG_IN); + else + dwFlag &= (DWORD) ~(VT_FLAG_IN); + TRCTTYIN(dwFlag); + SetConsoleMode(alt, dwFlag); + T(("effective mode set %s", _nc_trace_ttymode(&TRCTTY))); + } + code = OK; + } + return(code); +} + +NCURSES_EXPORT(int) +_nc_console_getmode(HANDLE hdl, TTY *arg) +{ + int code = ERR; + + if (arg) { + DWORD dwFlag = 0; + HANDLE alt; + + if (hdl==WINCONSOLE.inp) { + if(GetConsoleMode(hdl, &dwFlag)) { + arg->dwFlagIn = dwFlag; + alt = OutHandle(); + if (GetConsoleMode(alt, &dwFlag)) { + arg->dwFlagOut = dwFlag; + code = OK; + } + } + } else { + if (GetConsoleMode(hdl, &dwFlag)) { + arg->dwFlagOut = dwFlag; + alt = WINCONSOLE.inp; + if (GetConsoleMode(alt, &dwFlag)) { + arg->dwFlagIn = dwFlag; + code = OK; + } + } + } + } + T(("lib_win32con:_nc_console_getmode %s", _nc_trace_ttymode(arg))); + return(code); +} + +NCURSES_EXPORT(int) +_nc_console_flush(HANDLE hdl) +{ + int code = OK; + + T((T_CALLED("lib_win32con::_nc_console_flush(hdl=%p"), hdl)); + + if (hdl != INVALID_HANDLE_VALUE) { + if (hdl == WINCONSOLE.hdl || + hdl == WINCONSOLE.inp || + hdl == WINCONSOLE.out) { + if (!FlushConsoleInputBuffer(WINCONSOLE.inp)) + code = ERR; + } else { + code = ERR; + T(("_nc_console_flush not requesting a handle owned by console.")); + } + } + returnCode(code); +} + +NCURSES_EXPORT(WORD) +_nc_console_MapColor(bool fore, int color) +{ + static const int _cmap[] = + {0, 4, 2, 6, 1, 5, 3, 7}; + int a; + if (color < 0 || color > 7) + a = fore ? 7 : 0; + else + a = _cmap[color]; + if (!fore) + a = a << 4; + return (WORD) a; +} + + +/* + * Attempt to save the screen contents. PDCurses does this if + * PDC_RESTORE_SCREEN is set, giving the same visual appearance on + * restoration as if the library had allocated a console buffer. MSDN + * says that the data which can be read is limited to 64Kb (and may be + * less). + */ +static bool +save_original_screen(void) +{ + bool result = FALSE; + + WINCONSOLE.save_region.Top = 0; + WINCONSOLE.save_region.Left = 0; + WINCONSOLE.save_region.Bottom = (SHORT) (WINCONSOLE.SBI.dwSize.Y - 1); + WINCONSOLE.save_region.Right = (SHORT) (WINCONSOLE.SBI.dwSize.X - 1); + + if (read_screen_data()) { + result = TRUE; + } else { + + WINCONSOLE.save_region.Top = WINCONSOLE.SBI.srWindow.Top; + WINCONSOLE.save_region.Left = WINCONSOLE.SBI.srWindow.Left; + WINCONSOLE.save_region.Bottom = WINCONSOLE.SBI.srWindow.Bottom; + WINCONSOLE.save_region.Right = WINCONSOLE.SBI.srWindow.Right; + + WINCONSOLE.window_only = TRUE; + + if (read_screen_data()) { + result = TRUE; + } + } + + T(("... save original screen contents %s", result ? "ok" : "err")); + return result; +} + +static bool +restore_original_screen(void) +{ + COORD bufferCoord; + bool result = FALSE; + SMALL_RECT save_region = WINCONSOLE.save_region; + + T(("... restoring %s", + WINCONSOLE.window_only ? "window" : "entire buffer")); + + bufferCoord.X = (SHORT) (WINCONSOLE.window_only ? + WINCONSOLE.SBI.srWindow.Left : 0); + bufferCoord.Y = (SHORT) (WINCONSOLE.window_only ? + WINCONSOLE.SBI.srWindow.Top : 0); + + if (write_screen(WINCONSOLE.hdl, + WINCONSOLE.save_screen, + WINCONSOLE.save_size, + bufferCoord, + &save_region)) { + result = TRUE; + mvcur(-1, -1, LINES - 2, 0); + T(("... restore original screen contents ok %dx%d (%d,%d - %d,%d)", + WINCONSOLE.save_size.Y, + WINCONSOLE.save_size.X, + save_region.Top, + save_region.Left, + save_region.Bottom, + save_region.Right)); + } else { + T(("... restore original screen contents err")); + } + return result; +} + +static bool +read_screen_data(void) +{ + bool result = FALSE; + COORD bufferCoord; + size_t want; + + WINCONSOLE.save_size.X = (SHORT) (WINCONSOLE.save_region.Right + - WINCONSOLE.save_region.Left + 1); + WINCONSOLE.save_size.Y = (SHORT) (WINCONSOLE.save_region.Bottom + - WINCONSOLE.save_region.Top + 1); + + want = (size_t) (WINCONSOLE.save_size.X * WINCONSOLE.save_size.Y); + + if ((WINCONSOLE.save_screen = malloc(want * sizeof(CHAR_INFO))) != 0) { + bufferCoord.X = (SHORT) (WINCONSOLE.window_only ? + WINCONSOLE.SBI.srWindow.Left : 0); + bufferCoord.Y = (SHORT) (WINCONSOLE.window_only ? + WINCONSOLE.SBI.srWindow.Top : 0); + + T(("... reading console %s %dx%d into %d,%d - %d,%d at %d,%d", + WINCONSOLE.window_only ? "window" : "buffer", + WINCONSOLE.save_size.Y, WINCONSOLE.save_size.X, + WINCONSOLE.save_region.Top, + WINCONSOLE.save_region.Left, + WINCONSOLE.save_region.Bottom, + WINCONSOLE.save_region.Right, + bufferCoord.Y, + bufferCoord.X)); + + if (read_screen(WINCONSOLE.hdl, + WINCONSOLE.save_screen, + WINCONSOLE.save_size, + bufferCoord, + &WINCONSOLE.save_region)) { + result = TRUE; + } else { + T((" error %#lx", (unsigned long) GetLastError())); + FreeAndNull(WINCONSOLE.save_screen); + } + } + + return result; +} + +NCURSES_EXPORT(bool) +_nc_console_get_SBI(void) +{ + bool rc = FALSE; + if (GetConsoleScreenBufferInfo(WINCONSOLE.hdl, &(WINCONSOLE.SBI))) { + T(("GetConsoleScreenBufferInfo")); + T(("... buffer(X:%d Y:%d)", + WINCONSOLE.SBI.dwSize.X, + WINCONSOLE.SBI.dwSize.Y)); + T(("... window(X:%d Y:%d)", + WINCONSOLE.SBI.dwMaximumWindowSize.X, + WINCONSOLE.SBI.dwMaximumWindowSize.Y)); + T(("... cursor(X:%d Y:%d)", + WINCONSOLE.SBI.dwCursorPosition.X, + WINCONSOLE.SBI.dwCursorPosition.Y)); + T(("... display(Top:%d Bottom:%d Left:%d Right:%d)", + WINCONSOLE.SBI.srWindow.Top, + WINCONSOLE.SBI.srWindow.Bottom, + WINCONSOLE.SBI.srWindow.Left, + WINCONSOLE.SBI.srWindow.Right)); + if (WINCONSOLE.buffered) { + WINCONSOLE.origin.X = 0; + WINCONSOLE.origin.Y = 0; + } else { + WINCONSOLE.origin.X = WINCONSOLE.SBI.srWindow.Left; + WINCONSOLE.origin.Y = WINCONSOLE.SBI.srWindow.Top; + } + rc = TRUE; + } else { + T(("GetConsoleScreenBufferInfo ERR")); + } + return rc; +} + +#define MIN_WIDE 80 +#define MIN_HIGH 24 + +/* + * In "normal" mode, reset the buffer- and window-sizes back to their original values. + */ +NCURSES_EXPORT(void) +_nc_console_set_scrollback(bool normal, CONSOLE_SCREEN_BUFFER_INFO * info) +{ + SMALL_RECT rect; + COORD coord; + bool changed = FALSE; + + T((T_CALLED("lib_win32con::_nc_console_set_scrollback(%s)"), + (normal + ? "normal" + : "application"))); + + T(("... SBI.srWindow %d,%d .. %d,%d", + info->srWindow.Top, + info->srWindow.Left, + info->srWindow.Bottom, + info->srWindow.Right)); + T(("... SBI.dwSize %dx%d", + info->dwSize.Y, + info->dwSize.X)); + + if (normal) { + rect = info->srWindow; + coord = info->dwSize; + if (memcmp(info, &WINCONSOLE.SBI, sizeof(*info)) != 0) { + changed = TRUE; + WINCONSOLE.SBI = *info; + } + } else { + int high = info->srWindow.Bottom - info->srWindow.Top + 1; + int wide = info->srWindow.Right - info->srWindow.Left + 1; + + if (high < MIN_HIGH) { + T(("... height %d < %d", high, MIN_HIGH)); + high = MIN_HIGH; + changed = TRUE; + } + if (wide < MIN_WIDE) { + T(("... width %d < %d", wide, MIN_WIDE)); + wide = MIN_WIDE; + changed = TRUE; + } + + rect.Left = + rect.Top = 0; + rect.Right = (SHORT) (wide - 1); + rect.Bottom = (SHORT) (high - 1); + + coord.X = (SHORT) wide; + coord.Y = (SHORT) high; + + if (info->dwSize.Y != high || + info->dwSize.X != wide || + info->srWindow.Top != 0 || + info->srWindow.Left != 0) { + changed = TRUE; + } + + } + + if (changed) { + T(("... coord %d,%d", coord.Y, coord.X)); + T(("... rect %d,%d - %d,%d", + rect.Top, rect.Left, + rect.Bottom, rect.Right)); + SetConsoleScreenBufferSize(WINCONSOLE.hdl, coord); /* dwSize */ + SetConsoleWindowInfo(WINCONSOLE.hdl, TRUE, &rect); /* srWindow */ + _nc_console_get_SBI(); + } + returnVoid; +} + +static ULONGLONG +tdiff(FILETIME fstart, FILETIME fend) +{ + ULARGE_INTEGER ustart; + ULARGE_INTEGER uend; + ULONGLONG diff; + + ustart.LowPart = fstart.dwLowDateTime; + ustart.HighPart = fstart.dwHighDateTime; + uend.LowPart = fend.dwLowDateTime; + uend.HighPart = fend.dwHighDateTime; + + diff = (uend.QuadPart - ustart.QuadPart) / 10000; + return diff; +} + +static int +Adjust(int milliseconds, int diff) +{ + if (milliseconds != INFINITY) { + milliseconds -= diff; + if (milliseconds < 0) + milliseconds = 0; + } + return milliseconds; +} + +#define BUTTON_MASK (FROM_LEFT_1ST_BUTTON_PRESSED | \ + FROM_LEFT_2ND_BUTTON_PRESSED | \ + FROM_LEFT_3RD_BUTTON_PRESSED | \ + FROM_LEFT_4TH_BUTTON_PRESSED | \ + RIGHTMOST_BUTTON_PRESSED) + +static int +decode_mouse(SCREEN *sp, int mask) +{ + int result = 0; + + (void) sp; + assert(sp && console_initialized); + + if (mask & FROM_LEFT_1ST_BUTTON_PRESSED) + result |= BUTTON1_PRESSED; + if (mask & FROM_LEFT_2ND_BUTTON_PRESSED) + result |= BUTTON2_PRESSED; + if (mask & FROM_LEFT_3RD_BUTTON_PRESSED) + result |= BUTTON3_PRESSED; + if (mask & FROM_LEFT_4TH_BUTTON_PRESSED) + result |= BUTTON4_PRESSED; + + if (mask & RIGHTMOST_BUTTON_PRESSED) { + switch (WINCONSOLE.numButtons) { + case 1: + result |= BUTTON1_PRESSED; + break; + case 2: + result |= BUTTON2_PRESSED; + break; + case 3: + result |= BUTTON3_PRESSED; + break; + case 4: + result |= BUTTON4_PRESSED; + break; + } + } + + return result; +} + +#define AdjustY() (WINCONSOLE.buffered ? 0 : (int) WINCONSOLE.SBI.srWindow.Top) + +static bool +handle_mouse(SCREEN *sp, MOUSE_EVENT_RECORD mer) +{ + MEVENT work; + bool result = FALSE; + + assert(sp); + + sp->_drv_mouse_old_buttons = sp->_drv_mouse_new_buttons; + sp->_drv_mouse_new_buttons = mer.dwButtonState & BUTTON_MASK; + + /* + * We're only interested if the button is pressed or released. + * FIXME: implement continuous event-tracking. + */ + if (sp->_drv_mouse_new_buttons != sp->_drv_mouse_old_buttons) { + memset(&work, 0, sizeof(work)); + + if (sp->_drv_mouse_new_buttons) { + work.bstate |= + (mmask_t) decode_mouse(sp, + sp->_drv_mouse_new_buttons); + } else { + /* cf: BUTTON_PRESSED, BUTTON_RELEASED */ + work.bstate |= + (mmask_t) (decode_mouse(sp, + sp->_drv_mouse_old_buttons) + >> 1); + result = TRUE; + } + + work.x = mer.dwMousePosition.X; + work.y = mer.dwMousePosition.Y - AdjustY(); + + sp->_drv_mouse_fifo[sp->_drv_mouse_tail] = work; + sp->_drv_mouse_tail += 1; + } + return result; +} + +static int +rkeycompare(const void *el1, const void *el2) +{ + WORD key1 = (LOWORD((*((const LONG *) el1)))) & 0x7fff; + WORD key2 = (LOWORD((*((const LONG *) el2)))) & 0x7fff; + + return ((key1 < key2) ? -1 : ((key1 == key2) ? 0 : 1)); +} + + +static int +keycompare(const void *el1, const void *el2) +{ + WORD key1 = HIWORD((*((const LONG *) el1))); + WORD key2 = HIWORD((*((const LONG *) el2))); + + return ((key1 < key2) ? -1 : ((key1 == key2) ? 0 : 1)); +} + +static int +MapKey(WORD vKey) +{ + int code = -1; + + if (!WINCONSOLE.isTermInfoConsole) { + WORD nKey = 0; + void *res; + LONG key = GenMap(vKey, 0); + + res = bsearch(&key, + WINCONSOLE.map, + (size_t) (N_INI + FKEYS), + sizeof(keylist[0]), + keycompare); + if (res) { + key = *((LONG *) res); + nKey = LOWORD(key); + code = (int) (nKey & 0x7fff); + if (nKey & 0x8000) + code = -code; + } + } + return code; +} + +static int +AnsiKey(WORD vKey) +{ + int code = -1; + + if (!WINCONSOLE.isTermInfoConsole) { + WORD nKey = 0; + void *res; + LONG key = GenMap(vKey, 0); + + res = bsearch(&key, + WINCONSOLE.ansi_map, + (size_t) (N_INI + FKEYS), + sizeof(keylist[0]), + keycompare); + if (res) { + key = *((LONG *) res); + nKey = LOWORD(key); + code = (int) (nKey & 0x7fff); + if (nKey & 0x8000) + code = -code; + } + } + return code; +} + +NCURSES_EXPORT(int) +_nc_console_keyok(int keycode, int flag) +{ + int code = ERR; + WORD nKey; + WORD vKey; + void *res; + LONG key = GenMap(0, (WORD) keycode); + + T((T_CALLED("lib_win32con::_nc_console_keyok(%d, %d)"), keycode, flag)); + + res = bsearch(&key, + WINCONSOLE.rmap, + (size_t) (N_INI + FKEYS), + sizeof(keylist[0]), + rkeycompare); + if (res) { + key = *((LONG *) res); + vKey = HIWORD(key); + nKey = (LOWORD(key)) & 0x7fff; + if (!flag) + nKey |= 0x8000; + *(LONG *) res = GenMap(vKey, nKey); + } + returnCode(code); +} + +NCURSES_EXPORT(bool) +_nc_console_keyExist(int keycode) +{ + WORD nKey; + void *res; + bool found = FALSE; + LONG key = GenMap(0, (WORD) keycode); + + T((T_CALLED("lib_win32con::_nc_console_keyExist(%d)"), keycode)); + res = bsearch(&key, + WINCONSOLE.rmap, + (size_t) (N_INI + FKEYS), + sizeof(keylist[0]), + rkeycompare); + if (res) { + key = *((LONG *) res); + nKey = LOWORD(key); + if (!(nKey & 0x8000)) + found = TRUE; + } + returnCode(found); +} + +NCURSES_EXPORT(int) +_nc_console_twait( + SCREEN *sp, + HANDLE hdl, + int mode, + int milliseconds, + int *timeleft + EVENTLIST_2nd(_nc_eventlist * evl)) +{ + INPUT_RECORD inp_rec; + BOOL b; + DWORD nRead = 0, rc = (DWORD) (-1); + int code = 0; + FILETIME fstart; + FILETIME fend; + int diff; + bool isNoDelay = (milliseconds == 0); + +#ifdef NCURSES_WGETCH_EVENTS + (void) evl; /* TODO: implement wgetch-events */ +#endif + +#define IGNORE_CTRL_KEYS (SHIFT_PRESSED|LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED| \ + LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED) +#define CONSUME() ReadConsoleInput(hdl, &inp_rec, 1, &nRead) + + assert(sp); + + TR(TRACE_IEVENT, ("start twait: hdl=%p, %d milliseconds, mode: %d", + hdl, milliseconds, mode)); + + if (milliseconds < 0) + milliseconds = INFINITY; + + memset(&inp_rec, 0, sizeof(inp_rec)); + + while (true) { + if (!isNoDelay) { + GetSystemTimeAsFileTime(&fstart); + rc = WaitForSingleObject(hdl, (DWORD) milliseconds); + GetSystemTimeAsFileTime(&fend); + diff = (int) tdiff(fstart, fend); + milliseconds = Adjust(milliseconds, diff); + if (milliseconds< 0) + break; + } + + if (isNoDelay || (rc == WAIT_OBJECT_0)) { + if (mode) { + nRead = 0; + b = GetNumberOfConsoleInputEvents(hdl, &nRead); + if (!b) { + T(("twait:err GetNumberOfConsoleInputEvents")); + } + if (isNoDelay && b) { + T(("twait: Events Available: %ld", nRead)); + if (nRead==0) { + code = 0; + goto end; + } else { + DWORD n = 0; + INPUT_RECORD* pInpRec = + TypeAlloca(INPUT_RECORD, nRead); + if (pInpRec != NULL) { + DWORD i; + BOOL f; + memset(pInpRec, 0, sizeof(INPUT_RECORD)*nRead); + f = PeekConsoleInput(hdl, pInpRec, nRead, &n); + if (f) { + for(i = 0; i < n; i++) { + if (pInpRec[i].EventType==KEY_EVENT) { + if(pInpRec[i].Event.KeyEvent.bKeyDown) { + DWORD ctrlMask = + (pInpRec[i].Event.KeyEvent.dwControlKeyState & + IGNORE_CTRL_KEYS); + if (!ctrlMask) { + code = TW_INPUT; + goto end; + } + } + } + } + } else { + T(("twait:err PeekConsoleInput")); + } + code = 0; + goto end; + } else { + T(("twait:err could not alloca input records")); + } + } + } + if (b && nRead > 0) { + b = PeekConsoleInput(hdl, &inp_rec, 1, &nRead); + if (!b) { + T(("twait:err PeekConsoleInput")); + } + if (b && nRead > 0) { + switch (inp_rec.EventType) { + case KEY_EVENT: + if (mode & TW_INPUT) { + WORD vk = + inp_rec.Event.KeyEvent.wVirtualKeyCode; + char ch = + inp_rec.Event.KeyEvent.uChar.AsciiChar; + T(("twait:event KEY_EVENT")); + T(("twait vk=%d, ch=%d, keydown=%d", + vk, ch, inp_rec.Event.KeyEvent.bKeyDown)); + if (inp_rec.Event.KeyEvent.bKeyDown) { + T(("twait:event KeyDown")); + if (!WINCONSOLE.isTermInfoConsole && + (0 == ch)) { + int nKey = MapKey(vk); + if (nKey < 0) { + CONSUME(); + continue; + } + } + code = TW_INPUT; + goto end; + } else { + CONSUME(); + } + } + continue; + case MOUSE_EVENT: + T(("twait:event MOUSE_EVENT")); + if (decode_mouse(sp, + (inp_rec.Event.MouseEvent.dwButtonState + & BUTTON_MASK)) == 0) { + CONSUME(); + } else if (mode & TW_MOUSE) { + code = TW_MOUSE; + goto end; + } + continue; + /* e.g., FOCUS_EVENT */ + default: + T(("twait:event Tyoe %d", inp_rec.EventType)); + CONSUME(); + _nc_console_selectActiveHandle(); + continue; + } + } + } + } + continue; + } else { + if (rc != WAIT_TIMEOUT) { + code = -1; + break; + } else { + code = 0; + break; + } + } + } +end: + + TR(TRACE_IEVENT, ("end twait: returned %d (%lu), remaining time %d msec", + code, GetLastError(), milliseconds)); + + if (timeleft) + *timeleft = milliseconds; + + return code; +} + +NCURSES_EXPORT(int) +_nc_console_testmouse( + SCREEN *sp, + HANDLE hdl, + int delay + EVENTLIST_2nd(_nc_eventlist * evl)) +{ + int rc = 0; + + assert(sp); + + if (sp->_drv_mouse_head < sp->_drv_mouse_tail) { + rc = TW_MOUSE; + } else { + rc = _nc_console_twait(sp, + hdl, + TWAIT_MASK, + delay, + (int *) 0 + EVENTLIST_2nd(evl)); + } + return rc; +} + +NCURSES_EXPORT(int) +_nc_console_read( + SCREEN *sp, + HANDLE hdl, + int *buf) +{ + int rc = -1; + INPUT_RECORD inp_rec; + BOOL b; + DWORD nRead; + WORD vk; + + assert(sp); + assert(buf); + + memset(&inp_rec, 0, sizeof(inp_rec)); + + T((T_CALLED("lib_win32con::_nc_console_read(%p)"), sp)); + + while ((b = ReadConsoleInput(hdl, &inp_rec, 1, &nRead))) { + if (b && nRead > 0) { + if (rc < 0) + rc = 0; + rc = rc + (int) nRead; + if (inp_rec.EventType == KEY_EVENT) { + if (!inp_rec.Event.KeyEvent.bKeyDown) + continue; + *buf = (int) inp_rec.Event.KeyEvent.uChar.AsciiChar; + vk = inp_rec.Event.KeyEvent.wVirtualKeyCode; + /* + * There are 24 virtual function-keys, and typically + * 12 function-keys on a keyboard. Use the shift-modifier + * to provide the remaining 12 keys. + */ + if (vk >= VK_F1 && vk <= VK_F12) { + if (inp_rec.Event.KeyEvent.dwControlKeyState & + SHIFT_PRESSED) { + vk = (WORD) (vk + 12); + } + } + if (*buf == 0) { + int key = MapKey(vk); + if (key < 0) + continue; + if (sp->_keypad_on) { + *buf = key; + } else { + ungetch('\0'); + *buf = AnsiKey(vk); + } + } + break; + } else if (inp_rec.EventType == MOUSE_EVENT) { + if (handle_mouse(sp, + inp_rec.Event.MouseEvent)) { + *buf = KEY_MOUSE; + break; + } + } + continue; + } + } + returnCode(rc); +} + +/* Our replacement for the systems _isatty to include also + a test for mintty. This is called from the NC_ISATTY macro + defined in curses.priv.h + + Return codes: + - 0 : Not a TTY + - 1 : A Windows character device detected by _isatty + - 2 : A future implementation may return 2 for mintty + */ +NCURSES_EXPORT(int) +_nc_console_isatty(int fd) +{ + int result = 0; + T((T_CALLED("lib_win32con::_nc_console_isatty(%d"), fd)); + + if (_isatty(fd)) + result = 1; +#ifdef _NC_CHECK_MINTTY + else { + if (_nc_console_checkmintty(fd, NULL)) { + result = 2; + fprintf(stderr, "ncurses on Windows must run in a Windows console.\n"); + fprintf(stderr, "On newer versions of Windows, the calling program should create a PTY-like.\n"); + fprintf(stderr, "device using the CreatePseudoConsole Windows API call.\n"); + exit(EXIT_FAILURE); + } + } +#endif + returnCode(result); +} + +NCURSES_EXPORT(bool) +_nc_console_checkinit(bool initFlag, bool assumeTermInfo) +{ + bool res = FALSE; + + T((T_CALLED("lib_win32con::_nc_console_checkinit(initFlag=%d, assumeTermInfo=%d)"), + initFlag, assumeTermInfo)); + + if (!initFlag) { + res = console_initialized; + } else { + /* initialize once, or not at all */ + if (!console_initialized) { + int i; + DWORD num_buttons; + WORD a; + BOOL buffered = FALSE; + BOOL b; + + START_TRACE(); + WINCONSOLE.isTermInfoConsole = assumeTermInfo; + + WINCONSOLE.map = (LPDWORD)malloc(sizeof(DWORD)*MAPSIZE); + WINCONSOLE.rmap = (LPDWORD)malloc(sizeof(DWORD)*MAPSIZE); + WINCONSOLE.ansi_map = (LPDWORD)malloc(sizeof(DWORD)*MAPSIZE); + + for (i = 0; i < (N_INI + FKEYS); i++) { + if (i < N_INI) { + WINCONSOLE.rmap[i] = WINCONSOLE.map[i] = + (DWORD) keylist[i]; + WINCONSOLE.ansi_map[i] = (DWORD) ansi_keys[i]; + } else { + WINCONSOLE.rmap[i] = WINCONSOLE.map[i] = + (DWORD) GenMap((VK_F1 + (i - N_INI)), + (KEY_F(1) + (i - N_INI))); + WINCONSOLE.ansi_map[i] = + (DWORD) GenMap((VK_F1 + (i - N_INI)), + (';' + (i - N_INI))); + } + } + qsort(WINCONSOLE.ansi_map, + (size_t) (MAPSIZE), + sizeof(keylist[0]), + keycompare); + qsort(WINCONSOLE.map, + (size_t) (MAPSIZE), + sizeof(keylist[0]), + keycompare); + qsort(WINCONSOLE.rmap, + (size_t) (MAPSIZE), + sizeof(keylist[0]), + rkeycompare); + + if (GetNumberOfConsoleMouseButtons(&num_buttons)) { + WINCONSOLE.numButtons = (int) num_buttons; + } else { + WINCONSOLE.numButtons = 1; + } + + a = _nc_console_MapColor(true, COLOR_WHITE) | + _nc_console_MapColor(false, COLOR_BLACK); + for (i = 0; i < CON_NUMPAIRS; i++) + WINCONSOLE.pairs[i] = a; + + WINCONSOLE.inp = GetStdHandle(STD_INPUT_HANDLE); + WINCONSOLE.out = GetStdHandle(STD_OUTPUT_HANDLE); + WINCONSOLE.hdl = WINCONSOLE.out; + + GetConsoleMode(WINCONSOLE.inp, &WINCONSOLE.originalMode.dwFlagIn); + GetConsoleMode(WINCONSOLE.out, &WINCONSOLE.originalMode.dwFlagOut); + + if (!WINCONSOLE.isTermInfoConsole) { + b = AllocConsole(); + + if (!b) + b = AttachConsole(ATTACH_PARENT_PROCESS); + + if (getenv("NCGDB") || getenv("NCURSES_CONSOLE2")) { + T(("... will not buffer console")); + } else { + T(("... creating console buffer")); + WINCONSOLE.hdl = + CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, + 0, + NULL, + CONSOLE_TEXTMODE_BUFFER, + NULL); + buffered = TRUE; + } + } + + /* We set binary I/O even when using the console + driver to cover the situation, that the + TERM variable is set to #win32con, but actually + Windows supports virtual terminal processing. + So if terminfo functions are used in this setup, + they actually may work. + */ + _setmode(fileno(stdin), _O_BINARY); + _setmode(fileno(stdout), _O_BINARY); + + if (WINCONSOLE.hdl != INVALID_HANDLE_VALUE) { + WINCONSOLE.buffered = buffered; + _nc_console_get_SBI(); + WINCONSOLE.save_SBI = WINCONSOLE.SBI; + if (!buffered) { + save_original_screen(); + _nc_console_set_scrollback(FALSE, &WINCONSOLE.SBI); + } + GetConsoleCursorInfo(WINCONSOLE.hdl, &WINCONSOLE.save_CI); + T(("... initial cursor is %svisible, %d%%", + (WINCONSOLE.save_CI.bVisible ? "" : "not-"), + (int) WINCONSOLE.save_CI.dwSize)); + } + + WINCONSOLE.initialized = TRUE; + console_initialized = TRUE; + } + res = (WINCONSOLE.hdl != INVALID_HANDLE_VALUE); + } + returnBool(res); +} + +#endif // _NC_WINDOWS diff --git a/ncurses/tinfo/lib_win32util.c b/ncurses/tinfo/lib_win32util.c new file mode 100644 index 000000000000..d5bcd70199ed --- /dev/null +++ b/ncurses/tinfo/lib_win32util.c @@ -0,0 +1,134 @@ +/**************************************************************************** + * Copyright 2020 Thomas E. Dickey * + * Copyright 1998-2009,2010 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 * + * "Software"), to deal in the Software without restriction, including * + * without limitation the rights to use, copy, modify, merge, publish, * + * distribute, distribute with modifications, sublicense, and/or sell * + * copies of the Software, and to permit persons to whom the Software is * + * furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included * + * in all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * + * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + * * + * Except as contained in this notice, the name(s) of the above copyright * + * holders shall not be used in advertising or otherwise to promote the * + * sale, use or other dealings in this Software without prior written * + * authorization. * + ****************************************************************************/ + +/**************************************************************************** + * Author: Juergen Pfeifer * + * and: Thomas E. Dickey * + ****************************************************************************/ + +#include <curses.priv.h> + +MODULE_ID("$Id: lib_win32util.c,v 1.1 2020/08/14 21:57:01 juergen Exp $") + +#ifdef _NC_WINDOWS +#include <io.h> + +#ifdef _NC_CHECK_MINTTY +#define PSAPI_VERSION 2 +#include <psapi.h> +#include <tchar.h> + +#define array_length(a) (sizeof(a)/sizeof(a[0])) + +/* This function tests, whether or not the ncurses application + is running as a descendant of MSYS2/cygwin mintty terminal + application. mintty doesn't use Windows Console for it's screen + I/O, so the native Windows _isatty doesn't recognize it as + character device. But we can discover we are at the end of an + Pipe and can query the server side of the pipe, looking whether + or not this is mintty. + For now we terminate the program if we discover that situation. + Althogh in theory it would be possible, to remotely manipulate + the terminal state of mintty, this is out of scope for now and + not worth the significant effort. + */ +NCURSES_EXPORT(int) +_nc_console_checkmintty(int fd, LPHANDLE pMinTTY) +{ + HANDLE handle = _nc_console_handle(fd); + DWORD dw; + int code = 0; + + T((T_CALLED("lib_winhelper::_nc_console_checkmintty(%d, %p)"), fd, pMinTTY)); + + if (handle != INVALID_HANDLE_VALUE) { + dw = GetFileType(handle); + if (dw == FILE_TYPE_PIPE) { + if (GetNamedPipeInfo(handle, 0, 0, 0, 0)) { + ULONG pPid; + /* Requires NT6 */ + if (GetNamedPipeServerProcessId(handle, &pPid)) { + TCHAR buf[MAX_PATH]; + DWORD len = 0; + /* These security attributes may allow us to + create a remote thread in mintty to manipulate + the terminal state remotely */ + HANDLE pHandle = OpenProcess( + PROCESS_CREATE_THREAD + | PROCESS_QUERY_INFORMATION + | PROCESS_VM_OPERATION + | PROCESS_VM_WRITE + | PROCESS_VM_READ, + FALSE, + pPid); + if (pMinTTY) + *pMinTTY = INVALID_HANDLE_VALUE; + if (pHandle != INVALID_HANDLE_VALUE) { + if ((len = GetProcessImageFileName( + pHandle, + buf, + (DWORD) + array_length(buf)))) { + TCHAR *pos = _tcsrchr(buf, _T('\\')); + if (pos) { + pos++; + if (_tcsnicmp(pos, _TEXT("mintty.exe"), 10) + == 0) { + if (pMinTTY) + *pMinTTY = pHandle; + code = 1; + } + } + } + } + } + } + } + } + returnCode(code); +} +#endif /* _NC_CHECK_MINTTY */ + +#define JAN1970 116444736000000000LL /* the value for 01/01/1970 00:00 */ + +NCURSES_EXPORT(int) +_nc_gettimeofday(struct timeval *tv, void *tz GCC_UNUSED) +{ + union { + FILETIME ft; + long long since1601; /* time since 1 Jan 1601 in 100ns units */ + } data; + + GetSystemTimeAsFileTime(&data.ft); + tv->tv_usec = (long) ((data.since1601 / 10LL) % 1000000LL); + tv->tv_sec = (long) ((data.since1601 - JAN1970) / 10000000LL); + return (0); +} + +#endif // _NC_WINDOWS diff --git a/ncurses/tinfo/parse_entry.c b/ncurses/tinfo/parse_entry.c index 23574b6626bf..ec2d3364234e 100644 --- a/ncurses/tinfo/parse_entry.c +++ b/ncurses/tinfo/parse_entry.c @@ -48,7 +48,7 @@ #include <ctype.h> #include <tic.h> -MODULE_ID("$Id: parse_entry.c,v 1.99 2020/02/02 23:34:34 tom Exp $") +MODULE_ID("$Id: parse_entry.c,v 1.101 2020/10/24 21:37:13 tom Exp $") #ifdef LINT static short const parametrized[] = @@ -544,10 +544,14 @@ _nc_parse_entry(ENTRY * entryp, int literal, bool silent) case STRING: ptr = _nc_curr_token.tk_valstring; - if (_nc_syntax == SYN_TERMCAP) + if (_nc_syntax == SYN_TERMCAP) { + int n = entry_ptr->nte_index; ptr = _nc_captoinfo(_nc_curr_token.tk_name, ptr, - parametrized[entry_ptr->nte_index]); + (n < (int) SIZEOF(parametrized)) + ? parametrized[n] + : 0); + } entryp->tterm.Strings[entry_ptr->nte_index] = _nc_save_str(ptr); break; diff --git a/ncurses/tinfo/read_entry.c b/ncurses/tinfo/read_entry.c index 5b570b0fe192..9741e103b7a9 100644 --- a/ncurses/tinfo/read_entry.c +++ b/ncurses/tinfo/read_entry.c @@ -1,5 +1,5 @@ /**************************************************************************** - * Copyright 2018-2019,2020 Thomas E. Dickey * + * Copyright 2018-2020,2021 Thomas E. Dickey * * Copyright 1998-2016,2017 Free Software Foundation, Inc. * * * * Permission is hereby granted, free of charge, to any person obtaining a * @@ -42,7 +42,7 @@ #include <tic.h> -MODULE_ID("$Id: read_entry.c,v 1.157 2020/02/02 23:34:34 tom Exp $") +MODULE_ID("$Id: read_entry.c,v 1.159 2021/02/14 00:17:09 tom Exp $") #define TYPE_CALLOC(type,elts) typeCalloc(type, (unsigned)(elts)) @@ -160,11 +160,11 @@ convert_strings(char *buf, char **Strings, int count, int size, char *table) /* make sure all strings are NUL terminated */ if (VALID_STRING(Strings[i])) { - for (p = Strings[i]; p <= table + size; p++) + for (p = Strings[i]; p < table + size; p++) if (*p == '\0') break; /* if there is no NUL, ignore the string */ - if (p > table + size) + if (p >= table + size) Strings[i] = ABSENT_STRING; } } @@ -257,7 +257,6 @@ _nc_read_termtype(TERMTYPE2 *ptr, char *buffer, int limit) char buf[MAX_ENTRY_SIZE + 2]; char *string_table; unsigned want, have; - bool need_ints; size_t (*convert_numbers) (char *, NCURSES_INT2 *, int); int size_of_numbers; int max_entry_size = MAX_ENTRY_SIZE; @@ -276,7 +275,7 @@ _nc_read_termtype(TERMTYPE2 *ptr, char *buffer, int limit) returnDB(TGETENT_NO); } #if NCURSES_EXT_NUMBERS - if ((need_ints = (LOW_MSB(buf) == MAGIC2))) { + if (LOW_MSB(buf) == MAGIC2) { convert_numbers = convert_32bits; size_of_numbers = SIZEOF_INT2; } else { @@ -285,7 +284,7 @@ _nc_read_termtype(TERMTYPE2 *ptr, char *buffer, int limit) size_of_numbers = SIZEOF_SHORT; } #else - if ((need_ints = (LOW_MSB(buf) == MAGIC2))) { + if (LOW_MSB(buf) == MAGIC2) { convert_numbers = convert_32bits; size_of_numbers = SIZEOF_32BITS; } else { @@ -666,11 +665,10 @@ decode_hex(const char **source) { int result = 0; int nibble; - int ch; for (nibble = 0; nibble < 2; ++nibble) { + int ch = UChar(**source); result <<= 4; - ch = UChar(**source); *source += 1; if (ch >= '0' && ch <= '9') { ch -= '0'; diff --git a/ncurses/tinfo/tinfo_driver.c b/ncurses/tinfo/tinfo_driver.c index 7919a9b09276..c28d76415549 100644 --- a/ncurses/tinfo/tinfo_driver.c +++ b/ncurses/tinfo/tinfo_driver.c @@ -52,7 +52,7 @@ # endif #endif -MODULE_ID("$Id: tinfo_driver.c,v 1.67 2020/02/02 23:34:34 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, @@ -123,6 +123,8 @@ get_baudrate(TERMINAL *termp) 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 @@ -133,6 +135,9 @@ get_baudrate(TERMINAL *termp) #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 @@ -356,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); } } } @@ -427,12 +432,19 @@ drv_size(TERMINAL_CONTROL_BLOCK * TCB, int *linep, int *colp) 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; @@ -602,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 @@ -627,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; @@ -764,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)); } } @@ -800,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)); } } @@ -826,7 +842,7 @@ 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) { _nc_pair_content(SP_PARM, pair, &fg, &bg); @@ -933,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) @@ -1235,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); @@ -1254,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 +#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; } @@ -1275,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 @@ -1452,3 +1494,66 @@ NCURSES_EXPORT_VAR (TERM_DRIVER) _nc_TINFO_DRIVER = { 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 */ diff --git a/ncurses/tinfo/trim_sgr0.c b/ncurses/tinfo/trim_sgr0.c index 4d10529c029f..30c8f75c1e8a 100644 --- a/ncurses/tinfo/trim_sgr0.c +++ b/ncurses/tinfo/trim_sgr0.c @@ -37,7 +37,7 @@ #include <tic.h> -MODULE_ID("$Id: trim_sgr0.c,v 1.18 2020/02/02 23:34:34 tom Exp $") +MODULE_ID("$Id: trim_sgr0.c,v 1.20 2020/05/27 23:54:31 tom Exp $") #undef CUR #define CUR tp-> @@ -52,7 +52,7 @@ set_attribute_9(TERMTYPE2 *tp, int flag) const char *value; char *result; - value = tparm(set_attributes, 0, 0, 0, 0, 0, 0, 0, 0, flag); + value = TIPARM_9(set_attributes, 0, 0, 0, 0, 0, 0, 0, 0, flag); if (PRESENT(value)) result = strdup(value); else diff --git a/ncurses/tinfo/write_entry.c b/ncurses/tinfo/write_entry.c index 138517651e12..5bb7aee7f360 100644 --- a/ncurses/tinfo/write_entry.c +++ b/ncurses/tinfo/write_entry.c @@ -51,7 +51,7 @@ #define TRACE_NUM(n) /* nothing */ #endif -MODULE_ID("$Id: write_entry.c,v 1.115 2020/02/02 23:34:34 tom Exp $") +MODULE_ID("$Id: write_entry.c,v 1.116 2020/08/29 16:22:03 juergen Exp $") static int total_written; static int total_parts; @@ -192,7 +192,7 @@ make_db_root(const char *path) if ((rc = stat(path, &statbuf)) < 0) { rc = mkdir(path -#if !defined(_WIN32) +#ifndef _NC_WINDOWS ,0777 #endif ); |