libncurses: Import https://ftp.gnu.org/pub/gnu/ncurses/ncurses-6.5.tar.gz changes
Change-Id: I3433d30ca01359fd2e3623ede96b531f0b39cbfa
Signed-off-by: micky387 <mickaelsaibi@free.fr>
diff --git a/ncurses/tinfo/MKcaptab.awk b/ncurses/tinfo/MKcaptab.awk
index 56d3d17..ee4e2e9 100644
--- a/ncurses/tinfo/MKcaptab.awk
+++ b/ncurses/tinfo/MKcaptab.awk
@@ -1,5 +1,6 @@
##############################################################################
-# Copyright (c) 1998-2006,2007 Free Software Foundation, Inc. #
+# Copyright 2020 Thomas E. Dickey #
+# Copyright 1998-2006,2007 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"), #
@@ -25,7 +26,7 @@
# use or other dealings in this Software without prior written #
# authorization. #
##############################################################################
-# $Id: MKcaptab.awk,v 1.20 2007/08/12 00:26:15 tom Exp $
+# $Id: MKcaptab.awk,v 1.21 2020/02/02 23:34:34 tom Exp $
function add_string(text) {
if (text != "IGNORE") {
offsets[num_strings] = offset;
diff --git a/ncurses/tinfo/MKcaptab.sh b/ncurses/tinfo/MKcaptab.sh
index 20c94a6..5f41350 100755
--- a/ncurses/tinfo/MKcaptab.sh
+++ b/ncurses/tinfo/MKcaptab.sh
@@ -1,6 +1,7 @@
#!/bin/sh
##############################################################################
-# Copyright (c) 2007-2010,2011 Free Software Foundation, Inc. #
+# Copyright 2019-2020,2023 Thomas E. Dickey #
+# Copyright 2007-2010,2011 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"), #
@@ -26,11 +27,28 @@
# use or other dealings in this Software without prior written #
# authorization. #
##############################################################################
-# $Id: MKcaptab.sh,v 1.14 2011/10/22 16:34:50 tom Exp $
-AWK=${1-awk}
-OPT1=${2-0}
-OPT2=${3-tinfo/MKcaptab.awk}
-DATA=${4-../include/Caps}
+# $Id: MKcaptab.sh,v 1.20 2023/04/22 15:12:57 tom Exp $
+
+if test $# != 0
+then
+ AWK="$1"; shift 1
+else
+ AWK=awk
+fi
+
+if test $# != 0
+then
+ OPT1="$1"; shift 1
+else
+ OPT1="-0"
+fi
+
+if test $# != 0
+then
+ OPT2="$1"; shift 1
+else
+ OPT2="tinfo/MKcaptab.awk"
+fi
cat <<EOF
/*
@@ -50,16 +68,18 @@
#include <tic.h>
#include <hashsize.h>
+/* *INDENT-OFF* */
EOF
-./make_hash 1 info $OPT1 <$DATA
-./make_hash 3 cap $OPT1 <$DATA
+cat "$@" |./make_hash 1 info $OPT1
+cat "$@" |./make_hash 3 cap $OPT1
-$AWK -f $OPT2 bigstrings=$OPT1 tablename=capalias <$DATA
+cat "$@" |$AWK -f $OPT2 bigstrings=$OPT1 tablename=capalias
-$AWK -f $OPT2 bigstrings=$OPT1 tablename=infoalias <$DATA
+cat "$@" |$AWK -f $OPT2 bigstrings=$OPT1 tablename=infoalias
cat <<EOF
+/* *INDENT-ON* */
#if $OPT1
static void
@@ -70,7 +90,7 @@
static const struct name_table_entry *
_nc_build_names(struct name_table_entry **actual,
- const name_table_data *source,
+ const name_table_data * source,
const char *strings)
{
if (*actual == 0) {
@@ -97,7 +117,7 @@
static const struct alias *
_nc_build_alias(struct alias **actual,
- const alias_table_data *source,
+ const alias_table_data * source,
const char *strings,
size_t tablesize)
{
@@ -127,20 +147,22 @@
#define build_alias(root) _nc_ ## root ## alias_table
#endif
-NCURSES_EXPORT(const struct name_table_entry *) _nc_get_table (bool termcap)
+NCURSES_EXPORT(const struct name_table_entry *)
+_nc_get_table(bool termcap)
{
- return termcap ? build_names(cap) : build_names(info) ;
+ return termcap ? build_names(cap) : build_names(info);
}
-/* entrypoint used by tack (do not alter) */
-NCURSES_EXPORT(const HashValue *) _nc_get_hash_table (bool termcap)
+NCURSES_EXPORT(const HashValue *)
+_nc_get_hash_table(bool termcap)
{
- return termcap ? _nc_cap_hash_table: _nc_info_hash_table ;
+ return termcap ? _nc_cap_hash_table : _nc_info_hash_table;
}
-NCURSES_EXPORT(const struct alias *) _nc_get_alias_table (bool termcap)
+NCURSES_EXPORT(const struct alias *)
+_nc_get_alias_table(bool termcap)
{
- return termcap ? build_alias(cap) : build_alias(info) ;
+ return termcap ? build_alias(cap) : build_alias(info);
}
static HashValue
@@ -150,7 +172,7 @@
DEBUG(9, ("hashing %s", string));
while (*string) {
- sum += (long) (*string + (*(string + 1) << 8));
+ sum += (long) (UChar(*string) + (UChar(*(string + 1)) << 8));
string++;
}
@@ -187,18 +209,21 @@
return !strcmp(a, b);
}
-static const HashData hash_data[2] = {
- { HASHTABSIZE, _nc_info_hash_table, info_hash, compare_info_names },
- { HASHTABSIZE, _nc_cap_hash_table, tcap_hash, compare_tcap_names }
+static const HashData hash_data[2] =
+{
+ {HASHTABSIZE, _nc_info_hash_table, info_hash, compare_info_names},
+ {HASHTABSIZE, _nc_cap_hash_table, tcap_hash, compare_tcap_names}
};
-NCURSES_EXPORT(const HashData *) _nc_get_hash_info (bool termcap)
+NCURSES_EXPORT(const HashData *)
+_nc_get_hash_info(bool termcap)
{
return &hash_data[(termcap != FALSE)];
}
#if NO_LEAKS
-NCURSES_EXPORT(void) _nc_comp_captab_leaks(void)
+NCURSES_EXPORT(void)
+_nc_comp_captab_leaks(void)
{
#if $OPT1
FreeIfNeeded(_nc_cap_table);
diff --git a/ncurses/tinfo/MKcodes.awk b/ncurses/tinfo/MKcodes.awk
index 97e5131..48f4800 100644
--- a/ncurses/tinfo/MKcodes.awk
+++ b/ncurses/tinfo/MKcodes.awk
@@ -1,5 +1,6 @@
##############################################################################
-# Copyright (c) 1998-2009,2010 Free Software Foundation, Inc. #
+# Copyright 2019,2020 Thomas E. Dickey #
+# Copyright 2007-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"), #
@@ -25,7 +26,7 @@
# use or other dealings in this Software without prior written #
# authorization. #
##############################################################################
-# $Id: MKcodes.awk,v 1.9 2010/01/23 17:57:43 tom Exp $
+# $Id: MKcodes.awk,v 1.11 2020/02/02 23:34:34 tom Exp $
function large_item(value) {
result = sprintf("%d,", offset);
offset = offset + length(value) + 1;
@@ -79,7 +80,9 @@
}
$1 ~ /^#/ {next;}
+$1 ~ /^(cap|info)alias/ {next;}
+$1 == "userdef" {next;}
$1 == "SKIPWARN" {next;}
$3 == "bool" {
diff --git a/ncurses/tinfo/MKfallback.sh b/ncurses/tinfo/MKfallback.sh
index 11f1d2e..02b36ed 100755
--- a/ncurses/tinfo/MKfallback.sh
+++ b/ncurses/tinfo/MKfallback.sh
@@ -1,6 +1,7 @@
#!/bin/sh
##############################################################################
-# Copyright (c) 1998-2009,2010 Free Software Foundation, Inc. #
+# Copyright 2020,2023 Thomas E. Dickey #
+# Copyright 1998-2019,2020 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"), #
@@ -26,7 +27,7 @@
# use or other dealings in this Software without prior written #
# authorization. #
##############################################################################
-# $Id: MKfallback.sh,v 1.15 2010/08/07 20:32:34 tom Exp $
+# $Id: MKfallback.sh,v 1.26 2023/04/22 15:12:57 tom Exp $
#
# MKfallback.sh -- create fallback table for entry reads
#
@@ -43,9 +44,14 @@
shift
tic_path=$1
+test -z "$tic_path" && tic_path=tic
shift
-case $tic_path in #(vi
+infocmp_path=$1
+test -z "$infocmp_path" && infocmp_path=infocmp
+shift
+
+case "$tic_path" in #(vi
/*)
tic_head=`echo "$tic_path" | sed -e 's,/[^/]*$,,'`
PATH=$tic_head:$PATH
@@ -63,14 +69,16 @@
TERMINFO_DIRS=$TERMINFO:$terminfo_dir
export TERMINFO_DIRS
- $tic_path -x $terminfo_src >&2
+ "$tic_path" -x "$terminfo_src" >&2
else
tmp_info=
fi
cat <<EOF
+/* This file was generated by $0 */
+
/*
- * DO NOT EDIT THIS FILE BY HAND! It is generated by MKfallback.sh.
+ * DO NOT EDIT THIS FILE BY HAND!
*/
#include <curses.priv.h>
@@ -84,21 +92,21 @@
/* fallback entries for: $* */
EOF
- for x in $*
+ for x in "$@"
do
echo "/* $x */"
- infocmp -E $x
+ "$infocmp_path" -E "$x" | sed -e 's/\<short\>/NCURSES_INT2/g'
done
cat <<EOF
-static const TERMTYPE fallbacks[$#] =
+static const TERMTYPE2 fallbacks[$#] =
{
EOF
comma=""
- for x in $*
+ for x in "$@"
do
echo "$comma /* $x */"
- infocmp -e $x
+ "$infocmp_path" -e "$x"
comma=","
done
@@ -109,28 +117,48 @@
fi
cat <<EOF
-NCURSES_EXPORT(const TERMTYPE *) _nc_fallback (const char *name GCC_UNUSED)
+NCURSES_EXPORT(const TERMTYPE2 *)
+_nc_fallback2 (const char *name GCC_UNUSED)
{
EOF
if [ "$*" ]
then
cat <<EOF
- const TERMTYPE *tp;
+ const TERMTYPE2 *tp;
for (tp = fallbacks;
- tp < fallbacks + sizeof(fallbacks)/sizeof(TERMTYPE);
- tp++)
- if (_nc_name_match(tp->term_names, name, "|"))
+ tp < fallbacks + sizeof(fallbacks)/sizeof(TERMTYPE2);
+ tp++) {
+ if (_nc_name_match(tp->term_names, name, "|")) {
return(tp);
+ }
+ }
EOF
else
echo " /* the fallback list is empty */";
fi
cat <<EOF
- return((TERMTYPE *)0);
+ return((const TERMTYPE2 *)0);
}
+
+#if NCURSES_EXT_NUMBERS
+#undef _nc_fallback
+
+NCURSES_EXPORT(const TERMTYPE *)
+_nc_fallback (const char *name)
+{
+ const TERMTYPE2 *tp = _nc_fallback2(name);
+ const TERMTYPE *result = 0;
+ if (tp != 0) {
+ static TERMTYPE temp;
+ _nc_export_termtype2(&temp, tp);
+ result = &temp;
+ }
+ return result;
+}
+#endif
EOF
if test -n "$tmp_info" ; then
diff --git a/ncurses/tinfo/MKkeys_list.sh b/ncurses/tinfo/MKkeys_list.sh
index 14017b0..05ac8cf 100755
--- a/ncurses/tinfo/MKkeys_list.sh
+++ b/ncurses/tinfo/MKkeys_list.sh
@@ -1,7 +1,8 @@
#! /bin/sh
-# $Id: MKkeys_list.sh,v 1.4 2003/10/25 16:19:54 tom Exp $
+# $Id: MKkeys_list.sh,v 1.9 2024/01/19 12:26:30 tom Exp $
##############################################################################
-# Copyright (c) 2001,2003 Free Software Foundation, Inc. #
+# Copyright 2019-2022,2024 Thomas E. Dickey #
+# Copyright 2001-2003,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 "Software"), #
@@ -35,24 +36,32 @@
# Extract function-key names from the Caps file
#
: ${AWK-awk}
-DATA=${1-../../include/Caps}
+: ${USE_SIGWINCH-0}
+if test $# != 0
+then
+ DATA="$*"
+else
+ DATA=../../include/Caps
+fi
data=data$$
-trap 'rm -f $data' 0 1 2 5 15
-sed -e 's/[ ][ ]*/ /g' < $DATA >$data
+trap 'rm -f $data; exit 1' 1 2 3 15
+trap 'rm -f $data' 0
+cat $DATA | sed -e 's/[ ][ ]*/ /g' >$data
cat <<EOF
# These definitions were generated by $0 $DATA
KEY_BREAK
KEY_SRESET
KEY_RESET
-KEY_RESIZE
EOF
+test "$USE_SIGWINCH" = 1 && echo KEY_RESIZE
${AWK-awk} <$data '
/^#/ {next;}
/^capalias/ {next;}
/^infoalias/ {next;}
+/^userdef/ {next;}
$5 != "-" {
if (substr($5, 1, 4) == "KEY_" ) {
diff --git a/ncurses/tinfo/MKnames.awk b/ncurses/tinfo/MKnames.awk
index 7685d18..4594c72 100644
--- a/ncurses/tinfo/MKnames.awk
+++ b/ncurses/tinfo/MKnames.awk
@@ -1,5 +1,6 @@
##############################################################################
-# Copyright (c) 2007-2008,2009 Free Software Foundation, Inc. #
+# Copyright 2019,2020 Thomas E. Dickey #
+# Copyright 1998-2008,2009 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"), #
@@ -25,7 +26,7 @@
# use or other dealings in this Software without prior written #
# authorization. #
##############################################################################
-# $Id: MKnames.awk,v 1.22 2009/03/21 21:03:39 tom Exp $
+# $Id: MKnames.awk,v 1.24 2020/02/02 23:34:34 tom Exp $
function large_item(value) {
result = sprintf("%d,", offset);
offset = offset + length(value) + 1;
@@ -79,7 +80,9 @@
}
$1 ~ /^#/ {next;}
+$1 ~ /^(cap|info)alias/ {next;}
+$1 == "userdef" {next;}
$1 == "SKIPWARN" {next;}
$3 == "bool" {
diff --git a/ncurses/tinfo/MKuserdefs.sh b/ncurses/tinfo/MKuserdefs.sh
new file mode 100755
index 0000000..109dd64
--- /dev/null
+++ b/ncurses/tinfo/MKuserdefs.sh
@@ -0,0 +1,146 @@
+#!/bin/sh
+##############################################################################
+# Copyright 2019,2020 Thomas E. Dickey #
+# #
+# 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. #
+##############################################################################
+# $Id: MKuserdefs.sh,v 1.10 2020/02/02 23:34:34 tom Exp $
+AWK=${1-awk}; shift 1
+OPT1=${1-0}; shift 1
+
+cat <<EOF
+/*
+ * generated by $0
+ */
+
+EOF
+
+cat <<'EOF'
+/*
+ * comp_userdefs.c -- The names of widely used user-defined capabilities
+ * indexed via a hash table for the compiler.
+ *
+ */
+
+#include <curses.priv.h>
+#include <tic.h>
+#include <hashsize.h>
+
+#if NCURSES_XNAMES
+EOF
+
+cat "$@" | ./make_hash 1 user $OPT1
+
+cat <<EOF
+
+#define USERTABSIZE SIZEOF(user_names_data)
+
+#if $OPT1
+static void
+next_string(const char *strings, unsigned *offset)
+{
+ *offset += (unsigned) strlen(strings + *offset) + 1;
+}
+
+static const struct user_table_entry *
+_nc_build_names(struct user_table_entry **actual,
+ const user_table_data *source,
+ const char *strings)
+{
+ if (*actual == 0) {
+ *actual = typeCalloc(struct user_table_entry, USERTABSIZE);
+ if (*actual != 0) {
+ unsigned n;
+ unsigned len = 0;
+ for (n = 0; n < USERTABSIZE; ++n) {
+ (*actual)[n].ute_name = strings + len;
+ (*actual)[n].ute_type = (int) source[n].ute_type;
+ (*actual)[n].ute_argc = source[n].ute_argc;
+ (*actual)[n].ute_args = source[n].ute_args;
+ (*actual)[n].ute_index = source[n].ute_index;
+ (*actual)[n].ute_link = source[n].ute_link;
+ next_string(strings, &len);
+ }
+ }
+ }
+ return *actual;
+}
+
+#define build_names(root) _nc_build_names(&_nc_##root##_table, \\
+ root##_names_data, \\
+ root##_names_text)
+#else
+#define build_names(root) _nc_ ## root ## _table
+#endif
+
+NCURSES_EXPORT(const struct user_table_entry *) _nc_get_userdefs_table (void)
+{
+ return build_names(user) ;
+}
+
+static HashValue
+info_hash(const char *string)
+{
+ long sum = 0;
+
+ DEBUG(9, ("hashing %s", string));
+ while (*string) {
+ sum += (long) (*string + (*(string + 1) << 8));
+ string++;
+ }
+
+ DEBUG(9, ("sum is %ld", sum));
+ return (HashValue) (sum % HASHTABSIZE);
+}
+
+static int
+compare_info_names(const char *a, const char *b)
+{
+ return !strcmp(a, b);
+}
+
+static const HashData hash_data[] = {
+ { HASHTABSIZE, _nc_user_hash_table, info_hash, compare_info_names }
+};
+
+NCURSES_EXPORT(const HashData *) _nc_get_hash_user (void)
+{
+ return hash_data;
+}
+
+#if NO_LEAKS
+NCURSES_EXPORT(void) _nc_comp_userdefs_leaks(void)
+{
+#if $OPT1
+ FreeIfNeeded(_nc_user_table);
+#endif
+}
+#endif /* NO_LEAKS */
+
+#else /*! NCURSES_XNAMES */
+NCURSES_EXPORT(void) _nc_comp_userdefs(void);
+NCURSES_EXPORT(void) _nc_comp_userdefs(void) { }
+#endif /* NCURSES_XNAMES */
+EOF
diff --git a/ncurses/tinfo/README b/ncurses/tinfo/README
index 14c4220..6157ba1 100644
--- a/ncurses/tinfo/README
+++ b/ncurses/tinfo/README
@@ -1,5 +1,6 @@
-------------------------------------------------------------------------------
--- Copyright (c) 1998,2006 Free Software Foundation, Inc. --
+-- Copyright 2020 Thomas E. Dickey --
+-- Copyright 1998,2006 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 --
@@ -25,7 +26,7 @@
-- sale, use or other dealings in this Software without prior written --
-- authorization. --
-------------------------------------------------------------------------------
--- $Id: README,v 1.2 2006/04/22 22:19:37 tom Exp $
+-- $Id: README,v 1.3 2020/02/02 23:34:34 tom Exp $
-------------------------------------------------------------------------------
The files in this directory (tinfo) are those that support the terminfo
diff --git a/ncurses/tinfo/access.c b/ncurses/tinfo/access.c
index d987687..50a5769 100644
--- a/ncurses/tinfo/access.c
+++ b/ncurses/tinfo/access.c
@@ -1,5 +1,6 @@
/****************************************************************************
- * Copyright (c) 1998-2011,2012 Free Software Foundation, Inc. *
+ * Copyright 2019-2021,2023 Thomas E. Dickey *
+ * Copyright 1998-2011,2012 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 *
@@ -34,20 +35,33 @@
#include <ctype.h>
+#ifndef USE_ROOT_ACCESS
+#if HAVE_SETFSUID
+#include <sys/fsuid.h>
+#else
+#include <sys/stat.h>
+#endif
+#endif
+
+#if HAVE_GETAUXVAL && HAVE_SYS_AUXV_H && defined(__GLIBC__) && (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 19)
+#include <sys/auxv.h>
+#define USE_GETAUXVAL 1
+#else
+#define USE_GETAUXVAL 0
+#endif
+
#include <tic.h>
-MODULE_ID("$Id: access.c,v 1.23 2012/09/01 19:21:29 tom Exp $")
-
-#ifdef __TANDEM
-#define ROOT_UID 65535
-#endif
-
-#ifndef ROOT_UID
-#define ROOT_UID 0
-#endif
+MODULE_ID("$Id: access.c,v 1.37 2023/06/24 21:55:09 tom 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)
{
@@ -56,8 +70,8 @@
static char *temp;
char *s;
- temp = strdup(result);
- result = temp;
+ if ((temp = strdup(result)) != 0)
+ result = temp;
#if !MIXEDCASE_FILENAMES
for (s = result; *s != '\0'; ++s) {
*s = (char) LOWERCASE(*s);
@@ -119,7 +133,7 @@
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) {
@@ -134,7 +148,7 @@
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;
}
@@ -170,23 +184,101 @@
return result;
}
-#ifndef USE_ROOT_ENVIRON
+#if HAVE_GETEUID && HAVE_GETEGID
+#define is_posix_elevated() \
+ (getuid() != geteuid() \
+ || getgid() != getegid())
+#else
+#define is_posix_elevated() FALSE
+#endif
+
+#if HAVE_ISSETUGID
+#define is_elevated() issetugid()
+#elif USE_GETAUXVAL && defined(AT_SECURE)
+#define is_elevated() \
+ (getauxval(AT_SECURE) \
+ ? TRUE \
+ : (errno != ENOENT \
+ ? FALSE \
+ : is_posix_elevated()))
+#else
+#define is_elevated() is_posix_elevated()
+#endif
+
+#if HAVE_SETFSUID
+#define lower_privileges() \
+ int save_err = errno; \
+ setfsuid(getuid()); \
+ setfsgid(getgid()); \
+ errno = save_err
+#define resume_elevation() \
+ save_err = errno; \
+ setfsuid(geteuid()); \
+ setfsgid(getegid()); \
+ errno = save_err
+#else
+#define lower_privileges() /* nothing */
+#define resume_elevation() /* nothing */
+#endif
+
/*
- * Returns true if we allow application to use environment variables that are
- * used for searching lists of directories, etc.
+ * Returns true if not running as root or setuid. We use this check to allow
+ * applications to use environment variables that are used for searching lists
+ * of directories, etc.
*/
NCURSES_EXPORT(int)
_nc_env_access(void)
{
-#if HAVE_ISSETUGID
- if (issetugid())
- return FALSE;
-#elif HAVE_GETEUID && HAVE_GETEGID
- if (getuid() != geteuid()
- || getgid() != getegid())
- return FALSE;
+ int result = TRUE;
+
+#if HAVE_GETUID && HAVE_GETEUID
+#if !defined(USE_SETUID_ENVIRON)
+ if (is_elevated()) {
+ result = FALSE;
+ }
#endif
- /* ...finally, disallow root */
- return (getuid() != ROOT_UID) && (geteuid() != ROOT_UID);
+#if !defined(USE_ROOT_ENVIRON)
+ if ((getuid() == ROOT_UID) || (geteuid() == ROOT_UID)) {
+ result = FALSE;
+ }
+#endif
+#endif /* HAVE_GETUID && HAVE_GETEUID */
+ return result;
}
+
+#ifndef USE_ROOT_ACCESS
+/*
+ * Limit privileges if possible; otherwise disallow access for updating files.
+ */
+NCURSES_EXPORT(FILE *)
+_nc_safe_fopen(const char *path, const char *mode)
+{
+ FILE *result = NULL;
+#if HAVE_SETFSUID
+ lower_privileges();
+ result = fopen(path, mode);
+ resume_elevation();
+#else
+ if (!is_elevated() || *mode == 'r') {
+ result = fopen(path, mode);
+ }
#endif
+ return result;
+}
+
+NCURSES_EXPORT(int)
+_nc_safe_open3(const char *path, int flags, mode_t mode)
+{
+ int result = -1;
+#if HAVE_SETFSUID
+ lower_privileges();
+ result = open(path, flags, mode);
+ resume_elevation();
+#else
+ if (!is_elevated() || (flags & O_RDONLY)) {
+ result = open(path, flags, mode);
+ }
+#endif
+ return result;
+}
+#endif /* USE_ROOT_ACCESS */
diff --git a/ncurses/tinfo/add_tries.c b/ncurses/tinfo/add_tries.c
index 29a1a60..9d21557 100644
--- a/ncurses/tinfo/add_tries.c
+++ b/ncurses/tinfo/add_tries.c
@@ -1,5 +1,6 @@
/****************************************************************************
- * Copyright (c) 1998-2009,2010 Free Software Foundation, Inc. *
+ * Copyright 2019-2020,2023 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 *
@@ -38,8 +39,9 @@
*/
#include <curses.priv.h>
+#include <tic.h>
-MODULE_ID("$Id: add_tries.c,v 1.10 2010/12/19 01:31:14 tom Exp $")
+MODULE_ID("$Id: add_tries.c,v 1.13 2023/06/24 15:36:13 tom Exp $")
#define SET_TRY(dst,src) if ((dst->ch = *src++) == 128) dst->ch = '\0'
#define CMP_TRY(a,b) ((a)? (a == b) : (b == 128))
@@ -52,7 +54,7 @@
T((T_CALLED("_nc_add_to_try(%p, %s, %u)"),
(void *) *tree, _nc_visbuf(str), code));
- if (txt == 0 || *txt == '\0' || code == 0)
+ if (!VALID_STRING(str) || *txt == '\0' || code == 0)
returnCode(ERR);
if ((*tree) != 0) {
@@ -109,6 +111,7 @@
savedptr = ptr->child;
free(ptr);
}
+ *tree = NULL;
returnCode(ERR);
}
diff --git a/ncurses/tinfo/alloc_entry.c b/ncurses/tinfo/alloc_entry.c
index 14ea391..6280ad4 100644
--- a/ncurses/tinfo/alloc_entry.c
+++ b/ncurses/tinfo/alloc_entry.c
@@ -1,5 +1,6 @@
/****************************************************************************
- * Copyright (c) 1998-2012,2013 Free Software Foundation, Inc. *
+ * Copyright 2018-2022,2023 Thomas E. Dickey *
+ * Copyright 1998-2013,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 *
@@ -47,73 +48,89 @@
#include <tic.h>
-MODULE_ID("$Id: alloc_entry.c,v 1.58 2013/08/17 19:20:38 tom Exp $")
+MODULE_ID("$Id: alloc_entry.c,v 1.79 2023/09/15 08:16:12 tom Exp $")
#define ABSENT_OFFSET -1
#define CANCELLED_OFFSET -2
-#define MAX_STRTAB 4096 /* documented maximum entry size */
-
static char *stringbuf; /* buffer for string capabilities */
static size_t next_free; /* next free character in stringbuf */
NCURSES_EXPORT(void)
-_nc_init_entry(TERMTYPE *const tp)
+_nc_init_entry(ENTRY * const tp)
/* initialize a terminal type data block */
{
+ DEBUG(2, (T_CALLED("_nc_init_entry(tp=%p)"), (void *) tp));
+
+ if (tp == NULL) {
#if NO_LEAKS
- if (tp == 0) {
- if (stringbuf != 0) {
+ if (stringbuf != NULL) {
FreeAndNull(stringbuf);
}
return;
- }
+#else
+ _nc_err_abort("_nc_init_entry called without initialization");
#endif
+ }
- if (stringbuf == 0)
- TYPE_MALLOC(char, (size_t) MAX_STRTAB, stringbuf);
+ if (stringbuf == NULL)
+ TYPE_CALLOC(char, (size_t) MAX_ENTRY_SIZE, stringbuf);
next_free = 0;
- _nc_init_termtype(tp);
+ _nc_init_termtype(&(tp->tterm));
+
+ DEBUG(2, (T_RETURN("")));
}
NCURSES_EXPORT(ENTRY *)
_nc_copy_entry(ENTRY * oldp)
{
- ENTRY *newp = typeCalloc(ENTRY, 1);
+ ENTRY *newp;
- if (newp != 0) {
+ DEBUG(2, (T_CALLED("_nc_copy_entry(oldp=%p)"), (void *) oldp));
+
+ newp = typeCalloc(ENTRY, 1);
+ if (newp != NULL) {
*newp = *oldp;
- _nc_copy_termtype(&(newp->tterm), &(oldp->tterm));
+ _nc_copy_termtype2(&(newp->tterm), &(oldp->tterm));
}
- return newp;
+
+ DEBUG(2, (T_RETURN("%p"), (void *) newp));
+ return (newp);
}
/* save a copy of string in the string buffer */
NCURSES_EXPORT(char *)
-_nc_save_str(const char *const string)
+_nc_save_str(const char *string)
{
char *result = 0;
size_t old_next_free = next_free;
- size_t len = strlen(string) + 1;
- if (len == 1 && next_free != 0) {
- /*
- * Cheat a little by making an empty string point to the end of the
- * previous string.
- */
- if (next_free < MAX_STRTAB) {
- result = (stringbuf + next_free - 1);
+ if (stringbuf != NULL) {
+ size_t len;
+
+ if (!VALID_STRING(string))
+ string = "";
+ len = strlen(string) + 1;
+
+ if (len == 1 && next_free != 0) {
+ /*
+ * Cheat a little by making an empty string point to the end of the
+ * previous string.
+ */
+ if (next_free < MAX_ENTRY_SIZE) {
+ result = (stringbuf + next_free - 1);
+ }
+ } else if (next_free + len < MAX_ENTRY_SIZE) {
+ _nc_STRCPY(&stringbuf[next_free], string, MAX_ENTRY_SIZE);
+ DEBUG(7, ("Saved string %s", _nc_visbuf(string)));
+ DEBUG(7, ("at location %d", (int) next_free));
+ next_free += len;
+ result = (stringbuf + old_next_free);
+ } else {
+ _nc_warning("Too much data, some is lost: %s", string);
}
- } else if (next_free + len < MAX_STRTAB) {
- _nc_STRCPY(&stringbuf[next_free], string, MAX_STRTAB);
- DEBUG(7, ("Saved string %s", _nc_visbuf(string)));
- DEBUG(7, ("at location %d", (int) next_free));
- next_free += len;
- result = (stringbuf + old_next_free);
- } else {
- _nc_warning("Too much data, some is lost: %s", string);
}
return result;
}
@@ -125,17 +142,23 @@
int offsets[MAX_ENTRY_SIZE / sizeof(short)];
int useoffsets[MAX_USES];
unsigned i, n;
- unsigned nuses = ep->nuses;
- TERMTYPE *tp = &(ep->tterm);
+ unsigned nuses;
+ TERMTYPE2 *tp;
+ DEBUG(2, (T_CALLED("_nc_wrap_entry(ep=%p, copy_strings=%d)"), (void *)
+ ep, copy_strings));
+ if (ep == NULL || stringbuf == NULL)
+ _nc_err_abort("_nc_wrap_entry called without initialization");
+
+ nuses = ep->nuses;
+ tp = &(ep->tterm);
if (copy_strings) {
next_free = 0; /* clear static storage */
/* copy term_names, Strings, uses */
tp->term_names = _nc_save_str(tp->term_names);
for_each_string(i, tp) {
- if (tp->Strings[i] != ABSENT_STRING &&
- tp->Strings[i] != CANCELLED_STRING) {
+ if (VALID_STRING(tp->Strings[i])) {
tp->Strings[i] = _nc_save_str(tp->Strings[i]);
}
}
@@ -210,41 +233,148 @@
#endif
for (i = 0; i < nuses; i++) {
- if (useoffsets[i] == ABSENT_OFFSET)
+ if (useoffsets[i] == ABSENT_OFFSET) {
ep->uses[i].name = 0;
- else
- ep->uses[i].name = (tp->str_table + useoffsets[i]);
+ } else {
+ ep->uses[i].name = strdup(tp->str_table + useoffsets[i]);
+ }
}
+ DEBUG(2, (T_RETURN("")));
}
NCURSES_EXPORT(void)
-_nc_merge_entry(TERMTYPE *const to, TERMTYPE *const from)
+_nc_merge_entry(ENTRY * const target, ENTRY * const source)
/* merge capabilities from `from' entry into `to' entry */
{
+ TERMTYPE2 *to = &(target->tterm);
+ TERMTYPE2 *from = &(source->tterm);
+#if NCURSES_XNAMES
+ TERMTYPE2 copy;
+ size_t str_size, copy_size;
+ char *str_table;
+#endif
unsigned i;
+ if (source == 0 || from == 0 || target == 0 || to == 0)
+ return;
+
#if NCURSES_XNAMES
+ _nc_copy_termtype2(©, from);
+ from = ©
_nc_align_termtype(to, from);
+ /*
+ * compute the maximum size of the string-table.
+ */
+ str_size = strlen(to->term_names) + 1;
+ for_each_string(i, from) {
+ if (VALID_STRING(from->Strings[i]))
+ str_size += strlen(from->Strings[i]) + 1;
+ }
+ for_each_string(i, to) {
+ if (VALID_STRING(to->Strings[i]))
+ str_size += strlen(to->Strings[i]) + 1;
+ }
+ /* allocate a string-table large enough for both source/target, and
+ * copy all of the strings into that table. In the merge, we will
+ * select from the original source/target lists to construct a new
+ * target list.
+ */
+ if (str_size != 0) {
+ char *str_copied;
+ if ((str_table = malloc(str_size)) == NULL)
+ _nc_err_abort(MSG_NO_MEMORY);
+ str_copied = str_table;
+ _nc_STRCPY(str_copied, to->term_names, str_size);
+ to->term_names = str_copied;
+ copy_size = strlen(str_copied) + 1;
+ str_copied += copy_size;
+ str_size -= copy_size;
+ for_each_string(i, from) {
+ if (VALID_STRING(from->Strings[i])) {
+ _nc_STRCPY(str_copied, from->Strings[i], str_size);
+ from->Strings[i] = str_copied;
+ copy_size = strlen(str_copied) + 1;
+ str_copied += copy_size;
+ str_size -= copy_size;
+ }
+ }
+ for_each_string(i, to) {
+ if (VALID_STRING(to->Strings[i])) {
+ _nc_STRCPY(str_copied, to->Strings[i], str_size);
+ to->Strings[i] = str_copied;
+ copy_size = strlen(str_copied) + 1;
+ str_copied += copy_size;
+ str_size -= copy_size;
+ }
+ }
+ free(to->str_table);
+ to->str_table = str_table;
+ free(from->str_table);
+ }
+ /*
+ * Do the same for the extended-strings (i.e., lists of capabilities).
+ */
+ str_size = 0;
+ for (i = 0; i < NUM_EXT_NAMES(from); ++i) {
+ if (VALID_STRING(from->ext_Names[i]))
+ str_size += strlen(from->ext_Names[i]) + 1;
+ }
+ for (i = 0; i < NUM_EXT_NAMES(to); ++i) {
+ if (VALID_STRING(to->ext_Names[i]))
+ str_size += strlen(to->ext_Names[i]) + 1;
+ }
+ /* allocate a string-table large enough for both source/target, and
+ * copy all of the strings into that table. In the merge, we will
+ * select from the original source/target lists to construct a new
+ * target list.
+ */
+ if (str_size != 0) {
+ char *str_copied;
+ if ((str_table = malloc(str_size)) == NULL)
+ _nc_err_abort(MSG_NO_MEMORY);
+ str_copied = str_table;
+ for (i = 0; i < NUM_EXT_NAMES(from); ++i) {
+ if (VALID_STRING(from->ext_Names[i])) {
+ _nc_STRCPY(str_copied, from->ext_Names[i], str_size);
+ from->ext_Names[i] = str_copied;
+ copy_size = strlen(str_copied) + 1;
+ str_copied += copy_size;
+ str_size -= copy_size;
+ }
+ }
+ for (i = 0; i < NUM_EXT_NAMES(to); ++i) {
+ if (VALID_STRING(to->ext_Names[i])) {
+ _nc_STRCPY(str_copied, to->ext_Names[i], str_size);
+ to->ext_Names[i] = str_copied;
+ copy_size = strlen(str_copied) + 1;
+ str_copied += copy_size;
+ str_size -= copy_size;
+ }
+ }
+ free(to->ext_str_table);
+ to->ext_str_table = str_table;
+ free(from->ext_str_table);
+ }
#endif
for_each_boolean(i, from) {
- if (to->Booleans[i] != (char) CANCELLED_BOOLEAN) {
+ if (to->Booleans[i] != (NCURSES_SBOOL) CANCELLED_BOOLEAN) {
int mergebool = from->Booleans[i];
if (mergebool == CANCELLED_BOOLEAN)
to->Booleans[i] = FALSE;
else if (mergebool == TRUE)
- to->Booleans[i] = (char) mergebool;
+ to->Booleans[i] = (NCURSES_SBOOL) mergebool;
}
}
for_each_number(i, from) {
if (to->Numbers[i] != CANCELLED_NUMERIC) {
- short mergenum = from->Numbers[i];
+ int mergenum = from->Numbers[i];
if (mergenum == CANCELLED_NUMERIC)
to->Numbers[i] = ABSENT_NUMERIC;
else if (mergenum != ABSENT_NUMERIC)
- to->Numbers[i] = mergenum;
+ to->Numbers[i] = (NCURSES_INT2) mergenum;
}
}
@@ -263,13 +393,20 @@
to->Strings[i] = mergestring;
}
}
+#if NCURSES_XNAMES
+ /* cleanup */
+ free(copy.Booleans);
+ free(copy.Numbers);
+ free(copy.Strings);
+ free(copy.ext_Names);
+#endif
}
#if NO_LEAKS
NCURSES_EXPORT(void)
_nc_alloc_entry_leaks(void)
{
- if (stringbuf != 0) {
+ if (stringbuf != NULL) {
FreeAndNull(stringbuf);
}
next_free = 0;
diff --git a/ncurses/tinfo/alloc_ttype.c b/ncurses/tinfo/alloc_ttype.c
index 35c92dd..304c1b6 100644
--- a/ncurses/tinfo/alloc_ttype.c
+++ b/ncurses/tinfo/alloc_ttype.c
@@ -1,5 +1,6 @@
/****************************************************************************
- * Copyright (c) 1999-2012,2013 Free Software Foundation, Inc. *
+ * Copyright 2018-2022,2023 Thomas E. Dickey *
+ * Copyright 1999-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 *
@@ -42,7 +43,7 @@
#include <tic.h>
-MODULE_ID("$Id: alloc_ttype.c,v 1.27 2013/06/08 16:54:50 tom Exp $")
+MODULE_ID("$Id: alloc_ttype.c,v 1.51 2023/09/09 23:15:53 tom Exp $")
#if NCURSES_XNAMES
/*
@@ -61,7 +62,7 @@
} else if (cmp > 0) {
dst[n++] = *b++;
nb--;
- } else if (cmp == 0) {
+ } else {
dst[n++] = *a;
a++, b++;
na--, nb--;
@@ -78,37 +79,59 @@
}
static bool
-find_name(char **table, int length, char *name)
+find_name(char **table, int item, int length, const char *name)
{
- while (length-- > 0) {
- if (!strcmp(*table++, name)) {
- DEBUG(4, ("found name '%s'", name));
- return TRUE;
+ int n;
+ int result = -1;
+
+ for (n = item; n < length; ++n) {
+ if (!strcmp(table[n], name)) {
+ DEBUG(4, ("found name '%s' @%d", name, n));
+ result = n;
+ break;
}
}
- DEBUG(4, ("did not find name '%s'", name));
- return FALSE;
+ if (result < 0) {
+ DEBUG(4, ("did not find name '%s'", name));
+ }
+ return (result >= 0);
}
#define EXTEND_NUM(num, ext) \
+ DEBUG(4, ("extending " #num " from %d to %d", \
+ to->num, (unsigned short) (to->num + (ext - to->ext)))); \
to->num = (unsigned short) (to->num + (ext - to->ext))
static void
-realign_data(TERMTYPE *to, char **ext_Names,
+realign_data(TERMTYPE2 *to, char **ext_Names,
int ext_Booleans,
int ext_Numbers,
int ext_Strings)
{
int n, m, base;
- int limit = (to->ext_Booleans + to->ext_Numbers + to->ext_Strings);
+ int to_Booleans = to->ext_Booleans;
+ int to_Numbers = to->ext_Numbers;
+ int to_Strings = to->ext_Strings;
+ int to1, to2, from;
+
+ DEBUG(4, ("realign_data %d/%d/%d vs %d/%d/%d",
+ ext_Booleans,
+ ext_Numbers,
+ ext_Strings,
+ to->ext_Booleans,
+ to->ext_Numbers,
+ to->ext_Strings));
if (to->ext_Booleans != ext_Booleans) {
+ to1 = 0;
+ to2 = to_Booleans + to1;
+ from = 0;
EXTEND_NUM(num_Booleans, ext_Booleans);
TYPE_REALLOC(NCURSES_SBOOL, to->num_Booleans, to->Booleans);
for (n = to->ext_Booleans - 1,
m = ext_Booleans - 1,
base = to->num_Booleans - (m + 1); m >= 0; m--) {
- if (find_name(to->ext_Names, limit, ext_Names[m])) {
+ if (find_name(to->ext_Names, to1, to2, ext_Names[m + from])) {
to->Booleans[base + m] = to->Booleans[base + n--];
} else {
to->Booleans[base + m] = FALSE;
@@ -118,12 +141,15 @@
}
if (to->ext_Numbers != ext_Numbers) {
+ to1 = to_Booleans;
+ to2 = to_Numbers + to1;
+ from = ext_Booleans;
EXTEND_NUM(num_Numbers, ext_Numbers);
- TYPE_REALLOC(short, to->num_Numbers, to->Numbers);
+ TYPE_REALLOC(NCURSES_INT2, to->num_Numbers, to->Numbers);
for (n = to->ext_Numbers - 1,
m = ext_Numbers - 1,
base = to->num_Numbers - (m + 1); m >= 0; m--) {
- if (find_name(to->ext_Names, limit, ext_Names[m + ext_Booleans])) {
+ if (find_name(to->ext_Names, to1, to2, ext_Names[m + from])) {
to->Numbers[base + m] = to->Numbers[base + n--];
} else {
to->Numbers[base + m] = ABSENT_NUMERIC;
@@ -131,13 +157,17 @@
}
to->ext_Numbers = UShort(ext_Numbers);
}
+
if (to->ext_Strings != ext_Strings) {
+ to1 = to_Booleans + to_Numbers;
+ to2 = to_Strings + to1;
+ from = ext_Booleans + ext_Numbers;
EXTEND_NUM(num_Strings, ext_Strings);
TYPE_REALLOC(char *, to->num_Strings, to->Strings);
for (n = to->ext_Strings - 1,
m = ext_Strings - 1,
base = to->num_Strings - (m + 1); m >= 0; m--) {
- if (find_name(to->ext_Names, limit, ext_Names[m + ext_Booleans + ext_Numbers])) {
+ if (find_name(to->ext_Names, to1, to2, ext_Names[m + from])) {
to->Strings[base + m] = to->Strings[base + n--];
} else {
to->Strings[base + m] = ABSENT_STRING;
@@ -151,7 +181,7 @@
* Returns the first index in ext_Names[] for the given token-type
*/
static unsigned
-_nc_first_ext_name(TERMTYPE *tp, int token_type)
+_nc_first_ext_name(TERMTYPE2 *tp, int token_type)
{
unsigned first;
@@ -176,7 +206,7 @@
* Returns the last index in ext_Names[] for the given token-type
*/
static unsigned
-_nc_last_ext_name(TERMTYPE *tp, int token_type)
+_nc_last_ext_name(TERMTYPE2 *tp, int token_type)
{
unsigned last;
@@ -199,7 +229,7 @@
* Lookup an entry from extended-names, returning -1 if not found
*/
static int
-_nc_find_ext_name(TERMTYPE *tp, char *name, int token_type)
+_nc_find_ext_name(TERMTYPE2 *tp, char *name, int token_type)
{
unsigned j;
unsigned first = _nc_first_ext_name(tp, token_type);
@@ -218,7 +248,7 @@
* (e.g., Booleans[]).
*/
static int
-_nc_ext_data_index(TERMTYPE *tp, int n, int token_type)
+_nc_ext_data_index(TERMTYPE2 *tp, int n, int token_type)
{
switch (token_type) {
case BOOLEAN:
@@ -241,13 +271,14 @@
* data.
*/
static bool
-_nc_del_ext_name(TERMTYPE *tp, char *name, int token_type)
+_nc_del_ext_name(TERMTYPE2 *tp, char *name, int token_type)
{
- int j;
- int first, last;
+ int first;
if ((first = _nc_find_ext_name(tp, name, token_type)) >= 0) {
- last = (int) NUM_EXT_NAMES(tp) - 1;
+ int j;
+ int last = (int) NUM_EXT_NAMES(tp) - 1;
+
for (j = first; j < last; j++) {
tp->ext_Names[j] = tp->ext_Names[j + 1];
}
@@ -285,7 +316,7 @@
* index into the corresponding data array is returned.
*/
static int
-_nc_ins_ext_name(TERMTYPE *tp, char *name, int token_type)
+_nc_ins_ext_name(TERMTYPE2 *tp, char *name, int token_type)
{
unsigned first = _nc_first_ext_name(tp, token_type);
unsigned last = _nc_last_ext_name(tp, token_type);
@@ -319,7 +350,7 @@
case NUMBER:
tp->ext_Numbers++;
tp->num_Numbers++;
- TYPE_REALLOC(short, tp->num_Numbers, tp->Numbers);
+ TYPE_REALLOC(NCURSES_INT2, tp->num_Numbers, tp->Numbers);
for (k = (unsigned) (tp->num_Numbers - 1); k > j; k--)
tp->Numbers[k] = tp->Numbers[k - 1];
break;
@@ -340,12 +371,15 @@
* cancellation of a name that is inherited from another entry.
*/
static void
-adjust_cancels(TERMTYPE *to, TERMTYPE *from)
+adjust_cancels(TERMTYPE2 *to, TERMTYPE2 *from)
{
int first = to->ext_Booleans + to->ext_Numbers;
int last = first + to->ext_Strings;
int j, k;
+ DEBUG(3, (T_CALLED("adjust_cancels(%s), from(%s)"),
+ NonNull(to->term_names),
+ NonNull(from->term_names)));
for (j = first; j < last;) {
char *name = to->ext_Names[j];
int j_str = to->num_Strings - first - to->ext_Strings;
@@ -382,38 +416,47 @@
j++;
}
}
+ DEBUG(3, (T_RETURN("")));
}
NCURSES_EXPORT(void)
-_nc_align_termtype(TERMTYPE *to, TERMTYPE *from)
+_nc_align_termtype(TERMTYPE2 *to, TERMTYPE2 *from)
{
- int na = (int) NUM_EXT_NAMES(to);
- int nb = (int) NUM_EXT_NAMES(from);
- int n;
- bool same;
+ int na;
+ int nb;
char **ext_Names;
- int ext_Booleans, ext_Numbers, ext_Strings;
- bool used_ext_Names = FALSE;
- DEBUG(2, ("align_termtype to(%d:%s), from(%d:%s)", na, to->term_names,
- nb, from->term_names));
+ na = to ? ((int) NUM_EXT_NAMES(to)) : 0;
+ nb = from ? ((int) NUM_EXT_NAMES(from)) : 0;
- if (na != 0 || nb != 0) {
+ DEBUG(2, (T_CALLED("_nc_align_termtype to(%d:%s), from(%d:%s)"),
+ na, to ? NonNull(to->term_names) : "?",
+ nb, from ? NonNull(from->term_names) : "?"));
+
+ if (to != NULL && from != NULL && (na != 0 || nb != 0)) {
+ int ext_Booleans, ext_Numbers, ext_Strings;
+ bool used_ext_Names = FALSE;
+
if ((na == nb) /* check if the arrays are equivalent */
&&(to->ext_Booleans == from->ext_Booleans)
&& (to->ext_Numbers == from->ext_Numbers)
&& (to->ext_Strings == from->ext_Strings)) {
+ int n;
+ bool same;
+
for (n = 0, same = TRUE; n < na; n++) {
if (strcmp(to->ext_Names[n], from->ext_Names[n])) {
same = FALSE;
break;
}
}
- if (same)
+ if (same) {
+ DEBUG(2, (T_RETURN("")));
return;
+ }
}
/*
- * This is where we pay for having a simple extension representation.
+ * This is where we pay for having a simple extension representation.
* Allocate a new ext_Names array and merge the two ext_Names arrays
* into it, updating to's counts for booleans, etc. Fortunately we do
* this only for the terminfo compiler (tic) and comparer (infocmp).
@@ -470,42 +513,201 @@
if (!used_ext_Names)
free(ext_Names);
}
+ DEBUG(2, (T_RETURN("")));
}
#endif
-NCURSES_EXPORT(void)
-_nc_copy_termtype(TERMTYPE *dst, const TERMTYPE *src)
+#define srcINT 1
+#define dstINT 2
+
+/*
+ * TERMTYPE and TERMTYPE2 differ only with regard to the values in Numbers.
+ * Use 'mode' to decide which to use.
+ */
+static void
+copy_termtype(TERMTYPE2 *dst, const TERMTYPE2 *src, int mode)
{
-#if NCURSES_XNAMES
unsigned i;
+ int pass;
+ char *new_table;
+ size_t new_table_size;
+#if NCURSES_EXT_NUMBERS
+ short *oldptr = 0;
+ int *newptr = 0;
#endif
+ DEBUG(2, (T_CALLED("copy_termtype(dst=%p, src=%p, mode=%d)"), (void *)
+ dst, (const void *) src, mode));
*dst = *src; /* ...to copy the sizes and string-tables */
TYPE_MALLOC(NCURSES_SBOOL, NUM_BOOLEANS(dst), dst->Booleans);
- TYPE_MALLOC(short, NUM_NUMBERS(dst), dst->Numbers);
TYPE_MALLOC(char *, NUM_STRINGS(dst), dst->Strings);
memcpy(dst->Booleans,
src->Booleans,
NUM_BOOLEANS(dst) * sizeof(dst->Booleans[0]));
- memcpy(dst->Numbers,
- src->Numbers,
- NUM_NUMBERS(dst) * sizeof(dst->Numbers[0]));
memcpy(dst->Strings,
src->Strings,
NUM_STRINGS(dst) * sizeof(dst->Strings[0]));
- /* FIXME: we probably should also copy str_table and ext_str_table,
- * but tic and infocmp are not written to exploit that (yet).
- */
+ new_table = NULL;
+ new_table_size = 0;
+ for (pass = 0; pass < 2; ++pass) {
+ size_t str_size = 0;
+ if (src->term_names != NULL) {
+ if (pass) {
+ dst->term_names = new_table + str_size;
+ _nc_STRCPY(dst->term_names + str_size,
+ src->term_names,
+ new_table_size - str_size);
+ }
+ str_size += strlen(src->term_names) + 1;
+ }
+ for_each_string(i, src) {
+ if (VALID_STRING(src->Strings[i])) {
+ if (pass) {
+ _nc_STRCPY(new_table + str_size,
+ src->Strings[i],
+ new_table_size - str_size);
+ dst->Strings[i] = new_table + str_size;
+ }
+ str_size += strlen(src->Strings[i]) + 1;
+ }
+ }
+ if (pass) {
+ dst->str_table = new_table;
+ } else {
+ ++str_size;
+ if ((new_table = malloc(str_size)) == NULL)
+ _nc_err_abort(MSG_NO_MEMORY);
+ new_table_size = str_size;
+ }
+ }
+
+#if NCURSES_EXT_NUMBERS
+ if ((mode & dstINT) == 0) {
+ DEBUG(2, ("...convert int ->short"));
+ TYPE_MALLOC(short, NUM_NUMBERS(dst), oldptr);
+ ((TERMTYPE *) dst)->Numbers = oldptr;
+ } else {
+ DEBUG(2, ("...copy without changing size"));
+ TYPE_MALLOC(int, NUM_NUMBERS(dst), newptr);
+ dst->Numbers = newptr;
+ }
+ if ((mode == srcINT) && (oldptr != 0)) {
+ DEBUG(2, ("...copy int ->short"));
+ for (i = 0; i < NUM_NUMBERS(dst); ++i) {
+ if (src->Numbers[i] > MAX_OF_TYPE(short)) {
+ oldptr[i] = MAX_OF_TYPE(short);
+ } else {
+ oldptr[i] = (short) src->Numbers[i];
+ }
+ }
+ } else if ((mode == dstINT) && (newptr != 0)) {
+ DEBUG(2, ("...copy short ->int"));
+ for (i = 0; i < NUM_NUMBERS(dst); ++i) {
+ newptr[i] = ((const short *) (src->Numbers))[i];
+ }
+ } else {
+ DEBUG(2, ("...copy %s without change",
+ (mode & dstINT)
+ ? "int"
+ : "short"));
+ memcpy(dst->Numbers,
+ src->Numbers,
+ NUM_NUMBERS(dst) * ((mode & dstINT)
+ ? sizeof(int)
+ : sizeof(short)));
+ }
+#else
+ (void) mode;
+ TYPE_MALLOC(short, NUM_NUMBERS(dst), dst->Numbers);
+ memcpy(dst->Numbers,
+ src->Numbers,
+ NUM_NUMBERS(dst) * sizeof(dst->Numbers[0]));
+#endif
#if NCURSES_XNAMES
if ((i = NUM_EXT_NAMES(src)) != 0) {
TYPE_MALLOC(char *, i, dst->ext_Names);
memcpy(dst->ext_Names, src->ext_Names, i * sizeof(char *));
+
+ new_table = NULL;
+ new_table_size = 0;
+ for (pass = 0; pass < 2; ++pass) {
+ size_t str_size = 0;
+ char *raw_data = src->ext_str_table;
+ if (raw_data != NULL) {
+ for (i = 0; i < src->ext_Strings; ++i) {
+ size_t skip = strlen(raw_data) + 1;
+ if (skip != 1) {
+ if (pass) {
+ _nc_STRCPY(new_table + str_size,
+ raw_data,
+ new_table_size - str_size);
+ }
+ str_size += skip;
+ raw_data += skip;
+ }
+ }
+ }
+ for (i = 0; i < NUM_EXT_NAMES(dst); ++i) {
+ if (VALID_STRING(src->ext_Names[i])) {
+ if (pass) {
+ _nc_STRCPY(new_table + str_size,
+ src->ext_Names[i],
+ new_table_size - str_size);
+ dst->ext_Names[i] = new_table + str_size;
+ }
+ str_size += strlen(src->ext_Names[i]) + 1;
+ }
+ }
+ if (pass) {
+ dst->ext_str_table = new_table;
+ } else {
+ ++str_size;
+ if ((new_table = calloc(str_size, 1)) == NULL)
+ _nc_err_abort(MSG_NO_MEMORY);
+ new_table_size = str_size;
+ }
+ }
} else {
dst->ext_Names = 0;
}
#endif
+ (void) new_table_size;
+ DEBUG(2, (T_RETURN("")));
}
+
+NCURSES_EXPORT(void)
+_nc_copy_termtype(TERMTYPE *dst, const TERMTYPE *src)
+{
+ DEBUG(2, (T_CALLED("_nc_copy_termtype(dst=%p, src=%p)"), (void *) dst,
+ (const void *) src));
+ copy_termtype((TERMTYPE2 *) dst, (const TERMTYPE2 *) src, 0);
+ DEBUG(2, (T_RETURN("")));
+}
+
+#if NCURSES_EXT_NUMBERS
+NCURSES_EXPORT(void)
+_nc_copy_termtype2(TERMTYPE2 *dst, const TERMTYPE2 *src)
+{
+ DEBUG(2, (T_CALLED("_nc_copy_termtype2(dst=%p, src=%p)"), (void *) dst,
+ (const void *) src));
+ copy_termtype(dst, src, srcINT | dstINT);
+ DEBUG(2, (T_RETURN("")));
+}
+
+/*
+ * Use this for exporting the internal TERMTYPE2 to the legacy format used via
+ * the CUR macro by applications.
+ */
+NCURSES_EXPORT(void)
+_nc_export_termtype2(TERMTYPE *dst, const TERMTYPE2 *src)
+{
+ DEBUG(2, (T_CALLED("_nc_export_termtype2(dst=%p, src=%p)"), (void *)
+ dst, (const void *) src));
+ copy_termtype((TERMTYPE2 *) dst, src, srcINT);
+ DEBUG(2, (T_RETURN("")));
+}
+#endif /* NCURSES_EXT_NUMBERS */
diff --git a/ncurses/tinfo/captoinfo.c b/ncurses/tinfo/captoinfo.c
index e02e622..7e14731 100644
--- a/ncurses/tinfo/captoinfo.c
+++ b/ncurses/tinfo/captoinfo.c
@@ -1,5 +1,6 @@
/****************************************************************************
- * Copyright (c) 1998-2011,2012 Free Software Foundation, Inc. *
+ * 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 *
* copy of this software and associated documentation files (the *
@@ -33,12 +34,16 @@
****************************************************************************/
/*
- * captoinfo.c --- conversion between termcap and terminfo formats
+ * captoinfo.c
+ *
+ * Provide conversion in both directions between termcap and terminfo.
+ *
+ * cap-to-info --- conversion between termcap and terminfo formats
*
* The captoinfo() code was swiped from Ross Ridge's mytinfo package,
* adapted to fit ncurses by Eric S. Raymond <esr@snark.thyrsus.com>.
*
- * There is just one entry point:
+ * It has just one entry point:
*
* char *_nc_captoinfo(n, s, parameterized)
*
@@ -93,7 +98,13 @@
#include <ctype.h>
#include <tic.h>
-MODULE_ID("$Id: captoinfo.c,v 1.77 2012/12/30 00:50:40 tom Exp $")
+MODULE_ID("$Id: captoinfo.c,v 1.102 2021/09/04 10:29:15 tom Exp $")
+
+#if 0
+#define DEBUG_THIS(p) DEBUG(9, p)
+#else
+#define DEBUG_THIS(p) /* nothing */
+#endif
#define MAX_PUSHED 16 /* max # args we can push onto the stack */
@@ -181,7 +192,7 @@
case '$':
case '\\':
case '%':
- c = (unsigned char) (*sp);
+ c = UChar(*sp);
len = 2;
break;
case '\0':
@@ -194,29 +205,36 @@
case '3':
len = 1;
while (isdigit(UChar(*sp))) {
- c = (unsigned char) (8 * c + (*sp++ - '0'));
+ c = UChar(8 * c + (*sp++ - '0'));
len++;
}
break;
default:
- c = (unsigned char) (*sp);
- len = 2;
+ c = UChar(*sp);
+ len = (c != '\0') ? 2 : 1;
break;
}
break;
case '^':
- c = (unsigned char) (*++sp & 0x1f);
len = 2;
+ c = UChar(*++sp);
+ if (c == '?') {
+ c = 127;
+ } else if (c == '\0') {
+ len = 1;
+ } else {
+ c &= 0x1f;
+ }
break;
default:
- c = (unsigned char) (*sp);
- len = 1;
+ c = UChar(*sp);
+ len = (c != '\0') ? 1 : 0;
}
if (isgraph(c) && c != ',' && c != '\'' && c != '\\' && c != ':') {
dp = save_string(dp, "%\'");
dp = save_char(dp, c);
dp = save_char(dp, '\'');
- } else {
+ } else if (c != '\0') {
dp = save_string(dp, "%{");
if (c > 99)
dp = save_char(dp, c / 100 + '0');
@@ -232,6 +250,8 @@
getparm(int parm, int n)
/* push n copies of param on the terminfo stack if not already there */
{
+ int nn;
+
if (seenr) {
if (parm == 1)
parm = 2;
@@ -239,7 +259,7 @@
parm = 1;
}
- while (n--) {
+ for (nn = 0; nn < n; ++nn) {
dp = save_string(dp, "%p");
dp = save_char(dp, '0' + parm);
}
@@ -248,7 +268,7 @@
if (n > 1) {
_nc_warning("string may not be optimal");
dp = save_string(dp, "%Pa");
- while (n--) {
+ while (n-- > 0) {
dp = save_string(dp, "%ga");
}
}
@@ -288,6 +308,8 @@
seenr = 0;
param = 1;
+ DEBUG_THIS(("_nc_captoinfo params %d, %s", parameterized, s));
+
dp = init_string();
/* skip the initial padding (if we haven't been told not to) */
@@ -295,7 +317,7 @@
if (s == 0)
s = "";
if (parameterized >= 0 && isdigit(UChar(*s)))
- for (capstart = s;; s++)
+ for (capstart = s; *s != '\0'; s++)
if (!(isdigit(UChar(*s)) || *s == '*' || *s == '.'))
break;
@@ -309,7 +331,7 @@
}
switch (*s++) {
case '%':
- dp = save_char(dp, '%');
+ dp = save_string(dp, "%%");
break;
case 'r':
if (seenr++ == 1) {
@@ -342,13 +364,18 @@
dp = save_string(dp, "%{2}%*%-");
break;
case '>':
- getparm(param, 2);
/* %?%{x}%>%t%{y}%+%; */
- dp = save_string(dp, "%?");
- s += cvtchar(s);
- dp = save_string(dp, "%>%t");
- s += cvtchar(s);
- dp = save_string(dp, "%+%;");
+ if (s[0] && s[1]) {
+ getparm(param, 2);
+ dp = save_string(dp, "%?");
+ s += cvtchar(s);
+ dp = save_string(dp, "%>%t");
+ s += cvtchar(s);
+ dp = save_string(dp, "%+%;");
+ } else {
+ _nc_warning("expected two characters after %%>");
+ dp = save_string(dp, "%>");
+ }
break;
case 'a':
if ((*s == '=' || *s == '+' || *s == '-'
@@ -429,12 +456,17 @@
pop();
break;
case '0': /* not clear any of the historical termcaps did this */
- if (*s == '3')
+ if (*s == '3') {
+ ++s;
goto see03;
- else if (*s != '2')
- goto invalid;
- /* FALLTHRU */
+ }
+ if (*s == '2') {
+ ++s;
+ goto see02;
+ }
+ goto invalid;
case '2':
+ see02:
getparm(param, 1);
dp = save_string(dp, "%2d");
pop();
@@ -469,7 +501,8 @@
}
break;
default:
- dp = save_char(dp, *s++);
+ if (*s != '\0')
+ dp = save_char(dp, *s++);
break;
}
}
@@ -480,7 +513,7 @@
*/
if (capstart) {
dp = save_string(dp, "$<");
- for (s = capstart;; s++)
+ for (s = capstart; *s != '\0'; s++)
if (isdigit(UChar(*s)) || *s == '*' || *s == '.')
dp = save_char(dp, *s);
else
@@ -489,6 +522,9 @@
}
(void) save_char(dp, '\0');
+
+ DEBUG_THIS(("... _nc_captoinfo %s", NonNull(my_string)));
+
return (my_string);
}
@@ -525,13 +561,13 @@
static char *
save_tc_char(char *bufptr, int c1)
{
- char temp[80];
-
if (is7bits(c1) && isprint(c1)) {
if (c1 == ':' || c1 == '\\')
bufptr = save_char(bufptr, '\\');
bufptr = save_char(bufptr, c1);
} else {
+ char temp[80];
+
if (c1 == (c1 & 0x1f)) { /* iscntrl() returns T on 255 */
_nc_SPRINTF(temp, _nc_SLIMIT(sizeof(temp))
"%.20s", unctrl((chtype) c1));
@@ -554,6 +590,8 @@
}
/*
+ * info-to-cap --- conversion between terminfo and termcap formats
+ *
* Here are the capabilities infotocap assumes it can translate to:
*
* %% output `%'
@@ -571,6 +609,8 @@
* %m exclusive-or all parameters with 0177 (not in 4.4BSD)
*/
+#define octal_fixup(n, c) fixups[n].ch = ((fixups[n].ch << 3) | ((c) - '0'))
+
/*
* Convert a terminfo string to termcap format. Parameters are as in
* _nc_captoinfo().
@@ -586,12 +626,23 @@
char *bufptr = init_string();
char octal[4];
int len;
+ int digits;
bool syntax_error = FALSE;
+ int myfix = 0;
+ struct {
+ int ch;
+ int offset;
+ } fixups[MAX_TC_FIXUPS];
+
+ DEBUG_THIS(("_nc_infotocap %s params %d, %s",
+ _nc_strict_bsd ? "strict" : "loose",
+ parameterized,
+ _nc_visbuf(str)));
/* 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--;
@@ -603,7 +654,9 @@
bufptr = save_char(bufptr, *padding++);
}
- for (; *str && ((trimmed == 0) || (str < trimmed)); str++) {
+ for (; !syntax_error &&
+ *str &&
+ ((trimmed == 0) || (str < trimmed)); str++) {
int c1, c2;
char *cp = 0;
@@ -611,10 +664,23 @@
if (str[1] == '\0' || (str + 1) == trimmed) {
bufptr = save_string(bufptr, "\\136");
++str;
+ } else if (str[1] == '?') {
+ /*
+ * Although the 4.3BSD termcap file has an instance of "kb=^?",
+ * that appears to be just cut/paste since neither 4.3BSD nor
+ * 4.4BSD termcap interprets "^?" as DEL.
+ */
+ bufptr = save_string(bufptr, "\\177");
+ ++str;
} else {
bufptr = save_char(bufptr, *str++);
bufptr = save_char(bufptr, *str);
}
+ } else if (str[0] == ':') {
+ bufptr = save_char(bufptr, '\\');
+ bufptr = save_char(bufptr, '0');
+ bufptr = save_char(bufptr, '7');
+ bufptr = save_char(bufptr, '2');
} else if (str[0] == '\\') {
if (str[1] == '\0' || (str + 1) == trimmed) {
bufptr = save_string(bufptr, "\\134");
@@ -625,17 +691,20 @@
} else if (str[1] == ',') {
bufptr = save_char(bufptr, *++str);
} else {
- int xx1, xx2;
+ int xx1;
bufptr = save_char(bufptr, *str++);
xx1 = *str;
if (_nc_strict_bsd) {
- if (isdigit(UChar(xx1))) {
- int pad = 0;
- if (!isdigit(UChar(str[1])))
+ if (isoctal(UChar(xx1))) {
+ int pad = 0;
+ int xx2;
+ int fix = 0;
+
+ if (!isoctal(UChar(str[1])))
pad = 2;
- else if (str[1] && !isdigit(UChar(str[2])))
+ else if (str[1] && !isoctal(UChar(str[2])))
pad = 1;
/*
@@ -650,10 +719,31 @@
xx2 = '0';
pad = 0; /* FIXME - optionally pad to 3 digits */
}
+ if (myfix < MAX_TC_FIXUPS) {
+ fix = 3 - pad;
+ fixups[myfix].ch = 0;
+ fixups[myfix].offset = (int) (bufptr
+ - my_string
+ - 1);
+ }
while (pad-- > 0) {
bufptr = save_char(bufptr, xx2);
+ if (myfix < MAX_TC_FIXUPS) {
+ fixups[myfix].ch <<= 3;
+ fixups[myfix].ch |= (xx2 - '0');
+ }
xx2 = '0';
}
+ if (myfix < MAX_TC_FIXUPS) {
+ int n;
+ for (n = 0; n < fix; ++n) {
+ fixups[myfix].ch <<= 3;
+ fixups[myfix].ch |= (str[n] - '0');
+ }
+ if (fixups[myfix].ch < 32) {
+ ++myfix;
+ }
+ }
} else if (strchr("E\\nrtbf", xx1) == 0) {
switch (xx1) {
case 'e':
@@ -689,6 +779,24 @@
break;
}
}
+ } else {
+ if (myfix < MAX_TC_FIXUPS && isoctal(UChar(xx1))) {
+ bool will_fix = TRUE;
+ int n;
+
+ fixups[myfix].ch = 0;
+ fixups[myfix].offset = (int) (bufptr - my_string - 1);
+ for (n = 0; n < 3; ++n) {
+ if (isoctal(str[n])) {
+ octal_fixup(myfix, str[n]);
+ } else {
+ will_fix = FALSE;
+ break;
+ }
+ }
+ if (will_fix && (fixups[myfix].ch < 32))
+ ++myfix;
+ }
}
bufptr = save_char(bufptr, xx1);
}
@@ -735,8 +843,9 @@
} else if ((len = bcd_expression(str)) != 0) {
str += len;
bufptr = save_string(bufptr, "%B");
- } else if ((sscanf(str, "%%{%d}%%+%%c", &c1) == 1
- || sscanf(str, "%%'%c'%%+%%c", &ch1) == 1)
+ } else if ((sscanf(str, "%%{%d}%%+%%%c", &c1, &ch2) == 2
+ || sscanf(str, "%%'%c'%%+%%%c", &ch1, &ch2) == 2)
+ && ch2 == 'c'
&& (cp = strchr(str, '+'))) {
str = cp + 2;
bufptr = save_string(bufptr, "%+");
@@ -779,26 +888,46 @@
bufptr = save_char(bufptr, '%');
ch1 = 0;
ch2 = 0;
+ digits = 0;
while (isdigit(UChar(*str))) {
+ if (++digits > 2) {
+ syntax_error = TRUE;
+ break;
+ }
ch2 = ch1;
ch1 = *str++;
- if (_nc_strict_bsd) {
- if (ch1 > '3')
- return 0;
+ if (digits == 2 && ch2 != '0') {
+ syntax_error = TRUE;
+ break;
+ } else if (_nc_strict_bsd) {
+ if (ch1 > '3') {
+ syntax_error = TRUE;
+ break;
+ }
} else {
bufptr = save_char(bufptr, ch1);
}
}
+ if (syntax_error)
+ break;
+ /*
+ * Convert %02 to %2 and %03 to %3
+ */
+ if (ch2 == '0' && !_nc_strict_bsd) {
+ ch2 = 0;
+ bufptr[-2] = bufptr[-1];
+ *--bufptr = 0;
+ }
if (_nc_strict_bsd) {
- if (ch2 != 0 && ch2 != '0')
- return 0;
- if (ch1 < '2')
+ if (ch2 != 0 && ch2 != '0') {
+ syntax_error = TRUE;
+ } else if (ch1 < '2') {
ch1 = 'd';
+ }
bufptr = save_char(bufptr, ch1);
}
- if (strchr("doxX.", *str)) {
- if (*str != 'd') /* termcap doesn't have octal, hex */
- return 0;
+ if (strchr("oxX.", *str)) {
+ syntax_error = TRUE; /* termcap doesn't have octal, hex */
}
break;
@@ -811,14 +940,16 @@
break;
/*
- * %s isn't in termcap, but it's convenient to pass it through
+ * %s isn't in termcap, but it is convenient to pass it through
* so we can represent things like terminfo pfkey strings in
* termcap notation.
*/
case 's':
- if (_nc_strict_bsd)
- return 0;
- bufptr = save_string(bufptr, "%s");
+ if (_nc_strict_bsd) {
+ syntax_error = TRUE;
+ } else {
+ bufptr = save_string(bufptr, "%s");
+ }
break;
case 'p':
@@ -830,8 +961,9 @@
bufptr = save_string(bufptr, "%r");
seentwo++;
}
- } else if (*str >= '3')
- return (0);
+ } else if (*str >= '3') {
+ syntax_error = TRUE;
+ }
break;
case 'i':
@@ -855,6 +987,24 @@
} /* endwhile (*str) */
+ if (!syntax_error &&
+ myfix > 0 &&
+ ((int) strlen(my_string) - (4 * myfix)) < MIN_TC_FIXUPS) {
+ while (--myfix >= 0) {
+ char *p = fixups[myfix].offset + my_string;
+ *p++ = '^';
+ *p++ = (char) (fixups[myfix].ch | '@');
+ while ((p[0] = p[2]) != '\0') {
+ ++p;
+ }
+ }
+ }
+
+ DEBUG_THIS(("... _nc_infotocap %s",
+ syntax_error
+ ? "<ERR>"
+ : _nc_visbuf(my_string)));
+
return (syntax_error ? NULL : my_string);
}
diff --git a/ncurses/tinfo/comp_error.c b/ncurses/tinfo/comp_error.c
index ff0acc7..3e6b402 100644
--- a/ncurses/tinfo/comp_error.c
+++ b/ncurses/tinfo/comp_error.c
@@ -1,5 +1,6 @@
/****************************************************************************
- * Copyright (c) 1998-2011,2012 Free Software Foundation, Inc. *
+ * Copyright 2019-2020,2023 Thomas E. Dickey *
+ * Copyright 1998-2012,2016 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 *
@@ -41,7 +42,7 @@
#include <tic.h>
-MODULE_ID("$Id: comp_error.c,v 1.36 2012/02/22 22:34:31 tom Exp $")
+MODULE_ID("$Id: comp_error.c,v 1.44 2023/06/15 20:27:02 tom Exp $")
NCURSES_EXPORT_VAR(bool) _nc_suppress_warnings = FALSE;
NCURSES_EXPORT_VAR(int) _nc_curr_line = 0; /* current line # in input */
@@ -59,19 +60,28 @@
NCURSES_EXPORT(void)
_nc_set_source(const char *const name)
{
- FreeIfNeeded(SourceName);
- SourceName = strdup(name);
+ if (name == NULL) {
+ free(SourceName);
+ SourceName = NULL;
+ } else if (SourceName == NULL) {
+ SourceName = strdup(name);
+ } else if (strcmp(name, SourceName)) {
+ free(SourceName);
+ SourceName = strdup(name);
+ }
}
NCURSES_EXPORT(void)
_nc_set_type(const char *const name)
{
+#define MY_SIZE (size_t) MAX_NAME_SIZE
if (TermType == 0)
- TermType = typeMalloc(char, MAX_NAME_SIZE + 1);
+ TermType = typeMalloc(char, MY_SIZE + 1);
if (TermType != 0) {
TermType[0] = '\0';
- if (name)
- strncat(TermType, name, (size_t) MAX_NAME_SIZE);
+ if (name) {
+ _nc_STRNCAT(TermType, name, MY_SIZE, MY_SIZE);
+ }
}
}
@@ -92,9 +102,9 @@
where_is_problem(void)
{
fprintf(stderr, "\"%s\"", SourceName ? SourceName : "?");
- if (_nc_curr_line >= 0)
+ if (_nc_curr_line > 0)
fprintf(stderr, ", line %d", _nc_curr_line);
- if (_nc_curr_col >= 0)
+ if (_nc_curr_col > 0)
fprintf(stderr, ", col %d", _nc_curr_col);
if (TermType != 0 && TermType[0] != '\0')
fprintf(stderr, ", terminal '%s'", TermType);
@@ -103,7 +113,7 @@
}
NCURSES_EXPORT(void)
-_nc_warning(const char *const fmt,...)
+_nc_warning(const char *const fmt, ...)
{
va_list argp;
@@ -118,7 +128,7 @@
}
NCURSES_EXPORT(void)
-_nc_err_abort(const char *const fmt,...)
+_nc_err_abort(const char *const fmt, ...)
{
va_list argp;
@@ -131,7 +141,7 @@
}
NCURSES_EXPORT(void)
-_nc_syserr_abort(const char *const fmt,...)
+_nc_syserr_abort(const char *const fmt, ...)
{
va_list argp;
@@ -141,16 +151,16 @@
fprintf(stderr, "\n");
va_end(argp);
+#if defined(TRACE) || !defined(NDEBUG)
/* If we're debugging, try to show where the problem occurred - this
* will dump core.
*/
-#if defined(TRACE) || !defined(NDEBUG)
- abort();
-#else
+ if (_nc_env_access())
+ abort();
+#endif
/* Dumping core in production code is not a good idea.
*/
exit(EXIT_FAILURE);
-#endif
}
#if NO_LEAKS
diff --git a/ncurses/tinfo/comp_expand.c b/ncurses/tinfo/comp_expand.c
index 2ab06eb..e971384 100644
--- a/ncurses/tinfo/comp_expand.c
+++ b/ncurses/tinfo/comp_expand.c
@@ -1,5 +1,6 @@
/****************************************************************************
- * Copyright (c) 1998-2011,2012 Free Software Foundation, Inc. *
+ * Copyright 2020-2021,2023 Thomas E. Dickey *
+ * Copyright 1998-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 *
@@ -27,7 +28,7 @@
****************************************************************************/
/****************************************************************************
- * Author: Thomas E. Dickey <dickey@clark.net> 1998 *
+ * Author: Thomas E. Dickey 1998 *
****************************************************************************/
#include <curses.priv.h>
@@ -35,7 +36,13 @@
#include <ctype.h>
#include <tic.h>
-MODULE_ID("$Id: comp_expand.c,v 1.25 2012/03/24 18:37:17 tom Exp $")
+MODULE_ID("$Id: comp_expand.c,v 1.35 2023/04/28 20:59:06 tom Exp $")
+
+#if 0
+#define DEBUG_THIS(p) DEBUG(9, p)
+#else
+#define DEBUG_THIS(p) /* nothing */
+#endif
static int
trailing_spaces(const char *src)
@@ -46,10 +53,9 @@
}
/* this deals with differences over whether 0x7f and 0x80..0x9f are controls */
-#define REALCTL(s) (UChar(*(s)) < 127 && iscntrl(UChar(*(s))))
#define REALPRINT(s) (UChar(*(s)) < 127 && isprint(UChar(*(s))))
-#define P_LIMIT(p) (length - (size_t)(p))
+#define P_LIMIT(p) (length - (size_t)(p))
NCURSES_EXPORT(char *)
_nc_tic_expand(const char *srcp, bool tic_format, int numbers)
@@ -59,9 +65,13 @@
int bufp;
const char *str = VALID_STRING(srcp) ? srcp : "\0\0";
- bool islong = (strlen(str) > 3);
size_t need = (2 + strlen(str)) * 4;
int ch;
+ int octals = 0;
+ struct {
+ int ch;
+ int offset;
+ } fixups[MAX_TC_FIXUPS];
if (srcp == 0) {
#if NO_LEAKS
@@ -77,6 +87,10 @@
return 0;
}
+ DEBUG_THIS(("_nc_tic_expand %s:%s:%s",
+ tic_format ? "ti" : "tc",
+ numbers ? "#" : "",
+ _nc_visbuf(srcp)));
bufp = 0;
while ((ch = UChar(*str)) != 0) {
if (ch == '%' && REALPRINT(str + 1)) {
@@ -115,7 +129,6 @@
if (dst != 0
&& *dst == R_BRACE
&& value < 127
- && value != '\\' /* FIXME */
&& isprint((int) value)) {
ch = (int) value;
buffer[bufp++] = S_QUOTE;
@@ -133,6 +146,8 @@
}
break;
default:
+ if (*str == ',') /* minitel1 uses this */
+ buffer[bufp++] = '\\';
buffer[bufp++] = *str;
break;
}
@@ -149,43 +164,37 @@
trailing_spaces(str))) {
buffer[bufp++] = '\\';
buffer[bufp++] = 's';
- } else if ((ch == ',' || ch == ':' || ch == '^') && tic_format) {
+ } else if ((ch == ',' || ch == '^') && tic_format) {
buffer[bufp++] = '\\';
buffer[bufp++] = (char) ch;
} else if (REALPRINT(str)
&& (ch != ','
- && ch != ':'
+ && !(ch == ':' && !tic_format)
&& !(ch == '!' && !tic_format)
&& ch != '^'))
buffer[bufp++] = (char) ch;
-#if 0 /* FIXME: this would be more readable (in fact the whole 'islong' logic should be removed) */
- else if (ch == '\b') {
- buffer[bufp++] = '\\';
- buffer[bufp++] = 'b';
- } else if (ch == '\f') {
- buffer[bufp++] = '\\';
- buffer[bufp++] = 'f';
- } else if (ch == '\t' && islong) {
- buffer[bufp++] = '\\';
- buffer[bufp++] = 't';
- }
-#endif
- else if (ch == '\r' && (islong || (strlen(srcp) > 2 && str[1] == '\0'))) {
+ else if (ch == '\r') {
buffer[bufp++] = '\\';
buffer[bufp++] = 'r';
- } else if (ch == '\n' && islong) {
+ } else if (ch == '\n') {
buffer[bufp++] = '\\';
buffer[bufp++] = 'n';
}
#define UnCtl(c) ((c) + '@')
- else if (REALCTL(str) && ch != '\\'
- && (!islong || isdigit(UChar(str[1])))) {
+ else if (UChar(ch) < 32
+ && isdigit(UChar(str[1]))) {
_nc_SPRINTF(&buffer[bufp], _nc_SLIMIT(P_LIMIT(bufp))
"^%c", UnCtl(ch));
bufp += 2;
} else {
_nc_SPRINTF(&buffer[bufp], _nc_SLIMIT(P_LIMIT(bufp))
"\\%03o", ch);
+ if ((octals < MAX_TC_FIXUPS) &&
+ ((tic_format && (ch == 127)) || ch < 32)) {
+ fixups[octals].ch = UChar(ch);
+ fixups[octals].offset = bufp;
+ ++octals;
+ }
bufp += 4;
}
@@ -193,5 +202,26 @@
}
buffer[bufp] = '\0';
+
+ /*
+ * If most of a short string is ASCII control characters, reformat the
+ * string to show those in up-arrow format. For longer strings, it is
+ * more likely that the characters are just binary coding.
+ *
+ * If we're formatting termcap, just use the shorter format (up-arrows).
+ */
+ if (octals != 0 && (!tic_format || (bufp - (4 * octals)) < MIN_TC_FIXUPS)) {
+ while (--octals >= 0) {
+ char *p = buffer + fixups[octals].offset;
+ *p++ = '^';
+ *p++ = (char) ((fixups[octals].ch == 127)
+ ? '?'
+ : (fixups[octals].ch + (int) '@'));
+ while ((p[0] = p[2]) != 0) {
+ ++p;
+ }
+ }
+ }
+ DEBUG_THIS(("... %s", _nc_visbuf(buffer)));
return (buffer);
}
diff --git a/ncurses/tinfo/comp_hash.c b/ncurses/tinfo/comp_hash.c
index 959c6e1..4b081af 100644
--- a/ncurses/tinfo/comp_hash.c
+++ b/ncurses/tinfo/comp_hash.c
@@ -1,5 +1,6 @@
/****************************************************************************
- * Copyright (c) 1998-2008,2009 Free Software Foundation, Inc. *
+ * Copyright 2019-2020,2023 Thomas E. Dickey *
+ * Copyright 1998-2008,2009 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 *
@@ -44,13 +45,12 @@
#include <tic.h>
#include <hashsize.h>
-MODULE_ID("$Id: comp_hash.c,v 1.48 2009/08/08 17:36:21 tom Exp $")
+MODULE_ID("$Id: comp_hash.c,v 1.55 2023/06/24 13:29:43 tom Exp $")
/*
* Finds the entry for the given string in the hash table if present.
* Returns a pointer to the entry in the table or 0 if not found.
*/
-/* entrypoint used by tack (do not alter) */
NCURSES_EXPORT(struct name_table_entry const *)
_nc_find_entry(const char *string,
const HashValue * hash_table)
@@ -63,7 +63,9 @@
hashvalue = data->hash_of(string);
- if (data->table_data[hashvalue] >= 0) {
+ if (hashvalue >= 0
+ && (unsigned) hashvalue < data->table_size
+ && data->table_data[hashvalue] >= 0) {
real_table = _nc_get_table(termcap);
ptr = real_table + data->table_data[hashvalue];
@@ -96,19 +98,54 @@
const HashData *data = _nc_get_hash_info(termcap);
int hashvalue = data->hash_of(string);
- if (data->table_data[hashvalue] >= 0) {
+ if (hashvalue >= 0
+ && (unsigned) hashvalue < data->table_size
+ && data->table_data[hashvalue] >= 0) {
const struct name_table_entry *const table = _nc_get_table(termcap);
- ptr = table + data->table_data[hashvalue];
- while (ptr->nte_type != type
- || !data->compare_names(ptr->nte_name, string)) {
- if (ptr->nte_link < 0) {
- ptr = 0;
- break;
+ if (table != NULL) {
+ ptr = table + data->table_data[hashvalue];
+ while (ptr->nte_type != type
+ || !data->compare_names(ptr->nte_name, string)) {
+ if (ptr->nte_link < 0) {
+ ptr = 0;
+ break;
+ }
+ ptr = table + (ptr->nte_link + data->table_data[data->table_size]);
}
- ptr = table + (ptr->nte_link + data->table_data[data->table_size]);
}
}
return ptr;
}
+
+#if NCURSES_XNAMES
+NCURSES_EXPORT(struct user_table_entry const *)
+_nc_find_user_entry(const char *string)
+{
+ const HashData *data = _nc_get_hash_user();
+ int hashvalue;
+ struct user_table_entry const *ptr = 0;
+ struct user_table_entry const *real_table;
+
+ hashvalue = data->hash_of(string);
+
+ if (hashvalue >= 0
+ && (unsigned) hashvalue < data->table_size
+ && data->table_data[hashvalue] >= 0) {
+
+ real_table = _nc_get_userdefs_table();
+ ptr = real_table + data->table_data[hashvalue];
+ while (!data->compare_names(ptr->ute_name, string)) {
+ if (ptr->ute_link < 0) {
+ ptr = 0;
+ break;
+ }
+ ptr = real_table + (ptr->ute_link
+ + data->table_data[data->table_size]);
+ }
+ }
+
+ return (ptr);
+}
+#endif /* NCURSES_XNAMES */
diff --git a/ncurses/tinfo/comp_parse.c b/ncurses/tinfo/comp_parse.c
index 82a61a5..dec4b92 100644
--- a/ncurses/tinfo/comp_parse.c
+++ b/ncurses/tinfo/comp_parse.c
@@ -1,5 +1,6 @@
/****************************************************************************
- * Copyright (c) 1998-2012,2013 Free Software Foundation, Inc. *
+ * Copyright 2018-2023,2024 Thomas E. Dickey *
+ * Copyright 1998-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 *
@@ -47,23 +48,22 @@
#include <tic.h>
-MODULE_ID("$Id: comp_parse.c,v 1.90 2013/08/31 15:22:31 tom Exp $")
+MODULE_ID("$Id: comp_parse.c,v 1.134 2024/02/10 15:52:11 tom Exp $")
-static void sanity_check2(TERMTYPE *, bool);
-NCURSES_IMPEXP void NCURSES_API(*_nc_check_termtype2) (TERMTYPE *, bool) = sanity_check2;
+static void sanity_check2(TERMTYPE2 *, bool);
+NCURSES_IMPEXP void (NCURSES_API *_nc_check_termtype2) (TERMTYPE2 *, bool) = sanity_check2;
-/* obsolete: 20040705 */
-static void sanity_check(TERMTYPE *);
-NCURSES_IMPEXP void NCURSES_API(*_nc_check_termtype) (TERMTYPE *) = sanity_check;
-
-static void fixup_acsc(TERMTYPE *, int);
+static void fixup_acsc(TERMTYPE2 *, int);
static void
enqueue(ENTRY * ep)
/* add an entry to the in-core list */
{
- ENTRY *newp = _nc_copy_entry(ep);
+ ENTRY *newp;
+ DEBUG(2, (T_CALLED("enqueue(ep=%p)"), (void *) ep));
+
+ newp = _nc_copy_entry(ep);
if (newp == 0)
_nc_err_abort(MSG_NO_MEMORY);
@@ -73,8 +73,11 @@
newp->next = 0;
if (newp->last)
newp->last->next = newp;
+ DEBUG(2, (T_RETURN("")));
}
+#define NAMEBUFFER_SIZE (MAX_NAME_SIZE + 2)
+
static char *
force_bar(char *dst, char *src)
{
@@ -82,8 +85,8 @@
size_t len = strlen(src);
if (len > MAX_NAME_SIZE)
len = MAX_NAME_SIZE;
- (void) strncpy(dst, src, len);
- _nc_STRCPY(dst + len, "|", MAX_NAME_SIZE);
+ _nc_STRNCPY(dst, src, MAX_NAME_SIZE);
+ _nc_STRCPY(dst + len, "|", NAMEBUFFER_SIZE - len);
src = dst;
}
return src;
@@ -107,8 +110,8 @@
check_collisions(char *n1, char *n2, int counter)
{
char *pstart, *qstart, *pend, *qend;
- char nc1[MAX_NAME_SIZE + 2];
- char nc2[MAX_NAME_SIZE + 2];
+ char nc1[NAMEBUFFER_SIZE];
+ char nc2[NAMEBUFFER_SIZE];
n1 = ForceBar(nc1, n1);
n2 = ForceBar(nc2, n2);
@@ -182,11 +185,11 @@
++qend;
while ((*qstart++ = *qend++) != '\0') ;
fprintf(stderr, "...now\t%s\n", p2);
+ removed = TRUE;
} else {
fprintf(stderr, "Cannot remove alias '%.*s'\n",
(int) (qend - qstart), qstart);
}
- removed = TRUE;
break;
}
}
@@ -218,6 +221,12 @@
bool oldsuppress = _nc_suppress_warnings;
int immediate = 0;
+ DEBUG(2,
+ (T_CALLED("_nc_read_entry_source("
+ "file=%p, buf=%p, literal=%d, silent=%d, hook=%#"
+ PRIxPTR ")"),
+ (void *) fp, buf, literal, silent, CASTxPTR(hook)));
+
if (silent)
_nc_suppress_warnings = TRUE; /* shut the lexer up, too */
@@ -245,38 +254,159 @@
FreeIfNeeded(thisentry.tterm.Booleans);
FreeIfNeeded(thisentry.tterm.Numbers);
FreeIfNeeded(thisentry.tterm.Strings);
+ FreeIfNeeded(thisentry.tterm.str_table);
#if NCURSES_XNAMES
FreeIfNeeded(thisentry.tterm.ext_Names);
+ FreeIfNeeded(thisentry.tterm.ext_str_table);
#endif
}
}
if (_nc_tail) {
/* set up the head pointer */
- for (_nc_head = _nc_tail; _nc_head->last; _nc_head = _nc_head->last)
- continue;
+ for (_nc_head = _nc_tail; _nc_head->last; _nc_head = _nc_head->last) {
+ /* EMPTY */ ;
+ }
- DEBUG(1, ("head = %s", _nc_head->tterm.term_names));
- DEBUG(1, ("tail = %s", _nc_tail->tterm.term_names));
+ DEBUG(2, ("head = %s", _nc_head->tterm.term_names));
+ DEBUG(2, ("tail = %s", _nc_tail->tterm.term_names));
}
#ifdef TRACE
else if (!immediate)
- DEBUG(1, ("no entries parsed"));
+ DEBUG(2, ("no entries parsed"));
#endif
_nc_suppress_warnings = oldsuppress;
+ DEBUG(2, (T_RETURN("")));
}
+#if 0 && NCURSES_XNAMES
+static unsigned
+find_capname(TERMTYPE2 *p, const char *name)
+{
+ unsigned num_names = NUM_EXT_NAMES(p);
+ unsigned n;
+ if (name != 0) {
+ for (n = 0; n < num_names; ++n) {
+ if (!strcmp(p->ext_Names[n], name))
+ break;
+ }
+ } else {
+ n = num_names + 1;
+ }
+ return n;
+}
+
+static int
+extended_captype(TERMTYPE2 *p, unsigned which)
+{
+ int result = UNDEF;
+ unsigned limit = 0;
+ limit += p->ext_Booleans;
+ if (limit != 0 && which < limit) {
+ result = BOOLEAN;
+ } else {
+ limit += p->ext_Numbers;
+ if (limit != 0 && which < limit) {
+ result = NUMBER;
+ } else {
+ limit += p->ext_Strings;
+ if (limit != 0 && which < limit) {
+ result = ((p->Strings[STRCOUNT + which] != CANCELLED_STRING)
+ ? STRING
+ : CANCEL);
+ } else if (which >= limit) {
+ result = CANCEL;
+ }
+ }
+ }
+ return result;
+}
+
+static const char *
+name_of_captype(int which)
+{
+ const char *result = "?";
+ switch (which) {
+ case BOOLEAN:
+ result = "boolean";
+ break;
+ case NUMBER:
+ result = "number";
+ break;
+ case STRING:
+ result = "string";
+ break;
+ }
+ return result;
+}
+
+#define valid_TERMTYPE2(p) \
+ ((p) != 0 && \
+ (p)->term_names != 0 && \
+ (p)->ext_Names != 0)
+
+/*
+ * Disallow changing the type of an extended capability when doing a "use"
+ * if one or the other is a string.
+ */
+static int
+invalid_merge(TERMTYPE2 *to, TERMTYPE2 *from)
+{
+ int rc = FALSE;
+ if (valid_TERMTYPE2(to)
+ && valid_TERMTYPE2(from)) {
+ char *to_name = _nc_first_name(to->term_names);
+ char *from_name = strdup(_nc_first_name(from->term_names));
+ unsigned num_names = NUM_EXT_NAMES(from);
+ unsigned n;
+
+ for (n = 0; n < num_names; ++n) {
+ const char *capname = from->ext_Names[n];
+ int tt = extended_captype(to, find_capname(to, capname));
+ int tf = extended_captype(from, n);
+
+ if (tt <= STRING
+ && tf <= STRING
+ && (tt == STRING) != (tf == STRING)) {
+ if (from_name != 0 && strcmp(to_name, from_name)) {
+ _nc_warning("merge of %s to %s changes type of %s from %s to %s",
+ from_name,
+ to_name,
+ from->ext_Names[n],
+ name_of_captype(tf),
+ name_of_captype(tt));
+ } else {
+ _nc_warning("merge of %s changes type of %s from %s to %s",
+ to_name,
+ from->ext_Names[n],
+ name_of_captype(tf),
+ name_of_captype(tt));
+ }
+ rc = TRUE;
+ }
+ }
+ free(from_name);
+ }
+ return rc;
+}
+#define validate_merge(p, q) \
+ if (invalid_merge(&((p)->tterm), &((q)->tterm))) \
+ return FALSE
+#else
+#define validate_merge(p, q) /* nothing */
+#endif
+
NCURSES_EXPORT(int)
_nc_resolve_uses2(bool fullresolve, bool literal)
/* try to resolve all use capabilities */
{
ENTRY *qp, *rp, *lastread = 0;
bool keepgoing;
- unsigned i;
- int unresolved, total_unresolved, multiples;
+ unsigned i, j;
+ int total_unresolved, multiples;
- DEBUG(2, ("RESOLUTION BEGINNING"));
+ DEBUG(2, (T_CALLED("_nc_resolve_uses2")));
/*
* Check for multiple occurrences of the same name.
@@ -285,7 +415,7 @@
for_entry_list(qp) {
int matchcount = 0;
- for_entry_list(rp) {
+ for_entry_list2(rp, qp->next) {
if (qp > rp
&& check_collisions(qp->tterm.term_names,
rp->tterm.term_names,
@@ -301,8 +431,10 @@
}
}
}
- if (multiples > 0)
+ if (multiples > 0) {
+ DEBUG(2, (T_RETURN("false")));
return (FALSE);
+ }
DEBUG(2, ("NO MULTIPLE NAME OCCURRENCES"));
@@ -312,13 +444,15 @@
total_unresolved = 0;
_nc_curr_col = -1;
for_entry_list(qp) {
- unresolved = 0;
for (i = 0; i < qp->nuses; i++) {
bool foundit;
char *child = _nc_first_name(qp->tterm.term_names);
char *lookfor = qp->uses[i].name;
long lookline = qp->uses[i].line;
+ if (lookfor == 0)
+ continue;
+
foundit = FALSE;
_nc_set_type(child);
@@ -327,21 +461,31 @@
for_entry_list(rp) {
if (rp != qp
&& _nc_name_match(rp->tterm.term_names, lookfor, "|")) {
- DEBUG(2, ("%s: resolving use=%s (in core)",
- child, lookfor));
+ DEBUG(2, ("%s: resolving use=%s %p (in core)",
+ child, lookfor, lookfor));
qp->uses[i].link = rp;
foundit = TRUE;
+
+ /* verify that there are no earlier uses */
+ for (j = 0; j < i; ++j) {
+ if (qp->uses[j].link != NULL
+ && !strcmp(qp->uses[j].link->tterm.term_names,
+ rp->tterm.term_names)) {
+ _nc_warning("duplicate use=%s", lookfor);
+ break;
+ }
+ }
}
}
/* if that didn't work, try to merge in a compiled entry */
if (!foundit) {
- TERMTYPE thisterm;
+ TERMTYPE2 thisterm;
char filename[PATH_MAX];
memset(&thisterm, 0, sizeof(thisterm));
- if (_nc_read_entry(lookfor, filename, &thisterm) == 1) {
+ if (_nc_read_entry2(lookfor, filename, &thisterm) == 1) {
DEBUG(2, ("%s: resolving use=%s (compiled)",
child, lookfor));
@@ -353,12 +497,21 @@
qp->uses[i].link = rp;
foundit = TRUE;
+
+ /* verify that there are no earlier uses */
+ for (j = 0; j < i; ++j) {
+ if (qp->uses[j].link != NULL
+ && !strcmp(qp->uses[j].link->tterm.term_names,
+ rp->tterm.term_names)) {
+ _nc_warning("duplicate use=%s", lookfor);
+ break;
+ }
+ }
}
}
/* no good, mark this one unresolvable and complain */
if (!foundit) {
- unresolved++;
total_unresolved++;
_nc_curr_line = (int) lookline;
@@ -370,6 +523,7 @@
if (total_unresolved) {
/* free entries read in off disk */
_nc_free_entries(lastread);
+ DEBUG(2, (T_RETURN("false")));
return (FALSE);
}
@@ -382,25 +536,28 @@
*/
if (fullresolve) {
do {
- TERMTYPE merged;
+ ENTRY merged;
keepgoing = FALSE;
for_entry_list(qp) {
if (qp->nuses > 0) {
- DEBUG(2, ("%s: attempting merge",
- _nc_first_name(qp->tterm.term_names)));
+ DEBUG(2, ("%s: attempting merge of %d entries",
+ _nc_first_name(qp->tterm.term_names),
+ qp->nuses));
/*
* If any of the use entries we're looking for is
* incomplete, punt. We'll catch this entry on a
* subsequent pass.
*/
- for (i = 0; i < qp->nuses; i++)
- if (qp->uses[i].link->nuses) {
+ for (i = 0; i < qp->nuses; i++) {
+ if (qp->uses[i].link
+ && qp->uses[i].link->nuses) {
DEBUG(2, ("%s: use entry %d unresolved",
_nc_first_name(qp->tterm.term_names), i));
goto incomplete;
}
+ }
/*
* First, make sure there is no garbage in the
@@ -408,20 +565,24 @@
* the merged entry the name field and string
* table pointer.
*/
- _nc_copy_termtype(&merged, &(qp->tterm));
+ _nc_copy_termtype2(&(merged.tterm), &(qp->tterm));
/*
* Now merge in each use entry in the proper
* (reverse) order.
*/
- for (; qp->nuses; qp->nuses--)
- _nc_merge_entry(&merged,
- &qp->uses[qp->nuses - 1].link->tterm);
+ for (; qp->nuses; qp->nuses--) {
+ int n = (int) (qp->nuses - 1);
+ validate_merge(&merged, qp->uses[n].link);
+ _nc_merge_entry(&merged, qp->uses[n].link);
+ free(qp->uses[n].name);
+ }
/*
* Now merge in the original entry.
*/
- _nc_merge_entry(&merged, &qp->tterm);
+ validate_merge(&merged, qp);
+ _nc_merge_entry(&merged, qp);
/*
* Replace the original entry with the merged one.
@@ -429,10 +590,12 @@
FreeIfNeeded(qp->tterm.Booleans);
FreeIfNeeded(qp->tterm.Numbers);
FreeIfNeeded(qp->tterm.Strings);
+ FreeIfNeeded(qp->tterm.str_table);
#if NCURSES_XNAMES
FreeIfNeeded(qp->tterm.ext_Names);
+ FreeIfNeeded(qp->tterm.ext_str_table);
#endif
- qp->tterm = merged;
+ qp->tterm = merged.tterm;
_nc_wrap_entry(qp, TRUE);
/*
@@ -450,63 +613,57 @@
DEBUG(2, ("MERGES COMPLETED OK"));
}
- /*
- * We'd like to free entries read in off disk at this point, but can't.
- * The merge_entry() code doesn't copy the strings in the use entries,
- * it just aliases them. If this ever changes, do a
- * free_entries(lastread) here.
- */
-
DEBUG(2, ("RESOLUTION FINISHED"));
- if (fullresolve)
- if (_nc_check_termtype != 0) {
- _nc_curr_col = -1;
- for_entry_list(qp) {
- _nc_curr_line = (int) qp->startline;
- _nc_set_type(_nc_first_name(qp->tterm.term_names));
+ if (fullresolve) {
+ _nc_curr_col = -1;
+ for_entry_list(qp) {
+ _nc_curr_line = (int) qp->startline;
+ _nc_set_type(_nc_first_name(qp->tterm.term_names));
+ /*
+ * tic overrides this function pointer to provide more verbose
+ * checking.
+ */
+ if (_nc_check_termtype2 != sanity_check2) {
+ SCREEN *save_SP = SP;
+ SCREEN fake_sp;
+ TERMINAL fake_tm;
+ TERMINAL *save_tm = cur_term;
+
/*
- * tic overrides this function pointer to provide more verbose
- * checking.
+ * Setup so that tic can use ordinary terminfo interface to
+ * obtain capability information.
*/
- if (_nc_check_termtype2 != sanity_check2) {
- SCREEN *save_SP = SP;
- SCREEN fake_sp;
- TERMINAL fake_tm;
- TERMINAL *save_tm = cur_term;
+ memset(&fake_sp, 0, sizeof(fake_sp));
+ memset(&fake_tm, 0, sizeof(fake_tm));
+ fake_sp._term = &fake_tm;
+ TerminalType(&fake_tm) = qp->tterm;
+ _nc_set_screen(&fake_sp);
+ set_curterm(&fake_tm);
- /*
- * Setup so that tic can use ordinary terminfo interface
- * to obtain capability information.
- */
- memset(&fake_sp, 0, sizeof(fake_sp));
- memset(&fake_tm, 0, sizeof(fake_tm));
- fake_sp._term = &fake_tm;
- fake_tm.type = qp->tterm;
- _nc_set_screen(&fake_sp);
- set_curterm(&fake_tm);
+ _nc_check_termtype2(&qp->tterm, literal);
- _nc_check_termtype2(&qp->tterm, literal);
+ /*
+ * Checking calls tparm, which can allocate memory. Fix leaks.
+ */
+#define TPS(name) fake_tm.tparm_state.name
+ FreeAndNull(TPS(out_buff));
+ FreeAndNull(TPS(fmt_buff));
+#undef TPS
- _nc_set_screen(save_SP);
- set_curterm(save_tm);
- } else {
- fixup_acsc(&qp->tterm, literal);
- }
+ _nc_set_screen(save_SP);
+ set_curterm(save_tm);
+ } else {
+ fixup_acsc(&qp->tterm, literal);
}
- DEBUG(2, ("SANITY CHECK FINISHED"));
}
+ DEBUG(2, ("SANITY CHECK FINISHED"));
+ }
+ DEBUG(2, (T_RETURN("true")));
return (TRUE);
}
-/* obsolete: 20040705 */
-NCURSES_EXPORT(int)
-_nc_resolve_uses(bool fullresolve)
-{
- return _nc_resolve_uses2(fullresolve, FALSE);
-}
-
/*
* This bit of legerdemain turns all the terminfo variable names into
* references to locations in the arrays Booleans, Numbers, and Strings ---
@@ -517,18 +674,18 @@
#define CUR tp->
static void
-fixup_acsc(TERMTYPE *tp, int literal)
+fixup_acsc(TERMTYPE2 *tp, int literal)
{
if (!literal) {
- if (acs_chars == 0
- && enter_alt_charset_mode != 0
- && exit_alt_charset_mode != 0)
+ if (acs_chars == ABSENT_STRING
+ && PRESENT(enter_alt_charset_mode)
+ && PRESENT(exit_alt_charset_mode))
acs_chars = strdup(VT_ACSC);
}
}
static void
-sanity_check2(TERMTYPE *tp, bool literal)
+sanity_check2(TERMTYPE2 *tp, bool literal)
{
if (!PRESENT(exit_attribute_mode)) {
#ifdef __UNUSED__ /* this casts too wide a net */
@@ -547,7 +704,9 @@
#endif /* __UNUSED__ */
PAIRED(enter_standout_mode, exit_standout_mode);
PAIRED(enter_underline_mode, exit_underline_mode);
+#if defined(enter_italics_mode) && defined(exit_italics_mode)
PAIRED(enter_italics_mode, exit_italics_mode);
+#endif
}
/* we do this check/fix in postprocess_termcap(), but some packagers
@@ -578,23 +737,18 @@
PAIRED(enter_xon_mode, exit_xon_mode);
PAIRED(enter_am_mode, exit_am_mode);
ANDMISSING(label_off, label_on);
-#ifdef remove_clock
+#if defined(display_clock) && defined(remove_clock)
PAIRED(display_clock, remove_clock);
#endif
ANDMISSING(set_color_pair, initialize_pair);
}
-/* obsolete: 20040705 */
-static void
-sanity_check(TERMTYPE *tp)
-{
- sanity_check2(tp, FALSE);
-}
-
#if NO_LEAKS
NCURSES_EXPORT(void)
_nc_leaks_tic(void)
{
+ T((T_CALLED("_nc_leaks_tic()")));
+ _nc_globals.leak_checking = TRUE;
_nc_alloc_entry_leaks();
_nc_captoinfo_leaks();
_nc_comp_scan_leaks();
@@ -603,12 +757,14 @@
_nc_codes_leaks();
#endif
_nc_tic_expand(0, FALSE, 0);
+ T((T_RETURN("")));
}
NCURSES_EXPORT(void)
_nc_free_tic(int code)
{
+ T((T_CALLED("_nc_free_tic(%d)"), code));
_nc_leaks_tic();
- _nc_free_tinfo(code);
+ exit_terminfo(code);
}
#endif
diff --git a/ncurses/tinfo/comp_scan.c b/ncurses/tinfo/comp_scan.c
index fe6e8e7..3ba0835 100644
--- a/ncurses/tinfo/comp_scan.c
+++ b/ncurses/tinfo/comp_scan.c
@@ -1,5 +1,6 @@
/****************************************************************************
- * Copyright (c) 1998-2012,2013 Free Software Foundation, Inc. *
+,* Copyright 2020-2022,2023 Thomas E. Dickey *
+ * Copyright 1998-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 *
@@ -50,7 +51,7 @@
#include <ctype.h>
#include <tic.h>
-MODULE_ID("$Id: comp_scan.c,v 1.102 2013/11/16 19:57:50 tom Exp $")
+MODULE_ID("$Id: comp_scan.c,v 1.122 2023/05/27 20:13:10 tom Exp $")
/*
* Maximum length of string capability we'll accept before raising an error.
@@ -111,6 +112,9 @@
NCURSES_EXPORT(void)
_nc_reset_input(FILE *fp, char *buf)
{
+ TR(TRACE_DATABASE,
+ (T_CALLED("_nc_reset_input(fp=%p, buf=%p)"), (void *) fp, buf));
+
pushtype = NO_PUSHBACK;
if (pushname != 0)
pushname[0] = '\0';
@@ -120,6 +124,8 @@
if (fp != 0)
_nc_curr_line = 0;
_nc_curr_col = 0;
+
+ returnVoidDB;
}
/*
@@ -135,7 +141,7 @@
while (len--) {
if (!isspace(UChar(bufptr[len]))) {
- if (from_end < (int) len)
+ if (from_end <= (int) len)
result = bufptr[(int) len - from_end];
break;
}
@@ -144,6 +150,32 @@
}
/*
+ * Read, like fgets(), but error-out if the input contains nulls.
+ */
+static int
+get_text(char *buffer, int length)
+{
+ int count = 0;
+ int limit = length - 1;
+
+ while (limit-- > 0) {
+ int ch = fgetc(yyin);
+
+ if (ch == '\0') {
+ _nc_err_abort("This is not a text-file");
+ } else if (ch == EOF) {
+ break;
+ }
+ ++count;
+ *buffer++ = (char) ch;
+ if (ch == '\n')
+ break;
+ }
+ *buffer = '\0';
+ return count;
+}
+
+/*
* int next_char()
*
* Returns the next character in the input stream. Comments and leading
@@ -168,6 +200,8 @@
if (result != 0) {
FreeAndNull(result);
FreeAndNull(pushname);
+ bufptr = 0;
+ bufstart = 0;
allocated = 0;
}
/*
@@ -189,12 +223,11 @@
* quite hard to get completely right. Try it and see. If you
* succeed, don't forget to hack push_back() correspondingly.
*/
- size_t used;
size_t len;
do {
+ size_t used = 0;
bufstart = 0;
- used = 0;
do {
if (used + (LEXBUFSIZ / 4) >= allocated) {
allocated += (allocated + LEXBUFSIZ);
@@ -207,7 +240,7 @@
if (used == 0)
_nc_curr_file_pos = ftell(yyin);
- if (fgets(result + used, (int) (allocated - used), yyin) != 0) {
+ if (get_text(result + used, (int) (allocated - used))) {
bufstart = result;
if (used == 0) {
if (_nc_curr_line == 0
@@ -223,6 +256,8 @@
}
if ((bufptr = bufstart) != 0) {
used = strlen(bufptr);
+ if (used == 0)
+ return (EOF);
while (iswhite(*bufptr)) {
if (*bufptr == '\t') {
_nc_curr_col = (_nc_curr_col | 7) + 1;
@@ -267,7 +302,7 @@
/* push a character back onto the input stream */
{
if (bufptr == bufstart)
- _nc_syserr_abort("Can't backspace off beginning of line");
+ _nc_syserr_abort("cannot backspace off beginning of line");
*--bufptr = (char) c;
_nc_curr_col--;
}
@@ -276,14 +311,16 @@
stream_pos(void)
/* return our current character position in the input stream */
{
- return (yyin ? ftell(yyin) : (bufptr ? bufptr - bufstart : 0));
+ return (yyin ? ftell(yyin) : (bufptr ? (long) (bufptr - bufstart) : 0));
}
static bool
end_of_stream(void)
/* are we at end of input? */
{
- return ((yyin ? feof(yyin) : (bufptr && *bufptr == '\0'))
+ return ((yyin
+ ? (feof(yyin) && (bufptr == NULL || *bufptr == '\0'))
+ : (bufptr && *bufptr == '\0'))
? TRUE : FALSE);
}
@@ -291,9 +328,11 @@
static NCURSES_INLINE int
eat_escaped_newline(int ch)
{
- if (ch == '\\')
- while ((ch = next_char()) == '\n' || iswhite(ch))
- continue;
+ if (ch == '\\') {
+ while ((ch = next_char()) == '\n' || iswhite(ch)) {
+ /* EMPTY */ ;
+ }
+ }
return ch;
}
@@ -363,6 +402,8 @@
int old_col;
#endif
+ DEBUG(3, (T_CALLED("_nc_get_token(silent=%d)"), silent));
+
if (pushtype != NO_PUSHBACK) {
int retval = pushtype;
@@ -375,6 +416,7 @@
pushname[0] = '\0';
/* currtok wasn't altered by _nc_push_token() */
+ DEBUG(3, (T_RETURN("%d"), retval));
return (retval);
}
@@ -385,6 +427,7 @@
if (_nc_curr_token.tk_name == tok_buf)
_nc_curr_token.tk_name = 0;
}
+ DEBUG(3, (T_RETURN("%d"), EOF));
return (EOF);
}
@@ -393,7 +436,6 @@
while ((ch = next_char()) == '\n' || iswhite(ch)) {
if (ch == '\n')
had_newline = TRUE;
- continue;
}
ch = eat_escaped_newline(ch);
@@ -418,8 +460,9 @@
dot_flag = TRUE;
DEBUG(8, ("dot-flag set"));
- while ((ch = next_char()) == '.' || iswhite(ch))
- continue;
+ while ((ch = next_char()) == '.' || iswhite(ch)) {
+ /* EMPTY */ ;
+ }
}
if (ch == EOF) {
@@ -552,7 +595,7 @@
* Grrr...what we ought to do here is barf, complaining that
* the entry is malformed. But because a couple of name fields
* in the 8.2 termcap file end with |\, we just have to assume
- * it's termcap syntax.
+ * it is termcap syntax.
*/
_nc_syntax = SYN_TERMCAP;
separator = ':';
@@ -560,8 +603,9 @@
/* throw away trailing /, *$/ */
for (--tok_ptr;
iswhite(*tok_ptr) || *tok_ptr == ',';
- tok_ptr--)
- continue;
+ tok_ptr--) {
+ /* EMPTY */ ;
+ }
tok_ptr[1] = '\0';
}
@@ -583,14 +627,15 @@
*/
if (after_list != 0) {
if (!silent) {
- if (*after_list == '\0')
+ if (*after_list == '\0' || strchr("|", after_list[1]) != NULL) {
_nc_warning("empty longname field");
- else if (strchr(after_list, ' ') == 0)
+ } else if (strchr(after_list, ' ') == 0) {
_nc_warning("older tic versions may treat the description field as an alias");
+ }
}
} else {
after_list = tok_buf + strlen(tok_buf);
- DEBUG(1, ("missing description"));
+ DEBUG(2, ("missing description"));
}
/*
@@ -669,7 +714,15 @@
if (numchk == numbuf)
_nc_warning("no value given for `%s'", tok_buf);
if ((*numchk != '\0') || (ch != separator))
- _nc_warning("Missing separator");
+ _nc_warning("Missing separator for `%s'", tok_buf);
+ if (number < 0)
+ _nc_warning("value of `%s' cannot be negative", tok_buf);
+ if (number > MAX_OF_TYPE(NCURSES_INT2)) {
+ _nc_warning("limiting value of `%s' from %#lx to %#x",
+ tok_buf,
+ number, MAX_OF_TYPE(NCURSES_INT2));
+ number = MAX_OF_TYPE(NCURSES_INT2);
+ }
}
_nc_curr_token.tk_name = tok_buf;
_nc_curr_token.tk_valnumber = (int) number;
@@ -757,6 +810,7 @@
: "<null>"),
type));
+ DEBUG(3, (T_RETURN("%d"), type));
return (type);
}
@@ -780,7 +834,7 @@
*/
NCURSES_EXPORT(int)
-_nc_trans_string(char *ptr, char *last)
+_nc_trans_string(char *ptr, const char *const last)
{
int count = 0;
int number = 0;
@@ -810,8 +864,6 @@
}
if (c == '?' && (_nc_syntax != SYN_TERMCAP)) {
*(ptr++) = '\177';
- if (_nc_tracing)
- _nc_warning("Allow ^? as synonym for \\177");
} else {
if ((c &= 037) == 0)
c = 128;
@@ -824,8 +876,6 @@
if (c == EOF)
_nc_err_abort(MSG_NO_INPUTS);
-#define isoctal(c) ((c) >= '0' && (c) <= '7')
-
if (isoctal(c) || (strict_bsd && isdigit(c))) {
number = c - '0';
for (i = 0; i < 2; i++) {
@@ -990,10 +1040,8 @@
NCURSES_EXPORT(void)
_nc_panic_mode(char ch)
{
- int c;
-
for (;;) {
- c = next_char();
+ int c = next_char();
if (c == ch)
return;
if (c == EOF)
diff --git a/ncurses/tinfo/db_iterator.c b/ncurses/tinfo/db_iterator.c
index 94a4082..db3872e 100644
--- a/ncurses/tinfo/db_iterator.c
+++ b/ncurses/tinfo/db_iterator.c
@@ -1,5 +1,6 @@
/****************************************************************************
- * Copyright (c) 2006-2013,2014 Free Software Foundation, Inc. *
+ * Copyright 2018-2022,2023 Thomas E. Dickey *
+ * Copyright 2006-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 *
@@ -43,7 +44,7 @@
#include <hashed_db.h>
#endif
-MODULE_ID("$Id: db_iterator.c,v 1.39 2014/11/01 14:47:00 tom Exp $")
+MODULE_ID("$Id: db_iterator.c,v 1.50 2023/06/24 21:52:32 tom Exp $")
#define HaveTicDirectory _nc_globals.have_tic_directory
#define KeepTicDirectory _nc_globals.keep_tic_directory
@@ -72,15 +73,18 @@
{
bool result = FALSE;
- if (stat(name, sb) == 0
- && (S_ISDIR(sb->st_mode) || S_ISREG(sb->st_mode))) {
+ if (quick_prefix(name)) {
+ result = TRUE;
+ } else if (stat(name, sb) == 0
+ && (S_ISDIR(sb->st_mode)
+ || (S_ISREG(sb->st_mode) && sb->st_size))) {
result = TRUE;
}
#if USE_HASHED_DB
else if (strlen(name) < PATH_MAX - sizeof(DBM_SUFFIX)) {
char temp[PATH_MAX];
_nc_SPRINTF(temp, _nc_SLIMIT(sizeof(temp)) "%s%s", name, DBM_SUFFIX);
- if (stat(temp, sb) == 0 && S_ISREG(sb->st_mode)) {
+ if (stat(temp, sb) == 0 && S_ISREG(sb->st_mode) && sb->st_size) {
result = TRUE;
}
}
@@ -89,6 +93,27 @@
}
/*
+ * Trim newlines (and backslashes preceding those) and tab characters to
+ * help simplify scripting of the quick-dump feature. Leave spaces and
+ * other backslashes alone.
+ */
+static void
+trim_formatting(char *source)
+{
+ char *target = source;
+ char ch;
+
+ while ((ch = *source++) != '\0') {
+ if (ch == '\\' && *source == '\n')
+ continue;
+ if (ch == '\n' || ch == '\t')
+ continue;
+ *target++ = ch;
+ }
+ *target = '\0';
+}
+
+/*
* Store the latest value of an environment variable in my_vars[] so we can
* detect if one changes, invalidating the cached search-list.
*/
@@ -99,19 +124,21 @@
if (which < dbdLAST) {
char *value;
+ char *cached_value = my_vars[which].value;
+ bool same_value;
- if ((value = getenv(name)) == 0 || (value = strdup(value)) == 0) {
- ;
- } else if (my_vars[which].name == 0 || strcmp(my_vars[which].name, name)) {
- FreeIfNeeded(my_vars[which].value);
- my_vars[which].name = name;
- my_vars[which].value = value;
- result = TRUE;
- } else if ((my_vars[which].value != 0) ^ (value != 0)) {
- FreeIfNeeded(my_vars[which].value);
- my_vars[which].value = value;
- result = TRUE;
- } else if (value != 0 && strcmp(value, my_vars[which].value)) {
+ if ((value = getenv(name)) != 0) {
+ value = strdup(value);
+ }
+ same_value = ((value == 0 && cached_value == 0) ||
+ (value != 0 &&
+ cached_value != 0 &&
+ strcmp(value, cached_value) == 0));
+
+ /* Set variable name to enable checks in cache_expired(). */
+ my_vars[which].name = name;
+
+ if (!same_value) {
FreeIfNeeded(my_vars[which].value);
my_vars[which].value = value;
result = TRUE;
@@ -122,6 +149,7 @@
return result;
}
+#if NCURSES_USE_DATABASE || NCURSES_USE_TERMCAP
static char *
cache_getenv(const char *name, DBDIRS which)
{
@@ -133,6 +161,7 @@
}
return result;
}
+#endif
/*
* The cache expires if at least a second has passed since the initial lookup,
@@ -173,6 +202,13 @@
FreeAndNull(my_list);
}
+static void
+update_tic_dir(const char *update)
+{
+ free((char *) TicDirectory);
+ TicDirectory = update;
+}
+
/*
* Record the "official" location of the terminfo directory, according to
* the place where we're writing to, or the normal default, if not.
@@ -182,8 +218,9 @@
{
T(("_nc_tic_dir %s", NonNull(path)));
if (!KeepTicDirectory) {
- if (path != 0) {
- TicDirectory = path;
+ if (path != NULL) {
+ if (path != TicDirectory)
+ update_tic_dir(strdup(path));
HaveTicDirectory = TRUE;
} else if (HaveTicDirectory == 0) {
if (use_terminfo_vars()) {
@@ -251,7 +288,7 @@
*state = dbdTIC;
*offset = 0;
- T(("_nc_first_db"));
+ T((T_CALLED("_nc_first_db")));
/* build a blob containing all of the strings we will use for a lookup
* table.
@@ -260,7 +297,7 @@
size_t blobsize = 0;
const char *values[dbdLAST];
struct stat *my_stat;
- int j, k;
+ int j;
if (cache_has_expired)
free_cache();
@@ -330,10 +367,12 @@
my_list = typeCalloc(char *, blobsize);
my_stat = typeCalloc(struct stat, blobsize);
if (my_list != 0 && my_stat != 0) {
- k = 0;
+ int k = 0;
my_list[k++] = my_blob;
for (j = 0; my_blob[j] != '\0'; ++j) {
- if (my_blob[j] == NCURSES_PATHSEP) {
+ if (my_blob[j] == NCURSES_PATHSEP
+ && ((&my_blob[j] - my_list[k - 1]) != 3
+ || !quick_prefix(my_list[k - 1]))) {
my_blob[j] = '\0';
my_list[k++] = &my_blob[j + 1];
}
@@ -344,11 +383,16 @@
*/
for (j = 0; my_list[j] != 0; ++j) {
#ifdef TERMINFO
- if (*my_list[j] == '\0')
- my_list[j] = strdup(TERMINFO);
+ if (*my_list[j] == '\0') {
+ char *my_copy = strdup(TERMINFO);
+ if (my_copy != 0)
+ my_list[j] = my_copy;
+ }
#endif
+ trim_formatting(my_list[j]);
for (k = 0; k < j; ++k) {
if (!strcmp(my_list[j], my_list[k])) {
+ T(("duplicate %s", my_list[j]));
k = j - 1;
while ((my_list[j] = my_list[j + 1]) != 0) {
++j;
@@ -377,6 +421,7 @@
}
#endif
if (!found) {
+ T(("not found %s", my_list[j]));
k = j;
while ((my_list[k] = my_list[k + 1]) != 0) {
++k;
@@ -392,6 +437,7 @@
free(my_stat);
}
}
+ returnVoid;
}
#if NO_LEAKS
@@ -409,5 +455,6 @@
FreeIfNeeded(my_vars[which].value);
my_vars[which].value = 0;
}
+ update_tic_dir(NULL);
}
#endif
diff --git a/ncurses/tinfo/doalloc.c b/ncurses/tinfo/doalloc.c
index 7c502b0..e3b1a2e 100644
--- a/ncurses/tinfo/doalloc.c
+++ b/ncurses/tinfo/doalloc.c
@@ -1,5 +1,6 @@
/****************************************************************************
- * Copyright (c) 1998-2000,2012 Free Software Foundation, Inc. *
+ * Copyright 2020,2021 Thomas E. Dickey *
+ * Copyright 1998-2002,2012 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 *
@@ -39,15 +40,18 @@
#include <curses.priv.h>
-MODULE_ID("$Id: doalloc.c,v 1.11 2012/11/03 19:27:41 tom Exp $")
+MODULE_ID("$Id: doalloc.c,v 1.14 2021/04/24 23:43:39 tom Exp $")
-NCURSES_EXPORT(void *)
+void *
_nc_doalloc(void *oldp, size_t amount)
{
void *newp;
- if (oldp != 0) {
- if ((newp = realloc(oldp, amount)) == 0) {
+ if (oldp != NULL) {
+ if (amount == 0) {
+ free(oldp);
+ newp = NULL;
+ } else if ((newp = realloc(oldp, amount)) == 0) {
free(oldp);
errno = ENOMEM; /* just in case 'free' reset */
}
diff --git a/ncurses/tinfo/entries.c b/ncurses/tinfo/entries.c
index e84033d..f47fd3f 100644
--- a/ncurses/tinfo/entries.c
+++ b/ncurses/tinfo/entries.c
@@ -1,5 +1,6 @@
/****************************************************************************
- * Copyright (c) 2006-2011,2012 Free Software Foundation, Inc. *
+ * Copyright 2019-2022,2023 Thomas E. Dickey *
+ * Copyright 2006-2012,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 *
@@ -37,7 +38,7 @@
#include <tic.h>
-MODULE_ID("$Id: entries.c,v 1.21 2012/05/05 20:33:44 tom Exp $")
+MODULE_ID("$Id: entries.c,v 1.35 2023/05/27 20:13:10 tom Exp $")
/****************************************************************************
*
@@ -63,30 +64,8 @@
NCURSES_EXPORT_VAR(ENTRY *) _nc_head = 0;
NCURSES_EXPORT_VAR(ENTRY *) _nc_tail = 0;
-NCURSES_EXPORT(void)
-_nc_free_entry(ENTRY * headp, TERMTYPE *tterm)
-/* free the allocated storage consumed by the given list entry */
-{
- ENTRY *ep;
-
- if ((ep = _nc_delink_entry(headp, tterm)) != 0) {
- free(ep);
- }
-}
-
-NCURSES_EXPORT(void)
-_nc_free_entries(ENTRY * headp)
-/* free the allocated storage consumed by list entries */
-{
- (void) headp; /* unused - _nc_head is altered here! */
-
- while (_nc_head != 0) {
- _nc_free_termtype(&(_nc_head->tterm));
- }
-}
-
-NCURSES_EXPORT(ENTRY *)
-_nc_delink_entry(ENTRY * headp, TERMTYPE *tterm)
+static ENTRY *
+_nc_delink_entry(ENTRY * headp, const TERMTYPE2 *const tterm)
/* delink the allocated storage for the given list entry */
{
ENTRY *ep, *last;
@@ -112,22 +91,63 @@
}
NCURSES_EXPORT(void)
+_nc_free_entry(ENTRY * headp, TERMTYPE2 *tterm)
+/* free the allocated storage consumed by the given list entry */
+{
+ ENTRY *ep;
+
+ if ((ep = _nc_delink_entry(headp, tterm)) != 0) {
+ free(ep);
+ }
+}
+
+NCURSES_EXPORT(void)
+_nc_free_entries(ENTRY * headp)
+/* free the allocated storage consumed by list entries */
+{
+ (void) headp; /* unused - _nc_head is altered here! */
+
+ while (_nc_head != 0) {
+ _nc_free_termtype2(&(_nc_head->tterm));
+ }
+}
+
+NCURSES_EXPORT(void)
_nc_leaks_tinfo(void)
{
#if NO_LEAKS
char *s;
#endif
- T((T_CALLED("_nc_free_tinfo()")));
+ T((T_CALLED("_nc_leaks_tinfo()")));
#if NO_LEAKS
- _nc_free_tparm();
+ _nc_globals.leak_checking = TRUE;
+ _nc_free_tparm(cur_term);
_nc_tgetent_leaks();
+#ifdef USE_PTHREADS
+ /*
+ * Discard any prescreen data which is not used for the current screen.
+ */
+ _nc_lock_global(screen);
+ {
+ PRESCREEN_LIST *p;
+ pthread_t id = GetThreadID();
+ for (p = _nc_prescreen.allocated; p != 0; p = p->next) {
+ if (p->id == id && p->sp != CURRENT_SCREEN) {
+ FreeAndNull(p->sp);
+ }
+ }
+ }
+ _nc_unlock_global(screen);
+#endif
if (TerminalOf(CURRENT_SCREEN) != 0) {
del_curterm(TerminalOf(CURRENT_SCREEN));
}
+ _nc_forget_prescr();
_nc_comp_captab_leaks();
+ _nc_comp_userdefs_leaks();
_nc_free_entries(_nc_head);
_nc_get_type(0);
_nc_first_name(0);
@@ -144,7 +164,8 @@
free(s);
#ifdef TRACE
- trace(0);
+ T((T_RETURN("")));
+ curses_trace(0);
_nc_trace_buf(-1, (size_t) 0);
#endif
@@ -156,7 +177,18 @@
NCURSES_EXPORT(void)
_nc_free_tinfo(int code)
{
+ T((T_CALLED("_nc_free_tinfo(%d)"), code));
_nc_leaks_tinfo();
exit(code);
}
#endif
+
+NCURSES_EXPORT(void)
+exit_terminfo(int code)
+{
+ T((T_CALLED("exit_terminfo(%d)"), code));
+#if NO_LEAKS
+ _nc_leaks_tinfo();
+#endif
+ exit(code);
+}
diff --git a/ncurses/tinfo/free_ttype.c b/ncurses/tinfo/free_ttype.c
index ad056ba..7935152 100644
--- a/ncurses/tinfo/free_ttype.c
+++ b/ncurses/tinfo/free_ttype.c
@@ -1,5 +1,6 @@
/****************************************************************************
- * Copyright (c) 1999-2010,2011 Free Software Foundation, Inc. *
+ * Copyright 2020-2022,2023 Thomas E. Dickey *
+ * Copyright 1999-2011,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 *
@@ -42,25 +43,52 @@
#include <tic.h>
-MODULE_ID("$Id: free_ttype.c,v 1.15 2011/02/06 01:08:31 tom Exp $")
+MODULE_ID("$Id: free_ttype.c,v 1.22 2023/04/22 15:12:57 tom Exp $")
-NCURSES_EXPORT(void)
-_nc_free_termtype(TERMTYPE *ptr)
+static void
+really_free_termtype(TERMTYPE2 *ptr, bool freeStrings)
{
- T(("_nc_free_termtype(%s)", ptr->term_names));
+ T(("really_free_termtype(%s) %d", ptr->term_names, freeStrings));
- FreeIfNeeded(ptr->str_table);
+ if (freeStrings) {
+ FreeIfNeeded(ptr->str_table);
+ }
FreeIfNeeded(ptr->Booleans);
FreeIfNeeded(ptr->Numbers);
FreeIfNeeded(ptr->Strings);
#if NCURSES_XNAMES
- FreeIfNeeded(ptr->ext_str_table);
+ if (freeStrings) {
+ FreeIfNeeded(ptr->ext_str_table);
+ }
FreeIfNeeded(ptr->ext_Names);
#endif
memset(ptr, 0, sizeof(TERMTYPE));
_nc_free_entry(_nc_head, ptr);
}
+NCURSES_EXPORT(void)
+_nc_free_termtype(TERMTYPE *ptr)
+{
+ really_free_termtype((TERMTYPE2 *) ptr, !NCURSES_EXT_NUMBERS);
+}
+
+/*
+ * These similar entrypoints are not used outside of ncurses.
+ */
+NCURSES_EXPORT(void)
+_nc_free_termtype1(TERMTYPE *ptr)
+{
+ really_free_termtype((TERMTYPE2 *) ptr, TRUE);
+}
+
+#if NCURSES_EXT_NUMBERS
+NCURSES_EXPORT(void)
+_nc_free_termtype2(TERMTYPE2 *ptr)
+{
+ really_free_termtype(ptr, TRUE);
+}
+#endif
+
#if NCURSES_XNAMES
NCURSES_EXPORT_VAR(bool) _nc_user_definable = TRUE;
diff --git a/ncurses/tinfo/getenv_num.c b/ncurses/tinfo/getenv_num.c
index d5e35cb..ca179d3 100644
--- a/ncurses/tinfo/getenv_num.c
+++ b/ncurses/tinfo/getenv_num.c
@@ -1,5 +1,6 @@
/****************************************************************************
- * Copyright (c) 1998-2012,2013 Free Software Foundation, Inc. *
+ * Copyright 2018,2020 Thomas E. Dickey *
+ * Copyright 1998-2012,2013 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 *
@@ -36,7 +37,7 @@
#include <curses.priv.h>
-MODULE_ID("$Id: getenv_num.c,v 1.6 2013/09/28 20:25:08 tom Exp $")
+MODULE_ID("$Id: getenv_num.c,v 1.8 2020/02/02 23:34:34 tom Exp $")
NCURSES_EXPORT(int)
_nc_getenv_num(const char *name)
@@ -68,6 +69,8 @@
_nc_SPRINTF(buffer, _nc_SLIMIT(sizeof(buffer)) "%s=%d", name, value);
if ((s = strdup(buffer)) != 0)
putenv(s);
+#else
+#error expected setenv/putenv functions
#endif
}
}
diff --git a/ncurses/tinfo/hashed_db.c b/ncurses/tinfo/hashed_db.c
index b594205..b78d98f 100644
--- a/ncurses/tinfo/hashed_db.c
+++ b/ncurses/tinfo/hashed_db.c
@@ -1,5 +1,6 @@
/****************************************************************************
- * Copyright (c) 2006-2011,2013 Free Software Foundation, Inc. *
+ * Copyright 2019,2020 Thomas E. Dickey *
+ * Copyright 2006-2011,2013 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 *
@@ -36,7 +37,7 @@
#if USE_HASHED_DB
-MODULE_ID("$Id: hashed_db.c,v 1.17 2013/12/15 00:33:01 tom Exp $")
+MODULE_ID("$Id: hashed_db.c,v 1.19 2020/02/02 23:34:34 tom Exp $")
#if HASHED_DB_API >= 2
static DBC *cursor;
@@ -273,7 +274,7 @@
result = -1;
}
#else
- result = db->seq(db, key, data, 0);
+ result = db->seq(db, key, data, R_NEXT);
#endif
return result;
}
diff --git a/ncurses/tinfo/home_terminfo.c b/ncurses/tinfo/home_terminfo.c
index e77f71c..7e626df 100644
--- a/ncurses/tinfo/home_terminfo.c
+++ b/ncurses/tinfo/home_terminfo.c
@@ -1,5 +1,6 @@
/****************************************************************************
- * Copyright (c) 1998-2010,2012 Free Software Foundation, Inc. *
+ * Copyright 2020 Thomas E. Dickey *
+ * Copyright 1998-2012,2016 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 *
@@ -37,7 +38,7 @@
#include <curses.priv.h>
#include <tic.h>
-MODULE_ID("$Id: home_terminfo.c,v 1.15 2012/10/27 21:49:14 tom Exp $")
+MODULE_ID("$Id: home_terminfo.c,v 1.17 2020/02/02 23:34:34 tom Exp $")
/* ncurses extension...fall back on user's private directory */
@@ -48,10 +49,11 @@
{
char *result = 0;
#if USE_HOME_TERMINFO
- char *home;
-
if (use_terminfo_vars()) {
+
if (MyBuffer == 0) {
+ char *home;
+
if ((home = getenv("HOME")) != 0) {
size_t want = (strlen(home) + sizeof(PRIVATE_INFO));
TYPE_MALLOC(char, want, MyBuffer);
diff --git a/ncurses/tinfo/init_keytry.c b/ncurses/tinfo/init_keytry.c
index ea47b38..ef20dfb 100644
--- a/ncurses/tinfo/init_keytry.c
+++ b/ncurses/tinfo/init_keytry.c
@@ -1,5 +1,6 @@
/****************************************************************************
- * Copyright (c) 1999-2009,2010 Free Software Foundation, Inc. *
+ * Copyright 2020,2023 Thomas E. Dickey *
+ * Copyright 1999-2010,2016 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 *
@@ -29,7 +30,7 @@
#include <curses.priv.h>
#include <tic.h> /* struct tinfo_fkeys */
-MODULE_ID("$Id: init_keytry.c,v 1.17 2010/04/24 22:29:56 tom Exp $")
+MODULE_ID("$Id: init_keytry.c,v 1.20 2023/09/16 12:55:01 tom Exp $")
/*
** _nc_init_keytry()
@@ -66,7 +67,7 @@
NCURSES_EXPORT(void)
_nc_init_keytry(SCREEN *sp)
{
- unsigned n;
+ T(("_nc_init_keytry(%p)", (void *) sp));
/* The sp->_keytry value is initialized in newterm(), where the sp
* structure is created, because we can not tell where keypad() or
@@ -74,6 +75,8 @@
*/
if (sp != 0) {
+ unsigned n;
+
for (n = 0; _nc_tinfo_fkeys[n].code; n++) {
if (_nc_tinfo_fkeys[n].offset < STRCOUNT) {
(void) _nc_add_to_try(&(sp->_keytry),
@@ -94,7 +97,7 @@
char *value = tp->Strings[n];
if (name != 0
&& *name == 'k'
- && value != 0
+ && VALID_STRING(value)
&& NCURSES_SP_NAME(key_defined) (NCURSES_SP_ARGx
value) == 0) {
(void) _nc_add_to_try(&(sp->_keytry),
diff --git a/ncurses/tinfo/lib_acs.c b/ncurses/tinfo/lib_acs.c
index 69a1851..4ede53f 100644
--- a/ncurses/tinfo/lib_acs.c
+++ b/ncurses/tinfo/lib_acs.c
@@ -1,5 +1,6 @@
/****************************************************************************
- * Copyright (c) 1998-2013,2014 Free Software Foundation, Inc. *
+ * Copyright 2018-2019,2020 Thomas E. Dickey *
+ * Copyright 1998-2014,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 *
@@ -39,7 +40,7 @@
#define CUR SP_TERMTYPE
#endif
-MODULE_ID("$Id: lib_acs.c,v 1.45 2014/03/08 20:32:59 tom Exp $")
+MODULE_ID("$Id: lib_acs.c,v 1.50 2020/02/02 23:34:34 tom Exp $")
#if BROKEN_LINKER || USE_REENTRANT
#define MyBuffer _nc_prescreen.real_acs_map
@@ -171,7 +172,7 @@
if (ena_acs != NULL) {
NCURSES_PUTP2("ena_acs", ena_acs);
}
-#if NCURSES_EXT_FUNCS
+#if NCURSES_EXT_FUNCS && defined(enter_pc_charset_mode) && defined(exit_pc_charset_mode)
/*
* Linux console "supports" the "PC ROM" character set by the coincidence
* that smpch/rmpch and smacs/rmacs have the same values. ncurses has
@@ -205,8 +206,13 @@
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;
}
@@ -249,3 +255,72 @@
NCURSES_SP_NAME(_nc_init_acs) (CURRENT_SCREEN);
}
#endif
+
+#if !NCURSES_WCWIDTH_GRAPHICS
+NCURSES_EXPORT(int)
+_nc_wacs_width(unsigned ch)
+{
+ int result;
+ switch (ch) {
+ case 0x00a3: /* FALLTHRU - ncurses pound-sterling symbol */
+ case 0x00b0: /* FALLTHRU - VT100 degree symbol */
+ case 0x00b1: /* FALLTHRU - VT100 plus/minus */
+ case 0x00b7: /* FALLTHRU - VT100 bullet */
+ case 0x03c0: /* FALLTHRU - ncurses greek pi */
+ case 0x2190: /* FALLTHRU - Teletype arrow pointing left */
+ case 0x2191: /* FALLTHRU - Teletype arrow pointing up */
+ case 0x2192: /* FALLTHRU - Teletype arrow pointing right */
+ case 0x2193: /* FALLTHRU - Teletype arrow pointing down */
+ case 0x2260: /* FALLTHRU - ncurses not-equal */
+ case 0x2264: /* FALLTHRU - ncurses less-than-or-equal-to */
+ case 0x2265: /* FALLTHRU - ncurses greater-than-or-equal-to */
+ case 0x23ba: /* FALLTHRU - VT100 scan line 1 */
+ case 0x23bb: /* FALLTHRU - ncurses scan line 3 */
+ case 0x23bc: /* FALLTHRU - ncurses scan line 7 */
+ case 0x23bd: /* FALLTHRU - VT100 scan line 9 */
+ case 0x2500: /* FALLTHRU - VT100 horizontal line */
+ case 0x2501: /* FALLTHRU - thick horizontal line */
+ case 0x2502: /* FALLTHRU - VT100 vertical line */
+ case 0x2503: /* FALLTHRU - thick vertical line */
+ case 0x250c: /* FALLTHRU - VT100 upper left corner */
+ case 0x250f: /* FALLTHRU - thick upper left corner */
+ case 0x2510: /* FALLTHRU - VT100 upper right corner */
+ case 0x2513: /* FALLTHRU - thick upper right corner */
+ case 0x2514: /* FALLTHRU - VT100 lower left corner */
+ case 0x2517: /* FALLTHRU - thick lower left corner */
+ case 0x2518: /* FALLTHRU - VT100 lower right corner */
+ case 0x251b: /* FALLTHRU - thick lower right corner */
+ case 0x251c: /* FALLTHRU - VT100 tee pointing left */
+ case 0x2523: /* FALLTHRU - thick tee pointing left */
+ case 0x2524: /* FALLTHRU - VT100 tee pointing right */
+ case 0x252b: /* FALLTHRU - thick tee pointing right */
+ case 0x252c: /* FALLTHRU - VT100 tee pointing down */
+ case 0x2533: /* FALLTHRU - thick tee pointing down */
+ case 0x2534: /* FALLTHRU - VT100 tee pointing up */
+ case 0x253b: /* FALLTHRU - thick tee pointing up */
+ case 0x253c: /* FALLTHRU - VT100 large plus or crossover */
+ case 0x254b: /* FALLTHRU - thick large plus or crossover */
+ case 0x2550: /* FALLTHRU - double horizontal line */
+ case 0x2551: /* FALLTHRU - double vertical line */
+ case 0x2554: /* FALLTHRU - double upper left corner */
+ case 0x2557: /* FALLTHRU - double upper right corner */
+ case 0x255a: /* FALLTHRU - double lower left corner */
+ case 0x255d: /* FALLTHRU - double lower right corner */
+ case 0x2560: /* FALLTHRU - double tee pointing right */
+ case 0x2563: /* FALLTHRU - double tee pointing left */
+ case 0x2566: /* FALLTHRU - double tee pointing down */
+ case 0x2569: /* FALLTHRU - double tee pointing up */
+ case 0x256c: /* FALLTHRU - double large plus or crossover */
+ case 0x2592: /* FALLTHRU - VT100 checker board (stipple) */
+ case 0x25ae: /* FALLTHRU - Teletype solid square block */
+ case 0x25c6: /* FALLTHRU - VT100 diamond */
+ case 0x2603: /* FALLTHRU - Teletype lantern symbol */
+ result = 1;
+ break;
+ default:
+ result = wcwidth(ch);
+ break;
+ }
+ return result;
+}
+#endif /* !NCURSES_WCWIDTH_GRAPHICS */
diff --git a/ncurses/tinfo/lib_baudrate.c b/ncurses/tinfo/lib_baudrate.c
index 1cf5505..311c41a 100644
--- a/ncurses/tinfo/lib_baudrate.c
+++ b/ncurses/tinfo/lib_baudrate.c
@@ -1,5 +1,6 @@
/****************************************************************************
- * Copyright (c) 1998-2014,2015 Free Software Foundation, Inc. *
+ * Copyright 2020 Thomas E. Dickey *
+ * Copyright 1998-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 *
@@ -39,7 +40,7 @@
#include <curses.priv.h>
#include <termcap.h> /* ospeed */
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) || defined(__OpenBSD__)
#include <sys/param.h>
#endif
@@ -49,7 +50,11 @@
* of the indices up to B115200 fit nicely in a 'short', allowing us to retain
* ospeed's type for compatibility.
*/
-#if NCURSES_OSPEED_COMPAT && ((defined(__FreeBSD__) && (__FreeBSD_version < 700000)) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__))
+#if NCURSES_OSPEED_COMPAT && \
+ ((defined(__FreeBSD__) && (__FreeBSD_version < 700000)) || \
+ defined(__NetBSD__) || \
+ ((defined(__OpenBSD__) && OpenBSD < 201510)) || \
+ defined(__APPLE__))
#undef B0
#undef B50
#undef B75
@@ -79,7 +84,7 @@
#undef USE_OLD_TTY
#endif /* USE_OLD_TTY */
-MODULE_ID("$Id: lib_baudrate.c,v 1.37 2015/06/14 00:34:12 tom Exp $")
+MODULE_ID("$Id: lib_baudrate.c,v 1.45 2020/09/05 21:15:32 tom Exp $")
/*
* int
@@ -90,10 +95,11 @@
*/
struct speed {
- NCURSES_OSPEED s; /* values for 'ospeed' */
- int sp; /* the actual speed */
+ int given_speed; /* values for 'ospeed' */
+ int actual_speed; /* the actual speed */
};
+#if !defined(EXP_WIN32_DRIVER)
#define DATA(number) { B##number, number }
static struct speed const speeds[] =
@@ -117,6 +123,9 @@
#elif defined(EXTA)
{EXTA, 19200},
#endif
+#ifdef B28800
+ DATA(28800),
+#endif
#ifdef B38400
DATA(38400),
#elif defined(EXTB)
@@ -127,32 +136,80 @@
#endif
/* ifdef to prevent overflow when OLD_TTY is not available */
#if !(NCURSES_OSPEED_COMPAT && defined(__FreeBSD__) && (__FreeBSD_version > 700000))
+#ifdef B76800
+ DATA(76800),
+#endif
#ifdef B115200
DATA(115200),
#endif
+#ifdef B153600
+ DATA(153600),
+#endif
#ifdef B230400
DATA(230400),
#endif
+#ifdef B307200
+ DATA(307200),
+#endif
#ifdef B460800
DATA(460800),
#endif
+#ifdef B500000
+ DATA(500000),
+#endif
+#ifdef B576000
+ DATA(576000),
+#endif
#ifdef B921600
DATA(921600),
#endif
+#ifdef B1000000
+ DATA(1000000),
+#endif
+#ifdef B1152000
+ DATA(1152000),
+#endif
+#ifdef B1500000
+ DATA(1500000),
+#endif
+#ifdef B2000000
+ DATA(2000000),
+#endif
+#ifdef B2500000
+ DATA(2500000),
+#endif
+#ifdef B3000000
+ DATA(3000000),
+#endif
+#ifdef B3500000
+ DATA(3500000),
+#endif
+#ifdef B4000000
+ DATA(4000000),
+#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;
#endif
int result = ERR;
- unsigned i;
+ if (OSpeed < 0)
+ OSpeed = (NCURSES_OSPEED) OSpeed;
+ if (OSpeed < 0)
+ OSpeed = (unsigned short) OSpeed;
#if !USE_REENTRANT
if (OSpeed == last_OSpeed) {
result = last_baudrate;
@@ -160,9 +217,14 @@
#endif
if (result == ERR) {
if (OSpeed >= 0) {
+ unsigned i;
+
for (i = 0; i < SIZEOF(speeds); i++) {
- if ((int) speeds[i].s == OSpeed) {
- result = speeds[i].sp;
+ if (speeds[i].given_speed > OSpeed) {
+ break;
+ }
+ if (speeds[i].given_speed == OSpeed) {
+ result = speeds[i].actual_speed;
break;
}
}
@@ -175,22 +237,27 @@
#endif
}
return (result);
+#endif /* !EXP_WIN32_DRIVER */
}
NCURSES_EXPORT(int)
_nc_ospeed(int BaudRate)
{
int result = 1;
- unsigned i;
-
+#if defined(EXP_WIN32_DRIVER)
+ (void) BaudRate;
+#else
if (BaudRate >= 0) {
+ unsigned i;
+
for (i = 0; i < SIZEOF(speeds); i++) {
- if (speeds[i].sp == BaudRate) {
- result = speeds[i].s;
+ if (speeds[i].actual_speed == BaudRate) {
+ result = speeds[i].given_speed;
break;
}
}
}
+#endif
return (result);
}
@@ -201,6 +268,9 @@
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
@@ -208,7 +278,7 @@
*/
#ifdef TRACE
if (IsValidTIScreen(SP_PARM)
- && !NC_ISATTY(fileno(SP_PARM ? SP_PARM->_ofp : stdout))
+ && !NC_ISATTY(fileno((SP_PARM && SP_PARM->_ofp) ? SP_PARM->_ofp : stdout))
&& getenv("BAUDRATE") != 0) {
int ret;
if ((ret = _nc_getenv_num("BAUDRATE")) <= 0)
@@ -234,7 +304,7 @@
} 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 9941d13..1f8db2c 100644
--- a/ncurses/tinfo/lib_cur_term.c
+++ b/ncurses/tinfo/lib_cur_term.c
@@ -1,5 +1,6 @@
/****************************************************************************
- * Copyright (c) 1998-2013,2014 Free Software Foundation, Inc. *
+,* Copyright 2020-2021,2022 Thomas E. Dickey *
+ * Copyright 1998-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 *
@@ -38,11 +39,12 @@
#include <curses.priv.h>
#include <termcap.h> /* ospeed */
+#include <tic.h> /* VALID_STRING */
-MODULE_ID("$Id: lib_cur_term.c,v 1.33 2014/03/08 20:32:59 tom Exp $")
+MODULE_ID("$Id: lib_cur_term.c,v 1.49 2022/05/28 17:56:55 tom Exp $")
#undef CUR
-#define CUR termp->type.
+#define CUR TerminalType(termp).
#if USE_REENTRANT
@@ -76,7 +78,7 @@
#endif
NCURSES_EXPORT(TERMINAL *)
-NCURSES_SP_NAME(set_curterm) (NCURSES_SP_DCLx TERMINAL * termp)
+NCURSES_SP_NAME(set_curterm) (NCURSES_SP_DCLx TERMINAL *termp)
{
TERMINAL *oldterm;
@@ -95,16 +97,21 @@
#ifdef USE_TERM_DRIVER
TERMINAL_CONTROL_BLOCK *TCB = (TERMINAL_CONTROL_BLOCK *) termp;
ospeed = (NCURSES_OSPEED) _nc_ospeed(termp->_baudrate);
- if (TCB->drv->isTerminfo && termp->type.Strings) {
- PC = (char) ((pad_char != NULL) ? pad_char[0] : 0);
+ if (TCB->drv &&
+ TCB->drv->isTerminfo &&
+ TerminalType(termp).Strings) {
+ PC = (char) (VALID_STRING(pad_char) ? pad_char[0] : 0);
}
TCB->csp = SP_PARM;
#else
ospeed = (NCURSES_OSPEED) _nc_ospeed(termp->_baudrate);
- if (termp->type.Strings) {
- PC = (char) ((pad_char != NULL) ? pad_char[0] : 0);
+ if (TerminalType(termp).Strings) {
+ PC = (char) (VALID_STRING(pad_char) ? pad_char[0] : 0);
}
#endif
+#if !USE_REENTRANT
+ save_ttytype(termp);
+#endif
}
_nc_unlock_global(curses);
@@ -114,14 +121,14 @@
#if NCURSES_SP_FUNCS
NCURSES_EXPORT(TERMINAL *)
-set_curterm(TERMINAL * termp)
+set_curterm(TERMINAL *termp)
{
return NCURSES_SP_NAME(set_curterm) (CURRENT_SCREEN, termp);
}
#endif
NCURSES_EXPORT(int)
-NCURSES_SP_NAME(del_curterm) (NCURSES_SP_DCLx TERMINAL * termp)
+NCURSES_SP_NAME(del_curterm) (NCURSES_SP_DCLx TERMINAL *termp)
{
int rc = ERR;
@@ -139,7 +146,14 @@
#endif
);
- _nc_free_termtype(&(termp->type));
+#if NCURSES_EXT_NUMBERS
+#if NCURSES_EXT_COLORS
+ _nc_free_termtype1(&termp->type);
+#else
+ _nc_free_termtype2(&termp->type);
+#endif
+#endif
+ _nc_free_termtype2(&TerminalType(termp));
if (termp == cur)
NCURSES_SP_NAME(set_curterm) (NCURSES_SP_ARGx 0);
@@ -153,18 +167,29 @@
if (TCB->drv)
TCB->drv->td_release(TCB);
#endif
+#if NO_LEAKS
+ /* discard memory used in tgetent's cache for this terminal */
+ _nc_tgetent_leak(termp);
+#endif
+ if (--_nc_globals.terminal_count == 0) {
+ _nc_free_tparm(termp);
+ }
+
+ free(termp->tparm_state.fmt_buff);
+ free(termp->tparm_state.out_buff);
free(termp);
rc = OK;
}
+
returnCode(rc);
}
#if NCURSES_SP_FUNCS
NCURSES_EXPORT(int)
-del_curterm(TERMINAL * termp)
+del_curterm(TERMINAL *termp)
{
- int rc = ERR;
+ int rc;
_nc_lock_global(curses);
rc = NCURSES_SP_NAME(del_curterm) (CURRENT_SCREEN, termp);
diff --git a/ncurses/tinfo/lib_data.c b/ncurses/tinfo/lib_data.c
index 06b6f88..b817f49 100644
--- a/ncurses/tinfo/lib_data.c
+++ b/ncurses/tinfo/lib_data.c
@@ -1,5 +1,6 @@
/****************************************************************************
- * Copyright (c) 1998-2012,2013 Free Software Foundation, Inc. *
+ * Copyright 2018-2022,2024 Thomas E. Dickey *
+ * Copyright 1998-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 *
@@ -42,7 +43,7 @@
#include <curses.priv.h>
-MODULE_ID("$Id: lib_data.c,v 1.66 2013/08/24 17:28:24 tom Exp $")
+MODULE_ID("$Id: lib_data.c,v 1.89 2024/02/24 18:11:38 tom Exp $")
/*
* OS/2's native linker complains if we don't initialize public data when
@@ -94,7 +95,9 @@
NCURSES_EXPORT(int)
_nc_alloc_screen(void)
{
- return ((my_screen = _nc_alloc_screen_sp()) != 0);
+ my_screen = _nc_alloc_screen_sp();
+ T(("_nc_alloc_screen_sp %p", my_screen));
+ return (my_screen != 0);
}
NCURSES_EXPORT(void)
@@ -137,12 +140,15 @@
0, /* slk_format */
+ 2048, /* getstr_limit */
+
NULL, /* safeprint_buf */
0, /* safeprint_used */
TGETENT_0s, /* tgetent_cache */
0, /* tgetent_index */
0, /* tgetent_sequence */
+ 0, /* terminal_count */
0, /* dbd_blob */
0, /* dbd_list */
@@ -150,6 +156,15 @@
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
+
#ifndef USE_SP_WINDOWLIST
0, /* _nc_windowlist */
#endif
@@ -163,15 +178,27 @@
0, /* safeprint_rows */
#endif
-#ifdef USE_TERM_DRIVER
- 0, /* term_driver */
+#ifdef USE_PTHREADS
+ PTHREAD_MUTEX_INITIALIZER, /* mutex_curses */
+ PTHREAD_MUTEX_INITIALIZER, /* mutex_prescreen */
+ PTHREAD_MUTEX_INITIALIZER, /* mutex_screen */
+ PTHREAD_MUTEX_INITIALIZER, /* mutex_update */
+ PTHREAD_MUTEX_INITIALIZER, /* mutex_tst_tracef */
+ PTHREAD_MUTEX_INITIALIZER, /* mutex_tracef */
+ 0, /* nested_tracef */
+ 0, /* use_pthreads */
+#if USE_PTHREADS_EINTR
+ 0, /* read_thread */
#endif
-
+#endif
+#if USE_WIDEC_SUPPORT
+ CHARS_0s, /* key_name */
+#endif
#ifdef TRACE
- FALSE, /* init_trace */
- CHARS_0s, /* trace_fname */
+ FALSE, /* trace_opened */
0, /* trace_level */
NULL, /* trace_fp */
+ -1, /* trace_fd */
NULL, /* tracearg_buf */
0, /* tracearg_used */
@@ -194,15 +221,8 @@
0, /* nested_tracef */
#endif
#endif /* TRACE */
-#ifdef USE_PTHREADS
- PTHREAD_MUTEX_INITIALIZER, /* mutex_curses */
- PTHREAD_MUTEX_INITIALIZER, /* mutex_tst_tracef */
- PTHREAD_MUTEX_INITIALIZER, /* mutex_tracef */
- 0, /* nested_tracef */
- 0, /* use_pthreads */
-#endif
-#if USE_PTHREADS_EINTR
- 0, /* read_thread */
+#if NO_LEAKS
+ FALSE, /* leak_checking */
#endif
};
@@ -214,17 +234,11 @@
#define RIPOFF_0s { RIPOFF_0 }
NCURSES_EXPORT_VAR(NCURSES_PRESCREEN) _nc_prescreen = {
+ NULL, /* allocated */
TRUE, /* use_env */
FALSE, /* filter_mode */
A_NORMAL, /* previous_attr */
-#ifndef USE_SP_RIPOFF
- RIPOFF_0s, /* ripoff */
- NULL, /* rsp */
-#endif
{ /* tparm_state */
-#ifdef TRACE
- NULL, /* tname */
-#endif
NULL, /* tparam_base */
STACK_FRAME_0s, /* stack */
@@ -237,14 +251,21 @@
NULL, /* fmt_buff */
0, /* fmt_size */
- NUM_VARS_0s, /* dynamic_var */
NUM_VARS_0s, /* static_vars */
+#ifdef TRACE
+ NULL, /* tname */
+#endif
},
NULL, /* saved_tty */
+ FALSE, /* use_tioctl */
+ 0, /* _outch */
+#ifndef USE_SP_RIPOFF
+ RIPOFF_0s, /* ripoff */
+ NULL, /* rsp */
+#endif
#if NCURSES_NO_PADDING
FALSE, /* flag to set if padding disabled */
#endif
- 0, /* _outch */
#if BROKEN_LINKER || USE_REENTRANT
NULL, /* real_acs_map */
0, /* LINES */
@@ -252,12 +273,13 @@
8, /* TABSIZE */
1000, /* ESCDELAY */
0, /* cur_term */
+#endif
#ifdef TRACE
+#if BROKEN_LINKER || USE_REENTRANT
0L, /* _outchars */
NULL, /* _tputs_trace */
#endif
#endif
- FALSE, /* use_tioctl */
};
/* *INDENT-ON* */
@@ -287,6 +309,9 @@
if (!initialized) {
initialized = TRUE;
_nc_mutex_init(&_nc_globals.mutex_curses);
+ _nc_mutex_init(&_nc_globals.mutex_prescreen);
+ _nc_mutex_init(&_nc_globals.mutex_screen);
+ _nc_mutex_init(&_nc_globals.mutex_update);
_nc_mutex_init(&_nc_globals.mutex_tst_tracef);
_nc_mutex_init(&_nc_globals.mutex_tracef);
}
@@ -337,25 +362,28 @@
NCURSES_EXPORT(int)
_nc_mutex_lock(pthread_mutex_t * obj)
{
- if (_nc_use_pthreads == 0)
- return 0;
- return pthread_mutex_lock(obj);
+ int rc = 0;
+ if (_nc_use_pthreads != 0)
+ rc = pthread_mutex_lock(obj);
+ return rc;
}
NCURSES_EXPORT(int)
_nc_mutex_trylock(pthread_mutex_t * obj)
{
- if (_nc_use_pthreads == 0)
- return 0;
- return pthread_mutex_trylock(obj);
+ int rc = 0;
+ if (_nc_use_pthreads != 0)
+ rc = pthread_mutex_trylock(obj);
+ return rc;
}
NCURSES_EXPORT(int)
_nc_mutex_unlock(pthread_mutex_t * obj)
{
- if (_nc_use_pthreads == 0)
- return 0;
- return pthread_mutex_unlock(obj);
+ int rc = 0;
+ if (_nc_use_pthreads != 0)
+ rc = pthread_mutex_unlock(obj);
+ return rc;
}
#endif /* USE_PTHREADS */
@@ -371,7 +399,7 @@
if ((pthread_sigmask))
return pthread_sigmask(how, newmask, oldmask);
else
- return sigprocmask(how, newmask, oldmask);
+ return (sigprocmask) (how, newmask, oldmask);
}
#endif
#endif /* USE_PTHREADS */
diff --git a/ncurses/tinfo/lib_has_cap.c b/ncurses/tinfo/lib_has_cap.c
index 17e59d5..cbf68b3 100644
--- a/ncurses/tinfo/lib_has_cap.c
+++ b/ncurses/tinfo/lib_has_cap.c
@@ -1,5 +1,6 @@
/****************************************************************************
- * Copyright (c) 1998-2009,2013 Free Software Foundation, Inc. *
+ * Copyright 2020 Thomas E. Dickey *
+ * Copyright 1998-2009,2013 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 *
@@ -46,7 +47,7 @@
#define CUR SP_TERMTYPE
#endif
-MODULE_ID("$Id: lib_has_cap.c,v 1.10 2013/11/16 19:57:22 tom Exp $")
+MODULE_ID("$Id: lib_has_cap.c,v 1.11 2020/02/02 23:34:34 tom Exp $")
NCURSES_EXPORT(bool)
NCURSES_SP_NAME(has_ic) (NCURSES_SP_DCL0)
diff --git a/ncurses/tinfo/lib_kernel.c b/ncurses/tinfo/lib_kernel.c
index 37f7084..46f652b 100644
--- a/ncurses/tinfo/lib_kernel.c
+++ b/ncurses/tinfo/lib_kernel.c
@@ -1,5 +1,6 @@
/****************************************************************************
- * Copyright (c) 1998-2009,2010 Free Software Foundation, Inc. *
+ * Copyright 2020-2022,2023 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 *
@@ -48,8 +49,9 @@
#include <curses.priv.h>
-MODULE_ID("$Id: lib_kernel.c,v 1.31 2010/12/19 01:21:19 tom Exp $")
+MODULE_ID("$Id: lib_kernel.c,v 1.36 2023/06/10 13:29:06 tom Exp $")
+#ifdef TERMIOS
static int
_nc_vdisable(void)
{
@@ -57,7 +59,7 @@
#if defined(_POSIX_VDISABLE) && HAVE_UNISTD_H
value = _POSIX_VDISABLE;
#endif
-#if defined(_PC_VDISABLE)
+#if defined(_PC_VDISABLE) && HAVE_FPATHCONF
if (value == -1) {
value = (int) fpathconf(0, _PC_VDISABLE);
if (value == -1) {
@@ -70,6 +72,7 @@
#endif
return value;
}
+#endif /* TERMIOS */
/*
* erasechar()
@@ -91,6 +94,8 @@
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
@@ -126,6 +131,8 @@
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
@@ -141,30 +148,40 @@
}
#endif
+static void
+flush_input(int fd)
+{
+#ifdef TERMIOS
+ tcflush(fd, TCIFLUSH);
+#else /* !TERMIOS */
+ errno = 0;
+ do {
+#if defined(EXP_WIN32_DRIVER)
+ _nc_console_flush(_nc_console_fd2handle(fd));
+#else
+ ioctl(fd, TIOCFLUSH, 0);
+#endif
+ } while
+ (errno == EINTR);
+#endif
+}
+
/*
* flushinp()
*
- * Flush any input on cur_term->Filedes
- *
+ * Flush any input on tty
*/
NCURSES_EXPORT(int)
NCURSES_SP_NAME(flushinp) (NCURSES_SP_DCL0)
{
- TERMINAL *termp = TerminalOf(SP_PARM);
-
T((T_CALLED("flushinp(%p)"), (void *) SP_PARM));
- if (termp != 0) {
-#ifdef TERMIOS
- tcflush(termp->Filedes, TCIFLUSH);
-#else
- errno = 0;
- do {
- ioctl(termp->Filedes, TIOCFLUSH, 0);
- } while
- (errno == EINTR);
-#endif
+ if (SP_PARM != 0) {
+ if (NC_ISATTY(SP_PARM->_ifd))
+ flush_input(SP_PARM->_ifd);
+ else if (NC_ISATTY(SP_PARM->_ofd))
+ flush_input(SP_PARM->_ofd);
if (SP_PARM) {
SP_PARM->_fifohead = -1;
SP_PARM->_fifotail = 0;
diff --git a/ncurses/tinfo/lib_longname.c b/ncurses/tinfo/lib_longname.c
index fa231b8..9dc6d71 100644
--- a/ncurses/tinfo/lib_longname.c
+++ b/ncurses/tinfo/lib_longname.c
@@ -1,5 +1,6 @@
/****************************************************************************
- * Copyright (c) 1998-2010,2015 Free Software Foundation, Inc. *
+ * Copyright 2020,2021 Thomas E. Dickey *
+ * Copyright 1998-2010,2015 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 *
@@ -42,7 +43,7 @@
#include <curses.priv.h>
-MODULE_ID("$Id: lib_longname.c,v 1.13 2015/07/25 20:08:14 tom Exp $")
+MODULE_ID("$Id: lib_longname.c,v 1.15 2021/04/03 22:36:21 tom Exp $")
#if USE_REENTRANT
NCURSES_EXPORT(char *)
@@ -50,11 +51,12 @@
{
static char empty[] =
{'\0'};
- char *ptr;
T((T_CALLED("longname(%p)"), (void *) SP_PARM));
if (SP_PARM) {
+ char *ptr;
+
for (ptr = SP_PARM->_ttytype + strlen(SP_PARM->_ttytype);
ptr > SP_PARM->_ttytype;
ptr--)
diff --git a/ncurses/tinfo/lib_napms.c b/ncurses/tinfo/lib_napms.c
index df17363..1b89a54 100644
--- a/ncurses/tinfo/lib_napms.c
+++ b/ncurses/tinfo/lib_napms.c
@@ -1,5 +1,6 @@
/****************************************************************************
- * Copyright (c) 1998-2012,2014 Free Software Foundation, Inc. *
+ * Copyright 2020,2023 Thomas E. Dickey *
+ * Copyright 1998-2014,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 *
@@ -51,17 +52,18 @@
#endif
#endif
-MODULE_ID("$Id: lib_napms.c,v 1.24 2014/03/08 20:32:59 tom Exp $")
+MODULE_ID("$Id: lib_napms.c,v 1.28 2023/09/16 16:09:33 tom Exp $")
NCURSES_EXPORT(int)
NCURSES_SP_NAME(napms) (NCURSES_SP_DCLx int ms)
{
T((T_CALLED("napms(%d)"), ms));
+ if (ms > MAX_DELAY_MSECS)
+ ms = MAX_DELAY_MSECS;
+
#ifdef USE_TERM_DRIVER
- if (HasTerminal(SP_PARM)) {
- CallDriver_1(SP_PARM, td_nap, ms);
- }
+ CallDriver_1(SP_PARM, td_nap, ms);
#else /* !USE_TERM_DRIVER */
#if NCURSES_SP_FUNCS
(void) sp;
@@ -76,6 +78,8 @@
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 b736d5f..6a8bb39 100644
--- a/ncurses/tinfo/lib_options.c
+++ b/ncurses/tinfo/lib_options.c
@@ -1,5 +1,6 @@
/****************************************************************************
- * Copyright (c) 1998-2013,2014 Free Software Foundation, Inc. *
+ * Copyright 2020-2021,2023 Thomas E. Dickey *
+ * Copyright 1998-2014,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 *
@@ -46,7 +47,7 @@
#define CUR SP_TERMTYPE
#endif
-MODULE_ID("$Id: lib_options.c,v 1.78 2014/09/27 21:55:24 tom Exp $")
+MODULE_ID("$Id: lib_options.c,v 1.83 2023/04/29 18:56:12 tom Exp $")
NCURSES_EXPORT(int)
idlok(WINDOW *win, bool flag)
@@ -87,11 +88,11 @@
{
T((T_CALLED("halfdelay(%p,%d)"), (void *) SP_PARM, t));
- if (t < 1 || t > 255 || !IsValidTIScreen(SP_PARM))
+ if (t < 1 || t > 255 || !SP_PARM || !IsValidTIScreen(SP_PARM))
returnCode(ERR);
NCURSES_SP_NAME(cbreak) (NCURSES_SP_ARG);
- SP_PARM->_cbreak = t + 1;
+ IsCbreak(SP_PARM) = t + 1;
returnCode(OK);
}
@@ -202,7 +203,7 @@
#ifdef USE_TERM_DRIVER
code = CallDriver_1(SP_PARM, td_cursorSet, vis);
#else
- if (IsTermInfo(SP_PARM)) {
+ if (IsValidTIScreen(SP_PARM)) {
switch (vis) {
case 2:
code = NCURSES_PUTP2_FLUSH("cursor_visible",
@@ -241,7 +242,7 @@
NCURSES_SP_NAME(typeahead) (NCURSES_SP_DCLx int fd)
{
T((T_CALLED("typeahead(%p, %d)"), (void *) SP_PARM, fd));
- if (IsValidTIScreen(SP_PARM)) {
+ if (SP_PARM && IsValidTIScreen(SP_PARM)) {
SP_PARM->_checkfd = fd;
returnCode(OK);
} else {
@@ -360,7 +361,7 @@
#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 0dab4d4..e7d8535 100644
--- a/ncurses/tinfo/lib_print.c
+++ b/ncurses/tinfo/lib_print.c
@@ -1,5 +1,6 @@
/****************************************************************************
- * Copyright (c) 1998-2011,2012 Free Software Foundation, Inc. *
+ * Copyright 2018-2021,2023 Thomas E. Dickey *
+ * Copyright 1998-2011,2012 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 *
@@ -39,14 +40,14 @@
#define CUR SP_TERMTYPE
#endif
-MODULE_ID("$Id: lib_print.c,v 1.23 2012/02/22 22:34:31 tom Exp $")
+MODULE_ID("$Id: lib_print.c,v 1.31 2023/06/10 12:44:41 tom Exp $")
NCURSES_EXPORT(int)
NCURSES_SP_NAME(mcprint) (NCURSES_SP_DCLx char *data, int len)
/* ship binary character data to the printer via mc4/mc5/mc5p */
{
int result;
- char *mybuf, *switchon;
+ char *mybuf = NULL, *switchon;
size_t onsize, offsize;
size_t need;
@@ -59,7 +60,7 @@
}
if (prtr_non) {
- switchon = TPARM_1(prtr_non, len);
+ switchon = TIPARM_1(prtr_non, len);
onsize = strlen(switchon);
offsize = 0;
} else {
@@ -72,6 +73,7 @@
if (switchon == 0
|| (mybuf = typeMalloc(char, need + 1)) == 0) {
+ free(mybuf);
errno = ENOMEM;
return (ERR);
}
@@ -88,14 +90,14 @@
* data has actually been shipped to the terminal. If the write(2)
* operation is truly atomic we're protected from this.
*/
- result = (int) write(TerminalOf(SP_PARM)->Filedes, mybuf, need);
+ result = (int) write(SP_PARM->_ofd, mybuf, need);
/*
* By giving up our scheduler slot here we increase the odds that the
* kernel will ship the contiguous clist items from the last write
* immediately.
*/
-#ifndef __MINGW32__
+#ifndef _NC_WINDOWS
(void) sleep(0);
#endif
free(mybuf);
diff --git a/ncurses/tinfo/lib_raw.c b/ncurses/tinfo/lib_raw.c
index 928692b..fda6dea 100644
--- a/ncurses/tinfo/lib_raw.c
+++ b/ncurses/tinfo/lib_raw.c
@@ -1,5 +1,6 @@
/****************************************************************************
- * Copyright (c) 1998-2011,2012 Free Software Foundation, Inc. *
+ * Copyright 2020-2023,2024 Thomas E. Dickey *
+ * Copyright 1998-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 *
@@ -49,7 +50,7 @@
#include <curses.priv.h>
-MODULE_ID("$Id: lib_raw.c,v 1.21 2012/01/21 19:21:29 KO.Myung-Hun Exp $")
+MODULE_ID("$Id: lib_raw.c,v 1.30 2024/03/30 15:54:17 tom Exp $")
#if HAVE_SYS_TERMIO_H
#include <sys/termio.h> /* needed for ISC */
@@ -96,6 +97,8 @@
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
@@ -112,8 +115,10 @@
kbdinfo.fsMask |= KEYBOARD_BINARY_MODE;
KbdSetStatus(&kbdinfo, 0);
#endif
- SP_PARM->_raw = TRUE;
- SP_PARM->_cbreak = 1;
+ if (SP_PARM) {
+ IsRaw(SP_PARM) = TRUE;
+ IsCbreak(SP_PARM) = 1;
+ }
termp->Nttyb = buf;
}
AFTER("raw");
@@ -146,15 +151,19 @@
#ifdef TERMIOS
buf.c_lflag &= (unsigned) ~ICANON;
buf.c_iflag &= (unsigned) ~ICRNL;
- 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
result = NCURSES_SP_NAME(_nc_set_tty_mode) (NCURSES_SP_ARGx &buf);
if (result == OK) {
- SP_PARM->_cbreak = 1;
+ if (SP_PARM) {
+ IsCbreak(SP_PARM) = 1;
+ }
termp->Nttyb = buf;
}
AFTER("cbreak");
@@ -177,12 +186,12 @@
NCURSES_EXPORT(void)
NCURSES_SP_NAME(qiflush) (NCURSES_SP_DCL0)
{
- int result = ERR;
TERMINAL *termp;
T((T_CALLED("qiflush(%p)"), (void *) SP_PARM));
if ((termp = TerminalOf(SP_PARM)) != 0) {
TTY buf;
+ int result;
BEFORE("qiflush");
buf = termp->Nttyb;
@@ -190,6 +199,7 @@
buf.c_lflag &= (unsigned) ~(NOFLSH);
result = NCURSES_SP_NAME(_nc_set_tty_mode) (NCURSES_SP_ARGx &buf);
#else
+ result = ERR;
/* FIXME */
#endif
if (result == OK)
@@ -225,6 +235,8 @@
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
@@ -241,8 +253,10 @@
kbdinfo.fsMask |= KEYBOARD_ASCII_MODE;
KbdSetStatus(&kbdinfo, 0);
#endif
- SP_PARM->_raw = FALSE;
- SP_PARM->_cbreak = 0;
+ if (SP_PARM) {
+ IsRaw(SP_PARM) = FALSE;
+ IsCbreak(SP_PARM) = 0;
+ }
termp->Nttyb = buf;
}
AFTER("noraw");
@@ -275,12 +289,16 @@
#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
result = NCURSES_SP_NAME(_nc_set_tty_mode) (NCURSES_SP_ARGx &buf);
if (result == OK) {
- SP_PARM->_cbreak = 0;
+ if (SP_PARM) {
+ IsCbreak(SP_PARM) = 0;
+ }
termp->Nttyb = buf;
}
AFTER("nocbreak");
@@ -299,12 +317,12 @@
NCURSES_EXPORT(void)
NCURSES_SP_NAME(noqiflush) (NCURSES_SP_DCL0)
{
- int result = ERR;
TERMINAL *termp;
T((T_CALLED("noqiflush(%p)"), (void *) SP_PARM));
if ((termp = TerminalOf(SP_PARM)) != 0) {
TTY buf;
+ int result;
BEFORE("noqiflush");
buf = termp->Nttyb;
@@ -313,6 +331,7 @@
result = NCURSES_SP_NAME(_nc_set_tty_mode) (NCURSES_SP_ARGx &buf);
#else
/* FIXME */
+ result = ERR;
#endif
if (result == OK)
termp->Nttyb = buf;
@@ -375,3 +394,46 @@
return NCURSES_SP_NAME(intrflush) (CURRENT_SCREEN, win, flag);
}
#endif
+
+#if NCURSES_EXT_FUNCS
+/* *INDENT-OFF* */
+
+/*
+ * SCREEN is always opaque, but nl/raw/cbreak/echo set properties in it.
+ * As an extension, provide a way to query the properties.
+ *
+ * There are other properties which could be queried, e.g., filter, keypad,
+ * use_env, use_meta, but these particular properties are saved/restored within
+ * the wgetnstr() and wgetn_wstr() functions, which requires that the higher
+ * level curses library knows about the internal state of the lower level
+ * terminfo library.
+ */
+
+#define is_TEST(show,what) \
+ NCURSES_EXPORT(int) \
+ NCURSES_SP_NAME(show) (NCURSES_SP_DCL0) \
+ { \
+ return ((SP_PARM != NULL) ? (what(SP_PARM) ? 1 : 0) : -1); \
+ }
+
+is_TEST(is_nl, IsNl)
+is_TEST(is_raw, IsRaw)
+is_TEST(is_cbreak, IsCbreak)
+is_TEST(is_echo, IsEcho)
+
+#if NCURSES_SP_FUNCS
+#undef is_TEST
+#define is_TEST(show) \
+ NCURSES_EXPORT(int) \
+ show(void) \
+ { \
+ return NCURSES_SP_NAME(show) (CURRENT_SCREEN); \
+ }
+is_TEST(is_nl)
+is_TEST(is_raw)
+is_TEST(is_cbreak)
+is_TEST(is_echo)
+#endif
+
+/* *INDENT-ON* */
+#endif /* extensions */
diff --git a/ncurses/tinfo/lib_setup.c b/ncurses/tinfo/lib_setup.c
index 0a0a1f5..99097f0 100644
--- a/ncurses/tinfo/lib_setup.c
+++ b/ncurses/tinfo/lib_setup.c
@@ -1,5 +1,6 @@
/****************************************************************************
- * Copyright (c) 1998-2014,2015 Free Software Foundation, Inc. *
+ * Copyright 2018-2023,2024 Thomas E. Dickey *
+ * Copyright 1998-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 *
@@ -48,7 +49,7 @@
#include <locale.h>
#endif
-MODULE_ID("$Id: lib_setup.c,v 1.164 2015/06/27 18:10:55 tom Exp $")
+MODULE_ID("$Id: lib_setup.c,v 1.240 2024/04/20 17:04:05 tom Exp $")
/****************************************************************************
*
@@ -65,7 +66,7 @@
#endif
#if NEED_PTEM_H
- /* On SCO, they neglected to define struct winsize in termios.h -- it's only
+ /* On SCO, they neglected to define struct winsize in termios.h -- it is only
* in termio.h and ptem.h (the former conflicts with other definitions).
*/
# include <sys/stream.h>
@@ -98,7 +99,7 @@
* Reduce explicit use of "cur_term" global variable.
*/
#undef CUR
-#define CUR termp->type.
+#define CUR TerminalType(termp).
/*
* Wrap global variables in this module.
@@ -115,12 +116,12 @@
if (CURRENT_SCREEN) {
TERMINAL *termp = TerminalOf(CURRENT_SCREEN);
if (termp != 0) {
- result = termp->type.term_names;
+ result = TerminalType(termp).term_names;
}
}
#else
if (cur_term != 0) {
- result = cur_term->type.term_names;
+ result = TerminalType(cur_term).term_names;
}
#endif
return result;
@@ -173,16 +174,20 @@
NCURSES_SP_NAME(set_tabsize) (NCURSES_SP_DCLx int value)
{
int code = OK;
-#if USE_REENTRANT
- if (SP_PARM) {
- SP_PARM->_TABSIZE = value;
- } else {
+ if (value <= 0) {
code = ERR;
- }
+ } else {
+#if USE_REENTRANT
+ if (SP_PARM) {
+ SP_PARM->_TABSIZE = value;
+ } else {
+ code = ERR;
+ }
#else
- (void) SP_PARM;
- TABSIZE = value;
+ (void) SP_PARM;
+ TABSIZE = value;
#endif
+ }
return code;
}
@@ -220,9 +225,9 @@
NCURSES_EXPORT(void)
NCURSES_SP_NAME(use_env) (NCURSES_SP_DCLx bool f)
{
+ START_TRACE();
T((T_CALLED("use_env(%p,%d)"), (void *) SP_PARM, (int) f));
#if NCURSES_SP_FUNCS
- START_TRACE();
if (IsPreScreen(SP_PARM)) {
SP_PARM->_use_env = f;
}
@@ -235,11 +240,11 @@
NCURSES_EXPORT(void)
NCURSES_SP_NAME(use_tioctl) (NCURSES_SP_DCLx bool f)
{
+ START_TRACE();
T((T_CALLED("use_tioctl(%p,%d)"), (void *) SP_PARM, (int) f));
#if NCURSES_SP_FUNCS
- START_TRACE();
if (IsPreScreen(SP_PARM)) {
- SP_PARM->_use_tioctl = f;
+ SP_PARM->use_tioctl = f;
}
#else
_nc_prescreen.use_tioctl = f;
@@ -251,8 +256,8 @@
NCURSES_EXPORT(void)
use_env(bool f)
{
- T((T_CALLED("use_env(%d)"), (int) f));
START_TRACE();
+ T((T_CALLED("use_env(%d)"), (int) f));
_nc_prescreen.use_env = f;
returnVoid;
}
@@ -260,17 +265,202 @@
NCURSES_EXPORT(void)
use_tioctl(bool f)
{
- T((T_CALLED("use_tioctl(%d)"), (int) f));
START_TRACE();
+ T((T_CALLED("use_tioctl(%d)"), (int) f));
_nc_prescreen.use_tioctl = f;
returnVoid;
}
#endif
+#if !(defined(USE_TERM_DRIVER) || defined(EXP_WIN32_DRIVER))
+static void
+_nc_default_screensize(TERMINAL *termp, int *linep, int *colp)
+{
+ /* if we can't get dynamic info about the size, use static */
+ if (*linep <= 0) {
+ *linep = (int) lines;
+ }
+ if (*colp <= 0) {
+ *colp = (int) columns;
+ }
+
+ /* the ultimate fallback, assume fixed 24x80 size */
+ if (*linep <= 0) {
+ *linep = 24;
+ }
+ if (*colp <= 0) {
+ *colp = 80;
+ }
+}
+
+#if defined(USE_CHECK_SIZE) && defined(user6) && defined(user7)
+static const char *
+skip_csi(const char *value)
+{
+ if (UChar(*value) == CSI_CHR) {
+ ++value;
+ } else if (*value == ESC_CHR && value[1] == L_BLOCK) {
+ value += 2;
+ }
+ return value;
+}
+
+static bool
+is_expected(const char *value, const char *expected)
+{
+ bool result = FALSE;
+ if (VALID_STRING(value)) {
+ const char *skipped = skip_csi(value);
+ if (skipped != value) {
+ if (!strcmp(skipped, expected))
+ result = TRUE;
+ }
+ }
+ return result;
+}
+
+static bool
+get_position(TERMINAL *termp, int fd, int *row, int *col)
+{
+ bool result = FALSE;
+ size_t need = strlen(user7);
+ int have;
+
+ have = (int) write(fd, user7, need);
+
+ if (have == (int) need) {
+ int y, x;
+ char buf[20];
+ char *s;
+ char cc;
+ const char *skipped;
+ int scanned;
+
+ s = memset(buf, '\0', sizeof(buf));
+ do {
+ size_t ask = (sizeof(buf) - 1 - (size_t) (s - buf));
+ int got = (int) read(fd, s, ask);
+ if (got == 0)
+ break;
+ s += got;
+ *s = '\0';
+ } while (strchr(buf, 'R') == NULL && (size_t) (s + 1 - buf) < sizeof(buf));
+ T(("CPR response %s", _nc_visbuf(buf)));
+ skipped = skip_csi(buf);
+ cc = '\0';
+ if (skipped != buf
+ && *skipped != '\0'
+ && (scanned = sscanf(skip_csi(buf), "%d;%d%c", &y, &x, &cc)) == 3
+ && (cc == 'R')) {
+ *row = y;
+ *col = x;
+ result = TRUE;
+ }
+ }
+ T(("get_position %s %d,%d", result ? "OK" : "ERR", *row, *col));
+ return result;
+}
+
+static bool
+set_position(NCURSES_SP_DCLx TERMINAL *termp, int row, int col)
+{
+ bool result;
+ char *actual = TIPARM_2(cursor_address, row, col);
+ T((T_CALLED("set_position %d,%d)"), row, col));
+#if NCURSES_SP_FUNCS
+ result = (NCURSES_SP_NAME(_nc_putp) (NCURSES_SP_ARGx "set_position",
+ actual) == OK);
+ NCURSES_SP_NAME(_nc_flush) (NCURSES_SP_ARG);
+#else
+ /* This does not support padding because without sp-funcs, we have only
+ * the interface using stdio, but we are not guaranteed that Filedes
+ * is the same as fileno(stdout).
+ */
+ result = FALSE;
+ if (actual != NULL) {
+ size_t want = strlen(actual);
+ int have = (int) write(termp->Filedes, actual, want);
+ result = ((int) want == have);
+ }
+#endif
+ returnBool(result);
+}
+
+/*
+ * This is a little more complicated than one might expect, because we do this
+ * before setting up the terminal modes, etc., and cannot use the timeout or
+ * buffering functions.
+ *
+ * We check if the terminal description has the ECMA-48 CPR (cursor position
+ * report) in u7 and the response in u6. The two variations of is_expected()
+ * cover the termcap style and terminfo style, and are equivalent as far as we
+ * are concerned. For analyzing the response, we wait (a short time) for 'R'
+ * to be echoed, and then check if we received two integers in the response.
+ *
+ * In principle, this could run on "any" ECMA-48 terminal, but in practice,
+ * there is a scenario using GNU screen where it uses ncurses with a partially
+ * configured pseudo-terminal, and the CPR response goes to the wrong place.
+ * So we do a simple check to exclude pseudo-terminals.
+ */
+static void
+_nc_check_screensize(SCREEN *sp, TERMINAL *termp, int *linep, int *colp)
+{
+ int fd = termp->Filedes;
+ TTY saved;
+ const char *name = NULL;
+
+ if (IsRealTty(fd, name)
+ && VALID_STRING(cursor_address)
+ && is_expected(user7, "6n")
+ && (is_expected(user6, "%i%d;%dR") ||
+ is_expected(user6, "%i%p1%d;%p2%dR"))
+ && GET_TTY(fd, &saved) == OK) {
+ int current_y = -1, current_x = -1;
+ int updated_y = -1, updated_x = -1;
+ TTY alter = saved;
+
+#if NCURSES_SP_FUNCS
+ if (sp == NULL) {
+ sp = new_prescr();
+ sp->_term = termp;
+ NCURSES_SP_NAME(baudrate) (NCURSES_SP_ARG);
+ }
+#else
+ (void) sp;
+#endif
+
+ T(("trying CPR (u7/u6) with %s", name));
+ alter.c_lflag &= (unsigned) ~(ECHO | ICANON | ISIG | IEXTEN);
+ alter.c_iflag &= (unsigned) ~(IXON | BRKINT | PARMRK);
+ alter.c_cc[VMIN] = 0;
+ alter.c_cc[VTIME] = 1;
+ SET_TTY(fd, &alter);
+
+ if (get_position(termp, fd, ¤t_y, ¤t_x)
+ && set_position(NCURSES_SP_ARGx termp, 9999, 9999)
+ && get_position(termp, fd, &updated_y, &updated_x)) {
+ *linep = updated_y;
+ *colp = updated_x;
+ set_position(NCURSES_SP_ARGx termp, current_y, current_x);
+ }
+ /* restore tty modes */
+ SET_TTY(fd, &saved);
+ } else {
+ T(("NOT trying CPR with fd %d (%s): %s",
+ fd, NonNull(name), NC_ISATTY(fd) ? "tty" : "not a tty"));
+ }
+
+ _nc_default_screensize(termp, linep, colp);
+}
+#else /* !USE_CHECK_SIZE */
+#define _nc_check_screensize(sp, termp, linep, colp) /* nothing */
+#endif
+#endif /* !(defined(USE_TERM_DRIVER) || defined(EXP_WIN32_DRIVER)) */
+
NCURSES_EXPORT(void)
_nc_get_screensize(SCREEN *sp,
#ifdef USE_TERM_DRIVER
- TERMINAL * termp,
+ TERMINAL *termp,
#endif
int *linep, int *colp)
/* Obtain lines/columns values from the environment and/or terminfo entry */
@@ -297,16 +487,33 @@
#else /* !USE_TERM_DRIVER */
TERMINAL *termp = cur_term;
int my_tabsize;
+ bool useEnv = _nc_prescreen.use_env;
+ bool useTioctl = _nc_prescreen.use_tioctl;
+ T((T_CALLED("_nc_get_screensize (%p)"), (void *) sp));
+#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 (_nc_prescreen.use_env || _nc_prescreen.use_tioctl) {
- int value;
+#if NCURSES_SP_FUNCS
+ if (sp) {
+ useEnv = sp->_use_env;
+ useTioctl = sp->use_tioctl;
+ }
+#endif
+ T(("useEnv:%d useTioctl:%d", useEnv, useTioctl));
+ if (useEnv || useTioctl) {
#ifdef __EMX__
{
int screendata[2];
@@ -340,8 +547,10 @@
}
#endif /* HAVE_SIZECHANGE */
- if (_nc_prescreen.use_env) {
- if (_nc_prescreen.use_tioctl) {
+ if (useEnv) {
+ int value;
+
+ if (useTioctl) {
/*
* If environment variables are used, update them.
*/
@@ -367,30 +576,26 @@
*colp = value;
T(("screen size: environment COLUMNS = %d", *colp));
}
- }
- /* if we can't get dynamic info about the size, use static */
- if (*linep <= 0) {
- *linep = (int) lines;
- }
- if (*colp <= 0) {
- *colp = (int) columns;
- }
-
- /* the ultimate fallback, assume fixed 24x80 size */
- if (*linep <= 0) {
- *linep = 24;
- }
- if (*colp <= 0) {
- *colp = 80;
+ _nc_default_screensize(termp, linep, colp);
+ } else {
+ _nc_check_screensize(sp, termp, linep, colp);
}
/*
* Put the derived values back in the screen-size caps, so
* tigetnum() and tgetnum() will do the right thing.
*/
- lines = (short) (*linep);
- columns = (short) (*colp);
+ lines = (NCURSES_INT2) (*linep);
+ columns = (NCURSES_INT2) (*colp);
+#if NCURSES_EXT_NUMBERS
+#define OldNumber(termp,name) \
+ (termp)->type.Numbers[(&name - (termp)->type2.Numbers)]
+ OldNumber(termp, lines) = (short) (*linep);
+ OldNumber(termp, columns) = (short) (*colp);
+#endif
+ } else {
+ _nc_check_screensize(sp, termp, linep, colp);
}
T(("screen size is %dx%d", *linep, *colp));
@@ -407,6 +612,7 @@
TABSIZE = my_tabsize;
#endif
T(("TABSIZE = %d", TABSIZE));
+ returnVoid;
#endif /* USE_TERM_DRIVER */
}
@@ -431,23 +637,24 @@
int old_cols = columns;
#endif
- TINFO_GET_SIZE(sp, sp->_term, &new_lines, &new_cols);
-
- /*
- * See is_term_resized() and resizeterm().
- * We're doing it this way because those functions belong to the upper
- * ncurses library, while this resides in the lower terminfo library.
- */
- if (sp != 0 && sp->_resize != 0) {
- if ((new_lines != old_lines) || (new_cols != old_cols)) {
- sp->_resize(NCURSES_SP_ARGx new_lines, new_cols);
- } else if (sp->_sig_winch && (sp->_ungetch != 0)) {
- sp->_ungetch(SP_PARM, KEY_RESIZE); /* so application can know this */
+ if (sp != 0) {
+ TINFO_GET_SIZE(sp, sp->_term, &new_lines, &new_cols);
+ /*
+ * See is_term_resized() and resizeterm().
+ * We're doing it this way because those functions belong to the upper
+ * ncurses library, while this resides in the lower terminfo library.
+ */
+ if (sp->_resize != 0) {
+ if ((new_lines != old_lines) || (new_cols != old_cols)) {
+ sp->_resize(NCURSES_SP_ARGx new_lines, new_cols);
+ } else if (sp->_sig_winch && (sp->_ungetch != 0)) {
+ sp->_ungetch(SP_PARM, KEY_RESIZE); /* so application can know this */
+ }
+ sp->_sig_winch = FALSE;
}
- sp->_sig_winch = FALSE;
}
}
-#endif
+#endif /* USE_SIZECHANGE */
/****************************************************************************
*
@@ -461,10 +668,10 @@
* just like tgetent().
*/
int
-_nc_setup_tinfo(const char *const tn, TERMTYPE *const tp)
+_nc_setup_tinfo(const char *const tn, TERMTYPE2 *const tp)
{
char filename[PATH_MAX];
- int status = _nc_read_entry(tn, filename, tp);
+ int status = _nc_read_entry2(tn, filename, tp);
/*
* If we have an entry, force all of the cancelled strings to null
@@ -474,6 +681,7 @@
*/
if (status == TGETENT_YES) {
unsigned n;
+ T(("_nc_setup_tinfo - resetting invalid booleans/strings"));
for_each_boolean(n, tp) {
if (!VALID_BOOLEAN(tp->Booleans[n]))
tp->Booleans[n] = FALSE;
@@ -488,14 +696,12 @@
#endif
/*
-** Take the real command character out of the CC environment variable
-** and substitute it in for the prototype given in 'command_character'.
-*/
+ * Take the real command character out of the CC environment variable
+ * and substitute it in for the prototype given in 'command_character'.
+ */
void
-_nc_tinfo_cmdch(TERMINAL * termp, int proto)
+_nc_tinfo_cmdch(TERMINAL *termp, int proto)
{
- unsigned i;
- char CC;
char *tmp;
/*
@@ -504,11 +710,16 @@
* name as an environment variable - using the same symbol.
*/
if ((tmp = getenv("CC")) != 0 && strlen(tmp) == 1) {
- CC = *tmp;
+ unsigned i;
+ char CC = *tmp;
+
for_each_string(i, &(termp->type)) {
- for (tmp = termp->type.Strings[i]; tmp && *tmp; tmp++) {
- if (UChar(*tmp) == proto)
- *tmp = CC;
+ tmp = termp->type.Strings[i];
+ if (VALID_STRING(tmp)) {
+ for (; *tmp; ++tmp) {
+ if (UChar(*tmp) == proto)
+ *tmp = CC;
+ }
}
}
}
@@ -528,9 +739,9 @@
*/
env = setlocale(LC_CTYPE, 0);
#else
- if (((env = getenv("LC_ALL")) != 0 && *env != '\0')
+ if (((env = getenv("LANG")) != 0 && *env != '\0')
|| ((env = getenv("LC_CTYPE")) != 0 && *env != '\0')
- || ((env = getenv("LANG")) != 0 && *env != '\0')) {
+ || ((env = getenv("LC_ALL")) != 0 && *env != '\0')) {
;
}
#endif
@@ -544,22 +755,27 @@
NCURSES_EXPORT(int)
_nc_unicode_locale(void)
{
- int result = 0;
-#if defined(__MINGW32__) && USE_WIDEC_SUPPORT
- result = 1;
+ static bool initialized = FALSE;
+ static int result = 0;
+
+ if (!initialized) {
+#if defined(_NC_WINDOWS) && USE_WIDEC_SUPPORT
+ result = 1;
#elif HAVE_LANGINFO_CODESET
- char *env = nl_langinfo(CODESET);
- result = !strcmp(env, "UTF-8");
- T(("_nc_unicode_locale(%s) ->%d", env, result));
+ char *env = nl_langinfo(CODESET);
+ result = !strcmp(env, "UTF-8");
+ T(("_nc_unicode_locale(%s) ->%d", env, result));
#else
- char *env = _nc_get_locale();
- if (env != 0) {
- if (strstr(env, ".UTF-8") != 0) {
- result = 1;
- T(("_nc_unicode_locale(%s) ->%d", env, result));
+ char *env = _nc_get_locale();
+ if (env != 0) {
+ if (strstr(env, ".UTF-8") != 0) {
+ result = 1;
+ T(("_nc_unicode_locale(%s) ->%d", env, result));
+ }
}
- }
#endif
+ initialized = TRUE;
+ }
return result;
}
@@ -571,7 +787,7 @@
* character set.
*/
NCURSES_EXPORT(int)
-_nc_locale_breaks_acs(TERMINAL * termp)
+_nc_locale_breaks_acs(TERMINAL *termp)
{
const char *env_name = "NCURSES_NO_UTF8_ACS";
const char *env;
@@ -602,19 +818,18 @@
}
NCURSES_EXPORT(int)
-TINFO_SETUP_TERM(TERMINAL ** tp,
- NCURSES_CONST char *tname,
+TINFO_SETUP_TERM(TERMINAL **tp,
+ const char *tname,
int Filedes,
int *errret,
int reuse)
{
#ifdef USE_TERM_DRIVER
TERMINAL_CONTROL_BLOCK *TCB = 0;
-#else
- int status;
#endif
TERMINAL *termp;
SCREEN *sp = 0;
+ char *myname;
int code = ERR;
START_TRACE();
@@ -635,22 +850,30 @@
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
}
-
- if (strlen(tname) > MAX_NAME_SIZE) {
+ myname = strdup(tname);
+ if (myname == NULL || strlen(myname) > MAX_NAME_SIZE) {
ret_error(TGETENT_ERR,
- "TERM environment must be <= %d characters.\n",
- MAX_NAME_SIZE);
+ "TERM environment must be 1..%d characters.\n",
+ MAX_NAME_SIZE,
+ free(myname));
}
- T(("your terminal name is %s", tname));
+ T(("your terminal name is %s", myname));
/*
* Allow output redirection. This is what SVr3 does. If stdout is
@@ -658,6 +881,10 @@
*/
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
@@ -679,8 +906,8 @@
&& (termp != 0)
&& termp->Filedes == Filedes
&& termp->_termname != 0
- && !strcmp(termp->_termname, tname)
- && _nc_name_match(termp->type.term_names, tname, "|")) {
+ && !strcmp(termp->_termname, myname)
+ && _nc_name_match(TerminalType(termp).term_names, myname, "|")) {
T(("reusing existing terminal information and mode-settings"));
code = OK;
#ifdef USE_TERM_DRIVER
@@ -689,39 +916,70 @@
} else {
#ifdef USE_TERM_DRIVER
TERMINAL_CONTROL_BLOCK *my_tcb;
- my_tcb = typeCalloc(TERMINAL_CONTROL_BLOCK, 1);
- termp = &(my_tcb->term);
+ termp = 0;
+ if ((my_tcb = typeCalloc(TERMINAL_CONTROL_BLOCK, 1)) != 0)
+ termp = &(my_tcb->term);
#else
+ int status;
+
termp = typeCalloc(TERMINAL, 1);
#endif
if (termp == 0) {
- ret_error0(TGETENT_ERR,
- "Not enough memory to create terminal structure.\n");
+ ret_error1(TGETENT_ERR,
+ "Not enough memory to create terminal structure.\n",
+ myname, free(myname));
}
+ ++_nc_globals.terminal_count;
+#if HAVE_SYSCONF
+ {
+ long limit;
+#ifdef LINE_MAX
+ limit = LINE_MAX;
+#else
+ limit = _nc_globals.getstr_limit;
+#endif
+#ifdef _SC_LINE_MAX
+ if (limit < sysconf(_SC_LINE_MAX))
+ limit = sysconf(_SC_LINE_MAX);
+#endif
+ if (_nc_globals.getstr_limit < (int) limit)
+ _nc_globals.getstr_limit = (int) limit;
+ }
+#endif /* HAVE_SYSCONF */
+ T(("using %d for getstr limit", _nc_globals.getstr_limit));
+
#ifdef USE_TERM_DRIVER
INIT_TERM_DRIVER();
+ /*
+ * _nc_get_driver() will call td_CanHandle() for each driver, and win_driver
+ * needs file descriptor to do the test, so set it before calling.
+ */
+ termp->Filedes = (short) Filedes;
TCB = (TERMINAL_CONTROL_BLOCK *) termp;
- code = _nc_globals.term_driver(TCB, tname, errret);
+ code = _nc_globals.term_driver(TCB, myname, errret);
if (code == OK) {
- termp->Filedes = (short) Filedes;
- termp->_termname = strdup(tname);
+ termp->_termname = strdup(myname);
} else {
- ret_error0(errret ? *errret : TGETENT_ERR,
- "Could not find any driver to handle this terminal.\n");
+ ret_error1(errret ? *errret : TGETENT_ERR,
+ "Could not find any driver to handle terminal.\n",
+ myname, free(myname));
}
#else
#if NCURSES_USE_DATABASE || NCURSES_USE_TERMCAP
- status = _nc_setup_tinfo(tname, &termp->type);
+ status = _nc_setup_tinfo(myname, &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(myname);
if (fallback) {
- _nc_copy_termtype(&(termp->type), fallback);
+ T(("found fallback entry"));
+ _nc_copy_termtype2(&(TerminalType(termp)), fallback);
status = TGETENT_YES;
}
}
@@ -729,33 +987,41 @@
if (status != TGETENT_YES) {
del_curterm(termp);
if (status == TGETENT_ERR) {
+ free(myname);
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",
+ myname, free(myname));
+ } else {
+ free(myname);
+ ret_error0(status, "unexpected return-code\n");
}
}
+#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
termp->Filedes = (short) Filedes;
- termp->_termname = strdup(tname);
+ termp->_termname = strdup(myname);
set_curterm(termp);
- if (command_character)
+ if (VALID_STRING(command_character))
_nc_tinfo_cmdch(termp, UChar(*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.
+ * baudrate. Also get the shell-mode so that erasechar() works.
*/
if (NC_ISATTY(Filedes)) {
- def_prog_mode();
- baudrate();
+ NCURSES_SP_NAME(def_shell_mode) (NCURSES_SP_ARG);
+ NCURSES_SP_NAME(def_prog_mode) (NCURSES_SP_ARG);
+ NCURSES_SP_NAME(baudrate) (NCURSES_SP_ARG);
}
code = OK;
#endif
@@ -786,36 +1052,99 @@
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);
+ ret_error1(TGETENT_YES, "terminal is not really generic.\n",
+ myname, free(myname));
} else {
del_curterm(termp);
- ret_error1(TGETENT_NO, "I need something more specific.\n", tname);
+ ret_error1(TGETENT_NO, "I need something more specific.\n",
+ myname, free(myname));
}
} else if (hard_copy) {
- ret_error1(TGETENT_YES, "I can't handle hardcopy terminals.\n", tname);
+ ret_error1(TGETENT_YES, "I can't handle hardcopy terminals.\n",
+ myname, free(myname));
}
#endif
+ free(myname);
returnCode(code);
}
+#ifdef USE_PTHREADS
+/*
+ * Returns a non-null pointer unless a new screen should be allocated because
+ * no match was found in the pre-screen cache.
+ */
+NCURSES_EXPORT(SCREEN *)
+_nc_find_prescr(void)
+{
+ SCREEN *result = 0;
+ PRESCREEN_LIST *p;
+ pthread_t id = GetThreadID();
+ for (p = _nc_prescreen.allocated; p != 0; p = p->next) {
+ if (p->id == id) {
+ result = p->sp;
+ break;
+ }
+ }
+ return result;
+}
+
+/*
+ * Tells ncurses to forget that this thread was associated with the pre-screen
+ * cache. It does not modify the pre-screen cache itself, since that is used
+ * for creating new screens.
+ */
+NCURSES_EXPORT(void)
+_nc_forget_prescr(void)
+{
+ PRESCREEN_LIST *p, *q;
+ pthread_t id = GetThreadID();
+ _nc_lock_global(screen);
+ for (p = _nc_prescreen.allocated, q = 0; p != 0; q = p, p = p->next) {
+ if (p->id == id) {
+ if (q) {
+ q->next = p->next;
+ } else {
+ _nc_prescreen.allocated = p->next;
+ }
+ free(p);
+ break;
+ }
+ }
+ _nc_unlock_global(screen);
+}
+#endif /* USE_PTHREADS */
+
#if NCURSES_SP_FUNCS
/*
* In case of handling multiple screens, we need to have a screen before
- * initialization in setupscreen takes place. This is to extend the substitute
- * for some of the stuff in _nc_prescreen, especially for slk and ripoff
- * handling which should be done per screen.
+ * initialization in _nc_setupscreen takes place. This is to extend the
+ * substitute for some of the stuff in _nc_prescreen, especially for slk and
+ * ripoff handling which should be done per screen.
*/
NCURSES_EXPORT(SCREEN *)
new_prescr(void)
{
- static SCREEN *sp;
+ SCREEN *sp;
START_TRACE();
T((T_CALLED("new_prescr()")));
- if (sp == 0) {
+ _nc_lock_global(screen);
+ if ((sp = _nc_find_prescr()) == 0) {
sp = _nc_alloc_screen_sp();
+ T(("_nc_alloc_screen_sp %p", (void *) sp));
if (sp != 0) {
+#ifdef USE_PTHREADS
+ PRESCREEN_LIST *p = typeCalloc(PRESCREEN_LIST, 1);
+ if (p != 0) {
+ p->id = GetThreadID();
+ p->sp = sp;
+ p->next = _nc_prescreen.allocated;
+ _nc_prescreen.allocated = p;
+ }
+#else
+ _nc_prescreen.allocated = sp;
+#endif
sp->rsp = sp->rippedoff;
sp->_filtered = _nc_prescreen.filter_mode;
sp->_use_env = _nc_prescreen.use_env;
@@ -831,7 +1160,10 @@
sp->_ESCDELAY = _nc_prescreen._ESCDELAY;
#endif
}
+ } else {
+ T(("_nc_alloc_screen_sp %p (reuse)", (void *) sp));
}
+ _nc_unlock_global(screen);
returnSP(sp);
}
#endif
@@ -842,17 +1174,26 @@
* the same TERMINAL data (see comment).
*/
NCURSES_EXPORT(int)
-_nc_setupterm(NCURSES_CONST char *tname,
+_nc_setupterm(const char *tname,
int Filedes,
int *errret,
int reuse)
{
- int res;
+ int rc = ERR;
TERMINAL *termp = 0;
- res = TINFO_SETUP_TERM(&termp, tname, Filedes, errret, reuse);
- if (ERR != res)
- NCURSES_SP_NAME(set_curterm) (CURRENT_SCREEN_PRE, termp);
- return res;
+
+ _nc_init_pthreads();
+ _nc_lock_global(prescreen);
+ START_TRACE();
+ if (TINFO_SETUP_TERM(&termp, tname, Filedes, errret, reuse) == OK) {
+ _nc_forget_prescr();
+ if (NCURSES_SP_NAME(set_curterm) (CURRENT_SCREEN_PRE, termp) != 0) {
+ rc = OK;
+ }
+ }
+ _nc_unlock_global(prescreen);
+
+ return rc;
}
#endif
@@ -863,7 +1204,7 @@
* Make cur_term point to the structure.
*/
NCURSES_EXPORT(int)
-setupterm(NCURSES_CONST char *tname, int Filedes, int *errret)
+setupterm(const char *tname, int Filedes, int *errret)
{
START_TRACE();
return _nc_setupterm(tname, Filedes, errret, FALSE);
diff --git a/ncurses/tinfo/lib_termcap.c b/ncurses/tinfo/lib_termcap.c
index fdfc494..2ece985 100644
--- a/ncurses/tinfo/lib_termcap.c
+++ b/ncurses/tinfo/lib_termcap.c
@@ -1,5 +1,6 @@
/****************************************************************************
- * Copyright (c) 1998-2012,2013 Free Software Foundation, Inc. *
+ * Copyright 2018-2020,2023 Thomas E. Dickey *
+ * Copyright 1998-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 *
@@ -48,7 +49,7 @@
#define CUR SP_TERMTYPE
#endif
-MODULE_ID("$Id: lib_termcap.c,v 1.80 2013/06/08 16:48:47 tom Exp $")
+MODULE_ID("$Id: lib_termcap.c,v 1.89 2023/05/27 20:13:10 tom Exp $")
NCURSES_EXPORT_VAR(char *) UP = 0;
NCURSES_EXPORT_VAR(char *) BC = 0;
@@ -100,8 +101,7 @@
START_TRACE();
T((T_CALLED("tgetent()")));
- TINFO_SETUP_TERM(&termp, (NCURSES_CONST char *) name,
- STDOUT_FILENO, &rc, TRUE);
+ TINFO_SETUP_TERM(&termp, name, STDOUT_FILENO, &rc, TRUE);
#ifdef USE_TERM_DRIVER
if (termp == 0 ||
@@ -153,8 +153,12 @@
}
CacheInx = best;
}
- LAST_TRM = TerminalOf(SP_PARM);
- LAST_SEQ = ++CacheSeq;
+ if (rc == 1) {
+ LAST_TRM = TerminalOf(SP_PARM);
+ LAST_SEQ = ++CacheSeq;
+ } else {
+ LAST_TRM = 0;
+ }
PC = 0;
UP = 0;
@@ -175,7 +179,8 @@
if (backspace_if_not_bs != NULL)
BC = backspace_if_not_bs;
- if ((FIX_SGR0 = _nc_trim_sgr0(&(TerminalOf(SP_PARM)->type))) != 0) {
+ if ((FIX_SGR0 = _nc_trim_sgr0(&TerminalType(TerminalOf(SP_PARM))))
+ != 0) {
if (!strcmp(FIX_SGR0, exit_attribute_mode)) {
if (FIX_SGR0 != exit_attribute_mode) {
free(FIX_SGR0);
@@ -230,15 +235,15 @@
***************************************************************************/
NCURSES_EXPORT(int)
-NCURSES_SP_NAME(tgetflag) (NCURSES_SP_DCLx NCURSES_CONST char *id)
+NCURSES_SP_NAME(tgetflag) (NCURSES_SP_DCLx const char *id)
{
int result = 0; /* Solaris returns zero for missing flag */
- int j = -1;
T((T_CALLED("tgetflag(%p, %s)"), (void *) SP_PARM, id));
if (HasTInfoTerminal(SP_PARM) && ValidCap(id)) {
- TERMTYPE *tp = &(TerminalOf(SP_PARM)->type);
+ TERMTYPE2 *tp = &TerminalType(TerminalOf(SP_PARM));
struct name_table_entry const *entry_ptr;
+ int j = -1;
entry_ptr = _nc_find_type_entry(id, BOOLEAN, TRUE);
if (entry_ptr != 0) {
@@ -266,7 +271,7 @@
#if NCURSES_SP_FUNCS
NCURSES_EXPORT(int)
-tgetflag(NCURSES_CONST char *id)
+tgetflag(const char *id)
{
return NCURSES_SP_NAME(tgetflag) (CURRENT_SCREEN, id);
}
@@ -282,15 +287,15 @@
***************************************************************************/
NCURSES_EXPORT(int)
-NCURSES_SP_NAME(tgetnum) (NCURSES_SP_DCLx NCURSES_CONST char *id)
+NCURSES_SP_NAME(tgetnum) (NCURSES_SP_DCLx const char *id)
{
int result = ABSENT_NUMERIC;
- int j = -1;
T((T_CALLED("tgetnum(%p, %s)"), (void *) SP_PARM, id));
if (HasTInfoTerminal(SP_PARM) && ValidCap(id)) {
- TERMTYPE *tp = &(TerminalOf(SP_PARM)->type);
+ TERMTYPE2 *tp = &TerminalType(TerminalOf(SP_PARM));
struct name_table_entry const *entry_ptr;
+ int j = -1;
entry_ptr = _nc_find_type_entry(id, NUMBER, TRUE);
if (entry_ptr != 0) {
@@ -318,7 +323,7 @@
#if NCURSES_SP_FUNCS
NCURSES_EXPORT(int)
-tgetnum(NCURSES_CONST char *id)
+tgetnum(const char *id)
{
return NCURSES_SP_NAME(tgetnum) (CURRENT_SCREEN, id);
}
@@ -334,15 +339,15 @@
***************************************************************************/
NCURSES_EXPORT(char *)
-NCURSES_SP_NAME(tgetstr) (NCURSES_SP_DCLx NCURSES_CONST char *id, char **area)
+NCURSES_SP_NAME(tgetstr) (NCURSES_SP_DCLx const char *id, char **area)
{
char *result = NULL;
- int j = -1;
T((T_CALLED("tgetstr(%s,%p)"), id, (void *) area));
if (HasTInfoTerminal(SP_PARM) && ValidCap(id)) {
- TERMTYPE *tp = &(TerminalOf(SP_PARM)->type);
+ TERMTYPE2 *tp = &TerminalType(TerminalOf(SP_PARM));
struct name_table_entry const *entry_ptr;
+ int j = -1;
entry_ptr = _nc_find_type_entry(id, STRING, TRUE);
if (entry_ptr != 0) {
@@ -384,20 +389,41 @@
#if NCURSES_SP_FUNCS
NCURSES_EXPORT(char *)
-tgetstr(NCURSES_CONST char *id, char **area)
+tgetstr(const char *id, char **area)
{
return NCURSES_SP_NAME(tgetstr) (CURRENT_SCREEN, id, area);
}
#endif
#if NO_LEAKS
+#undef CacheInx
+#define CacheInx num
+NCURSES_EXPORT(void)
+_nc_tgetent_leak(const TERMINAL *const termp)
+{
+ if (termp != 0) {
+ int num;
+ for (CacheInx = 0; CacheInx < TGETENT_MAX; ++CacheInx) {
+ if (LAST_TRM == termp) {
+ FreeAndNull(FIX_SGR0);
+ if (LAST_TRM != 0) {
+ LAST_TRM = 0;
+ }
+ break;
+ }
+ }
+ }
+}
+
NCURSES_EXPORT(void)
_nc_tgetent_leaks(void)
{
+ int num;
for (CacheInx = 0; CacheInx < TGETENT_MAX; ++CacheInx) {
- FreeIfNeeded(FIX_SGR0);
- if (LAST_TRM != 0)
+ if (LAST_TRM != 0) {
del_curterm(LAST_TRM);
+ _nc_tgetent_leak(LAST_TRM);
+ }
}
}
#endif
diff --git a/ncurses/tinfo/lib_termname.c b/ncurses/tinfo/lib_termname.c
index e3f6827..2d80bb3 100644
--- a/ncurses/tinfo/lib_termname.c
+++ b/ncurses/tinfo/lib_termname.c
@@ -1,5 +1,6 @@
/****************************************************************************
- * Copyright (c) 1998-2003,2009 Free Software Foundation, Inc. *
+ * Copyright 2020 Thomas E. Dickey *
+ * Copyright 1998-2003,2009 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 *
@@ -28,7 +29,7 @@
#include <curses.priv.h>
-MODULE_ID("$Id: lib_termname.c,v 1.12 2009/10/24 21:56:58 tom Exp $")
+MODULE_ID("$Id: lib_termname.c,v 1.13 2020/02/02 23:34:34 tom Exp $")
NCURSES_EXPORT(char *)
NCURSES_SP_NAME(termname) (NCURSES_SP_DCL0)
diff --git a/ncurses/tinfo/lib_tgoto.c b/ncurses/tinfo/lib_tgoto.c
index 31daf44..58b561f 100644
--- a/ncurses/tinfo/lib_tgoto.c
+++ b/ncurses/tinfo/lib_tgoto.c
@@ -1,5 +1,6 @@
/****************************************************************************
- * Copyright (c) 2000-2008,2012 Free Software Foundation, Inc. *
+ * Copyright 2018-2020,2023 Thomas E. Dickey *
+ * Copyright 2000-2008,2012 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 *
@@ -35,7 +36,7 @@
#include <ctype.h>
#include <termcap.h>
-MODULE_ID("$Id: lib_tgoto.c,v 1.16 2012/02/24 02:08:08 tom Exp $")
+MODULE_ID("$Id: lib_tgoto.c,v 1.23 2023/04/16 17:19:40 tom Exp $")
#if !PURE_TERMINFO
static bool
@@ -125,7 +126,14 @@
*value += 1;
need_BC = TRUE;
} else {
- *value = 0200; /* tputs will treat this as \0 */
+ /* tputs will pretend this is \0, which will almost
+ * always work since ANSI-compatible terminals ignore
+ * the character. ECMA-48 does not document a C1
+ * control for this value. A few (obsolete) terminals
+ * can use this value in special cases, such as cursor
+ * addressing using single-byte coordinates.
+ */
+ *value = 0200;
}
}
result[used++] = (char) *value++;
@@ -199,6 +207,16 @@
result = tgoto_internal(string, x, y);
else
#endif
- result = TPARM_2((NCURSES_CONST char *) string, y, x);
+ if ((result = TIPARM_2(string, y, x)) == NULL) {
+ /*
+ * Because termcap did not provide a more general solution such as
+ * tparm(), it was necessary to handle single-parameter capabilities
+ * using tgoto(). The internal _nc_tiparm() function returns a NULL
+ * for that case; retry for the single-parameter case.
+ */
+ if ((result = TIPARM_1(string, y)) == NULL) {
+ result = TIPARM_0(string);
+ }
+ }
returnPtr(result);
}
diff --git a/ncurses/tinfo/lib_ti.c b/ncurses/tinfo/lib_ti.c
index e9ae746..5cb77b8 100644
--- a/ncurses/tinfo/lib_ti.c
+++ b/ncurses/tinfo/lib_ti.c
@@ -1,5 +1,6 @@
/****************************************************************************
- * Copyright (c) 1998-2010,2013 Free Software Foundation, Inc. *
+ * Copyright 2018,2020 Thomas E. Dickey *
+ * Copyright 1998-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 *
@@ -36,7 +37,7 @@
#include <tic.h>
-MODULE_ID("$Id: lib_ti.c,v 1.30 2013/06/08 16:55:05 tom Exp $")
+MODULE_ID("$Id: lib_ti.c,v 1.34 2020/02/02 23:34:34 tom Exp $")
#if 0
static bool
@@ -50,16 +51,16 @@
#endif
NCURSES_EXPORT(int)
-NCURSES_SP_NAME(tigetflag) (NCURSES_SP_DCLx NCURSES_CONST char *str)
+NCURSES_SP_NAME(tigetflag) (NCURSES_SP_DCLx const char *str)
{
int result = ABSENT_BOOLEAN;
- int j = -1;
T((T_CALLED("tigetflag(%p, %s)"), (void *) SP_PARM, str));
if (HasTInfoTerminal(SP_PARM)) {
- TERMTYPE *tp = &(TerminalOf(SP_PARM)->type);
+ TERMTYPE2 *tp = &TerminalType(TerminalOf(SP_PARM));
struct name_table_entry const *entry_ptr;
+ int j = -1;
entry_ptr = _nc_find_type_entry(str, BOOLEAN, FALSE);
if (entry_ptr != 0) {
@@ -88,23 +89,23 @@
#if NCURSES_SP_FUNCS
NCURSES_EXPORT(int)
-tigetflag(NCURSES_CONST char *str)
+tigetflag(const char *str)
{
return NCURSES_SP_NAME(tigetflag) (CURRENT_SCREEN, str);
}
#endif
NCURSES_EXPORT(int)
-NCURSES_SP_NAME(tigetnum) (NCURSES_SP_DCLx NCURSES_CONST char *str)
+NCURSES_SP_NAME(tigetnum) (NCURSES_SP_DCLx const char *str)
{
- int j = -1;
int result = CANCELLED_NUMERIC; /* Solaris returns a -1 on error */
T((T_CALLED("tigetnum(%p, %s)"), (void *) SP_PARM, str));
if (HasTInfoTerminal(SP_PARM)) {
- TERMTYPE *tp = &(TerminalOf(SP_PARM)->type);
+ TERMTYPE2 *tp = &TerminalType(TerminalOf(SP_PARM));
struct name_table_entry const *entry_ptr;
+ int j = -1;
entry_ptr = _nc_find_type_entry(str, NUMBER, FALSE);
if (entry_ptr != 0) {
@@ -135,23 +136,23 @@
#if NCURSES_SP_FUNCS
NCURSES_EXPORT(int)
-tigetnum(NCURSES_CONST char *str)
+tigetnum(const char *str)
{
return NCURSES_SP_NAME(tigetnum) (CURRENT_SCREEN, str);
}
#endif
NCURSES_EXPORT(char *)
-NCURSES_SP_NAME(tigetstr) (NCURSES_SP_DCLx NCURSES_CONST char *str)
+NCURSES_SP_NAME(tigetstr) (NCURSES_SP_DCLx const char *str)
{
char *result = CANCELLED_STRING;
- int j = -1;
T((T_CALLED("tigetstr(%p, %s)"), (void *) SP_PARM, str));
if (HasTInfoTerminal(SP_PARM)) {
- TERMTYPE *tp = &(TerminalOf(SP_PARM)->type);
+ TERMTYPE2 *tp = &TerminalType(TerminalOf(SP_PARM));
struct name_table_entry const *entry_ptr;
+ int j = -1;
entry_ptr = _nc_find_type_entry(str, STRING, FALSE);
if (entry_ptr != 0) {
@@ -180,7 +181,7 @@
#if NCURSES_SP_FUNCS
NCURSES_EXPORT(char *)
-tigetstr(NCURSES_CONST char *str)
+tigetstr(const char *str)
{
return NCURSES_SP_NAME(tigetstr) (CURRENT_SCREEN, str);
}
diff --git a/ncurses/tinfo/lib_tparm.c b/ncurses/tinfo/lib_tparm.c
index 4f18859..5666b27 100644
--- a/ncurses/tinfo/lib_tparm.c
+++ b/ncurses/tinfo/lib_tparm.c
@@ -1,5 +1,6 @@
/****************************************************************************
- * Copyright (c) 1998-2014,2015 Free Software Foundation, Inc. *
+ * Copyright 2018-2021,2023 Thomas E. Dickey *
+ * Copyright 1998-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 *
@@ -37,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.94 2015/07/17 01:03:35 tom Exp $")
+MODULE_ID("$Id: lib_tparm.c,v 1.153 2023/11/04 19:28:41 tom Exp $")
/*
* char *
@@ -106,128 +117,245 @@
NCURSES_EXPORT_VAR(int) _nc_tparm_err = 0;
-#define TPS(var) _nc_prescreen.tparm_state.var
+#define TPS(var) tps->var
#define popcount _nc_popcount /* workaround for NetBSD 6.0 defect */
-#if NO_LEAKS
-NCURSES_EXPORT(void)
-_nc_free_tparm(void)
+#define get_tparm_state(term) \
+ (term != NULL \
+ ? &(term->tparm_state) \
+ : &(_nc_prescreen.tparm_state))
+
+#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
+static int which_tparm;
+static TPARM_DATA **delete_tparm;
+#endif /* HAVE_TSEARCH */
+
+static char dummy[] = ""; /* avoid const-cast */
+
+#if HAVE_TSEARCH
+static int
+cmp_format(const void *p, const void *q)
{
- 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;
+ const char *a = *(char *const *) p;
+ const char *b = *(char *const *) q;
+ return strcmp(a, b);
+}
+#endif
+
+#if HAVE_TSEARCH
+static void
+visit_nodes(const void *nodep, VISIT which, int depth)
+{
+ (void) depth;
+ if (which == preorder || which == leaf) {
+ delete_tparm[which_tparm] = *(TPARM_DATA **) nodep;
+ which_tparm++;
}
}
#endif
-static NCURSES_INLINE void
-get_space(size_t need)
+NCURSES_EXPORT(void)
+_nc_free_tparm(TERMINAL *termp)
{
- need += TPS(out_used);
- if (need > TPS(out_size)) {
- TPS(out_size) = need * 2;
- TYPE_REALLOC(char, TPS(out_size), TPS(out_buff));
+ TPARM_STATE *tps = get_tparm_state(termp);
+#if HAVE_TSEARCH
+ if (MyCount != 0) {
+ delete_tparm = typeCalloc(TPARM_DATA *, MyCount);
+ if (delete_tparm != NULL) {
+ which_tparm = 0;
+ twalk(MyCache, visit_nodes);
+ for (which_tparm = 0; which_tparm < MyCount; ++which_tparm) {
+ TPARM_DATA *ptr = delete_tparm[which_tparm];
+ if (ptr != NULL) {
+ 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;
}
-static NCURSES_INLINE void
-save_text(const char *fmt, const char *s, int len)
+static int
+tparm_error(TPARM_STATE *tps, const char *message)
{
- size_t s_len = strlen(s);
- if (len > (int) s_len)
- s_len = (size_t) len;
-
- get_space(s_len + 1);
-
- _nc_SPRINTF(TPS(out_buff) + TPS(out_used),
- _nc_SLIMIT(TPS(out_size) - TPS(out_used))
- fmt, s);
- TPS(out_used) += strlen(TPS(out_buff) + TPS(out_used));
+ (void) tps;
+ (void) message;
+ DEBUG(2, ("%s: %s", message, _nc_visbuf(TPS(tparam_base))));
+ return ++_nc_tparm_err;
}
+#define get_space(tps, need) \
+{ \
+ size_t need2get = need + TPS(out_used); \
+ if (need2get > TPS(out_size)) { \
+ TPS(out_size) = need2get * 2; \
+ TYPE_REALLOC(char, TPS(out_size), TPS(out_buff)); \
+ } \
+}
+
+#if NCURSES_EXPANDED
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);
-
- _nc_SPRINTF(TPS(out_buff) + TPS(out_used),
- _nc_SLIMIT(TPS(out_size) - TPS(out_used))
- fmt, number);
- TPS(out_used) += strlen(TPS(out_buff) + TPS(out_used));
+ (get_space) (TPARM_STATE *tps, size_t need) {
+ get_space(tps, need);
}
+#undef get_space
+#endif
+
+#define save_text(tps, fmt, s, len) \
+{ \
+ size_t s_len = (size_t) len + strlen(s) + strlen(fmt); \
+ get_space(tps, s_len + 1); \
+ _nc_SPRINTF(TPS(out_buff) + TPS(out_used), \
+ _nc_SLIMIT(TPS(out_size) - TPS(out_used)) \
+ fmt, s); \
+ TPS(out_used) += strlen(TPS(out_buff) + TPS(out_used)); \
+}
+
+#if NCURSES_EXPANDED
static NCURSES_INLINE void
-save_char(int c)
-{
- if (c == 0)
- c = 0200;
- get_space((size_t) 1);
- TPS(out_buff)[TPS(out_used)++] = (char) c;
+ (save_text) (TPARM_STATE *tps, const char *fmt, const char *s, int len) {
+ save_text(tps, fmt, s, len);
}
+#undef save_text
+#endif
+
+#define save_number(tps, fmt, number, len) \
+{ \
+ size_t s_len = (size_t) len + 30 + strlen(fmt); \
+ get_space(tps, s_len + 1); \
+ _nc_SPRINTF(TPS(out_buff) + TPS(out_used), \
+ _nc_SLIMIT(TPS(out_size) - TPS(out_used)) \
+ fmt, number); \
+ TPS(out_used) += strlen(TPS(out_buff) + TPS(out_used)); \
+}
+
+#if NCURSES_EXPANDED
static NCURSES_INLINE void
-npush(int x)
-{
- if (TPS(stack_ptr) < STACKSIZE) {
- TPS(stack)[TPS(stack_ptr)].num_type = TRUE;
- TPS(stack)[TPS(stack_ptr)].data.num = x;
- TPS(stack_ptr)++;
- } else {
- DEBUG(2, ("npush: stack overflow: %s", _nc_visbuf(TPS(tparam_base))));
- _nc_tparm_err++;
- }
+ (save_number) (TPARM_STATE *tps, const char *fmt, int number, int len) {
+ save_number(tps, fmt, number, len);
}
+#undef save_number
+#endif
+
+#define save_char(tps, c) \
+{ \
+ get_space(tps, (size_t) 1); \
+ TPS(out_buff)[TPS(out_used)++] = (char) ((c == 0) ? 0200 : c); \
+}
+
+#if NCURSES_EXPANDED
+static NCURSES_INLINE void
+ (save_char) (TPARM_STATE *tps, int c) {
+ save_char(tps, c);
+}
+
+#undef save_char
+#endif
+
+#define npush(tps, x) \
+{ \
+ if (TPS(stack_ptr) < STACKSIZE) { \
+ TPS(stack)[TPS(stack_ptr)].num_type = TRUE; \
+ TPS(stack)[TPS(stack_ptr)].data.num = x; \
+ TPS(stack_ptr)++; \
+ } else { \
+ (void) tparm_error(tps, "npush: stack overflow"); \
+ } \
+}
+
+#if NCURSES_EXPANDED
+static NCURSES_INLINE void
+ (npush) (TPARM_STATE *tps, int x) {
+ npush(tps, x);
+}
+
+#undef npush
+#endif
+
+#define spush(tps, x) \
+{ \
+ if (TPS(stack_ptr) < STACKSIZE) { \
+ TPS(stack)[TPS(stack_ptr)].num_type = FALSE; \
+ TPS(stack)[TPS(stack_ptr)].data.str = x; \
+ TPS(stack_ptr)++; \
+ } else { \
+ (void) tparm_error(tps, "spush: stack overflow"); \
+ } \
+}
+
+#if NCURSES_EXPANDED
+static NCURSES_INLINE void
+ (spush) (TPARM_STATE *tps, char *x) {
+ spush(tps, x);
+}
+
+#undef spush
+#endif
+
+#define npop(tps) \
+ ((TPS(stack_ptr)-- > 0) \
+ ? ((TPS(stack)[TPS(stack_ptr)].num_type) \
+ ? TPS(stack)[TPS(stack_ptr)].data.num \
+ : 0) \
+ : (tparm_error(tps, "npop: stack underflow"), \
+ TPS(stack_ptr) = 0))
+
+#if NCURSES_EXPANDED
static NCURSES_INLINE int
-npop(void)
-{
- int result = 0;
- if (TPS(stack_ptr) > 0) {
- TPS(stack_ptr)--;
- if (TPS(stack)[TPS(stack_ptr)].num_type)
- result = TPS(stack)[TPS(stack_ptr)].data.num;
- } else {
- DEBUG(2, ("npop: stack underflow: %s", _nc_visbuf(TPS(tparam_base))));
- _nc_tparm_err++;
- }
- return result;
+ (npop) (TPARM_STATE *tps) {
+ return npop(tps);
}
+#undef npop
+#endif
-static NCURSES_INLINE void
-spush(char *x)
-{
- if (TPS(stack_ptr) < STACKSIZE) {
- TPS(stack)[TPS(stack_ptr)].num_type = FALSE;
- TPS(stack)[TPS(stack_ptr)].data.str = x;
- TPS(stack_ptr)++;
- } else {
- DEBUG(2, ("spush: stack overflow: %s", _nc_visbuf(TPS(tparam_base))));
- _nc_tparm_err++;
- }
-}
+#define spop(tps) \
+ ((TPS(stack_ptr)-- > 0) \
+ ? ((!TPS(stack)[TPS(stack_ptr)].num_type \
+ && TPS(stack)[TPS(stack_ptr)].data.str != 0) \
+ ? TPS(stack)[TPS(stack_ptr)].data.str \
+ : dummy) \
+ : (tparm_error(tps, "spop: stack underflow"), \
+ dummy))
+#if NCURSES_EXPANDED
static NCURSES_INLINE char *
-spop(void)
-{
- static char dummy[] = ""; /* avoid const-cast */
- char *result = dummy;
- if (TPS(stack_ptr) > 0) {
- TPS(stack_ptr)--;
- if (!TPS(stack)[TPS(stack_ptr)].num_type
- && TPS(stack)[TPS(stack_ptr)].data.str != 0)
- result = TPS(stack)[TPS(stack_ptr)].data.str;
- } else {
- DEBUG(2, ("spop: stack underflow: %s", _nc_visbuf(TPS(tparam_base))));
- _nc_tparm_err++;
- }
- return result;
+ (spop) (TPARM_STATE *tps) {
+ return spop(tps);
}
+#undef spop
+#endif
static NCURSES_INLINE const char *
parse_format(const char *s, char *format, int *len)
@@ -324,9 +452,6 @@
return s;
}
-#define isUPPER(c) ((c) >= 'A' && (c) <= 'Z')
-#define isLOWER(c) ((c) >= 'a' && (c) <= 'z')
-
/*
* 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
@@ -339,21 +464,22 @@
* 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(TERMINAL *term, const char *string, char **p_is_s, int *popcount)
{
+ TPARM_STATE *tps = get_tparm_state(term);
size_t len2;
int i;
int lastpop = -1;
int len;
int number = 0;
+ int level = -1;
const char *cp = string;
- static char dummy[] = "";
if (cp == 0)
return 0;
- if ((len2 = strlen(cp)) > TPS(fmt_size)) {
- TPS(fmt_size) = len2 + TPS(fmt_size) + 2;
+ if ((len2 = strlen(cp)) + 2 > TPS(fmt_size)) {
+ TPS(fmt_size) += len2 + 2;
TPS(fmt_buff) = typeRealloc(char, TPS(fmt_size), TPS(fmt_buff));
if (TPS(fmt_buff) == 0)
return 0;
@@ -378,22 +504,27 @@
#ifdef EXP_XTERM_1005
case 'u':
#endif
- if (lastpop <= 0)
- number++;
+ if (lastpop <= 0) {
+ tc_BUMP();
+ }
+ level -= 1;
lastpop = -1;
break;
case 'l':
case 's':
- if (lastpop > 0)
+ if (lastpop > 0) {
+ level -= 1;
p_is_s[lastpop - 1] = dummy;
- ++number;
+ }
+ tc_BUMP();
break;
case 'p':
cp++;
i = (UChar(*cp) - '0');
if (i >= 0 && i <= NUM_PARM) {
+ ++level;
lastpop = i;
if (lastpop > *popcount)
*popcount = lastpop;
@@ -401,20 +532,22 @@
break;
case 'P':
- ++number;
++cp;
break;
case 'g':
+ ++level;
cp++;
break;
case S_QUOTE:
+ ++level;
cp += 2;
lastpop = -1;
break;
case L_BRACE:
+ ++level;
cp++;
while (isdigit(UChar(*cp))) {
cp++;
@@ -434,14 +567,15 @@
case '=':
case '<':
case '>':
+ tc_BUMP();
+ level -= 1; /* pop 2, operate, push 1 */
lastpop = -1;
- number += 2;
break;
case '!':
case '~':
+ tc_BUMP();
lastpop = -1;
- ++number;
break;
case 'i':
@@ -458,100 +592,220 @@
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(TERMINAL *term, const char *string, TPARM_DATA *result)
{
- char *p_is_s[NUM_PARM];
- TPARM_ARG param[NUM_PARM];
- int popcount = 0;
+ TPARM_STATE *tps = get_tparm_state(term);
+ int rc = OK;
+
+ TPS(out_used) = 0;
+ memset(result, 0, sizeof(*result));
+
+ if (!VALID_STRING(string)) {
+ TR(TRACE_CALLS, ("%s: format is invalid", TPS(tname)));
+ rc = ERR;
+ } else {
+#if HAVE_TSEARCH
+ TPARM_DATA *fs;
+ void *ft;
+
+ result->format = string;
+ if ((ft = tfind(result, &MyCache, cmp_format)) != 0) {
+ size_t len2;
+ fs = *(TPARM_DATA **) ft;
+ *result = *fs;
+ if ((len2 = strlen(string)) + 2 > TPS(fmt_size)) {
+ TPS(fmt_size) += len2 + 2;
+ TPS(fmt_buff) = typeRealloc(char, TPS(fmt_size), TPS(fmt_buff));
+ if (TPS(fmt_buff) == 0)
+ return ERR;
+ }
+ } 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(term, 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;
+
+ 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 {
+ free(fs);
+ rc = ERR;
+ }
+ } else {
+ free(fs);
+ rc = ERR;
+ }
+ } else {
+ rc = ERR;
+ }
+#endif
+ }
+ }
+ }
+
+ return rc;
+}
+
+/*
+ * 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 < 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) {
+ data->param[i] = va_arg(ap, TPARM_ARG);
+ } else {
+ 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_STATE *tps, TPARM_DATA *data)
+{
+ bool termcap_hack = FALSE;
+
+ TPS(stack_ptr) = 0;
+
+ if (data->num_popped == 0) {
+ int i;
+
+ termcap_hack = TRUE;
+ for (i = data->num_parsed - 1; i >= 0; i--) {
+ if (data->p_is_s[i]) {
+ spush(tps, data->p_is_s[i]);
+ } else {
+ npush(tps, (int) data->param[i]);
+ }
+ }
+ }
+ return termcap_hack;
+}
+
+#ifdef TRACE
+static void
+tparm_trace_call(TPARM_STATE *tps, const char *string, TPARM_DATA *data)
+{
+ if (USE_TRACEF(TRACE_CALLS)) {
+ int i;
+ for (i = 0; i < data->num_actual; i++) {
+ if (data->p_is_s[i] != 0) {
+ save_text(tps, ", %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, data->num_actual);
+ break;
+ } else {
+ save_number(tps, ", %d", (int) data->param[i], 0);
+ }
+ }
+ _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(tps, string, data) /* nothing */
+#endif /* TRACE */
+
+#define init_vars(name) \
+ if (!name##_used) { \
+ name##_used = TRUE; \
+ memset(name##_vars, 0, sizeof(name##_vars)); \
+ }
+
+static NCURSES_INLINE char *
+tparam_internal(TPARM_STATE *tps, const char *string, TPARM_DATA *data)
+{
int number;
- int num_args;
int len;
int level;
int x, y;
int i;
+ const char *s;
const char *cp = string;
- size_t len2;
- bool termcap_hack;
- bool incremented_two;
-
- if (cp == NULL)
- return NULL;
-
- TPS(out_used) = 0;
- len2 = strlen(cp);
-
+ size_t len2 = strlen(cp);
+ bool incremented_two = FALSE;
+ bool termcap_hack = tparm_tc_compat(tps, data);
/*
- * 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.
+ * SVr4 curses stores variables 'A' to 'Z' in the TERMINAL structure (so
+ * they are initialized once to zero), and variables 'a' to 'z' on the
+ * stack in tparm, referring to the former as "static" and the latter as
+ * "dynamic". However, it makes no check to ensure that the "dynamic"
+ * variables are initialized.
+ *
+ * Solaris xpg4 curses makes no distinction between the upper/lower, and
+ * stores the common set of 26 variables on the stack, without initializing
+ * them.
+ *
+ * In ncurses, both sets of variables are initialized on the first use.
*/
- number = _nc_tparm_analyze(cp, p_is_s, &popcount);
- if (TPS(fmt_buff) == 0)
+ bool dynamic_used = FALSE;
+ int dynamic_vars[NUM_VARS];
+
+ tparm_trace_call(tps, string, data);
+
+ if (TPS(fmt_buff) == NULL) {
+ T((T_RETURN("<null>")));
return NULL;
-
- incremented_two = FALSE;
-
- if (number > NUM_PARM)
- number = NUM_PARM;
- if (popcount > NUM_PARM)
- popcount = NUM_PARM;
- num_args = max(popcount, number);
-
- 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;
- } else if (use_TPARM_ARG) {
- param[i] = va_arg(ap, TPARM_ARG);
- } else {
- 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.
- */
- TPS(stack_ptr) = 0;
- termcap_hack = FALSE;
- if (popcount == 0) {
- termcap_hack = TRUE;
- popcount = number;
- for (i = number - 1; i >= 0; i--) {
- if (p_is_s[i])
- spush(p_is_s[i]);
- else
- npush((int) param[i]);
- }
- }
-#ifdef TRACE
- 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
- save_number(", %d", (int) param[i], 0);
- }
- _tracef(T_CALLED("%s(%s%s)"), TPS(tname), _nc_visbuf(cp), TPS(out_buff));
- TPS(out_used) = 0;
- _nc_unlock_global(tracef);
- }
-#endif /* TRACE */
-
while ((cp - string) < (int) len2) {
if (*cp != '%') {
- save_char(UChar(*cp));
+ save_char(tps, UChar(*cp));
} else {
TPS(tparam_base) = cp++;
cp = parse_format(cp, TPS(fmt_buff), &len);
@@ -559,50 +813,54 @@
default:
break;
case '%':
- save_char('%');
+ save_char(tps, '%');
break;
case 'd': /* FALLTHRU */
case 'o': /* FALLTHRU */
case 'x': /* FALLTHRU */
case 'X': /* FALLTHRU */
- save_number(TPS(fmt_buff), npop(), len);
+ x = npop(tps);
+ save_number(tps, TPS(fmt_buff), x, len);
break;
case 'c': /* FALLTHRU */
- save_char(npop());
+ x = npop(tps);
+ save_char(tps, x);
break;
#ifdef EXP_XTERM_1005
case 'u':
{
unsigned char target[10];
- unsigned source = (unsigned) npop();
+ unsigned source = (unsigned) npop(tps);
int rc = _nc_conv_to_utf8(target, source, (unsigned)
sizeof(target));
int n;
for (n = 0; n < rc; ++n) {
- save_char(target[n]);
+ save_char(tps, target[n]);
}
}
break;
#endif
case 'l':
- npush((int) strlen(spop()));
+ s = spop(tps);
+ npush(tps, (int) strlen(s));
break;
case 's':
- save_text(TPS(fmt_buff), spop(), len);
+ s = spop(tps);
+ save_text(tps, TPS(fmt_buff), s, len);
break;
case 'p':
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(tps, data->p_is_s[i]);
} else {
- npush((int) param[i]);
+ npush(tps, (int) data->param[i]);
}
}
break;
@@ -611,10 +869,11 @@
cp++;
if (isUPPER(*cp)) {
i = (UChar(*cp) - 'A');
- TPS(static_vars)[i] = npop();
+ TPS(static_vars)[i] = npop(tps);
} else if (isLOWER(*cp)) {
i = (UChar(*cp) - 'a');
- TPS(dynamic_var)[i] = npop();
+ init_vars(dynamic);
+ dynamic_vars[i] = npop(tps);
}
break;
@@ -622,16 +881,17 @@
cp++;
if (isUPPER(*cp)) {
i = (UChar(*cp) - 'A');
- npush(TPS(static_vars)[i]);
+ npush(tps, TPS(static_vars)[i]);
} else if (isLOWER(*cp)) {
i = (UChar(*cp) - 'a');
- npush(TPS(dynamic_var)[i]);
+ init_vars(dynamic);
+ npush(tps, dynamic_vars[i]);
}
break;
case S_QUOTE:
cp++;
- npush(UChar(*cp));
+ npush(tps, UChar(*cp));
cp++;
break;
@@ -642,83 +902,95 @@
number = (number * 10) + (UChar(*cp) - '0');
cp++;
}
- npush(number);
+ npush(tps, number);
break;
case '+':
- npush(npop() + npop());
+ y = npop(tps);
+ x = npop(tps);
+ npush(tps, x + y);
break;
case '-':
- y = npop();
- x = npop();
- npush(x - y);
+ y = npop(tps);
+ x = npop(tps);
+ npush(tps, x - y);
break;
case '*':
- npush(npop() * npop());
+ y = npop(tps);
+ x = npop(tps);
+ npush(tps, x * y);
break;
case '/':
- y = npop();
- x = npop();
- npush(y ? (x / y) : 0);
+ y = npop(tps);
+ x = npop(tps);
+ npush(tps, y ? (x / y) : 0);
break;
case 'm':
- y = npop();
- x = npop();
- npush(y ? (x % y) : 0);
+ y = npop(tps);
+ x = npop(tps);
+ npush(tps, y ? (x % y) : 0);
break;
case 'A':
- y = npop();
- x = npop();
- npush(y && x);
+ y = npop(tps);
+ x = npop(tps);
+ npush(tps, y && x);
break;
case 'O':
- y = npop();
- x = npop();
- npush(y || x);
+ y = npop(tps);
+ x = npop(tps);
+ npush(tps, y || x);
break;
case '&':
- npush(npop() & npop());
+ y = npop(tps);
+ x = npop(tps);
+ npush(tps, x & y);
break;
case '|':
- npush(npop() | npop());
+ y = npop(tps);
+ x = npop(tps);
+ npush(tps, x | y);
break;
case '^':
- npush(npop() ^ npop());
+ y = npop(tps);
+ x = npop(tps);
+ npush(tps, x ^ y);
break;
case '=':
- y = npop();
- x = npop();
- npush(x == y);
+ y = npop(tps);
+ x = npop(tps);
+ npush(tps, x == y);
break;
case '<':
- y = npop();
- x = npop();
- npush(x < y);
+ y = npop(tps);
+ x = npop(tps);
+ npush(tps, x < y);
break;
case '>':
- y = npop();
- x = npop();
- npush(x > y);
+ y = npop(tps);
+ x = npop(tps);
+ npush(tps, x > y);
break;
case '!':
- npush(!npop());
+ x = npop(tps);
+ npush(tps, !x);
break;
case '~':
- npush(~npop());
+ x = npop(tps);
+ npush(tps, ~x);
break;
case 'i':
@@ -731,15 +1003,15 @@
*/
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;
@@ -748,7 +1020,7 @@
break;
case 't':
- x = npop();
+ x = npop(tps);
if (!x) {
/* scan forward for %e or %; at level zero */
cp++;
@@ -807,64 +1079,330 @@
cp++;
} /* endwhile (*cp) */
- get_space((size_t) 1);
+ get_space(tps, (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
+#ifdef CUR
+/*
+ * Only a few standard capabilities accept string parameters. The others that
+ * are parameterized accept only numeric parameters.
+ */
+static bool
+check_string_caps(TPARM_DATA *data, const char *string)
+{
+ bool result = FALSE;
+
+#define CHECK_CAP(name) (VALID_STRING(name) && !strcmp(name, string))
+
+ /*
+ * Disallow string parameters unless we can check them against a terminal
+ * description.
+ */
+ if (cur_term != NULL) {
+ int want_type = 0;
+
+ if (CHECK_CAP(pkey_key))
+ want_type = 2; /* function key #1, type string #2 */
+ else if (CHECK_CAP(pkey_local))
+ want_type = 2; /* function key #1, execute string #2 */
+ else if (CHECK_CAP(pkey_xmit))
+ want_type = 2; /* function key #1, transmit string #2 */
+ else if (CHECK_CAP(plab_norm))
+ want_type = 2; /* label #1, show string #2 */
+#ifdef pkey_plab
+ else if (CHECK_CAP(pkey_plab))
+ want_type = 6; /* function key #1, type string #2, show string #3 */
+#endif
+#if NCURSES_XNAMES
+ else {
+ char *check;
+
+ check = tigetstr("Cs");
+ if (CHECK_CAP(check))
+ want_type = 1; /* style #1 */
+
+ check = tigetstr("Ms");
+ if (CHECK_CAP(check))
+ want_type = 3; /* storage unit #1, content #2 */
+ }
#endif
-NCURSES_EXPORT(char *)
-tparm_varargs(NCURSES_CONST char *string,...)
-{
- va_list ap;
- char *result;
-
- _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 (want_type == data->tparm_type) {
+ result = TRUE;
+ } else {
+ T(("unexpected string-parameter"));
+ }
+ }
return result;
}
-#if !NCURSES_TPARM_VARARGS
+#define ValidCap(allow_strings) (myData.tparm_type == 0 || \
+ (allow_strings && \
+ check_string_caps(&myData, string)))
+#else
+#define ValidCap(allow_strings) 1
+#endif
+
+#if NCURSES_TPARM_VARARGS
+
NCURSES_EXPORT(char *)
-tparm_proto(NCURSES_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, ...)
{
- return tparm_varargs(string, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+ TPARM_STATE *tps = get_tparm_state(cur_term);
+ TPARM_DATA myData;
+ char *result = NULL;
+
+ _nc_tparm_err = 0;
+#ifdef TRACE
+ tps->tname = "tparm";
+#endif /* TRACE */
+
+ if (tparm_setup(cur_term, string, &myData) == OK && ValidCap(TRUE)) {
+ va_list ap;
+
+ va_start(ap, string);
+ tparm_copy_valist(&myData, TRUE, ap);
+ va_end(ap);
+
+ result = tparam_internal(tps, string, &myData);
+ }
+ return result;
}
+
+#else /* !NCURSES_TPARM_VARARGS */
+
+NCURSES_EXPORT(char *)
+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)
+{
+ TPARM_STATE *tps = get_tparm_state(cur_term);
+ TPARM_DATA myData;
+ char *result = NULL;
+
+ _nc_tparm_err = 0;
+#ifdef TRACE
+ tps->tname = "tparm";
+#endif /* TRACE */
+
+#define string_ok (sizeof(char*) <= sizeof(TPARM_ARG))
+
+ if (tparm_setup(cur_term, string, &myData) == OK && ValidCap(string_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(tps, string, &myData);
+ }
+ return result;
+}
+
#endif /* NCURSES_TPARM_VARARGS */
NCURSES_EXPORT(char *)
-tiparm(const char *string,...)
+tiparm(const char *string, ...)
{
- va_list ap;
- char *result;
+ TPARM_STATE *tps = get_tparm_state(cur_term);
+ TPARM_DATA myData;
+ char *result = NULL;
_nc_tparm_err = 0;
- va_start(ap, string);
#ifdef TRACE
- TPS(tname) = "tiparm";
+ tps->tname = "tiparm";
#endif /* TRACE */
- result = tparam_internal(FALSE, string, ap);
- va_end(ap);
+
+ if (tparm_setup(cur_term, string, &myData) == OK && ValidCap(TRUE)) {
+ va_list ap;
+
+ va_start(ap, string);
+ tparm_copy_valist(&myData, FALSE, ap);
+ va_end(ap);
+
+ result = tparam_internal(tps, string, &myData);
+ }
return result;
}
+
+/*
+ * Use tparm if the formatting string matches the expected number of parameters
+ * counting string-parameters.
+ */
+NCURSES_EXPORT(char *)
+tiparm_s(int num_expected, int tparm_type, const char *string, ...)
+{
+ TPARM_STATE *tps = get_tparm_state(cur_term);
+ TPARM_DATA myData;
+ char *result = NULL;
+
+ _nc_tparm_err = 0;
+#ifdef TRACE
+ tps->tname = "tiparm_s";
+#endif /* TRACE */
+ if (num_expected >= 0 &&
+ num_expected <= 9 &&
+ tparm_type >= 0 &&
+ tparm_type < 7 && /* limit to 2 string parameters */
+ tparm_setup(cur_term, string, &myData) == OK &&
+ myData.tparm_type == tparm_type &&
+ myData.num_actual == num_expected) {
+ va_list ap;
+
+ va_start(ap, string);
+ tparm_copy_valist(&myData, FALSE, ap);
+ va_end(ap);
+
+ result = tparam_internal(tps, string, &myData);
+ }
+ return result;
+}
+
+/*
+ * Analyze the formatting string, return the analysis.
+ */
+NCURSES_EXPORT(int)
+tiscan_s(int *num_expected, int *tparm_type, const char *string)
+{
+ TPARM_DATA myData;
+ int result = ERR;
+
+#ifdef TRACE
+ TPARM_STATE *tps = get_tparm_state(cur_term);
+ tps->tname = "tiscan_s";
+#endif /* TRACE */
+
+ if (tparm_setup(cur_term, string, &myData) == OK) {
+ *num_expected = myData.num_actual;
+ *tparm_type = myData.tparm_type;
+ result = OK;
+ }
+ return result;
+}
+
+/*
+ * The internal-use flavor ensures that parameters are numbers, not strings.
+ * In addition to ensuring that they are numbers, it ensures that the parameter
+ * count is consistent with intended usage.
+ *
+ * Unlike the general-purpose tparm/tiparm, these internal calls are fairly
+ * well defined:
+ *
+ * expected == 0 - not applicable
+ * expected == 1 - set color, or vertical/horizontal addressing
+ * expected == 2 - cursor addressing
+ * expected == 4 - initialize color or color pair
+ * expected == 9 - set attributes
+ *
+ * Only for the last case (set attributes) should a parameter be optional.
+ * Also, a capability which calls for more parameters than expected should be
+ * ignored.
+ *
+ * Return a null if the parameter-checks fail. Otherwise, return a pointer to
+ * the formatted capability string.
+ */
+NCURSES_EXPORT(char *)
+_nc_tiparm(int expected, const char *string, ...)
+{
+ TPARM_STATE *tps = get_tparm_state(cur_term);
+ TPARM_DATA myData;
+ char *result = NULL;
+
+ _nc_tparm_err = 0;
+ T((T_CALLED("_nc_tiparm(%d, %s, ...)"), expected, _nc_visbuf(string)));
+#ifdef TRACE
+ tps->tname = "_nc_tiparm";
+#endif /* TRACE */
+
+ if (tparm_setup(cur_term, string, &myData) == OK && ValidCap(FALSE)) {
+#ifdef CUR
+ if (myData.num_actual != expected && cur_term != NULL) {
+ int needed = expected;
+ if (CHECK_CAP(to_status_line)) {
+ needed = 0; /* allow for xterm's status line */
+ } else if (CHECK_CAP(set_a_background)) {
+ needed = 0; /* allow for monochrome fakers */
+ } else if (CHECK_CAP(set_a_foreground)) {
+ needed = 0;
+ } else if (CHECK_CAP(set_background)) {
+ needed = 0;
+ } else if (CHECK_CAP(set_foreground)) {
+ needed = 0;
+ }
+#if NCURSES_XNAMES
+ else {
+ char *check;
+
+ check = tigetstr("xm");
+ if (CHECK_CAP(check)) {
+ needed = 3;
+ }
+ check = tigetstr("S0");
+ if (CHECK_CAP(check)) {
+ needed = 0; /* used in screen-base */
+ }
+ }
+#endif
+ if (myData.num_actual >= needed && myData.num_actual <= expected)
+ expected = myData.num_actual;
+ }
+#endif
+ if (myData.num_actual == 0 && expected) {
+ T(("missing parameter%s, expected %s%d",
+ expected > 1 ? "s" : "",
+ expected == 9 ? "up to " : "",
+ expected));
+ } else if (myData.num_actual > expected) {
+ T(("too many parameters, have %d, expected %d",
+ myData.num_actual,
+ expected));
+ } else if (expected != 9 && myData.num_actual != expected) {
+ T(("expected %d parameters, have %d",
+ myData.num_actual,
+ expected));
+ } else {
+ va_list ap;
+
+ va_start(ap, string);
+ tparm_copy_valist(&myData, FALSE, ap);
+ va_end(ap);
+
+ result = tparam_internal(tps, string, &myData);
+ }
+ }
+ returnPtr(result);
+}
+
+/*
+ * Improve tic's checks by resetting the terminfo "static variables" before
+ * calling functions which may update them.
+ */
+NCURSES_EXPORT(void)
+_nc_reset_tparm(TERMINAL *term)
+{
+ TPARM_STATE *tps = get_tparm_state(term);
+ memset(TPS(static_vars), 0, sizeof(TPS(static_vars)));
+}
diff --git a/ncurses/tinfo/lib_tputs.c b/ncurses/tinfo/lib_tputs.c
index 09cbbc2..f834532 100644
--- a/ncurses/tinfo/lib_tputs.c
+++ b/ncurses/tinfo/lib_tputs.c
@@ -1,5 +1,6 @@
/****************************************************************************
- * Copyright (c) 1998-2013,2015 Free Software Foundation, Inc. *
+ * Copyright 2018-2022,2023 Thomas E. Dickey *
+ * Copyright 1998-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 *
@@ -51,12 +52,12 @@
#include <termcap.h> /* ospeed */
#include <tic.h>
-MODULE_ID("$Id: lib_tputs.c,v 1.96 2015/01/03 23:51:23 tom Exp $")
+MODULE_ID("$Id: lib_tputs.c,v 1.111 2023/09/16 16:05:15 tom Exp $")
NCURSES_EXPORT_VAR(char) PC = 0; /* used by termcap library */
NCURSES_EXPORT_VAR(NCURSES_OSPEED) ospeed = 0; /* used by termcap library */
-NCURSES_EXPORT_VAR(int) _nc_nulls_sent = 0; /* used by 'tack' program */
+NCURSES_EXPORT_VAR(int) _nc_nulls_sent = 0;
#if NCURSES_NO_PADDING
NCURSES_EXPORT(void)
@@ -88,6 +89,9 @@
{
T((T_CALLED("delay_output(%p,%d)"), (void *) SP_PARM, ms));
+ if (ms > MAX_DELAY_MSECS)
+ ms = MAX_DELAY_MSECS;
+
if (!HasTInfoTerminal(SP_PARM))
returnCode(ERR);
@@ -119,16 +123,20 @@
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;
- ssize_t res;
+ size_t amount = SP_PARM->out_inuse;
- SP->out_inuse = 0;
+ TR(TRACE_CHARPUT, ("flushing %ld/%ld bytes",
+ (unsigned long) amount, _nc_outchars));
while (amount) {
- res = write(SP_PARM->_ofd, buf, amount);
-
+ ssize_t res = write(SP_PARM->_ofd, buf, amount);
if (res > 0) {
/* if the write was incomplete, try again */
amount -= (size_t) res;
@@ -141,8 +149,17 @@
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);
}
+ if (SP_PARM != 0)
+ SP_PARM->out_inuse = 0;
+ returnVoid;
}
#if NCURSES_SP_FUNCS
@@ -263,21 +280,24 @@
NCURSES_SP_OUTC outc)
{
NCURSES_SP_OUTC my_outch = GetOutCh();
- bool always_delay;
- bool normal_delay;
+ bool always_delay = FALSE;
+ bool normal_delay = FALSE;
int number;
#if BSD_TPUTS
int trailpad;
#endif /* BSD_TPUTS */
#ifdef TRACE
- char addrbuf[32];
-
if (USE_TRACEF(TRACE_TPUTS)) {
- if (outc == NCURSES_SP_NAME(_nc_outch))
+ char addrbuf[32];
+ TR_FUNC_BFR(1);
+
+ if (outc == NCURSES_SP_NAME(_nc_outch)) {
_nc_STRCPY(addrbuf, "_nc_outch", sizeof(addrbuf));
- else
- _nc_SPRINTF(addrbuf, _nc_SLIMIT(sizeof(addrbuf)) "%p", outc);
+ } else {
+ _nc_SPRINTF(addrbuf, _nc_SLIMIT(sizeof(addrbuf)) "%s",
+ TR_FUNC_ARG(0, outc));
+ }
if (_nc_tputs_trace) {
_tracef("tputs(%s = %s, %d, %s) called", _nc_tputs_trace,
_nc_visbuf(string), affcnt, addrbuf);
@@ -289,32 +309,30 @@
}
#endif /* TRACE */
- if (SP_PARM != 0 && !HasTInfoTerminal(SP_PARM))
- return ERR;
-
if (!VALID_STRING(string))
return ERR;
- if (
+ if (SP_PARM != 0 && HasTInfoTerminal(SP_PARM)) {
+ if (
#if NCURSES_SP_FUNCS
- (SP_PARM != 0 && SP_PARM->_term == 0)
+ (SP_PARM != 0 && SP_PARM->_term == 0)
#else
- cur_term == 0
+ cur_term == 0
#endif
- ) {
- always_delay = FALSE;
- normal_delay = TRUE;
- } else {
- always_delay = (string == bell) || (string == flash_screen);
- normal_delay =
- !xon_xoff
- && padding_baud_rate
+ ) {
+ always_delay = FALSE;
+ normal_delay = TRUE;
+ } else {
+ always_delay = (string == bell) || (string == flash_screen);
+ normal_delay =
+ !xon_xoff
+ && padding_baud_rate
#if NCURSES_NO_PADDING
- && !GetNoPadding(SP_PARM)
+ && !GetNoPadding(SP_PARM)
#endif
- && (_nc_baudrate(ospeed) >= padding_baud_rate);
+ && (_nc_baudrate(ospeed) >= padding_baud_rate);
+ }
}
-
#if BSD_TPUTS
/*
* This ugly kluge deals with the fact that some ancient BSD programs
@@ -413,7 +431,7 @@
*/
if (trailpad > 0
&& (always_delay || normal_delay))
- delay_output(trailpad / 10);
+ NCURSES_SP_NAME(delay_output) (NCURSES_SP_ARGx trailpad / 10);
#endif /* BSD_TPUTS */
SetOutCh(my_outch);
@@ -425,7 +443,7 @@
_nc_outc_wrapper(SCREEN *sp, int c)
{
if (0 == sp) {
- return (ERR);
+ return fputc(c, stdout);
} else {
return sp->jump(c);
}
diff --git a/ncurses/tinfo/lib_ttyflags.c b/ncurses/tinfo/lib_ttyflags.c
index 43bed35..6363a80 100644
--- a/ncurses/tinfo/lib_ttyflags.c
+++ b/ncurses/tinfo/lib_ttyflags.c
@@ -1,5 +1,6 @@
/****************************************************************************
- * Copyright (c) 1998-2012,2014 Free Software Foundation, Inc. *
+ * Copyright 2020 Thomas E. Dickey *
+ * Copyright 1998-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 *
@@ -41,42 +42,42 @@
#define CUR SP_TERMTYPE
#endif
-MODULE_ID("$Id: lib_ttyflags.c,v 1.30 2014/04/26 18:47:20 juergen 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)
{
+ TERMINAL *termp = TerminalOf(SP_PARM);
int result = OK;
- if (buf == 0 || SP_PARM == 0) {
+ if (buf == 0 || termp == 0) {
result = ERR;
} else {
- TERMINAL *termp = TerminalOf(SP_PARM);
- if (0 == termp) {
- result = ERR;
- } else {
#ifdef USE_TERM_DRIVER
+ if (SP_PARM != 0) {
result = CallDriver_2(SP_PARM, td_sgmode, FALSE, buf);
-#else
- for (;;) {
- if (GET_TTY(termp->Filedes, buf) != 0) {
- if (errno == EINTR)
- continue;
- result = ERR;
- }
- break;
- }
-#endif
+ } else {
+ result = ERR;
}
-
- if (result == ERR)
- memset(buf, 0, sizeof(*buf));
+#else
+ for (;;) {
+ if (GET_TTY(termp->Filedes, buf) != 0) {
+ if (errno == EINTR)
+ continue;
+ result = ERR;
+ }
+ break;
+ }
+#endif
TR(TRACE_BITS, ("_nc_get_tty_mode(%d): %s",
termp ? termp->Filedes : -1,
_nc_trace_ttymode(buf)));
}
+ if (result == ERR && buf != 0)
+ memset(buf, 0, sizeof(*buf));
+
return (result);
}
@@ -141,7 +142,8 @@
int rc = ERR;
TERMINAL *termp = TerminalOf(SP_PARM);
- T((T_CALLED("def_shell_mode(%p)"), (void *) SP_PARM));
+ T((T_CALLED("def_shell_mode(%p) ->term %p"),
+ (void *) SP_PARM, (void *) termp));
if (termp != 0) {
#ifdef USE_TERM_DRIVER
@@ -154,6 +156,8 @@
#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;
@@ -179,7 +183,7 @@
int rc = ERR;
TERMINAL *termp = TerminalOf(SP_PARM);
- T((T_CALLED("def_prog_mode(%p)"), (void *) SP_PARM));
+ T((T_CALLED("def_prog_mode(%p) ->term %p"), (void *) SP_PARM, (void *) termp));
if (termp != 0) {
#ifdef USE_TERM_DRIVER
@@ -191,6 +195,8 @@
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
@@ -215,7 +221,7 @@
int rc = ERR;
TERMINAL *termp = TerminalOf(SP_PARM);
- T((T_CALLED("reset_prog_mode(%p)"), (void *) SP_PARM));
+ T((T_CALLED("reset_prog_mode(%p) ->term %p"), (void *) SP_PARM, (void *) termp));
if (termp != 0) {
#ifdef USE_TERM_DRIVER
@@ -247,7 +253,8 @@
int rc = ERR;
TERMINAL *termp = TerminalOf(SP_PARM);
- T((T_CALLED("reset_shell_mode(%p)"), (void *) SP_PARM));
+ T((T_CALLED("reset_shell_mode(%p) ->term %p"),
+ (void *) SP_PARM, (void *) termp));
if (termp != 0) {
#ifdef USE_TERM_DRIVER
diff --git a/ncurses/tinfo/lib_win32con.c b/ncurses/tinfo/lib_win32con.c
new file mode 100644
index 0000000..2d6857a
--- /dev/null
+++ b/ncurses/tinfo/lib_win32con.c
@@ -0,0 +1,1252 @@
+/****************************************************************************
+ * Copyright 2020-2021,2023 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.14 2023/08/05 20:44:38 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 read_screen_data(void);
+
+#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 is 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 is 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;
+}
+
+#if 0
+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;
+}
+#endif
+
+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 mmask_t
+decode_mouse(SCREEN *sp, int mask)
+{
+ mmask_t 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 |= decode_mouse(sp, sp->_drv_mouse_new_buttons);
+ } else {
+ /* cf: BUTTON_PRESSED, BUTTON_RELEASED */
+ work.bstate |= (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"
+ "On newer versions of Windows, the calling program should create a PTY-like.\n"
+ "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;
+
+#define SaveConsoleMode(handle, value) \
+ GetConsoleMode(WINCONSOLE.handle, &WINCONSOLE.originalMode.value)
+
+ if (WINCONSOLE.isTermInfoConsole) {
+ WINCONSOLE.inp = GetStdHandle(STD_INPUT_HANDLE);
+ WINCONSOLE.out = GetStdHandle(STD_OUTPUT_HANDLE);
+ WINCONSOLE.hdl = WINCONSOLE.out;
+
+ SaveConsoleMode(inp, dwFlagIn);
+ SaveConsoleMode(out, dwFlagOut);
+
+ } else {
+ b = AllocConsole();
+
+ if (!b)
+ b = AttachConsole(ATTACH_PARENT_PROCESS);
+
+ WINCONSOLE.inp = GetDirectHandle("CONIN$", FILE_SHARE_READ);
+ WINCONSOLE.out = GetDirectHandle("CONOUT$", FILE_SHARE_WRITE);
+
+ SaveConsoleMode(inp, dwFlagIn);
+ SaveConsoleMode(out, dwFlagOut);
+
+ if (getenv("NCGDB") || getenv("NCURSES_CONSOLE2")) {
+ WINCONSOLE.hdl = WINCONSOLE.out;
+ T(("... will not buffer console"));
+ } else {
+ T(("... creating console buffer"));
+ WINCONSOLE.hdl =
+ CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ 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 0000000..c67c8ce
--- /dev/null
+++ b/ncurses/tinfo/lib_win32util.c
@@ -0,0 +1,134 @@
+/****************************************************************************
+ * Copyright 2020-2021,2023 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.4 2023/06/17 17:19:06 tom 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 its 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.
+ Although 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 */
+
+#if HAVE_GETTIMEOFDAY == 2
+#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 // HAVE_GETTIMEOFDAY == 2
+
+#endif // _NC_WINDOWS
diff --git a/ncurses/tinfo/make_hash.c b/ncurses/tinfo/make_hash.c
index 37ac765..78a684c 100644
--- a/ncurses/tinfo/make_hash.c
+++ b/ncurses/tinfo/make_hash.c
@@ -1,5 +1,6 @@
/****************************************************************************
- * Copyright (c) 1998-2012,2013 Free Software Foundation, Inc. *
+ * Copyright 2018-2020,2024 Thomas E. Dickey *
+ * Copyright 2009-2013,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 *
@@ -34,7 +35,6 @@
/*
* make_hash.c --- build-time program for constructing comp_captab.c
- *
*/
#include <build.priv.h>
@@ -44,14 +44,14 @@
#include <ctype.h>
-MODULE_ID("$Id: make_hash.c,v 1.13 2013/09/28 20:55:47 tom Exp $")
+MODULE_ID("$Id: make_hash.c,v 1.34 2024/03/02 19:35:40 tom Exp $")
/*
* _nc_make_hash_table()
*
* Takes the entries in table[] and hashes them into hash_table[]
- * by name. There are CAPTABSIZE entries in table[] and HASHTABSIZE
- * slots in hash_table[].
+ * by name. There are CAPTABSIZE entries in the predefined table[]
+ * and HASHTABSIZE slots in hash_table[].
*
*/
@@ -59,6 +59,14 @@
#define MODULE_ID(id) /*nothing */
#include <tinfo/doalloc.c>
+#define L_PAREN "("
+#define R_PAREN ")"
+#define L_BRACE "{"
+#define R_BRACE "}"
+
+static const char *typenames[] =
+{"BOOLEAN", "NUMBER", "STRING"};
+
static void
failed(const char *s)
{
@@ -82,7 +90,7 @@
*
* Computes the hashing function on the given string.
*
- * The current hash function is the sum of each consectutive pair
+ * The current hash function is the sum of each consecutive pair
* of characters, taken as two-byte integers, mod HASHTABSIZE.
*
*/
@@ -93,36 +101,40 @@
long sum = 0;
while (*string) {
- sum += (long) (*string + (*(string + 1) << 8));
+ sum += (long) (UChar(*string) + (UChar(*(string + 1)) << 8));
string++;
}
return (int) (sum % HASHTABSIZE);
}
+#define UNUSED -1
+
static void
-_nc_make_hash_table(struct name_table_entry *table,
- HashValue * hash_table)
+_nc_make_hash_table(struct user_table_entry *table,
+ HashValue * hash_table,
+ unsigned tablesize)
{
- short i;
+ unsigned i;
int hashvalue;
int collisions = 0;
for (i = 0; i < HASHTABSIZE; i++) {
- hash_table[i] = -1;
+ hash_table[i] = UNUSED;
}
- for (i = 0; i < CAPTABSIZE; i++) {
- hashvalue = hash_function(table[i].nte_name);
+ for (i = 0; i < tablesize; i++) {
+ hashvalue = hash_function(table[i].ute_name);
if (hash_table[hashvalue] >= 0)
collisions++;
- if (hash_table[hashvalue] != 0)
- table[i].nte_link = hash_table[hashvalue];
- hash_table[hashvalue] = i;
+ if (hash_table[hashvalue] != UNUSED) {
+ table[i].ute_link = hash_table[hashvalue];
+ }
+ hash_table[hashvalue] = (HashValue) i;
}
- printf("/* %d collisions out of %d entries */\n", collisions, CAPTABSIZE);
+ printf("/* %d collisions out of %d entries */\n", collisions, tablesize);
}
/*
@@ -156,10 +168,18 @@
int col = 0;
- if (list == 0 && (list = typeCalloc(char *, (MAX_COLUMNS + 1))) == 0)
- return (0);
+ if (buffer == 0) {
+ free(list);
+ list = 0;
+ return 0;
+ }
if (*buffer != '#') {
+ if (list == 0) {
+ list = typeCalloc(char *, (MAX_COLUMNS + 1));
+ if (list == 0)
+ return (0);
+ }
while (*buffer != '\0') {
char *s;
for (s = buffer; (*s != '\0') && !isspace(UChar(*s)); s++)
@@ -188,21 +208,58 @@
return col ? list : 0;
}
+#define SetType(n,t) \
+ if (is_user) \
+ name_table[n].ute_type |= (int)(1 << (t)); \
+ else \
+ name_table[n].ute_type = (t)
+
+#define GetType(n) \
+ (is_user \
+ ? get_type(name_table[n].ute_type) \
+ : typenames[name_table[n].ute_type])
+
+static char *
+get_type(int type_mask)
+{
+ static char result[80];
+ unsigned n;
+ _nc_STRCPY(result, L_PAREN, sizeof(result));
+ for (n = 0; n < 3; ++n) {
+ if ((1 << n) & type_mask) {
+ size_t want = 5 + strlen(typenames[n]);
+ if (want > sizeof(result)) {
+ fprintf(stderr, "Buffer is not large enough for %s + %s\n",
+ result, typenames[n]);
+ exit(EXIT_FAILURE);
+ }
+ if (result[1])
+ _nc_STRCAT(result, "|", sizeof(result));
+ _nc_STRCAT(result, "1<<", sizeof(result));
+ _nc_STRCAT(result, typenames[n], sizeof(result));
+ }
+ }
+ _nc_STRCAT(result, R_PAREN, sizeof(result));
+ return result;
+}
+
int
main(int argc, char **argv)
{
- struct name_table_entry *name_table = typeCalloc(struct
- name_table_entry, CAPTABSIZE);
+ unsigned tablesize = CAPTABSIZE;
+ struct user_table_entry *name_table = typeCalloc(struct
+ user_table_entry, tablesize);
HashValue *hash_table = typeCalloc(HashValue, HASHTABSIZE);
- const char *root_name = "";
+ const char *root_name;
int column = 0;
int bigstring = 0;
- int n;
+ unsigned n;
+ unsigned nn;
+ unsigned tableused = 0;
+ bool is_user;
+ const char *table_name;
char buffer[BUFSIZ];
- static const char *typenames[] =
- {"BOOLEAN", "NUMBER", "STRING"};
-
short BoolCount = 0;
short NumCount = 0;
short StrCount = 0;
@@ -220,42 +277,80 @@
fprintf(stderr, "usage: make_hash column root_name bigstring\n");
exit(EXIT_FAILURE);
}
+ is_user = (*root_name == 'u');
+ table_name = (is_user ? "user" : "name");
/*
* Read the table into our arrays.
*/
- for (n = 0; (n < CAPTABSIZE) && fgets(buffer, BUFSIZ, stdin);) {
- char **list, *nlp = strchr(buffer, '\n');
+ for (n = 0; (n < tablesize) && fgets(buffer, BUFSIZ, stdin);) {
+ char **list;
+ char *nlp = strchr(buffer, '\n');
if (nlp)
*nlp = '\0';
+ else
+ buffer[sizeof(buffer) - 2] = '\0';
list = parse_columns(buffer);
if (list == 0) /* blank or comment */
continue;
- if (column > count_columns(list)) {
+ if (is_user) {
+ if (strcmp(list[0], "userdef"))
+ continue;
+ } else if (!strcmp(list[0], "userdef")) {
+ continue;
+ }
+ if (column < 0 || column > count_columns(list)) {
fprintf(stderr, "expected %d columns, have %d:\n%s\n",
column,
count_columns(list),
buffer);
exit(EXIT_FAILURE);
}
- name_table[n].nte_link = -1; /* end-of-hash */
- name_table[n].nte_name = strmalloc(list[column]);
+ nn = tableused;
+ if (is_user) {
+ unsigned j;
+ for (j = 0; j < tableused; ++j) {
+ if (!strcmp(list[column], name_table[j].ute_name)) {
+ nn = j;
+ break;
+ }
+ }
+ }
+ if (nn == tableused) {
+ name_table[nn].ute_link = -1; /* end-of-hash */
+ name_table[nn].ute_name = strmalloc(list[column]);
+ ++tableused;
+ }
+
if (!strcmp(list[2], "bool")) {
- name_table[n].nte_type = BOOLEAN;
- name_table[n].nte_index = BoolCount++;
+ SetType(nn, BOOLEAN);
+ name_table[nn].ute_index = BoolCount++;
} else if (!strcmp(list[2], "num")) {
- name_table[n].nte_type = NUMBER;
- name_table[n].nte_index = NumCount++;
+ SetType(nn, NUMBER);
+ name_table[nn].ute_index = NumCount++;
} else if (!strcmp(list[2], "str")) {
- name_table[n].nte_type = STRING;
- name_table[n].nte_index = StrCount++;
+ SetType(nn, STRING);
+ name_table[nn].ute_index = StrCount++;
+ if (is_user) {
+ if (*list[3] != '-') {
+ unsigned j;
+ name_table[nn].ute_argc = (unsigned) strlen(list[3]);
+ for (j = 0; j < name_table[nn].ute_argc; ++j) {
+ if (list[3][j] == 's') {
+ name_table[nn].ute_args |= (1U << j);
+ }
+ }
+ }
+ }
} else {
fprintf(stderr, "Unknown type: %s\n", list[2]);
exit(EXIT_FAILURE);
}
n++;
}
- _nc_make_hash_table(name_table, hash_table);
+ if (tablesize > tableused)
+ tablesize = tableused;
+ _nc_make_hash_table(name_table, hash_table, tablesize);
/*
* Write the compiled tables to standard output
@@ -265,66 +360,86 @@
int nxt;
printf("static const char %s_names_text[] = \\\n", root_name);
- for (n = 0; n < CAPTABSIZE; n++) {
- nxt = (int) strlen(name_table[n].nte_name) + 5;
+ for (n = 0; n < tablesize; n++) {
+ nxt = (int) strlen(name_table[n].ute_name) + 5;
if (nxt + len > 72) {
printf("\\\n");
len = 0;
}
- printf("\"%s\\0\" ", name_table[n].nte_name);
+ printf("\"%s\\0\" ", name_table[n].ute_name);
len += nxt;
}
printf(";\n\n");
len = 0;
- printf("static name_table_data const %s_names_data[] =\n",
+ printf("static %s_table_data const %s_names_data[] =\n",
+ table_name,
root_name);
- printf("{\n");
- for (n = 0; n < CAPTABSIZE; n++) {
- printf("\t{ %15d,\t%10s,\t%3d, %3d }%c\n",
- len,
- typenames[name_table[n].nte_type],
- name_table[n].nte_index,
- name_table[n].nte_link,
- n < CAPTABSIZE - 1 ? ',' : ' ');
- len += (int) strlen(name_table[n].nte_name) + 1;
+ printf("%s\n", L_BRACE);
+ for (n = 0; n < tablesize; n++) {
+ printf("\t%s %15d,\t%10s,", L_BRACE, len, GetType(n));
+ if (is_user)
+ printf("\t%d,%d,",
+ name_table[n].ute_argc,
+ name_table[n].ute_args);
+ printf("\t%3d, %3d %s%c\n",
+ name_table[n].ute_index,
+ name_table[n].ute_link,
+ R_BRACE,
+ n < tablesize - 1 ? ',' : ' ');
+ len += (int) strlen(name_table[n].ute_name) + 1;
}
- printf("};\n\n");
- printf("static struct name_table_entry *_nc_%s_table = 0;\n\n", root_name);
+ printf("%s;\n\n", R_BRACE);
+ printf("static struct %s_table_entry *_nc_%s_table = 0;\n\n",
+ table_name,
+ root_name);
} else {
- printf("static struct name_table_entry const _nc_%s_table[] =\n",
+ printf("static struct %s_table_entry const _nc_%s_table[] =\n",
+ table_name,
root_name);
- printf("{\n");
- for (n = 0; n < CAPTABSIZE; n++) {
+ printf("%s\n", L_BRACE);
+ for (n = 0; n < tablesize; n++) {
_nc_SPRINTF(buffer, _nc_SLIMIT(sizeof(buffer)) "\"%s\"",
- name_table[n].nte_name);
- printf("\t{ %15s,\t%10s,\t%3d, %3d }%c\n",
- buffer,
- typenames[name_table[n].nte_type],
- name_table[n].nte_index,
- name_table[n].nte_link,
- n < CAPTABSIZE - 1 ? ',' : ' ');
+ name_table[n].ute_name);
+ printf("\t%s %15s,\t%10s,", L_BRACE, buffer, GetType(n));
+ if (is_user)
+ printf("\t%d,%d,",
+ name_table[n].ute_argc,
+ name_table[n].ute_args);
+ printf("\t%3d, %3d %s%c\n",
+ name_table[n].ute_index,
+ name_table[n].ute_link,
+ R_BRACE,
+ n < tablesize - 1 ? ',' : ' ');
}
- printf("};\n\n");
+ printf("%s;\n\n", R_BRACE);
}
printf("static const HashValue _nc_%s_hash_table[%d] =\n",
root_name,
HASHTABSIZE + 1);
- printf("{\n");
+ printf("%s\n", L_BRACE);
for (n = 0; n < HASHTABSIZE; n++) {
printf("\t%3d,\n", hash_table[n]);
}
printf("\t0\t/* base-of-table */\n");
- printf("};\n\n");
+ printf("%s;\n\n", R_BRACE);
- printf("#if (BOOLCOUNT!=%d)||(NUMCOUNT!=%d)||(STRCOUNT!=%d)\n",
- BoolCount, NumCount, StrCount);
- printf("#error\t--> term.h and comp_captab.c disagree about the <--\n");
- printf("#error\t--> numbers of booleans, numbers and/or strings <--\n");
- printf("#endif\n\n");
+ if (!is_user) {
+ printf("#if (BOOLCOUNT!=%d)||(NUMCOUNT!=%d)||(STRCOUNT!=%d)\n",
+ BoolCount, NumCount, StrCount);
+ printf("#error\t--> term.h and comp_captab.c disagree about the <--\n");
+ printf("#error\t--> numbers of booleans, numbers and/or strings <--\n");
+ printf("#endif\n\n");
+ }
free(hash_table);
+ for (n = 0; (n < tablesize); ++n) {
+ free((void *) name_table[n].ute_name);
+ }
+ free(name_table);
+ parse_columns(0);
+
return EXIT_SUCCESS;
}
diff --git a/ncurses/tinfo/make_keys.c b/ncurses/tinfo/make_keys.c
index fa0c2f2..b8eb934 100644
--- a/ncurses/tinfo/make_keys.c
+++ b/ncurses/tinfo/make_keys.c
@@ -1,5 +1,6 @@
/****************************************************************************
- * Copyright (c) 1998-2011,2015 Free Software Foundation, Inc. *
+ * Copyright 2020,2021 Thomas E. Dickey *
+ * Copyright 1998-2011,2015 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 *
@@ -39,7 +40,7 @@
#define USE_TERMLIB 1
#include <build.priv.h>
-MODULE_ID("$Id: make_keys.c,v 1.21 2015/07/16 01:10:03 tom Exp $")
+MODULE_ID("$Id: make_keys.c,v 1.23 2021/08/18 20:55:25 tom Exp $")
#include <names.c>
@@ -127,11 +128,13 @@
{
static const char *prefix[] =
{
- "#ifndef NCU_KEYS_H",
- "#define NCU_KEYS_H 1",
+ "#ifndef _INIT_KEYTRY_H",
+ "#define _INIT_KEYTRY_H 1",
"",
"/* This file was generated by MAKE_KEYS */",
"",
+ "#include <tic.h>",
+ "",
"#if BROKEN_LINKER",
"static",
"#endif",
@@ -142,7 +145,7 @@
{
"\t{ 0, 0} };",
"",
- "#endif /* NCU_KEYS_H */",
+ "#endif /* _INIT_KEYTRY_H */",
0
};
diff --git a/ncurses/tinfo/name_match.c b/ncurses/tinfo/name_match.c
index c648535..71e584d 100644
--- a/ncurses/tinfo/name_match.c
+++ b/ncurses/tinfo/name_match.c
@@ -1,5 +1,6 @@
/****************************************************************************
- * Copyright (c) 1999-2012,2013 Free Software Foundation, Inc. *
+ * Copyright 2020 Thomas E. Dickey *
+ * Copyright 1998-2013,2016 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 *
@@ -33,7 +34,7 @@
#include <curses.priv.h>
#include <tic.h>
-MODULE_ID("$Id: name_match.c,v 1.23 2013/05/25 20:20:08 tom Exp $")
+MODULE_ID("$Id: name_match.c,v 1.25 2020/02/02 23:34:34 tom Exp $")
#define FirstName _nc_globals.first_name
@@ -58,8 +59,6 @@
NCURSES_EXPORT(char *)
_nc_first_name(const char *const sp)
{
- unsigned n;
-
#if NO_LEAKS
if (sp == 0) {
if (FirstName != 0) {
@@ -72,6 +71,7 @@
FirstName = typeMalloc(char, MAX_NAME_SIZE + 1);
if (FirstName != 0) {
+ unsigned n;
const char *src = sp;
#if NCURSES_USE_TERMCAP && NCURSES_XNAMES
src = skip_index(sp);
@@ -93,11 +93,13 @@
NCURSES_EXPORT(int)
_nc_name_match(const char *const namelst, const char *const name, const char *const delim)
{
- const char *s, *d, *t;
- int code, found;
+ const char *s;
if ((s = namelst) != 0) {
while (*s != '\0') {
+ const char *d, *t;
+ int code, found;
+
for (d = name; *d != '\0'; d++) {
if (*s != *d)
break;
diff --git a/ncurses/tinfo/obsolete.c b/ncurses/tinfo/obsolete.c
index 63476dc..cc62f18 100644
--- a/ncurses/tinfo/obsolete.c
+++ b/ncurses/tinfo/obsolete.c
@@ -1,5 +1,6 @@
/****************************************************************************
- * Copyright (c) 2013,2014 Free Software Foundation, Inc. *
+ * Copyright 2020,2023 Thomas E. Dickey *
+ * Copyright 2013-2014,2016 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 *
@@ -36,10 +37,10 @@
#include <curses.priv.h>
-MODULE_ID("$Id: obsolete.c,v 1.3 2014/10/11 02:39:35 tom Exp $")
+MODULE_ID("$Id: obsolete.c,v 1.11 2023/10/21 15:38:47 tom Exp $")
/*
- * Obsolete entrypoint retained for binary compatbility.
+ * Obsolete entrypoint retained for binary compatibility.
*/
NCURSES_EXPORT(void)
NCURSES_SP_NAME(_nc_set_buffer) (NCURSES_SP_DCLx FILE *ofp, int buffered)
@@ -68,7 +69,7 @@
size_t need = strlen(s);
result = malloc(need + 1);
if (result != 0) {
- strcpy(result, s);
+ _nc_STRCPY(result, s, need);
}
}
return result;
@@ -237,3 +238,98 @@
#undef CH
}
#endif /* EXP_XTERM_1005 */
+
+#ifdef EXP_OOM_TESTING
+/*
+ * Out-of-memory testing, suitable for checking if initialization (and limited
+ * running) recovers from errors due to insufficient memory. In practice, this
+ * is unlikely except with artificially constructed tests (or poorly behaved
+ * applications).
+ */
+#undef malloc
+#undef calloc
+#undef realloc
+#undef free
+#undef strdup
+
+#define TR_OOM(stmt) T(stmt)
+
+static long oom_limit = -1;
+static long oom_count = 0;
+
+static bool
+oom_check(void)
+{
+ static bool initialized = FALSE;
+ static bool triggered = FALSE;
+ bool result = FALSE;
+
+ if (!initialized) {
+ char *env = getenv("NCURSES_OOM_TESTING");
+ initialized = TRUE;
+ if (env != NULL) {
+ char *check;
+ oom_limit = strtol(env, &check, 0);
+ if (check != NULL && *check != '\0')
+ oom_limit = 0;
+ }
+ }
+ ++oom_count;
+ if (oom_limit >= 0) {
+ result = (oom_count > oom_limit);
+ if (result && !triggered) {
+ triggered = TRUE;
+ TR_OOM(("out-of-memory"));
+ }
+ }
+ return result;
+}
+
+NCURSES_EXPORT(void *)
+_nc_oom_malloc(size_t size)
+{
+ char *result = (oom_check()
+ ? NULL
+ : malloc(size));
+ TR_OOM(("oom #%ld malloc(%ld) %p", oom_count, size, result));
+ return result;
+}
+
+NCURSES_EXPORT(void *)
+_nc_oom_calloc(size_t nmemb, size_t size)
+{
+ char *result = (oom_check()
+ ? NULL
+ : calloc(nmemb, size));
+ TR_OOM(("oom #%ld calloc(%ld, %ld) %p", oom_count, nmemb, size, result));
+ return result;
+}
+
+NCURSES_EXPORT(void *)
+_nc_oom_realloc(void *ptr, size_t size)
+{
+ char *result = (oom_check()
+ ? NULL
+ : realloc(ptr, size));
+ TR_OOM(("oom #%ld realloc(%p, %ld) %p", oom_count, ptr, size, result));
+ return result;
+}
+
+NCURSES_EXPORT(void)
+_nc_oom_free(void *ptr)
+{
+ ++oom_count;
+ TR_OOM(("oom #%ld free(%p)", oom_count, ptr));
+ free(ptr);
+}
+
+NCURSES_EXPORT(char *)
+_nc_oom_strdup(const char *ptr)
+{
+ char *result = (oom_check()
+ ? NULL
+ : strdup(ptr));
+ TR_OOM(("oom #%ld strdup(%p) %p", oom_count, ptr, result));
+ return result;
+}
+#endif /* EXP_OOM_TESTING */
diff --git a/ncurses/tinfo/parse_entry.c b/ncurses/tinfo/parse_entry.c
index 0dc1414..13fef49 100644
--- a/ncurses/tinfo/parse_entry.c
+++ b/ncurses/tinfo/parse_entry.c
@@ -1,5 +1,6 @@
/****************************************************************************
- * Copyright (c) 1998-2011,2012 Free Software Foundation, Inc. *
+ * Copyright 2018-2022,2023 Thomas E. Dickey *
+ * Copyright 1998-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 *
@@ -47,7 +48,7 @@
#include <ctype.h>
#include <tic.h>
-MODULE_ID("$Id: parse_entry.c,v 1.80 2015/04/04 14:18:38 tom Exp $")
+MODULE_ID("$Id: parse_entry.c,v 1.108 2023/04/24 22:32:33 tom Exp $")
#ifdef LINT
static short const parametrized[] =
@@ -56,17 +57,17 @@
#include <parametrized.h>
#endif
-static void postprocess_termcap(TERMTYPE *, bool);
-static void postprocess_terminfo(TERMTYPE *);
+static void postprocess_termcap(TERMTYPE2 *, bool);
+static void postprocess_terminfo(TERMTYPE2 *);
static struct name_table_entry const *lookup_fullname(const char *name);
#if NCURSES_XNAMES
static struct name_table_entry const *
-_nc_extend_names(ENTRY * entryp, char *name, int token_type)
+_nc_extend_names(ENTRY * entryp, const char *name, int token_type)
{
static struct name_table_entry temp;
- TERMTYPE *tp = &(entryp->tterm);
+ TERMTYPE2 *tp = &(entryp->tterm);
unsigned offset = 0;
unsigned actual;
unsigned tindex;
@@ -109,7 +110,7 @@
/* Well, we are given a cancel for a name that we don't recognize */
return _nc_extend_names(entryp, name, STRING);
default:
- return 0;
+ return NULL;
}
/* Adjust the 'offset' (insertion-point) to keep the lists of extended
@@ -141,6 +142,11 @@
for (last = (unsigned) (max - 1); last > tindex; last--)
if (!found) {
+ char *saved;
+
+ if ((saved = _nc_save_str(name)) == NULL)
+ return NULL;
+
switch (token_type) {
case BOOLEAN:
tp->ext_Booleans++;
@@ -152,7 +158,7 @@
case NUMBER:
tp->ext_Numbers++;
tp->num_Numbers++;
- TYPE_REALLOC(short, tp->num_Numbers, tp->Numbers);
+ TYPE_REALLOC(NCURSES_INT2, tp->num_Numbers, tp->Numbers);
for_each_value(tp->num_Numbers)
tp->Numbers[last] = tp->Numbers[last - 1];
break;
@@ -168,7 +174,7 @@
TYPE_REALLOC(char *, actual, tp->ext_Names);
while (--actual > offset)
tp->ext_Names[actual] = tp->ext_Names[actual - 1];
- tp->ext_Names[offset] = _nc_save_str(name);
+ tp->ext_Names[offset] = saved;
}
temp.nte_name = tp->ext_Names[offset];
@@ -178,9 +184,79 @@
return &temp;
}
+
+static const char *
+usertype2s(int mask)
+{
+ const char *result = "unknown";
+ if (mask & (1 << BOOLEAN)) {
+ result = "boolean";
+ } else if (mask & (1 << NUMBER)) {
+ result = "number";
+ } else if (mask & (1 << STRING)) {
+ result = "string";
+ }
+ return result;
+}
+
+static bool
+expected_type(const char *name, int token_type, bool silent)
+{
+ struct user_table_entry const *entry = _nc_find_user_entry(name);
+ bool result = TRUE;
+ if ((entry != 0) && (token_type != CANCEL)) {
+ int have_type = (1 << token_type);
+ if (!(entry->ute_type & have_type)) {
+ if (!silent)
+ _nc_warning("expected %s-type for %s, have %s",
+ usertype2s(entry->ute_type),
+ name,
+ usertype2s(have_type));
+ result = FALSE;
+ }
+ }
+ return result;
+}
#endif /* NCURSES_XNAMES */
/*
+ * A valid entry name uses characters from the "portable character set"
+ * (more commonly referred to as US-ASCII), and disallows some of the
+ * punctuation characters:
+ *
+ * '/' is a pathname separator
+ * '\' may be a pathname separator, but more important, is an escape
+ * '|' delimits names and description
+ * '#' denotes a numeric value
+ * '=' denotes a string value
+ * '@' denotes a cancelled symbol
+ * ',' separates terminfo capabilities
+ * ':' separates termcap capabilities
+ *
+ * Termcap capability names may begin with a '#' or '@' (since they have
+ * exactly two characters).
+ */
+static bool
+valid_entryname(const char *name)
+{
+ bool result = TRUE;
+ bool first = TRUE;
+ int ch;
+ while ((ch = UChar(*name++)) != '\0') {
+ if (ch <= ' ' || ch > '~' || strchr("/\\|=,:", ch) != NULL) {
+ result = FALSE;
+ break;
+ }
+ if (!first && strchr("#@", ch) != NULL) {
+ result = FALSE;
+ break;
+ }
+ first = FALSE;
+ }
+ return result;
+}
+
+/*
* int
* _nc_parse_entry(entry, literal, silent)
*
@@ -203,24 +279,29 @@
{ bad_tc_usage = TRUE; \
_nc_warning("Legacy termcap allows only a trailing tc= clause"); }
-#define MAX_NUMBER 0x7fff /* positive shorts only */
+#define MAX_NUMBER MAX_OF_TYPE(NCURSES_INT2)
NCURSES_EXPORT(int)
-_nc_parse_entry(struct entry *entryp, int literal, bool silent)
+_nc_parse_entry(ENTRY * entryp, int literal, bool silent)
{
int token_type;
struct name_table_entry const *entry_ptr;
char *ptr, *base;
+ const char *name;
bool bad_tc_usage = FALSE;
+ TR(TRACE_DATABASE,
+ (T_CALLED("_nc_parse_entry(entry=%p, literal=%d, silent=%d)"),
+ (void *) entryp, literal, silent));
+
token_type = _nc_get_token(silent);
if (token_type == EOF)
- return (EOF);
+ returnDB(EOF);
if (token_type != NAMES)
_nc_err_abort("Entry does not start with terminal names in column one");
- _nc_init_entry(&entryp->tterm);
+ _nc_init_entry(entryp);
entryp->cstart = _nc_comment_start;
entryp->cend = _nc_comment_end;
@@ -236,13 +317,14 @@
* implemented it. Note that the resulting terminal type was never the
* 2-character name, but was instead the first alias after that.
*/
+#define ok_TC2(s) (isgraph(UChar(s)) && (s) != '|')
ptr = _nc_curr_token.tk_name;
if (_nc_syntax == SYN_TERMCAP
#if NCURSES_XNAMES
&& !_nc_user_definable
#endif
) {
- if (ptr[2] == '|') {
+ if (ok_TC2(ptr[0]) && ok_TC2(ptr[1]) && (ptr[2] == '|')) {
ptr += 3;
_nc_curr_token.tk_name[2] = '\0';
}
@@ -251,16 +333,21 @@
entryp->tterm.str_table = entryp->tterm.term_names = _nc_save_str(ptr);
if (entryp->tterm.str_table == 0)
- return (ERR);
+ returnDB(ERR);
- DEBUG(1, ("Starting '%s'", ptr));
+ DEBUG(2, ("Starting '%s'", ptr));
/*
* We do this because the one-token lookahead in the parse loop
* results in the terminal type getting prematurely set to correspond
* to that of the next entry.
*/
- _nc_set_type(_nc_first_name(entryp->tterm.term_names));
+ name = _nc_first_name(entryp->tterm.term_names);
+ if (!valid_entryname(name)) {
+ _nc_warning("invalid entry name \"%s\"", name);
+ name = "invalid";
+ }
+ _nc_set_type(name);
/* check for overly-long names and aliases */
for (base = entryp->tterm.term_names; (ptr = strchr(base, '|')) != 0;
@@ -282,11 +369,28 @@
bool is_use = (strcmp(_nc_curr_token.tk_name, "use") == 0);
bool is_tc = !is_use && (strcmp(_nc_curr_token.tk_name, "tc") == 0);
if (is_use || is_tc) {
- entryp->uses[entryp->nuses].name = _nc_save_str(_nc_curr_token.tk_valstring);
- entryp->uses[entryp->nuses].line = _nc_curr_line;
- entryp->nuses++;
- if (entryp->nuses > 1 && is_tc) {
- BAD_TC_USAGE
+ char *saved;
+
+ if (!VALID_STRING(_nc_curr_token.tk_valstring)
+ || _nc_curr_token.tk_valstring[0] == '\0') {
+ _nc_warning("missing name for use-clause");
+ continue;
+ } else if (!valid_entryname(_nc_curr_token.tk_valstring)) {
+ _nc_warning("invalid name for use-clause \"%s\"",
+ _nc_curr_token.tk_valstring);
+ continue;
+ } else if (entryp->nuses >= MAX_USES) {
+ _nc_warning("too many use-clauses, ignored \"%s\"",
+ _nc_curr_token.tk_valstring);
+ continue;
+ }
+ if ((saved = _nc_save_str(_nc_curr_token.tk_valstring)) != NULL) {
+ entryp->uses[entryp->nuses].name = saved;
+ entryp->uses[entryp->nuses].line = _nc_curr_line;
+ entryp->nuses++;
+ if (entryp->nuses > 1 && is_tc) {
+ BAD_TC_USAGE
+ }
}
} else {
/* normal token lookup */
@@ -294,7 +398,7 @@
_nc_get_hash_table(_nc_syntax));
/*
- * Our kluge to handle aliasing. The reason it's done
+ * Our kluge to handle aliasing. The reason it is done
* this ugly way, with a linear search, is so the hashing
* machinery doesn't have to be made really complicated
* (also we get better warnings this way). No point in
@@ -351,12 +455,20 @@
* define a name based on its context.
*/
if (entry_ptr == NOTFOUND
- && _nc_user_definable
- && (entry_ptr = _nc_extend_names(entryp,
- _nc_curr_token.tk_name,
- token_type)) != 0) {
- if (_nc_tracing >= DEBUG_LEVEL(1))
- _nc_warning("extended capability '%s'", _nc_curr_token.tk_name);
+ && _nc_user_definable) {
+ if (expected_type(_nc_curr_token.tk_name, token_type, silent)) {
+ if ((entry_ptr = _nc_extend_names(entryp,
+ _nc_curr_token.tk_name,
+ token_type)) != 0) {
+ if (_nc_tracing >= DEBUG_LEVEL(1)) {
+ _nc_warning("extended capability '%s'",
+ _nc_curr_token.tk_name);
+ }
+ }
+ } else {
+ /* ignore it: we have already printed error message */
+ continue;
+ }
}
#endif /* NCURSES_XNAMES */
@@ -369,7 +481,16 @@
}
/* deal with bad type/value combinations. */
- if (token_type != CANCEL && entry_ptr->nte_type != token_type) {
+ if (token_type == CANCEL) {
+ /*
+ * Prefer terminfo in this (long-obsolete) ambiguity:
+ */
+ if (!strcmp("ma", _nc_curr_token.tk_name)) {
+ entry_ptr = _nc_find_type_entry("ma", NUMBER,
+ _nc_syntax != 0);
+ assert(entry_ptr != 0);
+ }
+ } else if (entry_ptr->nte_type != token_type) {
/*
* Nasty special cases here handle situations in which type
* information can resolve name clashes. Normal lookup
@@ -446,20 +567,27 @@
break;
case NUMBER:
+#if !NCURSES_EXT_NUMBERS
if (_nc_curr_token.tk_valnumber > MAX_NUMBER) {
entryp->tterm.Numbers[entry_ptr->nte_index] = MAX_NUMBER;
- } else {
+ } else
+#endif
+ {
entryp->tterm.Numbers[entry_ptr->nte_index] =
- (short) _nc_curr_token.tk_valnumber;
+ (NCURSES_INT2) _nc_curr_token.tk_valnumber;
}
break;
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;
@@ -486,23 +614,26 @@
if (!literal) {
if (_nc_syntax == SYN_TERMCAP) {
bool has_base_entry = FALSE;
- unsigned i;
/*
* Don't insert defaults if this is a `+' entry meant only
* for inclusion in other entries (not sure termcap ever
* had these, actually).
*/
- if (strchr(entryp->tterm.term_names, '+'))
+ if (strchr(entryp->tterm.term_names, '+')) {
has_base_entry = TRUE;
- else
+ } else {
+ unsigned i;
/*
* Otherwise, look for a base entry that will already
* have picked up defaults via translation.
*/
- for (i = 0; i < entryp->nuses; i++)
- if (!strchr((char *) entryp->uses[i].name, '+'))
+ for (i = 0; i < entryp->nuses; i++) {
+ if (entryp->uses[i].name != 0
+ && !strchr(entryp->uses[i].name, '+'))
has_base_entry = TRUE;
+ }
+ }
postprocess_termcap(&entryp->tterm, has_base_entry);
} else
@@ -510,59 +641,66 @@
}
_nc_wrap_entry(entryp, FALSE);
- return (OK);
+ returnDB(OK);
}
NCURSES_EXPORT(int)
_nc_capcmp(const char *s, const char *t)
/* compare two string capabilities, stripping out padding */
{
- if (!VALID_STRING(s) && !VALID_STRING(t))
- return (0);
- else if (!VALID_STRING(s) || !VALID_STRING(t))
- return (1);
+ bool ok_s = VALID_STRING(s);
+ bool ok_t = VALID_STRING(t);
- for (;;) {
- if (s[0] == '$' && s[1] == '<') {
- for (s += 2;; s++)
- if (!(isdigit(UChar(*s))
- || *s == '.'
- || *s == '*'
- || *s == '/'
- || *s == '>'))
- break;
+ if (ok_s && ok_t) {
+ for (;;) {
+ if (s[0] == '$' && s[1] == '<') {
+ for (s += 2;; s++) {
+ if (!(isdigit(UChar(*s))
+ || *s == '.'
+ || *s == '*'
+ || *s == '/'
+ || *s == '>')) {
+ break;
+ }
+ }
+ }
+
+ if (t[0] == '$' && t[1] == '<') {
+ for (t += 2;; t++) {
+ if (!(isdigit(UChar(*t))
+ || *t == '.'
+ || *t == '*'
+ || *t == '/'
+ || *t == '>')) {
+ break;
+ }
+ }
+ }
+
+ /* we've now pushed s and t past any padding they pointed at */
+
+ if (*s == '\0' && *t == '\0')
+ return (0);
+
+ if (*s != *t)
+ return (*t - *s);
+
+ /* else *s == *t but one is not NUL, so continue */
+ s++, t++;
}
-
- if (t[0] == '$' && t[1] == '<') {
- for (t += 2;; t++)
- if (!(isdigit(UChar(*t))
- || *t == '.'
- || *t == '*'
- || *t == '/'
- || *t == '>'))
- break;
- }
-
- /* we've now pushed s and t past any padding they were pointing at */
-
- if (*s == '\0' && *t == '\0')
- return (0);
-
- if (*s != *t)
- return (*t - *s);
-
- /* else *s == *t but one is not NUL, so continue */
- s++, t++;
+ } else if (ok_s || ok_t) {
+ return 1;
}
+ return 0;
}
static void
-append_acs0(string_desc * dst, int code, int src)
+append_acs0(string_desc * dst, int code, char *src, size_t off)
{
- if (src != 0) {
+ if (src != 0 && off < strlen(src)) {
char temp[3];
temp[0] = (char) code;
- temp[1] = (char) src;
+ temp[1] = src[off];
temp[2] = 0;
_nc_safe_strcat(dst, temp);
}
@@ -571,8 +709,8 @@
static void
append_acs(string_desc * dst, int code, char *src)
{
- if (src != 0 && strlen(src) == 1) {
- append_acs0(dst, code, *src);
+ if (VALID_STRING(src) && strlen(src) == 1) {
+ append_acs0(dst, code, src, 0);
}
}
@@ -621,13 +759,6 @@
static const char C_HT[] = "\t";
/*
- * Note that WANTED and PRESENT are not simple inverses! If a capability
- * has been explicitly cancelled, it's not considered WANTED.
- */
-#define WANTED(s) ((s) == ABSENT_STRING)
-#define PRESENT(s) (((s) != ABSENT_STRING) && ((s) != CANCELLED_STRING))
-
-/*
* This bit of legerdemain turns all the terminfo variable names into
* references to locations in the arrays Booleans, Numbers, and Strings ---
* precisely what's needed.
@@ -637,11 +768,15 @@
#define CUR tp->
static void
-postprocess_termcap(TERMTYPE *tp, bool has_base)
+postprocess_termcap(TERMTYPE2 *tp, bool has_base)
{
char buf[MAX_LINE * 2 + 2];
string_desc result;
+ TR(TRACE_DATABASE,
+ (T_CALLED("postprocess_termcap(tp=%p, has_base=%d)"),
+ (void *) tp, has_base));
+
/*
* TERMCAP DEFAULTS AND OBSOLETE-CAPABILITY TRANSLATIONS
*
@@ -652,10 +787,10 @@
/* if there was a tc entry, assume we picked up defaults via that */
if (!has_base) {
- if (WANTED(init_3string) && termcap_init2)
+ if (WANTED(init_3string) && PRESENT(termcap_init2))
init_3string = _nc_save_str(termcap_init2);
- if (WANTED(reset_2string) && termcap_reset)
+ if (WANTED(reset_2string) && PRESENT(termcap_reset))
reset_2string = _nc_save_str(termcap_reset);
if (WANTED(carriage_return)) {
@@ -770,7 +905,7 @@
if (init_tabs != 8 && init_tabs != ABSENT_NUMERIC)
_nc_warning("hardware tabs with a width other than 8: %d", init_tabs);
else {
- if (tab && _nc_capcmp(tab, C_HT))
+ if (PRESENT(tab) && _nc_capcmp(tab, C_HT))
_nc_warning("hardware tabs with a non-^I tab string %s",
_nc_visbuf(tab));
else {
@@ -832,15 +967,14 @@
}
if (tp->Strings[to_ptr->nte_index]) {
- /* There's no point in warning about it if it's the same
+ const char *s = tp->Strings[from_ptr->nte_index];
+ const char *t = tp->Strings[to_ptr->nte_index];
+ /* There's no point in warning about it if it is the same
* string; that's just an inefficiency.
*/
- if (strcmp(
- tp->Strings[from_ptr->nte_index],
- tp->Strings[to_ptr->nte_index]) != 0)
+ if (VALID_STRING(s) && VALID_STRING(t) && strcmp(s, t) != 0)
_nc_warning("%s (%s) already has an explicit value %s, ignoring ko",
- ap->to, ap->from,
- _nc_visbuf(tp->Strings[to_ptr->nte_index]));
+ ap->to, ap->from, t);
continue;
}
@@ -848,17 +982,22 @@
* The magic moment -- copy the mapped key string over,
* stripping out padding.
*/
- for (dp = buf2, bp = tp->Strings[from_ptr->nte_index]; *bp; bp++) {
- if (bp[0] == '$' && bp[1] == '<') {
- while (*bp && *bp != '>') {
- ++bp;
- }
- } else
- *dp++ = *bp;
- }
- *dp = '\0';
+ bp = tp->Strings[from_ptr->nte_index];
+ if (VALID_STRING(bp)) {
+ for (dp = buf2; *bp; bp++) {
+ if (bp[0] == '$' && bp[1] == '<') {
+ while (*bp && *bp != '>') {
+ ++bp;
+ }
+ } else
+ *dp++ = *bp;
+ }
+ *dp = '\0';
- tp->Strings[to_ptr->nte_index] = _nc_save_str(buf2);
+ tp->Strings[to_ptr->nte_index] = _nc_save_str(buf2);
+ } else {
+ tp->Strings[to_ptr->nte_index] = bp;
+ }
}
/*
@@ -867,7 +1006,7 @@
* got mapped to kich1 and im to kIC to avoid a collision.
* If the description has im but not ic, hack kIC back to kich1.
*/
- if (foundim && WANTED(key_ic) && key_sic) {
+ if (foundim && WANTED(key_ic) && PRESENT(key_sic)) {
key_ic = key_sic;
key_sic = ABSENT_STRING;
}
@@ -919,16 +1058,21 @@
acs_chars = _nc_save_str(buf2);
_nc_warning("acsc string synthesized from XENIX capabilities");
}
- } else if (acs_chars == 0
- && enter_alt_charset_mode != 0
- && exit_alt_charset_mode != 0) {
+ } else if (acs_chars == ABSENT_STRING
+ && PRESENT(enter_alt_charset_mode)
+ && PRESENT(exit_alt_charset_mode)) {
acs_chars = _nc_save_str(VT_ACSC);
}
+ returnVoidDB;
}
static void
-postprocess_terminfo(TERMTYPE *tp)
+postprocess_terminfo(TERMTYPE2 *tp)
{
+ TR(TRACE_DATABASE,
+ (T_CALLED("postprocess_terminfo(tp=%p)"),
+ (void *) tp));
+
/*
* TERMINFO-TO-TERMINFO MAPPINGS FOR SOURCE TRANSLATION
* ----------------------------------------------------------------------
@@ -944,17 +1088,17 @@
_nc_str_init(&result, buf2, sizeof(buf2));
_nc_safe_strcat(&result, acs_chars);
- append_acs0(&result, 'l', box_chars_1[0]); /* ACS_ULCORNER */
- append_acs0(&result, 'q', box_chars_1[1]); /* ACS_HLINE */
- append_acs0(&result, 'k', box_chars_1[2]); /* ACS_URCORNER */
- append_acs0(&result, 'x', box_chars_1[3]); /* ACS_VLINE */
- append_acs0(&result, 'j', box_chars_1[4]); /* ACS_LRCORNER */
- append_acs0(&result, 'm', box_chars_1[5]); /* ACS_LLCORNER */
- append_acs0(&result, 'w', box_chars_1[6]); /* ACS_TTEE */
- append_acs0(&result, 'u', box_chars_1[7]); /* ACS_RTEE */
- append_acs0(&result, 'v', box_chars_1[8]); /* ACS_BTEE */
- append_acs0(&result, 't', box_chars_1[9]); /* ACS_LTEE */
- append_acs0(&result, 'n', box_chars_1[10]); /* ACS_PLUS */
+ append_acs0(&result, 'l', box_chars_1, 0); /* ACS_ULCORNER */
+ append_acs0(&result, 'q', box_chars_1, 1); /* ACS_HLINE */
+ append_acs0(&result, 'k', box_chars_1, 2); /* ACS_URCORNER */
+ append_acs0(&result, 'x', box_chars_1, 3); /* ACS_VLINE */
+ append_acs0(&result, 'j', box_chars_1, 4); /* ACS_LRCORNER */
+ append_acs0(&result, 'm', box_chars_1, 5); /* ACS_LLCORNER */
+ append_acs0(&result, 'w', box_chars_1, 6); /* ACS_TTEE */
+ append_acs0(&result, 'u', box_chars_1, 7); /* ACS_RTEE */
+ append_acs0(&result, 'v', box_chars_1, 8); /* ACS_BTEE */
+ append_acs0(&result, 't', box_chars_1, 9); /* ACS_LTEE */
+ append_acs0(&result, 'n', box_chars_1, 10); /* ACS_PLUS */
if (buf2[0]) {
acs_chars = _nc_save_str(buf2);
@@ -965,6 +1109,7 @@
/*
* ----------------------------------------------------------------------
*/
+ returnVoidDB;
}
/*
diff --git a/ncurses/tinfo/read_entry.c b/ncurses/tinfo/read_entry.c
index 81fdc46..b0f360e 100644
--- a/ncurses/tinfo/read_entry.c
+++ b/ncurses/tinfo/read_entry.c
@@ -1,5 +1,6 @@
/****************************************************************************
- * Copyright (c) 1998-2014,2015 Free Software Foundation, Inc. *
+ * Copyright 2018-2022,2023 Thomas E. Dickey *
+ * Copyright 1998-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 *
@@ -41,15 +42,87 @@
#include <tic.h>
-MODULE_ID("$Id: read_entry.c,v 1.129 2015/06/27 16:16:40 tom Exp $")
-
-#define TYPE_CALLOC(type,elts) typeCalloc(type, (unsigned)(elts))
+MODULE_ID("$Id: read_entry.c,v 1.171 2023/09/16 16:30:34 tom Exp $")
#define MyNumber(n) (short) LOW_MSB(n)
+#define SIZEOF_32BITS 4
+
#if NCURSES_USE_DATABASE
-static void
-convert_shorts(char *buf, short *Numbers, int count)
+#if NCURSES_EXT_NUMBERS
+static size_t
+convert_16bits(char *buf, NCURSES_INT2 *Numbers, int count)
+{
+ int i;
+ size_t j;
+ size_t size = SIZEOF_SHORT;
+ for (i = 0; i < count; i++) {
+ unsigned mask = 0xff;
+ unsigned char ch = 0;
+ Numbers[i] = 0;
+ for (j = 0; j < size; ++j) {
+ ch = UChar(*buf++);
+ Numbers[i] |= (ch << (8 * j));
+ mask <<= 8;
+ }
+ if (ch & 0x80) {
+ while (mask != 0) {
+ Numbers[i] |= (int) mask;
+ mask <<= 8;
+ }
+ }
+ TR(TRACE_DATABASE, ("get Numbers[%d]=%d", i, Numbers[i]));
+ }
+ return size;
+}
+
+static size_t
+convert_32bits(char *buf, NCURSES_INT2 *Numbers, int count)
+{
+ int i;
+ size_t j;
+ size_t size = SIZEOF_INT2;
+ unsigned char ch;
+
+ assert(sizeof(NCURSES_INT2) == size);
+ for (i = 0; i < count; i++) {
+ Numbers[i] = 0;
+ for (j = 0; j < size; ++j) {
+ ch = UChar(*buf++);
+ Numbers[i] |= (ch << (8 * j));
+ }
+ /* "unsigned" and NCURSES_INT2 are the same size - no sign-extension */
+ TR(TRACE_DATABASE, ("get Numbers[%d]=%d", i, Numbers[i]));
+ }
+ return size;
+}
+#else
+static size_t
+convert_32bits(char *buf, NCURSES_INT2 *Numbers, int count)
+{
+ int i, j;
+ unsigned char ch;
+ for (i = 0; i < count; i++) {
+ int value = 0;
+ for (j = 0; j < SIZEOF_32BITS; ++j) {
+ ch = UChar(*buf++);
+ value |= (ch << (8 * j));
+ }
+ if (value == -1)
+ Numbers[i] = ABSENT_NUMERIC;
+ else if (value == -2)
+ Numbers[i] = CANCELLED_NUMERIC;
+ else if (value > MAX_OF_TYPE(NCURSES_INT2))
+ Numbers[i] = MAX_OF_TYPE(NCURSES_INT2);
+ else
+ Numbers[i] = (short) value;
+ TR(TRACE_DATABASE, ("get Numbers[%d]=%d", i, Numbers[i]));
+ }
+ return SIZEOF_SHORT;
+}
+
+static size_t
+convert_16bits(char *buf, NCURSES_INT2 *Numbers, int count)
{
int i;
for (i = 0; i < count; i++) {
@@ -61,13 +134,17 @@
Numbers[i] = MyNumber(buf + 2 * i);
TR(TRACE_DATABASE, ("get Numbers[%d]=%d", i, Numbers[i]));
}
+ return SIZEOF_SHORT;
}
+#endif
-static void
-convert_strings(char *buf, char **Strings, int count, int size, char *table)
+static bool
+convert_strings(char *buf, char **Strings, int count, int size,
+ char *table, bool always)
{
int i;
char *p;
+ bool success = TRUE;
for (i = 0; i < count; i++) {
if (IS_NEG1(buf + 2 * i)) {
@@ -77,20 +154,44 @@
} else if (MyNumber(buf + 2 * i) > size) {
Strings[i] = ABSENT_STRING;
} else {
- Strings[i] = (MyNumber(buf + 2 * i) + table);
- TR(TRACE_DATABASE, ("Strings[%d] = %s", i, _nc_visbuf(Strings[i])));
+ int nn = MyNumber(buf + 2 * i);
+ if (nn >= 0 && nn < size) {
+ Strings[i] = (nn + table);
+ TR(TRACE_DATABASE, ("Strings[%d] = %s", i,
+ _nc_visbuf(Strings[i])));
+ } else {
+ TR(TRACE_DATABASE,
+ ("found out-of-range index %d to Strings[%d]", nn, i));
+ success = FALSE;
+ break;
+ }
}
/* 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;
+ } else if (p == Strings[i] && always) {
+ TR(TRACE_DATABASE,
+ ("found empty but required Strings[%d]", i));
+ success = FALSE;
+ break;
+ }
+ } else if (always) { /* names are always needed */
+ TR(TRACE_DATABASE,
+ ("found invalid but required Strings[%d]", i));
+ success = FALSE;
+ break;
}
}
+ if (!success) {
+ _nc_warning("corrupt data found in convert_strings");
+ }
+ return success;
}
static int
@@ -112,17 +213,22 @@
#define Read(buf, count) fake_read(buffer, &offset, limit, (char *) buf, (unsigned) count)
#define read_shorts(buf, count) \
- (Read(buf, (count)*2) == (int) (count)*2)
+ (Read(buf, (count)*SIZEOF_SHORT) == (int) (count)*SIZEOF_SHORT)
+
+#define read_numbers(buf, count) \
+ (Read(buf, (count)*(unsigned)size_of_numbers) == (int) (count)*size_of_numbers)
#define even_boundary(value) \
if ((value) % 2 != 0) Read(buf, 1)
#endif
NCURSES_EXPORT(void)
-_nc_init_termtype(TERMTYPE *const tp)
+_nc_init_termtype(TERMTYPE2 *const tp)
{
unsigned i;
+ DEBUG(2, (T_CALLED("_nc_init_termtype(tp=%p)"), (void *) tp));
+
#if NCURSES_XNAMES
tp->num_Booleans = BOOLCOUNT;
tp->num_Numbers = NUMCOUNT;
@@ -134,7 +240,7 @@
if (tp->Booleans == 0)
TYPE_MALLOC(NCURSES_SBOOL, BOOLCOUNT, tp->Booleans);
if (tp->Numbers == 0)
- TYPE_MALLOC(short, NUMCOUNT, tp->Numbers);
+ TYPE_MALLOC(NCURSES_INT2, NUMCOUNT, tp->Numbers);
if (tp->Strings == 0)
TYPE_MALLOC(char *, STRCOUNT, tp->Strings);
@@ -146,6 +252,8 @@
for_each_string(i, tp)
tp->Strings[i] = ABSENT_STRING;
+
+ DEBUG(2, (T_RETURN("")));
}
#if NCURSES_USE_DATABASE
@@ -169,7 +277,7 @@
* Return TGETENT_YES if read, TGETENT_NO if not found or garbled.
*/
NCURSES_EXPORT(int)
-_nc_read_termtype(TERMTYPE *ptr, char *buffer, int limit)
+_nc_read_termtype(TERMTYPE2 *ptr, char *buffer, int limit)
{
int offset = 0;
int name_size, bool_count, num_count, str_count, str_size;
@@ -177,6 +285,13 @@
char buf[MAX_ENTRY_SIZE + 2];
char *string_table;
unsigned want, have;
+ size_t (*convert_numbers) (char *, NCURSES_INT2 *, int);
+ int size_of_numbers;
+ int max_entry_size = MAX_ENTRY_SIZE;
+
+ TR(TRACE_DATABASE,
+ (T_CALLED("_nc_read_termtype(ptr=%p, buffer=%p, limit=%d)"),
+ (void *) ptr, buffer, limit));
TR(TRACE_DATABASE, ("READ termtype header @%d", offset));
@@ -185,14 +300,33 @@
/* grab the header */
if (!read_shorts(buf, 6)
|| !IS_TIC_MAGIC(buf)) {
- return (TGETENT_NO);
+ returnDB(TGETENT_NO);
}
+#if NCURSES_EXT_NUMBERS
+ if (LOW_MSB(buf) == MAGIC2) {
+ convert_numbers = convert_32bits;
+ size_of_numbers = SIZEOF_INT2;
+ } else {
+ max_entry_size = MAX_ENTRY_SIZE1;
+ convert_numbers = convert_16bits;
+ size_of_numbers = SIZEOF_SHORT;
+ }
+#else
+ if (LOW_MSB(buf) == MAGIC2) {
+ convert_numbers = convert_32bits;
+ size_of_numbers = SIZEOF_32BITS;
+ } else {
+ convert_numbers = convert_16bits;
+ size_of_numbers = SIZEOF_INT2;
+ }
+#endif
- name_size = MyNumber(buf + 2);
+ /* *INDENT-EQLS* */
+ name_size = MyNumber(buf + 2);
bool_count = MyNumber(buf + 4);
- num_count = MyNumber(buf + 6);
- str_count = MyNumber(buf + 8);
- str_size = MyNumber(buf + 10);
+ num_count = MyNumber(buf + 6);
+ str_count = MyNumber(buf + 8);
+ str_size = MyNumber(buf + 10);
TR(TRACE_DATABASE,
("TERMTYPE name_size=%d, bool=%d/%d, num=%d/%d str=%d/%d(%d)",
@@ -202,26 +336,22 @@
|| bool_count < 0
|| num_count < 0
|| str_count < 0
+ || bool_count > BOOLCOUNT
+ || num_count > NUMCOUNT
+ || str_count > STRCOUNT
|| str_size < 0) {
- return (TGETENT_NO);
+ returnDB(TGETENT_NO);
}
want = (unsigned) (str_size + name_size + 1);
- if (str_size) {
- /* try to allocate space for the string table */
- if (str_count * 2 >= MAX_ENTRY_SIZE
- || (string_table = typeMalloc(char, want)) == 0) {
- return (TGETENT_NO);
- }
- } else {
- str_count = 0;
- if ((string_table = typeMalloc(char, want)) == 0) {
- return (TGETENT_NO);
- }
+ /* try to allocate space for the string table */
+ if (str_count * SIZEOF_SHORT >= max_entry_size
+ || (string_table = typeMalloc(char, want)) == 0) {
+ returnDB(TGETENT_NO);
}
/* grab the name (a null-terminated string) */
- want = min(MAX_NAME_SIZE, (unsigned) name_size);
+ want = Min(MAX_NAME_SIZE, (unsigned) name_size);
ptr->str_table = string_table;
ptr->term_names = string_table;
if ((have = (unsigned) Read(ptr->term_names, want)) != want) {
@@ -234,10 +364,9 @@
offset = (int) (have - MAX_NAME_SIZE);
/* grab the booleans */
- if ((ptr->Booleans = TYPE_CALLOC(NCURSES_SBOOL,
- max(BOOLCOUNT, bool_count))) == 0
- || Read(ptr->Booleans, (unsigned) bool_count) < bool_count) {
- return (TGETENT_NO);
+ TYPE_CALLOC(NCURSES_SBOOL, Max(BOOLCOUNT, bool_count), ptr->Booleans);
+ if (Read(ptr->Booleans, (unsigned) bool_count) < bool_count) {
+ returnDB(TGETENT_NO);
}
/*
@@ -249,26 +378,27 @@
even_boundary(name_size + bool_count);
/* grab the numbers */
- if ((ptr->Numbers = TYPE_CALLOC(short, max(NUMCOUNT, num_count))) == 0
- || !read_shorts(buf, num_count)) {
- return (TGETENT_NO);
+ TYPE_CALLOC(NCURSES_INT2, Max(NUMCOUNT, num_count), ptr->Numbers);
+ if (!read_numbers(buf, num_count)) {
+ returnDB(TGETENT_NO);
}
- convert_shorts(buf, ptr->Numbers, num_count);
+ convert_numbers(buf, ptr->Numbers, num_count);
- if ((ptr->Strings = TYPE_CALLOC(char *, max(STRCOUNT, str_count))) == 0) {
- return (TGETENT_NO);
- }
+ TYPE_CALLOC(char *, Max(STRCOUNT, str_count), ptr->Strings);
if (str_count) {
/* grab the string offsets */
if (!read_shorts(buf, str_count)) {
- return (TGETENT_NO);
+ returnDB(TGETENT_NO);
}
/* finally, grab the string table itself */
if (Read(string_table, (unsigned) str_size) != str_size) {
- return (TGETENT_NO);
+ returnDB(TGETENT_NO);
}
- convert_strings(buf, ptr->Strings, str_count, str_size, string_table);
+ if (!convert_strings(buf, ptr->Strings, str_count, str_size,
+ string_table, FALSE)) {
+ returnDB(TGETENT_NO);
+ }
}
#if NCURSES_XNAMES
@@ -285,20 +415,20 @@
int ext_bool_count = MyNumber(buf + 0);
int ext_num_count = MyNumber(buf + 2);
int ext_str_count = MyNumber(buf + 4);
- int ext_str_size = MyNumber(buf + 6);
+ int ext_str_usage = MyNumber(buf + 6);
int ext_str_limit = MyNumber(buf + 8);
unsigned need = (unsigned) (ext_bool_count + ext_num_count + ext_str_count);
int base = 0;
- if (need >= (MAX_ENTRY_SIZE / 2)
- || ext_str_size >= MAX_ENTRY_SIZE
- || ext_str_limit >= MAX_ENTRY_SIZE
+ if ((int) need >= (max_entry_size / 2)
+ || ext_str_usage >= max_entry_size
+ || ext_str_limit >= max_entry_size
|| ext_bool_count < 0
|| ext_num_count < 0
|| ext_str_count < 0
- || ext_str_size < 0
+ || ext_str_usage < 0
|| ext_str_limit < 0) {
- return (TGETENT_NO);
+ returnDB(TGETENT_NO);
}
ptr->num_Booleans = UShort(BOOLCOUNT + ext_bool_count);
@@ -306,19 +436,25 @@
ptr->num_Strings = UShort(STRCOUNT + ext_str_count);
TYPE_REALLOC(NCURSES_SBOOL, ptr->num_Booleans, ptr->Booleans);
- TYPE_REALLOC(short, ptr->num_Numbers, ptr->Numbers);
+ TYPE_REALLOC(NCURSES_INT2, ptr->num_Numbers, ptr->Numbers);
TYPE_REALLOC(char *, ptr->num_Strings, ptr->Strings);
- TR(TRACE_DATABASE, ("extended header is %d/%d/%d(%d:%d)",
- ext_bool_count, ext_num_count, ext_str_count,
- ext_str_size, ext_str_limit));
+ TR(TRACE_DATABASE, ("extended header: "
+ "bool %d, "
+ "number %d, "
+ "string %d(%d:%d)",
+ ext_bool_count,
+ ext_num_count,
+ ext_str_count,
+ ext_str_usage,
+ ext_str_limit));
TR(TRACE_DATABASE, ("READ %d extended-booleans @%d",
ext_bool_count, offset));
if ((ptr->ext_Booleans = UShort(ext_bool_count)) != 0) {
if (Read(ptr->Booleans + BOOLCOUNT, (unsigned)
ext_bool_count) != ext_bool_count) {
- return (TGETENT_NO);
+ returnDB(TGETENT_NO);
}
}
even_boundary(ext_bool_count);
@@ -326,20 +462,20 @@
TR(TRACE_DATABASE, ("READ %d extended-numbers @%d",
ext_num_count, offset));
if ((ptr->ext_Numbers = UShort(ext_num_count)) != 0) {
- if (!read_shorts(buf, ext_num_count)) {
- return (TGETENT_NO);
+ if (!read_numbers(buf, ext_num_count)) {
+ returnDB(TGETENT_NO);
}
TR(TRACE_DATABASE, ("Before converting extended-numbers"));
- convert_shorts(buf, ptr->Numbers + NUMCOUNT, ext_num_count);
+ convert_numbers(buf, ptr->Numbers + NUMCOUNT, ext_num_count);
}
TR(TRACE_DATABASE, ("READ extended-offsets @%d", offset));
- if ((unsigned) (ext_str_count + (int) need) >= (MAX_ENTRY_SIZE / 2)) {
- return (TGETENT_NO);
+ if ((ext_str_count + (int) need) >= (max_entry_size / 2)) {
+ returnDB(TGETENT_NO);
}
if ((ext_str_count || need)
&& !read_shorts(buf, ext_str_count + (int) need)) {
- return (TGETENT_NO);
+ returnDB(TGETENT_NO);
}
TR(TRACE_DATABASE, ("READ %d bytes of extended-strings @%d",
@@ -348,47 +484,63 @@
if (ext_str_limit) {
ptr->ext_str_table = typeMalloc(char, (size_t) ext_str_limit);
if (ptr->ext_str_table == 0) {
- return (TGETENT_NO);
+ returnDB(TGETENT_NO);
}
if (Read(ptr->ext_str_table, (unsigned) ext_str_limit) != ext_str_limit) {
- return (TGETENT_NO);
+ returnDB(TGETENT_NO);
}
TR(TRACE_DATABASE, ("first extended-string is %s", _nc_visbuf(ptr->ext_str_table)));
}
if ((ptr->ext_Strings = UShort(ext_str_count)) != 0) {
+ int check = (ext_bool_count + ext_num_count + ext_str_count);
+
TR(TRACE_DATABASE,
- ("Before computing extended-string capabilities str_count=%d, ext_str_count=%d",
+ ("Before computing extended-string capabilities "
+ "str_count=%d, ext_str_count=%d",
str_count, ext_str_count));
- convert_strings(buf, ptr->Strings + str_count, ext_str_count,
- ext_str_limit, ptr->ext_str_table);
+ if (!convert_strings(buf, ptr->Strings + str_count, ext_str_count,
+ ext_str_limit, ptr->ext_str_table, FALSE)) {
+ returnDB(TGETENT_NO);
+ }
for (i = ext_str_count - 1; i >= 0; i--) {
TR(TRACE_DATABASE, ("MOVE from [%d:%d] %s",
i, i + str_count,
_nc_visbuf(ptr->Strings[i + str_count])));
ptr->Strings[i + STRCOUNT] = ptr->Strings[i + str_count];
- if (VALID_STRING(ptr->Strings[i + STRCOUNT]))
+ if (VALID_STRING(ptr->Strings[i + STRCOUNT])) {
base += (int) (strlen(ptr->Strings[i + STRCOUNT]) + 1);
+ ++check;
+ }
TR(TRACE_DATABASE, ("... to [%d] %s",
i + STRCOUNT,
_nc_visbuf(ptr->Strings[i + STRCOUNT])));
}
+ TR(TRACE_DATABASE, ("Check table-size: %d/%d", check, ext_str_usage));
+#if 0
+ /*
+ * Phasing in a proper check will be done "later".
+ */
+ if (check != ext_str_usage)
+ returnDB(TGETENT_NO);
+#endif
}
if (need) {
- if (ext_str_count >= (MAX_ENTRY_SIZE / 2)) {
- return (TGETENT_NO);
+ if (ext_str_count >= (max_entry_size / 2)) {
+ returnDB(TGETENT_NO);
}
- if ((ptr->ext_Names = TYPE_CALLOC(char *, need)) == 0) {
- return (TGETENT_NO);
- }
+ TYPE_CALLOC(char *, need, ptr->ext_Names);
TR(TRACE_DATABASE,
("ext_NAMES starting @%d in extended_strings, first = %s",
base, _nc_visbuf(ptr->ext_str_table + base)));
- convert_strings(buf + (2 * ext_str_count),
- ptr->ext_Names,
- (int) need,
- ext_str_limit, ptr->ext_str_table + base);
+ if (!convert_strings(buf + (2 * ext_str_count),
+ ptr->ext_Names,
+ (int) need,
+ ext_str_limit, ptr->ext_str_table + base,
+ TRUE)) {
+ returnDB(TGETENT_NO);
+ }
}
TR(TRACE_DATABASE,
@@ -415,7 +567,7 @@
for (i = str_count; i < STRCOUNT; i++)
ptr->Strings[i] = ABSENT_STRING;
- return (TGETENT_YES);
+ returnDB(TGETENT_YES);
}
/*
@@ -427,26 +579,31 @@
* table.
*/
NCURSES_EXPORT(int)
-_nc_read_file_entry(const char *const filename, TERMTYPE *ptr)
+_nc_read_file_entry(const char *const filename, TERMTYPE2 *ptr)
/* return 1 if read, 0 if not found or garbled */
{
FILE *fp = 0;
int code;
- int limit;
- char buffer[MAX_ENTRY_SIZE + 1];
if (_nc_access(filename, R_OK) < 0
- || (fp = fopen(filename, "rb")) == 0) {
+ || (fp = safe_fopen(filename, BIN_R)) == 0) {
TR(TRACE_DATABASE, ("cannot open terminfo %s (errno=%d)", filename, errno));
code = TGETENT_NO;
} else {
- if ((limit = (int) fread(buffer, sizeof(char), sizeof(buffer), fp))
- > 0) {
+ int limit;
+ char buffer[MAX_ENTRY_SIZE + 1];
+
+ limit = (int) fread(buffer, sizeof(char), sizeof(buffer), fp);
+ if (limit > 0) {
+ const char *old_source = _nc_get_source();
TR(TRACE_DATABASE, ("read terminfo %s", filename));
+ if (old_source == NULL)
+ _nc_set_source(filename);
if ((code = _nc_read_termtype(ptr, buffer, limit)) == TGETENT_NO) {
- _nc_free_termtype(ptr);
+ _nc_free_termtype2(ptr);
}
+ _nc_set_source(old_source);
} else {
code = TGETENT_NO;
}
@@ -508,6 +665,105 @@
return result;
}
+static int
+lookup_b64(int *target, const char **source)
+{
+ int result = 3;
+ int j;
+ /*
+ * ncurses' quickdump writes only RFC 4648 "url/filename-safe" encoding,
+ * but accepts RFC-3548
+ */
+ for (j = 0; j < 4; ++j) {
+ int ch = UChar(**source);
+ *source += 1;
+ if (ch >= 'A' && ch <= 'Z') {
+ target[j] = (ch - 'A');
+ } else if (ch >= 'a' && ch <= 'z') {
+ target[j] = 26 + (ch - 'a');
+ } else if (ch >= '0' && ch <= '9') {
+ target[j] = 52 + (ch - '0');
+ } else if (ch == '-' || ch == '+') {
+ target[j] = 62;
+ } else if (ch == '_' || ch == '/') {
+ target[j] = 63;
+ } else if (ch == '=') {
+ target[j] = 64;
+ result--;
+ } else {
+ result = -1;
+ break;
+ }
+ }
+ return result;
+}
+
+static int
+decode_hex(const char **source)
+{
+ int result = 0;
+ int nibble;
+
+ for (nibble = 0; nibble < 2; ++nibble) {
+ int ch = UChar(**source);
+ result <<= 4;
+ *source += 1;
+ if (ch >= '0' && ch <= '9') {
+ ch -= '0';
+ } else if (ch >= 'A' && ch <= 'F') {
+ ch -= 'A';
+ ch += 10;
+ } else if (ch >= 'a' && ch <= 'f') {
+ ch -= 'a';
+ ch += 10;
+ } else {
+ result = -1;
+ break;
+ }
+ result |= ch;
+ }
+ return result;
+}
+
+static int
+decode_quickdump(char *target, const char *source)
+{
+ char *base = target;
+ int result = 0;
+
+ if (!strncmp(source, "b64:", (size_t) 4)) {
+ source += 4;
+ while (*source != '\0') {
+ int bits[4];
+ int ch = lookup_b64(bits, &source);
+ if (ch < 0 || (ch + target - base) >= MAX_ENTRY_SIZE) {
+ result = 0;
+ break;
+ }
+ result += ch;
+ *target++ = (char) ((bits[0] << 2) | (bits[1] >> 4));
+ if (bits[2] < 64) {
+ *target++ = (char) ((bits[1] << 4) | (bits[2] >> 2));
+ if (bits[3] < 64) {
+ *target++ = (char) ((bits[2] << 6) | bits[3]);
+ }
+ }
+ }
+ } else if (!strncmp(source, "hex:", (size_t) 4)) {
+ source += 4;
+ while (*source != '\0') {
+ int ch = decode_hex(&source);
+ if (ch < 0 || (target - base) >= MAX_ENTRY_SIZE) {
+ result = 0;
+ break;
+ }
+ *target++ = (char) ch;
+ ++result;
+ }
+ }
+ return result;
+}
+
/*
* Build a terminfo pathname and try to read the data. Returns TGETENT_YES on
* success, TGETENT_NO on failure.
@@ -517,20 +773,39 @@
unsigned limit,
const char *const path,
const char *name,
- TERMTYPE *const tp)
+ TERMTYPE2 *const tp)
{
int code = TGETENT_NO;
-
#if USE_HASHED_DB
DB *capdbp;
+#endif
+ char buffer[MAX_ENTRY_SIZE + 1];
+ int used;
- if (make_db_filename(filename, limit, path)
- && (capdbp = _nc_db_open(filename, FALSE)) != 0) {
+ TR(TRACE_DATABASE,
+ (T_CALLED("_nc_read_tic_entry(file=%p, path=%s, name=%s)"),
+ filename, path, name));
+
+ assert(TGETENT_YES == TRUE); /* simplify call for _nc_name_match */
+
+ if ((used = decode_quickdump(buffer, path)) != 0
+ && (code = _nc_read_termtype(tp, buffer, used)) == TGETENT_YES
+ && (code = _nc_name_match(tp->term_names, name, "|")) == TGETENT_YES) {
+ TR(TRACE_DATABASE, ("loaded quick-dump for %s", name));
+ /* shorten name shown by infocmp */
+ _nc_STRCPY(filename, "$TERMINFO", limit);
+ } else
+#if USE_HASHED_DB
+ if (make_db_filename(filename, limit, path)
+ && (capdbp = _nc_db_open(filename, FALSE)) != 0) {
DBT key, data;
int reccnt = 0;
char *save = strdup(name);
+ if (save == 0)
+ returnDB(code);
+
memset(&key, 0, sizeof(key));
key.data = save;
key.size = strlen(save);
@@ -540,7 +815,7 @@
* looking for compiled (binary) terminfo data.
*
* cgetent uses a two-level lookup. On the first it uses the given
- * name to return a record containing only the aliases for an entry.
+ * name to return a record containing only the aliases for an entry.
* On the second (using that list of aliases as a key), it returns the
* content of the terminal description. We expect second lookup to
* return data beginning with the same set of aliases.
@@ -551,15 +826,15 @@
* (source/binary) by checking the lengths.
*/
while (_nc_db_get(capdbp, &key, &data) == 0) {
- int used = (int) data.size - 1;
char *have = (char *) data.data;
+ used = (int) data.size - 1;
if (*have++ == 0) {
if (data.size > key.size
&& IS_TIC_MAGIC(have)) {
code = _nc_read_termtype(tp, have, used);
if (code == TGETENT_NO) {
- _nc_free_termtype(tp);
+ _nc_free_termtype2(tp);
}
}
break;
@@ -586,30 +861,29 @@
code = _nc_read_file_entry(filename, tp);
}
#if NCURSES_USE_TERMCAP
- else if (code != TGETENT_YES) {
+ if (code != TGETENT_YES) {
code = _nc_read_termcap_entry(name, tp);
_nc_SPRINTF(filename, _nc_SLIMIT(PATH_MAX)
"%.*s", PATH_MAX - 1, _nc_get_source());
}
#endif
- return code;
+ returnDB(code);
}
#endif /* NCURSES_USE_DATABASE */
/*
- * _nc_read_entry(char *name, char *filename, TERMTYPE *tp)
- *
- * Find and read the compiled entry for a given terminal type,
- * if it exists. We take pains here to make sure no combination
- * of environment variables and terminal type name can be used to
- * overrun the file buffer.
+ * Find and read the compiled entry for a given terminal type, if it exists.
+ * We take pains here to make sure no combination of environment variables and
+ * terminal type name can be used to overrun the file buffer.
*/
-
NCURSES_EXPORT(int)
-_nc_read_entry(const char *const name, char *const filename, TERMTYPE *const tp)
+_nc_read_entry2(const char *const name, char *const filename, TERMTYPE2 *const tp)
{
int code = TGETENT_NO;
+ if (name == 0)
+ return _nc_read_entry2("", filename, tp);
+
_nc_SPRINTF(filename, _nc_SLIMIT(PATH_MAX)
"%.*s", PATH_MAX - 1, name);
@@ -628,7 +902,6 @@
_nc_first_db(&state, &offset);
code = TGETENT_ERR;
while ((path = _nc_next_db(&state, &offset)) != 0) {
- TR(TRACE_DATABASE, ("_nc_read_tic_entry path=%s, name=%s", path, name));
code = _nc_read_tic_entry(filename, PATH_MAX, path, name, tp);
if (code == TGETENT_YES) {
_nc_last_db();
@@ -645,3 +918,16 @@
}
return code;
}
+
+#if NCURSES_EXT_NUMBERS
+NCURSES_EXPORT(int)
+_nc_read_entry(const char *const name, char *const filename, TERMTYPE *const tp)
+{
+ TERMTYPE2 dummy;
+ int rc;
+ rc = _nc_read_entry2(name, filename, &dummy);
+ if (rc == TGETENT_YES)
+ _nc_export_termtype2(tp, &dummy);
+ return rc;
+}
+#endif
diff --git a/ncurses/tinfo/read_termcap.c b/ncurses/tinfo/read_termcap.c
index 6bfb23c..1a29484 100644
--- a/ncurses/tinfo/read_termcap.c
+++ b/ncurses/tinfo/read_termcap.c
@@ -1,5 +1,6 @@
/****************************************************************************
- * Copyright (c) 1998-2012,2013 Free Software Foundation, Inc. *
+ * Copyright 2018-2021,2023 Thomas E. Dickey *
+ * Copyright 1998-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 *
@@ -56,7 +57,7 @@
#include <sys/types.h>
#include <tic.h>
-MODULE_ID("$Id: read_termcap.c,v 1.89 2013/12/15 00:32:43 tom Exp $")
+MODULE_ID("$Id: read_termcap.c,v 1.104 2023/06/24 21:53:16 tom Exp $")
#if !PURE_TERMINFO
@@ -66,10 +67,10 @@
#define TC_REF_LOOP -3
#define TC_UNRESOLVED -4 /* this is not returned by BSD cgetent */
-static NCURSES_CONST char *
+static const char *
get_termpath(void)
{
- NCURSES_CONST char *result;
+ const char *result;
if (!use_terminfo_vars() || (result = getenv("TERMPATH")) == 0)
result = TERMPATH;
@@ -186,7 +187,7 @@
bp = buf;
for (;;) {
/*
- * Skip past the current capability field - it's either the
+ * Skip past the current capability field - it is either the
* name field if this is the first time through the loop, or
* the remainder of a field whose name failed to match cap.
*/
@@ -323,7 +324,7 @@
if (fd >= 0) {
(void) lseek(fd, (off_t) 0, SEEK_SET);
} else if ((_nc_access(db_array[current], R_OK) < 0)
- || (fd = open(db_array[current], O_RDONLY, 0)) < 0) {
+ || (fd = safe_open2(db_array[current], O_RDONLY)) < 0) {
/* No error on unfound file. */
if (errno == ENOENT)
continue;
@@ -364,7 +365,7 @@
if (bp >= b_end) {
int n;
- n = read(fd, buf, sizeof(buf));
+ n = (int) read(fd, buf, sizeof(buf));
if (n <= 0) {
if (myfd)
(void) close(fd);
@@ -393,7 +394,7 @@
|| *(rp - 1) != '\\')
break;
}
- *rp++ = c;
+ *rp++ = (char) c;
/*
* Enforce loop invariant: if no room
@@ -404,8 +405,8 @@
unsigned pos;
size_t newsize;
- pos = rp - record;
- newsize = r_end - record + BFRAG;
+ pos = (unsigned) (rp - record);
+ newsize = (size_t) (r_end - record + BFRAG);
record = DOALLOC(newsize);
if (record == 0) {
if (myfd)
@@ -492,14 +493,14 @@
}
}
tcstart = tc - 3;
- tclen = s - tcstart;
+ tclen = (int) (s - tcstart);
tcend = s;
icap = 0;
iret = _nc_getent(&icap, &ilen, &oline, current, db_array, fd,
tc, depth + 1, 0);
newicap = icap; /* Put into a register. */
- newilen = ilen;
+ newilen = (int) ilen;
if (iret != TC_SUCCESS) {
/* an error */
if (iret < TC_NOT_FOUND) {
@@ -523,7 +524,7 @@
/* not interested in name field of tc'ed record */
s = newicap;
while (*s != '\0' && *s++ != ':') ;
- newilen -= s - newicap;
+ newilen -= (int) (s - newicap);
newicap = s;
/* make sure interpolated record is `:'-terminated */
@@ -542,10 +543,10 @@
unsigned pos, tcpos, tcposend;
size_t newsize;
- pos = rp - record;
- newsize = r_end - record + diff + BFRAG;
- tcpos = tcstart - record;
- tcposend = tcend - record;
+ pos = (unsigned) (rp - record);
+ newsize = (size_t) (r_end - record + diff + BFRAG);
+ tcpos = (unsigned) (tcstart - record);
+ tcposend = (unsigned) (tcend - record);
record = DOALLOC(newsize);
if (record == 0) {
if (myfd)
@@ -583,7 +584,7 @@
*/
if (myfd)
(void) close(fd);
- *len = rp - record - 1; /* don't count NUL */
+ *len = (unsigned) (rp - record - 1); /* don't count NUL */
if (r_end > rp) {
if ((record = DOALLOC((size_t) (rp - record))) == 0) {
errno = ENOMEM;
@@ -791,7 +792,7 @@
int i;
char pathbuf[PBUFSIZ]; /* holds raw path of filenames */
CGETENT_CONST char *pathvec[PVECSIZ]; /* point to names in pathbuf */
- NCURSES_CONST char *termpath;
+ const char *termpath;
string_desc desc;
*lineno = 1;
@@ -802,7 +803,7 @@
/*
* TERMCAP can have one of two things in it. It can be the name of a file
* to use instead of /etc/termcap. In this case it better start with a
- * "/". Or it can be an entry to use so we don't have to read the file.
+ * "/". Or it can be an entry to use so we don't have to read the file.
* In this case it has to already have the newlines crunched out. If
* TERMCAP does not hold a file name then a path of names is searched
* instead. The path is found in the TERMPATH variable, or becomes
@@ -956,7 +957,7 @@
#endif /* !USE_GETCAP */
NCURSES_EXPORT(int)
-_nc_read_termcap_entry(const char *const tn, TERMTYPE *const tp)
+_nc_read_termcap_entry(const char *const tn, TERMTYPE2 *const tp)
{
int found = TGETENT_NO;
ENTRY *ep;
@@ -965,6 +966,8 @@
#endif
#if USE_GETCAP
char *p, tc[TBUFSIZ];
+ char *tc_buf = 0;
+#define MY_SIZE sizeof(tc) - 1
int status;
static char *source;
static int lineno;
@@ -982,8 +985,7 @@
if (use_terminfo_vars() && (p = getenv("TERMCAP")) != 0
&& !_nc_is_abs_path(p) && _nc_name_match(p, tn, "|:")) {
/* TERMCAP holds a termcap entry */
- strncpy(tc, p, sizeof(tc) - 1);
- tc[sizeof(tc) - 1] = '\0';
+ tc_buf = strdup(p);
_nc_set_source("TERMCAP");
} else {
/* we're using getcap(3) */
@@ -992,8 +994,13 @@
_nc_curr_line = lineno;
_nc_set_source(source);
+ tc_buf = tc;
}
- _nc_read_entry_source((FILE *) 0, tc, FALSE, TRUE, NULLHOOK);
+ if (tc_buf == 0)
+ return (TGETENT_ERR);
+ _nc_read_entry_source((FILE *) 0, tc_buf, FALSE, TRUE, NULLHOOK);
+ if (tc_buf != tc)
+ free(tc_buf);
#else
/*
* Here is what the 4.4BSD termcap(3) page prescribes:
@@ -1027,7 +1034,7 @@
int j, k;
bool use_buffer = FALSE;
bool normal = TRUE;
- char tc_buf[1024];
+ char *tc_buf = 0;
char pathbuf[PATH_MAX];
char *copied = 0;
char *cp;
@@ -1039,10 +1046,8 @@
ADD_TC(tc, 0);
normal = FALSE;
} else if (_nc_name_match(tc, tn, "|:")) { /* treat as a capability file */
- use_buffer = TRUE;
- _nc_SPRINTF(tc_buf,
- _nc_SLIMIT(sizeof(tc_buf))
- "%.*s\n", (int) sizeof(tc_buf) - 2, tc);
+ tc_buf = strdup(tc);
+ use_buffer = (tc_buf != 0);
normal = FALSE;
}
}
@@ -1050,23 +1055,25 @@
if (normal) { /* normal case */
char envhome[PATH_MAX], *h;
- copied = strdup(get_termpath());
- for (cp = copied; *cp; cp++) {
- if (*cp == NCURSES_PATHSEP)
- *cp = '\0';
- else if (cp == copied || cp[-1] == '\0') {
- ADD_TC(cp, filecount);
+ if ((copied = strdup(get_termpath())) != 0) {
+ for (cp = copied; *cp; cp++) {
+ if (*cp == NCURSES_PATHSEP)
+ *cp = '\0';
+ else if (cp == copied || cp[-1] == '\0') {
+ ADD_TC(cp, filecount);
+ }
}
}
-
-#define PRIVATE_CAP "%s/.termcap"
+#define PRIVATE_CAP "%.*s/.termcap"
if (use_terminfo_vars() && (h = getenv("HOME")) != NULL && *h != '\0'
&& (strlen(h) + sizeof(PRIVATE_CAP)) < PATH_MAX) {
/* user's .termcap, if any, should override it */
_nc_STRCPY(envhome, h, sizeof(envhome));
_nc_SPRINTF(pathbuf, _nc_SLIMIT(sizeof(pathbuf))
- PRIVATE_CAP, envhome);
+ PRIVATE_CAP,
+ (int) (sizeof(pathbuf) - sizeof(PRIVATE_CAP)),
+ envhome);
ADD_TC(pathbuf, filecount);
}
}
@@ -1108,9 +1115,10 @@
/*
* We don't suppress warning messages here. The presumption is
- * that since it's just a single entry, they won't be a pain.
+ * that since it is just a single entry, they won't be a pain.
*/
_nc_read_entry_source((FILE *) 0, tc_buf, FALSE, FALSE, NULLHOOK);
+ free(tc_buf);
} else {
int i;
@@ -1118,7 +1126,7 @@
TR(TRACE_DATABASE, ("Looking for %s in %s", tn, termpaths[i]));
if (_nc_access(termpaths[i], R_OK) == 0
- && (fp = fopen(termpaths[i], "r")) != (FILE *) 0) {
+ && (fp = safe_fopen(termpaths[i], "r")) != (FILE *) 0) {
_nc_set_source(termpaths[i]);
/*
@@ -1140,7 +1148,8 @@
return (TGETENT_ERR);
/* resolve all use references */
- _nc_resolve_uses2(TRUE, FALSE);
+ if (_nc_resolve_uses2(TRUE, FALSE) != TRUE)
+ return (TGETENT_ERR);
/* find a terminal matching tn, if we can */
#if USE_GETCAP_CACHE
@@ -1157,7 +1166,7 @@
_nc_free_entry(_nc_head, &(ep->tterm));
/*
- * OK, now try to write the type to user's terminfo directory.
+ * OK, now try to write the type to user's terminfo directory.
* Next time he loads this, it will come through terminfo.
*
* Advantage: Second and subsequent fetches of this entry will
diff --git a/ncurses/tinfo/strings.c b/ncurses/tinfo/strings.c
index 393d8e7..03f59c2 100644
--- a/ncurses/tinfo/strings.c
+++ b/ncurses/tinfo/strings.c
@@ -1,5 +1,6 @@
/****************************************************************************
- * Copyright (c) 2000-2007,2012 Free Software Foundation, Inc. *
+ * Copyright 2020,2023 Thomas E. Dickey *
+ * Copyright 2000-2012,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 *
@@ -35,8 +36,9 @@
**/
#include <curses.priv.h>
+#include <tic.h>
-MODULE_ID("$Id: strings.c,v 1.8 2012/02/22 22:34:31 tom Exp $")
+MODULE_ID("$Id: strings.c,v 1.11 2023/05/27 20:13:10 tom Exp $")
/****************************************************************************
* Useful string functions (especially for mvcur)
@@ -93,7 +95,7 @@
* Copy a descriptor
*/
NCURSES_EXPORT(string_desc *)
-_nc_str_copy(string_desc * dst, string_desc * src)
+_nc_str_copy(string_desc * dst, const string_desc * const src)
{
*dst = *src;
return dst;
@@ -105,7 +107,7 @@
NCURSES_EXPORT(bool)
_nc_safe_strcat(string_desc * dst, const char *src)
{
- if (src != 0) {
+ if (PRESENT(src)) {
size_t len = strlen(src);
if (len < dst->s_size) {
@@ -126,7 +128,7 @@
NCURSES_EXPORT(bool)
_nc_safe_strcpy(string_desc * dst, const char *src)
{
- if (src != 0) {
+ if (PRESENT(src)) {
size_t len = strlen(src);
if (len < dst->s_size) {
diff --git a/ncurses/tinfo/tinfo_driver.c b/ncurses/tinfo/tinfo_driver.c
index c6a1c22..fd993b8 100644
--- a/ncurses/tinfo/tinfo_driver.c
+++ b/ncurses/tinfo/tinfo_driver.c
@@ -1,5 +1,6 @@
/****************************************************************************
- * Copyright (c) 2008-2014,2015 Free Software Foundation, Inc. *
+ * Copyright 2018-2022,2023 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 *
@@ -28,12 +29,13 @@
/****************************************************************************
* 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.40 2015/06/27 01:20:41 tom Exp $")
+MODULE_ID("$Id: tinfo_driver.c,v 1.74 2023/09/16 10:44:33 tom Exp $")
/*
* SCO defines TIOCGSIZE and the corresponding struct. Other systems (SunOS,
@@ -113,9 +115,43 @@
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)
{
@@ -125,7 +161,7 @@
SCREEN *sp;
START_TRACE();
- T((T_CALLED("tinfo::drv_CanHandle(%p)"), TCB));
+ T((T_CALLED("tinfo::drv_CanHandle(%p)"), (void *) TCB));
assert(TCB != 0 && tname != 0);
termp = (TERMINAL *) TCB;
@@ -133,17 +169,20 @@
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;
}
}
@@ -153,17 +192,40 @@
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 (VALID_STRING(command_character))
+ _nc_tinfo_cmdch(termp, UChar(*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) {
/*
@@ -173,13 +235,19 @@
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);
@@ -261,8 +329,8 @@
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;
@@ -293,23 +361,23 @@
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);
}
}
}
@@ -358,18 +426,25 @@
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;
@@ -539,6 +614,8 @@
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
@@ -564,6 +641,8 @@
#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;
@@ -701,10 +780,10 @@
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));
}
}
@@ -737,7 +816,7 @@
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));
}
}
@@ -749,9 +828,9 @@
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)
@@ -763,22 +842,16 @@
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
@@ -807,13 +880,13 @@
#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;
}
@@ -849,12 +922,9 @@
/* 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);
}
@@ -879,11 +949,18 @@
} 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)
@@ -979,12 +1056,18 @@
{
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
@@ -1031,8 +1114,13 @@
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;
}
@@ -1062,7 +1150,6 @@
? "DIFF"
: "SAME"),
_nc_visbuf(show));
-
_nc_unlock_global(tracef);
}
#endif /* TRACE */
@@ -1171,30 +1258,42 @@
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);
SetSP();
-# if USE_PTHREADS_EINTR
- if ((pthread_self) && (pthread_kill) && (pthread_equal))
- _nc_globals.read_thread = pthread_self();
-# endif
+ _nc_set_read_thread(TRUE);
+#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);
-#if USE_PTHREADS_EINTR
- _nc_globals.read_thread = 0;
#endif
+ _nc_set_read_thread(FALSE);
+#ifndef EXP_WIN32_DRIVER
*buf = (int) c2;
+#endif
return n;
}
@@ -1211,6 +1310,8 @@
request = remaining;
}
}
+#elif defined(EXP_WIN32_DRIVER)
+ Sleep((DWORD) ms);
#else
_nc_timed_wait(0, 0, ms, (int *) 0 EVENTLIST_2nd(0));
#endif
@@ -1279,23 +1380,29 @@
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);
+ }
}
}
}
@@ -1382,3 +1489,66 @@
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 ec5e2b7..177dcd8 100644
--- a/ncurses/tinfo/trim_sgr0.c
+++ b/ncurses/tinfo/trim_sgr0.c
@@ -1,5 +1,6 @@
/****************************************************************************
- * Copyright (c) 2005-2010,2012 Free Software Foundation, Inc. *
+ * Copyright 2020-2021,2023 Thomas E. Dickey *
+ * Copyright 2005-2012,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 *
@@ -36,22 +37,18 @@
#include <tic.h>
-MODULE_ID("$Id: trim_sgr0.c,v 1.15 2012/12/15 20:57:17 tom Exp $")
+MODULE_ID("$Id: trim_sgr0.c,v 1.22 2023/09/23 18:47:56 tom Exp $")
#undef CUR
#define CUR tp->
-#define CSI 233
-#define ESC 033 /* ^[ */
-#define L_BRACK '['
-
static char *
-set_attribute_9(TERMTYPE *tp, int flag)
+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
@@ -64,9 +61,9 @@
{
int result = 0;
if (s != 0) {
- if (UChar(s[0]) == CSI)
+ if (UChar(s[0]) == CSI_CHR)
result = 1;
- else if (s[0] == ESC && s[1] == L_BRACK)
+ else if (s[0] == ESC_CHR && s[1] == L_BLOCK)
result = 2;
}
return result;
@@ -221,7 +218,7 @@
}
/*
- * While 'sgr0' is the "same" as termcap 'me', there is a compatibility issue.
+ * While 'sgr0' is the "same" as termcap 'me', there is a compatibility issue.
* The sgr/sgr0 capabilities include setting/clearing alternate character set
* mode. A termcap application cannot use sgr, so sgr0 strings that reset
* alternate character set mode will be misinterpreted. Here, we remove those
@@ -232,7 +229,7 @@
* an error occurs, or the original sgr0 if no change is needed.
*/
NCURSES_EXPORT(char *)
-_nc_trim_sgr0(TERMTYPE *tp)
+_nc_trim_sgr0(TERMTYPE2 *tp)
{
char *result = exit_attribute_mode;
@@ -263,7 +260,7 @@
/*
* If rmacs is a substring of sgr(0), remove that chunk.
*/
- if (exit_alt_charset_mode != 0) {
+ if (PRESENT(exit_alt_charset_mode)) {
TR(TRACE_DATABASE, ("scan for rmacs %s", _nc_visbuf(exit_alt_charset_mode)));
j = strlen(off);
k = strlen(exit_alt_charset_mode);
diff --git a/ncurses/tinfo/use_screen.c b/ncurses/tinfo/use_screen.c
index 6a0297c..a4bf932 100644
--- a/ncurses/tinfo/use_screen.c
+++ b/ncurses/tinfo/use_screen.c
@@ -1,5 +1,6 @@
/****************************************************************************
- * Copyright (c) 2007-2008,2009 Free Software Foundation, Inc. *
+ * Copyright 2018,2020 Thomas E. Dickey *
+ * Copyright 2007-2009,2016 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 *
@@ -32,15 +33,19 @@
#include <curses.priv.h>
-MODULE_ID("$Id: use_screen.c,v 1.8 2009/10/24 22:40:20 tom Exp $")
+MODULE_ID("$Id: use_screen.c,v 1.12 2020/02/02 23:34:34 tom Exp $")
NCURSES_EXPORT(int)
use_screen(SCREEN *screen, NCURSES_SCREEN_CB func, void *data)
{
SCREEN *save_SP;
int code = OK;
+ TR_FUNC_BFR(1);
- T((T_CALLED("use_screen(%p,%p,%p)"), (void *) screen, func, (void *) data));
+ T((T_CALLED("use_screen(%p,%s,%p)"),
+ (void *) screen,
+ TR_FUNC_ARG(0, func),
+ (void *) data));
/*
* FIXME - add a flag so a given thread can check if _it_ has already
diff --git a/ncurses/tinfo/write_entry.c b/ncurses/tinfo/write_entry.c
index b2edd5d..8ccca9e 100644
--- a/ncurses/tinfo/write_entry.c
+++ b/ncurses/tinfo/write_entry.c
@@ -1,5 +1,6 @@
/****************************************************************************
- * Copyright (c) 1998-2013,2014 Free Software Foundation, Inc. *
+ * Copyright 2018-2023,2024 Thomas E. Dickey *
+ * Copyright 1998-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 *
@@ -41,40 +42,74 @@
#include <tic.h>
+MODULE_ID("$Id: write_entry.c,v 1.132 2024/04/20 17:58:51 tom Exp $")
+
#if 1
#define TRACE_OUT(p) DEBUG(2, p)
+#define TRACE_NUM(n) if (VALID_NUMERIC(Numbers[n])) { \
+ TRACE_OUT(("put Numbers[%u]=%d", (unsigned) (n), Numbers[n])); }
#else
#define TRACE_OUT(p) /*nothing */
+#define TRACE_NUM(n) /* nothing */
#endif
-MODULE_ID("$Id: write_entry.c,v 1.92 2014/11/01 14:47:00 tom Exp $")
+/*
+ * FIXME: special case to work around Cygwin bug in link(), which updates
+ * the target file's timestamp.
+ */
+#if HAVE_LINK && !USE_SYMLINKS && !MIXEDCASE_FILENAMES && defined(__CYGWIN__)
+#define LINK_TOUCHES 1
+#else
+#define LINK_TOUCHES 0
+#endif
static int total_written;
+static int total_parts;
+static int total_size;
static int make_db_root(const char *);
-static int write_object(TERMTYPE *, char *, unsigned *, unsigned);
#if !USE_HASHED_DB
static void
-write_file(char *filename, TERMTYPE *tp)
+write_file(char *filename, TERMTYPE2 *tp)
{
char buffer[MAX_ENTRY_SIZE];
unsigned limit = sizeof(buffer);
unsigned offset = 0;
- FILE *fp = (_nc_access(filename, W_OK) == 0) ? fopen(filename, "wb") : 0;
- if (fp == 0) {
- perror(filename);
- _nc_syserr_abort("can't open %s/%s", _nc_tic_dir(0), filename);
- }
- DEBUG(1, ("Created %s", filename));
+ if (_nc_write_object(tp, buffer, &offset, limit) == ERR) {
+ _nc_warning("entry is larger than %u bytes", limit);
+ } else {
+ FILE *fp = ((_nc_access(filename, W_OK) == 0)
+ ? safe_fopen(filename, BIN_W)
+ : 0);
+ size_t actual;
- if (write_object(tp, buffer, &offset, limit) == ERR
- || fwrite(buffer, sizeof(char), (size_t) offset, fp) != offset) {
- _nc_syserr_abort("error writing %s/%s", _nc_tic_dir(0), filename);
- }
+ if (fp == 0) {
+ perror(filename);
+ _nc_syserr_abort("cannot open %s/%s", _nc_tic_dir(0), filename);
+ }
- fclose(fp);
+ actual = fwrite(buffer, sizeof(char), (size_t) offset, fp);
+ if (actual != offset) {
+ int myerr = ferror(fp) ? errno : 0;
+ if (myerr) {
+ _nc_syserr_abort("error writing %s/%s: %s",
+ _nc_tic_dir(NULL),
+ filename,
+ strerror(myerr));
+ } else {
+ _nc_syserr_abort("error writing %s/%s: %u bytes vs actual %lu",
+ _nc_tic_dir(NULL),
+ filename,
+ offset,
+ (unsigned long) actual);
+ }
+ } else {
+ fclose(fp);
+ DEBUG(1, ("Created %s", filename));
+ }
+ }
}
/*
@@ -93,18 +128,16 @@
char dir[sizeof(LEAF_FMT)];
char *s = 0;
- if (code == 0 || (s = (strchr) (dirnames, code)) == 0)
+ if (code == 0 || (s = (strchr) (dirnames, code)) == 0) {
_nc_err_abort("Illegal terminfo subdirectory \"" LEAF_FMT "\"", code);
-
- if (verified[s - dirnames])
- return;
-
- _nc_SPRINTF(dir, _nc_SLIMIT(sizeof(dir)) LEAF_FMT, code);
- if (make_db_root(dir) < 0) {
- _nc_err_abort("%s/%s: permission denied", _nc_tic_dir(0), dir);
+ } else if (!verified[s - dirnames]) {
+ _nc_SPRINTF(dir, _nc_SLIMIT(sizeof(dir)) LEAF_FMT, code);
+ if (make_db_root(dir) < 0) {
+ _nc_err_abort("%s/%s: permission denied", _nc_tic_dir(NULL), dir);
+ } else {
+ verified[s - dirnames] = TRUE;
+ }
}
-
- verified[s - dirnames] = TRUE;
}
#endif /* !USE_HASHED_DB */
@@ -112,7 +145,7 @@
make_db_path(char *dst, const char *src, size_t limit)
{
int rc = -1;
- const char *top = _nc_tic_dir(0);
+ const char *top = _nc_tic_dir(NULL);
if (src == top || _nc_is_abs_path(src)) {
if (strlen(src) + 1 <= limit) {
@@ -120,7 +153,7 @@
rc = 0;
}
} else {
- if (strlen(top) + strlen(src) + 2 <= limit) {
+ if ((strlen(top) + strlen(src) + 6) <= limit) {
_nc_SPRINTF(dst, _nc_SLIMIT(limit) "%s/%s", top, src);
rc = 0;
}
@@ -165,9 +198,9 @@
#else
struct stat statbuf;
- if ((rc = stat(path, &statbuf)) < 0) {
+ if ((rc = stat(path, &statbuf)) == -1) {
rc = mkdir(path
-#if !defined(__MINGW32__)
+#ifndef _NC_WINDOWS
,0777
#endif
);
@@ -189,26 +222,30 @@
{
const char *destination;
char actual[PATH_MAX];
+ bool specific = (dir != NULL);
- if (dir == 0
-#ifndef USE_ROOT_ENVIRON
- && use_terminfo_vars()
-#endif
- )
+ if (!specific && use_terminfo_vars())
dir = getenv("TERMINFO");
- if (dir != 0)
+ if (dir != NULL)
(void) _nc_tic_dir(dir);
- destination = _nc_tic_dir(0);
+ destination = _nc_tic_dir(NULL);
if (make_db_root(destination) < 0) {
- char *home = _nc_home_terminfo();
+ bool success = FALSE;
- if (home != 0) {
- destination = home;
- if (make_db_root(destination) < 0)
- _nc_err_abort("%s: permission denied (errno %d)",
- destination, errno);
+ if (!specific) {
+ char *home = _nc_home_terminfo();
+
+ if (home != NULL) {
+ destination = home;
+ if (make_db_root(destination) == 0)
+ success = TRUE;
+ }
+ }
+ if (!success) {
+ _nc_err_abort("%s: permission denied (errno %d)",
+ destination, errno);
}
}
@@ -220,10 +257,10 @@
make_db_path(actual, destination, sizeof(actual));
#else
if (chdir(_nc_tic_dir(destination)) < 0
- || getcwd(actual, sizeof(actual)) == 0)
+ || getcwd(actual, sizeof(actual)) == NULL)
_nc_err_abort("%s: not a directory", destination);
#endif
- _nc_keep_tic_dir(strdup(actual));
+ _nc_keep_tic_dir(actual);
}
/*
@@ -247,7 +284,7 @@
*/
NCURSES_EXPORT(void)
-_nc_write_entry(TERMTYPE *const tp)
+_nc_write_entry(TERMTYPE2 *const tp)
{
#if USE_HASHED_DB
@@ -268,6 +305,9 @@
#endif
#endif /* USE_SYMLINKS */
+ unsigned limit2 = sizeof(filename) - (2 + LEAF_LEN);
+ char saved = '\0';
+
static int call_count;
static time_t start_time; /* time at start of writes */
@@ -299,8 +339,9 @@
if (ptr != name_list) {
*ptr = '\0';
- for (ptr = name_list; *ptr != '\0' && *ptr != '|'; ptr++)
- continue;
+ for (ptr = name_list; *ptr != '\0' && *ptr != '|'; ptr++) {
+ /* EMPTY */ ;
+ }
if (*ptr == '\0')
other_names = ptr;
@@ -316,11 +357,11 @@
_nc_set_type(first_name);
#if USE_HASHED_DB
- if (write_object(tp, buffer + 1, &offset, limit - 1) != ERR) {
- DB *capdb = _nc_db_open(_nc_tic_dir(0), TRUE);
+ if (_nc_write_object(tp, buffer + 1, &offset, limit - 1) != ERR) {
+ DB *capdb = _nc_db_open(_nc_tic_dir(NULL), TRUE);
DBT key, data;
- if (capdb != 0) {
+ if (capdb != NULL) {
buffer[0] = 0;
memset(&key, 0, sizeof(key));
@@ -343,6 +384,8 @@
sizeof(buffer) - 1);
data.size = name_size + 1;
+ total_size += (int) data.size;
+ total_parts++;
_nc_db_put(capdb, &key, &data);
while (*other_names != '\0') {
@@ -357,6 +400,8 @@
key.data = ptr;
key.size = strlen(ptr);
+ total_size += (int) data.size;
+ total_parts++;
_nc_db_put(capdb, &key, &data);
}
}
@@ -366,11 +411,19 @@
start_time = 0;
}
- if (strlen(first_name) >= sizeof(filename) - (2 + LEAF_LEN))
+ if (strlen(first_name) >= limit2) {
_nc_warning("terminal name too long.");
+ saved = first_name[limit2];
+ first_name[limit2] = '\0';
+ }
_nc_SPRINTF(filename, _nc_SLIMIT(sizeof(filename))
- LEAF_FMT "/%s", first_name[0], first_name);
+ LEAF_FMT "/%.*s", UChar(first_name[0]),
+ (int) (sizeof(filename) - (LEAF_LEN + 2)),
+ first_name);
+
+ if (saved)
+ first_name[limit2] = saved;
/*
* Has this primary name been written since the first call to
@@ -402,10 +455,10 @@
write_file(filename, tp);
if (start_time == 0) {
- if (stat(filename, &statbuf) < 0
+ if (stat(filename, &statbuf) == -1
|| (start_time = statbuf.st_mtime) == 0) {
_nc_syserr_abort("error obtaining time from %s/%s",
- _nc_tic_dir(0), filename);
+ _nc_tic_dir(NULL), filename);
}
}
while (*other_names != '\0') {
@@ -420,32 +473,38 @@
_nc_warning("terminal alias %s too long.", ptr);
continue;
}
- if (strchr(ptr, '/') != 0) {
+ if (strchr(ptr, '/') != NULL) {
_nc_warning("cannot link alias %s.", ptr);
continue;
}
check_writeable(ptr[0]);
_nc_SPRINTF(linkname, _nc_SLIMIT(sizeof(linkname))
- LEAF_FMT "/%s", ptr[0], ptr);
+ LEAF_FMT "/%.*s", ptr[0],
+ (int) sizeof(linkname) - (2 + LEAF_LEN), ptr);
if (strcmp(filename, linkname) == 0) {
_nc_warning("self-synonym ignored");
- } else if (stat(linkname, &statbuf) >= 0 &&
- statbuf.st_mtime < start_time) {
+ }
+#if !LINK_TOUCHES
+ else if (stat(linkname, &statbuf) >= 0 &&
+ statbuf.st_mtime < start_time) {
_nc_warning("alias %s multiply defined.", ptr);
- } else if (_nc_access(linkname, W_OK) == 0)
+ }
+#endif
+ else if (_nc_access(linkname, W_OK) == 0)
#if HAVE_LINK
{
int code;
#if USE_SYMLINKS
- if (first_name[0] == linkname[0])
- strncpy(symlinkname, first_name, sizeof(symlinkname) - 1);
- else {
- _nc_STRCPY(symlinkname, "../", sizeof(suymlinkname));
- strncat(symlinkname, filename, sizeof(symlinkname) - 4);
+#define MY_SIZE sizeof(symlinkname) - 1
+ if (first_name[0] == linkname[0]) {
+ _nc_STRNCPY(symlinkname, first_name, MY_SIZE);
+ } else {
+ _nc_STRCPY(symlinkname, "../", sizeof(symlinkname));
+ _nc_STRNCPY(symlinkname + 3, filename, MY_SIZE - 3);
}
- symlinkname[sizeof(symlinkname) - 1] = '\0';
+ symlinkname[MY_SIZE] = '\0';
#endif /* USE_SYMLINKS */
#if HAVE_REMOVE
code = remove(linkname);
@@ -472,9 +531,9 @@
write_file(linkname, tp);
else {
#if MIXEDCASE_FILENAMES
- _nc_syserr_abort("can't link %s to %s", filename, linkname);
+ _nc_syserr_abort("cannot link %s to %s", filename, linkname);
#else
- _nc_warning("can't link %s to %s (errno=%d)", filename,
+ _nc_warning("cannot link %s to %s (errno=%d)", filename,
linkname, errno);
#endif
}
@@ -542,7 +601,7 @@
return nextfree;
}
-static void
+static size_t
convert_shorts(unsigned char *buf, short *Numbers, size_t count)
{
size_t i;
@@ -557,14 +616,49 @@
TRACE_OUT(("put Numbers[%u]=%d", (unsigned) i, Numbers[i]));
}
}
+ return SIZEOF_SHORT;
}
+#if NCURSES_EXT_NUMBERS
+static size_t
+convert_16bit(unsigned char *buf, NCURSES_INT2 *Numbers, size_t count)
+{
+ size_t i, j;
+ size_t size = SIZEOF_SHORT;
+ for (i = 0; i < count; i++) {
+ unsigned value = (unsigned) Numbers[i];
+ TRACE_NUM(i);
+ for (j = 0; j < size; ++j) {
+ *buf++ = value & 0xff;
+ value >>= 8;
+ }
+ }
+ return size;
+}
+
+static size_t
+convert_32bit(unsigned char *buf, NCURSES_INT2 *Numbers, size_t count)
+{
+ size_t i, j;
+ size_t size = SIZEOF_INT2;
+ for (i = 0; i < count; i++) {
+ unsigned value = (unsigned) Numbers[i];
+ TRACE_NUM(i);
+ for (j = 0; j < size; ++j) {
+ *buf++ = value & 0xff;
+ value >>= 8;
+ }
+ }
+ return size;
+}
+#endif
+
#define even_boundary(value) \
((value) % 2 != 0 && Write(&zero, sizeof(char), 1) != 1)
#if NCURSES_XNAMES
static unsigned
-extended_Booleans(TERMTYPE *tp)
+extended_Booleans(TERMTYPE2 *tp)
{
unsigned result = 0;
unsigned i;
@@ -577,7 +671,7 @@
}
static unsigned
-extended_Numbers(TERMTYPE *tp)
+extended_Numbers(TERMTYPE2 *tp)
{
unsigned result = 0;
unsigned i;
@@ -590,7 +684,7 @@
}
static unsigned
-extended_Strings(TERMTYPE *tp)
+extended_Strings(TERMTYPE2 *tp)
{
unsigned short result = 0;
unsigned short i;
@@ -607,7 +701,7 @@
* clause - discard the unneeded data.
*/
static bool
-extended_object(TERMTYPE *tp)
+extended_object(TERMTYPE2 *tp)
{
bool result = FALSE;
@@ -620,11 +714,11 @@
}
#endif
-static int
-write_object(TERMTYPE *tp, char *buffer, unsigned *offset, unsigned limit)
+NCURSES_EXPORT(int)
+_nc_write_object(TERMTYPE2 *tp, char *buffer, unsigned *offset, unsigned limit)
{
char *namelist;
- size_t namelen, boolmax, nummax, strmax;
+ size_t namelen, boolmax, nummax, strmax, numlen;
char zero = '\0';
size_t i;
int nextfree;
@@ -633,6 +727,12 @@
unsigned last_bool = BOOLWRITE;
unsigned last_num = NUMWRITE;
unsigned last_str = STRWRITE;
+#if NCURSES_EXT_NUMBERS
+ bool need_ints = FALSE;
+ size_t (*convert_numbers) (unsigned char *, NCURSES_INT2 *, size_t);
+#else
+#define convert_numbers convert_shorts
+#endif
#if NCURSES_XNAMES
/*
@@ -653,14 +753,21 @@
boolmax = 0;
for (i = 0; i < last_bool; i++) {
- if (tp->Booleans[i] == TRUE)
+ if (tp->Booleans[i] == TRUE) {
boolmax = i + 1;
+ }
}
nummax = 0;
for (i = 0; i < last_num; i++) {
- if (tp->Numbers[i] != ABSENT_NUMERIC)
+ if (tp->Numbers[i] != ABSENT_NUMERIC) {
nummax = i + 1;
+#if NCURSES_EXT_NUMBERS
+ if (tp->Numbers[i] > MAX_OF_TYPE(NCURSES_COLOR_T)) {
+ need_ints = TRUE;
+ }
+#endif
+ }
}
strmax = 0;
@@ -672,8 +779,19 @@
nextfree = compute_offsets(tp->Strings, strmax, offsets);
/* fill in the header */
+#if NCURSES_EXT_NUMBERS
+ if (need_ints) {
+ convert_numbers = convert_32bit;
+ LITTLE_ENDIAN(buf, MAGIC2);
+ } else {
+ convert_numbers = convert_16bit;
+ LITTLE_ENDIAN(buf, MAGIC);
+ }
+#else
LITTLE_ENDIAN(buf, MAGIC);
- LITTLE_ENDIAN(buf + 2, min(namelen, MAX_NAME_SIZE + 1));
+#endif
+ namelen = Min(namelen, MAX_NAME_SIZE + 1);
+ LITTLE_ENDIAN(buf + 2, namelen);
LITTLE_ENDIAN(buf + 4, boolmax);
LITTLE_ENDIAN(buf + 6, nummax);
LITTLE_ENDIAN(buf + 8, strmax);
@@ -682,62 +800,81 @@
/* write out the header */
TRACE_OUT(("Header of %s @%d", namelist, *offset));
if (Write(buf, 12, 1) != 1
- || Write(namelist, sizeof(char), namelen) != namelen)
- return (ERR);
-
- for (i = 0; i < boolmax; i++)
- if (tp->Booleans[i] == TRUE)
- buf[i] = TRUE;
- else
- buf[i] = FALSE;
- if (Write(buf, sizeof(char), boolmax) != boolmax)
- return (ERR);
-
- if (even_boundary(namelen + boolmax))
+ || Write(namelist, sizeof(char), namelen) != namelen) {
return (ERR);
+ }
+
+ for (i = 0; i < boolmax; i++) {
+ if (tp->Booleans[i] == TRUE) {
+ buf[i] = TRUE;
+ } else {
+ buf[i] = FALSE;
+ }
+ }
+ if (Write(buf, sizeof(char), boolmax) != boolmax) {
+ return (ERR);
+ }
+
+ if (even_boundary(namelen + boolmax)) {
+ return (ERR);
+ }
TRACE_OUT(("Numerics begin at %04x", *offset));
/* the numerics */
- convert_shorts(buf, tp->Numbers, nummax);
- if (Write(buf, 2, nummax) != nummax)
+ numlen = convert_numbers(buf, tp->Numbers, nummax);
+ if (Write(buf, numlen, nummax) != nummax) {
return (ERR);
+ }
TRACE_OUT(("String offsets begin at %04x", *offset));
/* the string offsets */
convert_shorts(buf, offsets, strmax);
- if (Write(buf, 2, strmax) != strmax)
+ if (Write(buf, SIZEOF_SHORT, strmax) != strmax) {
return (ERR);
+ }
TRACE_OUT(("String table begins at %04x", *offset));
/* the strings */
- for (i = 0; i < strmax; i++)
- if (VALID_STRING(tp->Strings[i]))
- if (!WRITE_STRING(tp->Strings[i]))
+ for (i = 0; i < strmax; i++) {
+ if (VALID_STRING(tp->Strings[i])) {
+ if (!WRITE_STRING(tp->Strings[i])) {
return (ERR);
+ }
+ }
+ }
#if NCURSES_XNAMES
if (extended_object(tp)) {
- unsigned extcnt = (unsigned) NUM_EXT_NAMES(tp);
+ unsigned ext_total = (unsigned) NUM_EXT_NAMES(tp);
+ unsigned ext_usage = ext_total;
- if (even_boundary(nextfree))
+ if (even_boundary(nextfree)) {
return (ERR);
+ }
nextfree = compute_offsets(tp->Strings + STRCOUNT,
(size_t) tp->ext_Strings,
offsets);
TRACE_OUT(("after extended string capabilities, nextfree=%d", nextfree));
- if (tp->ext_Strings >= SIZEOF(offsets))
+ if (tp->ext_Strings >= SIZEOF(offsets)) {
return (ERR);
+ }
nextfree += compute_offsets(tp->ext_Names,
- (size_t) extcnt,
+ (size_t) ext_total,
offsets + tp->ext_Strings);
TRACE_OUT(("after extended capnames, nextfree=%d", nextfree));
- strmax = tp->ext_Strings + extcnt;
+ strmax = tp->ext_Strings + ext_total;
+ for (i = 0; i < tp->ext_Strings; ++i) {
+ if (VALID_STRING(tp->Strings[i + STRCOUNT])) {
+ ext_usage++;
+ }
+ }
+ TRACE_OUT(("will write %u/%lu strings", ext_usage, (unsigned long) strmax));
/*
* Write the extended header
@@ -745,26 +882,30 @@
LITTLE_ENDIAN(buf + 0, tp->ext_Booleans);
LITTLE_ENDIAN(buf + 2, tp->ext_Numbers);
LITTLE_ENDIAN(buf + 4, tp->ext_Strings);
- LITTLE_ENDIAN(buf + 6, strmax);
+ LITTLE_ENDIAN(buf + 6, ext_usage);
LITTLE_ENDIAN(buf + 8, nextfree);
TRACE_OUT(("WRITE extended-header @%d", *offset));
- if (Write(buf, 10, 1) != 1)
+ if (Write(buf, 10, 1) != 1) {
return (ERR);
+ }
TRACE_OUT(("WRITE %d booleans @%d", tp->ext_Booleans, *offset));
if (tp->ext_Booleans
&& Write(tp->Booleans + BOOLCOUNT, sizeof(char),
- tp->ext_Booleans) != tp->ext_Booleans)
- return (ERR);
-
- if (even_boundary(tp->ext_Booleans))
+ tp->ext_Booleans) != tp->ext_Booleans) {
return (ERR);
+ }
+
+ if (even_boundary(tp->ext_Booleans)) {
+ return (ERR);
+ }
TRACE_OUT(("WRITE %d numbers @%d", tp->ext_Numbers, *offset));
if (tp->ext_Numbers) {
- convert_shorts(buf, tp->Numbers + NUMCOUNT, (size_t) tp->ext_Numbers);
- if (Write(buf, 2, tp->ext_Numbers) != tp->ext_Numbers)
+ numlen = convert_numbers(buf, tp->Numbers + NUMCOUNT, (size_t) tp->ext_Numbers);
+ if (Write(buf, numlen, tp->ext_Numbers) != tp->ext_Numbers) {
return (ERR);
+ }
}
/*
@@ -773,8 +914,9 @@
*/
convert_shorts(buf, offsets, strmax);
TRACE_OUT(("WRITE offsets @%d", *offset));
- if (Write(buf, 2, strmax) != strmax)
+ if (Write(buf, SIZEOF_SHORT, strmax) != strmax) {
return (ERR);
+ }
/*
* Write the string table after the offset tables so we do not
@@ -784,24 +926,28 @@
if (VALID_STRING(tp->Strings[i + STRCOUNT])) {
TRACE_OUT(("WRITE ext_Strings[%d]=%s", (int) i,
_nc_visbuf(tp->Strings[i + STRCOUNT])));
- if (!WRITE_STRING(tp->Strings[i + STRCOUNT]))
+ if (!WRITE_STRING(tp->Strings[i + STRCOUNT])) {
return (ERR);
+ }
}
}
/*
* Write the extended names
*/
- for (i = 0; i < extcnt; i++) {
+ for (i = 0; i < ext_total; i++) {
TRACE_OUT(("WRITE ext_Names[%d]=%s", (int) i, tp->ext_Names[i]));
- if (!WRITE_STRING(tp->ext_Names[i]))
+ if (!WRITE_STRING(tp->ext_Names[i])) {
return (ERR);
+ }
}
}
#endif /* NCURSES_XNAMES */
total_written++;
+ total_parts++;
+ total_size = total_size + (int) (*offset + 1);
return (OK);
}
@@ -811,5 +957,7 @@
NCURSES_EXPORT(int)
_nc_tic_written(void)
{
+ TR(TRACE_DATABASE, ("_nc_tic_written %d entries, %d parts, %d size",
+ total_written, total_parts, total_size));
return total_written;
}