summaryrefslogtreecommitdiff
path: root/progs
diff options
context:
space:
mode:
authorLorry <lorry@roadtrain.codethink.co.uk>2012-01-18 12:04:32 +0000
committerLorry <lorry@roadtrain.codethink.co.uk>2012-01-18 12:04:32 +0000
commite2d147e01aa8bd00b79c8288fa1c490d187c9e82 (patch)
tree0e50849418106307cd3b6ae5346d11cdcec8756c /progs
downloadncurses-e2d147e01aa8bd00b79c8288fa1c490d187c9e82.tar.gz
Tarball conversion
Diffstat (limited to 'progs')
-rwxr-xr-xprogs/MKtermsort.sh164
-rw-r--r--progs/Makefile.in320
-rwxr-xr-xprogs/capconvert256
-rw-r--r--progs/clear.c59
-rwxr-xr-xprogs/clear.sh29
-rw-r--r--progs/dump_entry.c1273
-rw-r--r--progs/dump_entry.h80
-rw-r--r--progs/infocmp.c1657
-rw-r--r--progs/modules45
-rw-r--r--progs/progs.priv.h192
-rw-r--r--progs/tabs.c510
-rw-r--r--progs/tic.c1714
-rw-r--r--progs/toe.c525
-rw-r--r--progs/tput.c447
-rw-r--r--progs/transform.c79
-rw-r--r--progs/tset.c1349
16 files changed, 8699 insertions, 0 deletions
diff --git a/progs/MKtermsort.sh b/progs/MKtermsort.sh
new file mode 100755
index 0000000..2247f14
--- /dev/null
+++ b/progs/MKtermsort.sh
@@ -0,0 +1,164 @@
+#!/bin/sh
+# $Id: MKtermsort.sh,v 1.10 2008/07/12 20:22:54 tom Exp $
+#
+# MKtermsort.sh -- generate indirection vectors for the various sort methods
+#
+##############################################################################
+# Copyright (c) 1998-2003,2008 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. #
+##############################################################################
+#
+# The output of this script is C source for nine arrays that list three sort
+# orders for each of the three different classes of terminfo capabilities.
+#
+# keep the order independent of locale:
+if test "${LANGUAGE+set}" = set; then LANGUAGE=C; export LANGUAGE; fi
+if test "${LANG+set}" = set; then LANG=C; export LANG; fi
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
+if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi
+if test "${LC_COLLATE+set}" = set; then LC_COLLATE=C; export LC_COLLATE; fi
+#
+AWK=${1-awk}
+DATA=${2-../include/Caps}
+
+data=data$$
+trap 'rm -f $data' 1 2 5 15
+sed -e 's/[ ][ ]*/ /g' < $DATA >$data
+DATA=$data
+
+echo "/*";
+echo " * termsort.c --- sort order arrays for use by infocmp.";
+echo " *";
+echo " * Note: this file is generated using MKtermsort.sh, do not edit by hand.";
+echo " */";
+
+echo "static const PredIdx bool_terminfo_sort[] = {";
+$AWK <$DATA '
+BEGIN {i = 0;}
+/^#/ {next;}
+$3 == "bool" {printf("%s\t%d\n", $2, i++);}
+' | sort | $AWK '{print "\t", $2, ",\t/* ", $1, " */";}';
+echo "};";
+echo "";
+
+echo "static const PredIdx num_terminfo_sort[] = {";
+$AWK <$DATA '
+BEGIN {i = 0;}
+/^#/ {next;}
+$3 == "num" {printf("%s\t%d\n", $2, i++);}
+' | sort | $AWK '{print "\t", $2, ",\t/* ", $1, " */";}';
+echo "};";
+echo "";
+
+echo "static const PredIdx str_terminfo_sort[] = {";
+$AWK <$DATA '
+BEGIN {i = 0;}
+/^#/ {next;}
+$3 == "str" {printf("%s\t%d\n", $2, i++);}
+' | sort | $AWK '{print "\t", $2, ",\t/* ", $1, " */";}';
+echo "};";
+echo "";
+
+echo "static const PredIdx bool_variable_sort[] = {";
+$AWK <$DATA '
+BEGIN {i = 0;}
+/^#/ {next;}
+$3 == "bool" {printf("%s\t%d\n", $1, i++);}
+' | sort | $AWK '{print "\t", $2, ",\t/* ", $1, " */";}';
+echo "};";
+echo "";
+
+echo "static const PredIdx num_variable_sort[] = {";
+$AWK <$DATA '
+BEGIN {i = 0;}
+/^#/ {next;}
+$3 == "num" {printf("%s\t%d\n", $1, i++);}
+' | sort | $AWK '{print "\t", $2, ",\t/* ", $1, " */";}';
+echo "};";
+echo "";
+
+echo "static const PredIdx str_variable_sort[] = {";
+$AWK <$DATA '
+BEGIN {i = 0;}
+/^#/ {next;}
+$3 == "str" {printf("%s\t%d\n", $1, i++);}
+' | sort | $AWK '{print "\t", $2, ",\t/* ", $1, " */";}';
+echo "};";
+echo "";
+
+echo "static const PredIdx bool_termcap_sort[] = {";
+$AWK <$DATA '
+BEGIN {i = 0;}
+/^#/ {next;}
+$3 == "bool" {printf("%s\t%d\n", $4, i++);}
+' | sort | $AWK '{print "\t", $2, ",\t/* ", $1, " */";}';
+echo "};";
+echo "";
+
+echo "static const PredIdx num_termcap_sort[] = {";
+$AWK <$DATA '
+BEGIN {i = 0;}
+/^#/ {next;}
+$3 == "num" {printf("%s\t%d\n", $4, i++);}
+' | sort | $AWK '{print "\t", $2, ",\t/* ", $1, " */";}';
+echo "};";
+echo "";
+
+echo "static const PredIdx str_termcap_sort[] = {";
+$AWK <$DATA '
+BEGIN {i = 0;}
+/^#/ {next;}
+$3 == "str" {printf("%s\t%d\n", $4, i++);}
+' | sort | $AWK '{print "\t", $2, ",\t/* ", $1, " */";}';
+echo "};";
+echo "";
+
+echo "static const bool bool_from_termcap[] = {";
+$AWK <$DATA '
+$3 == "bool" && substr($7, 1, 1) == "-" {print "\tFALSE,\t/* ", $2, " */";}
+$3 == "bool" && substr($7, 1, 1) == "Y" {print "\tTRUE,\t/* ", $2, " */";}
+'
+echo "};";
+echo "";
+
+echo "static const bool num_from_termcap[] = {";
+$AWK <$DATA '
+$3 == "num" && substr($7, 1, 1) == "-" {print "\tFALSE,\t/* ", $2, " */";}
+$3 == "num" && substr($7, 1, 1) == "Y" {print "\tTRUE,\t/* ", $2, " */";}
+'
+echo "};";
+echo "";
+
+echo "static const bool str_from_termcap[] = {";
+$AWK <$DATA '
+$3 == "str" && substr($7, 1, 1) == "-" {print "\tFALSE,\t/* ", $2, " */";}
+$3 == "str" && substr($7, 1, 1) == "Y" {print "\tTRUE,\t/* ", $2, " */";}
+'
+echo "};";
+echo "";
+
+rm -f $data
diff --git a/progs/Makefile.in b/progs/Makefile.in
new file mode 100644
index 0000000..bdb8a0f
--- /dev/null
+++ b/progs/Makefile.in
@@ -0,0 +1,320 @@
+# $Id: Makefile.in,v 1.85 2010/11/27 21:45:27 tom Exp $
+##############################################################################
+# Copyright (c) 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: Thomas E. Dickey 1996-on
+#
+# Makefile for ncurses source code.
+#
+# This makes the ncurses utility programs.
+#
+# The variable 'srcdir' refers to the source-distribution, and can be set with
+# the configure script by "--srcdir=DIR".
+#
+# The rules are organized to produce the libraries for the configured models,
+# and the programs with the configured default model.
+
+# turn off _all_ suffix rules; we'll generate our own
+.SUFFIXES:
+
+SHELL = /bin/sh
+VPATH = @srcdir@
+THIS = Makefile
+
+CF_MFLAGS = @cf_cv_makeflags@
+@SET_MAKE@
+
+x = @EXEEXT@
+o = .@OBJEXT@
+
+MODEL = ../@DFT_OBJ_SUBDIR@
+DESTDIR = @DESTDIR@
+top_srcdir = @top_srcdir@
+srcdir = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+bindir = @bindir@
+libdir = @libdir@
+includedir = @includedir@
+datadir = @datadir@
+
+LIBTOOL = @LIBTOOL@
+LIBTOOL_CLEAN = @LIB_CLEAN@
+LIBTOOL_COMPILE = @LIB_COMPILE@
+LIBTOOL_LINK = @LIB_LINK@
+LIBTOOL_INSTALL = @LIB_INSTALL@
+LIBTOOL_UNINSTALL = @LIB_UNINSTALL@
+
+INSTALL = @INSTALL@
+INSTALL_PROG = @INSTALL_PROGRAM@
+transform = @program_transform_name@
+
+AWK = @AWK@
+LN_S = @LN_S@
+
+CTAGS = @CTAGS@
+ETAGS = @ETAGS@
+
+CC = @CC@
+CPP = @CPP@
+CFLAGS = @CFLAGS@
+
+INCDIR = $(top_srcdir)/include
+CPPFLAGS = -I../progs -I$(srcdir) -DHAVE_CONFIG_H @CPPFLAGS@
+
+CCFLAGS = $(CPPFLAGS) $(CFLAGS)
+
+CFLAGS_LIBTOOL = $(CCFLAGS)
+CFLAGS_NORMAL = $(CCFLAGS)
+CFLAGS_DEBUG = $(CCFLAGS) @CC_G_OPT@ -DTRACE
+CFLAGS_PROFILE = $(CCFLAGS) -pg
+CFLAGS_SHARED = $(CCFLAGS) @CC_SHARED_OPTS@
+
+CFLAGS_DEFAULT = $(CFLAGS_@DFT_UPR_MODEL@)
+
+REL_VERSION = @cf_cv_rel_version@
+ABI_VERSION = @cf_cv_abi_version@
+LOCAL_LIBDIR = @top_builddir@/lib
+
+LD = @LD@
+LINK = @LINK_PROGS@ $(LIBTOOL_LINK)
+LDFLAGS = @EXTRA_LDFLAGS@ @LDFLAGS@
+
+LDFLAGS_LIBTOOL = $(LDFLAGS) $(CFLAGS_LIBTOOL)
+LDFLAGS_NORMAL = $(LDFLAGS) $(CFLAGS_NORMAL)
+LDFLAGS_DEBUG = $(LDFLAGS) $(CFLAGS_DEBUG)
+LDFLAGS_PROFILE = $(LDFLAGS) $(CFLAGS_PROFILE)
+LDFLAGS_SHARED = $(LDFLAGS) $(CFLAGS_SHARED) @LD_SHARED_OPTS@
+
+LDFLAGS_DEFAULT = $(LDFLAGS_@DFT_UPR_MODEL@)
+
+LIBS_TIC = @LDFLAGS_STATIC@ @TICS_ARGS@ @TINFO_ARGS@ @LDFLAGS_SHARED@ @LD_MODEL@ @LIBS@
+LDFLAGS_TIC = $(LDFLAGS_@DFT_UPR_MODEL@) $(LIBS_TIC)
+
+LIBS_TINFO = @LDFLAGS_STATIC@ @TINFO_ARGS@ @LDFLAGS_SHARED@ @LD_MODEL@ @LIBS@
+LDFLAGS_TINFO = $(LDFLAGS_@DFT_UPR_MODEL@) $(LIBS_TINFO)
+
+LINT = @LINT@
+LINT_OPTS = @LINT_OPTS@
+LINT_LIBS = -lncurses @LIBS@
+
+AUTO_SRC = \
+ termsort.c \
+ transform.h
+
+# tic relies on direct access to the terminfo database
+GET_PROGS = infocmp$x clear$x tabs$x tput$x tset$x toe$x
+PUT_PROGS = @MAKE_TERMINFO@ tic$x
+PROGS = $(PUT_PROGS) $(GET_PROGS)
+
+# Default library, for linking applications
+DEPS_CURSES = ../lib/@LIB_PREFIX@ncurses@DFT_DEP_SUFFIX@
+
+HEADER_DEPS = \
+ ../include/curses.h \
+ $(INCDIR)/term_entry.h \
+ $(INCDIR)/tic.h \
+ $(INCDIR)/nc_alloc.h
+
+################################################################################
+all: $(AUTO_SRC) $(PROGS)
+
+sources: $(AUTO_SRC)
+
+install: $(AUTO_SRC) install.progs
+uninstall: uninstall.progs
+
+# this line simplifies the configure-script
+libs \
+install.libs \
+uninstall.libs:
+
+TRANSFORM = sed 's/$x$$//'|sed '$(transform)'|sed 's/$$/$x/'
+
+# transformed names for installing files
+actual_captoinfo = `echo captoinfo$x| $(TRANSFORM)`
+actual_clear = `echo clear$x| $(TRANSFORM)`
+actual_infocmp = `echo infocmp$x| $(TRANSFORM)`
+actual_infotocap = `echo infotocap$x| $(TRANSFORM)`
+actual_init = `echo init$x| $(TRANSFORM)`
+actual_reset = `echo reset$x| $(TRANSFORM)`
+actual_tabs = `echo tabs$x| $(TRANSFORM)`
+actual_tic = `echo tic$x| $(TRANSFORM)`
+actual_toe = `echo toe$x| $(TRANSFORM)`
+actual_tput = `echo tput$x| $(TRANSFORM)`
+actual_tset = `echo tset$x| $(TRANSFORM)`
+
+# transformed names for comparing at runtime
+define_captoinfo = `echo captoinfo| $(TRANSFORM)`
+define_infotocap = `echo infotocap| $(TRANSFORM)`
+define_init = `echo init| $(TRANSFORM)`
+define_reset = `echo reset| $(TRANSFORM)`
+
+transform.h :
+ echo "#ifndef __TRANSFORM_H" >$@
+ echo "#define __TRANSFORM_H 1" >>$@
+ echo "#include <progs.priv.h>" >>$@
+ echo "extern bool same_program(const char *, const char *);" >>$@
+ -sh -c 'if test -n "$x" ; then echo "#define SUFFIX_IGNORED \"$x\"">>$@; fi'
+ echo "#define PROG_CAPTOINFO \"$(define_captoinfo)\"" >>$@
+ echo "#define PROG_INFOTOCAP \"$(define_infotocap)\"" >>$@
+ echo "#define PROG_RESET \"$(define_reset)\"" >>$@
+ echo "#define PROG_INIT \"$(define_init)\"" >>$@
+ echo "#endif /* __TRANSFORM_H */" >>$@
+
+install.progs: $(AUTO_SRC) $(PROGS) $(DESTDIR)$(bindir)
+@MAKE_TERMINFO@ $(LIBTOOL_INSTALL) $(INSTALL_PROG) tic$x $(DESTDIR)$(bindir)/$(actual_tic)
+@MAKE_TERMINFO@ $(LIBTOOL_INSTALL) $(INSTALL_PROG) toe$x $(DESTDIR)$(bindir)/$(actual_toe)
+@MAKE_TERMINFO@ @echo "linking $(actual_infotocap) to $(actual_tic)"
+@MAKE_TERMINFO@ -@rm -f $(DESTDIR)$(bindir)/$(actual_infotocap)
+@MAKE_TERMINFO@ (cd $(DESTDIR)$(bindir) && $(LN_S) $(actual_tic) $(actual_infotocap))
+@MAKE_TERMINFO@ @echo "linking $(actual_captoinfo) to $(actual_tic)"
+@MAKE_TERMINFO@ -@rm -f $(DESTDIR)$(bindir)/$(actual_captoinfo)
+@MAKE_TERMINFO@ (cd $(DESTDIR)$(bindir) && $(LN_S) $(actual_tic) $(actual_captoinfo))
+ $(LIBTOOL_INSTALL) $(INSTALL_PROG) infocmp$x $(DESTDIR)$(bindir)/$(actual_infocmp)
+ $(LIBTOOL_INSTALL) $(INSTALL_PROG) clear$x $(DESTDIR)$(bindir)/$(actual_clear)
+ $(LIBTOOL_INSTALL) $(INSTALL_PROG) tabs$x $(DESTDIR)$(bindir)/$(actual_tabs)
+ $(LIBTOOL_INSTALL) $(INSTALL_PROG) tput$x $(DESTDIR)$(bindir)/$(actual_tput)
+ $(LIBTOOL_INSTALL) $(INSTALL_PROG) tset$x $(DESTDIR)$(bindir)/$(actual_tset)
+ @echo "linking $(actual_reset) to $(actual_tset)"
+ -@rm -f $(DESTDIR)$(bindir)/$(actual_reset)
+ (cd $(DESTDIR)$(bindir) && $(LN_S) $(actual_tset) $(actual_reset))
+
+uninstall.progs:
+@MAKE_TERMINFO@ -@$(LIBTOOL_CLEAN) rm -f $(DESTDIR)$(bindir)/$(actual_tic)
+@MAKE_TERMINFO@ -@$(LIBTOOL_CLEAN) rm -f $(DESTDIR)$(bindir)/$(actual_toe)
+@MAKE_TERMINFO@ -@rm -f $(DESTDIR)$(bindir)/$(actual_captoinfo)
+@MAKE_TERMINFO@ -@rm -f $(DESTDIR)$(bindir)/$(actual_infotocap)
+ -@$(LIBTOOL_CLEAN) rm -f $(DESTDIR)$(bindir)/$(actual_infocmp)
+ -@$(LIBTOOL_CLEAN) rm -f $(DESTDIR)$(bindir)/$(actual_clear)
+ -@$(LIBTOOL_CLEAN) rm -f $(DESTDIR)$(bindir)/$(actual_tabs)
+ -@$(LIBTOOL_CLEAN) rm -f $(DESTDIR)$(bindir)/$(actual_tput)
+ -@$(LIBTOOL_CLEAN) rm -f $(DESTDIR)$(bindir)/$(actual_tset)
+ -@rm -f $(DESTDIR)$(bindir)/$(actual_reset)
+
+$(DESTDIR)$(bindir) :
+ mkdir -p $@
+
+#
+# Utilities normally built by make all start here
+#
+
+DEPS_TIC = \
+ $(MODEL)/tic$o \
+ $(MODEL)/dump_entry$o \
+ $(MODEL)/transform$o
+
+tic$x: $(DEPS_TIC) $(DEPS_CURSES) transform.h
+ @ECHO_LINK@ $(LINK) $(DEPS_TIC) $(LDFLAGS_TIC) -o $@
+
+DEPS_TOE = \
+ $(MODEL)/toe$o
+
+toe$x: $(DEPS_TOE) $(DEPS_CURSES)
+ @ECHO_LINK@ $(LINK) $(DEPS_TOE) $(LDFLAGS_TIC) -o $@
+
+DEPS_CLEAR = \
+ $(MODEL)/clear$o
+
+clear$x: $(DEPS_CLEAR) $(DEPS_CURSES)
+ @ECHO_LINK@ $(LINK) $(DEPS_CLEAR) $(LDFLAGS_TINFO) -o $@
+
+DEPS_TABS = \
+ $(MODEL)/tabs$o
+
+tabs$x: $(DEPS_TABS) $(DEPS_TABS)
+ @ECHO_LINK@ $(LINK) $(DEPS_TABS) $(LDFLAGS_TINFO) -o $@
+
+DEPS_TPUT = \
+ $(MODEL)/tput$o \
+ $(MODEL)/transform$o
+
+tput$x: $(DEPS_TPUT) $(DEPS_CURSES) transform.h
+ @ECHO_LINK@ $(LINK) $(DEPS_TPUT) $(LDFLAGS_TINFO) -o $@
+
+DEPS_INFOCMP = \
+ $(MODEL)/infocmp$o \
+ $(MODEL)/dump_entry$o
+
+infocmp$x: $(DEPS_INFOCMP) $(DEPS_CURSES)
+ @ECHO_LINK@ $(LINK) $(DEPS_INFOCMP) $(LDFLAGS_TIC) -o $@
+
+DEPS_TSET = \
+ $(MODEL)/tset$o \
+ $(MODEL)/transform$o
+
+tset$x: $(DEPS_TSET) $(DEPS_CURSES) transform.h
+ @ECHO_LINK@ $(LINK) $(DEPS_TSET) $(LDFLAGS_TINFO) -o $@
+
+termsort.c: $(srcdir)/MKtermsort.sh
+ sh $(srcdir)/MKtermsort.sh $(AWK) $(srcdir)/../include/@TERMINFO_CAPS@ >$@
+
+#
+# Utility productions start here
+#
+
+tags:
+ $(CTAGS) *.[ch]
+
+@MAKE_UPPER_TAGS@TAGS:
+@MAKE_UPPER_TAGS@ $(ETAGS) *.[ch]
+
+mostlyclean ::
+ -rm -f core tags TAGS *~ *.bak *.i *.ln *.atac trace
+
+clean :: mostlyclean
+ -sh -c "if test -n '$x' ; then $(MAKE) clean x=''; fi"
+ -rm -f $(AUTO_SRC)
+ -rm -f $(PROGS)
+ -rm -rf .libs
+
+distclean :: clean
+ -rm -f Makefile
+
+realclean :: distclean
+
+# These rules are used to allow "make -n" to work on a clean directory-tree
+../include/hashsize.h \
+../include/parametrized.h \
+../include/term.h :
+ cd ../include; $(MAKE) $(CF_MFLAGS)
+$(DEPS_CURSES) :
+ cd ../ncurses; $(MAKE) $(CF_MFLAGS)
+
+lint:
+@MAKE_TERMINFO@ $(LINT) $(LINT_OPTS) $(CPPFLAGS) $(srcdir)/tic.c $(srcdir)/dump_entry.c $(LINT_LIBS)
+@MAKE_TERMINFO@ $(LINT) $(LINT_OPTS) $(CPPFLAGS) $(srcdir)/toe.c $(srcdir)/dump_entry.c $(LINT_LIBS)
+ $(LINT) $(LINT_OPTS) $(CPPFLAGS) $(srcdir)/clear.c $(LINT_LIBS)
+ $(LINT) $(LINT_OPTS) $(CPPFLAGS) $(srcdir)/infocmp.c $(srcdir)/dump_entry.c $(LINT_LIBS)
+ $(LINT) $(LINT_OPTS) $(CPPFLAGS) $(srcdir)/tabs.c $(LINT_LIBS)
+ $(LINT) $(LINT_OPTS) $(CPPFLAGS) $(srcdir)/tput.c $(LINT_LIBS)
+ $(LINT) $(LINT_OPTS) $(CPPFLAGS) $(srcdir)/tset.c $(srcdir)/dump_entry.c $(LINT_LIBS)
+
+###############################################################################
+# The remainder of this file is automatically generated during configuration
+###############################################################################
diff --git a/progs/capconvert b/progs/capconvert
new file mode 100755
index 0000000..8199bbf
--- /dev/null
+++ b/progs/capconvert
@@ -0,0 +1,256 @@
+#!/bin/sh
+##############################################################################
+# Copyright (c) 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 "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: capconvert,v 1.4 2006/04/22 21:46:17 tom Exp $
+#
+# capconvert -- automated conversion from termcap to terminfo
+#
+
+echo "This script tries to automatically set you up so that your applications"
+echo "that now use termcap can use terminfo and the ncurses library."
+echo ""
+
+# Note, except for telling if we're running under xterm we don't use TERM at
+# all. This is because BSD users not infrequently have multiple termtypes
+# selected by conditionals in tset -- unless they're xterm users, in which
+# case they're on a workstation and probably don't.
+
+# Check to make sure TERMINFO is not already defined
+if test -n "$TERMINFO"
+then
+ echo "TERMINFO is already defined in your environment. This means"
+ echo "you already have a local terminfo tree, so you do not need any"
+ echo "conversion."
+ if test ! -d $TERMINFO ; then
+ echo "Caution: TERMINFO does not point to a directory!"
+ fi
+ exit;
+fi
+
+# Check to see if terminfo is present in one of the standard locations.
+terminfo=no
+for p in $TERMINFO \
+ /usr/lib/terminfo \
+ /usr/share/lib/terminfo \
+ /usr/share/terminfo \
+ /usr/local/lib/terminfo \
+ /usr/local/share/terminfo
+do
+ if test -d $p ; then
+ terminfo=yes
+ break
+ fi
+done
+
+if test $terminfo = yes
+then
+ echo "Your system already has a system-wide terminfo tree."
+ echo ""
+ if test -z "$TERMCAP"
+ then
+ echo "You have no TERMCAP variable set, so we are done."
+ # Assumes the terminfo master covers all canned terminal types
+ exit;
+ fi
+ if test "$TERM" = "xterm"
+ then
+ echo "You are running xterm, which usually sets TERMCAP itself."
+ echo "We can ignore this, because terminfo knows about xterm."
+ echo "So you will just use the system-wide terminfo tree."
+ exit;
+ else
+ echo "We will have to make a local one for you anyway, to capture the effect"
+ echo "of your TERMCAP variable."
+ fi
+else
+ echo "No system-wide terminfo tree. We will make you a local one."
+fi
+echo "";
+
+# Check if test -x works (it's not portable, but useful)
+OPT="-x"
+TMP=test$$; touch $TMP && chmod 755 $TMP
+if test $OPT $TMP ; then
+ chmod 644 $TMP
+ test $OPT $TMP && OPT="-f"
+else
+ OPT="-f"
+fi
+rm -f $TMP
+
+# First step -- go find tic
+TIC=
+IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}:"
+for x in $PATH .
+do
+ if test $OPT $x/tic
+ then
+ TIC=$x/tic
+ break
+ fi
+done
+IFS="$ac_save_ifs"
+
+if test -n "$TIC"
+then
+ echo "I see tic at $TIC."
+ case $TIC in # (vi
+ ./tic)
+ if test $OPT ../misc/shlib ; then
+ TIC="../misc/shlib $TIC"
+ fi
+ ;;
+ esac
+else
+ echo "You do not have tic installed anywhere I can see, please fix that."
+ exit;
+fi
+echo "";
+
+# We have tic. Either there's no system terminfo tree or there is one but
+# the user has a TERMCAP variable that may modify a stock description.
+#
+
+# Make the user a terminfo directory
+if test -d $HOME/.terminfo
+then
+ echo "It appears you already have a private terminfo directory"
+ echo "at $HOME/.terminfo; this seems odd, because TERMINFO"
+ echo "is not defined. I am not going to second-guess this -- if you"
+ echo "really want me to try auto-configuring for you, remove or"
+ echo "rename $HOME/terminfo and run me again."
+ exit;
+else
+ echo "I am creating your private terminfo directory at $HOME/.terminfo"
+ mkdir $HOME/.terminfo
+ # Ensure that that's where tic's compilation results.
+ # This isn't strictly necessary with a 1.9.7 or later tic.
+ TERMINFO="$HOME/.terminfo"; export TERMINFO
+fi
+echo "";
+
+# Find a terminfo source to work from
+if test -f ../misc/terminfo.src
+then
+ echo "I see the terminfo master source is handy; I will use that."
+ master=../misc/terminfo.src
+else
+ # Ooops...looks like we're running from somewhere other than the
+ # progs directory of an ncurses source tree.
+ master=`find $HOME -name "*terminfo.src" -print`
+ mcount=`echo $master | wc -l`
+ case $mcount in
+ 0)
+ echo "I can not find a terminfo source file anywhere under your home directory."
+ echo "There should be a file called terminfo.src somewhere in your"
+ echo "ncurses distribution; please put it in your home directotry"
+ echo "and run me again (it does not have to live there permanently)."
+ exit;
+ ;;
+ 1)
+ echo "I see a file called $master."
+ echo "I am going to assume this is the terminfo source included with"
+ echo "the ncurses distribution. If this assumption is wrong, please"
+ echo "interrupt me now! OK to continue?"
+ read ans;
+ ;;
+ 2)
+ echo "I see more than one possible terminfo source. Here they are:"
+ echo $master | sed "/^/s// /";
+ while :
+ do
+ echo "Please tell me which one to use:"
+ read master;
+ if test -f $master
+ then
+ break
+ else
+ echo "That file does not exist. Try again?";
+ fi
+ done
+ ;;
+ esac
+fi
+echo "";
+
+# Now that we have a master, compile it into the local tree
+echo "OK, now I will make your private terminfo tree. This may take a bit..."
+#
+# Kluge alert: we compile terminfo.src in two pieces because a lot of machines
+# with < 16MB RAM choke on tic's core-hog habits.
+trap "rm -f tsplit$$.*" 0 1 2 5 15
+sed -n $master \
+ -e '1,/SPLIT HERE/w 'tsplit$$.01 \
+ -e '/SPLIT HERE/,$w 'tsplit$$.02 \
+ 2>/dev/null
+for x in tsplit$$.*; do eval $TIC $x; done
+rm tsplit$$.*
+trap 0 1 2 5 15
+#
+echo "You now have a private tree under $HOME/.terminfo;"
+echo "the ncurses library will automatically read from it,"
+echo "and ncurses tic will automatically compile entries to it."
+
+# We're done unless user has a .termcap file or equivalent named by TERMCAP
+if test -z "$TERMCAP"
+then
+ echo "You have no TERMCAP set, so we are done."
+fi
+
+# OK, here comes the nasty case...user has a TERMCAP. Instead of
+# trying to follow all the convolutions of the relationship between
+# TERM and TERMCAP (partly because it's too painful, and partly because
+# we don't actually know what TERM will be nor even if it always has
+# the same value for this user) we do the following three steps...
+
+if test -f $HOME/.termcap
+then
+ echo 'I see you have a $HOME/.termcap file. I will compile that.'
+ eval $TIC $HOME/.termcap
+ echo "Done."
+ echo "Note that editing $HOME/.termcap will no longer change the data curses sees."
+elif test -f "$TERMCAP"
+then
+ echo "Your TERMCAP names the file $TERMCAP. I will compile that."
+ eval $TIC $TERMCAP
+ echo "Done."
+ echo "Note that editing $TERMCAP will no longer change the data curses sees."
+else
+ echo "Your TERMCAP value appears to be an entry in termcap format."
+ echo "I will compile it."
+ echo $TERMCAP >myterm$$
+ eval $TIC myterm$$
+ rm myterm$$
+ echo "Done."
+ echo "Note that editing TERMCAP will no longer change the data curses sees."
+fi
+echo "To do that, decompile the terminal decription you want with infocmp(1),"
+echo "edit to taste, and recompile using tic(1)."
+
+# capconvert ends here
+
diff --git a/progs/clear.c b/progs/clear.c
new file mode 100644
index 0000000..9f5a543
--- /dev/null
+++ b/progs/clear.c
@@ -0,0 +1,59 @@
+/****************************************************************************
+ * Copyright (c) 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"), 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: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 *
+ * and: Eric S. Raymond <esr@snark.thyrsus.com> *
+ * and: Thomas E. Dickey 1996-on *
+ ****************************************************************************/
+
+/*
+ * clear.c -- clears the terminal's screen
+ */
+
+#define USE_LIBTINFO
+#include <progs.priv.h>
+
+MODULE_ID("$Id: clear.c,v 1.11 2007/10/13 22:16:02 tom Exp $")
+
+static int
+putch(int c)
+{
+ return putchar(c);
+}
+
+int
+main(
+ int argc GCC_UNUSED,
+ char *argv[]GCC_UNUSED)
+{
+ setupterm((char *) 0, STDOUT_FILENO, (int *) 0);
+ ExitProgram((tputs(clear_screen, lines > 0 ? lines : 1, putch) == ERR)
+ ? EXIT_FAILURE
+ : EXIT_SUCCESS);
+}
diff --git a/progs/clear.sh b/progs/clear.sh
new file mode 100755
index 0000000..f26112b
--- /dev/null
+++ b/progs/clear.sh
@@ -0,0 +1,29 @@
+#!/bin/sh
+##############################################################################
+# Copyright (c) 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 "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. #
+##############################################################################
+exec tput clear
diff --git a/progs/dump_entry.c b/progs/dump_entry.c
new file mode 100644
index 0000000..485bbbd
--- /dev/null
+++ b/progs/dump_entry.c
@@ -0,0 +1,1273 @@
+/****************************************************************************
+ * Copyright (c) 1998-2008,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: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 *
+ * and: Eric S. Raymond <esr@snark.thyrsus.com> *
+ * and: Thomas E. Dickey 1996 on *
+ ****************************************************************************/
+
+#define __INTERNAL_CAPS_VISIBLE
+#include <progs.priv.h>
+
+#include "dump_entry.h"
+#include "termsort.c" /* this C file is generated */
+#include <parametrized.h> /* so is this */
+
+MODULE_ID("$Id: dump_entry.c,v 1.89 2010/05/01 22:04:08 tom Exp $")
+
+#define INDENT 8
+#define DISCARD(string) string = ABSENT_STRING
+#define PRINTF (void) printf
+
+#define OkIndex(index,array) ((int)(index) >= 0 && (int)(index) < (int) SIZEOF(array))
+
+typedef struct {
+ char *text;
+ size_t used;
+ size_t size;
+} DYNBUF;
+
+static int tversion; /* terminfo version */
+static int outform; /* output format to use */
+static int sortmode; /* sort mode to use */
+static int width = 60; /* max line width for listings */
+static int column; /* current column, limited by 'width' */
+static int oldcol; /* last value of column before wrap */
+static bool pretty; /* true if we format if-then-else strings */
+
+static char *save_sgr;
+
+static DYNBUF outbuf;
+static DYNBUF tmpbuf;
+
+/* indirection pointers for implementing sort and display modes */
+static const PredIdx *bool_indirect, *num_indirect, *str_indirect;
+static NCURSES_CONST char *const *bool_names;
+static NCURSES_CONST char *const *num_names;
+static NCURSES_CONST char *const *str_names;
+
+static const char *separator, *trailer;
+
+/* cover various ports and variants of terminfo */
+#define V_ALLCAPS 0 /* all capabilities (SVr4, XSI, ncurses) */
+#define V_SVR1 1 /* SVR1, Ultrix */
+#define V_HPUX 2 /* HP/UX */
+#define V_AIX 3 /* AIX */
+#define V_BSD 4 /* BSD */
+
+#if NCURSES_XNAMES
+#define OBSOLETE(n) (!_nc_user_definable && (n[0] == 'O' && n[1] == 'T'))
+#else
+#define OBSOLETE(n) (n[0] == 'O' && n[1] == 'T')
+#endif
+
+#define isObsolete(f,n) ((f == F_TERMINFO || f == F_VARIABLE) && OBSOLETE(n))
+
+#if NCURSES_XNAMES
+#define BoolIndirect(j) ((j >= BOOLCOUNT) ? (j) : ((sortmode == S_NOSORT) ? j : bool_indirect[j]))
+#define NumIndirect(j) ((j >= NUMCOUNT) ? (j) : ((sortmode == S_NOSORT) ? j : num_indirect[j]))
+#define StrIndirect(j) ((j >= STRCOUNT) ? (j) : ((sortmode == S_NOSORT) ? j : str_indirect[j]))
+#else
+#define BoolIndirect(j) ((sortmode == S_NOSORT) ? (j) : bool_indirect[j])
+#define NumIndirect(j) ((sortmode == S_NOSORT) ? (j) : num_indirect[j])
+#define StrIndirect(j) ((sortmode == S_NOSORT) ? (j) : str_indirect[j])
+#endif
+
+static void
+strncpy_DYN(DYNBUF * dst, const char *src, size_t need)
+{
+ size_t want = need + dst->used + 1;
+ if (want > dst->size) {
+ dst->size += (want + 1024); /* be generous */
+ dst->text = typeRealloc(char, dst->size, dst->text);
+ }
+ (void) strncpy(dst->text + dst->used, src, need);
+ dst->used += need;
+ dst->text[dst->used] = 0;
+}
+
+static void
+strcpy_DYN(DYNBUF * dst, const char *src)
+{
+ if (src == 0) {
+ dst->used = 0;
+ strcpy_DYN(dst, "");
+ } else {
+ strncpy_DYN(dst, src, strlen(src));
+ }
+}
+
+#if NO_LEAKS
+static void
+free_DYN(DYNBUF * p)
+{
+ if (p->text != 0)
+ free(p->text);
+ p->text = 0;
+ p->size = 0;
+ p->used = 0;
+}
+
+void
+_nc_leaks_dump_entry(void)
+{
+ free_DYN(&outbuf);
+ free_DYN(&tmpbuf);
+}
+#endif
+
+#define NameTrans(check,result) \
+ if (OkIndex(np->nte_index, check) \
+ && check[np->nte_index]) \
+ return (result[np->nte_index])
+
+NCURSES_CONST char *
+nametrans(const char *name)
+/* translate a capability name from termcap to terminfo */
+{
+ const struct name_table_entry *np;
+
+ if ((np = _nc_find_entry(name, _nc_get_hash_table(0))) != 0)
+ switch (np->nte_type) {
+ case BOOLEAN:
+ NameTrans(bool_from_termcap, boolcodes);
+ break;
+
+ case NUMBER:
+ NameTrans(num_from_termcap, numcodes);
+ break;
+
+ case STRING:
+ NameTrans(str_from_termcap, strcodes);
+ break;
+ }
+
+ return (0);
+}
+
+void
+dump_init(const char *version, int mode, int sort, int twidth, int traceval,
+ bool formatted)
+/* set up for entry display */
+{
+ width = twidth;
+ pretty = formatted;
+
+ /* versions */
+ if (version == 0)
+ tversion = V_ALLCAPS;
+ else if (!strcmp(version, "SVr1") || !strcmp(version, "SVR1")
+ || !strcmp(version, "Ultrix"))
+ tversion = V_SVR1;
+ else if (!strcmp(version, "HP"))
+ tversion = V_HPUX;
+ else if (!strcmp(version, "AIX"))
+ tversion = V_AIX;
+ else if (!strcmp(version, "BSD"))
+ tversion = V_BSD;
+ else
+ tversion = V_ALLCAPS;
+
+ /* implement display modes */
+ switch (outform = mode) {
+ case F_LITERAL:
+ case F_TERMINFO:
+ bool_names = boolnames;
+ num_names = numnames;
+ str_names = strnames;
+ separator = twidth ? ", " : ",";
+ trailer = "\n\t";
+ break;
+
+ case F_VARIABLE:
+ bool_names = boolfnames;
+ num_names = numfnames;
+ str_names = strfnames;
+ separator = twidth ? ", " : ",";
+ trailer = "\n\t";
+ break;
+
+ case F_TERMCAP:
+ case F_TCONVERR:
+ bool_names = boolcodes;
+ num_names = numcodes;
+ str_names = strcodes;
+ separator = ":";
+ trailer = "\\\n\t:";
+ break;
+ }
+
+ /* implement sort modes */
+ switch (sortmode = sort) {
+ case S_NOSORT:
+ if (traceval)
+ (void) fprintf(stderr,
+ "%s: sorting by term structure order\n", _nc_progname);
+ break;
+
+ case S_TERMINFO:
+ if (traceval)
+ (void) fprintf(stderr,
+ "%s: sorting by terminfo name order\n", _nc_progname);
+ bool_indirect = bool_terminfo_sort;
+ num_indirect = num_terminfo_sort;
+ str_indirect = str_terminfo_sort;
+ break;
+
+ case S_VARIABLE:
+ if (traceval)
+ (void) fprintf(stderr,
+ "%s: sorting by C variable order\n", _nc_progname);
+ bool_indirect = bool_variable_sort;
+ num_indirect = num_variable_sort;
+ str_indirect = str_variable_sort;
+ break;
+
+ case S_TERMCAP:
+ if (traceval)
+ (void) fprintf(stderr,
+ "%s: sorting by termcap name order\n", _nc_progname);
+ bool_indirect = bool_termcap_sort;
+ num_indirect = num_termcap_sort;
+ str_indirect = str_termcap_sort;
+ break;
+ }
+
+ if (traceval)
+ (void) fprintf(stderr,
+ "%s: width = %d, tversion = %d, outform = %d\n",
+ _nc_progname, width, tversion, outform);
+}
+
+static TERMTYPE *cur_type;
+
+static int
+dump_predicate(PredType type, PredIdx idx)
+/* predicate function to use for ordinary decompilation */
+{
+ switch (type) {
+ case BOOLEAN:
+ return (cur_type->Booleans[idx] == FALSE)
+ ? FAIL : cur_type->Booleans[idx];
+
+ case NUMBER:
+ return (cur_type->Numbers[idx] == ABSENT_NUMERIC)
+ ? FAIL : cur_type->Numbers[idx];
+
+ case STRING:
+ return (cur_type->Strings[idx] != ABSENT_STRING)
+ ? (int) TRUE : FAIL;
+ }
+
+ return (FALSE); /* pacify compiler */
+}
+
+static void set_obsolete_termcaps(TERMTYPE *tp);
+
+/* is this the index of a function key string? */
+#define FNKEY(i) (((i)<= 65 && (i)>= 75) || ((i)<= 216 && (i)>= 268))
+
+/*
+ * If we configure with a different Caps file, the offsets into the arrays
+ * will change. So we use an address expression.
+ */
+#define BOOL_IDX(name) (PredType) (&(name) - &(CUR Booleans[0]))
+#define NUM_IDX(name) (PredType) (&(name) - &(CUR Numbers[0]))
+#define STR_IDX(name) (PredType) (&(name) - &(CUR Strings[0]))
+
+static bool
+version_filter(PredType type, PredIdx idx)
+/* filter out capabilities we may want to suppress */
+{
+ switch (tversion) {
+ case V_ALLCAPS: /* SVr4, XSI Curses */
+ return (TRUE);
+
+ case V_SVR1: /* System V Release 1, Ultrix */
+ switch (type) {
+ case BOOLEAN:
+ return ((idx <= BOOL_IDX(xon_xoff)) ? TRUE : FALSE);
+ case NUMBER:
+ return ((idx <= NUM_IDX(width_status_line)) ? TRUE : FALSE);
+ case STRING:
+ return ((idx <= STR_IDX(prtr_non)) ? TRUE : FALSE);
+ }
+ break;
+
+ case V_HPUX: /* Hewlett-Packard */
+ switch (type) {
+ case BOOLEAN:
+ return ((idx <= BOOL_IDX(xon_xoff)) ? TRUE : FALSE);
+ case NUMBER:
+ return ((idx <= NUM_IDX(label_width)) ? TRUE : FALSE);
+ case STRING:
+ if (idx <= STR_IDX(prtr_non))
+ return (TRUE);
+ else if (FNKEY(idx)) /* function keys */
+ return (TRUE);
+ else if (idx == STR_IDX(plab_norm)
+ || idx == STR_IDX(label_on)
+ || idx == STR_IDX(label_off))
+ return (TRUE);
+ else
+ return (FALSE);
+ }
+ break;
+
+ case V_AIX: /* AIX */
+ switch (type) {
+ case BOOLEAN:
+ return ((idx <= BOOL_IDX(xon_xoff)) ? TRUE : FALSE);
+ case NUMBER:
+ return ((idx <= NUM_IDX(width_status_line)) ? TRUE : FALSE);
+ case STRING:
+ if (idx <= STR_IDX(prtr_non))
+ return (TRUE);
+ else if (FNKEY(idx)) /* function keys */
+ return (TRUE);
+ else
+ return (FALSE);
+ }
+ break;
+
+#define is_termcap(type) (OkIndex(idx, type##_from_termcap) && \
+ type##_from_termcap[idx])
+
+ case V_BSD: /* BSD */
+ switch (type) {
+ case BOOLEAN:
+ return is_termcap(bool);
+ case NUMBER:
+ return is_termcap(num);
+ case STRING:
+ return is_termcap(str);
+ }
+ break;
+ }
+
+ return (FALSE); /* pacify the compiler */
+}
+
+static void
+trim_trailing(void)
+{
+ while (outbuf.used > 0 && outbuf.text[outbuf.used - 1] == ' ')
+ outbuf.text[--outbuf.used] = '\0';
+}
+
+static void
+force_wrap(void)
+{
+ oldcol = column;
+ trim_trailing();
+ strcpy_DYN(&outbuf, trailer);
+ column = INDENT;
+}
+
+static void
+wrap_concat(const char *src)
+{
+ unsigned need = strlen(src);
+ unsigned want = strlen(separator) + need;
+
+ if (column > INDENT
+ && column + (int) want > width) {
+ force_wrap();
+ }
+ strcpy_DYN(&outbuf, src);
+ strcpy_DYN(&outbuf, separator);
+ column += (int) need;
+}
+
+#define IGNORE_SEP_TRAIL(first,last,sep_trail) \
+ if ((size_t)(last - first) > sizeof(sep_trail)-1 \
+ && !strncmp(first, sep_trail, sizeof(sep_trail)-1)) \
+ first += sizeof(sep_trail)-2
+
+/* Returns the nominal length of the buffer assuming it is termcap format,
+ * i.e., the continuation sequence is treated as a single character ":".
+ *
+ * There are several implementations of termcap which read the text into a
+ * fixed-size buffer. Generally they strip the newlines from the text, but may
+ * not do it until after the buffer is read. Also, "tc=" resolution may be
+ * expanded in the same buffer. This function is useful for measuring the size
+ * of the best fixed-buffer implementation; the worst case may be much worse.
+ */
+#ifdef TEST_TERMCAP_LENGTH
+static int
+termcap_length(const char *src)
+{
+ static const char pattern[] = ":\\\n\t:";
+
+ int len = 0;
+ const char *const t = src + strlen(src);
+
+ while (*src != '\0') {
+ IGNORE_SEP_TRAIL(src, t, pattern);
+ src++;
+ len++;
+ }
+ return len;
+}
+#else
+#define termcap_length(src) strlen(src)
+#endif
+
+static void
+indent_DYN(DYNBUF * buffer, int level)
+{
+ int n;
+
+ for (n = 0; n < level; n++)
+ strncpy_DYN(buffer, "\t", 1);
+}
+
+static bool
+has_params(const char *src)
+{
+ bool result = FALSE;
+ int len = (int) strlen(src);
+ int n;
+ bool ifthen = FALSE;
+ bool params = FALSE;
+
+ for (n = 0; n < len - 1; ++n) {
+ if (!strncmp(src + n, "%p", 2)) {
+ params = TRUE;
+ } else if (!strncmp(src + n, "%;", 2)) {
+ ifthen = TRUE;
+ result = params;
+ break;
+ }
+ }
+ if (!ifthen) {
+ result = ((len > 50) && params);
+ }
+ return result;
+}
+
+static char *
+fmt_complex(char *src, int level)
+{
+ bool percent = FALSE;
+ bool params = has_params(src);
+
+ while (*src != '\0') {
+ switch (*src) {
+ case '\\':
+ percent = FALSE;
+ strncpy_DYN(&tmpbuf, src++, 1);
+ break;
+ case '%':
+ percent = TRUE;
+ break;
+ case '?': /* "if" */
+ case 't': /* "then" */
+ case 'e': /* "else" */
+ if (percent) {
+ percent = FALSE;
+ tmpbuf.text[tmpbuf.used - 1] = '\n';
+ /* treat a "%e" as else-if, on the same level */
+ if (*src == 'e') {
+ indent_DYN(&tmpbuf, level);
+ strncpy_DYN(&tmpbuf, "%", 1);
+ strncpy_DYN(&tmpbuf, src, 1);
+ src++;
+ params = has_params(src);
+ if (!params && *src != '\0' && *src != '%') {
+ strncpy_DYN(&tmpbuf, "\n", 1);
+ indent_DYN(&tmpbuf, level + 1);
+ }
+ } else {
+ indent_DYN(&tmpbuf, level + 1);
+ strncpy_DYN(&tmpbuf, "%", 1);
+ strncpy_DYN(&tmpbuf, src, 1);
+ if (*src++ == '?') {
+ src = fmt_complex(src, level + 1);
+ if (*src != '\0' && *src != '%') {
+ strncpy_DYN(&tmpbuf, "\n", 1);
+ indent_DYN(&tmpbuf, level + 1);
+ }
+ } else if (level == 1) {
+ _nc_warning("%%%c without %%?", *src);
+ }
+ }
+ continue;
+ }
+ break;
+ case ';': /* "endif" */
+ if (percent) {
+ percent = FALSE;
+ if (level > 1) {
+ tmpbuf.text[tmpbuf.used - 1] = '\n';
+ indent_DYN(&tmpbuf, level);
+ strncpy_DYN(&tmpbuf, "%", 1);
+ strncpy_DYN(&tmpbuf, src++, 1);
+ return src;
+ }
+ _nc_warning("%%; without %%?");
+ }
+ break;
+ case 'p':
+ if (percent && params) {
+ tmpbuf.text[tmpbuf.used - 1] = '\n';
+ indent_DYN(&tmpbuf, level + 1);
+ strncpy_DYN(&tmpbuf, "%", 1);
+ }
+ params = FALSE;
+ percent = FALSE;
+ break;
+ case ' ':
+ strncpy_DYN(&tmpbuf, "\\s", 2);
+ ++src;
+ continue;
+ default:
+ percent = FALSE;
+ break;
+ }
+ strncpy_DYN(&tmpbuf, src++, 1);
+ }
+ return src;
+}
+
+#define SAME_CAP(n,cap) (&tterm->Strings[n] == &cap)
+#define EXTRA_CAP 20
+
+int
+fmt_entry(TERMTYPE *tterm,
+ PredFunc pred,
+ bool content_only,
+ bool suppress_untranslatable,
+ bool infodump,
+ int numbers)
+{
+ PredIdx i, j;
+ char buffer[MAX_TERMINFO_LENGTH + EXTRA_CAP];
+ char *capability;
+ NCURSES_CONST char *name;
+ int predval, len;
+ PredIdx num_bools = 0;
+ PredIdx num_values = 0;
+ PredIdx num_strings = 0;
+ bool outcount = 0;
+
+#define WRAP_CONCAT \
+ wrap_concat(buffer); \
+ outcount = TRUE
+
+ len = 12; /* terminfo file-header */
+
+ if (pred == 0) {
+ cur_type = tterm;
+ pred = dump_predicate;
+ }
+
+ strcpy_DYN(&outbuf, 0);
+ if (content_only) {
+ column = INDENT; /* FIXME: workaround to prevent empty lines */
+ } else {
+ strcpy_DYN(&outbuf, tterm->term_names);
+ strcpy_DYN(&outbuf, separator);
+ column = (int) outbuf.used;
+ force_wrap();
+ }
+
+ for_each_boolean(j, tterm) {
+ i = BoolIndirect(j);
+ name = ExtBoolname(tterm, i, bool_names);
+ assert(strlen(name) < sizeof(buffer) - EXTRA_CAP);
+
+ if (!version_filter(BOOLEAN, i))
+ continue;
+ else if (isObsolete(outform, name))
+ continue;
+
+ predval = pred(BOOLEAN, i);
+ if (predval != FAIL) {
+ (void) strcpy(buffer, name);
+ if (predval <= 0)
+ (void) strcat(buffer, "@");
+ else if (i + 1 > num_bools)
+ num_bools = i + 1;
+ WRAP_CONCAT;
+ }
+ }
+
+ if (column != INDENT)
+ force_wrap();
+
+ for_each_number(j, tterm) {
+ i = NumIndirect(j);
+ name = ExtNumname(tterm, i, num_names);
+ assert(strlen(name) < sizeof(buffer) - EXTRA_CAP);
+
+ if (!version_filter(NUMBER, i))
+ continue;
+ else if (isObsolete(outform, name))
+ continue;
+
+ predval = pred(NUMBER, i);
+ if (predval != FAIL) {
+ if (tterm->Numbers[i] < 0) {
+ sprintf(buffer, "%s@", name);
+ } else {
+ sprintf(buffer, "%s#%d", name, tterm->Numbers[i]);
+ if (i + 1 > num_values)
+ num_values = i + 1;
+ }
+ WRAP_CONCAT;
+ }
+ }
+
+ if (column != INDENT)
+ force_wrap();
+
+ len += (int) (num_bools
+ + num_values * 2
+ + strlen(tterm->term_names) + 1);
+ if (len & 1)
+ len++;
+
+#undef CUR
+#define CUR tterm->
+ if (outform == F_TERMCAP) {
+ if (termcap_reset != ABSENT_STRING) {
+ if (init_3string != ABSENT_STRING
+ && !strcmp(init_3string, termcap_reset))
+ DISCARD(init_3string);
+
+ if (reset_2string != ABSENT_STRING
+ && !strcmp(reset_2string, termcap_reset))
+ DISCARD(reset_2string);
+ }
+ }
+
+ for_each_string(j, tterm) {
+ i = StrIndirect(j);
+ name = ExtStrname(tterm, i, str_names);
+ assert(strlen(name) < sizeof(buffer) - EXTRA_CAP);
+
+ capability = tterm->Strings[i];
+
+ if (!version_filter(STRING, i))
+ continue;
+ else if (isObsolete(outform, name))
+ continue;
+
+#if NCURSES_XNAMES
+ /*
+ * Extended names can be longer than 2 characters, but termcap programs
+ * cannot read those (filter them out).
+ */
+ if (outform == F_TERMCAP && (strlen(name) > 2))
+ continue;
+#endif
+
+ if (outform == F_TERMCAP) {
+ /*
+ * Some older versions of vi want rmir/smir to be defined
+ * for ich/ich1 to work. If they're not defined, force
+ * them to be output as defined and empty.
+ */
+ if (PRESENT(insert_character) || PRESENT(parm_ich)) {
+ if (SAME_CAP(i, enter_insert_mode)
+ && enter_insert_mode == ABSENT_STRING) {
+ (void) strcpy(buffer, "im=");
+ WRAP_CONCAT;
+ continue;
+ }
+
+ if (SAME_CAP(i, exit_insert_mode)
+ && exit_insert_mode == ABSENT_STRING) {
+ (void) strcpy(buffer, "ei=");
+ WRAP_CONCAT;
+ continue;
+ }
+ }
+ /*
+ * termcap applications such as screen will be confused if sgr0
+ * is translated to a string containing rmacs. Filter that out.
+ */
+ if (PRESENT(exit_attribute_mode)) {
+ if (SAME_CAP(i, exit_attribute_mode)) {
+ char *trimmed_sgr0;
+ char *my_sgr = set_attributes;
+
+ set_attributes = save_sgr;
+
+ trimmed_sgr0 = _nc_trim_sgr0(tterm);
+ if (strcmp(capability, trimmed_sgr0))
+ capability = trimmed_sgr0;
+
+ set_attributes = my_sgr;
+ }
+ }
+ }
+
+ predval = pred(STRING, i);
+ buffer[0] = '\0';
+
+ if (predval != FAIL) {
+ if (capability != ABSENT_STRING
+ && i + 1 > num_strings)
+ num_strings = i + 1;
+
+ if (!VALID_STRING(capability)) {
+ sprintf(buffer, "%s@", name);
+ WRAP_CONCAT;
+ } else if (outform == F_TERMCAP || outform == F_TCONVERR) {
+ int params = ((i < (int) SIZEOF(parametrized))
+ ? parametrized[i]
+ : 0);
+ char *srccap = _nc_tic_expand(capability, TRUE, numbers);
+ char *cv = _nc_infotocap(name, srccap, params);
+
+ if (cv == 0) {
+ if (outform == F_TCONVERR) {
+ sprintf(buffer, "%s=!!! %s WILL NOT CONVERT !!!",
+ name, srccap);
+ } else if (suppress_untranslatable) {
+ continue;
+ } else {
+ char *s = srccap, *d = buffer;
+ sprintf(d, "..%s=", name);
+ d += strlen(d);
+ while ((*d = *s++) != 0) {
+ if (*d == ':') {
+ *d++ = '\\';
+ *d = ':';
+ } else if (*d == '\\') {
+ *++d = *s++;
+ }
+ d++;
+ }
+ }
+ } else {
+ sprintf(buffer, "%s=%s", name, cv);
+ }
+ len += (int) strlen(capability) + 1;
+ WRAP_CONCAT;
+ } else {
+ char *src = _nc_tic_expand(capability,
+ outform == F_TERMINFO, numbers);
+
+ strcpy_DYN(&tmpbuf, 0);
+ strcpy_DYN(&tmpbuf, name);
+ strcpy_DYN(&tmpbuf, "=");
+ if (pretty
+ && (outform == F_TERMINFO
+ || outform == F_VARIABLE)) {
+ fmt_complex(src, 1);
+ } else {
+ strcpy_DYN(&tmpbuf, src);
+ }
+ len += (int) strlen(capability) + 1;
+ wrap_concat(tmpbuf.text);
+ outcount = TRUE;
+ }
+ }
+ /* e.g., trimmed_sgr0 */
+ if (capability != tterm->Strings[i])
+ free(capability);
+ }
+ len += (int) (num_strings * 2);
+
+ /*
+ * This piece of code should be an effective inverse of the functions
+ * postprocess_terminfo() and postprocess_terminfo() in parse_entry.c.
+ * Much more work should be done on this to support dumping termcaps.
+ */
+ if (tversion == V_HPUX) {
+ if (VALID_STRING(memory_lock)) {
+ (void) sprintf(buffer, "meml=%s", memory_lock);
+ WRAP_CONCAT;
+ }
+ if (VALID_STRING(memory_unlock)) {
+ (void) sprintf(buffer, "memu=%s", memory_unlock);
+ WRAP_CONCAT;
+ }
+ } else if (tversion == V_AIX) {
+ if (VALID_STRING(acs_chars)) {
+ bool box_ok = TRUE;
+ const char *acstrans = "lqkxjmwuvtn";
+ const char *cp;
+ char *tp, *sp, boxchars[11];
+
+ tp = boxchars;
+ for (cp = acstrans; *cp; cp++) {
+ sp = strchr(acs_chars, *cp);
+ if (sp)
+ *tp++ = sp[1];
+ else {
+ box_ok = FALSE;
+ break;
+ }
+ }
+ tp[0] = '\0';
+
+ if (box_ok) {
+ (void) strcpy(buffer, "box1=");
+ (void) strcat(buffer, _nc_tic_expand(boxchars,
+ outform == F_TERMINFO, numbers));
+ WRAP_CONCAT;
+ }
+ }
+ }
+
+ /*
+ * kludge: trim off trailer to avoid an extra blank line
+ * in infocmp -u output when there are no string differences
+ */
+ if (outcount) {
+ bool trimmed = FALSE;
+ j = outbuf.used;
+ if (j >= 2
+ && outbuf.text[j - 1] == '\t'
+ && outbuf.text[j - 2] == '\n') {
+ outbuf.used -= 2;
+ trimmed = TRUE;
+ } else if (j >= 4
+ && outbuf.text[j - 1] == ':'
+ && outbuf.text[j - 2] == '\t'
+ && outbuf.text[j - 3] == '\n'
+ && outbuf.text[j - 4] == '\\') {
+ outbuf.used -= 4;
+ trimmed = TRUE;
+ }
+ if (trimmed) {
+ outbuf.text[outbuf.used] = '\0';
+ column = oldcol;
+ strcpy_DYN(&outbuf, " ");
+ }
+ }
+#if 0
+ fprintf(stderr, "num_bools = %d\n", num_bools);
+ fprintf(stderr, "num_values = %d\n", num_values);
+ fprintf(stderr, "num_strings = %d\n", num_strings);
+ fprintf(stderr, "term_names=%s, len=%d, strlen(outbuf)=%d, outbuf=%s\n",
+ tterm->term_names, len, outbuf.used, outbuf.text);
+#endif
+ /*
+ * Here's where we use infodump to trigger a more stringent length check
+ * for termcap-translation purposes.
+ * Return the length of the raw entry, without tc= expansions,
+ * It gives an idea of which entries are deadly to even *scan past*,
+ * as opposed to *use*.
+ */
+ return (infodump ? len : (int) termcap_length(outbuf.text));
+}
+
+static bool
+kill_string(TERMTYPE *tterm, char *cap)
+{
+ unsigned n;
+ for (n = 0; n < NUM_STRINGS(tterm); ++n) {
+ if (cap == tterm->Strings[n]) {
+ tterm->Strings[n] = ABSENT_STRING;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static char *
+find_string(TERMTYPE *tterm, char *name)
+{
+ PredIdx n;
+ for (n = 0; n < NUM_STRINGS(tterm); ++n) {
+ if (version_filter(STRING, n)
+ && !strcmp(name, strnames[n])) {
+ char *cap = tterm->Strings[n];
+ if (VALID_STRING(cap)) {
+ return cap;
+ }
+ break;
+ }
+ }
+ return ABSENT_STRING;
+}
+
+/*
+ * This is used to remove function-key labels from a termcap entry to
+ * make it smaller.
+ */
+static int
+kill_labels(TERMTYPE *tterm, int target)
+{
+ int n;
+ int result = 0;
+ char *cap;
+ char name[10];
+
+ for (n = 0; n <= 10; ++n) {
+ sprintf(name, "lf%d", n);
+ if ((cap = find_string(tterm, name)) != ABSENT_STRING
+ && kill_string(tterm, cap)) {
+ target -= (int) (strlen(cap) + 5);
+ ++result;
+ if (target < 0)
+ break;
+ }
+ }
+ return result;
+}
+
+/*
+ * This is used to remove function-key definitions from a termcap entry to
+ * make it smaller.
+ */
+static int
+kill_fkeys(TERMTYPE *tterm, int target)
+{
+ int n;
+ int result = 0;
+ char *cap;
+ char name[10];
+
+ for (n = 60; n >= 0; --n) {
+ sprintf(name, "kf%d", n);
+ if ((cap = find_string(tterm, name)) != ABSENT_STRING
+ && kill_string(tterm, cap)) {
+ target -= (int) (strlen(cap) + 5);
+ ++result;
+ if (target < 0)
+ break;
+ }
+ }
+ return result;
+}
+
+/*
+ * Check if the given acsc string is a 1-1 mapping, i.e., just-like-vt100.
+ * Also, since this is for termcap, we only care about the line-drawing map.
+ */
+#define isLine(c) (strchr("lmkjtuvwqxn", c) != 0)
+
+static bool
+one_one_mapping(const char *mapping)
+{
+ bool result = TRUE;
+
+ if (mapping != ABSENT_STRING) {
+ int n = 0;
+ while (mapping[n] != '\0') {
+ if (isLine(mapping[n]) &&
+ mapping[n] != mapping[n + 1]) {
+ result = FALSE;
+ break;
+ }
+ n += 2;
+ }
+ }
+ return result;
+}
+
+#define FMT_ENTRY() \
+ fmt_entry(tterm, pred, \
+ 0, \
+ suppress_untranslatable, \
+ infodump, numbers)
+
+#define SHOW_WHY PRINTF
+
+static bool
+purged_acs(TERMTYPE *tterm)
+{
+ bool result = FALSE;
+
+ if (VALID_STRING(acs_chars)) {
+ if (!one_one_mapping(acs_chars)) {
+ enter_alt_charset_mode = ABSENT_STRING;
+ exit_alt_charset_mode = ABSENT_STRING;
+ SHOW_WHY("# (rmacs/smacs removed for consistency)\n");
+ }
+ result = TRUE;
+ }
+ return result;
+}
+
+/*
+ * Dump a single entry.
+ */
+void
+dump_entry(TERMTYPE *tterm,
+ bool suppress_untranslatable,
+ bool limited,
+ int numbers,
+ PredFunc pred)
+{
+ TERMTYPE save_tterm;
+ int len, critlen;
+ const char *legend;
+ bool infodump;
+
+ if (outform == F_TERMCAP || outform == F_TCONVERR) {
+ critlen = MAX_TERMCAP_LENGTH;
+ legend = "older termcap";
+ infodump = FALSE;
+ set_obsolete_termcaps(tterm);
+ } else {
+ critlen = MAX_TERMINFO_LENGTH;
+ legend = "terminfo";
+ infodump = TRUE;
+ }
+
+ save_sgr = set_attributes;
+
+ if ((FMT_ENTRY() > critlen)
+ && limited) {
+
+ save_tterm = *tterm;
+ if (!suppress_untranslatable) {
+ SHOW_WHY("# (untranslatable capabilities removed to fit entry within %d bytes)\n",
+ critlen);
+ suppress_untranslatable = TRUE;
+ }
+ if (FMT_ENTRY() > critlen) {
+ /*
+ * We pick on sgr because it's a nice long string capability that
+ * is really just an optimization hack. Another good candidate is
+ * acsc since it is both long and unused by BSD termcap.
+ */
+ bool changed = FALSE;
+
+#if NCURSES_XNAMES
+ /*
+ * Extended names are most likely function-key definitions. Drop
+ * those first.
+ */
+ unsigned n;
+ for (n = STRCOUNT; n < NUM_STRINGS(tterm); n++) {
+ const char *name = ExtStrname(tterm, n, strnames);
+
+ if (VALID_STRING(tterm->Strings[n])) {
+ set_attributes = ABSENT_STRING;
+ /* we remove long names anyway - only report the short */
+ if (strlen(name) <= 2) {
+ SHOW_WHY("# (%s removed to fit entry within %d bytes)\n",
+ name,
+ critlen);
+ }
+ changed = TRUE;
+ if (FMT_ENTRY() <= critlen)
+ break;
+ }
+ }
+#endif
+ if (VALID_STRING(set_attributes)) {
+ set_attributes = ABSENT_STRING;
+ SHOW_WHY("# (sgr removed to fit entry within %d bytes)\n",
+ critlen);
+ changed = TRUE;
+ }
+ if (!changed || (FMT_ENTRY() > critlen)) {
+ if (purged_acs(tterm)) {
+ acs_chars = ABSENT_STRING;
+ SHOW_WHY("# (acsc removed to fit entry within %d bytes)\n",
+ critlen);
+ changed = TRUE;
+ }
+ }
+ if (!changed || (FMT_ENTRY() > critlen)) {
+ int oldversion = tversion;
+
+ tversion = V_BSD;
+ SHOW_WHY("# (terminfo-only capabilities suppressed to fit entry within %d bytes)\n",
+ critlen);
+
+ len = FMT_ENTRY();
+ if (len > critlen
+ && kill_labels(tterm, len - critlen)) {
+ SHOW_WHY("# (some labels capabilities suppressed to fit entry within %d bytes)\n",
+ critlen);
+ len = FMT_ENTRY();
+ }
+ if (len > critlen
+ && kill_fkeys(tterm, len - critlen)) {
+ SHOW_WHY("# (some function-key capabilities suppressed to fit entry within %d bytes)\n",
+ critlen);
+ len = FMT_ENTRY();
+ }
+ if (len > critlen) {
+ (void) fprintf(stderr,
+ "warning: %s entry is %d bytes long\n",
+ _nc_first_name(tterm->term_names),
+ len);
+ SHOW_WHY("# WARNING: this entry, %d bytes long, may core-dump %s libraries!\n",
+ len, legend);
+ }
+ tversion = oldversion;
+ }
+ set_attributes = save_sgr;
+ *tterm = save_tterm;
+ }
+ } else if (!version_filter(STRING, STR_IDX(acs_chars))) {
+ save_tterm = *tterm;
+ if (purged_acs(tterm)) {
+ (void) FMT_ENTRY();
+ }
+ *tterm = save_tterm;
+ }
+}
+
+void
+dump_uses(const char *name, bool infodump)
+/* dump "use=" clauses in the appropriate format */
+{
+ char buffer[MAX_TERMINFO_LENGTH];
+
+ if (outform == F_TERMCAP || outform == F_TCONVERR)
+ trim_trailing();
+ (void) sprintf(buffer, "%s%s", infodump ? "use=" : "tc=", name);
+ wrap_concat(buffer);
+}
+
+int
+show_entry(void)
+{
+ trim_trailing();
+ (void) fputs(outbuf.text, stdout);
+ putchar('\n');
+ return (int) outbuf.used;
+}
+
+void
+compare_entry(void (*hook) (PredType t, PredIdx i, const char *name),
+ TERMTYPE *tp GCC_UNUSED,
+ bool quiet)
+/* compare two entries */
+{
+ PredIdx i, j;
+ NCURSES_CONST char *name;
+
+ if (!quiet)
+ fputs(" comparing booleans.\n", stdout);
+ for_each_boolean(j, tp) {
+ i = BoolIndirect(j);
+ name = ExtBoolname(tp, i, bool_names);
+
+ if (isObsolete(outform, name))
+ continue;
+
+ (*hook) (CMP_BOOLEAN, i, name);
+ }
+
+ if (!quiet)
+ fputs(" comparing numbers.\n", stdout);
+ for_each_number(j, tp) {
+ i = NumIndirect(j);
+ name = ExtNumname(tp, i, num_names);
+
+ if (isObsolete(outform, name))
+ continue;
+
+ (*hook) (CMP_NUMBER, i, name);
+ }
+
+ if (!quiet)
+ fputs(" comparing strings.\n", stdout);
+ for_each_string(j, tp) {
+ i = StrIndirect(j);
+ name = ExtStrname(tp, i, str_names);
+
+ if (isObsolete(outform, name))
+ continue;
+
+ (*hook) (CMP_STRING, i, name);
+ }
+
+ /* (void) fputs(" comparing use entries.\n", stdout); */
+ (*hook) (CMP_USE, 0, "use");
+
+}
+
+#define NOTSET(s) ((s) == 0)
+
+/*
+ * 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.
+ */
+#undef CUR
+#define CUR tp->
+
+static void
+set_obsolete_termcaps(TERMTYPE *tp)
+{
+#include "capdefaults.c"
+}
+
+/*
+ * Convert an alternate-character-set string to canonical form: sorted and
+ * unique.
+ */
+void
+repair_acsc(TERMTYPE *tp)
+{
+ if (VALID_STRING(acs_chars)) {
+ size_t n, m;
+ char mapped[256];
+ char extra = 0;
+ unsigned source;
+ unsigned target;
+ bool fix_needed = FALSE;
+
+ for (n = 0, source = 0; acs_chars[n] != 0; n++) {
+ target = UChar(acs_chars[n]);
+ if (source >= target) {
+ fix_needed = TRUE;
+ break;
+ }
+ source = target;
+ if (acs_chars[n + 1])
+ n++;
+ }
+ if (fix_needed) {
+ memset(mapped, 0, sizeof(mapped));
+ for (n = 0; acs_chars[n] != 0; n++) {
+ source = UChar(acs_chars[n]);
+ if ((target = (unsigned char) acs_chars[n + 1]) != 0) {
+ mapped[source] = (char) target;
+ n++;
+ } else {
+ extra = (char) source;
+ }
+ }
+ for (n = m = 0; n < sizeof(mapped); n++) {
+ if (mapped[n]) {
+ acs_chars[m++] = (char) n;
+ acs_chars[m++] = mapped[n];
+ }
+ }
+ if (extra)
+ acs_chars[m++] = extra; /* garbage in, garbage out */
+ acs_chars[m] = 0;
+ }
+ }
+}
diff --git a/progs/dump_entry.h b/progs/dump_entry.h
new file mode 100644
index 0000000..b99a37a
--- /dev/null
+++ b/progs/dump_entry.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+ * Copyright (c) 1998-2006,2008 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: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 *
+ * and: Eric S. Raymond <esr@snark.thyrsus.com> *
+ * and: Thomas E. Dickey 1996-on *
+ ****************************************************************************/
+
+
+/*
+ * $Id: dump_entry.h,v 1.30 2008/07/12 20:23:03 tom Exp $
+ *
+ * Dump control definitions and variables
+ */
+
+#ifndef DUMP_ENTRY_H
+#define DUMP_ENTRY_H 1
+
+/* capability output formats */
+#define F_TERMINFO 0 /* use terminfo names */
+#define F_VARIABLE 1 /* use C variable names */
+#define F_TERMCAP 2 /* termcap names with capability conversion */
+#define F_TCONVERR 3 /* as T_TERMCAP, no skip of untranslatables */
+#define F_LITERAL 4 /* like F_TERMINFO, but no smart defaults */
+
+/* capability sort modes */
+#define S_DEFAULT 0 /* sort by terminfo name (implicit) */
+#define S_NOSORT 1 /* don't sort */
+#define S_TERMINFO 2 /* sort by terminfo names (explicit) */
+#define S_VARIABLE 3 /* sort by C variable names */
+#define S_TERMCAP 4 /* sort by termcap names */
+
+/* capability types for the comparison hook */
+#define CMP_BOOLEAN 0 /* comparison on booleans */
+#define CMP_NUMBER 1 /* comparison on numerics */
+#define CMP_STRING 2 /* comparison on strings */
+#define CMP_USE 3 /* comparison on use capabilities */
+
+typedef unsigned PredType;
+typedef unsigned PredIdx;
+typedef int (*PredFunc)(PredType, PredIdx);
+
+extern NCURSES_CONST char *nametrans(const char *);
+extern int fmt_entry(TERMTYPE *, PredFunc, bool, bool, bool, int);
+extern int show_entry(void);
+extern void compare_entry(void (*)(PredType, PredIdx, const char *), TERMTYPE *, bool);
+extern void dump_entry(TERMTYPE *, bool, bool, int, PredFunc);
+extern void dump_init(const char *, int, int, int, int, bool);
+extern void dump_uses(const char *, bool);
+extern void repair_acsc(TERMTYPE * tp);
+
+#define FAIL -1
+
+#endif /* DUMP_ENTRY_H */
diff --git a/progs/infocmp.c b/progs/infocmp.c
new file mode 100644
index 0000000..2af9cb5
--- /dev/null
+++ b/progs/infocmp.c
@@ -0,0 +1,1657 @@
+/****************************************************************************
+ * Copyright (c) 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: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 *
+ * and: Eric S. Raymond <esr@snark.thyrsus.com> *
+ * and: Thomas E. Dickey 1996-on *
+ ****************************************************************************/
+
+/*
+ * infocmp.c -- decompile an entry, or compare two entries
+ * written by Eric S. Raymond
+ * and Thomas E Dickey
+ */
+
+#include <progs.priv.h>
+
+#include <dump_entry.h>
+
+MODULE_ID("$Id: infocmp.c,v 1.105 2010/05/01 22:04:08 tom Exp $")
+
+#define L_CURL "{"
+#define R_CURL "}"
+
+#define MAX_STRING 1024 /* maximum formatted string */
+
+const char *_nc_progname = "infocmp";
+
+typedef char path[PATH_MAX];
+
+/***************************************************************************
+ *
+ * The following control variables, together with the contents of the
+ * terminfo entries, completely determine the actions of the program.
+ *
+ ***************************************************************************/
+
+static ENTRY *entries; /* terminfo entries */
+static int termcount; /* count of terminal entries */
+
+static bool limited = TRUE; /* "-r" option is not set */
+static bool quiet = FALSE;
+static bool literal = FALSE;
+static const char *bool_sep = ":";
+static const char *s_absent = "NULL";
+static const char *s_cancel = "NULL";
+static const char *tversion; /* terminfo version selected */
+static int itrace; /* trace flag for debugging */
+static int mwidth = 60;
+static int numbers = 0; /* format "%'char'" to/from "%{number}" */
+static int outform = F_TERMINFO; /* output format */
+static int sortmode; /* sort_mode */
+
+/* main comparison mode */
+static int compare;
+#define C_DEFAULT 0 /* don't force comparison mode */
+#define C_DIFFERENCE 1 /* list differences between two terminals */
+#define C_COMMON 2 /* list common capabilities */
+#define C_NAND 3 /* list capabilities in neither terminal */
+#define C_USEALL 4 /* generate relative use-form entry */
+static bool ignorepads; /* ignore pad prefixes when diffing */
+
+#if NO_LEAKS
+#undef ExitProgram
+static void ExitProgram(int code) GCC_NORETURN;
+/* prototype is to get gcc to accept the noreturn attribute */
+static void
+ExitProgram(int code)
+{
+ while (termcount-- > 0)
+ _nc_free_termtype(&entries[termcount].tterm);
+ _nc_leaks_dump_entry();
+ free(entries);
+ _nc_free_tic(code);
+}
+#endif
+
+static char *
+canonical_name(char *ptr, char *buf)
+/* extract the terminal type's primary name */
+{
+ char *bp;
+
+ (void) strcpy(buf, ptr);
+ if ((bp = strchr(buf, '|')) != 0)
+ *bp = '\0';
+
+ return (buf);
+}
+
+/***************************************************************************
+ *
+ * Predicates for dump function
+ *
+ ***************************************************************************/
+
+static int
+capcmp(PredIdx idx, const char *s, const char *t)
+/* capability comparison function */
+{
+ if (!VALID_STRING(s) && !VALID_STRING(t))
+ return (s != t);
+ else if (!VALID_STRING(s) || !VALID_STRING(t))
+ return (1);
+
+ if ((idx == acs_chars_index) || !ignorepads)
+ return (strcmp(s, t));
+ else
+ return (_nc_capcmp(s, t));
+}
+
+static int
+use_predicate(unsigned type, PredIdx idx)
+/* predicate function to use for use decompilation */
+{
+ ENTRY *ep;
+
+ switch (type) {
+ case BOOLEAN:
+ {
+ int is_set = FALSE;
+
+ /*
+ * This assumes that multiple use entries are supposed
+ * to contribute the logical or of their boolean capabilities.
+ * This is true if we take the semantics of multiple uses to
+ * be 'each capability gets the first non-default value found
+ * in the sequence of use entries'.
+ *
+ * Note that cancelled or absent booleans are stored as FALSE,
+ * unlike numbers and strings, whose cancelled/absent state is
+ * recorded in the terminfo database.
+ */
+ for (ep = &entries[1]; ep < entries + termcount; ep++)
+ if (ep->tterm.Booleans[idx] == TRUE) {
+ is_set = entries[0].tterm.Booleans[idx];
+ break;
+ }
+ if (is_set != entries[0].tterm.Booleans[idx])
+ return (!is_set);
+ else
+ return (FAIL);
+ }
+
+ case NUMBER:
+ {
+ int value = ABSENT_NUMERIC;
+
+ /*
+ * We take the semantics of multiple uses to be 'each
+ * capability gets the first non-default value found
+ * in the sequence of use entries'.
+ */
+ for (ep = &entries[1]; ep < entries + termcount; ep++)
+ if (VALID_NUMERIC(ep->tterm.Numbers[idx])) {
+ value = ep->tterm.Numbers[idx];
+ break;
+ }
+
+ if (value != entries[0].tterm.Numbers[idx])
+ return (value != ABSENT_NUMERIC);
+ else
+ return (FAIL);
+ }
+
+ case STRING:
+ {
+ char *termstr, *usestr = ABSENT_STRING;
+
+ termstr = entries[0].tterm.Strings[idx];
+
+ /*
+ * We take the semantics of multiple uses to be 'each
+ * capability gets the first non-default value found
+ * in the sequence of use entries'.
+ */
+ for (ep = &entries[1]; ep < entries + termcount; ep++)
+ if (ep->tterm.Strings[idx]) {
+ usestr = ep->tterm.Strings[idx];
+ break;
+ }
+
+ if (usestr == ABSENT_STRING && termstr == ABSENT_STRING)
+ return (FAIL);
+ else if (!usestr || !termstr || capcmp(idx, usestr, termstr))
+ return (TRUE);
+ else
+ return (FAIL);
+ }
+ }
+
+ return (FALSE); /* pacify compiler */
+}
+
+static bool
+useeq(ENTRY * e1, ENTRY * e2)
+/* are the use references in two entries equivalent? */
+{
+ unsigned i, j;
+
+ if (e1->nuses != e2->nuses)
+ return (FALSE);
+
+ /* Ugh...this is quadratic again */
+ for (i = 0; i < e1->nuses; i++) {
+ bool foundmatch = FALSE;
+
+ /* search second entry for given use reference */
+ for (j = 0; j < e2->nuses; j++)
+ if (!strcmp(e1->uses[i].name, e2->uses[j].name)) {
+ foundmatch = TRUE;
+ break;
+ }
+
+ if (!foundmatch)
+ return (FALSE);
+ }
+
+ return (TRUE);
+}
+
+static bool
+entryeq(TERMTYPE *t1, TERMTYPE *t2)
+/* are two entries equivalent? */
+{
+ unsigned i;
+
+ for (i = 0; i < NUM_BOOLEANS(t1); i++)
+ if (t1->Booleans[i] != t2->Booleans[i])
+ return (FALSE);
+
+ for (i = 0; i < NUM_NUMBERS(t1); i++)
+ if (t1->Numbers[i] != t2->Numbers[i])
+ return (FALSE);
+
+ for (i = 0; i < NUM_STRINGS(t1); i++)
+ if (capcmp((PredIdx) i, t1->Strings[i], t2->Strings[i]))
+ return (FALSE);
+
+ return (TRUE);
+}
+
+#define TIC_EXPAND(result) _nc_tic_expand(result, outform==F_TERMINFO, numbers)
+
+static void
+print_uses(ENTRY * ep, FILE *fp)
+/* print an entry's use references */
+{
+ unsigned i;
+
+ if (!ep->nuses)
+ fputs("NULL", fp);
+ else
+ for (i = 0; i < ep->nuses; i++) {
+ fputs(ep->uses[i].name, fp);
+ if (i < ep->nuses - 1)
+ fputs(" ", fp);
+ }
+}
+
+static const char *
+dump_boolean(int val)
+/* display the value of a boolean capability */
+{
+ switch (val) {
+ case ABSENT_BOOLEAN:
+ return (s_absent);
+ case CANCELLED_BOOLEAN:
+ return (s_cancel);
+ case FALSE:
+ return ("F");
+ case TRUE:
+ return ("T");
+ default:
+ return ("?");
+ }
+}
+
+static void
+dump_numeric(int val, char *buf)
+/* display the value of a boolean capability */
+{
+ switch (val) {
+ case ABSENT_NUMERIC:
+ strcpy(buf, s_absent);
+ break;
+ case CANCELLED_NUMERIC:
+ strcpy(buf, s_cancel);
+ break;
+ default:
+ sprintf(buf, "%d", val);
+ break;
+ }
+}
+
+static void
+dump_string(char *val, char *buf)
+/* display the value of a string capability */
+{
+ if (val == ABSENT_STRING)
+ strcpy(buf, s_absent);
+ else if (val == CANCELLED_STRING)
+ strcpy(buf, s_cancel);
+ else {
+ sprintf(buf, "'%.*s'", MAX_STRING - 3, TIC_EXPAND(val));
+ }
+}
+
+static void
+compare_predicate(PredType type, PredIdx idx, const char *name)
+/* predicate function to use for entry difference reports */
+{
+ register ENTRY *e1 = &entries[0];
+ register ENTRY *e2 = &entries[1];
+ char buf1[MAX_STRING], buf2[MAX_STRING];
+ int b1, b2;
+ int n1, n2;
+ char *s1, *s2;
+
+ switch (type) {
+ case CMP_BOOLEAN:
+ b1 = e1->tterm.Booleans[idx];
+ b2 = e2->tterm.Booleans[idx];
+ switch (compare) {
+ case C_DIFFERENCE:
+ if (!(b1 == ABSENT_BOOLEAN && b2 == ABSENT_BOOLEAN) && b1 != b2)
+ (void) printf("\t%s: %s%s%s.\n",
+ name,
+ dump_boolean(b1),
+ bool_sep,
+ dump_boolean(b2));
+ break;
+
+ case C_COMMON:
+ if (b1 == b2 && b1 != ABSENT_BOOLEAN)
+ (void) printf("\t%s= %s.\n", name, dump_boolean(b1));
+ break;
+
+ case C_NAND:
+ if (b1 == ABSENT_BOOLEAN && b2 == ABSENT_BOOLEAN)
+ (void) printf("\t!%s.\n", name);
+ break;
+ }
+ break;
+
+ case CMP_NUMBER:
+ n1 = e1->tterm.Numbers[idx];
+ n2 = e2->tterm.Numbers[idx];
+ dump_numeric(n1, buf1);
+ dump_numeric(n2, buf2);
+ switch (compare) {
+ case C_DIFFERENCE:
+ if (!((n1 == ABSENT_NUMERIC && n2 == ABSENT_NUMERIC)) && n1 != n2)
+ (void) printf("\t%s: %s, %s.\n", name, buf1, buf2);
+ break;
+
+ case C_COMMON:
+ if (n1 != ABSENT_NUMERIC && n2 != ABSENT_NUMERIC && n1 == n2)
+ (void) printf("\t%s= %s.\n", name, buf1);
+ break;
+
+ case C_NAND:
+ if (n1 == ABSENT_NUMERIC && n2 == ABSENT_NUMERIC)
+ (void) printf("\t!%s.\n", name);
+ break;
+ }
+ break;
+
+ case CMP_STRING:
+ s1 = e1->tterm.Strings[idx];
+ s2 = e2->tterm.Strings[idx];
+ switch (compare) {
+ case C_DIFFERENCE:
+ if (capcmp(idx, s1, s2)) {
+ dump_string(s1, buf1);
+ dump_string(s2, buf2);
+ if (strcmp(buf1, buf2))
+ (void) printf("\t%s: %s, %s.\n", name, buf1, buf2);
+ }
+ break;
+
+ case C_COMMON:
+ if (s1 && s2 && !capcmp(idx, s1, s2))
+ (void) printf("\t%s= '%s'.\n", name, TIC_EXPAND(s1));
+ break;
+
+ case C_NAND:
+ if (!s1 && !s2)
+ (void) printf("\t!%s.\n", name);
+ break;
+ }
+ break;
+
+ case CMP_USE:
+ /* unlike the other modes, this compares *all* use entries */
+ switch (compare) {
+ case C_DIFFERENCE:
+ if (!useeq(e1, e2)) {
+ (void) fputs("\tuse: ", stdout);
+ print_uses(e1, stdout);
+ fputs(", ", stdout);
+ print_uses(e2, stdout);
+ fputs(".\n", stdout);
+ }
+ break;
+
+ case C_COMMON:
+ if (e1->nuses && e2->nuses && useeq(e1, e2)) {
+ (void) fputs("\tuse: ", stdout);
+ print_uses(e1, stdout);
+ fputs(".\n", stdout);
+ }
+ break;
+
+ case C_NAND:
+ if (!e1->nuses && !e2->nuses)
+ (void) printf("\t!use.\n");
+ break;
+ }
+ }
+}
+
+/***************************************************************************
+ *
+ * Init string analysis
+ *
+ ***************************************************************************/
+
+typedef struct {
+ const char *from;
+ const char *to;
+} assoc;
+
+static const assoc std_caps[] =
+{
+ /* these are specified by X.364 and iBCS2 */
+ {"\033c", "RIS"}, /* full reset */
+ {"\0337", "SC"}, /* save cursor */
+ {"\0338", "RC"}, /* restore cursor */
+ {"\033[r", "RSR"}, /* not an X.364 mnemonic */
+ {"\033[m", "SGR0"}, /* not an X.364 mnemonic */
+ {"\033[2J", "ED2"}, /* clear page */
+
+ /* this group is specified by ISO 2022 */
+ {"\033(0", "ISO DEC G0"}, /* enable DEC graphics for G0 */
+ {"\033(A", "ISO UK G0"}, /* enable UK chars for G0 */
+ {"\033(B", "ISO US G0"}, /* enable US chars for G0 */
+ {"\033)0", "ISO DEC G1"}, /* enable DEC graphics for G1 */
+ {"\033)A", "ISO UK G1"}, /* enable UK chars for G1 */
+ {"\033)B", "ISO US G1"}, /* enable US chars for G1 */
+
+ /* these are DEC private controls widely supported by emulators */
+ {"\033=", "DECPAM"}, /* application keypad mode */
+ {"\033>", "DECPNM"}, /* normal keypad mode */
+ {"\033<", "DECANSI"}, /* enter ANSI mode */
+ {"\033[!p", "DECSTR"}, /* soft reset */
+ {"\033 F", "S7C1T"}, /* 7-bit controls */
+
+ {(char *) 0, (char *) 0}
+};
+
+static const assoc std_modes[] =
+/* ECMA \E[ ... [hl] modes recognized by many emulators */
+{
+ {"2", "AM"}, /* keyboard action mode */
+ {"4", "IRM"}, /* insert/replace mode */
+ {"12", "SRM"}, /* send/receive mode */
+ {"20", "LNM"}, /* linefeed mode */
+ {(char *) 0, (char *) 0}
+};
+
+static const assoc private_modes[] =
+/* DEC \E[ ... [hl] modes recognized by many emulators */
+{
+ {"1", "CKM"}, /* application cursor keys */
+ {"2", "ANM"}, /* set VT52 mode */
+ {"3", "COLM"}, /* 132-column mode */
+ {"4", "SCLM"}, /* smooth scroll */
+ {"5", "SCNM"}, /* reverse video mode */
+ {"6", "OM"}, /* origin mode */
+ {"7", "AWM"}, /* wraparound mode */
+ {"8", "ARM"}, /* auto-repeat mode */
+ {(char *) 0, (char *) 0}
+};
+
+static const assoc ecma_highlights[] =
+/* recognize ECMA attribute sequences */
+{
+ {"0", "NORMAL"}, /* normal */
+ {"1", "+BOLD"}, /* bold on */
+ {"2", "+DIM"}, /* dim on */
+ {"3", "+ITALIC"}, /* italic on */
+ {"4", "+UNDERLINE"}, /* underline on */
+ {"5", "+BLINK"}, /* blink on */
+ {"6", "+FASTBLINK"}, /* fastblink on */
+ {"7", "+REVERSE"}, /* reverse on */
+ {"8", "+INVISIBLE"}, /* invisible on */
+ {"9", "+DELETED"}, /* deleted on */
+ {"10", "MAIN-FONT"}, /* select primary font */
+ {"11", "ALT-FONT-1"}, /* select alternate font 1 */
+ {"12", "ALT-FONT-2"}, /* select alternate font 2 */
+ {"13", "ALT-FONT-3"}, /* select alternate font 3 */
+ {"14", "ALT-FONT-4"}, /* select alternate font 4 */
+ {"15", "ALT-FONT-5"}, /* select alternate font 5 */
+ {"16", "ALT-FONT-6"}, /* select alternate font 6 */
+ {"17", "ALT-FONT-7"}, /* select alternate font 7 */
+ {"18", "ALT-FONT-1"}, /* select alternate font 1 */
+ {"19", "ALT-FONT-1"}, /* select alternate font 1 */
+ {"20", "FRAKTUR"}, /* Fraktur font */
+ {"21", "DOUBLEUNDER"}, /* double underline */
+ {"22", "-DIM"}, /* dim off */
+ {"23", "-ITALIC"}, /* italic off */
+ {"24", "-UNDERLINE"}, /* underline off */
+ {"25", "-BLINK"}, /* blink off */
+ {"26", "-FASTBLINK"}, /* fastblink off */
+ {"27", "-REVERSE"}, /* reverse off */
+ {"28", "-INVISIBLE"}, /* invisible off */
+ {"29", "-DELETED"}, /* deleted off */
+ {(char *) 0, (char *) 0}
+};
+
+static int
+skip_csi(const char *cap)
+{
+ int result = 0;
+ if (cap[0] == '\033' && cap[1] == '[')
+ result = 2;
+ else if (UChar(cap[0]) == 0233)
+ result = 1;
+ return result;
+}
+
+static bool
+same_param(const char *table, const char *param, unsigned length)
+{
+ bool result = FALSE;
+ if (strncmp(table, param, length) == 0) {
+ result = !isdigit(UChar(param[length]));
+ }
+ return result;
+}
+
+static char *
+lookup_params(const assoc * table, char *dst, char *src)
+{
+ char *result = 0;
+ const char *ep = strtok(src, ";");
+
+ if (ep != 0) {
+ const assoc *ap;
+
+ do {
+ bool found = FALSE;
+
+ for (ap = table; ap->from; ap++) {
+ size_t tlen = strlen(ap->from);
+
+ if (same_param(ap->from, ep, tlen)) {
+ (void) strcat(dst, ap->to);
+ found = TRUE;
+ break;
+ }
+ }
+
+ if (!found)
+ (void) strcat(dst, ep);
+ (void) strcat(dst, ";");
+ } while
+ ((ep = strtok((char *) 0, ";")));
+
+ dst[strlen(dst) - 1] = '\0';
+
+ result = dst;
+ }
+ return result;
+}
+
+static void
+analyze_string(const char *name, const char *cap, TERMTYPE *tp)
+{
+ char buf2[MAX_TERMINFO_LENGTH];
+ const char *sp;
+ const assoc *ap;
+ int tp_lines = tp->Numbers[2];
+
+ if (cap == ABSENT_STRING || cap == CANCELLED_STRING)
+ return;
+ (void) printf("%s: ", name);
+
+ for (sp = cap; *sp; sp++) {
+ int i;
+ int csi;
+ size_t len = 0;
+ size_t next;
+ const char *expansion = 0;
+ char buf3[MAX_TERMINFO_LENGTH];
+
+ /* first, check other capabilities in this entry */
+ for (i = 0; i < STRCOUNT; i++) {
+ char *cp = tp->Strings[i];
+
+ /* don't use soft-key capabilities */
+ if (strnames[i][0] == 'k' && strnames[i][0] == 'f')
+ continue;
+
+ if (cp != ABSENT_STRING && cp != CANCELLED_STRING && cp[0] && cp
+ != cap) {
+ len = strlen(cp);
+ (void) strncpy(buf2, sp, len);
+ buf2[len] = '\0';
+
+ if (_nc_capcmp(cp, buf2))
+ continue;
+
+#define ISRS(s) (!strncmp((s), "is", 2) || !strncmp((s), "rs", 2))
+ /*
+ * Theoretically we just passed the test for translation
+ * (equality once the padding is stripped). However, there
+ * are a few more hoops that need to be jumped so that
+ * identical pairs of initialization and reset strings
+ * don't just refer to each other.
+ */
+ if (ISRS(name) || ISRS(strnames[i]))
+ if (cap < cp)
+ continue;
+#undef ISRS
+
+ expansion = strnames[i];
+ break;
+ }
+ }
+
+ /* now check the standard capabilities */
+ if (!expansion) {
+ csi = skip_csi(sp);
+ for (ap = std_caps; ap->from; ap++) {
+ size_t adj = (size_t) (csi ? 2 : 0);
+
+ len = strlen(ap->from);
+ if (csi && skip_csi(ap->from) != csi)
+ continue;
+ if (len > adj
+ && strncmp(ap->from + adj, sp + csi, len - adj) == 0) {
+ expansion = ap->to;
+ len -= adj;
+ len += (size_t) csi;
+ break;
+ }
+ }
+ }
+
+ /* now check for standard-mode sequences */
+ if (!expansion
+ && (csi = skip_csi(sp)) != 0
+ && (len = strspn(sp + csi, "0123456789;"))
+ && (len < sizeof(buf3))
+ && (next = (size_t) csi + len)
+ && ((sp[next] == 'h') || (sp[next] == 'l'))) {
+
+ (void) strcpy(buf2, (sp[next] == 'h') ? "ECMA+" : "ECMA-");
+ (void) strncpy(buf3, sp + csi, len);
+ buf3[len] = '\0';
+ len += (size_t) csi + 1;
+
+ expansion = lookup_params(std_modes, buf2, buf3);
+ }
+
+ /* now check for private-mode sequences */
+ if (!expansion
+ && (csi = skip_csi(sp)) != 0
+ && sp[csi] == '?'
+ && (len = strspn(sp + csi + 1, "0123456789;"))
+ && (len < sizeof(buf3))
+ && (next = (size_t) csi + 1 + len)
+ && ((sp[next] == 'h') || (sp[next] == 'l'))) {
+
+ (void) strcpy(buf2, (sp[next] == 'h') ? "DEC+" : "DEC-");
+ (void) strncpy(buf3, sp + csi + 1, len);
+ buf3[len] = '\0';
+ len += (size_t) csi + 2;
+
+ expansion = lookup_params(private_modes, buf2, buf3);
+ }
+
+ /* now check for ECMA highlight sequences */
+ if (!expansion
+ && (csi = skip_csi(sp)) != 0
+ && (len = strspn(sp + csi, "0123456789;")) != 0
+ && (len < sizeof(buf3))
+ && (next = (size_t) csi + len)
+ && sp[next] == 'm') {
+
+ (void) strcpy(buf2, "SGR:");
+ (void) strncpy(buf3, sp + csi, len);
+ buf3[len] = '\0';
+ len += (size_t) csi + 1;
+
+ expansion = lookup_params(ecma_highlights, buf2, buf3);
+ }
+
+ if (!expansion
+ && (csi = skip_csi(sp)) != 0
+ && sp[csi] == 'm') {
+ len = (size_t) csi + 1;
+ (void) strcpy(buf2, "SGR:");
+ strcat(buf2, ecma_highlights[0].to);
+ expansion = buf2;
+ }
+
+ /* now check for scroll region reset */
+ if (!expansion
+ && (csi = skip_csi(sp)) != 0) {
+ if (sp[csi] == 'r') {
+ expansion = "RSR";
+ len = 1;
+ } else {
+ (void) sprintf(buf2, "1;%dr", tp_lines);
+ len = strlen(buf2);
+ if (strncmp(buf2, sp + csi, len) == 0)
+ expansion = "RSR";
+ }
+ len += (size_t) csi;
+ }
+
+ /* now check for home-down */
+ if (!expansion
+ && (csi = skip_csi(sp)) != 0) {
+ (void) sprintf(buf2, "%d;1H", tp_lines);
+ len = strlen(buf2);
+ if (strncmp(buf2, sp + csi, len) == 0) {
+ expansion = "LL";
+ } else {
+ (void) sprintf(buf2, "%dH", tp_lines);
+ len = strlen(buf2);
+ if (strncmp(buf2, sp + csi, len) == 0) {
+ expansion = "LL";
+ }
+ }
+ len += (size_t) csi;
+ }
+
+ /* now look at the expansion we got, if any */
+ if (expansion) {
+ printf("{%s}", expansion);
+ sp += len - 1;
+ } else {
+ /* couldn't match anything */
+ buf2[0] = *sp;
+ buf2[1] = '\0';
+ fputs(TIC_EXPAND(buf2), stdout);
+ }
+ }
+ putchar('\n');
+}
+
+/***************************************************************************
+ *
+ * File comparison
+ *
+ ***************************************************************************/
+
+static void
+file_comparison(int argc, char *argv[])
+{
+#define MAXCOMPARE 2
+ /* someday we may allow comparisons on more files */
+ int filecount = 0;
+ ENTRY *heads[MAXCOMPARE];
+ ENTRY *qp, *rp;
+ int i, n;
+
+ memset(heads, 0, sizeof(heads));
+ dump_init((char *) 0, F_LITERAL, S_TERMINFO, 0, itrace, FALSE);
+
+ for (n = 0; n < argc && n < MAXCOMPARE; n++) {
+ if (freopen(argv[n], "r", stdin) == 0)
+ _nc_err_abort("Can't open %s", argv[n]);
+
+ _nc_head = _nc_tail = 0;
+
+ /* parse entries out of the source file */
+ _nc_set_source(argv[n]);
+ _nc_read_entry_source(stdin, NULL, TRUE, literal, NULLHOOK);
+
+ if (itrace)
+ (void) fprintf(stderr, "Resolving file %d...\n", n - 0);
+
+ /* maybe do use resolution */
+ if (!_nc_resolve_uses2(!limited, literal)) {
+ (void) fprintf(stderr,
+ "There are unresolved use entries in %s:\n",
+ argv[n]);
+ for_entry_list(qp) {
+ if (qp->nuses) {
+ (void) fputs(qp->tterm.term_names, stderr);
+ (void) fputc('\n', stderr);
+ }
+ }
+ ExitProgram(EXIT_FAILURE);
+ }
+
+ heads[filecount] = _nc_head;
+ filecount++;
+ }
+
+ /* OK, all entries are in core. Ready to do the comparison */
+ if (itrace)
+ (void) fprintf(stderr, "Entries are now in core...\n");
+
+ /* The entry-matching loop. Sigh, this is intrinsically quadratic. */
+ for (qp = heads[0]; qp; qp = qp->next) {
+ for (rp = heads[1]; rp; rp = rp->next)
+ if (_nc_entry_match(qp->tterm.term_names, rp->tterm.term_names)) {
+ if (qp->ncrosslinks < MAX_CROSSLINKS)
+ qp->crosslinks[qp->ncrosslinks] = rp;
+ qp->ncrosslinks++;
+
+ if (rp->ncrosslinks < MAX_CROSSLINKS)
+ rp->crosslinks[rp->ncrosslinks] = qp;
+ rp->ncrosslinks++;
+ }
+ }
+
+ /* now we have two circular lists with crosslinks */
+ if (itrace)
+ (void) fprintf(stderr, "Name matches are done...\n");
+
+ for (qp = heads[0]; qp; qp = qp->next) {
+ if (qp->ncrosslinks > 1) {
+ (void) fprintf(stderr,
+ "%s in file 1 (%s) has %d matches in file 2 (%s):\n",
+ _nc_first_name(qp->tterm.term_names),
+ argv[0],
+ qp->ncrosslinks,
+ argv[1]);
+ for (i = 0; i < qp->ncrosslinks; i++)
+ (void) fprintf(stderr,
+ "\t%s\n",
+ _nc_first_name((qp->crosslinks[i])->tterm.term_names));
+ }
+ }
+
+ for (rp = heads[1]; rp; rp = rp->next) {
+ if (rp->ncrosslinks > 1) {
+ (void) fprintf(stderr,
+ "%s in file 2 (%s) has %d matches in file 1 (%s):\n",
+ _nc_first_name(rp->tterm.term_names),
+ argv[1],
+ rp->ncrosslinks,
+ argv[0]);
+ for (i = 0; i < rp->ncrosslinks; i++)
+ (void) fprintf(stderr,
+ "\t%s\n",
+ _nc_first_name((rp->crosslinks[i])->tterm.term_names));
+ }
+ }
+
+ (void) printf("In file 1 (%s) only:\n", argv[0]);
+ for (qp = heads[0]; qp; qp = qp->next)
+ if (qp->ncrosslinks == 0)
+ (void) printf("\t%s\n",
+ _nc_first_name(qp->tterm.term_names));
+
+ (void) printf("In file 2 (%s) only:\n", argv[1]);
+ for (rp = heads[1]; rp; rp = rp->next)
+ if (rp->ncrosslinks == 0)
+ (void) printf("\t%s\n",
+ _nc_first_name(rp->tterm.term_names));
+
+ (void) printf("The following entries are equivalent:\n");
+ for (qp = heads[0]; qp; qp = qp->next) {
+ if (qp->ncrosslinks == 1) {
+ rp = qp->crosslinks[0];
+
+ repair_acsc(&qp->tterm);
+ repair_acsc(&rp->tterm);
+#if NCURSES_XNAMES
+ _nc_align_termtype(&qp->tterm, &rp->tterm);
+#endif
+ if (entryeq(&qp->tterm, &rp->tterm) && useeq(qp, rp)) {
+ char name1[NAMESIZE], name2[NAMESIZE];
+
+ (void) canonical_name(qp->tterm.term_names, name1);
+ (void) canonical_name(rp->tterm.term_names, name2);
+
+ (void) printf("%s = %s\n", name1, name2);
+ }
+ }
+ }
+
+ (void) printf("Differing entries:\n");
+ termcount = 2;
+ for (qp = heads[0]; qp; qp = qp->next) {
+
+ if (qp->ncrosslinks == 1) {
+ rp = qp->crosslinks[0];
+#if NCURSES_XNAMES
+ /* sorry - we have to do this on each pass */
+ _nc_align_termtype(&qp->tterm, &rp->tterm);
+#endif
+ if (!(entryeq(&qp->tterm, &rp->tterm) && useeq(qp, rp))) {
+ char name1[NAMESIZE], name2[NAMESIZE];
+
+ entries[0] = *qp;
+ entries[1] = *rp;
+
+ (void) canonical_name(qp->tterm.term_names, name1);
+ (void) canonical_name(rp->tterm.term_names, name2);
+
+ switch (compare) {
+ case C_DIFFERENCE:
+ if (itrace)
+ (void) fprintf(stderr,
+ "%s: dumping differences\n",
+ _nc_progname);
+ (void) printf("comparing %s to %s.\n", name1, name2);
+ compare_entry(compare_predicate, &entries->tterm, quiet);
+ break;
+
+ case C_COMMON:
+ if (itrace)
+ (void) fprintf(stderr,
+ "%s: dumping common capabilities\n",
+ _nc_progname);
+ (void) printf("comparing %s to %s.\n", name1, name2);
+ compare_entry(compare_predicate, &entries->tterm, quiet);
+ break;
+
+ case C_NAND:
+ if (itrace)
+ (void) fprintf(stderr,
+ "%s: dumping differences\n",
+ _nc_progname);
+ (void) printf("comparing %s to %s.\n", name1, name2);
+ compare_entry(compare_predicate, &entries->tterm, quiet);
+ break;
+
+ }
+ }
+ }
+ }
+}
+
+static void
+usage(void)
+{
+ static const char *tbl[] =
+ {
+ "Usage: infocmp [options] [-A directory] [-B directory] [termname...]"
+ ,""
+ ,"Options:"
+ ," -1 print single-column"
+ ," -C use termcap-names"
+ ," -F compare terminfo-files"
+ ," -I use terminfo-names"
+ ," -L use long names"
+ ," -R subset (see manpage)"
+ ," -T eliminate size limits (test)"
+ ," -U eliminate post-processing of entries"
+ ," -V print version"
+#if NCURSES_XNAMES
+ ," -a with -F, list commented-out caps"
+#endif
+ ," -c list common capabilities"
+ ," -d list different capabilities"
+ ," -e format output for C initializer"
+ ," -E format output as C tables"
+ ," -f with -1, format complex strings"
+ ," -G format %{number} to %'char'"
+ ," -g format %'char' to %{number}"
+ ," -i analyze initialization/reset"
+ ," -l output terminfo names"
+ ," -n list capabilities in neither"
+ ," -p ignore padding specifiers"
+ ," -q brief listing, removes headers"
+ ," -r with -C, output in termcap form"
+ ," -r with -F, resolve use-references"
+ ," -s [d|i|l|c] sort fields"
+#if NCURSES_XNAMES
+ ," -t suppress commented-out capabilities"
+#endif
+ ," -u produce source with 'use='"
+ ," -v number (verbose)"
+ ," -w number (width)"
+#if NCURSES_XNAMES
+ ," -x treat unknown capabilities as user-defined"
+#endif
+ };
+ const size_t first = 3;
+ const size_t last = SIZEOF(tbl);
+ const size_t left = (last - first + 1) / 2 + first;
+ size_t n;
+
+ for (n = 0; n < left; n++) {
+ size_t m = (n < first) ? last : n + left - first;
+ if (m < last)
+ fprintf(stderr, "%-40.40s%s\n", tbl[n], tbl[m]);
+ else
+ fprintf(stderr, "%s\n", tbl[n]);
+ }
+ ExitProgram(EXIT_FAILURE);
+}
+
+static char *
+any_initializer(const char *fmt, const char *type)
+{
+ static char *initializer;
+ char *s;
+
+ if (initializer == 0)
+ initializer = (char *) malloc(strlen(entries->tterm.term_names) +
+ strlen(type) + strlen(fmt));
+
+ (void) strcpy(initializer, entries->tterm.term_names);
+ for (s = initializer; *s != 0 && *s != '|'; s++) {
+ if (!isalnum(UChar(*s)))
+ *s = '_';
+ }
+ *s = 0;
+ (void) sprintf(s, fmt, type);
+ return initializer;
+}
+
+static char *
+name_initializer(const char *type)
+{
+ return any_initializer("_%s_data", type);
+}
+
+static char *
+string_variable(const char *type)
+{
+ return any_initializer("_s_%s", type);
+}
+
+/* dump C initializers for the terminal type */
+static void
+dump_initializers(TERMTYPE *term)
+{
+ unsigned n;
+ const char *str = 0;
+
+ printf("\nstatic char %s[] = \"%s\";\n\n",
+ name_initializer("alias"), entries->tterm.term_names);
+
+ for_each_string(n, term) {
+ char buf[MAX_STRING], *sp, *tp;
+
+ if (VALID_STRING(term->Strings[n])) {
+ tp = buf;
+ *tp++ = '"';
+ for (sp = term->Strings[n];
+ *sp != 0 && (tp - buf) < MAX_STRING - 6;
+ sp++) {
+ if (isascii(UChar(*sp))
+ && isprint(UChar(*sp))
+ && *sp != '\\'
+ && *sp != '"')
+ *tp++ = *sp;
+ else {
+ (void) sprintf(tp, "\\%03o", UChar(*sp));
+ tp += 4;
+ }
+ }
+ *tp++ = '"';
+ *tp = '\0';
+ (void) printf("static char %-20s[] = %s;\n",
+ string_variable(ExtStrname(term, n, strnames)), buf);
+ }
+ }
+ printf("\n");
+
+ (void) printf("static char %s[] = %s\n", name_initializer("bool"), L_CURL);
+
+ for_each_boolean(n, term) {
+ switch ((int) (term->Booleans[n])) {
+ case TRUE:
+ str = "TRUE";
+ break;
+
+ case FALSE:
+ str = "FALSE";
+ break;
+
+ case ABSENT_BOOLEAN:
+ str = "ABSENT_BOOLEAN";
+ break;
+
+ case CANCELLED_BOOLEAN:
+ str = "CANCELLED_BOOLEAN";
+ break;
+ }
+ (void) printf("\t/* %3u: %-8s */\t%s,\n",
+ n, ExtBoolname(term, n, boolnames), str);
+ }
+ (void) printf("%s;\n", R_CURL);
+
+ (void) printf("static short %s[] = %s\n", name_initializer("number"), L_CURL);
+
+ for_each_number(n, term) {
+ char buf[BUFSIZ];
+ switch (term->Numbers[n]) {
+ case ABSENT_NUMERIC:
+ str = "ABSENT_NUMERIC";
+ break;
+ case CANCELLED_NUMERIC:
+ str = "CANCELLED_NUMERIC";
+ break;
+ default:
+ sprintf(buf, "%d", term->Numbers[n]);
+ str = buf;
+ break;
+ }
+ (void) printf("\t/* %3u: %-8s */\t%s,\n", n,
+ ExtNumname(term, n, numnames), str);
+ }
+ (void) printf("%s;\n", R_CURL);
+
+ (void) printf("static char * %s[] = %s\n", name_initializer("string"), L_CURL);
+
+ for_each_string(n, term) {
+
+ if (term->Strings[n] == ABSENT_STRING)
+ str = "ABSENT_STRING";
+ else if (term->Strings[n] == CANCELLED_STRING)
+ str = "CANCELLED_STRING";
+ else {
+ str = string_variable(ExtStrname(term, n, strnames));
+ }
+ (void) printf("\t/* %3u: %-8s */\t%s,\n", n,
+ ExtStrname(term, n, strnames), str);
+ }
+ (void) printf("%s;\n", R_CURL);
+
+#if NCURSES_XNAMES
+ if ((NUM_BOOLEANS(term) != BOOLCOUNT)
+ || (NUM_NUMBERS(term) != NUMCOUNT)
+ || (NUM_STRINGS(term) != STRCOUNT)) {
+ (void) printf("static char * %s[] = %s\n",
+ name_initializer("string_ext"), L_CURL);
+ for (n = BOOLCOUNT; n < NUM_BOOLEANS(term); ++n) {
+ (void) printf("\t/* %3u: bool */\t\"%s\",\n",
+ n, ExtBoolname(term, n, boolnames));
+ }
+ for (n = NUMCOUNT; n < NUM_NUMBERS(term); ++n) {
+ (void) printf("\t/* %3u: num */\t\"%s\",\n",
+ n, ExtNumname(term, n, numnames));
+ }
+ for (n = STRCOUNT; n < NUM_STRINGS(term); ++n) {
+ (void) printf("\t/* %3u: str */\t\"%s\",\n",
+ n, ExtStrname(term, n, strnames));
+ }
+ (void) printf("%s;\n", R_CURL);
+ }
+#endif
+}
+
+/* dump C initializers for the terminal type */
+static void
+dump_termtype(TERMTYPE *term)
+{
+ (void) printf("\t%s\n\t\t%s,\n", L_CURL, name_initializer("alias"));
+ (void) printf("\t\t(char *)0,\t/* pointer to string table */\n");
+
+ (void) printf("\t\t%s,\n", name_initializer("bool"));
+ (void) printf("\t\t%s,\n", name_initializer("number"));
+
+ (void) printf("\t\t%s,\n", name_initializer("string"));
+
+#if NCURSES_XNAMES
+ (void) printf("#if NCURSES_XNAMES\n");
+ (void) printf("\t\t(char *)0,\t/* pointer to extended string table */\n");
+ (void) printf("\t\t%s,\t/* ...corresponding names */\n",
+ ((NUM_BOOLEANS(term) != BOOLCOUNT)
+ || (NUM_NUMBERS(term) != NUMCOUNT)
+ || (NUM_STRINGS(term) != STRCOUNT))
+ ? name_initializer("string_ext")
+ : "(char **)0");
+
+ (void) printf("\t\t%d,\t\t/* count total Booleans */\n", NUM_BOOLEANS(term));
+ (void) printf("\t\t%d,\t\t/* count total Numbers */\n", NUM_NUMBERS(term));
+ (void) printf("\t\t%d,\t\t/* count total Strings */\n", NUM_STRINGS(term));
+
+ (void) printf("\t\t%d,\t\t/* count extensions to Booleans */\n",
+ NUM_BOOLEANS(term) - BOOLCOUNT);
+ (void) printf("\t\t%d,\t\t/* count extensions to Numbers */\n",
+ NUM_NUMBERS(term) - NUMCOUNT);
+ (void) printf("\t\t%d,\t\t/* count extensions to Strings */\n",
+ NUM_STRINGS(term) - STRCOUNT);
+
+ (void) printf("#endif /* NCURSES_XNAMES */\n");
+#else
+ (void) term;
+#endif /* NCURSES_XNAMES */
+ (void) printf("\t%s\n", R_CURL);
+}
+
+static int
+optarg_to_number(void)
+{
+ char *temp = 0;
+ long value = strtol(optarg, &temp, 0);
+
+ if (temp == 0 || temp == optarg || *temp != 0) {
+ fprintf(stderr, "Expected a number, not \"%s\"\n", optarg);
+ ExitProgram(EXIT_FAILURE);
+ }
+ return (int) value;
+}
+
+static char *
+terminal_env(void)
+{
+ char *terminal;
+
+ if ((terminal = getenv("TERM")) == 0) {
+ (void) fprintf(stderr,
+ "%s: environment variable TERM not set\n",
+ _nc_progname);
+ exit(EXIT_FAILURE);
+ }
+ return terminal;
+}
+
+/***************************************************************************
+ *
+ * Main sequence
+ *
+ ***************************************************************************/
+
+#if NO_LEAKS
+#define MAIN_LEAKS() \
+ free(myargv); \
+ free(tfile); \
+ free(tname)
+#else
+#define MAIN_LEAKS() /* nothing */
+#endif
+
+int
+main(int argc, char *argv[])
+{
+ /* Avoid "local data >32k" error with mwcc */
+ /* Also avoid overflowing smaller stacks on systems like AmigaOS */
+ path *tfile = 0;
+ char **tname = 0;
+ int maxterms;
+
+ char **myargv;
+
+ char *firstdir, *restdir;
+ int c, i, len;
+ bool formatted = FALSE;
+ bool filecompare = FALSE;
+ int initdump = 0;
+ bool init_analyze = FALSE;
+ bool suppress_untranslatable = FALSE;
+
+ /* where is the terminfo database location going to default to? */
+ restdir = firstdir = 0;
+
+#if NCURSES_XNAMES
+ use_extended_names(FALSE);
+#endif
+
+ _nc_progname = _nc_rootname(argv[0]);
+
+ /* make sure we have enough space to add two terminal entries */
+ myargv = typeCalloc(char *, (size_t) (argc + 3));
+ memcpy(myargv, argv, (sizeof(char *) * (size_t) argc));
+ argv = myargv;
+
+ while ((c = getopt(argc,
+ argv,
+ "1A:aB:CcdEeFfGgIiLlnpqR:rs:TtUuVv:w:x")) != -1) {
+ switch (c) {
+ case '1':
+ mwidth = 0;
+ break;
+
+ case 'A':
+ firstdir = optarg;
+ break;
+
+#if NCURSES_XNAMES
+ case 'a':
+ _nc_disable_period = TRUE;
+ use_extended_names(TRUE);
+ break;
+#endif
+ case 'B':
+ restdir = optarg;
+ break;
+
+ case 'C':
+ outform = F_TERMCAP;
+ tversion = "BSD";
+ if (sortmode == S_DEFAULT)
+ sortmode = S_TERMCAP;
+ break;
+
+ case 'c':
+ compare = C_COMMON;
+ break;
+
+ case 'd':
+ compare = C_DIFFERENCE;
+ break;
+
+ case 'E':
+ initdump |= 2;
+ break;
+
+ case 'e':
+ initdump |= 1;
+ break;
+
+ case 'F':
+ filecompare = TRUE;
+ break;
+
+ case 'f':
+ formatted = TRUE;
+ break;
+
+ case 'G':
+ numbers = 1;
+ break;
+
+ case 'g':
+ numbers = -1;
+ break;
+
+ case 'I':
+ outform = F_TERMINFO;
+ if (sortmode == S_DEFAULT)
+ sortmode = S_VARIABLE;
+ tversion = 0;
+ break;
+
+ case 'i':
+ init_analyze = TRUE;
+ break;
+
+ case 'L':
+ outform = F_VARIABLE;
+ if (sortmode == S_DEFAULT)
+ sortmode = S_VARIABLE;
+ break;
+
+ case 'l':
+ outform = F_TERMINFO;
+ break;
+
+ case 'n':
+ compare = C_NAND;
+ break;
+
+ case 'p':
+ ignorepads = TRUE;
+ break;
+
+ case 'q':
+ quiet = TRUE;
+ s_absent = "-";
+ s_cancel = "@";
+ bool_sep = ", ";
+ break;
+
+ case 'R':
+ tversion = optarg;
+ break;
+
+ case 'r':
+ tversion = 0;
+ break;
+
+ case 's':
+ if (*optarg == 'd')
+ sortmode = S_NOSORT;
+ else if (*optarg == 'i')
+ sortmode = S_TERMINFO;
+ else if (*optarg == 'l')
+ sortmode = S_VARIABLE;
+ else if (*optarg == 'c')
+ sortmode = S_TERMCAP;
+ else {
+ (void) fprintf(stderr,
+ "%s: unknown sort mode\n",
+ _nc_progname);
+ ExitProgram(EXIT_FAILURE);
+ }
+ break;
+
+ case 'T':
+ limited = FALSE;
+ break;
+
+#if NCURSES_XNAMES
+ case 't':
+ _nc_disable_period = FALSE;
+ suppress_untranslatable = TRUE;
+ break;
+#endif
+
+ case 'U':
+ literal = TRUE;
+ break;
+
+ case 'u':
+ compare = C_USEALL;
+ break;
+
+ case 'V':
+ puts(curses_version());
+ ExitProgram(EXIT_SUCCESS);
+
+ case 'v':
+ itrace = optarg_to_number();
+ set_trace_level(itrace);
+ break;
+
+ case 'w':
+ mwidth = optarg_to_number();
+ break;
+
+#if NCURSES_XNAMES
+ case 'x':
+ use_extended_names(TRUE);
+ break;
+#endif
+
+ default:
+ usage();
+ }
+ }
+
+ maxterms = (argc + 2 - optind);
+ tfile = typeMalloc(path, maxterms);
+ tname = typeCalloc(char *, maxterms);
+ entries = typeCalloc(ENTRY, maxterms);
+
+ if (tfile == 0
+ || tname == 0
+ || entries == 0) {
+ fprintf(stderr, "%s: not enough memory\n", _nc_progname);
+ ExitProgram(EXIT_FAILURE);
+ }
+
+ /* by default, sort by terminfo name */
+ if (sortmode == S_DEFAULT)
+ sortmode = S_TERMINFO;
+
+ /* set up for display */
+ dump_init(tversion, outform, sortmode, mwidth, itrace, formatted);
+
+ /* make sure we have at least one terminal name to work with */
+ if (optind >= argc)
+ argv[argc++] = terminal_env();
+
+ /* if user is after a comparison, make sure we have two entries */
+ if (compare != C_DEFAULT && optind >= argc - 1)
+ argv[argc++] = terminal_env();
+
+ /* exactly two terminal names with no options means do -d */
+ if (argc - optind == 2 && compare == C_DEFAULT)
+ compare = C_DIFFERENCE;
+
+ if (!filecompare) {
+ /* grab the entries */
+ termcount = 0;
+ for (; optind < argc; optind++) {
+ const char *directory = termcount ? restdir : firstdir;
+ int status;
+
+ tname[termcount] = argv[optind];
+
+ if (directory) {
+#if USE_DATABASE
+#if MIXEDCASE_FILENAMES
+#define LEAF_FMT "%c"
+#else
+#define LEAF_FMT "%02x"
+#endif
+ (void) sprintf(tfile[termcount], "%s/" LEAF_FMT "/%s",
+ directory,
+ UChar(*argv[optind]), argv[optind]);
+ if (itrace)
+ (void) fprintf(stderr,
+ "%s: reading entry %s from file %s\n",
+ _nc_progname,
+ argv[optind], tfile[termcount]);
+
+ status = _nc_read_file_entry(tfile[termcount],
+ &entries[termcount].tterm);
+#else
+ (void) fprintf(stderr, "%s: terminfo files not supported\n",
+ _nc_progname);
+ MAIN_LEAKS();
+ ExitProgram(EXIT_FAILURE);
+#endif
+ } else {
+ if (itrace)
+ (void) fprintf(stderr,
+ "%s: reading entry %s from database\n",
+ _nc_progname,
+ tname[termcount]);
+
+ status = _nc_read_entry(tname[termcount],
+ tfile[termcount],
+ &entries[termcount].tterm);
+ }
+
+ if (status <= 0) {
+ (void) fprintf(stderr,
+ "%s: couldn't open terminfo file %s.\n",
+ _nc_progname,
+ tfile[termcount]);
+ MAIN_LEAKS();
+ ExitProgram(EXIT_FAILURE);
+ }
+ repair_acsc(&entries[termcount].tterm);
+ termcount++;
+ }
+
+#if NCURSES_XNAMES
+ if (termcount > 1)
+ _nc_align_termtype(&entries[0].tterm, &entries[1].tterm);
+#endif
+
+ /* dump as C initializer for the terminal type */
+ if (initdump) {
+ if (initdump & 1)
+ dump_termtype(&entries[0].tterm);
+ if (initdump & 2)
+ dump_initializers(&entries[0].tterm);
+ }
+
+ /* analyze the init strings */
+ else if (init_analyze) {
+#undef CUR
+#define CUR entries[0].tterm.
+ analyze_string("is1", init_1string, &entries[0].tterm);
+ analyze_string("is2", init_2string, &entries[0].tterm);
+ analyze_string("is3", init_3string, &entries[0].tterm);
+ analyze_string("rs1", reset_1string, &entries[0].tterm);
+ analyze_string("rs2", reset_2string, &entries[0].tterm);
+ analyze_string("rs3", reset_3string, &entries[0].tterm);
+ analyze_string("smcup", enter_ca_mode, &entries[0].tterm);
+ analyze_string("rmcup", exit_ca_mode, &entries[0].tterm);
+#undef CUR
+ } else {
+
+ /*
+ * Here's where the real work gets done
+ */
+ switch (compare) {
+ case C_DEFAULT:
+ if (itrace)
+ (void) fprintf(stderr,
+ "%s: about to dump %s\n",
+ _nc_progname,
+ tname[0]);
+ (void) printf("#\tReconstructed via infocmp from file: %s\n",
+ tfile[0]);
+ dump_entry(&entries[0].tterm,
+ suppress_untranslatable,
+ limited,
+ numbers,
+ NULL);
+ len = show_entry();
+ if (itrace)
+ (void) fprintf(stderr, "%s: length %d\n", _nc_progname, len);
+ break;
+
+ case C_DIFFERENCE:
+ if (itrace)
+ (void) fprintf(stderr, "%s: dumping differences\n", _nc_progname);
+ (void) printf("comparing %s to %s.\n", tname[0], tname[1]);
+ compare_entry(compare_predicate, &entries->tterm, quiet);
+ break;
+
+ case C_COMMON:
+ if (itrace)
+ (void) fprintf(stderr,
+ "%s: dumping common capabilities\n",
+ _nc_progname);
+ (void) printf("comparing %s to %s.\n", tname[0], tname[1]);
+ compare_entry(compare_predicate, &entries->tterm, quiet);
+ break;
+
+ case C_NAND:
+ if (itrace)
+ (void) fprintf(stderr,
+ "%s: dumping differences\n",
+ _nc_progname);
+ (void) printf("comparing %s to %s.\n", tname[0], tname[1]);
+ compare_entry(compare_predicate, &entries->tterm, quiet);
+ break;
+
+ case C_USEALL:
+ if (itrace)
+ (void) fprintf(stderr, "%s: dumping use entry\n", _nc_progname);
+ dump_entry(&entries[0].tterm,
+ suppress_untranslatable,
+ limited,
+ numbers,
+ use_predicate);
+ for (i = 1; i < termcount; i++)
+ dump_uses(tname[i], !(outform == F_TERMCAP
+ || outform == F_TCONVERR));
+ len = show_entry();
+ if (itrace)
+ (void) fprintf(stderr, "%s: length %d\n", _nc_progname, len);
+ break;
+ }
+ }
+ } else if (compare == C_USEALL)
+ (void) fprintf(stderr, "Sorry, -u doesn't work with -F\n");
+ else if (compare == C_DEFAULT)
+ (void) fprintf(stderr, "Use `tic -[CI] <file>' for this.\n");
+ else if (argc - optind != 2)
+ (void) fprintf(stderr,
+ "File comparison needs exactly two file arguments.\n");
+ else
+ file_comparison(argc - optind, argv + optind);
+
+ MAIN_LEAKS();
+ ExitProgram(EXIT_SUCCESS);
+}
+
+/* infocmp.c ends here */
diff --git a/progs/modules b/progs/modules
new file mode 100644
index 0000000..55d7a9f
--- /dev/null
+++ b/progs/modules
@@ -0,0 +1,45 @@
+# $Id: modules,v 1.17 2010/01/23 17:47:23 tom Exp $
+# Program modules (some are in ncurses lib!)
+##############################################################################
+# Copyright (c) 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: Thomas E. Dickey 1995-on
+#
+
+@ base
+clear progs $(srcdir) $(HEADER_DEPS)
+tic progs $(srcdir) $(HEADER_DEPS) transform.h $(srcdir)/dump_entry.h
+toe progs $(srcdir) $(HEADER_DEPS) $(INCDIR)/hashed_db.h
+dump_entry progs $(srcdir) $(HEADER_DEPS) $(srcdir)/dump_entry.h ../include/parametrized.h $(INCDIR)/capdefaults.c termsort.c
+infocmp progs $(srcdir) $(HEADER_DEPS) $(srcdir)/dump_entry.h
+tabs progs $(srcdir) $(HEADER_DEPS)
+tput progs $(srcdir) $(HEADER_DEPS) transform.h $(srcdir)/dump_entry.h termsort.c
+tset progs $(srcdir) $(HEADER_DEPS) transform.h $(srcdir)/dump_entry.h ../include/termcap.h
+transform progs $(srcdir) $(HEADER_DEPS) transform.h
+
+# vile:makemode
diff --git a/progs/progs.priv.h b/progs/progs.priv.h
new file mode 100644
index 0000000..f0ea460
--- /dev/null
+++ b/progs/progs.priv.h
@@ -0,0 +1,192 @@
+/****************************************************************************
+ * Copyright (c) 1998-2007,2008 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: Thomas E. Dickey 1997-on *
+ ****************************************************************************/
+/*
+ * $Id: progs.priv.h,v 1.34 2008/08/03 17:43:05 tom Exp $
+ *
+ * progs.priv.h
+ *
+ * Header file for curses utility programs
+ */
+
+#include <ncurses_cfg.h>
+
+#if USE_RCS_IDS
+#define MODULE_ID(id) static const char Ident[] = id;
+#else
+#define MODULE_ID(id) /*nothing*/
+#endif
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <sys/types.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#if HAVE_SYS_BSDTYPES_H
+#include <sys/bsdtypes.h> /* needed for ISC */
+#endif
+
+#if HAVE_LIMITS_H
+# include <limits.h>
+#elif HAVE_SYS_PARAM_H
+# include <sys/param.h>
+#endif
+
+#if HAVE_DIRENT_H
+# include <dirent.h>
+# define NAMLEN(dirent) strlen((dirent)->d_name)
+# if defined(_FILE_OFFSET_BITS) && defined(HAVE_STRUCT_DIRENT64)
+# if !defined(_LP64) && (_FILE_OFFSET_BITS == 64)
+# define DIRENT struct dirent64
+# else
+# define DIRENT struct dirent
+# endif
+# else
+# define DIRENT struct dirent
+# endif
+#else
+# define DIRENT struct direct
+# define NAMLEN(dirent) (dirent)->d_namlen
+# if HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif
+# if HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif
+# if HAVE_NDIR_H
+# include <ndir.h>
+# endif
+#endif
+
+#include <assert.h>
+#include <errno.h>
+
+#if DECL_ERRNO
+extern int errno;
+#endif
+
+#if HAVE_GETOPT_H
+#include <getopt.h>
+#else
+/* 'getopt()' may be prototyped in <stdlib.h>, but declaring its
+ * variables doesn't hurt.
+ */
+extern char *optarg;
+extern int optind;
+#endif /* HAVE_GETOPT_H */
+
+#include <curses.h>
+#include <term_entry.h>
+#include <tic.h>
+#include <nc_tparm.h>
+
+#include <nc_alloc.h>
+#if HAVE_NC_FREEALL
+#undef ExitProgram
+#ifdef USE_LIBTINFO
+#define ExitProgram(code) _nc_free_tinfo(code)
+#else
+#define ExitProgram(code) _nc_free_tic(code)
+#endif
+#endif
+
+/* usually in <unistd.h> */
+#ifndef STDOUT_FILENO
+#define STDOUT_FILENO 1
+#endif
+
+#ifndef STDERR_FILENO
+#define STDERR_FILENO 2
+#endif
+
+#ifndef EXIT_SUCCESS
+#define EXIT_SUCCESS 0
+#endif
+
+#ifndef EXIT_FAILURE
+#define EXIT_FAILURE 1
+#endif
+
+#ifndef R_OK
+#define R_OK 4 /* Test for readable. */
+#endif
+
+#ifndef W_OK
+#define W_OK 2 /* Test for writable. */
+#endif
+
+#ifndef X_OK
+#define X_OK 1 /* Test for executable. */
+#endif
+
+#ifndef F_OK
+#define F_OK 0 /* Test for existence. */
+#endif
+
+/* usually in <unistd.h> */
+#ifndef STDOUT_FILENO
+#define STDOUT_FILENO 1
+#endif
+
+#ifndef STDERR_FILENO
+#define STDERR_FILENO 2
+#endif
+
+/* may be in limits.h, included from various places */
+#ifndef PATH_MAX
+# if defined(_POSIX_PATH_MAX)
+# define PATH_MAX _POSIX_PATH_MAX
+# elif defined(MAXPATHLEN)
+# define PATH_MAX MAXPATHLEN
+# else
+# define PATH_MAX 255 /* the Posix minimum pathsize */
+# endif
+#endif
+
+/* We use isascii only to guard against use of 7-bit ctype tables in the
+ * isprint test in infocmp.
+ */
+#if !HAVE_ISASCII
+# undef isascii
+# if ('z'-'a' == 25) && ('z' < 127) && ('Z'-'A' == 25) && ('Z' < 127) && ('9' < 127)
+# define isascii(c) (UChar(c) <= 127)
+# else
+# define isascii(c) 1 /* not really ascii anyway */
+# endif
+#endif
+
+#define UChar(c) ((unsigned char)(c))
+
+#define SIZEOF(v) (sizeof(v)/sizeof(v[0]))
diff --git a/progs/tabs.c b/progs/tabs.c
new file mode 100644
index 0000000..b59c908
--- /dev/null
+++ b/progs/tabs.c
@@ -0,0 +1,510 @@
+/****************************************************************************
+ * Copyright (c) 2008-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: Thomas E. Dickey 2008 *
+ ****************************************************************************/
+
+/*
+ * tabs.c -- set terminal hard-tabstops
+ */
+
+#define USE_LIBTINFO
+#include <progs.priv.h>
+
+MODULE_ID("$Id: tabs.c,v 1.19 2010/10/23 22:26:01 tom Exp $")
+
+static void usage(void) GCC_NORETURN;
+
+static int max_cols;
+
+static int
+putch(int c)
+{
+ return putchar(c);
+}
+
+static void
+do_tabs(int *tab_list)
+{
+ int last = 1;
+ int stop;
+
+ putchar('\r');
+ while ((stop = *tab_list++) > 0) {
+ if (last < stop) {
+ while (last++ < stop) {
+ if (last > max_cols)
+ break;
+ putchar(' ');
+ }
+ }
+ if (stop <= max_cols) {
+ tputs(tparm(set_tab, stop), 1, putch);
+ last = stop;
+ } else {
+ break;
+ }
+ }
+ putchar('\n');
+}
+
+static int *
+decode_tabs(const char *tab_list)
+{
+ int *result = typeCalloc(int, strlen(tab_list) + (unsigned) max_cols);
+ int n = 0;
+ int value = 0;
+ int prior = 0;
+ int ch;
+
+ if (result != 0) {
+ while ((ch = *tab_list++) != '\0') {
+ if (isdigit(UChar(ch))) {
+ value *= 10;
+ value += (ch - '0');
+ } else if (ch == ',') {
+ result[n] = value + prior;
+ if (n > 0 && result[n] <= result[n - 1]) {
+ fprintf(stderr,
+ "tab-stops are not in increasing order: %d %d\n",
+ value, result[n - 1]);
+ free(result);
+ result = 0;
+ break;
+ }
+ ++n;
+ value = 0;
+ prior = 0;
+ } else if (ch == '+') {
+ if (n)
+ prior = result[n - 1];
+ }
+ }
+ }
+
+ if (result != 0) {
+ /*
+ * If there is only one value, then it is an option such as "-8".
+ */
+ if ((n == 0) && (value > 0)) {
+ int step = value;
+ while (n < max_cols - 1) {
+ result[n++] = value;
+ value += step;
+ }
+ }
+
+ /*
+ * Add the last value, if any.
+ */
+ result[n++] = value + prior;
+ result[n] = 0;
+ }
+ return result;
+}
+
+static void
+print_ruler(int *tab_list)
+{
+ int last = 0;
+ int stop;
+ int n;
+
+ /* first print a readable ruler */
+ for (n = 0; n < max_cols; n += 10) {
+ int ch = 1 + (n / 10);
+ char buffer[20];
+ sprintf(buffer, "----+----%c",
+ ((ch < 10)
+ ? (ch + '0')
+ : (ch + 'A' - 10)));
+ printf("%.*s", ((max_cols - n) > 10) ? 10 : (max_cols - n), buffer);
+ }
+ putchar('\n');
+
+ /* now, print '*' for each stop */
+ for (n = 0, last = 0; (tab_list[n] > 0) && (last < max_cols); ++n) {
+ stop = tab_list[n];
+ while (++last < stop) {
+ if (last <= max_cols) {
+ putchar('-');
+ } else {
+ break;
+ }
+ }
+ if (last <= max_cols) {
+ putchar('*');
+ last = stop;
+ } else {
+ break;
+ }
+ }
+ while (++last <= max_cols)
+ putchar('-');
+ putchar('\n');
+}
+
+/*
+ * Write an '*' on each tabstop, to demonstrate whether it lines up with the
+ * ruler.
+ */
+static void
+write_tabs(int *tab_list)
+{
+ int stop;
+
+ while ((stop = *tab_list++) > 0 && stop <= max_cols) {
+ fputs((stop == 1) ? "*" : "\t*", stdout);
+ };
+ /* also show a tab _past_ the stops */
+ if (stop < max_cols)
+ fputs("\t+", stdout);
+ putchar('\n');
+}
+
+/*
+ * Trim leading/trailing blanks, as well as blanks after a comma.
+ * Convert embedded blanks to commas.
+ */
+static char *
+trimmed_tab_list(const char *source)
+{
+ char *result = strdup(source);
+ int ch, j, k, last;
+
+ if (result != 0) {
+ for (j = k = last = 0; result[j] != 0; ++j) {
+ ch = UChar(result[j]);
+ if (isspace(ch)) {
+ if (last == '\0') {
+ continue;
+ } else if (isdigit(last) || last == ',') {
+ ch = ',';
+ }
+ } else if (ch == ',') {
+ ;
+ } else {
+ if (last == ',')
+ result[k++] = (char) last;
+ result[k++] = (char) ch;
+ }
+ last = ch;
+ }
+ result[k] = '\0';
+ }
+ return result;
+}
+
+static bool
+comma_is_needed(const char *source)
+{
+ bool result = FALSE;
+
+ if (source != 0) {
+ unsigned len = strlen(source);
+ if (len != 0)
+ result = (source[len - 1] != ',');
+ } else {
+ result = FALSE;
+ }
+ return result;
+}
+
+/*
+ * Add a command-line parameter to the tab-list. It can be blank- or comma-
+ * separated (or a mixture). For simplicity, empty tabs are ignored, e.g.,
+ * tabs 1,,6,11
+ * tabs 1,6,11
+ * are treated the same.
+ */
+static const char *
+add_to_tab_list(char **append, const char *value)
+{
+ char *result = *append;
+ char *copied = trimmed_tab_list(value);
+
+ if (copied != 0 && *copied != '\0') {
+ const char *comma = ",";
+ unsigned need = 1 + strlen(copied);
+
+ if (*copied == ',')
+ comma = "";
+ else if (!comma_is_needed(*append))
+ comma = "";
+
+ need += strlen(comma);
+ if (*append != 0)
+ need += strlen(*append);
+
+ result = malloc(need);
+ if (result != 0) {
+ *result = '\0';
+ if (*append != 0) {
+ strcpy(result, *append);
+ free(*append);
+ }
+ strcat(result, comma);
+ strcat(result, copied);
+ }
+
+ *append = result;
+ }
+ return result;
+}
+
+/*
+ * Check for illegal characters in the tab-list.
+ */
+static bool
+legal_tab_list(const char *program, const char *tab_list)
+{
+ bool result = TRUE;
+
+ if (tab_list != 0 && *tab_list != '\0') {
+ if (comma_is_needed(tab_list)) {
+ int n, ch;
+ for (n = 0; tab_list[n] != '\0'; ++n) {
+ ch = UChar(tab_list[n]);
+ if (!(isdigit(ch) || ch == ',' || ch == '+')) {
+ fprintf(stderr,
+ "%s: unexpected character found '%c'\n",
+ program, ch);
+ result = FALSE;
+ break;
+ }
+ }
+ } else {
+ fprintf(stderr, "%s: trailing comma found '%s'\n", program, tab_list);
+ result = FALSE;
+ }
+ } else {
+ fprintf(stderr, "%s: no tab-list given\n", program);
+ result = FALSE;
+ }
+ return result;
+}
+
+static void
+usage(void)
+{
+ static const char *msg[] =
+ {
+ "Usage: tabs [options] [tabstop-list]"
+ ,""
+ ,"Options:"
+ ," -0 reset tabs"
+ ," -8 set tabs to standard interval"
+ ," -a Assembler, IBM S/370, first format"
+ ," -a2 Assembler, IBM S/370, second format"
+ ," -c COBOL, normal format"
+ ," -c2 COBOL compact format"
+ ," -c3 COBOL compact format extended"
+ ," -d debug (show ruler with expected/actual tab positions)"
+ ," -f FORTRAN"
+ ," -n no-op (do not modify terminal settings)"
+ ," -p PL/I"
+ ," -s SNOBOL"
+ ," -u UNIVAC 1100 Assembler"
+ ," -T name use terminal type 'name'"
+ ,""
+ ,"A tabstop-list is an ordered list of column numbers, e.g., 1,11,21"
+ ,"or 1,+10,+10 which is the same."
+ };
+ unsigned n;
+
+ fflush(stdout);
+ for (n = 0; n < SIZEOF(msg); ++n) {
+ fprintf(stderr, "%s\n", msg[n]);
+ }
+ ExitProgram(EXIT_FAILURE);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int rc = EXIT_FAILURE;
+ bool debug = FALSE;
+ bool no_op = FALSE;
+ int n, ch;
+ NCURSES_CONST char *term_name = 0;
+ const char *mar_list = 0; /* ignored */
+ char *append = 0;
+ const char *tab_list = 0;
+
+ if ((term_name = getenv("TERM")) == 0)
+ term_name = "ansi+tabs";
+
+ /* cannot use getopt, since some options are two-character */
+ for (n = 1; n < argc; ++n) {
+ char *option = argv[n];
+ switch (option[0]) {
+ case '-':
+ while ((ch = *++option) != '\0') {
+ switch (ch) {
+ case 'a':
+ switch (*option) {
+ case '\0':
+ tab_list = "1,10,16,36,72";
+ /* Assembler, IBM S/370, first format */
+ break;
+ case '2':
+ tab_list = "1,10,16,40,72";
+ /* Assembler, IBM S/370, second format */
+ break;
+ default:
+ usage();
+ }
+ break;
+ case 'c':
+ switch (*option) {
+ case '\0':
+ tab_list = "1,8,12,16,20,55";
+ /* COBOL, normal format */
+ break;
+ case '2':
+ tab_list = "1,6,10,14,49";
+ /* COBOL compact format */
+ break;
+ case '3':
+ tab_list = "1,6,10,14,18,22,26,30,34,38,42,46,50,54,58,62,67";
+ /* COBOL compact format extended */
+ break;
+ default:
+ usage();
+ }
+ break;
+ case 'd': /* ncurses extension */
+ debug = TRUE;
+ break;
+ case 'f':
+ tab_list = "1,7,11,15,19,23";
+ /* FORTRAN */
+ break;
+ case 'n': /* ncurses extension */
+ no_op = TRUE;
+ break;
+ case 'p':
+ tab_list = "1,5,9,13,17,21,25,29,33,37,41,45,49,53,57,61";
+ /* PL/I */
+ break;
+ case 's':
+ tab_list = "1,10,55";
+ /* SNOBOL */
+ break;
+ case 'u':
+ tab_list = "1,12,20,44";
+ /* UNIVAC 1100 Assembler */
+ break;
+ case 'T':
+ ++n;
+ if (*++option != '\0') {
+ term_name = option;
+ } else {
+ term_name = argv[n++];
+ }
+ option += ((int) strlen(option)) - 1;
+ continue;
+ default:
+ if (isdigit(UChar(*option))) {
+ tab_list = option;
+ ++n;
+ } else {
+ usage();
+ }
+ option += ((int) strlen(option)) - 1;
+ break;
+ }
+ }
+ break;
+ case '+':
+ while ((ch = *++option) != '\0') {
+ switch (ch) {
+ case 'm':
+ mar_list = option;
+ break;
+ default:
+ /* special case of relative stops separated by spaces? */
+ if (option == argv[n] + 1) {
+ tab_list = add_to_tab_list(&append, argv[n]);
+ }
+ break;
+ }
+ }
+ break;
+ default:
+ if (append != 0) {
+ if (tab_list != (const char *) append) {
+ /* one of the predefined options was used */
+ free(append);
+ append = 0;
+ }
+ }
+ tab_list = add_to_tab_list(&append, option);
+ break;
+ }
+ }
+
+ setupterm(term_name, STDOUT_FILENO, (int *) 0);
+
+ max_cols = (columns > 0) ? columns : 80;
+
+ if (!VALID_STRING(clear_all_tabs)) {
+ fprintf(stderr,
+ "%s: terminal type '%s' cannot reset tabs\n",
+ argv[0], term_name);
+ } else if (!VALID_STRING(set_tab)) {
+ fprintf(stderr,
+ "%s: terminal type '%s' cannot set tabs\n",
+ argv[0], term_name);
+ } else if (legal_tab_list(argv[0], tab_list)) {
+ int *list = decode_tabs(tab_list);
+
+ if (!no_op)
+ tputs(clear_all_tabs, 1, putch);
+
+ if (list != 0) {
+ if (!no_op)
+ do_tabs(list);
+ if (debug) {
+ fflush(stderr);
+ printf("tabs %s\n", tab_list);
+ print_ruler(list);
+ write_tabs(list);
+ }
+ free(list);
+ } else if (debug) {
+ fflush(stderr);
+ printf("tabs %s\n", tab_list);
+ }
+ rc = EXIT_SUCCESS;
+ }
+ if (append != 0)
+ free(append);
+ ExitProgram(rc);
+}
diff --git a/progs/tic.c b/progs/tic.c
new file mode 100644
index 0000000..8e89095
--- /dev/null
+++ b/progs/tic.c
@@ -0,0 +1,1714 @@
+/****************************************************************************
+ * Copyright (c) 1998-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"), 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: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 *
+ * and: Eric S. Raymond <esr@snark.thyrsus.com> *
+ * and: Thomas E. Dickey 1996 on *
+ ****************************************************************************/
+
+/*
+ * tic.c --- Main program for terminfo compiler
+ * by Eric S. Raymond
+ *
+ */
+
+#include <progs.priv.h>
+#include <sys/stat.h>
+
+#include <dump_entry.h>
+#include <transform.h>
+
+MODULE_ID("$Id: tic.c,v 1.147 2011/02/12 18:39:08 tom Exp $")
+
+const char *_nc_progname = "tic";
+
+static FILE *log_fp;
+static FILE *tmp_fp;
+static bool capdump = FALSE; /* running as infotocap? */
+static bool infodump = FALSE; /* running as captoinfo? */
+static bool showsummary = FALSE;
+static const char *to_remove;
+
+static void (*save_check_termtype) (TERMTYPE *, bool);
+static void check_termtype(TERMTYPE *tt, bool);
+
+static const char usage_string[] = "\
+[-e names] \
+[-o dir] \
+[-R name] \
+[-v[n]] \
+[-V] \
+[-w[n]] \
+[-\
+1\
+a\
+C\
+c\
+f\
+G\
+g\
+I\
+L\
+N\
+r\
+s\
+T\
+t\
+U\
+x\
+] \
+source-file\n";
+
+#if NO_LEAKS
+static void
+free_namelist(char **src)
+{
+ if (src != 0) {
+ int n;
+ for (n = 0; src[n] != 0; ++n)
+ free(src[n]);
+ free(src);
+ }
+}
+#endif
+
+static void
+cleanup(char **namelst GCC_UNUSED)
+{
+#if NO_LEAKS
+ free_namelist(namelst);
+#endif
+ if (tmp_fp != 0)
+ fclose(tmp_fp);
+ if (to_remove != 0) {
+#if HAVE_REMOVE
+ remove(to_remove);
+#else
+ unlink(to_remove);
+#endif
+ }
+}
+
+static void
+failed(const char *msg)
+{
+ perror(msg);
+ cleanup((char **) 0);
+ ExitProgram(EXIT_FAILURE);
+}
+
+static void
+usage(void)
+{
+ static const char *const tbl[] =
+ {
+ "Options:",
+ " -1 format translation output one capability per line",
+#if NCURSES_XNAMES
+ " -a retain commented-out capabilities (sets -x also)",
+#endif
+ " -C translate entries to termcap source form",
+ " -c check only, validate input without compiling or translating",
+ " -e<names> translate/compile only entries named by comma-separated list",
+ " -f format complex strings for readability",
+ " -G format %{number} to %'char'",
+ " -g format %'char' to %{number}",
+ " -I translate entries to terminfo source form",
+ " -L translate entries to full terminfo source form",
+ " -N disable smart defaults for source translation",
+ " -o<dir> set output directory for compiled entry writes",
+ " -R<name> restrict translation to given terminfo/termcap version",
+ " -r force resolution of all use entries in source translation",
+ " -s print summary statistics",
+ " -T remove size-restrictions on compiled description",
+#if NCURSES_XNAMES
+ " -t suppress commented-out capabilities",
+#endif
+ " -U suppress post-processing of entries",
+ " -V print version",
+ " -v[n] set verbosity level",
+ " -w[n] set format width for translation output",
+#if NCURSES_XNAMES
+ " -x treat unknown capabilities as user-defined",
+#endif
+ "",
+ "Parameters:",
+ " <file> file to translate or compile"
+ };
+ size_t j;
+
+ fprintf(stderr, "Usage: %s %s\n", _nc_progname, usage_string);
+ for (j = 0; j < SIZEOF(tbl); j++) {
+ fputs(tbl[j], stderr);
+ putc('\n', stderr);
+ }
+ ExitProgram(EXIT_FAILURE);
+}
+
+#define L_BRACE '{'
+#define R_BRACE '}'
+#define S_QUOTE '\'';
+
+static void
+write_it(ENTRY * ep)
+{
+ unsigned n;
+ int ch;
+ char *s, *d, *t;
+ char result[MAX_ENTRY_SIZE];
+
+ /*
+ * Look for strings that contain %{number}, convert them to %'char',
+ * which is shorter and runs a little faster.
+ */
+ for (n = 0; n < STRCOUNT; n++) {
+ s = ep->tterm.Strings[n];
+ if (VALID_STRING(s)
+ && strchr(s, L_BRACE) != 0) {
+ d = result;
+ t = s;
+ while ((ch = *t++) != 0) {
+ *d++ = (char) ch;
+ if (ch == '\\') {
+ *d++ = *t++;
+ } else if ((ch == '%')
+ && (*t == L_BRACE)) {
+ char *v = 0;
+ long value = strtol(t + 1, &v, 0);
+ if (v != 0
+ && *v == R_BRACE
+ && value > 0
+ && value != '\\' /* FIXME */
+ && value < 127
+ && isprint((int) value)) {
+ *d++ = S_QUOTE;
+ *d++ = (char) value;
+ *d++ = S_QUOTE;
+ t = (v + 1);
+ }
+ }
+ }
+ *d = 0;
+ if (strlen(result) < strlen(s))
+ strcpy(s, result);
+ }
+ }
+
+ _nc_set_type(_nc_first_name(ep->tterm.term_names));
+ _nc_curr_line = ep->startline;
+ _nc_write_entry(&ep->tterm);
+}
+
+static bool
+immedhook(ENTRY * ep GCC_UNUSED)
+/* write out entries with no use capabilities immediately to save storage */
+{
+#if !HAVE_BIG_CORE
+ /*
+ * This is strictly a core-economy kluge. The really clean way to handle
+ * compilation is to slurp the whole file into core and then do all the
+ * name-collision checks and entry writes in one swell foop. But the
+ * terminfo master file is large enough that some core-poor systems swap
+ * like crazy when you compile it this way...there have been reports of
+ * this process taking *three hours*, rather than the twenty seconds or
+ * less typical on my development box.
+ *
+ * So. This hook *immediately* writes out the referenced entry if it
+ * has no use capabilities. The compiler main loop refrains from
+ * adding the entry to the in-core list when this hook fires. If some
+ * other entry later needs to reference an entry that got written
+ * immediately, that's OK; the resolution code will fetch it off disk
+ * when it can't find it in core.
+ *
+ * Name collisions will still be detected, just not as cleanly. The
+ * write_entry() code complains before overwriting an entry that
+ * postdates the time of tic's first call to write_entry(). Thus
+ * it will complain about overwriting entries newly made during the
+ * tic run, but not about overwriting ones that predate it.
+ *
+ * The reason this is a hook, and not in line with the rest of the
+ * compiler code, is that the support for termcap fallback cannot assume
+ * it has anywhere to spool out these entries!
+ *
+ * The _nc_set_type() call here requires a compensating one in
+ * _nc_parse_entry().
+ *
+ * If you define HAVE_BIG_CORE, you'll disable this kluge. This will
+ * make tic a bit faster (because the resolution code won't have to do
+ * disk I/O nearly as often).
+ */
+ if (ep->nuses == 0) {
+ int oldline = _nc_curr_line;
+
+ write_it(ep);
+ _nc_curr_line = oldline;
+ free(ep->tterm.str_table);
+ return (TRUE);
+ }
+#endif /* HAVE_BIG_CORE */
+ return (FALSE);
+}
+
+static void
+put_translate(int c)
+/* emit a comment char, translating terminfo names to termcap names */
+{
+ static bool in_name = FALSE;
+ static size_t have, used;
+ static char *namebuf, *suffix;
+
+ if (in_name) {
+ if (used + 1 >= have) {
+ have += 132;
+ namebuf = typeRealloc(char, have, namebuf);
+ suffix = typeRealloc(char, have, suffix);
+ }
+ if (c == '\n' || c == '@') {
+ namebuf[used++] = '\0';
+ (void) putchar('<');
+ (void) fputs(namebuf, stdout);
+ putchar(c);
+ in_name = FALSE;
+ } else if (c != '>') {
+ namebuf[used++] = (char) c;
+ } else { /* ah! candidate name! */
+ char *up;
+ NCURSES_CONST char *tp;
+
+ namebuf[used++] = '\0';
+ in_name = FALSE;
+
+ suffix[0] = '\0';
+ if ((up = strchr(namebuf, '#')) != 0
+ || (up = strchr(namebuf, '=')) != 0
+ || ((up = strchr(namebuf, '@')) != 0 && up[1] == '>')) {
+ (void) strcpy(suffix, up);
+ *up = '\0';
+ }
+
+ if ((tp = nametrans(namebuf)) != 0) {
+ (void) putchar(':');
+ (void) fputs(tp, stdout);
+ (void) fputs(suffix, stdout);
+ (void) putchar(':');
+ } else {
+ /* couldn't find a translation, just dump the name */
+ (void) putchar('<');
+ (void) fputs(namebuf, stdout);
+ (void) fputs(suffix, stdout);
+ (void) putchar('>');
+ }
+ }
+ } else {
+ used = 0;
+ if (c == '<') {
+ in_name = TRUE;
+ } else {
+ putchar(c);
+ }
+ }
+}
+
+/* Returns a string, stripped of leading/trailing whitespace */
+static char *
+stripped(char *src)
+{
+ while (isspace(UChar(*src)))
+ src++;
+ if (*src != '\0') {
+ char *dst;
+ size_t len;
+
+ if ((dst = strdup(src)) == NULL)
+ failed("strdup");
+
+ assert(dst != 0);
+
+ len = strlen(dst);
+ while (--len != 0 && isspace(UChar(dst[len])))
+ dst[len] = '\0';
+ return dst;
+ }
+ return 0;
+}
+
+static FILE *
+open_input(const char *filename)
+{
+ FILE *fp = fopen(filename, "r");
+ struct stat sb;
+
+ if (fp == 0) {
+ fprintf(stderr, "%s: Can't open %s\n", _nc_progname, filename);
+ ExitProgram(EXIT_FAILURE);
+ }
+ if (fstat(fileno(fp), &sb) < 0
+ || (sb.st_mode & S_IFMT) != S_IFREG) {
+ fprintf(stderr, "%s: %s is not a file\n", _nc_progname, filename);
+ ExitProgram(EXIT_FAILURE);
+ }
+ return fp;
+}
+
+/* Parse the "-e" option-value into a list of names */
+static char **
+make_namelist(char *src)
+{
+ char **dst = 0;
+
+ char *s, *base;
+ unsigned pass, n, nn;
+ char buffer[BUFSIZ];
+
+ if (src == 0) {
+ /* EMPTY */ ;
+ } else if (strchr(src, '/') != 0) { /* a filename */
+ FILE *fp = open_input(src);
+
+ for (pass = 1; pass <= 2; pass++) {
+ nn = 0;
+ while (fgets(buffer, sizeof(buffer), fp) != 0) {
+ if ((s = stripped(buffer)) != 0) {
+ if (dst != 0)
+ dst[nn] = s;
+ else
+ free(s);
+ nn++;
+ }
+ }
+ if (pass == 1) {
+ dst = typeCalloc(char *, nn + 1);
+ rewind(fp);
+ }
+ }
+ fclose(fp);
+ } else { /* literal list of names */
+ for (pass = 1; pass <= 2; pass++) {
+ for (n = nn = 0, base = src;; n++) {
+ int mark = src[n];
+ if (mark == ',' || mark == '\0') {
+ if (pass == 1) {
+ nn++;
+ } else {
+ src[n] = '\0';
+ if ((s = stripped(base)) != 0)
+ dst[nn++] = s;
+ base = &src[n + 1];
+ }
+ }
+ if (mark == '\0')
+ break;
+ }
+ if (pass == 1)
+ dst = typeCalloc(char *, nn + 1);
+ }
+ }
+ if (showsummary && (dst != 0)) {
+ fprintf(log_fp, "Entries that will be compiled:\n");
+ for (n = 0; dst[n] != 0; n++)
+ fprintf(log_fp, "%u:%s\n", n + 1, dst[n]);
+ }
+ return dst;
+}
+
+static bool
+matches(char **needle, const char *haystack)
+/* does entry in needle list match |-separated field in haystack? */
+{
+ bool code = FALSE;
+ size_t n;
+
+ if (needle != 0) {
+ for (n = 0; needle[n] != 0; n++) {
+ if (_nc_name_match(haystack, needle[n], "|")) {
+ code = TRUE;
+ break;
+ }
+ }
+ } else
+ code = TRUE;
+ return (code);
+}
+
+static FILE *
+open_tempfile(char *name)
+{
+ FILE *result = 0;
+#if HAVE_MKSTEMP
+ int fd = mkstemp(name);
+ if (fd >= 0)
+ result = fdopen(fd, "w");
+#else
+ if (tmpnam(name) != 0)
+ result = fopen(name, "w");
+#endif
+ return result;
+}
+
+int
+main(int argc, char *argv[])
+{
+ char my_tmpname[PATH_MAX];
+ int v_opt = -1, debug_level;
+ int smart_defaults = TRUE;
+ char *termcap;
+ ENTRY *qp;
+
+ int this_opt, last_opt = '?';
+
+ int outform = F_TERMINFO; /* output format */
+ int sortmode = S_TERMINFO; /* sort_mode */
+
+ int width = 60;
+ bool formatted = FALSE; /* reformat complex strings? */
+ bool literal = FALSE; /* suppress post-processing? */
+ int numbers = 0; /* format "%'char'" to/from "%{number}" */
+ bool forceresolve = FALSE; /* force resolution */
+ bool limited = TRUE;
+ char *tversion = (char *) NULL;
+ const char *source_file = "terminfo";
+ char **namelst = 0;
+ char *outdir = (char *) NULL;
+ bool check_only = FALSE;
+ bool suppress_untranslatable = FALSE;
+
+ log_fp = stderr;
+
+ _nc_progname = _nc_rootname(argv[0]);
+
+ if ((infodump = same_program(_nc_progname, PROG_CAPTOINFO)) != FALSE) {
+ outform = F_TERMINFO;
+ sortmode = S_TERMINFO;
+ }
+ if ((capdump = same_program(_nc_progname, PROG_INFOTOCAP)) != FALSE) {
+ outform = F_TERMCAP;
+ sortmode = S_TERMCAP;
+ }
+#if NCURSES_XNAMES
+ use_extended_names(FALSE);
+#endif
+
+ /*
+ * Processing arguments is a little complicated, since someone made a
+ * design decision to allow the numeric values for -w, -v options to
+ * be optional.
+ */
+ while ((this_opt = getopt(argc, argv,
+ "0123456789CILNR:TUVace:fGgo:rstvwx")) != -1) {
+ if (isdigit(this_opt)) {
+ switch (last_opt) {
+ case 'v':
+ v_opt = (v_opt * 10) + (this_opt - '0');
+ break;
+ case 'w':
+ width = (width * 10) + (this_opt - '0');
+ break;
+ default:
+ if (this_opt != '1')
+ usage();
+ last_opt = this_opt;
+ width = 0;
+ }
+ continue;
+ }
+ switch (this_opt) {
+ case 'C':
+ capdump = TRUE;
+ outform = F_TERMCAP;
+ sortmode = S_TERMCAP;
+ break;
+ case 'I':
+ infodump = TRUE;
+ outform = F_TERMINFO;
+ sortmode = S_TERMINFO;
+ break;
+ case 'L':
+ infodump = TRUE;
+ outform = F_VARIABLE;
+ sortmode = S_VARIABLE;
+ break;
+ case 'N':
+ smart_defaults = FALSE;
+ literal = TRUE;
+ break;
+ case 'R':
+ tversion = optarg;
+ break;
+ case 'T':
+ limited = FALSE;
+ break;
+ case 'U':
+ literal = TRUE;
+ break;
+ case 'V':
+ puts(curses_version());
+ cleanup(namelst);
+ ExitProgram(EXIT_SUCCESS);
+ case 'c':
+ check_only = TRUE;
+ break;
+ case 'e':
+ namelst = make_namelist(optarg);
+ break;
+ case 'f':
+ formatted = TRUE;
+ break;
+ case 'G':
+ numbers = 1;
+ break;
+ case 'g':
+ numbers = -1;
+ break;
+ case 'o':
+ outdir = optarg;
+ break;
+ case 'r':
+ forceresolve = TRUE;
+ break;
+ case 's':
+ showsummary = TRUE;
+ break;
+ case 'v':
+ v_opt = 0;
+ break;
+ case 'w':
+ width = 0;
+ break;
+#if NCURSES_XNAMES
+ case 't':
+ _nc_disable_period = FALSE;
+ suppress_untranslatable = TRUE;
+ break;
+ case 'a':
+ _nc_disable_period = TRUE;
+ /* FALLTHRU */
+ case 'x':
+ use_extended_names(TRUE);
+ break;
+#endif
+ default:
+ usage();
+ }
+ last_opt = this_opt;
+ }
+
+ debug_level = (v_opt > 0) ? v_opt : (v_opt == 0);
+ set_trace_level(debug_level);
+
+ if (_nc_tracing) {
+ save_check_termtype = _nc_check_termtype2;
+ _nc_check_termtype2 = check_termtype;
+ }
+#if !HAVE_BIG_CORE
+ /*
+ * Aaargh! immedhook seriously hoses us!
+ *
+ * One problem with immedhook is it means we can't do -e. Problem
+ * is that we can't guarantee that for each terminal listed, all the
+ * terminals it depends on will have been kept in core for reference
+ * resolution -- in fact it's certain the primitive types at the end
+ * of reference chains *won't* be in core unless they were explicitly
+ * in the select list themselves.
+ */
+ if (namelst && (!infodump && !capdump)) {
+ (void) fprintf(stderr,
+ "Sorry, -e can't be used without -I or -C\n");
+ cleanup(namelst);
+ ExitProgram(EXIT_FAILURE);
+ }
+#endif /* HAVE_BIG_CORE */
+
+ if (optind < argc) {
+ source_file = argv[optind++];
+ if (optind < argc) {
+ fprintf(stderr,
+ "%s: Too many file names. Usage:\n\t%s %s",
+ _nc_progname,
+ _nc_progname,
+ usage_string);
+ ExitProgram(EXIT_FAILURE);
+ }
+ } else {
+ if (infodump == TRUE) {
+ /* captoinfo's no-argument case */
+ source_file = "/etc/termcap";
+ if ((termcap = getenv("TERMCAP")) != 0
+ && (namelst = make_namelist(getenv("TERM"))) != 0) {
+ if (access(termcap, F_OK) == 0) {
+ /* file exists */
+ source_file = termcap;
+ } else if ((tmp_fp = open_tempfile(strcpy(my_tmpname,
+ "/tmp/XXXXXX")))
+ != 0) {
+ source_file = my_tmpname;
+ fprintf(tmp_fp, "%s\n", termcap);
+ fclose(tmp_fp);
+ tmp_fp = open_input(source_file);
+ to_remove = source_file;
+ } else {
+ failed("tmpnam");
+ }
+ }
+ } else {
+ /* tic */
+ fprintf(stderr,
+ "%s: File name needed. Usage:\n\t%s %s",
+ _nc_progname,
+ _nc_progname,
+ usage_string);
+ cleanup(namelst);
+ ExitProgram(EXIT_FAILURE);
+ }
+ }
+
+ if (tmp_fp == 0)
+ tmp_fp = open_input(source_file);
+
+ if (infodump)
+ dump_init(tversion,
+ smart_defaults
+ ? outform
+ : F_LITERAL,
+ sortmode, width, debug_level, formatted);
+ else if (capdump)
+ dump_init(tversion,
+ outform,
+ sortmode, width, debug_level, FALSE);
+
+ /* parse entries out of the source file */
+ _nc_set_source(source_file);
+#if !HAVE_BIG_CORE
+ if (!(check_only || infodump || capdump))
+ _nc_set_writedir(outdir);
+#endif /* HAVE_BIG_CORE */
+ _nc_read_entry_source(tmp_fp, (char *) NULL,
+ !smart_defaults || literal, FALSE,
+ ((check_only || infodump || capdump)
+ ? NULLHOOK
+ : immedhook));
+
+ /* do use resolution */
+ if (check_only || (!infodump && !capdump) || forceresolve) {
+ if (!_nc_resolve_uses2(TRUE, literal) && !check_only) {
+ cleanup(namelst);
+ ExitProgram(EXIT_FAILURE);
+ }
+ }
+
+ /* length check */
+ if (check_only && (capdump || infodump)) {
+ for_entry_list(qp) {
+ if (matches(namelst, qp->tterm.term_names)) {
+ int len = fmt_entry(&qp->tterm, NULL, FALSE, TRUE, infodump, numbers);
+
+ if (len > (infodump ? MAX_TERMINFO_LENGTH : MAX_TERMCAP_LENGTH))
+ (void) fprintf(stderr,
+ "warning: resolved %s entry is %d bytes long\n",
+ _nc_first_name(qp->tterm.term_names),
+ len);
+ }
+ }
+ }
+
+ /* write or dump all entries */
+ if (!check_only) {
+ if (!infodump && !capdump) {
+ _nc_set_writedir(outdir);
+ for_entry_list(qp) {
+ if (matches(namelst, qp->tterm.term_names))
+ write_it(qp);
+ }
+ } else {
+ /* this is in case infotocap() generates warnings */
+ _nc_curr_col = _nc_curr_line = -1;
+
+ for_entry_list(qp) {
+ if (matches(namelst, qp->tterm.term_names)) {
+ int j = qp->cend - qp->cstart;
+ int len = 0;
+
+ /* this is in case infotocap() generates warnings */
+ _nc_set_type(_nc_first_name(qp->tterm.term_names));
+
+ (void) fseek(tmp_fp, qp->cstart, SEEK_SET);
+ while (j-- > 0) {
+ if (infodump)
+ (void) putchar(fgetc(tmp_fp));
+ else
+ put_translate(fgetc(tmp_fp));
+ }
+
+ repair_acsc(&qp->tterm);
+ dump_entry(&qp->tterm, suppress_untranslatable,
+ limited, numbers, NULL);
+ for (j = 0; j < (int) qp->nuses; j++)
+ dump_uses(qp->uses[j].name, !capdump);
+ len = show_entry();
+ if (debug_level != 0 && !limited)
+ printf("# length=%d\n", len);
+ }
+ }
+ if (!namelst && _nc_tail) {
+ int c, oldc = '\0';
+ bool in_comment = FALSE;
+ bool trailing_comment = FALSE;
+
+ (void) fseek(tmp_fp, _nc_tail->cend, SEEK_SET);
+ while ((c = fgetc(tmp_fp)) != EOF) {
+ if (oldc == '\n') {
+ if (c == '#') {
+ trailing_comment = TRUE;
+ in_comment = TRUE;
+ } else {
+ in_comment = FALSE;
+ }
+ }
+ if (trailing_comment
+ && (in_comment || (oldc == '\n' && c == '\n')))
+ putchar(c);
+ oldc = c;
+ }
+ }
+ }
+ }
+
+ /* Show the directory into which entries were written, and the total
+ * number of entries
+ */
+ if (showsummary
+ && (!(check_only || infodump || capdump))) {
+ int total = _nc_tic_written();
+ if (total != 0)
+ fprintf(log_fp, "%d entries written to %s\n",
+ total,
+ _nc_tic_dir((char *) 0));
+ else
+ fprintf(log_fp, "No entries written\n");
+ }
+ cleanup(namelst);
+ ExitProgram(EXIT_SUCCESS);
+}
+
+/*
+ * 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 (see comp_parse.c).
+ */
+#undef CUR
+#define CUR tp->
+
+/*
+ * Check if the alternate character-set capabilities are consistent.
+ */
+static void
+check_acs(TERMTYPE *tp)
+{
+ if (VALID_STRING(acs_chars)) {
+ const char *boxes = "lmkjtuvwqxn";
+ char mapped[256];
+ char missing[256];
+ const char *p;
+ char *q;
+
+ memset(mapped, 0, sizeof(mapped));
+ for (p = acs_chars; *p != '\0'; p += 2) {
+ if (p[1] == '\0') {
+ _nc_warning("acsc has odd number of characters");
+ break;
+ }
+ mapped[UChar(p[0])] = p[1];
+ }
+
+ if (mapped[UChar('I')] && !mapped[UChar('i')]) {
+ _nc_warning("acsc refers to 'I', which is probably an error");
+ }
+
+ for (p = boxes, q = missing; *p != '\0'; ++p) {
+ if (!mapped[UChar(p[0])]) {
+ *q++ = p[0];
+ }
+ }
+ *q = '\0';
+
+ assert(strlen(missing) <= strlen(boxes));
+ if (*missing != '\0' && strcmp(missing, boxes)) {
+ _nc_warning("acsc is missing some line-drawing mapping: %s", missing);
+ }
+ }
+}
+
+/*
+ * Check if the color capabilities are consistent
+ */
+static void
+check_colors(TERMTYPE *tp)
+{
+ if ((max_colors > 0) != (max_pairs > 0)
+ || ((max_colors > max_pairs) && (initialize_pair == 0)))
+ _nc_warning("inconsistent values for max_colors (%d) and max_pairs (%d)",
+ max_colors, max_pairs);
+
+ PAIRED(set_foreground, set_background);
+ PAIRED(set_a_foreground, set_a_background);
+ PAIRED(set_color_pair, initialize_pair);
+
+ if (VALID_STRING(set_foreground)
+ && VALID_STRING(set_a_foreground)
+ && !_nc_capcmp(set_foreground, set_a_foreground))
+ _nc_warning("expected setf/setaf to be different");
+
+ if (VALID_STRING(set_background)
+ && VALID_STRING(set_a_background)
+ && !_nc_capcmp(set_background, set_a_background))
+ _nc_warning("expected setb/setab to be different");
+
+ /* see: has_colors() */
+ if (VALID_NUMERIC(max_colors) && VALID_NUMERIC(max_pairs)
+ && (((set_foreground != NULL)
+ && (set_background != NULL))
+ || ((set_a_foreground != NULL)
+ && (set_a_background != NULL))
+ || set_color_pair)) {
+ if (!VALID_STRING(orig_pair) && !VALID_STRING(orig_colors))
+ _nc_warning("expected either op/oc string for resetting colors");
+ }
+}
+
+static char
+keypad_final(const char *string)
+{
+ char result = '\0';
+
+ if (VALID_STRING(string)
+ && *string++ == '\033'
+ && *string++ == 'O'
+ && strlen(string) == 1) {
+ result = *string;
+ }
+
+ return result;
+}
+
+static int
+keypad_index(const char *string)
+{
+ char *test;
+ const char *list = "PQRSwxymtuvlqrsPpn"; /* app-keypad except "Enter" */
+ int ch;
+ int result = -1;
+
+ if ((ch = keypad_final(string)) != '\0') {
+ test = strchr(list, ch);
+ if (test != 0)
+ result = (test - list);
+ }
+ return result;
+}
+
+/*
+ * list[] is down, up, left, right
+ * "left" may be ^H rather than \E[D
+ * "down" may be ^J rather than \E[B
+ * But up/right are generally consistently escape sequences for ANSI terminals.
+ */
+static void
+check_ansi_cursor(char *list[4])
+{
+ int j, k;
+ int want;
+ size_t prefix = 0;
+ size_t suffix;
+ bool skip[4];
+ bool repeated = FALSE;
+
+ for (j = 0; j < 4; ++j) {
+ skip[j] = FALSE;
+ for (k = 0; k < j; ++k) {
+ if (j != k
+ && !strcmp(list[j], list[k])) {
+ char *value = _nc_tic_expand(list[k], TRUE, 0);
+ _nc_warning("repeated cursor control %s\n", value);
+ repeated = TRUE;
+ }
+ }
+ }
+ if (!repeated) {
+ char *up = list[1];
+
+ if (UChar(up[0]) == '\033') {
+ if (up[1] == '[') {
+ prefix = 2;
+ } else {
+ prefix = 1;
+ }
+ } else if (UChar(up[0]) == UChar('\233')) {
+ prefix = 1;
+ }
+ if (prefix) {
+ suffix = prefix;
+ while (up[suffix] && isdigit(UChar(up[suffix])))
+ ++suffix;
+ }
+ if (prefix && up[suffix] == 'A') {
+ skip[1] = TRUE;
+ if (!strcmp(list[0], "\n"))
+ skip[0] = TRUE;
+ if (!strcmp(list[2], "\b"))
+ skip[2] = TRUE;
+
+ for (j = 0; j < 4; ++j) {
+ if (skip[j] || strlen(list[j]) == 1)
+ continue;
+ if (memcmp(list[j], up, prefix)) {
+ char *value = _nc_tic_expand(list[j], TRUE, 0);
+ _nc_warning("inconsistent prefix for %s\n", value);
+ continue;
+ }
+ if (strlen(list[j]) < suffix) {
+ char *value = _nc_tic_expand(list[j], TRUE, 0);
+ _nc_warning("inconsistent length for %s, expected %d\n",
+ value, (int) suffix + 1);
+ continue;
+ }
+ want = "BADC"[j];
+ if (list[j][suffix] != want) {
+ char *value = _nc_tic_expand(list[j], TRUE, 0);
+ _nc_warning("inconsistent suffix for %s, expected %c, have %c\n",
+ value, want, list[j][suffix]);
+ }
+ }
+ }
+ }
+}
+
+#define EXPECTED(name) if (!PRESENT(name)) _nc_warning("expected " #name)
+
+static void
+check_cursor(TERMTYPE *tp)
+{
+ int count;
+ char *list[4];
+
+ /* if we have a parameterized form, then the non-parameterized is easy */
+ ANDMISSING(parm_down_cursor, cursor_down);
+ ANDMISSING(parm_up_cursor, cursor_up);
+ ANDMISSING(parm_left_cursor, cursor_left);
+ ANDMISSING(parm_right_cursor, cursor_right);
+
+ /* Given any of a set of cursor movement, the whole set should be present.
+ * Technically this is not true (we could use cursor_address to fill in
+ * unsupported controls), but it is likely.
+ */
+ count = 0;
+ if (PRESENT(parm_down_cursor)) {
+ list[count++] = parm_down_cursor;
+ }
+ if (PRESENT(parm_up_cursor)) {
+ list[count++] = parm_up_cursor;
+ }
+ if (PRESENT(parm_left_cursor)) {
+ list[count++] = parm_left_cursor;
+ }
+ if (PRESENT(parm_right_cursor)) {
+ list[count++] = parm_right_cursor;
+ }
+ if (count == 4) {
+ check_ansi_cursor(list);
+ } else if (count != 0) {
+ EXPECTED(parm_down_cursor);
+ EXPECTED(parm_up_cursor);
+ EXPECTED(parm_left_cursor);
+ EXPECTED(parm_right_cursor);
+ }
+
+ count = 0;
+ if (PRESENT(cursor_down)) {
+ list[count++] = cursor_down;
+ }
+ if (PRESENT(cursor_up)) {
+ list[count++] = cursor_up;
+ }
+ if (PRESENT(cursor_left)) {
+ list[count++] = cursor_left;
+ }
+ if (PRESENT(cursor_right)) {
+ list[count++] = cursor_right;
+ }
+ if (count == 4) {
+ check_ansi_cursor(list);
+ } else if (count != 0) {
+ count = 0;
+ if (PRESENT(cursor_down) && strcmp(cursor_down, "\n"))
+ ++count;
+ if (PRESENT(cursor_left) && strcmp(cursor_left, "\b"))
+ ++count;
+ if (PRESENT(cursor_up) && strlen(cursor_up) > 1)
+ ++count;
+ if (PRESENT(cursor_right) && strlen(cursor_right) > 1)
+ ++count;
+ if (count) {
+ EXPECTED(cursor_down);
+ EXPECTED(cursor_up);
+ EXPECTED(cursor_left);
+ EXPECTED(cursor_right);
+ }
+ }
+}
+
+#define MAX_KP 5
+/*
+ * Do a quick sanity-check for vt100-style keypads to see if the 5-key keypad
+ * is mapped inconsistently.
+ */
+static void
+check_keypad(TERMTYPE *tp)
+{
+ char show[80];
+
+ if (VALID_STRING(key_a1) &&
+ VALID_STRING(key_a3) &&
+ VALID_STRING(key_b2) &&
+ VALID_STRING(key_c1) &&
+ VALID_STRING(key_c3)) {
+ char final[MAX_KP + 1];
+ int list[MAX_KP];
+ int increase = 0;
+ int j, k, kk;
+ int last;
+ int test;
+
+ final[0] = keypad_final(key_a1);
+ final[1] = keypad_final(key_a3);
+ final[2] = keypad_final(key_b2);
+ final[3] = keypad_final(key_c1);
+ final[4] = keypad_final(key_c3);
+ final[5] = '\0';
+
+ /* special case: legacy coding using 1,2,3,0,. on the bottom */
+ assert(strlen(final) <= MAX_KP);
+ if (!strcmp(final, "qsrpn"))
+ return;
+
+ list[0] = keypad_index(key_a1);
+ list[1] = keypad_index(key_a3);
+ list[2] = keypad_index(key_b2);
+ list[3] = keypad_index(key_c1);
+ list[4] = keypad_index(key_c3);
+
+ /* check that they're all vt100 keys */
+ for (j = 0; j < MAX_KP; ++j) {
+ if (list[j] < 0) {
+ return;
+ }
+ }
+
+ /* check if they're all in increasing order */
+ for (j = 1; j < MAX_KP; ++j) {
+ if (list[j] > list[j - 1]) {
+ ++increase;
+ }
+ }
+ if (increase != (MAX_KP - 1)) {
+ show[0] = '\0';
+
+ for (j = 0, last = -1; j < MAX_KP; ++j) {
+ for (k = 0, kk = -1, test = 100; k < 5; ++k) {
+ if (list[k] > last &&
+ list[k] < test) {
+ test = list[k];
+ kk = k;
+ }
+ }
+ last = test;
+ assert(strlen(show) < (MAX_KP * 4));
+ switch (kk) {
+ case 0:
+ strcat(show, " ka1");
+ break;
+ case 1:
+ strcat(show, " ka3");
+ break;
+ case 2:
+ strcat(show, " kb2");
+ break;
+ case 3:
+ strcat(show, " kc1");
+ break;
+ case 4:
+ strcat(show, " kc3");
+ break;
+ }
+ }
+
+ _nc_warning("vt100 keypad order inconsistent: %s", show);
+ }
+
+ } else if (VALID_STRING(key_a1) ||
+ VALID_STRING(key_a3) ||
+ VALID_STRING(key_b2) ||
+ VALID_STRING(key_c1) ||
+ VALID_STRING(key_c3)) {
+ show[0] = '\0';
+ if (keypad_index(key_a1) >= 0)
+ strcat(show, " ka1");
+ if (keypad_index(key_a3) >= 0)
+ strcat(show, " ka3");
+ if (keypad_index(key_b2) >= 0)
+ strcat(show, " kb2");
+ if (keypad_index(key_c1) >= 0)
+ strcat(show, " kc1");
+ if (keypad_index(key_c3) >= 0)
+ strcat(show, " kc3");
+ if (*show != '\0')
+ _nc_warning("vt100 keypad map incomplete:%s", show);
+ }
+}
+
+static void
+check_printer(TERMTYPE *tp)
+{
+ PAIRED(enter_doublewide_mode, exit_doublewide_mode);
+ PAIRED(enter_italics_mode, exit_italics_mode);
+ PAIRED(enter_leftward_mode, exit_leftward_mode);
+ PAIRED(enter_micro_mode, exit_micro_mode);
+ PAIRED(enter_shadow_mode, exit_shadow_mode);
+ PAIRED(enter_subscript_mode, exit_subscript_mode);
+ PAIRED(enter_superscript_mode, exit_superscript_mode);
+ PAIRED(enter_upward_mode, exit_upward_mode);
+
+ ANDMISSING(start_char_set_def, stop_char_set_def);
+
+ /* if we have a parameterized form, then the non-parameterized is easy */
+ ANDMISSING(set_bottom_margin_parm, set_bottom_margin);
+ ANDMISSING(set_left_margin_parm, set_left_margin);
+ ANDMISSING(set_right_margin_parm, set_right_margin);
+ ANDMISSING(set_top_margin_parm, set_top_margin);
+
+ ANDMISSING(parm_down_micro, micro_down);
+ ANDMISSING(parm_left_micro, micro_left);
+ ANDMISSING(parm_right_micro, micro_right);
+ ANDMISSING(parm_up_micro, micro_up);
+}
+
+/*
+ * Returns the expected number of parameters for the given capability.
+ */
+static int
+expected_params(const char *name)
+{
+ /* *INDENT-OFF* */
+ static const struct {
+ const char *name;
+ int count;
+ } table[] = {
+ { "S0", 1 }, /* 'screen' extension */
+ { "birep", 2 },
+ { "chr", 1 },
+ { "colornm", 1 },
+ { "cpi", 1 },
+ { "csnm", 1 },
+ { "csr", 2 },
+ { "cub", 1 },
+ { "cud", 1 },
+ { "cuf", 1 },
+ { "cup", 2 },
+ { "cuu", 1 },
+ { "cvr", 1 },
+ { "cwin", 5 },
+ { "dch", 1 },
+ { "defc", 3 },
+ { "dial", 1 },
+ { "dispc", 1 },
+ { "dl", 1 },
+ { "ech", 1 },
+ { "getm", 1 },
+ { "hpa", 1 },
+ { "ich", 1 },
+ { "il", 1 },
+ { "indn", 1 },
+ { "initc", 4 },
+ { "initp", 7 },
+ { "lpi", 1 },
+ { "mc5p", 1 },
+ { "mrcup", 2 },
+ { "mvpa", 1 },
+ { "pfkey", 2 },
+ { "pfloc", 2 },
+ { "pfx", 2 },
+ { "pfxl", 3 },
+ { "pln", 2 },
+ { "qdial", 1 },
+ { "rcsd", 1 },
+ { "rep", 2 },
+ { "rin", 1 },
+ { "sclk", 3 },
+ { "scp", 1 },
+ { "scs", 1 },
+ { "scsd", 2 },
+ { "setab", 1 },
+ { "setaf", 1 },
+ { "setb", 1 },
+ { "setcolor", 1 },
+ { "setf", 1 },
+ { "sgr", 9 },
+ { "sgr1", 6 },
+ { "slength", 1 },
+ { "slines", 1 },
+ { "smgbp", 1 }, /* 2 if smgtp is not given */
+ { "smglp", 1 },
+ { "smglr", 2 },
+ { "smgrp", 1 },
+ { "smgtb", 2 },
+ { "smgtp", 1 },
+ { "tsl", 1 },
+ { "u6", -1 },
+ { "vpa", 1 },
+ { "wind", 4 },
+ { "wingo", 1 },
+ };
+ /* *INDENT-ON* */
+
+ unsigned n;
+ int result = 0; /* function-keys, etc., use none */
+
+ for (n = 0; n < SIZEOF(table); n++) {
+ if (!strcmp(name, table[n].name)) {
+ result = table[n].count;
+ break;
+ }
+ }
+
+ return result;
+}
+
+/*
+ * Make a quick sanity check for the parameters which are used in the given
+ * strings. If there are no "%p" tokens, then there should be no other "%"
+ * markers.
+ */
+static void
+check_params(TERMTYPE *tp, const char *name, char *value)
+{
+ int expected = expected_params(name);
+ int actual = 0;
+ int n;
+ bool params[10];
+ char *s = value;
+
+#ifdef set_top_margin_parm
+ if (!strcmp(name, "smgbp")
+ && set_top_margin_parm == 0)
+ expected = 2;
+#endif
+
+ for (n = 0; n < 10; n++)
+ params[n] = FALSE;
+
+ while (*s != 0) {
+ if (*s == '%') {
+ if (*++s == '\0') {
+ _nc_warning("expected character after %% in %s", name);
+ break;
+ } else if (*s == 'p') {
+ if (*++s == '\0' || !isdigit((int) *s)) {
+ _nc_warning("expected digit after %%p in %s", name);
+ return;
+ } else {
+ n = (*s - '0');
+ if (n > actual)
+ actual = n;
+ params[n] = TRUE;
+ }
+ }
+ }
+ s++;
+ }
+
+ if (params[0]) {
+ _nc_warning("%s refers to parameter 0 (%%p0), which is not allowed", name);
+ }
+ if (value == set_attributes || expected < 0) {
+ ;
+ } else if (expected != actual) {
+ _nc_warning("%s uses %d parameters, expected %d", name,
+ actual, expected);
+ for (n = 1; n < actual; n++) {
+ if (!params[n])
+ _nc_warning("%s omits parameter %d", name, n);
+ }
+ }
+}
+
+static char *
+skip_delay(char *s)
+{
+ while (*s == '/' || isdigit(UChar(*s)))
+ ++s;
+ return s;
+}
+
+/*
+ * Skip a delay altogether, e.g., when comparing a simple string to sgr,
+ * the latter may have a worst-case delay on the end.
+ */
+static char *
+ignore_delays(char *s)
+{
+ int delaying = 0;
+
+ do {
+ switch (*s) {
+ case '$':
+ if (delaying == 0)
+ delaying = 1;
+ break;
+ case '<':
+ if (delaying == 1)
+ delaying = 2;
+ break;
+ case '\0':
+ delaying = 0;
+ break;
+ default:
+ if (delaying) {
+ s = skip_delay(s);
+ if (*s == '>')
+ ++s;
+ delaying = 0;
+ }
+ break;
+ }
+ if (delaying)
+ ++s;
+ } while (delaying);
+ return s;
+}
+
+/*
+ * An sgr string may contain several settings other than the one we're
+ * interested in, essentially sgr0 + rmacs + whatever. As long as the
+ * "whatever" is contained in the sgr string, that is close enough for our
+ * sanity check.
+ */
+static bool
+similar_sgr(int num, char *a, char *b)
+{
+ static const char *names[] =
+ {
+ "none"
+ ,"standout"
+ ,"underline"
+ ,"reverse"
+ ,"blink"
+ ,"dim"
+ ,"bold"
+ ,"invis"
+ ,"protect"
+ ,"altcharset"
+ };
+ char *base_a = a;
+ char *base_b = b;
+ int delaying = 0;
+
+ while (*b != 0) {
+ while (*a != *b) {
+ if (*a == 0) {
+ if (b[0] == '$'
+ && b[1] == '<') {
+ _nc_warning("Did not find delay %s", _nc_visbuf(b));
+ } else {
+ _nc_warning("checking sgr(%s) %s\n\tcompare to %s\n\tunmatched %s",
+ names[num], _nc_visbuf2(1, base_a),
+ _nc_visbuf2(2, base_b),
+ _nc_visbuf2(3, b));
+ }
+ return FALSE;
+ } else if (delaying) {
+ a = skip_delay(a);
+ b = skip_delay(b);
+ } else if ((*b == '0' || (*b == ';')) && *a == 'm') {
+ b++;
+ } else {
+ a++;
+ }
+ }
+ switch (*a) {
+ case '$':
+ if (delaying == 0)
+ delaying = 1;
+ break;
+ case '<':
+ if (delaying == 1)
+ delaying = 2;
+ break;
+ default:
+ delaying = 0;
+ break;
+ }
+ a++;
+ b++;
+ }
+ /* ignore delays on the end of the string */
+ a = ignore_delays(a);
+ return ((num != 0) || (*a == 0));
+}
+
+static char *
+check_sgr(TERMTYPE *tp, char *zero, int num, char *cap, const char *name)
+{
+ char *test;
+
+ _nc_tparm_err = 0;
+ test = TPARM_9(set_attributes,
+ num == 1,
+ num == 2,
+ num == 3,
+ num == 4,
+ num == 5,
+ num == 6,
+ num == 7,
+ num == 8,
+ num == 9);
+ if (test != 0) {
+ if (PRESENT(cap)) {
+ if (!similar_sgr(num, test, cap)) {
+ _nc_warning("%s differs from sgr(%d)\n\t%s=%s\n\tsgr(%d)=%s",
+ name, num,
+ name, _nc_visbuf2(1, cap),
+ num, _nc_visbuf2(2, test));
+ }
+ } else if (_nc_capcmp(test, zero)) {
+ _nc_warning("sgr(%d) present, but not %s", num, name);
+ }
+ } else if (PRESENT(cap)) {
+ _nc_warning("sgr(%d) missing, but %s present", num, name);
+ }
+ if (_nc_tparm_err)
+ _nc_warning("stack error in sgr(%d) string", num);
+ return test;
+}
+
+#define CHECK_SGR(num,name) check_sgr(tp, zero, num, name, #name)
+
+#ifdef TRACE
+/*
+ * If tic is compiled with TRACE, we'll be able to see the output from the
+ * DEBUG() macro. But since it doesn't use traceon(), it always goes to
+ * the standard error. Use this function to make it simpler to follow the
+ * resulting debug traces.
+ */
+static void
+show_where(unsigned level)
+{
+ if (_nc_tracing >= DEBUG_LEVEL(level)) {
+ char my_name[256];
+ _nc_get_type(my_name);
+ _tracef("\"%s\", line %d, '%s'",
+ _nc_get_source(),
+ _nc_curr_line, my_name);
+ }
+}
+
+#else
+#define show_where(level) /* nothing */
+#endif
+
+/* other sanity-checks (things that we don't want in the normal
+ * logic that reads a terminfo entry)
+ */
+static void
+check_termtype(TERMTYPE *tp, bool literal)
+{
+ bool conflict = FALSE;
+ unsigned j, k;
+ char fkeys[STRCOUNT];
+
+ /*
+ * A terminal entry may contain more than one keycode assigned to
+ * a given string (e.g., KEY_END and KEY_LL). But curses will only
+ * return one (the last one assigned).
+ */
+ if (!(_nc_syntax == SYN_TERMCAP && capdump)) {
+ memset(fkeys, 0, sizeof(fkeys));
+ for (j = 0; _nc_tinfo_fkeys[j].code; j++) {
+ char *a = tp->Strings[_nc_tinfo_fkeys[j].offset];
+ bool first = TRUE;
+ if (!VALID_STRING(a))
+ continue;
+ for (k = j + 1; _nc_tinfo_fkeys[k].code; k++) {
+ char *b = tp->Strings[_nc_tinfo_fkeys[k].offset];
+ if (!VALID_STRING(b)
+ || fkeys[k])
+ continue;
+ if (!_nc_capcmp(a, b)) {
+ fkeys[j] = 1;
+ fkeys[k] = 1;
+ if (first) {
+ if (!conflict) {
+ _nc_warning("Conflicting key definitions (using the last)");
+ conflict = TRUE;
+ }
+ fprintf(stderr, "... %s is the same as %s",
+ keyname((int) _nc_tinfo_fkeys[j].code),
+ keyname((int) _nc_tinfo_fkeys[k].code));
+ first = FALSE;
+ } else {
+ fprintf(stderr, ", %s",
+ keyname((int) _nc_tinfo_fkeys[k].code));
+ }
+ }
+ }
+ if (!first)
+ fprintf(stderr, "\n");
+ }
+ }
+
+ for (j = 0; j < NUM_STRINGS(tp); j++) {
+ char *a = tp->Strings[j];
+ if (VALID_STRING(a))
+ check_params(tp, ExtStrname(tp, j, strnames), a);
+ }
+
+ check_acs(tp);
+ check_colors(tp);
+ check_cursor(tp);
+ check_keypad(tp);
+ check_printer(tp);
+
+ /*
+ * These may be mismatched because the terminal description relies on
+ * restoring the cursor visibility by resetting it.
+ */
+ ANDMISSING(cursor_invisible, cursor_normal);
+ ANDMISSING(cursor_visible, cursor_normal);
+
+ if (PRESENT(cursor_visible) && PRESENT(cursor_normal)
+ && !_nc_capcmp(cursor_visible, cursor_normal))
+ _nc_warning("cursor_visible is same as cursor_normal");
+
+ /*
+ * From XSI & O'Reilly, we gather that sc/rc are required if csr is
+ * given, because the cursor position after the scrolling operation is
+ * performed is undefined.
+ */
+ ANDMISSING(change_scroll_region, save_cursor);
+ ANDMISSING(change_scroll_region, restore_cursor);
+
+ /*
+ * If we can clear tabs, we should be able to initialize them.
+ */
+ ANDMISSING(clear_all_tabs, set_tab);
+
+ if (PRESENT(set_attributes)) {
+ char *zero = 0;
+
+ _nc_tparm_err = 0;
+ if (PRESENT(exit_attribute_mode)) {
+ zero = strdup(CHECK_SGR(0, exit_attribute_mode));
+ } else {
+ zero = strdup(TPARM_9(set_attributes, 0, 0, 0, 0, 0, 0, 0, 0, 0));
+ }
+ if (_nc_tparm_err)
+ _nc_warning("stack error in sgr(0) string");
+
+ if (zero != 0) {
+ CHECK_SGR(1, enter_standout_mode);
+ CHECK_SGR(2, enter_underline_mode);
+ CHECK_SGR(3, enter_reverse_mode);
+ CHECK_SGR(4, enter_blink_mode);
+ CHECK_SGR(5, enter_dim_mode);
+ CHECK_SGR(6, enter_bold_mode);
+ CHECK_SGR(7, enter_secure_mode);
+ CHECK_SGR(8, enter_protected_mode);
+ CHECK_SGR(9, enter_alt_charset_mode);
+ free(zero);
+ } else {
+ _nc_warning("sgr(0) did not return a value");
+ }
+ } else if (PRESENT(exit_attribute_mode) &&
+ set_attributes != CANCELLED_STRING) {
+ if (_nc_syntax == SYN_TERMINFO)
+ _nc_warning("missing sgr string");
+ }
+
+ if (PRESENT(exit_attribute_mode)) {
+ char *check_sgr0 = _nc_trim_sgr0(tp);
+
+ if (check_sgr0 == 0 || *check_sgr0 == '\0') {
+ _nc_warning("trimmed sgr0 is empty");
+ } else {
+ show_where(2);
+ if (check_sgr0 != exit_attribute_mode) {
+ DEBUG(2,
+ ("will trim sgr0\n\toriginal sgr0=%s\n\ttrimmed sgr0=%s",
+ _nc_visbuf2(1, exit_attribute_mode),
+ _nc_visbuf2(2, check_sgr0)));
+ free(check_sgr0);
+ } else {
+ DEBUG(2,
+ ("will not trim sgr0\n\toriginal sgr0=%s",
+ _nc_visbuf(exit_attribute_mode)));
+ }
+ }
+ }
+#ifdef TRACE
+ show_where(2);
+ if (!auto_right_margin) {
+ DEBUG(2,
+ ("can write to lower-right directly"));
+ } else if (PRESENT(enter_am_mode) && PRESENT(exit_am_mode)) {
+ DEBUG(2,
+ ("can write to lower-right by suppressing automargin"));
+ } else if ((PRESENT(enter_insert_mode) && PRESENT(exit_insert_mode))
+ || PRESENT(insert_character) || PRESENT(parm_ich)) {
+ DEBUG(2,
+ ("can write to lower-right by using inserts"));
+ } else {
+ DEBUG(2,
+ ("cannot write to lower-right"));
+ }
+#endif
+
+ /*
+ * Some standard applications (e.g., vi) and some non-curses
+ * applications (e.g., jove) get confused if we have both ich1 and
+ * smir/rmir. Let's be nice and warn about that, too, even though
+ * ncurses handles it.
+ */
+ if ((PRESENT(enter_insert_mode) || PRESENT(exit_insert_mode))
+ && PRESENT(parm_ich)) {
+ _nc_warning("non-curses applications may be confused by ich1 with smir/rmir");
+ }
+
+ /*
+ * Finally, do the non-verbose checks
+ */
+ if (save_check_termtype != 0)
+ save_check_termtype(tp, literal);
+}
diff --git a/progs/toe.c b/progs/toe.c
new file mode 100644
index 0000000..6f45992
--- /dev/null
+++ b/progs/toe.c
@@ -0,0 +1,525 @@
+/****************************************************************************
+ * Copyright (c) 1998-2008,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: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 *
+ * and: Eric S. Raymond <esr@snark.thyrsus.com> *
+ * and: Thomas E. Dickey 1996-on *
+ ****************************************************************************/
+
+/*
+ * toe.c --- table of entries report generator
+ */
+
+#include <progs.priv.h>
+
+#include <sys/stat.h>
+
+#if USE_HASHED_DB
+#include <hashed_db.h>
+#endif
+
+MODULE_ID("$Id: toe.c,v 1.52 2010/05/01 22:04:08 tom Exp $")
+
+#define isDotname(name) (!strcmp(name, ".") || !strcmp(name, ".."))
+
+const char *_nc_progname;
+
+#if NO_LEAKS
+#undef ExitProgram
+static void ExitProgram(int code) GCC_NORETURN;
+static void
+ExitProgram(int code)
+{
+ _nc_free_entries(_nc_head);
+ _nc_free_tic(code);
+}
+#endif
+
+static void
+failed(const char *msg)
+{
+ perror(msg);
+ ExitProgram(EXIT_FAILURE);
+}
+
+#if USE_HASHED_DB
+static bool
+make_db_name(char *dst, const char *src, unsigned limit)
+{
+ static const char suffix[] = DBM_SUFFIX;
+
+ bool result = FALSE;
+ unsigned lens = sizeof(suffix) - 1;
+ unsigned size = strlen(src);
+ unsigned need = lens + size;
+
+ if (need <= limit) {
+ if (size >= lens
+ && !strcmp(src + size - lens, suffix))
+ (void) strcpy(dst, src);
+ else
+ (void) sprintf(dst, "%s%s", src, suffix);
+ result = TRUE;
+ }
+ return result;
+}
+#endif
+
+static bool
+is_database(const char *path)
+{
+ bool result = FALSE;
+#if USE_DATABASE
+ if (_nc_is_dir_path(path) && access(path, R_OK | X_OK) == 0) {
+ result = TRUE;
+ }
+#endif
+#if USE_TERMCAP
+ if (_nc_is_file_path(path) && access(path, R_OK) == 0) {
+ result = TRUE;
+ }
+#endif
+#if USE_HASHED_DB
+ if (!result) {
+ char filename[PATH_MAX];
+ if (_nc_is_file_path(path) && access(path, R_OK) == 0) {
+ result = TRUE;
+ } else if (make_db_name(filename, path, sizeof(filename))) {
+ if (_nc_is_file_path(filename) && access(filename, R_OK) == 0) {
+ result = TRUE;
+ }
+ }
+ }
+#endif
+ return result;
+}
+
+static void
+deschook(const char *cn, TERMTYPE *tp)
+/* display a description for the type */
+{
+ const char *desc;
+
+ if ((desc = strrchr(tp->term_names, '|')) == 0 || *++desc == '\0')
+ desc = "(No description)";
+
+ (void) printf("%-10s\t%s\n", cn, desc);
+}
+
+#if USE_TERMCAP
+static void
+show_termcap(char *buffer,
+ void (*hook) (const char *, TERMTYPE *tp))
+{
+ TERMTYPE data;
+ char *next = strchr(buffer, ':');
+ char *last;
+ char *list = buffer;
+
+ if (next)
+ *next = '\0';
+
+ last = strrchr(buffer, '|');
+ if (last)
+ ++last;
+
+ data.term_names = strdup(buffer);
+ while ((next = strtok(list, "|")) != 0) {
+ if (next != last)
+ hook(next, &data);
+ list = 0;
+ }
+ free(data.term_names);
+}
+#endif
+
+static int
+typelist(int eargc, char *eargv[],
+ bool verbosity,
+ void (*hook) (const char *, TERMTYPE *tp))
+/* apply a function to each entry in given terminfo directories */
+{
+ int i;
+
+ for (i = 0; i < eargc; i++) {
+#if USE_DATABASE
+ if (_nc_is_dir_path(eargv[i])) {
+ char *cwd_buf = 0;
+ DIR *termdir;
+ DIRENT *subdir;
+
+ if ((termdir = opendir(eargv[i])) == 0) {
+ (void) fflush(stdout);
+ (void) fprintf(stderr,
+ "%s: can't open terminfo directory %s\n",
+ _nc_progname, eargv[i]);
+ return (EXIT_FAILURE);
+ } else if (verbosity)
+ (void) printf("#\n#%s:\n#\n", eargv[i]);
+
+ while ((subdir = readdir(termdir)) != 0) {
+ size_t len = NAMLEN(subdir);
+ size_t cwd_len = len + strlen(eargv[i]) + 3;
+ char name_1[PATH_MAX];
+ DIR *entrydir;
+ DIRENT *entry;
+
+ cwd_buf = typeRealloc(char, cwd_len, cwd_buf);
+ if (cwd_buf == 0)
+ failed("realloc cwd_buf");
+
+ assert(cwd_buf != 0);
+
+ strncpy(name_1, subdir->d_name, len)[len] = '\0';
+ if (isDotname(name_1))
+ continue;
+
+ (void) sprintf(cwd_buf, "%s/%.*s/", eargv[i], (int) len, name_1);
+ if (chdir(cwd_buf) != 0)
+ continue;
+
+ entrydir = opendir(".");
+ if (entrydir == 0) {
+ perror(cwd_buf);
+ continue;
+ }
+ while ((entry = readdir(entrydir)) != 0) {
+ char name_2[PATH_MAX];
+ TERMTYPE lterm;
+ char *cn;
+ int status;
+
+ len = NAMLEN(entry);
+ strncpy(name_2, entry->d_name, len)[len] = '\0';
+ if (isDotname(name_2) || !_nc_is_file_path(name_2))
+ continue;
+
+ status = _nc_read_file_entry(name_2, &lterm);
+ if (status <= 0) {
+ (void) fflush(stdout);
+ (void) fprintf(stderr,
+ "%s: couldn't open terminfo file %s.\n",
+ _nc_progname, name_2);
+ return (EXIT_FAILURE);
+ }
+
+ /* only visit things once, by primary name */
+ cn = _nc_first_name(lterm.term_names);
+ if (!strcmp(cn, name_2)) {
+ /* apply the selected hook function */
+ (*hook) (cn, &lterm);
+ }
+ _nc_free_termtype(&lterm);
+ }
+ closedir(entrydir);
+ }
+ closedir(termdir);
+ if (cwd_buf != 0)
+ free(cwd_buf);
+ }
+#if USE_HASHED_DB
+ else {
+ DB *capdbp;
+ char filename[PATH_MAX];
+
+ if (make_db_name(filename, eargv[i], sizeof(filename))) {
+ if ((capdbp = _nc_db_open(filename, FALSE)) != 0) {
+ DBT key, data;
+ int code;
+
+ code = _nc_db_first(capdbp, &key, &data);
+ while (code == 0) {
+ TERMTYPE lterm;
+ int used;
+ char *have;
+ char *cn;
+
+ if (_nc_db_have_data(&key, &data, &have, &used)) {
+ if (_nc_read_termtype(&lterm, have, used) > 0) {
+ /* only visit things once, by primary name */
+ cn = _nc_first_name(lterm.term_names);
+ /* apply the selected hook function */
+ (*hook) (cn, &lterm);
+ _nc_free_termtype(&lterm);
+ }
+ }
+ code = _nc_db_next(capdbp, &key, &data);
+ }
+
+ _nc_db_close(capdbp);
+ }
+ }
+ }
+#endif
+#endif
+#if USE_TERMCAP
+#if HAVE_BSD_CGETENT
+ char *db_array[2];
+ char *buffer = 0;
+
+ if (verbosity)
+ (void) printf("#\n#%s:\n#\n", eargv[i]);
+
+ db_array[0] = eargv[i];
+ db_array[1] = 0;
+
+ if (cgetfirst(&buffer, db_array)) {
+ show_termcap(buffer, hook);
+ free(buffer);
+ while (cgetnext(&buffer, db_array)) {
+ show_termcap(buffer, hook);
+ free(buffer);
+ }
+ }
+ cgetclose();
+#else
+ /* scan termcap text-file only */
+ if (_nc_is_file_path(eargv[i])) {
+ char buffer[2048];
+ FILE *fp;
+
+ if ((fp = fopen(eargv[i], "r")) != 0) {
+ while (fgets(buffer, sizeof(buffer), fp) != 0) {
+ if (*buffer == '#')
+ continue;
+ if (isspace(*buffer))
+ continue;
+ show_termcap(buffer, hook);
+ }
+ fclose(fp);
+ }
+ }
+#endif
+#endif
+ }
+
+ return (EXIT_SUCCESS);
+}
+
+static void
+usage(void)
+{
+ (void) fprintf(stderr, "usage: %s [-ahuUV] [-v n] [file...]\n", _nc_progname);
+ ExitProgram(EXIT_FAILURE);
+}
+
+int
+main(int argc, char *argv[])
+{
+ bool all_dirs = FALSE;
+ bool direct_dependencies = FALSE;
+ bool invert_dependencies = FALSE;
+ bool header = FALSE;
+ char *report_file = 0;
+ unsigned i;
+ int code;
+ int this_opt, last_opt = '?';
+ int v_opt = 0;
+
+ _nc_progname = _nc_rootname(argv[0]);
+
+ while ((this_opt = getopt(argc, argv, "0123456789ahu:vU:V")) != -1) {
+ /* handle optional parameter */
+ if (isdigit(this_opt)) {
+ switch (last_opt) {
+ case 'v':
+ v_opt = (this_opt - '0');
+ break;
+ default:
+ if (isdigit(last_opt))
+ v_opt *= 10;
+ else
+ v_opt = 0;
+ v_opt += (this_opt - '0');
+ last_opt = this_opt;
+ }
+ continue;
+ }
+ switch (this_opt) {
+ case 'a':
+ all_dirs = TRUE;
+ break;
+ case 'h':
+ header = TRUE;
+ break;
+ case 'u':
+ direct_dependencies = TRUE;
+ report_file = optarg;
+ break;
+ case 'v':
+ v_opt = 1;
+ break;
+ case 'U':
+ invert_dependencies = TRUE;
+ report_file = optarg;
+ break;
+ case 'V':
+ puts(curses_version());
+ ExitProgram(EXIT_SUCCESS);
+ default:
+ usage();
+ }
+ }
+ set_trace_level(v_opt);
+
+ if (report_file != 0) {
+ if (freopen(report_file, "r", stdin) == 0) {
+ (void) fflush(stdout);
+ fprintf(stderr, "%s: can't open %s\n", _nc_progname, report_file);
+ ExitProgram(EXIT_FAILURE);
+ }
+
+ /* parse entries out of the source file */
+ _nc_set_source(report_file);
+ _nc_read_entry_source(stdin, 0, FALSE, FALSE, NULLHOOK);
+ }
+
+ /* maybe we want a direct-dependency listing? */
+ if (direct_dependencies) {
+ ENTRY *qp;
+
+ for_entry_list(qp) {
+ if (qp->nuses) {
+ unsigned j;
+
+ (void) printf("%s:", _nc_first_name(qp->tterm.term_names));
+ for (j = 0; j < qp->nuses; j++)
+ (void) printf(" %s", qp->uses[j].name);
+ putchar('\n');
+ }
+ }
+
+ ExitProgram(EXIT_SUCCESS);
+ }
+
+ /* maybe we want a reverse-dependency listing? */
+ if (invert_dependencies) {
+ ENTRY *qp, *rp;
+ int matchcount;
+
+ for_entry_list(qp) {
+ matchcount = 0;
+ for_entry_list(rp) {
+ if (rp->nuses == 0)
+ continue;
+
+ for (i = 0; i < rp->nuses; i++)
+ if (_nc_name_match(qp->tterm.term_names,
+ rp->uses[i].name, "|")) {
+ if (matchcount++ == 0)
+ (void) printf("%s:",
+ _nc_first_name(qp->tterm.term_names));
+ (void) printf(" %s",
+ _nc_first_name(rp->tterm.term_names));
+ }
+ }
+ if (matchcount)
+ putchar('\n');
+ }
+
+ ExitProgram(EXIT_SUCCESS);
+ }
+
+ /*
+ * If we get this far, user wants a simple terminal type listing.
+ */
+ if (optind < argc) {
+ code = typelist(argc - optind, argv + optind, header, deschook);
+ } else if (all_dirs) {
+ DBDIRS state;
+ int offset;
+ int pass;
+ const char *path;
+ char **eargv = 0;
+
+ code = EXIT_FAILURE;
+ for (pass = 0; pass < 2; ++pass) {
+ unsigned count = 0;
+
+ _nc_first_db(&state, &offset);
+ while ((path = _nc_next_db(&state, &offset)) != 0) {
+ if (!is_database(path)) {
+ ;
+ } else if (eargv != 0) {
+ unsigned n;
+ int found = FALSE;
+
+ /* eliminate duplicates */
+ for (n = 0; n < count; ++n) {
+ if (!strcmp(path, eargv[n])) {
+ found = TRUE;
+ break;
+ }
+ }
+ if (!found) {
+ eargv[count] = strdup(path);
+ ++count;
+ }
+ } else {
+ ++count;
+ }
+ }
+ if (!pass) {
+ eargv = typeCalloc(char *, count + 1);
+ if (eargv == 0)
+ failed("realloc eargv");
+
+ assert(eargv != 0);
+ } else {
+ code = typelist((int) count, eargv, header, deschook);
+ while (count-- > 0)
+ free(eargv[count]);
+ free(eargv);
+ }
+ }
+ } else {
+ DBDIRS state;
+ int offset;
+ const char *path;
+ char *eargv[3];
+ int count = 0;
+
+ _nc_first_db(&state, &offset);
+ while ((path = _nc_next_db(&state, &offset)) != 0) {
+ if (is_database(path)) {
+ eargv[count++] = strdup(path);
+ break;
+ }
+ }
+ eargv[count] = 0;
+
+ code = typelist(count, eargv, header, deschook);
+
+ while (count-- > 0)
+ free(eargv[count]);
+ }
+ _nc_last_db();
+
+ ExitProgram(code);
+}
diff --git a/progs/tput.c b/progs/tput.c
new file mode 100644
index 0000000..2e67cfe
--- /dev/null
+++ b/progs/tput.c
@@ -0,0 +1,447 @@
+/****************************************************************************
+ * Copyright (c) 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: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 *
+ * and: Eric S. Raymond <esr@snark.thyrsus.com> *
+ ****************************************************************************/
+
+/*
+ * tput.c -- shellscript access to terminal capabilities
+ *
+ * by Eric S. Raymond <esr@snark.thyrsus.com>, portions based on code from
+ * Ross Ridge's mytinfo package.
+ */
+
+#define USE_LIBTINFO
+#include <progs.priv.h>
+
+#if !PURE_TERMINFO
+#include <dump_entry.h>
+#include <termsort.c>
+#endif
+#include <transform.h>
+
+MODULE_ID("$Id: tput.c,v 1.46 2010/01/09 16:53:24 tom Exp $")
+
+#define PUTS(s) fputs(s, stdout)
+#define PUTCHAR(c) putchar(c)
+#define FLUSH fflush(stdout)
+
+typedef enum {
+ Numbers = 0
+ ,Num_Str
+ ,Num_Str_Str
+} TParams;
+
+static char *prg_name;
+static bool is_init = FALSE;
+static bool is_reset = FALSE;
+
+static void
+quit(int status, const char *fmt,...)
+{
+ va_list argp;
+
+ va_start(argp, fmt);
+ fprintf(stderr, "%s: ", prg_name);
+ vfprintf(stderr, fmt, argp);
+ fprintf(stderr, "\n");
+ va_end(argp);
+ ExitProgram(status);
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: %s [-V] [-S] [-T term] capname\n", prg_name);
+ ExitProgram(EXIT_FAILURE);
+}
+
+static void
+check_aliases(const char *name)
+{
+ is_init = same_program(name, PROG_INIT);
+ is_reset = same_program(name, PROG_RESET);
+}
+
+/*
+ * Lookup the type of call we should make to tparm(). This ignores the actual
+ * terminfo capability (bad, because it is not extensible), but makes this
+ * code portable to platforms where sizeof(int) != sizeof(char *).
+ *
+ * FIXME: If we want extensibility, analyze the capability string as we do
+ * in tparm() to decide how to parse the varargs list.
+ */
+static TParams
+tparm_type(const char *name)
+{
+#define TD(code, longname, ti, tc) {code,longname},{code,ti},{code,tc}
+ TParams result = Numbers;
+ /* *INDENT-OFF* */
+ static const struct {
+ TParams code;
+ const char *name;
+ } table[] = {
+ TD(Num_Str, "pkey_key", "pfkey", "pk"),
+ TD(Num_Str, "pkey_local", "pfloc", "pl"),
+ TD(Num_Str, "pkey_xmit", "pfx", "px"),
+ TD(Num_Str, "plab_norm", "pln", "pn"),
+ TD(Num_Str_Str, "pkey_plab", "pfxl", "xl"),
+ };
+ /* *INDENT-ON* */
+
+ unsigned n;
+ for (n = 0; n < SIZEOF(table); n++) {
+ if (!strcmp(name, table[n].name)) {
+ result = table[n].code;
+ break;
+ }
+ }
+ return result;
+}
+
+static int
+exit_code(int token, int value)
+{
+ int result = 99;
+
+ switch (token) {
+ case BOOLEAN:
+ result = !value; /* TRUE=0, FALSE=1 */
+ break;
+ case NUMBER:
+ result = 0; /* always zero */
+ break;
+ case STRING:
+ result = value; /* 0=normal, 1=missing */
+ break;
+ }
+ return result;
+}
+
+static int
+tput(int argc, char *argv[])
+{
+ NCURSES_CONST char *name;
+ char *s;
+ int i, j, c;
+ int status;
+ FILE *f;
+#if !PURE_TERMINFO
+ bool termcap = FALSE;
+#endif
+
+ if ((name = argv[0]) == 0)
+ name = "";
+ check_aliases(name);
+ if (is_reset || is_init) {
+ if (init_prog != 0) {
+ system(init_prog);
+ }
+ FLUSH;
+
+ if (is_reset && reset_1string != 0) {
+ PUTS(reset_1string);
+ } else if (init_1string != 0) {
+ PUTS(init_1string);
+ }
+ FLUSH;
+
+ if (is_reset && reset_2string != 0) {
+ PUTS(reset_2string);
+ } else if (init_2string != 0) {
+ PUTS(init_2string);
+ }
+ FLUSH;
+
+#ifdef set_lr_margin
+ if (set_lr_margin != 0) {
+ PUTS(TPARM_2(set_lr_margin, 0, columns - 1));
+ } else
+#endif
+#ifdef set_left_margin_parm
+ if (set_left_margin_parm != 0
+ && set_right_margin_parm != 0) {
+ PUTS(TPARM_1(set_left_margin_parm, 0));
+ PUTS(TPARM_1(set_right_margin_parm, columns - 1));
+ } else
+#endif
+ if (clear_margins != 0
+ && set_left_margin != 0
+ && set_right_margin != 0) {
+ PUTS(clear_margins);
+ if (carriage_return != 0) {
+ PUTS(carriage_return);
+ } else {
+ PUTCHAR('\r');
+ }
+ PUTS(set_left_margin);
+ if (parm_right_cursor) {
+ PUTS(TPARM_1(parm_right_cursor, columns - 1));
+ } else {
+ for (i = 0; i < columns - 1; i++) {
+ PUTCHAR(' ');
+ }
+ }
+ PUTS(set_right_margin);
+ if (carriage_return != 0) {
+ PUTS(carriage_return);
+ } else {
+ PUTCHAR('\r');
+ }
+ }
+ FLUSH;
+
+ if (init_tabs != 8) {
+ if (clear_all_tabs != 0 && set_tab != 0) {
+ for (i = 0; i < columns - 1; i += 8) {
+ if (parm_right_cursor) {
+ PUTS(TPARM_1(parm_right_cursor, 8));
+ } else {
+ for (j = 0; j < 8; j++)
+ PUTCHAR(' ');
+ }
+ PUTS(set_tab);
+ }
+ FLUSH;
+ }
+ }
+
+ if (is_reset && reset_file != 0) {
+ f = fopen(reset_file, "r");
+ if (f == 0) {
+ quit(4 + errno, "Can't open reset_file: '%s'", reset_file);
+ }
+ while ((c = fgetc(f)) != EOF) {
+ PUTCHAR(c);
+ }
+ fclose(f);
+ } else if (init_file != 0) {
+ f = fopen(init_file, "r");
+ if (f == 0) {
+ quit(4 + errno, "Can't open init_file: '%s'", init_file);
+ }
+ while ((c = fgetc(f)) != EOF) {
+ PUTCHAR(c);
+ }
+ fclose(f);
+ }
+ FLUSH;
+
+ if (is_reset && reset_3string != 0) {
+ PUTS(reset_3string);
+ } else if (init_3string != 0) {
+ PUTS(init_3string);
+ }
+ FLUSH;
+ return 0;
+ }
+
+ if (strcmp(name, "longname") == 0) {
+ PUTS(longname());
+ return 0;
+ }
+#if !PURE_TERMINFO
+ retry:
+#endif
+ if ((status = tigetflag(name)) != -1) {
+ return exit_code(BOOLEAN, status);
+ } else if ((status = tigetnum(name)) != CANCELLED_NUMERIC) {
+ (void) printf("%d\n", status);
+ return exit_code(NUMBER, 0);
+ } else if ((s = tigetstr(name)) == CANCELLED_STRING) {
+#if !PURE_TERMINFO
+ if (!termcap) {
+ const struct name_table_entry *np;
+
+ termcap = TRUE;
+ if ((np = _nc_find_entry(name, _nc_get_hash_table(termcap))) != 0) {
+ switch (np->nte_type) {
+ case BOOLEAN:
+ if (bool_from_termcap[np->nte_index])
+ name = boolnames[np->nte_index];
+ break;
+
+ case NUMBER:
+ if (num_from_termcap[np->nte_index])
+ name = numnames[np->nte_index];
+ break;
+
+ case STRING:
+ if (str_from_termcap[np->nte_index])
+ name = strnames[np->nte_index];
+ break;
+ }
+ goto retry;
+ }
+ }
+#endif
+ quit(4, "unknown terminfo capability '%s'", name);
+ } else if (s != ABSENT_STRING) {
+ if (argc > 1) {
+ int k;
+ int popcount;
+ long numbers[1 + NUM_PARM];
+ char *strings[1 + NUM_PARM];
+ char *p_is_s[NUM_PARM];
+
+ /* Nasty hack time. The tparm function needs to see numeric
+ * parameters as numbers, not as pointers to their string
+ * representations
+ */
+
+ for (k = 1; k < argc; k++) {
+ char *tmp = 0;
+ strings[k] = argv[k];
+ numbers[k] = strtol(argv[k], &tmp, 0);
+ if (tmp == 0 || *tmp != 0)
+ numbers[k] = 0;
+ }
+ for (k = argc; k <= NUM_PARM; k++) {
+ numbers[k] = 0;
+ strings[k] = 0;
+ }
+
+ switch (tparm_type(name)) {
+ case Num_Str:
+ s = TPARM_2(s, numbers[1], strings[2]);
+ break;
+ case Num_Str_Str:
+ s = TPARM_3(s, numbers[1], strings[2], strings[3]);
+ break;
+ case Numbers:
+ default:
+ (void) _nc_tparm_analyze(s, p_is_s, &popcount);
+#define myParam(n) (p_is_s[n - 1] != 0 ? ((long) strings[n]) : numbers[n])
+ s = TPARM_9(s,
+ myParam(1),
+ myParam(2),
+ myParam(3),
+ myParam(4),
+ myParam(5),
+ myParam(6),
+ myParam(7),
+ myParam(8),
+ myParam(9));
+ break;
+ }
+ }
+
+ /* use putp() in order to perform padding */
+ putp(s);
+ return exit_code(STRING, 0);
+ }
+ return exit_code(STRING, 1);
+}
+
+int
+main(int argc, char **argv)
+{
+ char *term;
+ int errret;
+ bool cmdline = TRUE;
+ int c;
+ char buf[BUFSIZ];
+ int result = 0;
+
+ check_aliases(prg_name = _nc_rootname(argv[0]));
+
+ term = getenv("TERM");
+
+ while ((c = getopt(argc, argv, "ST:V")) != -1) {
+ switch (c) {
+ case 'S':
+ cmdline = FALSE;
+ break;
+ case 'T':
+ use_env(FALSE);
+ term = optarg;
+ break;
+ case 'V':
+ puts(curses_version());
+ ExitProgram(EXIT_SUCCESS);
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+ }
+
+ /*
+ * Modify the argument list to omit the options we processed.
+ */
+ if (is_reset || is_init) {
+ if (optind-- < argc) {
+ argc -= optind;
+ argv += optind;
+ }
+ argv[0] = prg_name;
+ } else {
+ argc -= optind;
+ argv += optind;
+ }
+
+ if (term == 0 || *term == '\0')
+ quit(2, "No value for $TERM and no -T specified");
+
+ if (setupterm(term, STDOUT_FILENO, &errret) != OK && errret <= 0)
+ quit(3, "unknown terminal \"%s\"", term);
+
+ if (cmdline) {
+ if ((argc <= 0) && !is_reset && !is_init)
+ usage();
+ ExitProgram(tput(argc, argv));
+ }
+
+ while (fgets(buf, sizeof(buf), stdin) != 0) {
+ char *argvec[16]; /* command, 9 parms, null, & slop */
+ int argnum = 0;
+ char *cp;
+
+ /* crack the argument list into a dope vector */
+ for (cp = buf; *cp; cp++) {
+ if (isspace(UChar(*cp))) {
+ *cp = '\0';
+ } else if (cp == buf || cp[-1] == 0) {
+ argvec[argnum++] = cp;
+ if (argnum >= (int) SIZEOF(argvec) - 1)
+ break;
+ }
+ }
+ argvec[argnum] = 0;
+
+ if (argnum != 0
+ && tput(argnum, argvec) != 0) {
+ if (result == 0)
+ result = 4; /* will return value >4 */
+ ++result;
+ }
+ }
+
+ ExitProgram(result);
+}
diff --git a/progs/transform.c b/progs/transform.c
new file mode 100644
index 0000000..75f4573
--- /dev/null
+++ b/progs/transform.c
@@ -0,0 +1,79 @@
+/****************************************************************************
+ * Copyright (c) 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: Thomas E. Dickey *
+ ****************************************************************************/
+#include <progs.priv.h>
+#include <string.h>
+
+#include <transform.h>
+
+MODULE_ID("$Id: transform.c,v 1.2 2010/09/04 21:16:17 tom Exp $")
+
+#ifdef SUFFIX_IGNORED
+static void
+trim_suffix(const char *a, unsigned *len)
+{
+ const char ignore[] = SUFFIX_IGNORED;
+
+ if (sizeof(ignore) != 0) {
+ bool trim = FALSE;
+ unsigned need = (sizeof(ignore) - 1);
+
+ if (*len > need) {
+ unsigned first = *len - need;
+ unsigned n;
+ trim = TRUE;
+ for (n = first; n < *len; ++n) {
+ if (tolower(UChar(a[n])) != tolower(UChar(ignore[n - first]))) {
+ trim = FALSE;
+ break;
+ }
+ }
+ if (trim) {
+ *len -= need;
+ }
+ }
+ }
+}
+#else
+#define trim_suffix(a, len) /* nothing */
+#endif
+
+bool
+same_program(const char *a, const char *b)
+{
+ unsigned len_a = strlen(a);
+ unsigned len_b = strlen(b);
+
+ trim_suffix(a, &len_a);
+ trim_suffix(b, &len_b);
+
+ return (len_a == len_b) && (strncmp(a, b, len_a) == 0);
+}
diff --git a/progs/tset.c b/progs/tset.c
new file mode 100644
index 0000000..084e41d
--- /dev/null
+++ b/progs/tset.c
@@ -0,0 +1,1349 @@
+/****************************************************************************
+ * Copyright (c) 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: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 *
+ * and: Eric S. Raymond <esr@snark.thyrsus.com> *
+ * and: Thomas E. Dickey 1996-on *
+ ****************************************************************************/
+
+/*
+ * Notes:
+ * The initial adaptation from 4.4BSD Lite sources in September 1995 used 686
+ * lines from that version, and made changes/additions for 150 lines. There
+ * was no reformatting, so with/without ignoring whitespace, the amount of
+ * change is the same.
+ *
+ * Comparing with current (2009) source, excluding this comment:
+ * a) 209 lines match identically to the 4.4BSD Lite sources, with 771 lines
+ * changed/added.
+ * a) Ignoring whitespace, the current version still uses 516 lines from the
+ * 4.4BSD Lite sources, with 402 lines changed/added.
+ *
+ * Raymond's original comment on this follows...
+ */
+
+/*
+ * tset.c - terminal initialization utility
+ *
+ * This code was mostly swiped from 4.4BSD tset, with some obsolescent
+ * cruft removed and substantial portions rewritten. A Regents of the
+ * University of California copyright applies to some portions of the
+ * code, and is reproduced below:
+ */
+/*-
+ * Copyright (c) 1980, 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#define USE_LIBTINFO
+#define __INTERNAL_CAPS_VISIBLE /* we need to see has_hardware_tabs */
+#include <progs.priv.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <termcap.h>
+#include <fcntl.h>
+
+#if HAVE_GETTTYNAM && HAVE_TTYENT_H
+#include <ttyent.h>
+#endif
+#ifdef NeXT
+char *ttyname(int fd);
+#endif
+
+#if HAVE_SIZECHANGE
+# if !defined(sun) || !TERMIOS
+# if HAVE_SYS_IOCTL_H
+# include <sys/ioctl.h>
+# endif
+# endif
+#endif
+
+#if NEED_PTEM_H
+/* they neglected to define struct winsize in termios.h -- it's only
+ in termio.h */
+#include <sys/stream.h>
+#include <sys/ptem.h>
+#endif
+
+#include <dump_entry.h>
+#include <transform.h>
+
+MODULE_ID("$Id: tset.c,v 1.82 2010/05/01 21:42:46 tom Exp $")
+
+/*
+ * SCO defines TIOCGSIZE and the corresponding struct. Other systems (SunOS,
+ * Solaris, IRIX) define TIOCGWINSZ and struct winsize.
+ */
+#ifdef TIOCGSIZE
+# define IOCTL_GET_WINSIZE TIOCGSIZE
+# define IOCTL_SET_WINSIZE TIOCSSIZE
+# define STRUCT_WINSIZE struct ttysize
+# define WINSIZE_ROWS(n) n.ts_lines
+# define WINSIZE_COLS(n) n.ts_cols
+#else
+# ifdef TIOCGWINSZ
+# define IOCTL_GET_WINSIZE TIOCGWINSZ
+# define IOCTL_SET_WINSIZE TIOCSWINSZ
+# define STRUCT_WINSIZE struct winsize
+# define WINSIZE_ROWS(n) n.ws_row
+# define WINSIZE_COLS(n) n.ws_col
+# endif
+#endif
+
+#ifndef environ
+extern char **environ;
+#endif
+
+#undef CTRL
+#define CTRL(x) ((x) & 0x1f)
+
+const char *_nc_progname = "tset";
+
+static TTY mode, oldmode, original;
+
+static bool opt_c; /* set control-chars */
+static bool opt_w; /* set window-size */
+
+static bool can_restore = FALSE;
+static bool isreset = FALSE; /* invoked as reset */
+static int terasechar = -1; /* new erase character */
+static int intrchar = -1; /* new interrupt character */
+static int tkillchar = -1; /* new kill character */
+static int tlines, tcolumns; /* window size */
+
+#define LOWERCASE(c) ((isalpha(UChar(c)) && isupper(UChar(c))) ? tolower(UChar(c)) : (c))
+
+static int
+CaselessCmp(const char *a, const char *b)
+{ /* strcasecmp isn't portable */
+ while (*a && *b) {
+ int cmp = LOWERCASE(*a) - LOWERCASE(*b);
+ if (cmp != 0)
+ break;
+ a++, b++;
+ }
+ return LOWERCASE(*a) - LOWERCASE(*b);
+}
+
+static void
+exit_error(void)
+{
+ if (can_restore)
+ SET_TTY(STDERR_FILENO, &original);
+ (void) fprintf(stderr, "\n");
+ fflush(stderr);
+ ExitProgram(EXIT_FAILURE);
+ /* NOTREACHED */
+}
+
+static void
+err(const char *fmt,...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ (void) fprintf(stderr, "%s: ", _nc_progname);
+ (void) vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ exit_error();
+ /* NOTREACHED */
+}
+
+static void
+failed(const char *msg)
+{
+ char temp[BUFSIZ];
+ unsigned len = strlen(_nc_progname) + 2;
+
+ if ((int) len < (int) sizeof(temp) - 12) {
+ strcpy(temp, _nc_progname);
+ strcat(temp, ": ");
+ } else {
+ strcpy(temp, "tset: ");
+ }
+ perror(strncat(temp, msg, sizeof(temp) - strlen(temp) - 2));
+ exit_error();
+ /* NOTREACHED */
+}
+
+static void
+cat(char *file)
+{
+ FILE *fp;
+ size_t nr;
+ char buf[BUFSIZ];
+
+ if ((fp = fopen(file, "r")) == 0)
+ failed(file);
+
+ while ((nr = fread(buf, sizeof(char), sizeof(buf), fp)) != 0)
+ if (fwrite(buf, sizeof(char), nr, stderr) != nr)
+ failed("write to stderr");
+ fclose(fp);
+}
+
+static int
+outc(int c)
+{
+ return putc(c, stderr);
+}
+
+/* Prompt the user for a terminal type. */
+static const char *
+askuser(const char *dflt)
+{
+ static char answer[256];
+ char *p;
+
+ /* We can get recalled; if so, don't continue uselessly. */
+ clearerr(stdin);
+ if (feof(stdin) || ferror(stdin)) {
+ (void) fprintf(stderr, "\n");
+ exit_error();
+ /* NOTREACHED */
+ }
+ for (;;) {
+ if (dflt)
+ (void) fprintf(stderr, "Terminal type? [%s] ", dflt);
+ else
+ (void) fprintf(stderr, "Terminal type? ");
+ (void) fflush(stderr);
+
+ if (fgets(answer, sizeof(answer), stdin) == 0) {
+ if (dflt == 0) {
+ exit_error();
+ /* NOTREACHED */
+ }
+ return (dflt);
+ }
+
+ if ((p = strchr(answer, '\n')) != 0)
+ *p = '\0';
+ if (answer[0])
+ return (answer);
+ if (dflt != 0)
+ return (dflt);
+ }
+}
+
+/**************************************************************************
+ *
+ * Mapping logic begins here
+ *
+ **************************************************************************/
+
+/* Baud rate conditionals for mapping. */
+#define GT 0x01
+#define EQ 0x02
+#define LT 0x04
+#define NOT 0x08
+#define GE (GT | EQ)
+#define LE (LT | EQ)
+
+typedef struct map {
+ struct map *next; /* Linked list of maps. */
+ const char *porttype; /* Port type, or "" for any. */
+ const char *type; /* Terminal type to select. */
+ int conditional; /* Baud rate conditionals bitmask. */
+ int speed; /* Baud rate to compare against. */
+} MAP;
+
+static MAP *cur, *maplist;
+
+typedef struct speeds {
+ const char *string;
+ int speed;
+} SPEEDS;
+
+static const SPEEDS speeds[] =
+{
+ {"0", B0},
+ {"50", B50},
+ {"75", B75},
+ {"110", B110},
+ {"134", B134},
+ {"134.5", B134},
+ {"150", B150},
+ {"200", B200},
+ {"300", B300},
+ {"600", B600},
+ {"1200", B1200},
+ {"1800", B1800},
+ {"2400", B2400},
+ {"4800", B4800},
+ {"9600", B9600},
+ /* sgttyb may define up to this point */
+#ifdef B19200
+ {"19200", B19200},
+#endif
+#ifdef B38400
+ {"38400", B38400},
+#endif
+#ifdef B19200
+ {"19200", B19200},
+#endif
+#ifdef B38400
+ {"38400", B38400},
+#endif
+#ifdef B19200
+ {"19200", B19200},
+#else
+#ifdef EXTA
+ {"19200", EXTA},
+#endif
+#endif
+#ifdef B38400
+ {"38400", B38400},
+#else
+#ifdef EXTB
+ {"38400", EXTB},
+#endif
+#endif
+#ifdef B57600
+ {"57600", B57600},
+#endif
+#ifdef B115200
+ {"115200", B115200},
+#endif
+#ifdef B230400
+ {"230400", B230400},
+#endif
+#ifdef B460800
+ {"460800", B460800},
+#endif
+ {(char *) 0, 0}
+};
+
+static int
+tbaudrate(char *rate)
+{
+ const SPEEDS *sp;
+ int found = FALSE;
+
+ /* The baudrate number can be preceded by a 'B', which is ignored. */
+ if (*rate == 'B')
+ ++rate;
+
+ for (sp = speeds; sp->string; ++sp) {
+ if (!CaselessCmp(rate, sp->string)) {
+ found = TRUE;
+ break;
+ }
+ }
+ if (!found)
+ err("unknown baud rate %s", rate);
+ return (sp->speed);
+}
+
+/*
+ * Syntax for -m:
+ * [port-type][test baudrate]:terminal-type
+ * The baud rate tests are: >, <, @, =, !
+ */
+static void
+add_mapping(const char *port, char *arg)
+{
+ MAP *mapp;
+ char *copy, *p;
+ const char *termp;
+ char *base = 0;
+
+ copy = strdup(arg);
+ mapp = typeMalloc(MAP, 1);
+ if (copy == 0 || mapp == 0)
+ failed("malloc");
+
+ assert(copy != 0);
+ assert(mapp != 0);
+
+ mapp->next = 0;
+ if (maplist == 0)
+ cur = maplist = mapp;
+ else {
+ cur->next = mapp;
+ cur = mapp;
+ }
+
+ mapp->porttype = arg;
+ mapp->conditional = 0;
+
+ arg = strpbrk(arg, "><@=!:");
+
+ if (arg == 0) { /* [?]term */
+ mapp->type = mapp->porttype;
+ mapp->porttype = 0;
+ goto done;
+ }
+
+ if (arg == mapp->porttype) /* [><@=! baud]:term */
+ termp = mapp->porttype = 0;
+ else
+ termp = base = arg;
+
+ for (;; ++arg) { /* Optional conditionals. */
+ switch (*arg) {
+ case '<':
+ if (mapp->conditional & GT)
+ goto badmopt;
+ mapp->conditional |= LT;
+ break;
+ case '>':
+ if (mapp->conditional & LT)
+ goto badmopt;
+ mapp->conditional |= GT;
+ break;
+ case '@':
+ case '=': /* Not documented. */
+ mapp->conditional |= EQ;
+ break;
+ case '!':
+ mapp->conditional |= NOT;
+ break;
+ default:
+ goto next;
+ }
+ }
+
+ next:
+ if (*arg == ':') {
+ if (mapp->conditional)
+ goto badmopt;
+ ++arg;
+ } else { /* Optional baudrate. */
+ arg = strchr(p = arg, ':');
+ if (arg == 0)
+ goto badmopt;
+ *arg++ = '\0';
+ mapp->speed = tbaudrate(p);
+ }
+
+ if (arg == (char *) 0) /* Non-optional type. */
+ goto badmopt;
+
+ mapp->type = arg;
+
+ /* Terminate porttype, if specified. */
+ if (termp != 0)
+ *base = '\0';
+
+ /* If a NOT conditional, reverse the test. */
+ if (mapp->conditional & NOT)
+ mapp->conditional = ~mapp->conditional & (EQ | GT | LT);
+
+ /* If user specified a port with an option flag, set it. */
+ done:
+ if (port) {
+ if (mapp->porttype) {
+ badmopt:
+ err("illegal -m option format: %s", copy);
+ }
+ mapp->porttype = port;
+ }
+ free(copy);
+#ifdef MAPDEBUG
+ (void) printf("port: %s\n", mapp->porttype ? mapp->porttype : "ANY");
+ (void) printf("type: %s\n", mapp->type);
+ (void) printf("conditional: ");
+ p = "";
+ if (mapp->conditional & GT) {
+ (void) printf("GT");
+ p = "/";
+ }
+ if (mapp->conditional & EQ) {
+ (void) printf("%sEQ", p);
+ p = "/";
+ }
+ if (mapp->conditional & LT)
+ (void) printf("%sLT", p);
+ (void) printf("\nspeed: %d\n", mapp->speed);
+#endif
+}
+
+/*
+ * Return the type of terminal to use for a port of type 'type', as specified
+ * by the first applicable mapping in 'map'. If no mappings apply, return
+ * 'type'.
+ */
+static const char *
+mapped(const char *type)
+{
+ MAP *mapp;
+ int match;
+
+ for (mapp = maplist; mapp; mapp = mapp->next)
+ if (mapp->porttype == 0 || !strcmp(mapp->porttype, type)) {
+ switch (mapp->conditional) {
+ case 0: /* No test specified. */
+ match = TRUE;
+ break;
+ case EQ:
+ match = (ospeed == mapp->speed);
+ break;
+ case GE:
+ match = (ospeed >= mapp->speed);
+ break;
+ case GT:
+ match = (ospeed > mapp->speed);
+ break;
+ case LE:
+ match = (ospeed <= mapp->speed);
+ break;
+ case LT:
+ match = (ospeed < mapp->speed);
+ break;
+ default:
+ match = FALSE;
+ }
+ if (match)
+ return (mapp->type);
+ }
+ /* No match found; return given type. */
+ return (type);
+}
+
+/**************************************************************************
+ *
+ * Entry fetching
+ *
+ **************************************************************************/
+
+/*
+ * Figure out what kind of terminal we're dealing with, and then read in
+ * its termcap entry.
+ */
+static const char *
+get_termcap_entry(char *userarg)
+{
+ int errret;
+ char *p;
+ const char *ttype;
+#if HAVE_GETTTYNAM
+ struct ttyent *t;
+#else
+ FILE *fp;
+#endif
+ char *ttypath;
+
+ if (userarg) {
+ ttype = userarg;
+ goto found;
+ }
+
+ /* Try the environment. */
+ if ((ttype = getenv("TERM")) != 0)
+ goto map;
+
+ if ((ttypath = ttyname(STDERR_FILENO)) != 0) {
+ p = _nc_basename(ttypath);
+#if HAVE_GETTTYNAM
+ /*
+ * We have the 4.3BSD library call getttynam(3); that means
+ * there's an /etc/ttys to look up device-to-type mappings in.
+ * Try ttyname(3); check for dialup or other mapping.
+ */
+ if ((t = getttynam(p))) {
+ ttype = t->ty_type;
+ goto map;
+ }
+#else
+ if ((fp = fopen("/etc/ttytype", "r")) != 0
+ || (fp = fopen("/etc/ttys", "r")) != 0) {
+ char buffer[BUFSIZ];
+ char *s, *t, *d;
+
+ while (fgets(buffer, sizeof(buffer) - 1, fp) != 0) {
+ for (s = buffer, t = d = 0; *s; s++) {
+ if (isspace(UChar(*s)))
+ *s = '\0';
+ else if (t == 0)
+ t = s;
+ else if (d == 0 && s != buffer && s[-1] == '\0')
+ d = s;
+ }
+ if (t != 0 && d != 0 && !strcmp(d, p)) {
+ ttype = strdup(t);
+ fclose(fp);
+ goto map;
+ }
+ }
+ fclose(fp);
+ }
+#endif /* HAVE_GETTTYNAM */
+ }
+
+ /* If still undefined, use "unknown". */
+ ttype = "unknown";
+
+ map:ttype = mapped(ttype);
+
+ /*
+ * If not a path, remove TERMCAP from the environment so we get a
+ * real entry from /etc/termcap. This prevents us from being fooled
+ * by out of date stuff in the environment.
+ */
+ found:if ((p = getenv("TERMCAP")) != 0 && !_nc_is_abs_path(p)) {
+ /* 'unsetenv("TERMCAP")' is not portable.
+ * The 'environ' array is better.
+ */
+ int n;
+ for (n = 0; environ[n] != 0; n++) {
+ if (!strncmp("TERMCAP=", environ[n], 8)) {
+ while ((environ[n] = environ[n + 1]) != 0) {
+ n++;
+ }
+ break;
+ }
+ }
+ }
+
+ /*
+ * ttype now contains a pointer to the type of the terminal.
+ * If the first character is '?', ask the user.
+ */
+ if (ttype[0] == '?') {
+ if (ttype[1] != '\0')
+ ttype = askuser(ttype + 1);
+ else
+ ttype = askuser(0);
+ }
+ /* Find the terminfo entry. If it doesn't exist, ask the user. */
+ while (setupterm((NCURSES_CONST char *) ttype, STDOUT_FILENO, &errret)
+ != OK) {
+ if (errret == 0) {
+ (void) fprintf(stderr, "%s: unknown terminal type %s\n",
+ _nc_progname, ttype);
+ ttype = 0;
+ } else {
+ (void) fprintf(stderr,
+ "%s: can't initialize terminal type %s (error %d)\n",
+ _nc_progname, ttype, errret);
+ ttype = 0;
+ }
+ ttype = askuser(ttype);
+ }
+#if BROKEN_LINKER
+ tgetflag("am"); /* force lib_termcap.o to be linked for 'ospeed' */
+#endif
+ return (ttype);
+}
+
+/**************************************************************************
+ *
+ * Mode-setting logic
+ *
+ **************************************************************************/
+
+/* some BSD systems have these built in, some systems are missing
+ * one or more definitions. The safest solution is to override unless the
+ * commonly-altered ones are defined.
+ */
+#if !(defined(CERASE) && defined(CINTR) && defined(CKILL) && defined(CQUIT))
+#undef CEOF
+#undef CERASE
+#undef CINTR
+#undef CKILL
+#undef CLNEXT
+#undef CRPRNT
+#undef CQUIT
+#undef CSTART
+#undef CSTOP
+#undef CSUSP
+#endif
+
+/* control-character defaults */
+#ifndef CEOF
+#define CEOF CTRL('D')
+#endif
+#ifndef CERASE
+#define CERASE CTRL('H')
+#endif
+#ifndef CINTR
+#define CINTR 127 /* ^? */
+#endif
+#ifndef CKILL
+#define CKILL CTRL('U')
+#endif
+#ifndef CLNEXT
+#define CLNEXT CTRL('v')
+#endif
+#ifndef CRPRNT
+#define CRPRNT CTRL('r')
+#endif
+#ifndef CQUIT
+#define CQUIT CTRL('\\')
+#endif
+#ifndef CSTART
+#define CSTART CTRL('Q')
+#endif
+#ifndef CSTOP
+#define CSTOP CTRL('S')
+#endif
+#ifndef CSUSP
+#define CSUSP CTRL('Z')
+#endif
+
+#if defined(_POSIX_VDISABLE)
+#define DISABLED(val) (((_POSIX_VDISABLE != -1) \
+ && ((val) == _POSIX_VDISABLE)) \
+ || ((val) <= 0))
+#else
+#define DISABLED(val) ((int)(val) <= 0)
+#endif
+
+#define CHK(val, dft) (DISABLED(val) ? dft : val)
+
+static bool set_tabs(void);
+
+/*
+ * Reset the terminal mode bits to a sensible state. Very useful after
+ * a child program dies in raw mode.
+ */
+static void
+reset_mode(void)
+{
+#ifdef TERMIOS
+ tcgetattr(STDERR_FILENO, &mode);
+#else
+ stty(STDERR_FILENO, &mode);
+#endif
+
+#ifdef TERMIOS
+#if defined(VDISCARD) && defined(CDISCARD)
+ mode.c_cc[VDISCARD] = CHK(mode.c_cc[VDISCARD], CDISCARD);
+#endif
+ mode.c_cc[VEOF] = CHK(mode.c_cc[VEOF], CEOF);
+ mode.c_cc[VERASE] = CHK(mode.c_cc[VERASE], CERASE);
+#if defined(VFLUSH) && defined(CFLUSH)
+ mode.c_cc[VFLUSH] = CHK(mode.c_cc[VFLUSH], CFLUSH);
+#endif
+ mode.c_cc[VINTR] = CHK(mode.c_cc[VINTR], CINTR);
+ mode.c_cc[VKILL] = CHK(mode.c_cc[VKILL], CKILL);
+#if defined(VLNEXT) && defined(CLNEXT)
+ mode.c_cc[VLNEXT] = CHK(mode.c_cc[VLNEXT], CLNEXT);
+#endif
+ mode.c_cc[VQUIT] = CHK(mode.c_cc[VQUIT], CQUIT);
+#if defined(VREPRINT) && defined(CRPRNT)
+ mode.c_cc[VREPRINT] = CHK(mode.c_cc[VREPRINT], CRPRNT);
+#endif
+#if defined(VSTART) && defined(CSTART)
+ mode.c_cc[VSTART] = CHK(mode.c_cc[VSTART], CSTART);
+#endif
+#if defined(VSTOP) && defined(CSTOP)
+ mode.c_cc[VSTOP] = CHK(mode.c_cc[VSTOP], CSTOP);
+#endif
+#if defined(VSUSP) && defined(CSUSP)
+ mode.c_cc[VSUSP] = CHK(mode.c_cc[VSUSP], CSUSP);
+#endif
+#if defined(VWERASE) && defined(CWERASE)
+ mode.c_cc[VWERASE] = CHK(mode.c_cc[VWERASE], CWERASE);
+#endif
+
+ mode.c_iflag &= ~(IGNBRK | PARMRK | INPCK | ISTRIP | INLCR | IGNCR
+#ifdef IUCLC
+ | IUCLC
+#endif
+#ifdef IXANY
+ | IXANY
+#endif
+ | IXOFF);
+
+ mode.c_iflag |= (BRKINT | IGNPAR | ICRNL | IXON
+#ifdef IMAXBEL
+ | IMAXBEL
+#endif
+ );
+
+ mode.c_oflag &= ~(0
+#ifdef OLCUC
+ | OLCUC
+#endif
+#ifdef OCRNL
+ | OCRNL
+#endif
+#ifdef ONOCR
+ | ONOCR
+#endif
+#ifdef ONLRET
+ | ONLRET
+#endif
+#ifdef OFILL
+ | OFILL
+#endif
+#ifdef OFDEL
+ | OFDEL
+#endif
+#ifdef NLDLY
+ | NLDLY
+#endif
+#ifdef CRDLY
+ | CRDLY
+#endif
+#ifdef TABDLY
+ | TABDLY
+#endif
+#ifdef BSDLY
+ | BSDLY
+#endif
+#ifdef VTDLY
+ | VTDLY
+#endif
+#ifdef FFDLY
+ | FFDLY
+#endif
+ );
+
+ mode.c_oflag |= (OPOST
+#ifdef ONLCR
+ | ONLCR
+#endif
+ );
+
+ mode.c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD | CLOCAL);
+ mode.c_cflag |= (CS8 | CREAD);
+ mode.c_lflag &= ~(ECHONL | NOFLSH
+#ifdef TOSTOP
+ | TOSTOP
+#endif
+#ifdef ECHOPTR
+ | ECHOPRT
+#endif
+#ifdef XCASE
+ | XCASE
+#endif
+ );
+
+ mode.c_lflag |= (ISIG | ICANON | ECHO | ECHOE | ECHOK
+#ifdef ECHOCTL
+ | ECHOCTL
+#endif
+#ifdef ECHOKE
+ | ECHOKE
+#endif
+ );
+#endif
+
+ SET_TTY(STDERR_FILENO, &mode);
+}
+
+/*
+ * Returns a "good" value for the erase character. This is loosely based on
+ * the BSD4.4 logic.
+ */
+#ifdef TERMIOS
+static int
+default_erase(void)
+{
+ int result;
+
+ if (over_strike
+ && key_backspace != 0
+ && strlen(key_backspace) == 1)
+ result = key_backspace[0];
+ else
+ result = CERASE;
+
+ return result;
+}
+#endif
+
+/*
+ * Update the values of the erase, interrupt, and kill characters in 'mode'.
+ *
+ * SVr4 tset (e.g., Solaris 2.5) only modifies the intr, quit or erase
+ * characters if they're unset, or if we specify them as options. This differs
+ * from BSD 4.4 tset, which always sets erase.
+ */
+static void
+set_control_chars(void)
+{
+#ifdef TERMIOS
+ if (DISABLED(mode.c_cc[VERASE]) || terasechar >= 0)
+ mode.c_cc[VERASE] = (terasechar >= 0) ? terasechar : default_erase();
+
+ if (DISABLED(mode.c_cc[VINTR]) || intrchar >= 0)
+ mode.c_cc[VINTR] = (intrchar >= 0) ? intrchar : CINTR;
+
+ if (DISABLED(mode.c_cc[VKILL]) || tkillchar >= 0)
+ mode.c_cc[VKILL] = (tkillchar >= 0) ? tkillchar : CKILL;
+#endif
+}
+
+/*
+ * Set up various conversions in 'mode', including parity, tabs, returns,
+ * echo, and case, according to the termcap entry. If the program we're
+ * running was named with a leading upper-case character, map external
+ * uppercase to internal lowercase.
+ */
+static void
+set_conversions(void)
+{
+#ifdef __OBSOLETE__
+ /*
+ * Conversion logic for some *really* ancient terminal glitches,
+ * not supported in terminfo. Left here for succeeding generations
+ * to marvel at.
+ */
+ if (tgetflag("UC")) {
+#ifdef IUCLC
+ mode.c_iflag |= IUCLC;
+ mode.c_oflag |= OLCUC;
+#endif
+ } else if (tgetflag("LC")) {
+#ifdef IUCLC
+ mode.c_iflag &= ~IUCLC;
+ mode.c_oflag &= ~OLCUC;
+#endif
+ }
+ mode.c_iflag &= ~(PARMRK | INPCK);
+ mode.c_lflag |= ICANON;
+ if (tgetflag("EP")) {
+ mode.c_cflag |= PARENB;
+ mode.c_cflag &= ~PARODD;
+ }
+ if (tgetflag("OP")) {
+ mode.c_cflag |= PARENB;
+ mode.c_cflag |= PARODD;
+ }
+#endif /* __OBSOLETE__ */
+
+#ifdef TERMIOS
+#ifdef ONLCR
+ mode.c_oflag |= ONLCR;
+#endif
+ mode.c_iflag |= ICRNL;
+ mode.c_lflag |= ECHO;
+#ifdef OXTABS
+ mode.c_oflag |= OXTABS;
+#endif /* OXTABS */
+
+ /* test used to be tgetflag("NL") */
+ if (newline != (char *) 0 && newline[0] == '\n' && !newline[1]) {
+ /* Newline, not linefeed. */
+#ifdef ONLCR
+ mode.c_oflag &= ~ONLCR;
+#endif
+ mode.c_iflag &= ~ICRNL;
+ }
+#ifdef __OBSOLETE__
+ if (tgetflag("HD")) /* Half duplex. */
+ mode.c_lflag &= ~ECHO;
+#endif /* __OBSOLETE__ */
+#ifdef OXTABS
+ /* test used to be tgetflag("pt") */
+ if (has_hardware_tabs) /* Print tabs. */
+ mode.c_oflag &= ~OXTABS;
+#endif /* OXTABS */
+ mode.c_lflag |= (ECHOE | ECHOK);
+#endif
+}
+
+/* Output startup string. */
+static void
+set_init(void)
+{
+ char *p;
+ bool settle;
+
+#ifdef __OBSOLETE__
+ if (pad_char != (char *) 0) /* Get/set pad character. */
+ PC = pad_char[0];
+#endif /* OBSOLETE */
+
+#ifdef TAB3
+ if (oldmode.c_oflag & (TAB3 | ONLCR | OCRNL | ONLRET)) {
+ oldmode.c_oflag &= (TAB3 | ONLCR | OCRNL | ONLRET);
+ SET_TTY(STDERR_FILENO, &oldmode);
+ }
+#endif
+ settle = set_tabs();
+
+ if (isreset) {
+ if ((p = reset_1string) != 0) {
+ tputs(p, 0, outc);
+ settle = TRUE;
+ }
+ if ((p = reset_2string) != 0) {
+ tputs(p, 0, outc);
+ settle = TRUE;
+ }
+ /* What about rf, rs3, as per terminfo man page? */
+ /* also might be nice to send rmacs, rmul, rmm */
+ if ((p = reset_file) != 0
+ || (p = init_file) != 0) {
+ cat(p);
+ settle = TRUE;
+ }
+ }
+
+ if (settle) {
+ (void) putc('\r', stderr);
+ (void) fflush(stderr);
+ (void) napms(1000); /* Settle the terminal. */
+ }
+}
+
+/*
+ * Set the hardware tabs on the terminal, using the ct (clear all tabs),
+ * st (set one tab) and ch (horizontal cursor addressing) capabilities.
+ * This is done before if and is, so they can patch in case we blow this.
+ * Return TRUE if we set any tab stops, FALSE if not.
+ */
+static bool
+set_tabs(void)
+{
+ if (set_tab && clear_all_tabs) {
+ int c;
+
+ (void) putc('\r', stderr); /* Force to left margin. */
+ tputs(clear_all_tabs, 0, outc);
+
+ for (c = 8; c < tcolumns; c += 8) {
+ /* Get to the right column. In BSD tset, this
+ * used to try a bunch of half-clever things
+ * with cup and hpa, for an average saving of
+ * somewhat less than two character times per
+ * tab stop, less than .01 sec at 2400cps. We
+ * lost all this cruft because it seemed to be
+ * introducing some odd bugs.
+ * -----------12345678----------- */
+ (void) fputs(" ", stderr);
+ tputs(set_tab, 0, outc);
+ }
+ putc('\r', stderr);
+ return (TRUE);
+ }
+ return (FALSE);
+}
+
+/**************************************************************************
+ *
+ * Main sequence
+ *
+ **************************************************************************/
+
+/*
+ * Tell the user if a control key has been changed from the default value.
+ */
+#ifdef TERMIOS
+static void
+report(const char *name, int which, unsigned def)
+{
+ unsigned older, newer;
+ char *p;
+
+ newer = mode.c_cc[which];
+ older = oldmode.c_cc[which];
+
+ if (older == newer && older == def)
+ return;
+
+ (void) fprintf(stderr, "%s %s ", name, older == newer ? "is" : "set to");
+
+ if (DISABLED(newer))
+ (void) fprintf(stderr, "undef.\n");
+ /*
+ * Check 'delete' before 'backspace', since the key_backspace value
+ * is ambiguous.
+ */
+ else if (newer == 0177)
+ (void) fprintf(stderr, "delete.\n");
+ else if ((p = key_backspace) != 0
+ && newer == (unsigned char) p[0]
+ && p[1] == '\0')
+ (void) fprintf(stderr, "backspace.\n");
+ else if (newer < 040) {
+ newer ^= 0100;
+ (void) fprintf(stderr, "control-%c (^%c).\n", UChar(newer), UChar(newer));
+ } else
+ (void) fprintf(stderr, "%c.\n", UChar(newer));
+}
+#endif
+
+/*
+ * Convert the obsolete argument forms into something that getopt can handle.
+ * This means that -e, -i and -k get default arguments supplied for them.
+ */
+static void
+obsolete(char **argv)
+{
+ for (; *argv; ++argv) {
+ char *parm = argv[0];
+
+ if (parm[0] == '-' && parm[1] == '\0') {
+ argv[0] = strdup("-q");
+ continue;
+ }
+
+ if ((parm[0] != '-')
+ || (argv[1] && argv[1][0] != '-')
+ || (parm[1] != 'e' && parm[1] != 'i' && parm[1] != 'k')
+ || (parm[2] != '\0'))
+ continue;
+ switch (argv[0][1]) {
+ case 'e':
+ argv[0] = strdup("-e^H");
+ break;
+ case 'i':
+ argv[0] = strdup("-i^C");
+ break;
+ case 'k':
+ argv[0] = strdup("-k^U");
+ break;
+ }
+ }
+}
+
+static void
+usage(void)
+{
+ static const char *tbl[] =
+ {
+ ""
+ ,"Options:"
+ ," -c set control characters"
+ ," -e ch erase character"
+ ," -I no initialization strings"
+ ," -i ch interrupt character"
+ ," -k ch kill character"
+ ," -m mapping map identifier to type"
+ ," -Q do not output control key settings"
+ ," -r display term on stderr"
+ ," -s output TERM set command"
+ ," -V print curses-version"
+ ," -w set window-size"
+ };
+ unsigned n;
+ (void) fprintf(stderr, "Usage: %s [options] [terminal]\n", _nc_progname);
+ for (n = 0; n < sizeof(tbl) / sizeof(tbl[0]); ++n)
+ fprintf(stderr, "%s\n", tbl[n]);
+ exit_error();
+ /* NOTREACHED */
+}
+
+static char
+arg_to_char(void)
+{
+ return (char) ((optarg[0] == '^' && optarg[1] != '\0')
+ ? ((optarg[1] == '?') ? '\177' : CTRL(optarg[1]))
+ : optarg[0]);
+}
+
+int
+main(int argc, char **argv)
+{
+ int ch, noinit, noset, quiet, Sflag, sflag, showterm;
+ const char *p;
+ const char *ttype;
+
+ obsolete(argv);
+ noinit = noset = quiet = Sflag = sflag = showterm = 0;
+ while ((ch = getopt(argc, argv, "a:cd:e:Ii:k:m:np:qQSrsVw")) != -1) {
+ switch (ch) {
+ case 'c': /* set control-chars */
+ opt_c = TRUE;
+ break;
+ case 'a': /* OBSOLETE: map identifier to type */
+ add_mapping("arpanet", optarg);
+ break;
+ case 'd': /* OBSOLETE: map identifier to type */
+ add_mapping("dialup", optarg);
+ break;
+ case 'e': /* erase character */
+ terasechar = arg_to_char();
+ break;
+ case 'I': /* no initialization strings */
+ noinit = 1;
+ break;
+ case 'i': /* interrupt character */
+ intrchar = arg_to_char();
+ break;
+ case 'k': /* kill character */
+ tkillchar = arg_to_char();
+ break;
+ case 'm': /* map identifier to type */
+ add_mapping(0, optarg);
+ break;
+ case 'n': /* OBSOLETE: set new tty driver */
+ break;
+ case 'p': /* OBSOLETE: map identifier to type */
+ add_mapping("plugboard", optarg);
+ break;
+ case 'Q': /* don't output control key settings */
+ quiet = 1;
+ break;
+ case 'q': /* display term only */
+ noset = 1;
+ break;
+ case 'r': /* display term on stderr */
+ showterm = 1;
+ break;
+ case 'S': /* OBSOLETE: output TERM & TERMCAP */
+ Sflag = 1;
+ break;
+ case 's': /* output TERM set command */
+ sflag = 1;
+ break;
+ case 'V': /* print curses-version */
+ puts(curses_version());
+ ExitProgram(EXIT_SUCCESS);
+ case 'w': /* set window-size */
+ opt_w = TRUE;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ }
+
+ _nc_progname = _nc_rootname(*argv);
+ argc -= optind;
+ argv += optind;
+
+ if (argc > 1)
+ usage();
+
+ if (!opt_c && !opt_w)
+ opt_c = opt_w = TRUE;
+
+ if (GET_TTY(STDERR_FILENO, &mode) < 0)
+ failed("standard error");
+ can_restore = TRUE;
+ original = oldmode = mode;
+#ifdef TERMIOS
+ ospeed = (NCURSES_OSPEED) cfgetospeed(&mode);
+#else
+ ospeed = (NCURSES_OSPEED) mode.sg_ospeed;
+#endif
+
+ if (same_program(_nc_progname, PROG_RESET)) {
+ isreset = TRUE;
+ reset_mode();
+ }
+
+ (void) get_termcap_entry(*argv);
+
+ if (!noset) {
+ tcolumns = columns;
+ tlines = lines;
+
+#if HAVE_SIZECHANGE
+ if (opt_w) {
+ STRUCT_WINSIZE win;
+ /* Set window size if not set already */
+ (void) ioctl(STDERR_FILENO, IOCTL_GET_WINSIZE, &win);
+ if (WINSIZE_ROWS(win) == 0 &&
+ WINSIZE_COLS(win) == 0 &&
+ tlines > 0 && tcolumns > 0) {
+ WINSIZE_ROWS(win) = tlines;
+ WINSIZE_COLS(win) = tcolumns;
+ (void) ioctl(STDERR_FILENO, IOCTL_SET_WINSIZE, &win);
+ }
+ }
+#endif
+ if (opt_c) {
+ set_control_chars();
+ set_conversions();
+
+ if (!noinit)
+ set_init();
+
+ /* Set the modes if they've changed. */
+ if (memcmp(&mode, &oldmode, sizeof(mode))) {
+ SET_TTY(STDERR_FILENO, &mode);
+ }
+ }
+ }
+
+ /* Get the terminal name from the entry. */
+ ttype = _nc_first_name(cur_term->type.term_names);
+
+ if (noset)
+ (void) printf("%s\n", ttype);
+ else {
+ if (showterm)
+ (void) fprintf(stderr, "Terminal type is %s.\n", ttype);
+ /*
+ * If erase, kill and interrupt characters could have been
+ * modified and not -Q, display the changes.
+ */
+#ifdef TERMIOS
+ if (!quiet) {
+ report("Erase", VERASE, CERASE);
+ report("Kill", VKILL, CKILL);
+ report("Interrupt", VINTR, CINTR);
+ }
+#endif
+ }
+
+ if (Sflag)
+ err("The -S option is not supported under terminfo.");
+
+ if (sflag) {
+ int len;
+ char *var;
+ char *leaf;
+ /*
+ * Figure out what shell we're using. A hack, we look for an
+ * environmental variable SHELL ending in "csh".
+ */
+ if ((var = getenv("SHELL")) != 0
+ && ((len = (int) strlen(leaf = _nc_basename(var))) >= 3)
+ && !strcmp(leaf + len - 3, "csh"))
+ p = "set noglob;\nsetenv TERM %s;\nunset noglob;\n";
+ else
+ p = "TERM=%s;\n";
+ (void) printf(p, ttype);
+ }
+
+ ExitProgram(EXIT_SUCCESS);
+}