Base version of ncurses-5.7 library
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..886fd5b
--- /dev/null
+++ b/progs/Makefile.in
@@ -0,0 +1,297 @@
+# $Id: Makefile.in,v 1.79 2008/09/07 13:58:55 tom Exp $
+##############################################################################
+# 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: 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
+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@
+
+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 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_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 "#define PROG_CAPTOINFO \"$(define_captoinfo)\"" >$@
+	echo "#define PROG_INFOTOCAP \"$(define_infotocap)\"" >>$@
+	echo "#define PROG_RESET     \"$(define_reset)\""     >>$@
+	echo "#define PROG_INIT      \"$(define_init)\""      >>$@
+
+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) 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_tput)
+	-@$(LIBTOOL_CLEAN) rm -f $(DESTDIR)$(bindir)/$(actual_tset)
+	-@rm -f $(DESTDIR)$(bindir)/$(actual_reset)
+
+$(DESTDIR)$(bindir) :
+	sh $(srcdir)/../mkdirs.sh $@
+
+#
+# Utilities normally built by make all start here
+#
+
+DEPS_TIC = \
+	$(MODEL)/tic$o \
+	$(MODEL)/dump_entry$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_TPUT = \
+	$(MODEL)/tput$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
+
+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)/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..bd24220
--- /dev/null
+++ b/progs/dump_entry.c
@@ -0,0 +1,1273 @@
+/****************************************************************************
+ * 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: 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.88 2008/08/04 12:36:12 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 (((len = 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 ((len = 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 ((len = 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 || ((len = 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 || ((len = 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)) {
+	    len = 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..84989ff
--- /dev/null
+++ b/progs/infocmp.c
@@ -0,0 +1,1653 @@
+/****************************************************************************
+ * 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: 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.103 2008/08/16 22:04:56 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) {
+	rp = qp->crosslinks[0];
+
+	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
+ *
+ ***************************************************************************/
+
+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);
+		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);
+		directory = TERMINFO;	/* for error message */
+	    }
+
+	    if (status <= 0) {
+		(void) fprintf(stderr,
+			       "%s: couldn't open terminfo file %s.\n",
+			       _nc_progname,
+			       tfile[termcount]);
+		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);
+
+#if NO_LEAKS
+    free(myargv);
+    free(tfile);
+    free(tname);
+#endif
+    ExitProgram(EXIT_SUCCESS);
+}
+
+/* infocmp.c ends here */
diff --git a/progs/modules b/progs/modules
new file mode 100644
index 0000000..3b4f3b6
--- /dev/null
+++ b/progs/modules
@@ -0,0 +1,43 @@
+# $Id: modules,v 1.13 2006/12/24 00:53:21 tom Exp $
+# Program modules (some are in ncurses lib!)
+##############################################################################
+# Copyright (c) 1998-2005,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.                                                             #
+##############################################################################
+#
+# 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)             $(srcdir)/dump_entry.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
+tput		progs		$(srcdir)	$(HEADER_DEPS) transform.h termsort.c
+tset		progs		$(srcdir)	$(HEADER_DEPS) transform.h $(srcdir)/dump_entry.h ../include/termcap.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/tic.c b/progs/tic.c
new file mode 100644
index 0000000..82bc3ea
--- /dev/null
+++ b/progs/tic.c
@@ -0,0 +1,1521 @@
+/****************************************************************************
+ * 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: 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.137 2008/09/13 16:59:24 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 = strcpy((char *) malloc(strlen(src) + 1), src);
+	size_t 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 = (strcmp(_nc_progname, PROG_CAPTOINFO) == 0)) != FALSE) {
+	outform = F_TERMINFO;
+	sortmode = S_TERMINFO;
+    }
+    if ((capdump = (strcmp(_nc_progname, PROG_INFOTOCAP) == 0)) != 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));
+		    }
+
+		    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;
+}
+
+#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);
+    }
+}
+
+/*
+ * 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 {
+		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);
+	fprintf(stderr, "\"%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_keypad(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 (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..8af6f37
--- /dev/null
+++ b/progs/toe.c
@@ -0,0 +1,514 @@
+/****************************************************************************
+ * 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: 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.51 2008/08/16 21:53:25 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
+
+#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) {
+		    perror("realloc cwd_buf");
+		    continue;
+		}
+
+		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);
+	    } 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..022d494
--- /dev/null
+++ b/progs/tput.c
@@ -0,0 +1,439 @@
+/****************************************************************************
+ * 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: 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.42 2008/07/13 11:05:12 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 = (strcmp(name, PROG_INIT) == 0);
+    is_reset = (strcmp(name, PROG_RESET) == 0);
+}
+
+/*
+ * 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 ((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
+    {
+	const struct name_table_entry *np;
+
+	if ((np = _nc_find_entry(name, _nc_get_hash_table(1))) != 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;
+	    }
+    }
+#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) {
+	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/tset.c b/progs/tset.c
new file mode 100644
index 0000000..6a4d2d6
--- /dev/null
+++ b/progs/tset.c
@@ -0,0 +1,1331 @@
+/****************************************************************************
+ * 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: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
+ *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
+ *     and: Thomas E. Dickey                        1996-on                 *
+ ****************************************************************************/
+
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. 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.76 2008/10/11 19:26:19 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
+
+extern char **environ;
+
+#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 = (MAP *) malloc(sizeof(MAP));
+    if (copy == 0 || mapp == 0)
+	failed("malloc");
+    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 (!strcmp(_nc_progname, PROG_RESET)) {
+	isreset = TRUE;
+	reset_mode();
+    }
+
+    ttype = 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);
+}