aboutsummaryrefslogtreecommitdiff
path: root/contrib/ncurses/tack
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/ncurses/tack')
-rw-r--r--contrib/ncurses/tack/COPYING340
-rw-r--r--contrib/ncurses/tack/HISTORY42
-rw-r--r--contrib/ncurses/tack/Makefile.in155
-rw-r--r--contrib/ncurses/tack/README5
-rw-r--r--contrib/ncurses/tack/ansi.c889
-rw-r--r--contrib/ncurses/tack/charset.c709
-rw-r--r--contrib/ncurses/tack/color.c767
-rw-r--r--contrib/ncurses/tack/control.c657
-rw-r--r--contrib/ncurses/tack/crum.c426
-rw-r--r--contrib/ncurses/tack/edit.c977
-rw-r--r--contrib/ncurses/tack/fun.c912
-rw-r--r--contrib/ncurses/tack/init.c300
-rw-r--r--contrib/ncurses/tack/menu.c421
-rw-r--r--contrib/ncurses/tack/modes.c913
-rw-r--r--contrib/ncurses/tack/modules18
-rw-r--r--contrib/ncurses/tack/output.c818
-rw-r--r--contrib/ncurses/tack/pad.c1955
-rw-r--r--contrib/ncurses/tack/scan.c261
-rw-r--r--contrib/ncurses/tack/sync.c424
-rw-r--r--contrib/ncurses/tack/sysdep.c455
-rw-r--r--contrib/ncurses/tack/tack.1311
-rw-r--r--contrib/ncurses/tack/tack.c620
-rw-r--r--contrib/ncurses/tack/tack.h403
23 files changed, 12778 insertions, 0 deletions
diff --git a/contrib/ncurses/tack/COPYING b/contrib/ncurses/tack/COPYING
new file mode 100644
index 000000000000..60549be514af
--- /dev/null
+++ b/contrib/ncurses/tack/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/contrib/ncurses/tack/HISTORY b/contrib/ncurses/tack/HISTORY
new file mode 100644
index 000000000000..b1de61d1c4af
--- /dev/null
+++ b/contrib/ncurses/tack/HISTORY
@@ -0,0 +1,42 @@
+
+Current history:
+
+1999/05/16 Minor fix to build/link on CLIX
+1999/05/09 Update to build/link on NeXT
+1999/04/17 Update to work with ncurses 5.0 beta1 (TERMTYPE struct)
+1999/02/07 Build with ncurses 4.2 981219 (renamed function)
+1998/01/09 1.00 First release under GPL
+1997/12/24 0.02 First version that requires ncurses
+1997/10/29 0.01 Second beta release to the ncurses mailing list.
+1997/10/06 0.00 First beta release to the ncurses mailing list.
+
+Ancient history: TACK -- the terminfo action checker
+
+ The purpose of this program is to verify the correctness of
+terminfos and to calculate the pads needed for each capability.
+This program is not designed to test curses and therefore uses
+as little of curses as possible.
+
+ This program was originally called TED. In 1991 it was
+released to USENET in comp.sources. TED was originally written to
+test both terminfos and termcaps. The original intent was to
+create a terminfo editor. This code fell quite short of its goal.
+Tests were controled by command line switches and editing was done
+with pen and paper.
+
+ In 1995 Eric S. Raymond got interested in the program and added
+a first cut at making the program menu driven. He also converted
+the code from K&R C to an ANSI/POSIX-conforming C. He re-christened
+the program TAC (Terminfo Action Checker). Eric also wrote a man
+page for TAC.
+
+ In 1997 I decided to dust off the code and make it easier to
+use by the novice. I totally rewrote the menu system and added
+the editing features I originally planned for TED. I also did
+a total rewrite of the code that does the timings. In the process
+of rewriting the code I changed it to be more tightly coupled
+with ncurses. By this time someone had taken the name TAC so
+I re-christened the program TACK.
+
+Daniel Weaver
+<danw@znyx.com>
diff --git a/contrib/ncurses/tack/Makefile.in b/contrib/ncurses/tack/Makefile.in
new file mode 100644
index 000000000000..0c4018fbbc02
--- /dev/null
+++ b/contrib/ncurses/tack/Makefile.in
@@ -0,0 +1,155 @@
+# $Id: Makefile.in,v 1.7 1998/03/28 21:41:21 tom Exp $
+# Makefile for tack
+#
+# 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@
+
+MODEL = ../@DFT_OBJ_SUBDIR@
+INSTALL_PREFIX = @INSTALL_PREFIX@
+srcdir = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+bindir = @bindir@
+libdir = @libdir@
+includedir = @includedir@
+datadir = @datadir@
+
+ticdir = $(datadir)/terminfo
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+
+AWK = @AWK@
+LN_S = @LN_S@
+
+CC = @CC@
+CFLAGS = @CFLAGS@
+
+INCDIR = $(srcdir)/../include
+CPPFLAGS = -DHAVE_CONFIG_H -I../tack -I$(srcdir) @CPPFLAGS@
+
+CCFLAGS = $(CPPFLAGS) $(CFLAGS)
+
+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@)
+
+LD = @LD@
+LINK = $(CC)
+LDFLAGS = @EXTRA_LDFLAGS@ \
+ @PROG_ARGS@ @LDFLAGS@ @LD_MODEL@ @LIBS@ @EXTRA_LIBS@
+
+LDFLAGS_NORMAL = $(LDFLAGS)
+LDFLAGS_DEBUG = $(LDFLAGS) @CC_G_OPT@
+LDFLAGS_PROFILE = $(LDFLAGS) -pg
+LDFLAGS_SHARED = $(LDFLAGS) @CC_SHARED_OPTS@ # @LD_SHARED_OPTS@
+
+LDFLAGS_DEFAULT = $(LDFLAGS_@DFT_UPR_MODEL@)
+
+LINT = @LINT@
+LINT_OPTS = @LINT_OPTS@
+LINT_LIBS = -lncurses @LIBS@
+
+PROGS = tack
+
+# Default library, for linking applications
+DEPS_CURSES = ../lib/libncurses@DFT_DEP_SUFFIX@
+
+################################################################################
+all: $(PROGS)
+
+install: install.tack
+uninstall: uninstall.tack
+
+# this line simplifies the configure-script
+install.libs:
+uninstall.libs:
+
+install.tack: $(PROGS) $(INSTALL_PREFIX)$(bindir)
+ $(INSTALL_PROGRAM) tack $(INSTALL_PREFIX)$(bindir)/tack
+
+uninstall.tack:
+ -@rm -f $(INSTALL_PREFIX)$(bindir)/tack
+
+$(INSTALL_PREFIX)$(bindir) :
+ $(srcdir)/../mkinstalldirs $@
+
+#
+# Rules for building tack
+#
+
+DEPS_TACK = \
+ $(MODEL)/ansi.o \
+ $(MODEL)/charset.o \
+ $(MODEL)/color.o \
+ $(MODEL)/control.o \
+ $(MODEL)/crum.o \
+ $(MODEL)/edit.o \
+ $(MODEL)/fun.o \
+ $(MODEL)/init.o \
+ $(MODEL)/menu.o \
+ $(MODEL)/modes.o \
+ $(MODEL)/output.o \
+ $(MODEL)/pad.o \
+ $(MODEL)/scan.o \
+ $(MODEL)/sync.o \
+ $(MODEL)/sysdep.o \
+ $(MODEL)/tack.o
+
+tack: $(DEPS_TACK) $(DEPS_CURSES)
+ @ECHO_LINK@ $(LINK) $(DEPS_TACK) $(LDFLAGS_DEFAULT) -o $@
+
+#
+# Utility productions start here
+#
+
+tags:
+ ctags *.[ch]
+
+TAGS:
+ etags *.[ch]
+
+clean ::
+ -rm -f tags TAGS do.tic *~
+ -rm -f $(PROGS)
+
+distclean :: clean
+ -rm -f Makefile
+
+mostlyclean :: clean
+
+realclean :: distclean
+
+tack.tar: Makefile.in modules *.[ch] tack.1 HISTORY COPYING
+ tar -cvf tack.tar Makefile.in modules *.[ch] tack.1 HISTORY COPYING
+
+# 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:
+ $(LINT) $(LINT_OPTS) $(CPPFLAGS) $(srcdir)/clear.c $(LINT_LIBS)
+
+###############################################################################
+# The remainder of this file is automatically generated during configuration
+###############################################################################
diff --git a/contrib/ncurses/tack/README b/contrib/ncurses/tack/README
new file mode 100644
index 000000000000..c1b0286b4fc4
--- /dev/null
+++ b/contrib/ncurses/tack/README
@@ -0,0 +1,5 @@
+-- $Id: README,v 1.1 1999/04/18 01:41:31 tom Exp $
+
+The 'tack' program is distributed with ncurses, but is not an integral
+part of ncurses (the two are licensed differently, and the tack directory
+may be removed without causing ncurses to configure or build properly).
diff --git a/contrib/ncurses/tack/ansi.c b/contrib/ncurses/tack/ansi.c
new file mode 100644
index 000000000000..a514a9c1d0fb
--- /dev/null
+++ b/contrib/ncurses/tack/ansi.c
@@ -0,0 +1,889 @@
+/*
+** Copyright (C) 1991, 1997 Free Software Foundation, Inc.
+**
+** This file is part of TACK.
+**
+** TACK is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2, or (at your option)
+** any later version.
+**
+** TACK is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with TACK; see the file COPYING. If not, write to
+** the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA 02111-1307, USA.
+*/
+
+#include <tack.h>
+
+MODULE_ID("$Id: ansi.c,v 1.2 1999/08/21 23:11:57 tom Exp $")
+
+/*
+ * Standalone tests for ANSI terminals. Three entry points:
+ * test_ansi_graphics(), test_ansi_reports() and test_ansi_sgr().
+ */
+
+/*****************************************************************************
+ *
+ * Test ANSI status reports
+ *
+ *****************************************************************************/
+
+/* ASCII control characters */
+#define A_DC1 0x11 /* Control Q */
+#define A_DC3 0x13 /* Control S */
+#define A_ESC 0x1b
+#define A_DCS 0x90
+#define A_CSI 0x9b
+#define A_ST 0x9c
+
+#define MAX_MODES 256
+
+static char default_bank[] = "\033(B\017";
+static int private_use, ape, terminal_class, got_escape;
+static short ansi_value[256];
+static char ansi_buf[512], pack_buf[512];
+static char *ach, *pch;
+
+struct ansi_reports {
+ int lvl, final;
+ const char *text;
+ const char *request;
+};
+
+static struct ansi_reports report_list[] = {
+ {0, 'c', "(DA) Primary device attributes", "\033[0c"},
+ {1, 0, "(DSR) Terminal status", "\033[5n"},
+ {1, 'R', "(DSR) Cursor position", "\033[6n"},
+ {62, 0, "(DA) Secondary device attributes", "\033[>0c"},
+ {62, 0, "(DSR) Printer status", "\033[?15n"},
+ {62, 0, "(DSR) Function key definition", "\033[?25n"},
+ {62, 0, "(DSR) Keyboard language", "\033[?26n"},
+ {63, 0, "(DECRQSS) Data destination", "\033P$q$}\033\\"},
+ {63, 0, "(DECRQSS) Status line type", "\033P$q$~\033\\"},
+ {63, 0, "(DECRQSS) Erase attribute", "\033P$q\"q\033\\"},
+ {63, 0, "(DECRQSS) Personality", "\033P$q\"p\033\\"},
+ {63, 0, "(DECRQSS) Top and bottom margins", "\033P$qr\033\\"},
+ {63, 0, "(DECRQSS) Character attributes", "\033P$qm\033\\"},
+ {63, 0, "(DECRQSS) Illegal request", "\033P$q@\033\\"},
+ {63, 0, "(DECRQUPSS) User pref suplemental set", "\033[&u"},
+ {63, 0, "(DECRQPSR) Cursor information", "\033[1$w"},
+ {63, 0, "(DECRQPSR) Tab stop information", "\033[2$w"},
+ {64, 0, "(DA) Tertiary device attributes", "\033[=0c"},
+ {64, 0, "(DSR) Extended cursor position", "\033[?6n"},
+ {64, 0, "(DSR) Macro space", "\033[?62n"},
+ {64, 0, "(DSR) Memory checksum", "\033[?63n"},
+ {64, 0, "(DSR) Data integrity", "\033[?75n"},
+ {64, 0, "(DSR) Multiple session status", "\033[?85n"},
+ {64, 0, "(DECRQSS) Attribute change extent", "\033P$q*x\033\\"},
+ {64, 0, "(DECRQSS) Columns per page", "\033P$q$|\033\\"},
+ {64, 0, "(DECRQSS) Lines per page", "\033P$qt\033\\"},
+ {64, 0, "(DECRQSS) Lines per screen", "\033P$q*|\033\\"},
+ {64, 0, "(DECRQSS) Left and right margins", "\033P$qs\033\\"},
+ {64, 0, "(DECRQSS) Local functions", "\033P$q+q\033\\"},
+ {64, 0, "(DECRQSS) Local function key control", "\033P$q=}\033\\"},
+ {64, 0, "(DECRQSS) Select modifier key reporting", "\033P$q+r\033\\"},
+ {64, 0, "(DECRQDE) Window report", "\033[\"v"},
+ {0, 0, 0, 0}
+};
+
+struct request_control {
+ const char *text;
+ const char *expect;
+ const char *request;
+ const char *set_mode;
+ const char *reset_mode;
+};
+
+/* Request control function selection or setting */
+static const struct request_control rqss[] = {
+ {"Data sent to screen", "0", "$}", "\033[0$}", 0},
+ {"Data sent to disabled status line", "0", "$}", 0, 0},
+ {"\033[0$~\033[1$}", "\033[0$}", 0, 0, 0},
+ {"Data sent to enabled status line", "1", "$}", 0, 0},
+ {"\033[2$~\033[1$}", "\033[0$}", 0, 0, 0},
+ {"Disbale status line", "0", "$~", "\033[0$~", 0},
+ {"Top status line", "1", "$~", "\033[1$~", 0},
+ {"Bottom status line", "2", "$~", "\033[2$~", 0},
+ {"Eraseable character", "0", "\"q", "\033[0\"q", 0},
+ {"Noneraseable character", "1", "\"q", "\033[1\"q", "\033[0\"q"},
+ {"Top and bottom margins", "3;10", "r", "\0337\033[3;10r", 0},
+ {"\033[r\0338", 0, 0, 0, 0},
+ {"Top and bottom margins", "default", "r", "\0337\033[r", "\0338"},
+ {"Character attributes, dim, bold", "1", "m", "\033[2;1m", "\033[m"},
+ {"Character attributes, bold, dim", "2", "m", "\033[1;2m", "\033[m"},
+ {"Character attributes, under, rev", "4;7", "m", "\033[4;7m", "\033[m"},
+ {"Character attributes, color", "35;42", "m", "\033[35;42m", "\033[m"},
+ {"All character attributes", "", "m", "\033[1;2;3;4;5;6;7;8;9m", 0},
+ {"\033[m", 0, 0, 0, 0},
+ {0, 0, 0, 0, 0}
+};
+
+/*
+** pack_ansi()
+**
+** read and pack an ANSI character
+*/
+static int
+pack_ansi(void)
+{
+ int ch;
+
+ if (*pch)
+ return *pch++;
+
+ while (1) {
+ ch = getchp(char_mask);
+ if (ch == EOF)
+ return EOF;
+ if (ch == A_DC1 || ch == A_DC3)
+ continue;
+ *ach++ = ch;
+ *ach = '\0';
+ if (got_escape && ch >= ' ') {
+ got_escape = 0;
+ if (ch < '@' || ch > '_') {
+ *pch++ = A_ESC;
+ *pch = ch;
+ pch[1] = '\0';
+ return A_ESC;
+ }
+ ch += 0x40;
+ break;
+ } else if (ch == A_ESC) {
+ got_escape = 1;
+ } else {
+ break;
+ }
+ }
+ *pch++ = ch;
+ *pch = '\0';
+ return ch;
+}
+
+
+/*
+** read_ansi()
+**
+** read an ANSI status report from terminal
+*/
+static void
+read_ansi(void)
+{
+ int ch;
+
+ fflush(stdout);
+ ach = ansi_buf;
+ pch = pack_buf;
+ ansi_buf[0] = pack_buf[0] = '\0';
+ got_escape = 0;
+ ch = pack_ansi();
+ if (ch == A_ESC)
+ do {
+ ch = pack_ansi();
+ if (ch == EOF)
+ return;
+ } while (ch < '0' || ch > '~');
+ else
+ if (ch == A_CSI)
+ do {
+ ch = pack_ansi();
+ if (ch == EOF)
+ return;
+ } while (ch < '@' || ch > '~');
+ else
+ if (ch == A_DCS)
+ do {
+ ch = pack_ansi();
+ if (ch == EOF)
+ return;
+ } while (ch != A_ST);
+ return;
+}
+
+/*
+** valid_mode(expected)
+**
+** read a terminal mode status report and parse the result
+** Return TRUE if we got the expected terminating character.
+*/
+static int
+valid_mode(int expected)
+{
+ char *s;
+ int ch, terminator;
+
+ read_ansi();
+
+ ape = 0;
+ ch = pack_buf[0] & 0xff;
+ ansi_value[0] = 0;
+ if (ch != A_CSI && ch != A_DCS)
+ return FALSE;
+
+ s = pack_buf + 1;
+ private_use = 0;
+ if ((*s >= '<') & (*s <= '?')) {
+ private_use = *s++;
+ }
+ terminator = 0;
+ for (; (ch = *s); s++) {
+ if (ch >= '0' && ch <= '9')
+ ansi_value[ape] = ansi_value[ape] * 10 + ch - '0';
+ else if (ch == ';' || ch == ':')
+ ansi_value[++ape] = 0;
+ else if (ch >= '<' && ch <= '?')
+ private_use = ch;
+ else if (ch >= ' ')
+ terminator = (terminator << 8) | ch;
+ else
+ break;
+ }
+ return terminator == expected;
+}
+
+/*
+** read_reports()
+**
+** read all the reports in the ANSI report structure
+*/
+static int
+read_reports(void)
+{
+ int i, j, k, tc, vcr, lc;
+ char *s;
+
+ lc = 5;
+ terminal_class = tc = 0;
+ for (i = 0; report_list[i].text; i++, lc++) {
+ if (terminal_class < report_list[i].lvl &&
+ tc < report_list[i].lvl) {
+ put_crlf();
+ menu_prompt();
+ ptext(" <return> to continue > ");
+ j = wait_here();
+ if (j != 'c' && j != 'C')
+ return j;
+ tc = report_list[i].lvl;
+ } else if (lc + 2 >= lines) {
+ put_crlf();
+ ptext("Hit any key to continue ");
+ (void) wait_here();
+ lc = 1;
+ }
+ sprintf(temp, "%s (%s) ", report_list[i].text,
+ expand_command(report_list[i].request));
+ ptext(temp);
+ for (j = strlen(temp); j < 49; j++)
+ putchp(' ');
+ tc_putp(report_list[i].request);
+ vcr = 0;
+ if (report_list[i].final == 0) {
+ read_ansi();
+ } else if (valid_mode(report_list[i].final))
+ switch (report_list[i].final) {
+ case 'c':
+ terminal_class = ansi_value[0];
+ break;
+ case 'R':
+ vcr = TRUE;
+ break;
+ }
+ j = pack_buf[0] & 0xff;
+ if (j == A_CSI || j == A_DCS) {
+ s = expand(ansi_buf);
+ if (char_count + expand_chars >= columns) {
+ put_str("\r\n ");
+ lc++;
+ }
+ put_str(s);
+ }
+ put_crlf();
+ if (vcr) { /* find out how big the screen is */
+ tc_putp(report_list[i].request);
+ if (!valid_mode('R'))
+ continue;
+ j = ansi_value[0];
+ k = ansi_value[1];
+ tc_putp("\033[255B\033[255C\033[6n");
+ if (!valid_mode('R'))
+ continue;
+ sprintf(temp, "\033[%d;%dH", j, k);
+ tc_putp(temp);
+ ptext("(DSR) Screen size (CSI 6 n)");
+ for (j = char_count; j < 50; j++)
+ putchp(' ');
+ sprintf(temp, "%d x %d", ansi_value[1], ansi_value[0]);
+ ptextln(temp);
+
+ }
+ }
+ menu_prompt();
+ ptext(" r->repeat test, <return> to continue > ");
+ return wait_here();
+}
+
+/*
+** request_cfss()
+**
+** Request Control function selection or settings
+*/
+static int
+request_cfss(void)
+{
+ int i, j, k, l, ch;
+ char *s;
+
+ put_clear();
+ ptextln("Request Expected Received");
+ put_crlf();
+ for (i = 0; rqss[i].text; i++) {
+ ptext(rqss[i].text);
+ j = strlen(rqss[i].text) + strlen(rqss[i].expect);
+ putchp(' ');
+ for (j++; j < 40; j++)
+ putchp(' ');
+ ptext(rqss[i].expect);
+ putchp(' ');
+ tc_putp(rqss[i].set_mode);
+ sprintf(temp, "\033P$q%s\033\\", rqss[i].request);
+ tc_putp(temp);
+ read_ansi();
+ tc_putp(rqss[i].reset_mode);
+ putchp(' ');
+ for (j = 0; ansi_buf[j]; j++) {
+ if (ansi_buf[j] == 'r') {
+ for (k = j++; (ch = (ansi_buf[k] & 0xff)); k++)
+ if (ch == A_ESC) {
+ break;
+ } else if (ch == A_ST) {
+ break;
+ }
+ ansi_buf[k] = '\0';
+ s = expand(&ansi_buf[j]);
+ if (char_count + expand_chars >= columns)
+ put_str("\r\n ");
+ put_str(s);
+ }
+ }
+ put_crlf();
+ }
+ /* calculate the valid attributes */
+ ptext("Valid attributes: 0");
+ j = 0;
+ for (i = 1; i < 20; i++) {
+ sprintf(temp, "\033[0;%dm\033P$qm\033\\", i);
+ tc_putp(temp);
+ (void) valid_mode('m');
+ if (ape > 0) {
+ j = i;
+ sprintf(temp, "\033[0m; %d", i);
+ tc_putp(temp);
+ }
+ }
+ put_crlf();
+ /* calculate how many parameters can be sent */
+ ptext("Max number of parameters: ");
+ sprintf(temp, "%dm\033P$qm\033\\", j);
+ l = -1;
+ if (j > 0)
+ for (l = 1; l < 33; l++) {
+ tc_putp("\033[0");
+ for (ch = 1; ch <= l; ch++)
+ put_this(';');
+ tc_putp(temp);
+ (void) valid_mode('m');
+ if (ape == 0)
+ break;
+ }
+ tc_putp("\033[m");
+ if (l >= 0) {
+ sprintf(temp, "%d", l);
+ ptext(temp);
+ } else
+ ptext("unknown");
+ put_crlf();
+ return wait_here();
+}
+
+/*
+** mode_display(puc, mode, initial, set, reset)
+**
+** print the mode display entry
+*/
+static void
+mode_display(const char *p, int n, int c, char s, char r)
+{
+ int k;
+
+ sprintf(temp, "%s%d (%c, %c, %c)", p, n, c, s, r);
+ k = strlen(temp);
+ if (char_count + k >= columns)
+ put_crlf();
+ for (; k < 14; k++)
+ putchp(' ');
+ put_str(temp);
+}
+
+/*
+** terminal_state()
+**
+** test DECRQM status reports
+*/
+static void
+terminal_state(void)
+{
+ static const char *puc[] = {"", "<", "=", ">", "?", 0};
+
+ int i, j, k, l, modes_found;
+ char *s;
+ char buf[256], tms[256];
+ int mode_puc[MAX_MODES], mode_number[MAX_MODES];
+ char set_value[MAX_MODES], reset_value[MAX_MODES];
+ char current_value[MAX_MODES];
+
+ ptext("Testing terminal mode status. (CSI 0 $ p)");
+ tc_putp("\033[0$p");
+ modes_found = 0;
+ tms[0] = '\0';
+ if (valid_mode(('$' << 8) | 'y')) {
+ for (i = 0; puc[i]; i++) {
+ put_crlf();
+ if (i) {
+ sprintf(temp, "Private use: %c", puc[i][0]);
+ } else {
+ strcpy(temp, "Standard modes:");
+ }
+ k = strlen(temp);
+ ptext(temp);
+ for (j = 0; j < (int) sizeof(buf); buf[j++] = ' ')
+ ;
+ for (j = l = 0; j < 255 && j - l < 50; j++) {
+ sprintf(temp, "\033[%s%d$p", puc[i], j);
+ tc_putp(temp);
+ if (!valid_mode(('$' << 8) | 'y')) {
+ /* not valid, save terminating value */
+ s = expand(ansi_buf);
+ sprintf(tms, "%s%s%d %s ", tms,
+ puc[i], j, s);
+ break;
+ }
+ if (private_use != puc[i][0])
+ break;
+ if (ansi_value[0] != j)
+ break;
+ if (ansi_value[1]) {
+ l = j;
+ if (k > 70) {
+ buf[k] = '\0';
+ put_crlf();
+ ptextln(buf);
+ for (k = 0; k < (int) sizeof(buf);) {
+ buf[k++] = ' ';
+ }
+ k = 0;
+ }
+ sprintf(temp, " %d", j);
+ ptext(temp);
+ k += strlen(temp);
+ buf[k - 1] = ansi_value[1] + '0';
+ if (modes_found >= MAX_MODES)
+ continue;
+ current_value[modes_found] =
+ ansi_value[1] + '0';
+ /* some modes never return */
+ if ((i == 0 && j == 13) /* control execution */
+ || (puc[i][0] == '?' && j == 2)) /* VT52 */
+ set_value[modes_found] =
+ reset_value[modes_found] = '-';
+ else
+ set_value[modes_found] =
+ reset_value[modes_found] = ' ';
+ mode_puc[modes_found] = i;
+ mode_number[modes_found++] = j;
+ }
+ }
+ buf[k] = '\0';
+ if (buf[k - 1] != ' ') {
+ put_crlf();
+ ptext(buf);
+ }
+ }
+
+ if ((i = modes_found) != 0) {
+ put_crlf();
+ put_crlf();
+ if (tms[0]) {
+ ptextln(tms);
+ }
+ ptext("Hit 'Y' to test mode set/reset states: ");
+ i = wait_here();
+ }
+ if (i == 'y' || i == 'Y')
+ while (1) {
+#ifdef STATUSFIX
+ FILE *fp;
+
+#ifdef TEDANSI
+ fp = fopen("ted.ansi", "w");
+#else
+ fp = fopen("/dev/console", "w");
+#endif
+#endif
+ for (i = j = 0; j < modes_found; j = ++i >> 1) {
+ if (set_value[j] == '-')
+ continue;
+ k = (current_value[j] ^ i) & 1;
+ sprintf(temp, "\033[%s%d%c\033[%s%d$p",
+ puc[mode_puc[j]], mode_number[j],
+ k ? 'l' : 'h',
+ puc[mode_puc[j]], mode_number[j]);
+#ifdef STATUSFIX
+ if (fp) {
+ fprintf(fp, "%s\n", expand(temp));
+ fflush(fp);
+ }
+#endif
+ tc_putp(temp);
+ if (!valid_mode(('$' << 8) | 'y'))
+ continue;
+ if (k) {
+ reset_value[j] = ansi_value[1] + '0';
+ } else {
+ set_value[j] = ansi_value[1] + '0';
+ }
+ }
+ put_str("\033[30l"); /* added for GORT bug
+ (WY-185) */
+#ifdef STATUSFIX
+ if (fp)
+ fclose(fp);
+#endif
+ tty_set();
+ /* print the results */
+ put_clear();
+ putln("mode (initial, set, reset)");
+ for (j = 0; j < modes_found; j++) {
+ mode_display(puc[mode_puc[j]], mode_number[j],
+ current_value[j], set_value[j], reset_value[j]);
+ }
+ ptext("\n\nHit 'R' to repeat test. 'S' to sort results: ");
+ i = wait_here();
+ if (i == 's' || i == 'S') { /* print the same stuff,
+ sorted by
+ current_value */
+ put_crlf();
+ for (i = '1'; i <= '4'; i++) {
+ for (j = 0; j < modes_found; j++) {
+ if (current_value[j] == i)
+ mode_display(puc[mode_puc[j]],
+ mode_number[j], current_value[j],
+ set_value[j], reset_value[j]);
+ }
+ }
+ ptext("\n\nHit 'R' to repeat test: ");
+ i = wait_here();
+ }
+ if (i != 'r' && i != 'R')
+ break;
+ tty_raw(1, char_mask);
+ }
+ } else {
+ tty_set();
+ }
+}
+
+
+/*
+** ansi_report_help()
+**
+** Display the informational data for the ANSI report test.
+*/
+static void
+ansi_report_help(void)
+{
+ ptext("Begin ANSI status report testing. ");
+ ptext(" Parity bit set will be displayed in reverse video. ");
+ ptext(" If the terminal hangs, hit any alphabetic key. ");
+ ptextln(" Use c to continue testing. Use any other letter to quit.");
+ put_crlf();
+}
+
+/*
+** test_ansi_reports()
+**
+** Test the ANSI status report functions
+*/
+void
+tools_status(
+ struct test_list *t GCC_UNUSED,
+ int *state GCC_UNUSED,
+ int *ch)
+{
+ int i;
+
+ put_clear();
+ ansi_report_help();
+ tty_raw(1, char_mask);
+
+ do {
+ i = read_reports();
+ if (i != 'r' && i != 'R') {
+ *ch = i;
+ return;
+ }
+ } while (i);
+
+ if (terminal_class >= 63) {
+ do {
+ i = request_cfss();
+ } while (i == 'r' || i == 'R');
+ *ch = i;
+ terminal_state();
+ } else {
+ tty_set();
+ }
+}
+
+
+/*
+** display_sgr()
+**
+** Test a range of ANSI sgr attributes
+** puc -> Private Use Character
+*/
+static void
+display_sgr(int puc)
+{
+ int k;
+
+ temp[0] = puc;
+ temp[1] = '\0';
+ for (k = 0; k < 80; k++) {
+ if (char_count + 8 > 80)
+ put_crlf();
+ else if (char_count + 8 > columns)
+ put_crlf();
+ else if (k > 0)
+ printf(" ");
+ printf("\033[%s%dmMode %2d\033[0m", temp, k, k);
+ char_count += 8;
+ if (puc == '\0') {
+ if (k == 19)
+ printf("\033[10m");
+ if (k == 39)
+ printf("\033[37m");
+ if (k == 49)
+ printf("\033[40m");
+ }
+ }
+ put_crlf();
+ if (puc == '<')
+ printf("\033[<1m");
+ else if (puc)
+ printf("\033[%s0m", temp);
+ set_attr(0);
+}
+
+/*
+** print_sgr20(on, off)
+**
+** print the sgr line for sgr20()
+*/
+static void
+print_sgr20(int on, int off)
+{
+ if (char_count > columns - 13) {
+ put_crlf();
+ } else if (char_count) {
+ put_str(" ");
+ }
+ char_count += 11;
+ printf("%d/%d \033[%dmon\033[%dm off\033[0m", on, off, on, off);
+}
+
+/*
+** sgr20(void)
+**
+** display the enter/exit attributes 1-9 and 20-29
+*/
+static void
+sgr20(void)
+{
+ int k;
+
+ put_crlf();
+ ptextln("Test enter/exit attributes 1-9 and 21-29.");
+ for (k = 1; k < 10; k++) {
+ print_sgr20(k, k + 20);
+ }
+ print_sgr20(1, 22); /* bold */
+ print_sgr20(2, 22); /* dim */
+ print_sgr20(8, 22); /* blank */
+ printf("\033[0m");
+ set_attr(0);
+}
+
+/*
+** tools_sgr(testlist, state, ch)
+**
+** Run the ANSI graphics rendition mode tool
+** Return the last character typed.
+*/
+void
+tools_sgr(
+ struct test_list *t GCC_UNUSED,
+ int *state GCC_UNUSED,
+ int *ch)
+{
+ int k;
+
+ put_clear();
+ for (k = 0;;) {
+ display_sgr(k);
+ put_crlf();
+ menu_prompt();
+ ptext("/sgr Enter =><?r [<cr>] > ");
+ k = wait_here();
+ if ((k == 'r') || (k == 'R')) {
+ k = 0;
+ } else if ((k < '<') || (k > '?')) {
+ break;
+ }
+ }
+ sgr20();
+
+ put_newlines(2);
+ *ch = REQUEST_PROMPT;
+}
+
+/*****************************************************************************
+ *
+ * Test ANSI graphics
+ *
+ *****************************************************************************/
+/*
+** select_bank(bank)
+**
+** select a graphics character set for ANSI terminals
+*/
+static void
+select_bank(char *bank)
+{
+ tc_putp(bank);
+ switch (bank[1] & 3) {
+ case 0:
+ putchp('O' & 0x1f); /* control O */
+ break;
+ case 1:
+ putchp('N' & 0x1f); /* control N */
+ tc_putp("\033~");
+ break;
+ case 2:
+ tc_putp("\033n\033}");
+ break;
+ case 3:
+ tc_putp("\033o\033|");
+ break;
+ }
+}
+
+/*
+** show_characters(bank, bias)
+**
+** print the ANSI graphics characters
+*/
+static void
+show_characters(char *bank, int bias)
+{
+ int i;
+
+ sprintf(temp, "G%d GL ", bank[1] & 3);
+ ptext(temp);
+ select_bank(bank);
+ for (i = ' '; i < 0x80; i++) {
+ if (char_count >= columns ||
+ (i != ' ' && (i & 31) == 0))
+ put_str("\n ");
+ putchp(i + bias);
+ }
+ select_bank(default_bank);
+ put_str(" DEL <");
+ select_bank(bank);
+ putchp(0x7f + bias);
+ select_bank(default_bank);
+ putchp('>');
+ put_crlf();
+ put_crlf();
+}
+
+
+/* ANSI graphics test
+ 94 96 character sets
+ G0 ( ,
+ G1 ) -
+ G2 * .
+ G3 + /
+
+Standard Definitions
+ A UK
+ B US ASCII
+
+Dec extended definitions
+ 0 Special graphics
+
+ */
+
+/*
+** tools_charset(testlist, state, ch)
+**
+** Run the ANSI alt-charset mode tool
+*/
+void
+tools_charset(
+ struct test_list *t GCC_UNUSED,
+ int *state GCC_UNUSED,
+ int *chp GCC_UNUSED)
+{
+ int j, ch;
+ char bank[32];
+
+ put_clear();
+ ptext("Enter the bank ()*+,-./ followed by the character set");
+ ptext(" 0123456789:;<=>? for private use, and");
+ ptextln(" @A...Z[\\]^_`a...z{|}~ for standard sets.");
+ strcpy(bank, "\033)0");
+ for (; bank[0];) {
+ put_crlf();
+ show_characters(bank, 0);
+
+ /* G0 will not print in GR */
+ if (bank[1] & 3) {
+ show_characters(bank, 0x80);
+ }
+ ptext("bank+set> ");
+ for (j = 1; (ch = getchp(char_mask)); j++) {
+ if (ch == EOF)
+ break;
+ putchp(ch);
+ if (j == 1 && ch > '/')
+ j++;
+ bank[j] = ch;
+ if (ch < ' ' || ch > '/')
+ break;
+ if (j + 1 >= (int) sizeof(bank))
+ break;
+ }
+ if (j == 1)
+ break;
+ if (bank[j] < '0' || bank[j] > '~')
+ break;
+ bank[j + 1] = '\0';
+ }
+ put_crlf();
+}
diff --git a/contrib/ncurses/tack/charset.c b/contrib/ncurses/tack/charset.c
new file mode 100644
index 000000000000..c31b78b56863
--- /dev/null
+++ b/contrib/ncurses/tack/charset.c
@@ -0,0 +1,709 @@
+/*
+** Copyright (C) 1991, 1997 Free Software Foundation, Inc.
+**
+** This file is part of TACK.
+**
+** TACK is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2, or (at your option)
+** any later version.
+**
+** TACK is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with TACK; see the file COPYING. If not, write to
+** the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA 02111-1307, USA.
+*/
+
+#include <tack.h>
+
+MODULE_ID("$Id: charset.c,v 1.2 1999/05/09 18:30:49 tom Exp $")
+
+/*
+ Menu definitions for alternate character set and SGR tests.
+*/
+
+static void charset_bel(struct test_list *t, int *state, int *ch);
+static void charset_flash(struct test_list *t, int *state, int *ch);
+static void charset_civis(struct test_list *t, int *state, int *ch);
+static void charset_cvvis(struct test_list *t, int *state, int *ch);
+static void charset_cnorm(struct test_list *t, int *state, int *ch);
+static void charset_hs(struct test_list *t, int *state, int *ch);
+static void charset_status(struct test_list *t, int *state, int *ch);
+static void charset_dsl(struct test_list *t, int *state, int *ch);
+static void charset_enacs(struct test_list *t, int *state, int *ch);
+static void charset_smacs(struct test_list *t, int *state, int *ch);
+static void charset_attributes(struct test_list *t, int *state, int *ch);
+static void charset_sgr(struct test_list *t, int *state, int *ch);
+
+const struct test_list acs_test_list[] = {
+ {0, 0, 0, 0, "e) edit terminfo", 0, &edit_menu},
+ {MENU_NEXT, 3, "bel", 0, 0, charset_bel, 0},
+ {MENU_NEXT, 3, "flash", 0, 0, charset_flash, 0},
+ {MENU_NEXT, 3, "civis", 0, 0, charset_civis, 0},
+ {MENU_NEXT, 3, "cvvis", 0, 0, charset_cvvis, 0},
+ {MENU_NEXT, 3, "cnorm", 0, 0, charset_cnorm, 0},
+ {MENU_NEXT, 3, "hs", 0, 0, charset_hs, 0},
+ {MENU_NEXT, 3, "tsl) (fsl) (wsl", "hs", 0, charset_status, 0},
+ {MENU_NEXT, 3, "dsl", "hs", 0, charset_dsl, 0},
+ {MENU_NEXT, 0, "acsc) (enacs) (smacs) (rmacs", 0, 0, charset_enacs, 0},
+ {MENU_NEXT, 0, "smacs) (rmacs", 0, 0, charset_smacs, 0},
+ {MENU_NEXT, 11, 0, 0, 0, charset_attributes, 0},
+ {MENU_NEXT, 11, "sgr) (sgr0", "ma", 0, charset_sgr, 0},
+ {MENU_LAST, 0, 0, 0, 0, 0, 0}
+};
+
+const struct mode_list alt_modes[] = {
+ {"normal", "(sgr0)", "(sgr0)", 1},
+ {"standout", "(smso)", "(rmso)", 2},
+ {"underline", "(smul)", "(rmul)", 4},
+ {"reverse", "(rev)", "(sgr0)", 8},
+ {"blink", "(blink)", "(sgr0)", 16},
+ {"dim", "(dim)", "(sgr0)", 32},
+ {"bold", "(bold)", "(sgr0)", 64},
+ {"invis", "(invis)", "(sgr0)", 128},
+ {"protect", "(prot)", "(sgr0)", 256},
+ {"altcharset", "(smacs)", "(rmacs)", 512}
+};
+
+/* On many terminals the underline attribute is the last scan line.
+ This is OK unless the following line is reverse video.
+ Then the underline attribute does not show up. The following map
+ will reorder the display so that the underline attribute will
+ show up. */
+const int mode_map[10] = {0, 1, 3, 4, 5, 6, 7, 8, 9, 2};
+
+struct graphics_pair {
+ unsigned char c;
+ const char *name;
+};
+
+static struct graphics_pair glyph[] = {
+ {'+', "arrow pointing right"},
+ {',', "arrow pointing left"},
+ {'.', "arrow pointing down"},
+ {'0', "solid square block"},
+ {'i', "lantern symbol"},
+ {'-', "arrow pointing up"},
+ {'`', "diamond"},
+ {'a', "checker board (stipple)"},
+ {'f', "degree symbol"},
+ {'g', "plus/minus"},
+ {'h', "board of squares"},
+ {'j', "lower right corner"},
+ {'k', "upper right corner"},
+ {'l', "upper left corner"},
+ {'m', "lower left corner"},
+ {'n', "plus"},
+ {'o', "scan line 1"},
+ {'p', "scan line 3"},
+ {'q', "horizontal line"},
+ {'r', "scan line 7"},
+ {'s', "scan line 9"},
+ {'t', "left tee (|-)"},
+ {'u', "right tee (-|)"},
+ {'v', "bottom tee(_|_)"},
+ {'w', "top tee (T)"},
+ {'x', "vertical line"},
+ {'y', "less/equal"},
+ {'z', "greater/equal"},
+ {'{', "Pi"},
+ {'|', "not equal"},
+ {'}', "UK pound sign"},
+ {'~', "bullet"},
+ {'\0', "\0"}
+};
+
+/*
+** charset_hs(test_list, status, ch)
+**
+** (hs) test Has status line
+*/
+static void
+charset_hs(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ if (has_status_line != 1) {
+ ptext("(hs) Has-status line is not defined. ");
+ generic_done_message(t, state, ch);
+ }
+}
+
+/*
+** charset_status(test_list, status, ch)
+**
+** (tsl) (fsl) (wsl) test Status line
+*/
+static void
+charset_status(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int i, max;
+ char *s;
+ static char m[] = "*** status line *** 123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.";
+
+ if (has_status_line != 1) {
+ return;
+ }
+ put_clear();
+ max = width_status_line == -1 ? columns : width_status_line;
+ sprintf(temp, "Terminal has status line of %d characters", max);
+ ptextln(temp);
+
+ put_str("This line s");
+ s = tparm(to_status_line, 0);
+ tc_putp(s);
+ for (i = 0; i < max; i++)
+ putchp(m[i]);
+ tc_putp(from_status_line);
+ putln("hould not be broken.");
+ ptextln("If the previous line is not a complete sentence then (tsl) to-status-line, (fsl) from-status-line, or (wsl) width-of-status-line is incorrect." );
+ generic_done_message(t, state, ch);
+}
+
+/*
+** charset_dsl(test_list, status, ch)
+**
+** (dsl) test Disable status line
+*/
+static void
+charset_dsl(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ if (has_status_line != 1) {
+ return;
+ }
+ if (dis_status_line) {
+ ptextln("Disable status line (dsl)");
+ tc_putp(dis_status_line);
+ ptext("If you can still see the status line then (dsl) disable-status-line has failed. ");
+ } else {
+ ptext("(dsl) Disable-status-line is not defined. ");
+ }
+ generic_done_message(t, state, ch);
+}
+
+
+void
+eat_cookie(void)
+{ /* put a blank if this is not a magic cookie
+ terminal */
+ if (magic_cookie_glitch < 1)
+ putchp(' ');
+}
+
+
+void
+put_mode(char *s)
+{ /* send the attribute string (with or without
+ % execution) */
+ tc_putp(tparm(s)); /* allow % execution */
+}
+
+
+void
+set_attr(int a)
+{ /* set the attribute from the bits in a */
+ int i, b[32];
+
+ if (magic_cookie_glitch > 0) {
+ char_count += magic_cookie_glitch;
+ }
+ if (a == 0 && exit_attribute_mode) {
+ put_mode(exit_attribute_mode);
+ return;
+ }
+ for (i = 0; i < 31; i++) {
+ b[i] = (a >> i) & 1;
+ }
+ tc_putp(tparm(set_attributes, b[1], b[2], b[3], b[4], b[5],
+ b[6], b[7], b[8], b[9]));
+}
+
+/*
+** charset_sgr(test_list, status, ch)
+**
+** (sgr) test Set Graphics Rendition
+*/
+static void
+charset_sgr(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int i, j;
+
+ if (!set_attributes) {
+ ptext("(sgr) Set-graphics-rendition is not defined. ");
+ generic_done_message(t, state, ch);
+ return;
+ }
+ if (!exit_attribute_mode) {
+ ptextln("(sgr0) Set-graphics-rendition-zero is not defined.");
+ /* go ahead and test anyway */
+ }
+ ptext("Test video attributes (sgr)");
+
+ for (i = 0; i < (int) (sizeof(alt_modes) / sizeof(struct mode_list));
+ i++) {
+ put_crlf();
+ sprintf(temp, "%d %-20s", i, alt_modes[i].name);
+ put_str(temp);
+ set_attr(alt_modes[i].number);
+ sprintf(temp, "%s", alt_modes[i].name);
+ put_str(temp);
+ set_attr(0);
+ }
+
+ putln("\n\nDouble mode test");
+ for (i = 0; i <= 9; i++) {
+ sprintf(temp, " %2d ", mode_map[i]);
+ put_str(temp);
+ }
+ for (i = 0; i <= 9; i++) {
+ put_crlf();
+ sprintf(temp, "%d", mode_map[i]);
+ put_str(temp);
+ for (j = 0; j <= 9; j++) {
+ eat_cookie();
+ set_attr((1 << mode_map[i]) | (1 << mode_map[j]));
+ put_str("Aa");
+ set_attr(0);
+ if (j < 9)
+ eat_cookie();
+ }
+ }
+ put_crlf();
+
+ if (max_attributes >= 0) {
+ sprintf(temp, "(ma) Maximum attributes %d ", max_attributes);
+ ptext(temp);
+ }
+ generic_done_message(t, state, ch);
+}
+
+/*
+** test_one_attr(mode-number, begin-string, end-string)
+**
+** Display one attribute line.
+*/
+static void
+test_one_attr(
+ int n,
+ char *begin_mode,
+ char *end_mode)
+{
+ int i;
+
+ sprintf(temp, "%-10s %s ", alt_modes[n].name, alt_modes[n].begin_mode);
+ ptext(temp);
+ for (; char_count < 19;) {
+ putchp(' ');
+ }
+ if (begin_mode) {
+ putchp('.');
+ put_mode(begin_mode);
+ put_str(alt_modes[n].name);
+ for (i = strlen(alt_modes[n].name); i < 13; i++) {
+ putchp(' ');
+ }
+ if (end_mode) {
+ put_mode(end_mode);
+ sprintf(temp, ". %s", alt_modes[n].end_mode);
+ } else {
+ set_attr(0);
+ strcpy(temp, ". (sgr)");
+ }
+ ptextln(temp);
+ } else {
+ for (i = 0; i < magic_cookie_glitch; i++)
+ putchp('*');
+ put_str("*** missing ***");
+ for (i = 0; i < magic_cookie_glitch; i++)
+ putchp('*');
+ put_crlf();
+ }
+}
+
+/*
+** charset_attributes(test_list, status, ch)
+**
+** Test SGR
+*/
+static void
+charset_attributes(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ putln("Test video attributes");
+ test_one_attr(1, enter_standout_mode, exit_standout_mode);
+ test_one_attr(2, enter_underline_mode, exit_underline_mode);
+ test_one_attr(9, enter_alt_charset_mode, exit_alt_charset_mode);
+ if (!exit_attribute_mode && !set_attributes) {
+ ptextln("(sgr0) exit attribute mode is not defined.");
+ generic_done_message(t, state, ch);
+ return;
+ }
+ test_one_attr(3, enter_reverse_mode, exit_attribute_mode);
+ test_one_attr(4, enter_blink_mode, exit_attribute_mode);
+ test_one_attr(5, enter_dim_mode, exit_attribute_mode);
+ test_one_attr(6, enter_bold_mode, exit_attribute_mode);
+ test_one_attr(7, enter_secure_mode, exit_attribute_mode);
+ test_one_attr(8, enter_protected_mode, exit_attribute_mode);
+ generic_done_message(t, state, ch);
+}
+
+#define GLYPHS 256
+
+/*
+** charset_smacs(test_list, status, ch)
+**
+** display all posible acs characters
+** (smacs) (rmacs)
+*/
+static void
+charset_smacs(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int i, c;
+
+ if (enter_alt_charset_mode) {
+ put_clear();
+ ptextln("The following characters are available. (smacs) (rmacs)");
+ for (i = ' '; i <= '`'; i += 32) {
+ put_crlf();
+ put_mode(exit_alt_charset_mode);
+ for (c = 0; c < 32; c++) {
+ putchp(c + i);
+ }
+ put_crlf();
+ put_mode(enter_alt_charset_mode);
+ for (c = 0; c < 32; c++) {
+ putchp(c + i);
+ }
+ put_mode(exit_alt_charset_mode);
+ put_crlf();
+ }
+ put_mode(exit_alt_charset_mode);
+ put_crlf();
+ generic_done_message(t, state, ch);
+ }
+}
+
+
+static void
+test_acs(
+ int attr)
+{ /* alternate character set */
+ int i, j;
+ char valid_glyph[GLYPHS];
+ char acs_table[GLYPHS];
+ static unsigned char vt100[] = "`afgjklmnopqrstuvwxyz{|}~";
+
+ line_count = 0;
+ for (i = 0; i < GLYPHS; i++) {
+ valid_glyph[i] = FALSE;
+ acs_table[i] = i;
+ }
+ if (acs_chars) {
+ sprintf(temp, "Alternate character set map: %s",
+ expand(acs_chars));
+ putln(temp);
+ for (i = 0; acs_chars[i]; i += 2) {
+ if (acs_chars[i + 1] == 0) {
+ break;
+ }
+ for (j = 0;; j++) {
+ if (glyph[j].c == (unsigned char) acs_chars[i]) {
+ acs_table[glyph[j].c] = acs_chars[i + 1];
+ valid_glyph[glyph[j].c] = TRUE;
+ break;
+ }
+ if (glyph[j].name[0] == '\0') {
+ if (isgraph(acs_chars[i])) {
+ sprintf(temp, " %c",
+ acs_chars[i]);
+ } else {
+ sprintf(temp, " 0x%02x",
+ (acs_chars[i] & 0xff));
+ }
+ strcpy(&temp[5], " *** has no mapping ***");
+ putln(temp);
+ break;
+ }
+ }
+ }
+ } else {
+ ptextln("acs_chars not defined (acsc)");
+ /* enable the VT-100 graphics characters (default) */
+ for (i = 0; vt100[i]; i++) {
+ valid_glyph[vt100[i]] = TRUE;
+ }
+ }
+ if (attr) {
+ set_attr(attr);
+ }
+ _nc_init_acs(); /* puts 'ena_acs' and incidentally links acs_map[] */
+ for (i = 0; glyph[i].name[0]; i++) {
+ if (valid_glyph[glyph[i].c]) {
+ put_mode(enter_alt_charset_mode);
+ put_this(acs_table[glyph[i].c]);
+ char_count++;
+ put_mode(exit_alt_charset_mode);
+ if (magic_cookie_glitch >= 1) {
+ sprintf(temp, " %-30.30s", glyph[i].name);
+ put_str(temp);
+ if (char_count + 33 >= columns)
+ put_crlf();
+ } else {
+ sprintf(temp, " %-24.24s", glyph[i].name);
+ put_str(temp);
+ if (char_count + 26 >= columns)
+ put_crlf();
+ }
+ if (line_count >= lines) {
+ (void) wait_here();
+ put_clear();
+ }
+ }
+ }
+ if (char_count > 1) {
+ put_crlf();
+ }
+#ifdef ACS_ULCORNER
+ maybe_wait(5);
+ put_mode(enter_alt_charset_mode);
+ put_this(ACS_ULCORNER);
+ put_this(ACS_TTEE);
+ put_this(ACS_URCORNER);
+ put_this(ACS_ULCORNER);
+ put_this(ACS_HLINE);
+ put_this(ACS_URCORNER);
+ char_count += 6;
+ put_mode(exit_alt_charset_mode);
+ put_crlf();
+ put_mode(enter_alt_charset_mode);
+ put_this(ACS_LTEE);
+ put_this(ACS_PLUS);
+ put_this(ACS_RTEE);
+ put_this(ACS_VLINE);
+ if (magic_cookie_glitch >= 1)
+ put_this(' ');
+ else {
+ put_mode(exit_alt_charset_mode);
+ put_this(' ');
+ put_mode(enter_alt_charset_mode);
+ }
+ put_this(ACS_VLINE);
+ char_count += 6;
+ put_mode(exit_alt_charset_mode);
+ put_str(" Here are 2 boxes");
+ put_crlf();
+ put_mode(enter_alt_charset_mode);
+ put_this(ACS_LLCORNER);
+ put_this(ACS_BTEE);
+ put_this(ACS_LRCORNER);
+ put_this(ACS_LLCORNER);
+ put_this(ACS_HLINE);
+ put_this(ACS_LRCORNER);
+ char_count += 6;
+ put_mode(exit_alt_charset_mode);
+ put_crlf();
+#endif
+}
+
+/*
+** charset_bel(test_list, status, ch)
+**
+** (bel) test Bell
+*/
+static void
+charset_bel(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ if (bell) {
+ ptextln("Testing bell (bel)");
+ tc_putp(bell);
+ ptext("If you did not hear the Bell then (bel) has failed. ");
+ } else {
+ ptext("(bel) Bell is not defined. ");
+ }
+ generic_done_message(t, state, ch);
+}
+
+/*
+** charset_flash(test_list, status, ch)
+**
+** (flash) test Visual bell
+*/
+static void
+charset_flash(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ if (flash_screen) {
+ ptextln("Testing visual bell (flash)");
+ tc_putp(flash_screen);
+ ptext("If you did not see the screen flash then (flash) has failed. ");
+ } else {
+ ptext("(flash) Flash is not defined. ");
+ }
+ generic_done_message(t, state, ch);
+}
+
+/*
+** charset_civis(test_list, status, ch)
+**
+** (civis) test Cursor invisible
+*/
+static void
+charset_civis(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ if (cursor_normal) {
+ if (cursor_invisible) {
+ ptext("(civis) Turn off the cursor. ");
+ tc_putp(cursor_invisible);
+ ptext("If you can still see the cursor then (civis) has failed. ");
+ } else {
+ ptext("(civis) Cursor-invisible is not defined. ");
+ }
+ generic_done_message(t, state, ch);
+ tc_putp(cursor_normal);
+ }
+}
+
+/*
+** charset_cvvis(test_list, status, ch)
+**
+** (cvvis) test Cursor very visible
+*/
+static void
+charset_cvvis(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ if (cursor_normal) {
+ if (cursor_visible) {
+ ptext("(cvvis) Make cursor very visible. ");
+ tc_putp(cursor_visible);
+ ptext("If the cursor is not very visible then (cvvis) has failed. ");
+ } else {
+ ptext("(cvvis) Cursor-very-visible is not defined. ");
+ }
+ generic_done_message(t, state, ch);
+ tc_putp(cursor_normal);
+ }
+}
+
+/*
+** charset_cnorm(test_list, status, ch)
+**
+** (cnorm) test Cursor normal
+*/
+static void
+charset_cnorm(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ if (cursor_normal) {
+ ptext("(cnorm) Normal cursor. ");
+ tc_putp(cursor_normal);
+ ptext("If the cursor is not normal then (cnorm) has failed. ");
+ } else {
+ ptext("(cnorm) Cursor-normal is not defined. ");
+ }
+ generic_done_message(t, state, ch);
+}
+
+/*
+** charset_enacs(test_list, status, ch)
+**
+** test Alternate character set mode and alternate characters
+** (acsc) (enacs) (smacs) (rmacs)
+*/
+static void
+charset_enacs(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int c, i;
+
+ if (enter_alt_charset_mode || acs_chars) {
+ c = 0;
+ while (1) {
+ put_clear();
+ /*
+ for terminals that use separate fonts for
+ attributes (such as X windows) the line
+ drawing characters must be checked for
+ each font.
+ */
+ if (c >= '0' && c <= '9') {
+ test_acs(alt_modes[c - '0'].number);
+ set_attr(0);
+ } else {
+ test_acs(0);
+ }
+
+ while (1) {
+ ptextln("[r] to repeat, [012345789] to test with attributes on, [?] for a list of attributes, anything else to go to next test. ");
+ generic_done_message(t, state, ch);
+ if (*ch != '?') {
+ break;
+ }
+ for (i = 0; i <= 9; i++) {
+ sprintf(temp, " %d %s %s", i, alt_modes[i].begin_mode,
+ alt_modes[i].name);
+ ptextln(temp);
+ }
+ }
+ if (*ch >= '0' && *ch <= '9') {
+ c = *ch;
+ } else
+ if (*ch != 'r') {
+ break;
+ }
+ }
+ } else {
+ ptext("(smacs) Enter-alt-char-set-mode and (acsc) Alternate-char-set are not defined. ");
+ generic_done_message(t, state, ch);
+ }
+}
+
+/*
+** charset_can_test()
+**
+** Initialize the can_test data base
+*/
+void
+charset_can_test(void)
+{
+ int i;
+
+ for (i = 0; i < 9; i++) {
+ can_test(alt_modes[i].begin_mode, FLAG_CAN_TEST);
+ can_test(alt_modes[i].end_mode, FLAG_CAN_TEST);
+ }
+}
diff --git a/contrib/ncurses/tack/color.c b/contrib/ncurses/tack/color.c
new file mode 100644
index 000000000000..710538aef48c
--- /dev/null
+++ b/contrib/ncurses/tack/color.c
@@ -0,0 +1,767 @@
+/*
+** Copyright (C) 1991, 1997 Free Software Foundation, Inc.
+**
+** This file is part of TACK.
+**
+** TACK is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2, or (at your option)
+** any later version.
+**
+** TACK is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with TACK; see the file COPYING. If not, write to
+** the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA 02111-1307, USA.
+*/
+
+#include <tack.h>
+
+MODULE_ID("$Id: color.c,v 1.1 1999/04/18 01:24:45 tom Exp $")
+
+/*
+ * Color terminal tests. Has only one entry point: test_color().
+ */
+
+static void color_check(struct test_list *, int *, int *);
+static void color_setf(struct test_list *, int *, int *);
+static void color_matrix(struct test_list *, int *, int *);
+static void color_ncv(struct test_list *, int *, int *);
+static void color_ccc(struct test_list *, int *, int *);
+static void color_bce(struct test_list *, int *, int *);
+
+struct test_list color_test_list[] = {
+ {0, 0, 0, 0, "e) edit terminfo", 0, &edit_menu},
+ {MENU_NEXT, 2, "colors) (pairs", 0, 0, color_check, 0},
+ {MENU_NEXT, 12, "setf) (setb) (scp", 0, 0, color_setf, 0},
+ {MENU_NEXT, 24, "op", 0, 0, color_matrix, 0},
+ {MENU_NEXT, 16, "ncv", 0, 0, color_ncv, 0},
+ {MENU_NEXT, 0, "bce", 0, 0, color_bce, 0},
+ {MENU_NEXT | MENU_CLEAR, 0, "ccc) (initc) (initp", "hls op oc", 0, color_ccc, 0},
+ {MENU_LAST, 0, 0, 0, 0, 0, 0}
+};
+
+#ifndef COLOR_BLACK
+#define COLOR_BLACK 0
+#define COLOR_BLUE 1
+#define COLOR_GREEN 2
+#define COLOR_CYAN 3
+#define COLOR_RED 4
+#define COLOR_MAGENTA 5
+#define COLOR_YELLOW 6
+#define COLOR_WHITE 7
+#endif
+
+struct color_table {
+ const char *name;
+ int index;
+ int r, g, b;
+ int h, l, s;
+};
+
+static struct color_table def_colors[8] = {
+ {"black ", COLOR_BLACK, 0, 0, 0, 0, 0, 0},
+ {"blue ", COLOR_BLUE, 0, 0, 1000, 330, 50, 100},
+ {"green ", COLOR_GREEN, 0, 1000, 0, 240, 50, 100},
+ {"cyan ", COLOR_CYAN, 0, 1000, 1000, 300, 50, 100},
+ {"red ", COLOR_RED, 1000, 0, 0, 120, 50, 100},
+ {"magenta", COLOR_MAGENTA, 1000, 0, 1000, 60, 50, 100},
+ {"yellow ", COLOR_YELLOW, 1000, 1000, 0, 180, 50, 100},
+ {"white ", COLOR_WHITE, 1000, 1000, 1000, 0, 100, 0}
+};
+
+#define MAX_PAIR 256
+static int fg_color[MAX_PAIR] = {COLOR_BLACK, COLOR_BLUE, COLOR_GREEN,
+COLOR_CYAN, COLOR_RED, COLOR_MAGENTA, COLOR_YELLOW, COLOR_WHITE};
+static int bg_color[MAX_PAIR] = {COLOR_BLACK, COLOR_BLACK, COLOR_BLACK,
+COLOR_BLACK, COLOR_BLACK, COLOR_BLACK, COLOR_BLACK, COLOR_BLACK};
+static int pairs_used = 8;
+static int a_bright_color, bright_value;
+static int cookie_monster, color_step, colors_per_line;
+static int R, G, B;
+
+static int
+color_trans(int c)
+{ /* translate or load the color */
+ int i;
+
+ for (i = 0; i < pairs_used; i++) {
+ if (fg_color[i] == c) {
+ return i;
+ }
+ }
+ if (!can_change) {
+ return 0;
+ }
+ if (pairs_used > max_colors || pairs_used >= MAX_PAIR) {
+ pairs_used = 0;
+ ptextln("Ran out of colors");
+ }
+ fg_color[pairs_used] = c;
+ bg_color[pairs_used] = c;
+ if (hue_lightness_saturation) {
+ tc_putp(tparm(initialize_color, pairs_used,
+ def_colors[c].h, def_colors[c].l, def_colors[c].s));
+ } else {
+ tc_putp(tparm(initialize_color, pairs_used,
+ def_colors[c].r, def_colors[c].g, def_colors[c].b));
+ }
+ return pairs_used++;
+}
+
+static void
+new_color(
+ int fg,
+ int bg,
+ int hungry)
+{ /* change the color to fg and bg. */
+ int i;
+
+ if (hungry) {
+ eat_cookie();
+ }
+ if (set_a_foreground) {
+ /* set ANSI color (setaf) (setab) */
+ tc_putp(tparm(set_a_foreground, fg));
+ tc_putp(tparm(set_a_background, bg));
+ } else if (set_foreground) {
+ /* make sure black is zero */
+ (void) color_trans(COLOR_BLACK);
+ tc_putp(tparm(set_foreground, color_trans(fg)));
+ tc_putp(tparm(set_background, color_trans(bg)));
+ } else { /* set color pair */
+ for (i = 0; i < pairs_used; i++) {
+ if (fg_color[i] == fg && bg_color[i] == bg) {
+ tc_putp(tparm(set_color_pair, i));
+ if (hungry) {
+ eat_cookie();
+ }
+ return;
+ }
+ }
+ if (!can_change) {
+ /* try to set just the foreground */
+ for (i = pairs_used - 1; i; i--) {
+ if (fg_color[i] == fg)
+ break;
+ }
+ tc_putp(tparm(set_color_pair, i));
+ if (hungry) {
+ eat_cookie();
+ }
+ return;
+ }
+ if (pairs_used > max_pairs || pairs_used >= MAX_PAIR) {
+ pairs_used = 0;
+ ptextln("Ran out of color pairs");
+ }
+ fg_color[pairs_used] = fg;
+ bg_color[pairs_used] = bg;
+ if (hue_lightness_saturation) {
+ tc_putp(tparm(initialize_pair, pairs_used,
+ def_colors[fg].h, def_colors[fg].l, def_colors[fg].s,
+ def_colors[bg].h, def_colors[bg].l, def_colors[bg].s));
+ } else {
+ tc_putp(tparm(initialize_pair, pairs_used,
+ def_colors[fg].r, def_colors[fg].g, def_colors[fg].b,
+ def_colors[bg].r, def_colors[bg].g, def_colors[bg].b));
+ }
+ tc_putp(tparm(set_color_pair, pairs_used));
+ pairs_used++;
+ }
+ if (hungry) {
+ eat_cookie();
+ }
+}
+
+
+static void
+set_color_step(void)
+{ /* set the color_step for the (ccc) display */
+ int i;
+
+ for (i = 2; i < 1000; i++) {
+ if ((i * i * i) >= max_colors) {
+ break;
+ }
+ }
+ color_step = 1000 / (i - 1);
+}
+
+
+static void
+rgb_2_hls(int r, int g, int b, int *h, int *l, int *s)
+{ /* convert RGB to HLS system */
+ int min, max, t;
+
+ if ((min = g < r ? g : r) > b) {
+ min = b;
+ }
+ if ((max = g > r ? g : r) < b) {
+ max = b;
+ }
+
+ /* calculate lightness */
+ *l = (min + max) / 20;
+
+ if (min == max) { /* black, white and all shades of gray */
+ *h = 0;
+ *s = 0;
+ return;
+ }
+ /* calculate saturation */
+ if (*l < 50) {
+ *s = ((max - min) * 100) / (max + min);
+ } else {
+ *s = ((max - min) * 100) / (2000 - max - min);
+ }
+
+ /* calculate hue */
+ if (r == max) {
+ t = 120 + ((g - b) * 60) / (max - min);
+ } else if (g == max) {
+ t = 240 + ((b - r) * 60) / (max - min);
+ } else {
+ t = 360 + ((r - g) * 60) / (max - min);
+ }
+ *h = t % 360;
+}
+
+
+static void
+send_color(int p, int r, int g, int b)
+{ /* send the initialize_color (initc) command */
+ int h, l, s;
+
+ if (hue_lightness_saturation) {
+ rgb_2_hls(r, g, b, &h, &l, &s);
+ tc_putp(tparm(initialize_color, p, h, l, s));
+ } else {
+ tc_putp(tparm(initialize_color, p, r, g, b));
+ }
+}
+
+
+static void
+send_pair(int p, int fr, int fg, int fb, int br, int bg, int bb)
+{ /* send the initialize_pair (initp) command */
+ int fh, fl, fs, bh, bl, bs;
+
+ if (hue_lightness_saturation) {
+ rgb_2_hls(fr, fg, fb, &fh, &fl, &fs);
+ rgb_2_hls(br, bg, bb, &bh, &bl, &bs);
+ tc_putp(tparm(initialize_pair, p, fh, fl, fs, bh, bl, bs));
+ } else {
+ tc_putp(tparm(initialize_pair, p, fr, fg, fb, bb, bg, bb));
+ }
+}
+
+
+static int
+load_palette(int n)
+{ /* load the color palette */
+ int rgb;
+
+ for (;;) {
+ if (pairs_used >= n) {
+ return FALSE;
+ }
+ if (set_a_foreground || set_foreground) {
+ if (pairs_used >= max_colors) {
+ return FALSE;
+ }
+ send_color(pairs_used, R, G, B);
+ rgb = R + G + B;
+ if (rgb > bright_value) {
+ bright_value = rgb;
+ a_bright_color = pairs_used;
+ }
+ } else {
+ if (pairs_used >= max_pairs) {
+ return FALSE;
+ }
+ if (pairs_used == 0) {
+ send_pair(pairs_used, 1000, 1000, 1000, R, G, B);
+ } else {
+ send_pair(pairs_used, R, G, B, R, G, B);
+ }
+ }
+ pairs_used++;
+ if ((B += color_step) > 1000) {
+ B = 0;
+ if ((G += color_step) > 1000) {
+ G = 0;
+ if ((R += color_step) > 1000) {
+ return TRUE;
+ }
+ }
+ }
+ }
+}
+
+
+static int
+rainbow(int n)
+{ /* print the programable color display */
+ int i, c, d, palette_full, initial_pair;
+ static const struct {
+ const char *name;
+ char ch;
+ } splat[] = {
+ {"Bg normal", ' '},
+ {"Fg normal", ' '},
+ {0, 0}
+ };
+
+ if ((set_a_foreground || set_foreground)
+ ? pairs_used >= max_colors
+ : pairs_used >= max_pairs) {
+ ptext("New palette: ");
+ (void) wait_here();
+ initial_pair = pairs_used = 1;
+ bright_value = 0;
+ } else if (line_count + 3 >= lines) {
+ ptext("Go: ");
+ (void) wait_here();
+ put_clear();
+ initial_pair = pairs_used = 1;
+ bright_value = 0;
+ n++;
+ } else {
+ initial_pair = pairs_used;
+ n += initial_pair;
+ }
+ palette_full = load_palette(n);
+ for (d = 0; splat[d].name; d++) {
+ c = splat[d].ch;
+ if (d == 1) {
+ put_mode(enter_reverse_mode);
+ }
+ for (i = initial_pair; i < n; i++) {
+ if (i >= pairs_used) {
+ break;
+ }
+ if (set_a_foreground) {
+ if (i >= max_colors) {
+ break;
+ }
+ tc_putp(tparm(set_a_foreground, i));
+ tc_putp(tparm(set_a_background, i));
+ } else if (set_foreground) {
+ if (i >= max_colors) {
+ break;
+ }
+ tc_putp(tparm(set_foreground, i));
+ tc_putp(tparm(set_background, i));
+ } else {
+ if (i >= max_pairs) {
+ break;
+ }
+ tc_putp(tparm(set_color_pair, i));
+ }
+ putchp(c);
+ }
+ if (d == 1) {
+ put_mode(exit_attribute_mode);
+ }
+ if (set_a_foreground) {
+ tc_putp(tparm(set_a_foreground, a_bright_color));
+ tc_putp(tparm(set_a_background, 0));
+ } else if (set_foreground) {
+ tc_putp(tparm(set_foreground, a_bright_color));
+ tc_putp(tparm(set_background, 0));
+ } else {
+ tc_putp(tparm(set_color_pair, 0));
+ }
+ put_str(" ");
+ put_str(splat[d].name);
+ put_crlf();
+ }
+ return palette_full;
+}
+
+
+static void
+ncv_display(int m)
+{ /* print the no_color_video (ncv) test line */
+ putchp('0' + m);
+ putchp(' ');
+ eat_cookie();
+ set_attr(1 << m);
+ sprintf(temp, "%-11s", alt_modes[m].name);
+ put_str(temp);
+
+ new_color(COLOR_BLUE, COLOR_BLACK, TRUE);
+ put_str("blue");
+
+ new_color(COLOR_BLACK, COLOR_GREEN, TRUE);
+ put_str("green");
+
+ new_color(COLOR_WHITE, COLOR_BLACK, TRUE);
+ put_str(alt_modes[m].name);
+ eat_cookie();
+ set_attr(0);
+ put_crlf();
+}
+
+
+static void
+dump_colors(void)
+{ /* display the colors in some esthetic
+ pattern */
+ static int xmap[8] = {0, 3, 4, 7, 1, 2, 5, 6};
+ int i, j, k, xi, xj, width, p, cs;
+ int found_one;
+
+ cs = color_step <= 125 ? 125 : color_step;
+ width = (1000 / cs) + 1;
+ for (xi = 0; xi < 16; xi++) {
+ i = (xi & 8) ? xi ^ 15 : xi;
+ R = i * cs;
+ if (R <= 1000) {
+ found_one = FALSE;
+ for (xj = 0; xj < 32; xj++) {
+ j = ((xj & 8) ? xj ^ 15 : xj) & 7;
+ k = xmap[((xi >> 1) & 4) + (xj >> 3)];
+ G = j * cs;
+ B = k * cs;
+ if (G <= 1000 && B <= 1000) {
+ p = (k * width + j) * width + i;
+ if (set_a_background) {
+ if (p >= max_colors) {
+ continue;
+ }
+ send_color(p, R, G, B);
+ tc_putp(tparm(set_a_background, p));
+ } else if (set_background) {
+ if (p >= max_colors) {
+ continue;
+ }
+ send_color(p, R, G, B);
+ tc_putp(tparm(set_background, p));
+ } else {
+ if (p >= max_pairs) {
+ continue;
+ }
+ send_pair(p, R, G, B, R, G, B);
+ tc_putp(tparm(set_color_pair, p));
+ }
+ found_one = TRUE;
+ putchp(' ');
+ putchp(' ');
+ }
+ }
+ if (found_one) {
+ put_crlf();
+ }
+ }
+ }
+}
+
+/*
+** color_check(test_list, status, ch)
+**
+** test (colors) and (pairs)
+*/
+static void
+color_check(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ if (max_colors <= 0 && max_pairs <= 0) {
+ ptext("This is not a color terminal; (colors) and (pairs) are missing. ");
+ *state |= MENU_STOP;
+ } else {
+ sprintf(temp, "This terminal can display %d colors and %d color pairs. (colors) (pairs)",
+ max_colors, max_pairs);
+ ptextln(temp);
+ }
+ generic_done_message(t, state, ch);
+}
+
+/*
+** color_setf(test_list, status, ch)
+**
+** test (setf) (setb) and (scp)
+*/
+static void
+color_setf(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int i, j;
+
+ if (max_colors <= 0 && max_pairs <= 0) {
+ ptext("This is not a color terminal; (colors) and (pairs) are missing. ");
+ generic_done_message(t, state, ch);
+ *state |= MENU_STOP;
+ return;
+ }
+ if ((set_a_foreground == NULL || set_a_background == NULL)
+ && (set_foreground == NULL || set_background == NULL)
+ && set_color_pair == NULL) {
+ ptextln("Both set foreground (setaf/setf) and set color pair (scp) are not present.");
+ if (!set_a_background || !set_background) {
+ ptextln("(setab/setb) set background not present");
+ }
+ ptext("These must be defined for color testing. ");
+ generic_done_message(t, state, ch);
+ *state |= MENU_STOP;
+ return;
+ }
+ /* initialize the color palette */
+ pairs_used = max_colors >= 8 ? 8 : max_colors;
+ if (can_change) {
+ tc_putp(orig_colors);
+ }
+ tc_putp(tparm(orig_pair));
+ new_color(COLOR_WHITE, COLOR_BLACK, FALSE);
+
+ ptextln("(setf) (setb) (scp) The following colors are predefined:");
+ ptextln("\n Foreground Background");
+ put_crlf();
+ j = max_colors > 8 ? 8 : max_colors;
+ /*
+ the black on white test is the same as the white on black test.
+ */
+ for (i = 1; i < j; i++) {
+ putchp('0' + def_colors[i].index);
+ putchp(' ');
+ sprintf(temp, " %s ", def_colors[i].name);
+
+ new_color(def_colors[i].index, COLOR_BLACK, TRUE);
+ put_str(temp);
+
+ new_color(COLOR_BLACK, COLOR_BLACK, TRUE);
+ put_str(" ");
+
+ new_color(COLOR_BLACK, def_colors[i].index, TRUE);
+ put_str(temp);
+
+ new_color(COLOR_WHITE, COLOR_BLACK, FALSE);
+ put_crlf();
+ }
+ put_crlf();
+ generic_done_message(t, state, ch);
+}
+
+/*
+** color_matrix(test_list, status, ch)
+**
+** test (pairs) (op)
+*/
+static void
+color_matrix(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int i, j, matrix_size, matrix_area, brightness;
+
+ matrix_size = max_colors > 8 ? 8 : max_colors;
+
+ sprintf(temp, "(pairs) There are %d color pairs.", max_pairs);
+ ptextln(temp);
+
+ for ( ; matrix_size; matrix_size--) {
+ if (matrix_size * matrix_size <= max_pairs) {
+ break;
+ }
+ }
+ matrix_area = matrix_size * matrix_size;
+ for (brightness = 0; brightness < 2; brightness++) {
+ put_crlf();
+ sprintf(temp,
+ "%dx%d matrix of foreground/background colors, bright *o%s*",
+ matrix_size, matrix_size, brightness ? "n" : "ff");
+ put_str(temp);
+
+ put_str("\n ");
+ for (i = 0; i < matrix_size; i++) {
+ (void) sprintf(temp, "%-8s", def_colors[i].name);
+ put_str(temp);
+ }
+ for (j = 0; j < matrix_area; j++) {
+ if (j % matrix_size == 0) {
+ tc_putp(tparm(orig_pair));
+ put_crlf();
+ if (brightness) {
+ tc_putp(exit_standout_mode);
+ }
+ (void) sprintf(temp, "%-8s", def_colors[j / matrix_size].name);
+ put_str(temp);
+ if (brightness) {
+ put_mode(enter_bold_mode);
+ }
+ }
+ new_color(def_colors[j % matrix_size].index,
+ def_colors[j / matrix_size].index,
+ FALSE);
+ put_str(" Hello ");
+ }
+ tc_putp(tparm(orig_pair));
+ if (brightness) {
+ tc_putp(exit_standout_mode);
+ }
+ put_crlf();
+ }
+ generic_done_message(t, state, ch);
+}
+
+/*
+** color_ncv(test_list, status, ch)
+**
+** test (ncv)
+*/
+static void
+color_ncv(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int i;
+
+ if (no_color_video == -1) {
+ /* I have no idea what this means */
+ return;
+ }
+ sprintf(temp, "According to no_color_video (ncv) which is %d, the following attributes should work correctly with color.", no_color_video);
+ ptextln(temp);
+ put_crlf();
+ set_attr(0);
+ ncv_display(0);
+ for (i = 1; i <= 9; i++) {
+ if (((no_color_video >> (mode_map[i] - 1)) & 1) == 0) {
+ ncv_display(mode_map[i]);
+ }
+ }
+ if (no_color_video & 0x3ff) {
+ ptextln("\nThe following attributes should not work correctly with color. (ncv)\n");
+ for (i = 1; i <= 9; i++) {
+ if ((no_color_video >> (mode_map[i] - 1)) & 1) {
+ ncv_display(mode_map[i]);
+ }
+ }
+ }
+ tc_putp(orig_pair);
+ put_crlf();
+ generic_done_message(t, state, ch);
+}
+
+/*
+** color_bce(test_list, status, ch)
+**
+** test (bce) background color erase
+*/
+static void
+color_bce(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ new_color(COLOR_BLACK, COLOR_WHITE, FALSE);
+ put_clear();
+ put_newlines(2);
+ new_color(COLOR_WHITE, COLOR_BLACK, FALSE);
+ ptextln("If the two lines above are black then back_color_erase (bce) should be false.");
+ sprintf(temp, "(bce) is %s in the data base.", back_color_erase ? "true" : "false");
+ ptextln(temp);
+ generic_done_message(t, state, ch);
+}
+
+/*
+** color_ccc(test_list, status, ch)
+**
+** test (ccc) color palette test (oc) (op) (initc) (initp)
+*/
+static void
+color_ccc(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int i, j;
+
+ if (!can_change) {
+ ptextln("Terminal can not change colors (ccc)");
+ generic_done_message(t, state, ch);
+ return;
+ }
+ tc_putp(orig_colors);
+ pairs_used = 0;
+ new_color(COLOR_WHITE, COLOR_BLACK, FALSE);
+ sprintf(temp, "Reloading colors (init%c) using %s method",
+ set_foreground ? 'c' : 'p',
+ hue_lightness_saturation ? "HLS" : "RGB");
+ ptextln(temp);
+ put_crlf();
+ j = max_colors > 7 ? 7 : max_colors;
+ /* redisplay the above test with reinitialized colors */
+ /* If these colors don't look right to you... */
+ for (i = 0; i < j; i++) {
+ sprintf(temp, " %s ", def_colors[i ^ 7].name);
+
+ new_color(i ^ 7, COLOR_BLACK, TRUE);
+ put_str(temp);
+
+ new_color(COLOR_BLACK, COLOR_BLACK, TRUE);
+ put_str(" ");
+
+ new_color(COLOR_BLACK, i ^ 7, TRUE);
+ put_str(temp);
+
+ new_color(COLOR_WHITE, COLOR_BLACK, FALSE);
+ put_crlf();
+ }
+ generic_done_message(t, state, ch);
+ if (*ch != 0 && *ch != 'n') {
+ tc_putp(orig_colors);
+ tc_putp(tparm(orig_pair));
+ return;
+ }
+
+ pairs_used = 0;
+ cookie_monster = 0;
+ if (magic_cookie_glitch > 0) {
+ cookie_monster =
+ ((set_a_foreground || set_foreground)
+ ? magic_cookie_glitch : 0) +
+ ((set_a_background || set_background)
+ ? magic_cookie_glitch : 0) +
+ (set_color_pair ? magic_cookie_glitch : 0);
+ }
+ set_color_step();
+ colors_per_line = max_colors > max_pairs
+ ? max_pairs : max_colors;
+ j = (columns - 14) / (cookie_monster + 1);
+ if (colors_per_line > j) {
+ colors_per_line = (j / i) * i;
+ }
+ sprintf(temp, "RGB color step %d, cookies %d", color_step,
+ cookie_monster);
+ ptextln(temp);
+
+ R = G = B = 0;
+ pairs_used = 0;
+ for (;;) {
+ if (rainbow(colors_per_line)) {
+ break;
+ }
+ }
+ generic_done_message(t, state, ch);
+ if (*ch != 0 && *ch != 'n') {
+ tc_putp(orig_colors);
+ tc_putp(tparm(orig_pair));
+ return;
+ }
+ dump_colors();
+ tc_putp(orig_colors);
+ tc_putp(tparm(orig_pair));
+ generic_done_message(t, state, ch);
+}
diff --git a/contrib/ncurses/tack/control.c b/contrib/ncurses/tack/control.c
new file mode 100644
index 000000000000..4c2158e4dda3
--- /dev/null
+++ b/contrib/ncurses/tack/control.c
@@ -0,0 +1,657 @@
+/*
+** Copyright (C) 1991, 1997 Free Software Foundation, Inc.
+**
+** This file is part of TACK.
+**
+** TACK is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2, or (at your option)
+** any later version.
+**
+** TACK is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with TACK; see the file COPYING. If not, write to
+** the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA 02111-1307, USA.
+*/
+
+#include <tack.h>
+
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+MODULE_ID("$Id: control.c,v 1.2 1999/06/16 00:45:59 tom Exp $")
+
+/* terminfo test program control subroutines */
+
+#if HAVE_GETTIMEOFDAY
+#define MY_TIMER struct timeval
+#else
+#define MY_TIMER time_t
+#endif
+
+/* globals */
+int test_complete; /* counts number of tests completed */
+
+char txt_longer_test_time[80]; /* +) use longer time */
+char txt_shorter_test_time[80]; /* -) use shorter time */
+int pad_test_duration = 1; /* number of seconds for a pad test */
+int auto_pad_mode; /* run the time tests */
+int no_alarm_event; /* TRUE if the alarm has not gone off yet */
+int usec_run_time; /* length of last test in microseconds */
+MY_TIMER stop_watch[MAX_TIMERS]; /* Hold the start timers */
+
+char txt_longer_augment[80]; /* >) use bigger augment */
+char txt_shorter_augment[80]; /* <) use smaller augment */
+
+/* caps under test data base */
+int tt_delay_max; /* max number of milliseconds we can delay */
+int tt_delay_used; /* number of milliseconds consumed in delay */
+const char *tt_cap[TT_MAX]; /* value of string */
+int tt_affected[TT_MAX]; /* lines or columns effected (repitition factor) */
+int tt_count[TT_MAX]; /* Number of times sent */
+int tt_delay[TT_MAX]; /* Number of milliseconds delay */
+int ttp; /* number of entries used */
+
+/* Saved value of the above data base */
+const char *tx_cap[TT_MAX]; /* value of string */
+int tx_affected[TT_MAX]; /* lines or columns effected (repitition factor) */
+int tx_count[TT_MAX]; /* Number of times sent */
+int tx_index[TT_MAX]; /* String index */
+int tx_delay[TT_MAX]; /* Number of milliseconds delay */
+int txp; /* number of entries used */
+int tx_characters; /* printing characters sent by test */
+int tx_cps; /* characters per second */
+struct test_list *tx_source; /* The test that generated this data */
+
+extern struct test_menu pad_menu; /* Pad menu structure */
+extern struct test_list pad_test_list[];
+
+#define RESULT_BLOCK 1024
+static int blocks; /* number of result blocks available */
+static struct test_results *results; /* pointer to next available */
+struct test_results *pads[STRCOUNT]; /* save pad results here */
+
+/*
+** event_start(number)
+**
+** Begin the stopwatch at the current time-of-day.
+*/
+void
+event_start(int n)
+{
+#if HAVE_GETTIMEOFDAY
+ (void) gettimeofday(&stop_watch[n], (struct timezone *)0);
+#else
+ stop_watch[n] = time((time_t *)0);
+#endif
+}
+
+/*
+** event_time(number)
+**
+** Return the number of milliseconds since this stop watch began.
+*/
+long
+event_time(int n)
+{
+#if HAVE_GETTIMEOFDAY
+ MY_TIMER current_time;
+
+ (void) gettimeofday(&current_time, (struct timezone *)0);
+ return ((current_time.tv_sec - stop_watch[n].tv_sec) * 1000000)
+ + current_time.tv_usec - stop_watch[n].tv_usec;
+#else
+ return (time((time_t *)0) - stop_watch[n]) * 1000;
+#endif
+}
+
+/*****************************************************************************
+ *
+ * Execution control for string capability tests
+ *
+ *****************************************************************************/
+
+/*
+** get_next_block()
+**
+** Get a results block for pad test data.
+*/
+static struct test_results *
+get_next_block(void)
+{
+ if (blocks <= 0) {
+ results = (struct test_results *)
+ malloc(sizeof(struct test_results) * RESULT_BLOCK);
+ if (!results) {
+ ptextln("Malloc failed");
+ return (struct test_results *) 0;
+ }
+ blocks = RESULT_BLOCK;
+ }
+ blocks--;
+ return results++;
+}
+
+/*
+** set_augment_txt()
+**
+** Initialize the augment menu selections
+*/
+void
+set_augment_txt(void)
+{
+ sprintf(txt_longer_augment,
+ ">) Change lines/characters effected to %d", augment << 1);
+ sprintf(txt_shorter_augment,
+ "<) Change lines/characters effected to %d", augment >> 1);
+}
+
+void
+control_init(void)
+{
+ sprintf(txt_longer_test_time, "+) Change test time to %d seconds",
+ pad_test_duration + 1);
+ sprintf(txt_shorter_test_time, "-) Change test time to %d seconds",
+ pad_test_duration - 1);
+ set_augment_txt();
+}
+
+/*
+** msec_cost(cap, affected-count)
+**
+** Return the number of milliseconds delay needed by the cap.
+*/
+int
+msec_cost(
+ const char *const cap,
+ int affcnt)
+{
+ int dec, value, total, star, ch;
+ const char *cp;
+
+ if (!cap) {
+ return 0;
+ }
+ total = 0;
+ for (cp = cap; *cp; cp++) {
+ if (*cp == '$' && cp[1] == '<') {
+ star = 1;
+ value = dec = 0;
+ for (cp += 2; (ch = *cp); cp++) {
+ if (ch >= '0' && ch <= '9') {
+ value = value * 10 + (ch - '0');
+ dec *= 10;
+ } else
+ if (ch == '.') {
+ dec = 1;
+ } else
+ if (ch == '*') {
+ star = affcnt;
+ } else
+ if (ch == '>') {
+ break;
+ }
+ }
+ if (dec > 1) {
+ total += (value * star) / dec;
+ } else {
+ total += (value * star);
+ }
+ }
+ }
+ return total;
+}
+
+/*
+** liberated(cap)
+**
+** Return the cap without padding
+*/
+char *
+liberated(char *cap)
+{
+ static char cb[1024];
+ char *ts, *ls;
+
+ cb[0] = '\0';
+ ls = NULL;
+ if (cap) {
+ for (ts = cb; (*ts = *cap); ++cap) {
+ if (*cap == '$' && cap[1] == '<') {
+ ls = ts;
+ }
+ ++ts;
+ if (*cap == '>') {
+ if (ls) {
+ ts = ls;
+ ls = NULL;
+ }
+ }
+ }
+ }
+ return cb;
+}
+
+/*
+** page_loop()
+**
+** send CR/LF or go home and bump letter
+*/
+void
+page_loop(void)
+{
+ if (line_count + 2 >= lines) {
+ NEXT_LETTER;
+ go_home();
+ } else {
+ put_crlf();
+ }
+}
+
+/*
+** skip_pad_test(test-list-entry, state, ch, text)
+**
+** Print the start test line. Handle start up commands.
+** Return TRUE if a return is requested.
+*/
+int
+skip_pad_test(
+ struct test_list *test,
+ int *state,
+ int *ch,
+ const char *text)
+{
+ char rep_text[16];
+
+ while(1) {
+ if (text) {
+ ptext(text);
+ }
+ if ((test->flags & MENU_LC_MASK)) {
+ sprintf(rep_text, " *%d", augment);
+ ptext(rep_text);
+ }
+ ptext(" [n] > ");
+ *ch = wait_here();
+ if (*ch == 's') {
+ /* Skip is converted to next */
+ *ch = 'n';
+ return TRUE;
+ }
+ if (*ch == 'q') {
+ /* Quit is converted to help */
+ *ch = '?';
+ return TRUE;
+ }
+ if (*ch == '\r' || *ch == '\n' || *ch == 'n' || *ch == 'r') {
+ /* this is the only response that allows the test to run */
+ *ch = 0;
+ }
+ if (subtest_menu(pad_test_list, state, ch)) {
+ continue;
+ }
+ return (*ch != 0);
+ }
+}
+
+/*
+** pad_done_message(test_list)
+**
+** Print the Done message and request input.
+*/
+void
+pad_done_message(
+ struct test_list *test,
+ int *state,
+ int *ch)
+{
+ int default_action = 0;
+ char done_message[128];
+ char rep_text[16];
+
+ while (1) {
+ if ((test->flags & MENU_LC_MASK)) {
+ sprintf(rep_text, "*%d", augment);
+ } else {
+ rep_text[0] = '\0';
+ }
+ if (test->caps_done) {
+ sprintf(done_message, "(%s)%s Done ", test->caps_done,
+ rep_text);
+ ptext(done_message);
+ } else {
+ if (rep_text[0]) {
+ ptext(rep_text);
+ ptext(" ");
+ }
+ ptext("Done ");
+ }
+ if (debug_level & 2) {
+ dump_test_stats(test, state, ch);
+ } else {
+ *ch = wait_here();
+ }
+ if (*ch == '\r' || *ch == '\n') {
+ *ch = default_action;
+ return;
+ }
+ if (*ch == 's' || *ch == 'n') {
+ *ch = 0;
+ return;
+ }
+ if (strchr(pad_repeat_test, *ch)) {
+ /* default action is now repeat */
+ default_action = 'r';
+ }
+ if (subtest_menu(pad_test_list, state, ch)) {
+ continue;
+ }
+ return;
+ }
+}
+
+/*
+** sliding_scale(dividend, factor, divisor)
+**
+** Return (dividend * factor) / divisor
+*/
+int
+sliding_scale(
+ int dividend,
+ int factor,
+ int divisor)
+{
+ double d = dividend;
+
+ if (divisor) {
+ d = (d * (double) factor) / (double) divisor;
+ return (int) (d + 0.5);
+ }
+ return 0;
+}
+
+/*
+** pad_test_startup()
+**
+** Do the stuff needed to begin a test.
+*/
+void
+pad_test_startup(
+ int do_clear)
+{
+ if (do_clear) {
+ put_clear();
+ }
+ repeats = augment;
+ raw_characters_sent = 0;
+ test_complete = ttp = char_count = tt_delay_used = 0;
+ letter = letters[letter_number = 0];
+ if (pad_test_duration <= 0) {
+ pad_test_duration = 1;
+ }
+ tt_delay_max = pad_test_duration * 1000;
+ set_alarm_clock(pad_test_duration);
+ event_start(TIME_TEST);
+}
+
+/*
+** still_testing()
+**
+** This function is called to see if the test loop should be terminated.
+*/
+int
+still_testing(void)
+{
+ fflush(stdout);
+ test_complete++;
+ return EXIT_CONDITION;
+}
+
+/*
+** pad_test_shutdown()
+**
+** Do the stuff needed to end a test.
+*/
+void
+pad_test_shutdown(
+ struct test_list *t,
+ int crlf)
+{
+ int i;
+ int counts; /* total counts */
+ int ss; /* Save string index */
+ int cpo; /* characters per operation */
+ int delta; /* difference in characters */
+ int bogus; /* Time is inaccurate */
+ struct test_results *r; /* Results of current test */
+ int ss_index[TT_MAX]; /* String index */
+
+ if (tty_can_sync == SYNC_TESTED) {
+ bogus = tty_sync_error();
+ } else {
+ bogus = 1;
+ }
+ usec_run_time = event_time(TIME_TEST);
+ tx_source = t;
+ tx_characters = raw_characters_sent;
+ tx_cps = sliding_scale(tx_characters, 1000000, usec_run_time);
+
+ /* save the data base */
+ for (txp = ss = counts = 0; txp < ttp; txp++) {
+ tx_cap[txp] = tt_cap[txp];
+ tx_count[txp] = tt_count[txp];
+ tx_delay[txp] = tt_delay[txp];
+ tx_affected[txp] = tt_affected[txp];
+ tx_index[txp] = get_string_cap_byvalue(tt_cap[txp]);
+ if (tx_index[txp] >= 0) {
+ if (cap_match(t->caps_done, strnames[tx_index[txp]])) {
+ ss_index[ss++] = txp;
+ counts += tx_count[txp];
+ }
+ }
+ }
+
+ if (crlf) {
+ put_crlf();
+ }
+ if (counts == 0 || tty_cps == 0 || bogus) {
+ /* nothing to do */
+ return;
+ }
+ /* calculate the suggested pad times */
+ delta = usec_run_time - sliding_scale(tx_characters, 1000000, tty_cps);
+ if (delta < 0) {
+ /* probably should bump tx_characters */
+ delta = 0;
+ }
+ cpo = delta / counts;
+ for (i = 0; i < ss; i++) {
+ if (!(r = get_next_block())) {
+ return;
+ }
+ r->next = pads[tx_index[ss_index[i]]];
+ pads[tx_index[ss_index[i]]] = r;
+ r->test = t;
+ r->reps = tx_affected[ss_index[i]];
+ r->delay = cpo;
+ }
+}
+
+/*
+** show_cap_results(index)
+**
+** Display the previous results
+*/
+static void
+show_cap_results(
+ int x)
+{
+ struct test_results *r; /* a result */
+ int delay;
+
+ if ((r = pads[x])) {
+ sprintf(temp, "(%s)", strnames[x]);
+ ptext(temp);
+ while (r) {
+ sprintf(temp, "$<%d>", r->delay / 1000);
+ put_columns(temp, strlen(temp), 10);
+ r = r->next;
+ }
+ r = pads[x];
+ while (r) {
+ if (r->reps > 1) {
+ delay = r->delay / (r->reps * 100);
+ sprintf(temp, "$<%d.%d*>", delay / 10, delay % 10);
+ put_columns(temp, strlen(temp), 10);
+ }
+ r = r->next;
+ }
+ put_crlf();
+ }
+}
+
+/*
+** dump_test_stats(test_list, status, ch)
+**
+** Dump the statistics about the last test
+*/
+void
+dump_test_stats(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int i, j;
+ char tbuf[32];
+ int x[32];
+
+ put_crlf();
+ if (tx_source && tx_source->caps_done) {
+ cap_index(tx_source->caps_done, x);
+ if (x[0] >= 0) {
+ sprintf(temp, "Caps summary for (%s)",
+ tx_source->caps_done);
+ ptextln(temp);
+ for (i = 0; x[i] >= 0; i++) {
+ show_cap_results(x[i]);
+ }
+ put_crlf();
+ }
+ }
+ sprintf(tbuf, "%011u", usec_run_time);
+ sprintf(temp, "Test time: %d.%s, characters per second %d, characters %d",
+ usec_run_time / 1000000, &tbuf[5], tx_cps, tx_characters);
+ ptextln(temp);
+ for (i = 0; i < txp; i++) {
+ if ((j = get_string_cap_byvalue(tx_cap[i])) >= 0) {
+ sprintf(tbuf, "(%s)", strnames[j]);
+ } else {
+ strcpy(tbuf, "(?)");
+ }
+ sprintf(temp, "%8d %3d $<%3d> %8s %s",
+ tx_count[i], tx_affected[i], tx_delay[i],
+ tbuf, expand(tx_cap[i]));
+ putln(temp);
+ }
+ generic_done_message(t, state, ch);
+}
+
+/*
+** longer_test_time(test_list, status, ch)
+**
+** Extend the number of seconds for each test.
+*/
+void
+longer_test_time(
+ struct test_list *t GCC_UNUSED,
+ int *state GCC_UNUSED,
+ int *ch)
+{
+ pad_test_duration += 1;
+ sprintf(txt_longer_test_time, "+) Change test time to %d seconds",
+ pad_test_duration + 1);
+ sprintf(txt_shorter_test_time, "-) Change test time to %d seconds",
+ pad_test_duration - 1);
+ sprintf(temp, "Tests will run for %d seconds", pad_test_duration);
+ ptext(temp);
+ *ch = REQUEST_PROMPT;
+}
+
+/*
+** shorter_test_time(test_list, status, ch)
+**
+** Shorten the number of seconds for each test.
+*/
+void
+shorter_test_time(
+ struct test_list *t GCC_UNUSED,
+ int *state GCC_UNUSED,
+ int *ch)
+{
+ if (pad_test_duration > 1) {
+ pad_test_duration -= 1;
+ sprintf(txt_longer_test_time, "+) Change test time to %d seconds",
+ pad_test_duration + 1);
+ sprintf(txt_shorter_test_time, "-) Change test time to %d seconds",
+ pad_test_duration - 1);
+ }
+ sprintf(temp, "Tests will run for %d second%s", pad_test_duration,
+ pad_test_duration > 1 ? "s" : "");
+ ptext(temp);
+ *ch = REQUEST_PROMPT;
+}
+
+/*
+** longer_augment(test_list, status, ch)
+**
+** Lengthen the number of lines/characters effected
+*/
+void
+longer_augment(
+ struct test_list *t,
+ int *state GCC_UNUSED,
+ int *ch)
+{
+ augment <<= 1;
+ set_augment_txt();
+ if (augment_test) {
+ t = augment_test;
+ }
+ sprintf(temp, "The pad tests will effect %d %s.", augment,
+ ((t->flags & MENU_LC_MASK) == MENU_lines) ?
+ "lines" : "characters");
+ ptextln(temp);
+ *ch = REQUEST_PROMPT;
+}
+
+/*
+** shorter_augment(test_list, status, ch)
+**
+** Shorten the number of lines/characters effected
+*/
+void
+shorter_augment(
+ struct test_list *t,
+ int *state GCC_UNUSED,
+ int *ch)
+{
+ if (augment > 1) {
+ /* don't let the augment go to zero */
+ augment >>= 1;
+ }
+ set_augment_txt();
+ if (augment_test) {
+ t = augment_test;
+ }
+ sprintf(temp, "The pad tests will effect %d %s.", augment,
+ ((t->flags & MENU_LC_MASK) == MENU_lines) ?
+ "lines" : "characters");
+ ptextln(temp);
+ *ch = REQUEST_PROMPT;
+}
diff --git a/contrib/ncurses/tack/crum.c b/contrib/ncurses/tack/crum.c
new file mode 100644
index 000000000000..94183635b2ec
--- /dev/null
+++ b/contrib/ncurses/tack/crum.c
@@ -0,0 +1,426 @@
+/*
+** Copyright (C) 1991, 1997 Free Software Foundation, Inc.
+**
+** This file is part of TACK.
+**
+** TACK is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2, or (at your option)
+** any later version.
+**
+** TACK is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with TACK; see the file COPYING. If not, write to
+** the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA 02111-1307, USA.
+*/
+
+#include <tack.h>
+
+MODULE_ID("$Id: crum.c,v 1.2 1999/08/21 23:09:08 tom Exp $")
+
+/*
+ * Test cursor movement.
+ */
+
+static void crum_clear(struct test_list *t, int *state, int *ch);
+static void crum_home(struct test_list *t, int *state, int *ch);
+static void crum_ll(struct test_list *t, int *state, int *ch);
+static void crum_move(struct test_list *t, int *state, int *ch);
+static void crum_os(struct test_list *t, int *state, int *ch);
+
+static char crum_text[5][80];
+
+struct test_list crum_test_list[] = {
+ {0, 0, 0, 0, "e) edit terminfo", 0, &edit_menu},
+ {MENU_NEXT, 0, "clear", 0, 0, crum_clear, 0},
+ {MENU_NEXT, 0, "home", 0, 0, crum_home, 0},
+ {MENU_NEXT, 0, "ll", 0, 0, crum_ll, 0},
+ {MENU_NEXT, 0, crum_text[0], "home cuu1", 0, crum_move, 0},
+ {MENU_NEXT + 1, 0, crum_text[1], "cub1 cud1 cuf1 cuu1", 0, crum_move, 0},
+ {MENU_NEXT + 2, 0, crum_text[2], "cub cud cuf cuu", 0, crum_move, 0},
+ {MENU_NEXT + 3, 0, crum_text[3], "vpa hpa", 0, crum_move, 0},
+ {MENU_NEXT + 4, 0, crum_text[4], "cup", 0, crum_move, 0},
+ {MENU_NEXT, 0, "cup", "os", 0, crum_os, 0},
+ {MENU_LAST, 0, 0, 0, 0, 0, 0}
+};
+
+/*
+** move_to(from-row, from-column, to-row, to-column, selection)
+**
+** move the cursor from (rf, cf) to (rt, ct) using sel
+*/
+static void
+move_to(
+ int rf,
+ int cf,
+ int rt,
+ int ct,
+ int sel)
+{
+ char *s;
+
+ if (sel & 16) { /* use (cup) */
+ s = tparm(cursor_address, rt, ct);
+ tputs(s, lines, tc_putch);
+ return;
+ }
+ if (sel & 8) { /* use (hpa) (vpa) */
+ if (column_address) {
+ s = tparm(column_address, ct);
+ tputs(s, 1, tc_putch);
+ cf = ct;
+ }
+ if (row_address) {
+ s = tparm(row_address, rt);
+ tputs(s, 1, tc_putch);
+ rf = rt;
+ }
+ }
+ if (sel & 4) { /* paramiterized relative cursor movement */
+ if (parm_right_cursor)
+ if (cf < ct) {
+ s = tparm(parm_right_cursor, ct - cf);
+ tputs(s, ct - cf, tc_putch);
+ cf = ct;
+ }
+ if (parm_left_cursor)
+ if (cf > ct) {
+ s = tparm(parm_left_cursor, cf - ct);
+ tputs(s, cf - ct, tc_putch);
+ cf = ct;
+ }
+ if (parm_down_cursor)
+ if (rf < rt) {
+ s = tparm(parm_down_cursor, rt - rf);
+ tputs(s, rt - rf, tc_putch);
+ rf = rt;
+ }
+ if (parm_up_cursor)
+ if (rf > rt) {
+ s = tparm(parm_up_cursor, rf - rt);
+ tputs(s, rf - rt, tc_putch);
+ rf = rt;
+ }
+ }
+ if (sel & 2) {
+ if (cursor_left)
+ while (cf > ct) {
+ tc_putp(cursor_left);
+ cf--;
+ }
+ /*
+ do vertical motion next. Just in case cursor_down has a
+ side effect of changing the column. This could happen if
+ the tty handler translates NL to CRNL.
+ */
+ if (cursor_down)
+ while (rf < rt) {
+ tc_putp(cursor_down);
+ rf++;
+ }
+ if (cursor_up)
+ while (rf > rt) {
+ tc_putp(cursor_up);
+ rf--;
+ }
+ if (cursor_right)
+ while (cf < ct) {
+ tc_putp(cursor_right);
+ cf++;
+ }
+ }
+ /* last chance */
+ if (rf > rt) {
+ if (can_go_home) { /* a bit drastic but ... */
+ go_home();
+ cf = 0;
+ rf = 0;
+ } else if (cursor_up) {
+ while (rf > rt) {
+ tc_putp(cursor_up);
+ rf--;
+ }
+ }
+ }
+ if (ct == 0 && rt > rf) {
+ put_crlf();
+ cf = 0;
+ rf++;
+ }
+ if (ct == 0 && cf != 0) {
+ put_cr();
+ cf = 0;
+ }
+ while (rf < rt) {
+ put_lf();
+ rf++;
+ }
+ while (cf > ct) {
+ put_str("\b");
+ cf--;
+ }
+ if (cursor_right) {
+ while (cf < ct) {
+ tc_putp(cursor_right);
+ cf++;
+ }
+ } else {
+ /* go ahead and trash my display */
+ while (cf < ct) {
+ putchp(' ');
+ cf++;
+ }
+ }
+}
+
+/*
+** display_it(selection, text)
+**
+** print the display using sel
+*/
+static void
+display_it(
+ int sel,
+ char *txt)
+{
+ int i, done_line;
+
+ put_clear();
+ go_home();
+ put_newlines(2);
+ ptextln(" The top line should be alternating <'s and >'s");
+ ptextln(" The left side should be alternating A's and V's");
+ ptext(" Testing ");
+ ptext(txt);
+ put_cr();
+
+ /* horizontal */
+ move_to(done_line = line_count, 0, 0, 2, sel);
+ for (i = 4; i < columns - 2; i += 2) {
+ putchp('>');
+ move_to(0, i - 1, 0, i, sel);
+ }
+ putchp('>');
+ i -= 2;
+ move_to(0, i + 1, 0, i - 1, sel);
+ for (; i > 2; i -= 2) {
+ putchp('<');
+ move_to(0, i, 0, i - 3, sel);
+ }
+ putchp('<');
+
+ /* vertical */
+ move_to(0, 2, 0, 0, sel);
+ for (i = 2; i < lines - 1; i += 2) {
+ putchp('V');
+ move_to(i - 2, 1, i, 0, sel);
+ }
+ putchp('V');
+ i -= 2;
+ move_to(i, 1, i + 1, 0, sel);
+ for (; i > 0; i -= 2) {
+ putchp('A');
+ move_to(i + 1, 1, i - 1, 0, sel);
+ }
+ putchp('A');
+ move_to(i + 1, 1, 0, 0, sel); /* go home first */
+ move_to(0, 0, done_line + 1, 3, sel);
+ put_str(txt);
+ put_str(" Done. ");
+}
+
+/*
+** crum_clear(test_list, status, ch)
+**
+** (clear) test Clear screen
+*/
+static void
+crum_clear(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int i;
+
+ if (clear_screen) {
+ for (i = lines; i > 1; i--) {
+ putln("garbage");
+ }
+ put_clear();
+ ptextln("This line should start in the home position.");
+ ptext("The rest of the screen should be clear. ");
+ } else {
+ ptextln("(clear) Clear screen is not defined. ");
+ }
+ generic_done_message(t, state, ch);
+}
+
+/*
+** crum_home(test_list, status, ch)
+**
+** (home) test Home cursor
+*/
+static void
+crum_home(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ if (cursor_home) {
+ put_clear();
+ put_newlines(lines / 2);
+ go_home();
+ put_crlf();
+ ptext("The bottom line should have text.");
+ go_home();
+ put_newlines(lines - 1);
+ ptext("This line is on the bottom.");
+ go_home();
+ ptextln("This line starts in the home position.");
+ put_crlf();
+ } else {
+ ptextln("(home) Home cursor is not defined. ");
+ }
+ generic_done_message(t, state, ch);
+}
+
+/*
+** crum_ll(test_list, status, ch)
+**
+** (ll) test Last line
+*/
+static void
+crum_ll(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ /*
+ (ll) may be simulated with (cup). Don't complain if (cup) is present.
+ */
+ if (cursor_to_ll) {
+ put_clear();
+ put_str("This line could be anywhere.");
+ tc_putp(cursor_to_ll);
+ ptext("This line should be on the bottom");
+ go_home();
+ put_crlf();
+ } else
+ if (cursor_address) {
+ return;
+ } else {
+ ptextln("(ll) Move to last line is not defined. ");
+ }
+ generic_done_message(t, state, ch);
+}
+
+/*
+** crum_move(test_list, status, ch)
+**
+** (*) test all cursor move commands
+*/
+static void
+crum_move(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ char buf[80];
+ int n;
+
+ switch (n = (t->flags & 15)) {
+ case 0:
+ sprintf(buf, " (cr) (nel) (cub1)%s",
+ cursor_home ? " (home)" : (cursor_up ? " (cuu1)" : ""));
+ break;
+ case 1:
+ sprintf(buf, "%s%s%s%s", cursor_left ? " (cub1)" : "",
+ cursor_down ? " (cud1)" : "", cursor_right ? " (cuf1)" : "",
+ cursor_up ? " (cuu1)" : "");
+ if (buf[0] == '\0') {
+ ptext(" (cub1) (cud1) (cuf1) (cuu1) not defined.");
+ }
+ break;
+ case 2:
+ sprintf(buf, "%s%s%s%s", parm_left_cursor ? " (cub)" : "",
+ parm_down_cursor ? " (cud)" : "",
+ parm_right_cursor ? " (cuf)" : "",
+ parm_up_cursor ? " (cuu)" : "");
+ if (buf[0] == '\0') {
+ ptext(" (cub) (cud) (cuf) (cuu) not defined.");
+ }
+ break;
+ case 3:
+ sprintf(buf, "%s%s", row_address ? " (vpa)" : "",
+ column_address ? " (hpa)" : "");
+ if (buf[0] == '\0') {
+ ptext(" (vpa) (hpa) not defined.");
+ }
+ break;
+ case 4:
+ if (!cursor_address) {
+ ptext(" (cup) not defined. ");
+ generic_done_message(t, state, ch);
+ return;
+ }
+ strcpy(buf, " (cup)");
+ break;
+ }
+ if (buf[0] == '\0') {
+ put_str(" Done. ");
+ } else {
+ can_test(buf, FLAG_TESTED);
+ strcpy(crum_text[n], &buf[2]);
+ crum_text[n][strlen(buf) - 3] = '\0';
+
+ display_it(1 << n, buf);
+ }
+ *ch = wait_here();
+ if (*ch != 'r') {
+ put_clear();
+ }
+}
+
+/*
+** crum_os(test_list, status, ch)
+**
+** (cup) test Cursor position on overstrike terminals
+*/
+static void
+crum_os(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int i;
+
+ if (cursor_address && over_strike) {
+ put_clear();
+ for (i = 0; i < columns - 2; i++) {
+ tc_putch('|');
+ }
+ for (i = 1; i < lines - 2; i++) {
+ put_crlf();
+ tc_putch('_');
+ }
+ for (i = 0; i < columns - 2; i++) {
+ tputs(tparm(cursor_address, 0, i), lines, tc_putch);
+ tc_putch('+');
+ }
+ for (i = 0; i < lines - 2; i++) {
+ tputs(tparm(cursor_address, i, 0), lines, tc_putch);
+ tc_putch(']');
+ tc_putch('_');
+ }
+ go_home();
+ put_newlines(3);
+ ptext(" All the characters should look the same. ");
+ generic_done_message(t, state, ch);
+ put_clear();
+ }
+}
diff --git a/contrib/ncurses/tack/edit.c b/contrib/ncurses/tack/edit.c
new file mode 100644
index 000000000000..5685d9253fe6
--- /dev/null
+++ b/contrib/ncurses/tack/edit.c
@@ -0,0 +1,977 @@
+/*
+** Copyright (C) 1997 Free Software Foundation, Inc.
+**
+** This file is part of TACK.
+**
+** TACK is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2, or (at your option)
+** any later version.
+**
+** TACK is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with TACK; see the file COPYING. If not, write to
+** the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA 02111-1307, USA.
+*/
+
+#include <tack.h>
+#include <time.h>
+#include <tic.h>
+
+MODULE_ID("$Id: edit.c,v 1.3 1999/06/16 00:43:43 tom Exp $")
+
+/*
+ * Terminfo edit features
+ */
+static void show_info(struct test_list *, int *, int *);
+static void show_value(struct test_list *, int *, int *);
+static void show_untested(struct test_list *, int *, int *);
+static void show_changed(struct test_list *, int *, int *);
+
+#define SHOW_VALUE 1
+#define SHOW_EDIT 2
+#define SHOW_DELETE 3
+
+struct test_list edit_test_list[] = {
+ {MENU_CLEAR, 0, 0, 0, "i) display current terminfo", show_info, 0},
+ {0, 0, 0, 0, "w) write the current terminfo to a file", save_info, 0},
+ {SHOW_VALUE, 3, 0, 0, "v) show value of a selected cap", show_value, 0},
+ {SHOW_EDIT, 4, 0, 0, "e) edit value of a selected cap", show_value, 0},
+ {SHOW_DELETE, 3, 0, 0, "d) delete string", show_value, 0},
+ {0, 3, 0, 0, "m) show caps that have been modified", show_changed, 0},
+ {MENU_CLEAR + FLAG_CAN_TEST, 0, 0, 0, "c) show caps that can be tested", show_report, 0},
+ {MENU_CLEAR + FLAG_TESTED, 0, 0, 0, "t) show caps that have been tested", show_report, 0},
+ {MENU_CLEAR + FLAG_FUNCTION_KEY, 0, 0, 0, "f) show a list of function keys", show_report, 0},
+ {MENU_CLEAR, 0, 0, 0, "u) show caps defined that can not be tested", show_untested, 0},
+ {MENU_LAST, 0, 0, 0, 0, 0, 0}
+};
+
+static char change_pad_text[MAX_CHANGES][80];
+struct test_list change_pad_list[MAX_CHANGES] = {
+ {MENU_LAST, 0, 0, 0, 0, 0, 0}
+};
+
+static void build_change_menu(struct test_menu *);
+static void change_one_entry(struct test_list *, int *, int *);
+
+struct test_menu change_pad_menu = {
+ 0, 'q', 0,
+ "Select cap name", "change", 0,
+ build_change_menu, change_pad_list, 0, 0, 0
+};
+
+extern struct test_results *pads[STRCOUNT]; /* save pad results here */
+
+static TERMTYPE original_term; /* terminal type description */
+
+static char flag_boolean[BOOLCOUNT]; /* flags for booleans */
+static char flag_numerics[NUMCOUNT]; /* flags for numerics */
+static char flag_strings[STRCOUNT]; /* flags for strings */
+static int xon_index; /* Subscript for (xon) */
+int xon_shadow;
+
+static int start_display; /* the display has just started */
+static int display_lines; /* number of lines displayed */
+
+/*
+** send_info_string(str)
+**
+** Return the terminfo string prefixed by the correct seperator
+*/
+static void
+send_info_string(
+ const char *str,
+ int *ch)
+{
+ int len;
+
+ if (display_lines == -1) {
+ return;
+ }
+ len = strlen(str);
+ if (len + char_count + 3 >= columns) {
+ if (start_display == 0) {
+ put_str(",");
+ }
+ put_crlf();
+ if (++display_lines > lines) {
+ ptext("-- more -- ");
+ *ch = wait_here();
+ if (*ch == 'q') {
+ display_lines = -1;
+ return;
+ }
+ display_lines = 0;
+ }
+ if (len >= columns) {
+ /* if the terminal does not (am) then this loses */
+ if (columns) {
+ display_lines += ((strlen(str) + 3) / columns) + 1;
+ }
+ put_str(" ");
+ put_str(str);
+ start_display = 0;
+ return;
+ }
+ ptext(" ");
+ } else
+ if (start_display == 0) {
+ ptext(", ");
+ } else {
+ ptext(" ");
+ }
+ ptext(str);
+ start_display = 0;
+}
+
+/*
+** show_info(test_list, status, ch)
+**
+** Display the current terminfo
+*/
+static void
+show_info(
+ struct test_list *t GCC_UNUSED,
+ int *state GCC_UNUSED,
+ int *ch)
+{
+ int i;
+ char buf[1024];
+
+ display_lines = 1;
+ start_display = 1;
+ for (i = 0; i < BOOLCOUNT; i++) {
+ if ((i == xon_index) ? xon_shadow : CUR Booleans[i]) {
+ send_info_string(boolnames[i], ch);
+ }
+ }
+ for (i = 0; i < NUMCOUNT; i++) {
+ if (CUR Numbers[i] >= 0) {
+ sprintf(buf, "%s#%d", numnames[i], CUR Numbers[i]);
+ send_info_string(buf, ch);
+ }
+ }
+ for (i = 0; i < STRCOUNT; i++) {
+ if (CUR Strings[i]) {
+ sprintf(buf, "%s=%s", strnames[i],
+ print_expand(CUR Strings[i]));
+ send_info_string(buf, ch);
+ }
+ }
+ put_newlines(2);
+ *ch = REQUEST_PROMPT;
+}
+
+/*
+** save_info_string(str, fp)
+**
+** Write the terminfo string prefixed by the correct seperator
+*/
+static void
+save_info_string(
+ const char *str,
+ FILE *fp)
+{
+ int len;
+
+ len = strlen(str);
+ if (len + display_lines >= 77) {
+ if (display_lines > 0) {
+ (void) fprintf(fp, "\n\t");
+ }
+ display_lines = 8;
+ } else
+ if (display_lines > 0) {
+ (void) fprintf(fp, " ");
+ display_lines++;
+ } else {
+ (void) fprintf(fp, "\t");
+ display_lines = 8;
+ }
+ (void) fprintf(fp, "%s,", str);
+ display_lines += len + 1;
+}
+
+/*
+** save_info(test_list, status, ch)
+**
+** Write the current terminfo to a file
+*/
+void
+save_info(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int i;
+ FILE *fp;
+ time_t now;
+ char buf[1024];
+
+ if ((fp = fopen(tty_basename, "w")) == (FILE *) NULL) {
+ (void) sprintf(temp, "can't open: %s", tty_basename);
+ ptextln(temp);
+ generic_done_message(t, state, ch);
+ return;
+ }
+ time(&now);
+ /* Note: ctime() returns a newline at the end of the string */
+ (void) fprintf(fp, "# Terminfo created by TACK for TERM=%s on %s",
+ tty_basename, ctime(&now));
+ (void) fprintf(fp, "%s|%s,\n", tty_basename, longname());
+
+ display_lines = 0;
+ for (i = 0; i < BOOLCOUNT; i++) {
+ if (i == xon_index ? xon_shadow : CUR Booleans[i]) {
+ save_info_string(boolnames[i], fp);
+ }
+ }
+ for (i = 0; i < NUMCOUNT; i++) {
+ if (CUR Numbers[i] >= 0) {
+ sprintf(buf, "%s#%d", numnames[i], CUR Numbers[i]);
+ save_info_string(buf, fp);
+ }
+ }
+ for (i = 0; i < STRCOUNT; i++) {
+ if (CUR Strings[i]) {
+ sprintf(buf, "%s=%s", strnames[i],
+ _nc_tic_expand(CUR Strings[i], TRUE, TRUE));
+ save_info_string(buf, fp);
+ }
+ }
+ (void) fprintf(fp, "\n");
+ (void) fclose(fp);
+ sprintf(temp, "Terminfo saved as file: %s", tty_basename);
+ ptextln(temp);
+}
+
+/*
+** show_value(test_list, status, ch)
+**
+** Display the value of a selected cap
+*/
+static void
+show_value(
+ struct test_list *t,
+ int *state GCC_UNUSED,
+ int *ch)
+{
+ struct name_table_entry const *nt;
+ char *s;
+ int n, op, b;
+ char buf[1024];
+ char tmp[1024];
+
+ ptext("enter name: ");
+ read_string(buf, 80);
+ if (buf[0] == '\0' || buf[1] == '\0') {
+ *ch = buf[0];
+ return;
+ }
+ if (line_count + 2 >= lines) {
+ put_clear();
+ }
+ op = t->flags & 255;
+ if ((nt = _nc_find_entry(buf, _nc_info_hash_table))) {
+ switch (nt->nte_type) {
+ case BOOLEAN:
+ if (op == SHOW_DELETE) {
+ if (nt->nte_index == xon_index) {
+ xon_shadow = 0;
+ } else {
+ CUR Booleans[nt->nte_index] = 0;
+ }
+ return;
+ }
+ b = nt->nte_index == xon_index ? xon_shadow :
+ CUR Booleans[nt->nte_index];
+ sprintf(temp, "boolean %s %s", buf,
+ b ? "True" : "False");
+ break;
+ case STRING:
+ if (op == SHOW_DELETE) {
+ CUR Strings[nt->nte_index] = (char *) 0;
+ return;
+ }
+ if (CUR Strings[nt->nte_index]) {
+ sprintf(temp, "string %s %s", buf,
+ expand(CUR Strings[nt->nte_index]));
+ } else {
+ sprintf(temp, "undefined string %s", buf);
+ }
+ break;
+ case NUMBER:
+ if (op == SHOW_DELETE) {
+ CUR Numbers[nt->nte_index] = -1;
+ return;
+ }
+ sprintf(temp, "numeric %s %d", buf,
+ CUR Numbers[nt->nte_index]);
+ break;
+ default:
+ sprintf(temp, "unknown");
+ break;
+ }
+ ptextln(temp);
+ } else {
+ sprintf(temp, "Cap not found: %s", buf);
+ ptextln(temp);
+ return;
+ }
+ if (op != SHOW_EDIT) {
+ return;
+ }
+ if (nt->nte_type == BOOLEAN) {
+ ptextln("Value flipped");
+ if (nt->nte_index == xon_index) {
+ xon_shadow = !xon_shadow;
+ } else {
+ CUR Booleans[nt->nte_index] = !CUR Booleans[nt->nte_index];
+ }
+ return;
+ }
+ ptextln("Enter new value");
+ read_string(buf, sizeof(buf));
+
+ switch (nt->nte_type) {
+ case STRING:
+ _nc_reset_input((FILE *) 0, buf);
+ _nc_trans_string(tmp);
+ s = (char *)malloc(strlen(tmp) + 1);
+ strcpy(s, tmp);
+ CUR Strings[nt->nte_index] = s;
+ sprintf(temp, "new string value %s", nt->nte_name);
+ ptextln(temp);
+ ptextln(expand(CUR Strings[nt->nte_index]));
+ break;
+ case NUMBER:
+ if (sscanf(buf, "%d", &n) == 1) {
+ CUR Numbers[nt->nte_index] = n;
+ sprintf(temp, "new numeric value %s %d",
+ nt->nte_name, n);
+ ptextln(temp);
+ } else {
+ sprintf(temp, "Illegal number: %s", buf);
+ ptextln(temp);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+/*
+** get_string_cap_byname(name, long_name)
+**
+** Given a cap name, find the value
+** Errors are quietly ignored.
+*/
+char *
+get_string_cap_byname(
+ const char *name,
+ const char **long_name)
+{
+ struct name_table_entry const *nt;
+
+ if ((nt = _nc_find_entry(name, _nc_info_hash_table))) {
+ if (nt->nte_type == STRING) {
+ *long_name = strfnames[nt->nte_index];
+ return (CUR Strings[nt->nte_index]);
+ }
+ }
+ *long_name = "??";
+ return (char *) 0;
+}
+
+/*
+** get_string_cap_byvalue(value)
+**
+** Given a capability string, find its position in the data base.
+** Return the index or -1 if not found.
+*/
+int
+get_string_cap_byvalue(
+ const char *value)
+{
+ int i;
+
+ if (value) {
+ for (i = 0; i < STRCOUNT; i++) {
+ if (CUR Strings[i] == value) {
+ return i;
+ }
+ }
+ /* search for translated strings */
+ for (i = 0; i < TM_last; i++) {
+ if (TM_string[i].value == value) {
+ return TM_string[i].index;
+ }
+ }
+ }
+ return -1;
+}
+
+/*
+** show_changed(test_list, status, ch)
+**
+** Display a list of caps that have been changed.
+*/
+static void
+show_changed(
+ struct test_list *t GCC_UNUSED,
+ int *state GCC_UNUSED,
+ int *ch)
+{
+ int i, header = 1, v;
+ const char *a;
+ const char *b;
+ static char title[] = " old value cap new value";
+ char abuf[1024];
+
+ for (i = 0; i < BOOLCOUNT; i++) {
+ v = (i == xon_index) ? xon_shadow : CUR Booleans[i];
+ if (original_term.Booleans[i] != v) {
+ if (header) {
+ ptextln(title);
+ header = 0;
+ }
+ sprintf(temp, "%30d %6s %d",
+ original_term.Booleans[i], boolnames[i], v);
+ ptextln(temp);
+ }
+ }
+ for (i = 0; i < NUMCOUNT; i++) {
+ if (original_term.Numbers[i] != CUR Numbers[i]) {
+ if (header) {
+ ptextln(title);
+ header = 0;
+ }
+ sprintf(temp, "%30d %6s %d",
+ original_term.Numbers[i], numnames[i],
+ CUR Numbers[i]);
+ ptextln(temp);
+ }
+ }
+ for (i = 0; i < STRCOUNT; i++) {
+ a = original_term.Strings[i] ? original_term.Strings[i] : "";
+ b = CUR Strings[i] ? CUR Strings[i] : "";
+ if (strcmp(a, b)) {
+ if (header) {
+ ptextln(title);
+ header = 0;
+ }
+ strcpy(abuf, _nc_tic_expand(a, TRUE, TRUE));
+ sprintf(temp, "%30s %6s %s", abuf, strnames[i],
+ _nc_tic_expand(b, TRUE, TRUE));
+ putln(temp);
+ }
+ }
+ if (header) {
+ ptextln("No changes");
+ }
+ put_crlf();
+ *ch = REQUEST_PROMPT;
+}
+
+/*
+** user_modified()
+**
+** Return TRUE if the user has modified the terminfo
+*/
+int
+user_modified(void)
+{
+ const char *a, *b;
+ int i, v;
+
+ for (i = 0; i < BOOLCOUNT; i++) {
+ v = (i == xon_index) ? xon_shadow : CUR Booleans[i];
+ if (original_term.Booleans[i] != v) {
+ return TRUE;
+ }
+ }
+ for (i = 0; i < NUMCOUNT; i++) {
+ if (original_term.Numbers[i] != CUR Numbers[i]) {
+ return TRUE;
+ }
+ }
+ for (i = 0; i < STRCOUNT; i++) {
+ a = original_term.Strings[i] ? original_term.Strings[i] : "";
+ b = CUR Strings[i] ? CUR Strings[i] : "";
+ if (strcmp(a, b)) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/*****************************************************************************
+ *
+ * Maintain the list of capabilities that can be tested
+ *
+ *****************************************************************************/
+
+/*
+** mark_cap(name, flag)
+**
+** Mark the cap data base with the flag provided.
+*/
+static void
+mark_cap(
+ char *name,
+ int flag)
+{
+ struct name_table_entry const *nt;
+
+ if ((nt = _nc_find_entry(name, _nc_info_hash_table))) {
+ switch (nt->nte_type) {
+ case BOOLEAN:
+ flag_boolean[nt->nte_index] |= flag;
+ break;
+ case STRING:
+ flag_strings[nt->nte_index] |= flag;
+ break;
+ case NUMBER:
+ flag_numerics[nt->nte_index] |= flag;
+ break;
+ default:
+ sprintf(temp, "unknown cap type (%s)", name);
+ ptextln(temp);
+ break;
+ }
+ } else {
+ sprintf(temp, "Cap not found: %s", name);
+ ptextln(temp);
+ (void) wait_here();
+ }
+}
+
+/*
+** can_test(name-list, flags)
+**
+** Scan the name list and get the names.
+** Enter each name into the can-test data base.
+** <space> ( and ) may be used as seperators.
+*/
+void
+can_test(
+ const char *s,
+ int flags)
+{
+ int ch, i, j;
+ char name[32];
+
+ if (s) {
+ for (i = j = 0; (name[j] = ch = *s); s++) {
+ if (ch == ' ' || ch == ')' || ch == '(') {
+ if (j) {
+ name[j] = '\0';
+ mark_cap(name, flags);
+ }
+ j = 0;
+ } else {
+ j++;
+ }
+ }
+ if (j) {
+ mark_cap(name, flags);
+ }
+ }
+}
+
+/*
+** cap_index(name-list, index-list)
+**
+** Scan the name list and return a list of indexes.
+** <space> ( and ) may be used as seperators.
+** This list is terminated with -1.
+*/
+void
+cap_index(
+ const char *s,
+ int *inx)
+{
+ struct name_table_entry const *nt;
+ int ch, i, j;
+ char name[32];
+
+ if (s) {
+ for (i = j = 0; ; s++) {
+ name[j] = ch = *s;
+ if (ch == ' ' || ch == ')' || ch == '(' || ch == 0) {
+ if (j) {
+ name[j] = '\0';
+ if ((nt = _nc_find_entry(name,
+ _nc_info_hash_table)) &&
+ (nt->nte_type == STRING)) {
+ *inx++ = nt->nte_index;
+ }
+ }
+ if (ch == 0) {
+ break;
+ }
+ j = 0;
+ } else {
+ j++;
+ }
+ }
+ }
+ *inx = -1;
+}
+
+/*
+** cap_match(name-list, cap)
+**
+** Scan the name list and see if the cap is in the list.
+** Return TRUE if we find an exact match.
+** <space> ( and ) may be used as seperators.
+*/
+int
+cap_match(
+ const char *names,
+ const char *cap)
+{
+ char *s;
+ int c, l, t;
+
+ if (names) {
+ l = strlen(cap);
+ while ((s = strstr(names, cap))) {
+ c = (names == s) ? 0 : *(s - 1);
+ t = s[l];
+ if ((c == 0 || c == ' ' || c == '(') &&
+ (t == 0 || t == ' ' || t == ')')) {
+ return TRUE;
+ }
+ if (t == 0) {
+ break;
+ }
+ names = s + l;
+ }
+ }
+ return FALSE;
+}
+
+/*
+** show_report(test_list, status, ch)
+**
+** Display a list of caps that can be tested
+*/
+void
+show_report(
+ struct test_list *t,
+ int *state GCC_UNUSED,
+ int *ch)
+{
+ int i, j, nc, flag;
+ const char *s;
+ const char *nx[BOOLCOUNT + NUMCOUNT + STRCOUNT];
+
+ flag = t->flags & 255;
+ nc = 0;
+ for (i = 0; i < BOOLCOUNT; i++) {
+ if (flag_boolean[i] & flag) {
+ nx[nc++] = boolnames[i];
+ }
+ }
+ for (i = 0; i < NUMCOUNT; i++) {
+ if (flag_numerics[i] & flag) {
+ nx[nc++] = numnames[i];
+ }
+ }
+ for (i = 0; i < STRCOUNT; i++) {
+ if (flag_strings[i] & flag) {
+ nx[nc++] = strnames[i];
+ }
+ }
+ /* sort */
+ for (i = 0; i < nc - 1; i++) {
+ for (j = i + 1; j < nc; j++) {
+ if (strcmp(nx[i], nx[j]) > 0) {
+ s = nx[i];
+ nx[i] = nx[j];
+ nx[j] = s;
+ }
+ }
+ }
+ if (flag & FLAG_FUNCTION_KEY) {
+ ptextln("The following function keys can be tested:");
+ } else
+ if (flag & FLAG_CAN_TEST) {
+ ptextln("The following capabilities can be tested:");
+ } else
+ if (flag & FLAG_TESTED) {
+ ptextln("The following capabilities have been tested:");
+ }
+ put_crlf();
+ for (i = 0; i < nc; i++) {
+ sprintf(temp, "%s ", nx[i]);
+ ptext(temp);
+ }
+ put_newlines(1);
+ *ch = REQUEST_PROMPT;
+}
+
+/*
+** show_untested(test_list, status, ch)
+**
+** Display a list of caps that are defined but cannot be tested.
+** Don't bother to sort this list.
+*/
+static void
+show_untested(
+ struct test_list *t GCC_UNUSED,
+ int *state GCC_UNUSED,
+ int *ch)
+{
+ int i;
+
+ ptextln("Caps that are defined but cannot be tested:");
+ for (i = 0; i < BOOLCOUNT; i++) {
+ if (flag_boolean[i] == 0 && CUR Booleans[i]) {
+ sprintf(temp, "%s ", boolnames[i]);
+ ptext(temp);
+ }
+ }
+ for (i = 0; i < NUMCOUNT; i++) {
+ if (flag_numerics[i] == 0 && CUR Numbers[i] >= 0) {
+ sprintf(temp, "%s ", numnames[i]);
+ ptext(temp);
+ }
+ }
+ for (i = 0; i < STRCOUNT; i++) {
+ if (flag_strings[i] == 0 && CUR Strings[i]) {
+ sprintf(temp, "%s ", strnames[i]);
+ ptext(temp);
+ }
+ }
+ put_newlines(1);
+ *ch = REQUEST_PROMPT;
+}
+
+/*
+** edit_init()
+**
+** Initialize the function key data base
+*/
+void
+edit_init(void)
+{
+ int i, j, lc;
+ char *lab;
+ struct name_table_entry const *nt;
+ int label_strings[STRCOUNT];
+
+ _nc_copy_termtype(&original_term, &cur_term->type);
+ for (i = 0; i < BOOLCOUNT; i++) {
+ original_term.Booleans[i] = CUR Booleans[i];
+ }
+ for (i = 0; i < NUMCOUNT; i++) {
+ original_term.Numbers[i] = CUR Numbers[i];
+ }
+ /* scan for labels */
+ for (i = lc = 0; i < STRCOUNT; i++) {
+ original_term.Strings[i] = CUR Strings[i];
+ if (strncmp(strnames[i], "lf", 2) == 0) {
+ flag_strings[i] |= FLAG_LABEL;
+ if (CUR Strings[i]) {
+ label_strings[lc++] = i;
+ }
+ }
+ }
+ /* scan for function keys */
+ for (i = 0; i < STRCOUNT; i++) {
+ if ((strnames[i][0] == 'k') && strcmp(strnames[i], "kmous")) {
+ flag_strings[i] |= FLAG_FUNCTION_KEY;
+ lab = (char *) 0;
+ for (j = 0; j < lc; j++) {
+ if (!strcmp(&strnames[i][1],
+ &strnames[label_strings[j]][1])) {
+ lab = CUR Strings[label_strings[j]];
+ break;
+ }
+ }
+ enter_key(strnames[i], CUR Strings[i], lab);
+ }
+ }
+ /* Lookup the translated strings */
+ for (i = 0; i < TM_last; i++) {
+ if ((nt = _nc_find_entry(TM_string[i].name,
+ _nc_info_hash_table)) && (nt->nte_type == STRING)) {
+ TM_string[i].index = nt->nte_index;
+ } else {
+ sprintf(temp, "TM_string lookup failed for: %s",
+ TM_string[i].name);
+ ptextln(temp);
+ }
+ }
+ if ((nt = _nc_find_entry("xon", _nc_info_hash_table)) != 0) {
+ xon_index = nt->nte_index;
+ }
+ xon_shadow = xon_xoff;
+}
+
+/*
+** change_one_entry(test_list, status, ch)
+**
+** Change the padding on the selected cap
+*/
+static void
+change_one_entry(
+ struct test_list *test,
+ int *state,
+ int *chp)
+{
+ struct name_table_entry const *nt;
+ int i, j, x, star, slash, v, dot, ch;
+ const char *s;
+ char *t, *p;
+ const char *current_string;
+ char buf[1024];
+ char pad[1024];
+
+ i = test->flags & 255;
+ if (i == 255) {
+ /* read the cap name from the user */
+ ptext("enter name: ");
+ read_string(pad, 32);
+ if (pad[0] == '\0' || pad[1] == '\0') {
+ *chp = pad[0];
+ return;
+ }
+ if ((nt = _nc_find_entry(pad, _nc_info_hash_table)) &&
+ (nt->nte_type == STRING)) {
+ x = nt->nte_index;
+ current_string = CUR Strings[x];
+ } else {
+ sprintf(temp, "%s is not a string capability", pad);
+ ptext(temp);
+ generic_done_message(test, state, chp);
+ return;
+ }
+ } else {
+ x = tx_index[i];
+ current_string = tx_cap[i];
+ strcpy(pad, strnames[x]);
+ }
+ if (!current_string) {
+ ptextln("That string is not currently defined. Please enter a new value, including the padding delay:");
+ read_string(buf, sizeof(buf));
+ _nc_reset_input((FILE *) 0, buf);
+ _nc_trans_string(pad);
+ t = (char *)malloc(strlen(pad) + 1);
+ strcpy(t, pad);
+ CUR Strings[x] = t;
+ sprintf(temp, "new string value %s", strnames[x]);
+ ptextln(temp);
+ ptextln(expand(t));
+ return;
+ }
+ sprintf(buf, "Current value: (%s) %s", pad, _nc_tic_expand(current_string, TRUE, TRUE));
+ putln(buf);
+ ptextln("Enter new pad. 0 for no pad. CR for no change.");
+ read_string(buf, 32);
+ if (buf[0] == '\0' || (buf[1] == '\0' && isalpha(buf[0]))) {
+ *chp = buf[0];
+ return;
+ }
+ star = slash = FALSE;
+ for (j = v = dot = 0; (ch = buf[j]); j++) {
+ if (ch >= '0' && ch <= '9') {
+ v = ch - '0' + v * 10;
+ if (dot) {
+ dot++;
+ }
+ } else if (ch == '*') {
+ star = TRUE;
+ } else if (ch == '/') {
+ slash = TRUE;
+ } else if (ch == '.') {
+ dot = 1;
+ } else {
+ sprintf(temp, "Illegal character: %c", ch);
+ ptextln(temp);
+ ptext("General format: 99.9*/ ");
+ generic_done_message(test, state, chp);
+ return;
+ }
+ }
+ while (dot > 2) {
+ v /= 10;
+ dot--;
+ }
+ if (dot == 2) {
+ sprintf(pad, "%d.%d%s%s", v / 10, v % 10,
+ star ? "*" : "", slash ? "/" : "");
+ } else {
+ sprintf(pad, "%d%s%s",
+ v, star ? "*" : "", slash ? "/" : "");
+ }
+ s = current_string;
+ t = buf;
+ for (v = 0; (ch = *t = *s++); t++) {
+ if (v == '$' && ch == '<') {
+ while ((ch = *s++) && (ch != '>'));
+ for (p = pad; (*++t = *p++); );
+ *t++ = '>';
+ while ((*t++ = *s++));
+ pad[0] = '\0';
+ break;
+ }
+ v = ch;
+ }
+ if (pad[0]) {
+ sprintf(t, "$<%s>", pad);
+ }
+ if ((t = (char *)malloc(strlen(buf) + 1))) {
+ strcpy(t, buf);
+ CUR Strings[x] = t;
+ if (i != 255) {
+ tx_cap[i] = t;
+ }
+ }
+ generic_done_message(test, state, chp);
+}
+
+/*
+** build_change_menu(menu_list)
+**
+** Build the change pad menu list
+*/
+static void
+build_change_menu(
+ struct test_menu *m)
+{
+ int i, j, k;
+ char *s;
+
+ for (i = j = 0; i < txp; i++) {
+ if ((k = tx_index[i]) >= 0) {
+ s = _nc_tic_expand(tx_cap[i], TRUE, TRUE);
+ s[40] = '\0';
+ sprintf(change_pad_text[j], "%c) (%s) %s",
+ 'a' + j, strnames[k], s);
+ change_pad_list[j].flags = i;
+ change_pad_list[j].lines_needed = 4;
+ change_pad_list[j].menu_entry = change_pad_text[j];
+ change_pad_list[j].test_procedure = change_one_entry;
+ j++;
+ }
+ }
+ strcpy(change_pad_text[j], "z) enter name");
+ change_pad_list[j].flags = 255;
+ change_pad_list[j].lines_needed = 4;
+ change_pad_list[j].menu_entry = change_pad_text[j];
+ change_pad_list[j].test_procedure = change_one_entry;
+ j++;
+ change_pad_list[j].flags = MENU_LAST;
+ if (m->menu_title) {
+ put_crlf();
+ ptextln(m->menu_title);
+ }
+}
diff --git a/contrib/ncurses/tack/fun.c b/contrib/ncurses/tack/fun.c
new file mode 100644
index 000000000000..7ddfbbdf8c42
--- /dev/null
+++ b/contrib/ncurses/tack/fun.c
@@ -0,0 +1,912 @@
+/*
+** Copyright (C) 1991, 1997 Free Software Foundation, Inc.
+**
+** This file is part of TACK.
+**
+** TACK is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2, or (at your option)
+** any later version.
+**
+** TACK is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with TACK; see the file COPYING. If not, write to
+** the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA 02111-1307, USA.
+*/
+
+#include <tack.h>
+
+MODULE_ID("$Id: fun.c,v 1.2 1999/06/16 00:46:12 tom Exp $")
+
+/*
+ * Test the function keys on the terminal. The code for echo tests
+ * lives here too.
+ */
+
+static void funkey_keys(struct test_list *, int *, int *);
+static void funkey_meta(struct test_list *, int *, int *);
+static void funkey_label(struct test_list *, int *, int *);
+static void funkey_prog(struct test_list *, int *, int *);
+static void funkey_local(struct test_list *, int *, int *);
+
+struct test_list funkey_test_list[] = {
+ {0, 0, 0, 0, "e) edit terminfo", 0, &edit_menu},
+ {MENU_CLEAR + FLAG_FUNCTION_KEY, 0, 0, 0, "f) show a list of function keys", show_report, 0},
+ {MENU_NEXT | MENU_CLEAR, 0, "smkx) (rmkx", 0,
+ "k) test function keys", funkey_keys, 0},
+ {MENU_NEXT, 10, "km", "smm rmm", 0, funkey_meta, 0},
+ {MENU_NEXT, 8, "nlab) (smln) (pln) (rmln", "lw lh", 0, funkey_label, 0},
+ {MENU_NEXT, 2, "pfx", 0, 0, funkey_prog, 0},
+ {MENU_NEXT, 2, "pfloc", 0, 0, funkey_local, 0},
+ {MENU_LAST, 0, 0, 0, 0, 0, 0}
+};
+
+static void printer_on(struct test_list *, int *, int *);
+static void printer_mc0(struct test_list *, int *, int *);
+
+struct test_list printer_test_list[] = {
+ {0, 0, 0, 0, "e) edit terminfo", 0, &edit_menu},
+ {MENU_NEXT | MENU_CLEAR, 0, "mc4) (mc5) (mc5i", 0, 0, printer_on, 0},
+ {MENU_NEXT | MENU_CLEAR, 0, "mc0", 0, 0, printer_mc0, 0},
+ {MENU_LAST, 0, 0, 0, 0, 0, 0}
+};
+
+#define MAX_STRINGS STRCOUNT
+
+/* scan code externals */
+extern int scan_max; /* length of longest scan code */
+extern char **scan_up, **scan_down, **scan_name;
+extern int *scan_tested, *scan_length;
+
+/* local definitions */
+static const char *fk_name[MAX_STRINGS];
+static char *fkval[MAX_STRINGS];
+static char *fk_label[MAX_STRINGS]; /* function key labels (if any) */
+static int fk_tested[MAX_STRINGS];
+static int fkmax = 1; /* length of longest key */
+static int got_labels = 0; /* true if we have some labels */
+static int key_count = 0;
+static int end_state;
+
+/* unknown function keys */
+#define MAX_FK_UNK 50
+static char *fk_unknown[MAX_FK_UNK];
+static int fk_length[MAX_FK_UNK];
+static int funk;
+
+/*
+** keys_tested(first-time, show-help, hex-output)
+**
+** Display a list of the keys not tested.
+*/
+static void
+keys_tested(
+ int first_time,
+ int show_help,
+ int hex_output)
+{
+ int i, l;
+ char outbuf[256];
+
+ put_clear();
+ tty_set();
+ flush_input();
+ if (got_labels) {
+ putln("Function key labels:");
+ for (i = 0; i < key_count; ++i) {
+ if (fk_label[i]) {
+ sprintf(outbuf, "%s %s",
+ fk_name[i] ? fk_name[i] : "??", fk_label[i]);
+ put_columns(outbuf, strlen(outbuf), 16);
+ }
+ }
+ put_newlines(2);
+ }
+ if (funk) {
+ putln("The following keys are not defined:");
+ for (i = 0; i < funk; ++i) {
+ put_columns(fk_unknown[i], fk_length[i], 16);
+ }
+ put_mode(exit_attribute_mode);
+ put_newlines(2);
+ }
+ if (first_time) {
+ putln("The following keys are defined:");
+ } else {
+ putln("The following keys have not been tested:");
+ }
+ if (scan_mode) {
+ for (i = 0; scan_down[i]; i++) {
+ if (!scan_tested[i]) {
+ if (hex_output) {
+ strcpy(outbuf, hex_expand_to(scan_down[i], 3));
+ } else {
+ strcpy(outbuf, expand(scan_down[i]));
+ }
+ l = expand_chars;
+ if (hex_output) {
+ strcat(outbuf, hex_expand_to(scan_up[i], 3));
+ } else {
+ strcat(outbuf, expand(scan_up[i]));
+ }
+ expand_chars += l;
+ l = strlen(scan_name[i]);
+ if (((char_count + 16) & ~15) +
+ ((expand_chars + 7) & ~7) + l >= columns) {
+ put_crlf();
+ } else
+ if (char_count + 24 > columns) {
+ put_crlf();
+ } else if (char_count) {
+ putchp(' ');
+ }
+ put_columns(outbuf, expand_chars, 16);
+ put_columns(scan_name[i], l, 8);
+ }
+ }
+ } else {
+ for (i = 0; i < key_count; i++) {
+ if (!fk_tested[i]) {
+ if (hex_output) {
+ strcpy(outbuf, hex_expand_to(fkval[i], 3));
+ } else {
+ strcpy(outbuf, expand(fkval[i]));
+ }
+ l = strlen(fk_name[i]);
+ if (((char_count + 16) & ~15) +
+ ((expand_chars + 7) & ~7) + l >= columns) {
+ put_crlf();
+ } else
+ if (char_count + 24 > columns) {
+ put_crlf();
+ } else
+ if (char_count) {
+ putchp(' ');
+ }
+ put_columns(outbuf, expand_chars, 16);
+ put_columns(fk_name[i], l, 8);
+ }
+ }
+ }
+ put_newlines(2);
+ if (show_help) {
+ ptextln("Hit any function key. Type 'end' to quit. Type ? to update the display.");
+ put_crlf();
+ }
+}
+
+/*
+** enter_key(name, value, label)
+**
+** Enter a function key into the data base
+*/
+void
+enter_key(
+ const char *name,
+ char *value,
+ char *lab)
+{
+ int j;
+
+ if (value) {
+ j = strlen(value);
+ fkmax = fkmax > j ? fkmax : j;
+ /* do not permit duplicates */
+ for (j = 0; j < key_count; j++) {
+ if (!strcmp(fk_name[j], name)) {
+ return;
+ }
+ }
+ fkval[key_count] = value;
+ fk_tested[key_count] = 0;
+ fk_label[key_count] = lab;
+ fk_name[key_count++] = name;
+ if (lab) {
+ got_labels = TRUE;
+ }
+ }
+}
+
+
+static void
+fresh_line(void)
+{ /* clear the line for a new fumction key line */
+ if (over_strike) {
+ put_crlf();
+ } else {
+ put_cr();
+ if (clr_eol) {
+ tc_putp(clr_eol);
+ } else {
+ put_str(" \r");
+ }
+ }
+}
+
+
+static int
+end_funky(int ch)
+{ /* return true if this is the end */
+ switch (ch) {
+ case 'e':
+ case 'E':
+ end_state = 'e';
+ break;
+ case 'n':
+ case 'N':
+ if (end_state == 'e') {
+ end_state = 'n';
+ } else {
+ end_state = 0;
+ }
+ break;
+ case 'd':
+ case 'D':
+ if (end_state == 'n') {
+ end_state = 'd';
+ } else {
+ end_state = 0;
+ }
+ break;
+ case 'l':
+ case 'L':
+ if (end_state == 'l') {
+ end_state = '?';
+ } else {
+ end_state = 'l';
+ }
+ break;
+ default:
+ end_state = 0;
+ break;
+ }
+ return end_state == 'd';
+}
+
+
+static int
+found_match(char *s, int hx, int cc)
+{ /* return true if this string is a match */
+ int j, f;
+ char outbuf[256];
+
+ if (!*s) {
+ return 0;
+ }
+ if (scan_mode) {
+ for (j = f = 0; scan_down[j]; j++) {
+ if (scan_length[j] == 0) {
+ continue;
+ }
+ if (!strncmp(s, scan_down[j], scan_length[j])) {
+ if (!f) { /* first match */
+ put_cr();
+ if (hx) {
+ put_str(hex_expand_to(s, 10));
+ } else {
+ put_str(expand_to(s, 10));
+ }
+ f = 1;
+ }
+ (void) end_funky(scan_name[j][0]);
+ put_str(" ");
+ put_str(scan_name[j]);
+ scan_tested[j] = 1;
+ s += scan_length[j];
+ if (strncmp(s, scan_up[j], scan_length[j])) {
+ put_str(" scan down");
+ } else {
+ s += scan_length[j];
+ }
+ if (!*s) {
+ break;
+ }
+ j = -1;
+ }
+ if (!strncmp(s, scan_up[j], scan_length[j])) {
+ if (!f) { /* first match */
+ put_cr();
+ if (hx) {
+ put_str(hex_expand_to(s, 10));
+ } else {
+ put_str(expand_to(s, 10));
+ }
+ f = 1;
+ }
+ put_str(" ");
+ put_str(scan_name[j]);
+ put_str(" scan up");
+ s += scan_length[j];
+ if (!*s) {
+ break;
+ }
+ j = -1;
+ }
+ }
+ } else {
+ for (j = f = 0; j < key_count; j++) {
+ if (!strcmp(s, fkval[j])) {
+ if (!f) { /* first match */
+ put_cr();
+ if (hx) {
+ put_str(hex_expand_to(s, 10));
+ } else {
+ put_str(expand_to(s, 10));
+ }
+ f = 1;
+ }
+ sprintf(outbuf, " (%s)", fk_name[j]);
+ put_str(outbuf);
+ if (fk_label[j]) {
+ sprintf(outbuf, " <%s>", fk_label[j]);
+ put_str(outbuf);
+ }
+ fk_tested[j] = 1;
+ }
+ }
+ }
+ if (end_state == '?') {
+ keys_tested(0, 1, hx);
+ tty_raw(cc, char_mask);
+ end_state = 0;
+ }
+ return f;
+}
+
+
+static int
+found_exit(char *keybuf, int hx, int cc)
+{ /* return true if the user wants to exit */
+ int j, k;
+ char *s;
+
+
+ if (scan_mode) {
+ if (*keybuf == '\0') {
+ return TRUE;
+ }
+ } else {
+ /* break is a special case */
+ if (*keybuf == '\0') {
+ fresh_line();
+ tty_set();
+ ptext("Hit X to exit: ");
+ if (wait_here() == 'X') {
+ return TRUE;
+ }
+ keys_tested(0, 1, hx);
+ tty_raw(cc, char_mask);
+ return FALSE;
+ }
+ /* is this the end? */
+ for (k = 0; (j = (keybuf[k] & STRIP_PARITY)); k++) {
+ if (end_funky(j)) {
+ return TRUE;
+ }
+ }
+
+ j = TRUE; /* does he need an updated list? */
+ for (k = 0; keybuf[k]; k++) {
+ j &= (keybuf[k] & STRIP_PARITY) == '?';
+ }
+ if (j || end_state == '?') {
+ keys_tested(0, 1, hx);
+ tty_raw(cc, char_mask);
+ end_state = 0;
+ return FALSE;
+ }
+ }
+
+ put_cr();
+ if (hx) {
+ s = hex_expand_to(keybuf, 10);
+ } else {
+ s = expand_to(keybuf, 10);
+ }
+ sprintf(temp, "%s Unknown", s);
+ put_str(temp);
+ for (j = 0; j < MAX_FK_UNK; j++) {
+ if (j == funk) {
+ fk_length[funk] = expand_chars;
+ if ((fk_unknown[funk] = (char *)malloc(strlen(s) + 1))) {
+ strcpy(fk_unknown[funk++], s);
+ }
+ break;
+ }
+ if (fk_length[j] == expand_chars) {
+ if (!strcmp(fk_unknown[j], s)) {
+ break;
+ }
+ }
+ }
+ return FALSE;
+}
+
+/*
+** funkey_keys(test_list, status, ch)
+**
+** Test function keys
+*/
+static void
+funkey_keys(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ char keybuf[256];
+
+ if (keypad_xmit) {
+ tc_putp(keypad_xmit);
+ }
+ keys_tested(1, 1, hex_out); /* also clears screen */
+ keybuf[0] = '\0';
+ end_state = 0;
+ if (scan_mode) {
+ fkmax = scan_max;
+ }
+ tty_raw(0, char_mask);
+ while (end_state != 'd') {
+ read_key(keybuf, sizeof(keybuf));
+ fresh_line();
+ if (found_match(keybuf, hex_out, 0)) {
+ continue;
+ }
+ if (found_exit(keybuf, hex_out, 0)) {
+ break;
+ }
+ }
+ if (keypad_local) {
+ tc_putp(keypad_local);
+ }
+ keys_tested(0, 0, hex_out);
+ ptext("Function key test ");
+ generic_done_message(t, state, ch);
+}
+
+int
+tty_meta_prep(void)
+{ /* print a warning before the meta key test */
+ if (not_a_tty) {
+ return 0;
+ }
+ if (initial_stty_query(TTY_8_BIT)) {
+ return 0;
+ }
+ ptext("The meta key test must be run with the");
+ ptext(" terminal set for 8 data bits. Two stop bits");
+ ptext(" may also be needed for correct display. I will");
+ ptext(" transmit 8 bit data but if the terminal is set for");
+ ptextln(" 7 bit data, garbage may appear on the screen.");
+ return 1;
+}
+
+/*
+** funkey_meta(test_list, status, ch)
+**
+** Test meta key (km) (smm) (rmm)
+*/
+static void
+funkey_meta(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int i, j, k, len;
+ char outbuf[256];
+
+ if (has_meta_key) {
+ put_crlf();
+ if (char_mask != ALLOW_PARITY) {
+ if (tty_meta_prep()) {
+ ptext("\nHit any key to continue > ");
+ (void) wait_here();
+ put_crlf();
+ }
+ }
+ ptext("Begin meta key test. (km) (smm) (rmm) Hit any key");
+ ptext(" with the meta key. The character will be");
+ ptext(" displayed in hex. If the meta key is working");
+ ptext(" then the most significant bit will be set. Type");
+ ptextln(" 'end' to exit.");
+ tty_raw(1, ALLOW_PARITY);
+ tc_putp(meta_on);
+
+ for (i = j = k = len = 0; i != 'e' || j != 'n' || k != 'd';) {
+ i = j;
+ j = k;
+ k = getchp(ALLOW_PARITY);
+ if (k == EOF) {
+ break;
+ }
+ if ((len += 3) >= columns) {
+ put_crlf();
+ len = 3;
+ }
+ sprintf(outbuf, "%02X ", k);
+ put_str(outbuf);
+ k &= STRIP_PARITY;
+ }
+ tc_putp(meta_off);
+ put_crlf();
+ tty_set();
+ put_crlf();
+ } else {
+ ptext("(km) Has-meta-key is not set. ");
+ }
+ generic_done_message(t, state, ch);
+}
+
+/*
+** funkey_label(test_list, status, ch)
+**
+** Test labels (nlab) (smln) (pln) (rmln) (lw) (lh)
+*/
+static void
+funkey_label(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int i;
+ char outbuf[256];
+
+ if (num_labels == -1) {
+ ptextln("Your terminal has no labels. (nlab)");
+ } else {
+ sprintf(temp, "Your terminal has %d labels (nlab) that are %d characters wide (lw) and %d lines high (lh)",
+ num_labels, label_width, label_height);
+ ptext(temp);
+ ptextln(" Testing (smln) (pln) (rmln)");
+ if (label_on) {
+ tc_putp(label_on);
+ }
+ if (label_width <= 0) {
+ label_width = sizeof(outbuf) - 1;
+ }
+ for (i = 1; i <= num_labels; i++) {
+ sprintf(outbuf, "L%d..............................", i);
+ outbuf[label_width] = '\0';
+ tc_putp(tparm(plab_norm, i, outbuf));
+ }
+ if (label_off) {
+ ptext("Hit any key to remove the labels: ");
+ (void) wait_here();
+ tc_putp(label_off);
+ }
+ }
+ generic_done_message(t, state, ch);
+}
+
+/*
+** funkey_prog(test_list, status, ch)
+**
+** Test program function keys (pfx)
+*/
+static void
+funkey_prog(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int i, fk;
+ char mm[256];
+
+ fk = 1; /* use function key 1 for now */
+ if (pkey_xmit) {
+ /* test program function key */
+ sprintf(temp,
+ "(pfx) Set function key %d to transmit abc\\n", fk);
+ ptextln(temp);
+ tc_putp(tparm(pkey_xmit, fk, "abc\n"));
+ sprintf(temp, "Hit function key %d\n", fk);
+ ptextln(temp);
+ for (i = 0; i < 4; ++i)
+ mm[i] = getchp(STRIP_PARITY);
+ mm[i] = '\0';
+ put_crlf();
+ if (mm[0] != 'a' || mm[1] != 'b' || mm[2] != 'c') {
+ sprintf(temp, "Error string recieved was: %s", expand(mm));
+ ptextln(temp);
+ } else {
+ putln("Thank you\n");
+ }
+ flush_input();
+ if (key_f1) {
+ tc_putp(tparm(pkey_xmit, fk, key_f1));
+ }
+ } else {
+ ptextln("Function key transmit (pfx), not present.");
+ }
+ generic_done_message(t, state, ch);
+}
+
+/*
+** funkey_local(test_list, status, ch)
+**
+** Test program local function keys (pfloc)
+*/
+static void
+funkey_local(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int fk;
+
+ fk = 1;
+ if (pkey_local) {
+ /* test local function key */
+ sprintf(temp,
+ "(pfloc) Set function key %d to execute a clear and print \"Done!\"", fk);
+ ptextln(temp);
+ sprintf(temp, "%sDone!", liberated(clear_screen));
+ tc_putp(tparm(pkey_local, fk, temp));
+ sprintf(temp, "Hit function key %d. Then hit return.", fk);
+ ptextln(temp);
+ (void) wait_here();
+ flush_input();
+ if (key_f1 && pkey_xmit) {
+ tc_putp(tparm(pkey_xmit, fk, key_f1));
+ }
+ } else {
+ ptextln("Function key execute local (pfloc), not present.");
+ }
+
+ generic_done_message(t, state, ch);
+}
+
+/*
+** printer_on(test_list, status, ch)
+**
+** Test printer on/off (mc4) (mc5) (mc5i)
+*/
+static void
+printer_on(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ if (!prtr_on || !prtr_off) {
+ ptextln("Printer on/off missing. (mc5) (mc4)");
+ } else if (prtr_silent) {
+ ptextln("Your printer is silent. (mc5i) is set.");
+ tc_putp(prtr_on);
+ ptextln("This line should be on the printer but not your screen. (mc5)");
+ tc_putp(prtr_off);
+ ptextln("This line should be only on the screen. (mc4)");
+ } else {
+ ptextln("Your printer is not silent. (mc5i) is reset.");
+ tc_putp(prtr_on);
+ ptextln("This line should be on the printer and the screen. (mc5)");
+ tc_putp(prtr_off);
+ ptextln("This line should only be on the screen. (mc4)");
+ }
+ generic_done_message(t, state, ch);
+}
+
+/*
+** printer_mc0(test_list, status, ch)
+**
+** Test screen print (mc0)
+*/
+static void
+printer_mc0(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ if (print_screen) {
+ ptext("I am going to send the contents of the screen to");
+ ptext(" the printer, then wait for a keystroke from you.");
+ ptext(" All of the text that appears on the screen");
+ ptextln(" should be printed. (mc0)");
+ tc_putp(print_screen);
+ } else {
+ ptext("(mc0) Print-screen is not present. ");
+ }
+ generic_done_message(t, state, ch);
+}
+
+
+static void
+line_pattern(void)
+{ /* put up a pattern that will help count the
+ number of lines */
+ int i, j;
+
+ put_clear();
+ if (over_strike) {
+ for (i = 0; i < 100; i++) {
+ if (i) {
+ put_crlf();
+ }
+ for (j = i / 10; j; j--) {
+ put_this(' ');
+ }
+ put_this('0' + ((i + 1) % 10));
+ }
+ } else /* I assume it will scroll */ {
+ for (i = 100; i; i--) {
+ sprintf(temp, "\r\n%d", i);
+ put_str(temp);
+ }
+ }
+}
+
+
+static void
+column_pattern(void)
+{ /* put up a pattern that will help count the
+ number of columns */
+ int i, j;
+
+ put_clear();
+ for (i = 0; i < 20; i++) {
+ for (j = 1; j < 10; j++) {
+ put_this('0' + j);
+ }
+ put_this('.');
+ }
+}
+
+/*
+** report_help()
+**
+** Print the help text for the echo tests
+*/
+static void
+report_help(int crx)
+{
+ ptextln("The following commands may also be entered:");
+ ptextln(" clear clear screen.");
+ ptextln(" columns print a test patterm to help count screen width.");
+ ptextln(" lines print a test patterm to help count screen length.");
+ ptextln(" end exit.");
+ ptextln(" echo redisplay last report.");
+ if (crx) {
+ ptextln(" hex redisplay last report in hex.");
+ } else {
+ ptextln(" hex toggle hex display mode.");
+ }
+ ptextln(" help display this list.");
+ ptextln(" high toggle forced high bit (0x80).");
+ ptextln(" scan toggle scan mode.");
+ ptextln(" one echo one character after <cr> or <lf> as is. (report mode)");
+ ptextln(" two echo two characters after <cr> or <lf> as is.");
+ ptextln(" all echo all characters after <cr> or <lf> as is. (echo mode)");
+}
+
+/*
+** tools_report(testlist, state, ch)
+**
+** Run the echo tool and report tool
+*/
+void
+tools_report(
+ struct test_list *t,
+ int *state GCC_UNUSED,
+ int *pch GCC_UNUSED)
+{
+ int i, j, ch, crp, crx, high_bit, save_scan_mode, hex_display;
+ char buf[1024];
+ char txt[8];
+
+ hex_display = hex_out;
+ put_clear();
+ if ((crx = (t->flags & 255)) == 1) {
+ ptext("Characters after a CR or LF will be echoed as");
+ ptextln(" is. All other characters will be expanded.");
+ report_help(crx);
+ } else { /* echo test */
+ ptextln("Begin echo test.");
+ report_help(crx);
+ }
+ txt[sizeof(txt) - 1] = '\0';
+ save_scan_mode = scan_mode;
+ tty_raw(1, char_mask);
+ for (i = crp = high_bit = 0;;) {
+ ch = getchp(char_mask);
+ if (ch == EOF) {
+ break;
+ }
+ if (i >= (int) sizeof(buf) - 1) {
+ i = 0;
+ }
+ buf[i++] = ch;
+ buf[i] = '\0';
+ for (j = 0; j < (int) sizeof(txt) - 1; j++) {
+ txt[j] = txt[j + 1];
+ }
+ txt[sizeof(txt) - 1] = ch & STRIP_PARITY;
+ if (crx == 0) { /* echo test */
+ if (hex_display) {
+ ptext(hex_expand_to(&buf[i - 1], 3));
+ } else {
+ tc_putch(ch | high_bit);
+ }
+ } else /* status report test */
+ if (ch == '\n' || ch == '\r') {
+ put_crlf();
+ crp = 0;
+ } else if (crp++ < crx) {
+ tc_putch(ch | high_bit);
+ } else {
+ put_str(expand(&buf[i - 1]));
+ }
+ if (!strncmp(&txt[sizeof(txt) - 7], "columns", 7)) {
+ column_pattern();
+ buf[i = 0] = '\0';
+ crp = 0;
+ }
+ if (!strncmp(&txt[sizeof(txt) - 5], "lines", 5)) {
+ line_pattern();
+ buf[i = 0] = '\0';
+ crp = 0;
+ }
+ if (!strncmp(&txt[sizeof(txt) - 5], "clear", 5)) {
+ put_clear();
+ buf[i = 0] = '\0';
+ crp = 0;
+ }
+ if (!strncmp(&txt[sizeof(txt) - 4], "high", 4)) {
+ high_bit ^= 0x80;
+ if (high_bit) {
+ ptextln("\nParity bit set");
+ } else {
+ ptextln("\nParity bit reset");
+ }
+ }
+ if (!strncmp(&txt[sizeof(txt) - 4], "help", 4)) {
+ put_crlf();
+ report_help(crx);
+ }
+ if (!strncmp(&txt[sizeof(txt) - 4], "echo", 4)) {
+ /* display the last status report */
+ /* clear bypass condition on Tek terminals */
+ put_crlf();
+ if (i >= 4) {
+ buf[i -= 4] = '\0';
+ }
+ put_str(expand(buf));
+ }
+ if (save_scan_mode &&
+ !strncmp(&txt[sizeof(txt) - 4], "scan", 4)) {
+ /* toggle scan mode */
+ scan_mode = !scan_mode;
+ }
+ if (!strncmp(&txt[sizeof(txt) - 3], "end", 3))
+ break;
+ if (!strncmp(&txt[sizeof(txt) - 3], "hex", 3)) {
+ if (crx) {
+ /* display the last status report in hex */
+ /* clear bypass condition on Tek terminals */
+ put_crlf();
+ if (i >= 3) {
+ buf[i -= 3] = '\0';
+ }
+ put_str(hex_expand_to(buf, 3));
+ } else {
+ hex_display = !hex_display;
+ }
+ }
+ if (!strncmp(&txt[sizeof(txt) - 3], "two", 3))
+ crx = 2;
+ if (!strncmp(&txt[sizeof(txt) - 3], "one", 3))
+ crx = 1;
+ if (!strncmp(&txt[sizeof(txt) - 3], "all", 3))
+ crx = 0;
+ }
+ scan_mode = save_scan_mode;
+ put_crlf();
+ tty_set();
+ if (crx) {
+ ptextln("End of status report test.");
+ } else {
+ ptextln("End of echo test.");
+ }
+}
diff --git a/contrib/ncurses/tack/init.c b/contrib/ncurses/tack/init.c
new file mode 100644
index 000000000000..e19493d6b50a
--- /dev/null
+++ b/contrib/ncurses/tack/init.c
@@ -0,0 +1,300 @@
+/*
+** Copyright (C) 1991, 1997 Free Software Foundation, Inc.
+**
+** This file is part of TACK.
+**
+** TACK is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2, or (at your option)
+** any later version.
+**
+** TACK is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with TACK; see the file COPYING. If not, write to
+** the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA 02111-1307, USA.
+*/
+/* initialization and wrapup code */
+
+#include <tack.h>
+
+MODULE_ID("$Id: init.c,v 1.1 1999/04/18 01:05:23 tom Exp $")
+
+#if NCURSES_VERSION_MAJOR >= 5 || NCURSES_VERSION_PATCH >= 981219
+#define _nc_get_curterm(p) _nc_get_tty_mode(p)
+#endif
+
+FILE *debug_fp;
+char temp[1024];
+char tty_basename[64];
+
+void
+put_name(const char *cap, const char *name)
+{ /* send the cap name followed by the cap */
+ if (cap) {
+ ptext(name);
+ tc_putp(cap);
+ }
+}
+
+static void
+report_cap(const char *tag, const char *s)
+{ /* expand the cap or print *** missing *** */
+ int i;
+
+ ptext(tag);
+ for (i = char_count; i < 13; i++) {
+ putchp(' ');
+ }
+ put_str(" = ");
+ if (s) {
+ putln(expand(s));
+ } else {
+ putln("*** missing ***");
+ }
+}
+
+
+void
+reset_init(void)
+{ /* send the reset and init strings */
+ int i;
+
+ ptext("Terminal reset");
+ i = char_count;
+ put_name(reset_1string, " (rs1)");
+ put_name(reset_2string, " (rs2)");
+ /* run the reset file */
+ if (reset_file && reset_file[0]) {
+ FILE *fp;
+ int ch;
+
+ can_test("rf", FLAG_TESTED);
+ if ((fp = fopen(reset_file, "r"))) { /* send the reset file */
+ sprintf(temp, " (rf) %s", reset_file);
+ ptextln(temp);
+ while (1) {
+ ch = getc(fp);
+ if (ch == EOF)
+ break;
+ put_this(ch);
+ }
+ fclose(fp);
+ } else {
+ sprintf(temp, "\nCannot open reset file (rf) %s", reset_file);
+ ptextln(temp);
+ }
+ }
+ put_name(reset_3string, " (rs3)");
+ if (i != char_count) {
+ put_crlf();
+ }
+ ptext(" init");
+ put_name(init_1string, " (is1)");
+ put_name(init_2string, " (is2)");
+ if (set_tab && clear_all_tabs && init_tabs != 8) {
+ put_crlf();
+ tc_putp(clear_all_tabs);
+ for (char_count = 0; char_count < columns; char_count++) {
+ put_this(' ');
+ if ((char_count & 7) == 7) {
+ tc_putp(set_tab);
+ }
+ }
+ put_cr();
+ }
+ /* run the initialization file */
+ if (init_file && init_file[0]) {
+ FILE *fp;
+ int ch;
+
+ can_test("if", FLAG_TESTED);
+ if ((fp = fopen(init_file, "r"))) { /* send the init file */
+ sprintf(temp, " (if) %s", init_file);
+ ptextln(temp);
+ while (1) {
+ ch = getc(fp);
+ if (ch == EOF)
+ break;
+ put_this(ch);
+ }
+ fclose(fp);
+ } else {
+ sprintf(temp, "\nCannot open init file (if) %s", init_file);
+ ptextln(temp);
+ }
+ }
+ if (init_prog) {
+ can_test("iprog", FLAG_TESTED);
+ (void) system(init_prog);
+ }
+ put_name(init_3string, " (is3)");
+
+ fflush(stdout);
+}
+
+/*
+** display_basic()
+**
+** display the basic terminal definitions
+*/
+void
+display_basic(void)
+{
+ put_str("Name: ");
+ putln(ttytype);
+
+ report_cap("\\r ^M (cr)", carriage_return);
+ report_cap("\\n ^J (ind)", scroll_forward);
+ report_cap("\\b ^H (cub1)", cursor_left);
+ report_cap("\\t ^I (ht)", tab);
+/* report_cap("\\f ^L (ff)", form_feed); */
+ if (newline) {
+ /* OK if missing */
+ report_cap(" (nel)", newline);
+ }
+ report_cap(" (clear)", clear_screen);
+ if (!cursor_home && cursor_address) {
+ report_cap("(cup) (home)", tparm(cursor_address, 0, 0));
+ } else {
+ report_cap(" (home)", cursor_home);
+ }
+ report_cap("ENQ (u9)", user9);
+ report_cap("ACK (u8)", user8);
+
+ sprintf(temp, "\nTerminal size: %d x %d. Baud rate: %ld. Frame size: %d.%d", columns, lines, tty_baud_rate, tty_frame_size >> 1, (tty_frame_size & 1) * 5);
+ putln(temp);
+}
+
+/*
+** curses_setup(exec_name)
+**
+** Startup ncurses
+*/
+void
+curses_setup(
+ char *exec_name)
+{
+ int status;
+ static TERMTYPE term;
+ char tty_filename[2048];
+
+ tty_init();
+
+ /**
+ See if the terminal is in the terminfo data base. This call has
+ two useful benefits, 1) it returns the filename of the terminfo entry,
+ and 2) it searches only terminfo's. This allows us to abort before
+ ncurses starts scanning the termcap file.
+ **/
+ if ((status = _nc_read_entry(tty_basename, tty_filename, &term)) == 0) {
+ fprintf(stderr, "Terminal not found: TERM=%s\n", tty_basename);
+ show_usage(exec_name);
+ exit(1);
+ }
+ if (status == -1) {
+ fprintf(stderr, "Terminfo database is inaccessible\n");
+ exit(1);
+ }
+
+ /**
+ This call will load the terminfo data base and set the cur-term
+ variable. Only terminals that actually exist will get here so its
+ OK to ignore errors. This is a good thing since ncurses does not
+ permit (os) or (gn) to be set.
+ **/
+ setupterm(tty_basename, 1, &status);
+
+ /**
+ Get the current terminal definitions. This must be done before
+ getting the baudrate.
+ **/
+ _nc_get_curterm(&cur_term->Nttyb);
+ tty_baud_rate = baudrate();
+ tty_cps = (tty_baud_rate << 1) / tty_frame_size;
+
+ /* set up the defaults */
+ replace_mode = TRUE;
+ scan_mode = 0;
+ char_count = 0;
+ select_delay_type = debug_level = 0;
+ char_mask = (meta_on && meta_on[0] == '\0') ? ALLOW_PARITY : STRIP_PARITY;
+ /* Don't change the XON/XOFF modes yet. */
+ select_xon_xoff = initial_stty_query(TTY_XON_XOFF) ? 1 : needs_xon_xoff;
+
+ fflush(stdout); /* flush any output */
+ tty_set();
+
+ go_home(); /* set can_go_home */
+ put_clear(); /* set can_clear_screen */
+
+ if (send_reset_init) {
+ reset_init();
+ }
+
+ /*
+ I assume that the reset and init strings may not have the correct
+ pads. (Because that part of the test comes much later.) Because
+ of this, I allow the terminal some time to catch up.
+ */
+ fflush(stdout); /* waste some time */
+ sleep(1); /* waste more time */
+ charset_can_test();
+ can_test("lines cols cr nxon rf if iprog rmp", FLAG_CAN_TEST);
+ edit_init(); /* initialize the edit data base */
+
+ if (send_reset_init && enter_ca_mode) {
+ tc_putp(enter_ca_mode);
+ put_clear(); /* just in case we switched pages */
+ }
+ put_crlf();
+ ptext("Using terminfo from: ");
+ ptextln(tty_filename);
+ put_crlf();
+
+ if (tty_can_sync == SYNC_NEEDED) {
+ verify_time();
+ }
+
+ display_basic();
+}
+
+/*
+** bye_kids(exit-condition)
+**
+** Shutdown the terminal, clear the signals, and exit
+*/
+void
+bye_kids(int n)
+{ /* reset the tty and exit */
+ ignoresig();
+ if (send_reset_init) {
+ if (exit_ca_mode) {
+ tc_putp(exit_ca_mode);
+ }
+ if (initial_stty_query(TTY_XON_XOFF)) {
+ if (enter_xon_mode) {
+ tc_putp(enter_xon_mode);
+ }
+ } else if (exit_xon_mode) {
+ tc_putp(exit_xon_mode);
+ }
+ }
+ if (debug_fp) {
+ fclose(debug_fp);
+ }
+ if (log_fp) {
+ fclose(log_fp);
+ }
+ tty_reset();
+ fclose(stdin);
+ fclose(stdout);
+ fclose(stderr);
+ if (not_a_tty)
+ sleep(1);
+ exit(n);
+}
diff --git a/contrib/ncurses/tack/menu.c b/contrib/ncurses/tack/menu.c
new file mode 100644
index 000000000000..a2bcc3809054
--- /dev/null
+++ b/contrib/ncurses/tack/menu.c
@@ -0,0 +1,421 @@
+/*
+** Copyright (C) 1991, 1997 Free Software Foundation, Inc.
+**
+** This file is part of TACK.
+**
+** TACK is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2, or (at your option)
+** any later version.
+**
+** TACK is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with TACK; see the file COPYING. If not, write to
+** the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA 02111-1307, USA.
+*/
+
+#include <tack.h>
+
+MODULE_ID("$Id: menu.c,v 1.1 1998/01/10 00:29:30 tom Exp $")
+
+/*
+ Menu control
+ */
+
+static void test_byname(struct test_menu *, int *, int *);
+
+struct test_list *augment_test;
+char prompt_string[80]; /* menu prompt storage */
+
+/*
+** menu_prompt()
+**
+** Print the menu prompt string.
+*/
+void
+menu_prompt(void)
+{
+ ptext(&prompt_string[1]);
+}
+
+/*
+** menu_test_loop(test-structure, state, control-character)
+**
+** This function implements the repeat test function.
+*/
+static void
+menu_test_loop(
+ struct test_list *test,
+ int *state,
+ int *ch)
+{
+ int nch, p;
+
+ if ((test->flags & MENU_REP_MASK) && (augment_test != test)) {
+ /* set the augment variable (first time only) */
+ p = (test->flags >> 8) & 15;
+ if ((test->flags & MENU_REP_MASK) == MENU_LM1) {
+ augment = lines - 1;
+ } else
+ if ((test->flags & MENU_ONE_MASK) == MENU_ONE) {
+ augment = 1;
+ } else
+ if ((test->flags & MENU_LC_MASK) == MENU_lines) {
+ augment = lines * p / 10;
+ } else
+ if ((test->flags & MENU_LC_MASK) == MENU_columns) {
+ augment = columns * p / 10;
+ } else {
+ augment = 1;
+ }
+ augment_test = test;
+ set_augment_txt();
+ }
+ do {
+ if ((test->flags | *state) & MENU_CLEAR) {
+ put_clear();
+ } else
+ if (line_count + test->lines_needed >= lines) {
+ put_clear();
+ }
+ nch = 0;
+ if (test->test_procedure) {
+ /* The procedure takes precidence so I can pass
+ the menu entry as an argument.
+ */
+ can_test(test->caps_done, FLAG_TESTED);
+ can_test(test->caps_tested, FLAG_TESTED);
+ test->test_procedure(test, state, &nch);
+ } else
+ if (test->sub_menu) {
+ /* nested menu's */
+ menu_display(test->sub_menu, &nch);
+ *state = 0;
+ if (nch == 'q' || nch == 's') {
+ /* Quit and skip are killed here */
+ nch = '?';
+ }
+ } else {
+ break; /* cya */
+ }
+ if (nch == '\r' || nch == '\n' || nch == 'n') {
+ nch = 0;
+ break;
+ }
+ } while (nch == 'r');
+ *ch = nch;
+}
+
+/*
+** menu_display(menu-structure, flags)
+**
+** This function implements menu control.
+*/
+void
+menu_display(
+ struct test_menu *menu,
+ int *last_ch)
+{
+ int test_state = 0, run_standard_tests;
+ int hot_topic, ch = 0, nch = 0;
+ struct test_list *mt;
+ struct test_list *repeat_tests = 0;
+ int repeat_state = 0;
+ int prompt_length;
+
+ prompt_length = strlen(prompt_string);
+ if (menu->ident) {
+ sprintf(&prompt_string[prompt_length], "/%s", menu->ident);
+ }
+ hot_topic = menu->default_action;
+ run_standard_tests = menu->standard_tests ?
+ menu->standard_tests[0] : -1;
+ if (!last_ch) {
+ last_ch = &ch;
+ }
+ while (1) {
+ if (ch == 0) {
+ /* Display the menu */
+ put_crlf();
+ if (menu->menu_function) {
+ /*
+ this function may be used to restrict menu
+ entries. If used it must print the title.
+ */
+ menu->menu_function(menu);
+ } else
+ if (menu->menu_title) {
+ ptextln(menu->menu_title);
+ }
+ for (mt = menu->tests; (mt->flags & MENU_LAST) == 0; mt++) {
+ if (mt->menu_entry) {
+ ptext(" ");
+ ptextln(mt->menu_entry);
+ }
+ }
+ if (menu->standard_tests) {
+ ptext(" ");
+ ptextln(menu->standard_tests);
+ ptextln(" r) repeat test");
+ ptextln(" s) skip to next test");
+ }
+ ptextln(" q) quit");
+ ptextln(" ?) help");
+ }
+ if (ch == 0 || ch == REQUEST_PROMPT) {
+ put_crlf();
+ ptext(&prompt_string[1]);
+ if (hot_topic) {
+ ptext(" [");
+ putchp(hot_topic);
+ ptext("]");
+ }
+ ptext(" > ");
+ /* read a character */
+ ch = wait_here();
+ }
+ if (ch == '\r' || ch == '\n') {
+ ch = hot_topic;
+ }
+ if (ch == 'q') {
+ break;
+ }
+ if (ch == '?') {
+ ch = 0;
+ continue;
+ }
+ nch = ch;
+ ch = 0;
+ /* Run one of the standard tests (by request) */
+ for (mt = menu->tests; (mt->flags & MENU_LAST) == 0; mt++) {
+ if (mt->menu_entry && (nch == mt->menu_entry[0])) {
+ if (mt->flags & MENU_MENU) {
+ test_byname(menu, &test_state, &nch);
+ } else {
+ menu_test_loop(mt, &test_state, &nch);
+ }
+ ch = nch;
+ if ((mt->flags & MENU_COMPLETE) && ch == 0) {
+ /* top level */
+ hot_topic = 'q';
+ ch = '?';
+ }
+ }
+ }
+ if (menu->standard_tests && nch == 'r') {
+ menu->resume_tests = repeat_tests;
+ test_state = repeat_state;
+ nch = run_standard_tests;
+ }
+ if (nch == run_standard_tests) {
+ if (!(mt = menu->resume_tests)) {
+ mt = menu->tests;
+ }
+ if (mt->flags & MENU_LAST) {
+ mt = menu->tests;
+ }
+ /* Run the standard test suite */
+ for ( ; (mt->flags & MENU_LAST) == 0; ) {
+ if ((mt->flags & MENU_NEXT) == MENU_NEXT) {
+ repeat_tests = mt;
+ repeat_state = test_state;
+ nch = run_standard_tests;
+ menu_test_loop(mt, &test_state, &nch);
+ if (nch != 0 && nch != 'n') {
+ ch = nch;
+ break;
+ }
+ if (test_state & MENU_STOP) {
+ break;
+ }
+ }
+ mt++;
+ }
+ if (ch == 0) {
+ ch = hot_topic;
+ }
+ menu->resume_tests = mt;
+ menu->resume_state = test_state;
+ menu->resume_char = ch;
+
+ if (ch == run_standard_tests) {
+ /* pop up a level */
+ break;
+ }
+ }
+ }
+ *last_ch = ch;
+ prompt_string[prompt_length] = '\0';
+}
+
+/*
+** generic_done_message(test_list)
+**
+** Print the Done message and request input.
+*/
+void
+generic_done_message(
+ struct test_list *test,
+ int *state,
+ int *ch)
+{
+ char done_message[128];
+
+ if (test->caps_done) {
+ sprintf(done_message, "(%s) Done ", test->caps_done);
+ ptext(done_message);
+ } else {
+ ptext("Done ");
+ }
+ *ch = wait_here();
+ if (*ch == '\r' || *ch == '\n' || *ch == 'n') {
+ *ch = 0;
+ }
+ if (*ch == 's') {
+ *state |= MENU_STOP;
+ *ch = 0;
+ }
+}
+
+/*
+** menu_clear_screen(test, state, ch)
+**
+** Just clear the screen.
+*/
+void
+menu_clear_screen(
+ struct test_list *test GCC_UNUSED,
+ int *state GCC_UNUSED,
+ int *ch GCC_UNUSED)
+{
+ put_clear();
+}
+
+/*
+** menu_reset_init(test, state, ch)
+**
+** Send the reset and init strings.
+*/
+void
+menu_reset_init(
+ struct test_list *test GCC_UNUSED,
+ int *state GCC_UNUSED,
+ int *ch GCC_UNUSED)
+{
+ reset_init();
+ put_crlf();
+}
+
+/*
+** subtest_menu(test, state, ch)
+**
+** Scan the menu looking for something to execute
+** Return TRUE if we found anything.
+*/
+int
+subtest_menu(
+ struct test_list *test,
+ int *state,
+ int *ch)
+{
+ struct test_list *mt;
+
+ if (*ch) {
+ for (mt = test; (mt->flags & MENU_LAST) == 0; mt++) {
+ if (mt->menu_entry && (*ch == mt->menu_entry[0])) {
+ *ch = 0;
+ menu_test_loop(mt, state, ch);
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+/*
+** menu_can_scan(menu-structure)
+**
+** Recursivly scan the menu tree and find which cap names can be tested.
+*/
+void
+menu_can_scan(
+ const struct test_menu *menu)
+{
+ struct test_list *mt;
+
+ for (mt = menu->tests; (mt->flags & MENU_LAST) == 0; mt++) {
+ can_test(mt->caps_done, FLAG_CAN_TEST);
+ can_test(mt->caps_tested, FLAG_CAN_TEST);
+ if (!(mt->test_procedure)) {
+ if (mt->sub_menu) {
+ menu_can_scan(mt->sub_menu);
+ }
+ }
+ }
+}
+
+/*
+** menu_search(menu-structure, cap)
+**
+** Recursivly search the menu tree and execute any tests that use cap.
+*/
+static void
+menu_search(
+ struct test_menu *menu,
+ int *state,
+ int *ch,
+ char *cap)
+{
+ struct test_list *mt;
+ int nch;
+
+ for (mt = menu->tests; (mt->flags & MENU_LAST) == 0; mt++) {
+ nch = 0;
+ if (cap_match(mt->caps_done, cap)
+ || cap_match(mt->caps_tested, cap)) {
+ menu_test_loop(mt, state, &nch);
+ }
+ if (!(mt->test_procedure)) {
+ if (mt->sub_menu) {
+ menu_search(mt->sub_menu, state, &nch, cap);
+ }
+ }
+ if (*state & MENU_STOP) {
+ break;
+ }
+ if (nch != 0 && nch != 'n') {
+ *ch = nch;
+ break;
+ }
+ }
+}
+
+/*
+** test_byname(menu, state, ch)
+**
+** Get a cap name then run all tests that use that cap.
+*/
+static void
+test_byname(
+ struct test_menu *menu,
+ int *state GCC_UNUSED,
+ int *ch)
+{
+ int test_state = 0;
+ char cap[32];
+
+ if (tty_can_sync == SYNC_NOT_TESTED) {
+ verify_time();
+ }
+ ptext("enter name: ");
+ read_string(cap, sizeof(cap));
+ if (cap[0]) {
+ menu_search(menu, &test_state, ch, cap);
+ }
+ *ch = '?';
+}
diff --git a/contrib/ncurses/tack/modes.c b/contrib/ncurses/tack/modes.c
new file mode 100644
index 000000000000..f370ba892cc6
--- /dev/null
+++ b/contrib/ncurses/tack/modes.c
@@ -0,0 +1,913 @@
+/*
+** Copyright (C) 1991, 1997 Free Software Foundation, Inc.
+**
+** This file is part of TACK.
+**
+** TACK is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2, or (at your option)
+** any later version.
+**
+** TACK is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with TACK; see the file COPYING. If not, write to
+** the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA 02111-1307, USA.
+*/
+
+#include <tack.h>
+
+MODULE_ID("$Id: modes.c,v 1.1 1998/01/10 00:29:53 tom Exp $")
+
+/*
+ * Tests boolean flags and terminal modes.
+ */
+static void subtest_os(struct test_list *, int *, int *);
+static void subtest_rmam(struct test_list *, int *, int *);
+static void subtest_smam(struct test_list *, int *, int *);
+static void subtest_am(struct test_list *, int *, int *);
+static void subtest_ul(struct test_list *, int *, int *);
+static void subtest_uc(struct test_list *, int *, int *);
+static void subtest_bw(struct test_list *, int *, int *);
+static void subtest_xenl(struct test_list *, int *, int *);
+static void subtest_eo(struct test_list *, int *, int *);
+static void subtest_xmc(struct test_list *, int *, int *);
+static void subtest_xhp(struct test_list *, int *, int *);
+static void subtest_mir(struct test_list *, int *, int *);
+static void subtest_msgr(struct test_list *, int *, int *);
+static void subtest_tbc(struct test_list *, int *, int *);
+static void subtest_xt(struct test_list *, int *, int *);
+static void subtest_hts(struct test_list *, int *, int *);
+static void subtest_cbt(struct test_list *, int *, int *);
+static void subtest_in(struct test_list *, int *, int *);
+static void subtest_dadb(struct test_list *, int *, int *);
+
+struct test_list mode_test_list[] = {
+ {0, 0, 0, 0, "e) edit terminfo", 0, &edit_menu},
+ {MENU_NEXT, 3, "os", 0, 0, subtest_os, 0},
+ {MENU_NEXT, 1, "rmam", 0, 0, subtest_rmam, 0},
+ {MENU_NEXT, 1, "smam", 0, 0, subtest_smam, 0},
+ {MENU_NEXT, 1, "am", 0, 0, subtest_am, 0},
+ {MENU_NEXT, 3, "ul", 0, 0, subtest_ul, 0},
+ {MENU_NEXT, 3, "uc", 0, 0, subtest_uc, 0},
+ {MENU_NEXT, 3, "bw", 0, 0, subtest_bw, 0},
+ {MENU_NEXT, 4, "xenl", 0, 0, subtest_xenl, 0},
+ {MENU_NEXT, 3, "eo", 0, 0, subtest_eo, 0},
+ {MENU_NEXT, 3, "xmc", 0, 0, subtest_xmc, 0},
+ {MENU_NEXT, 3, "xhp", 0, 0, subtest_xhp, 0},
+ {MENU_NEXT, 6, "mir", 0, 0, subtest_mir, 0},
+ {MENU_NEXT, 6, "msgr", 0, 0, subtest_msgr, 0},
+ {MENU_NEXT | MENU_CLEAR, 0, "tbc", "it", 0, subtest_tbc, 0},
+ {MENU_NEXT | MENU_CLEAR, 0, "hts", "it", 0, subtest_hts, 0},
+ {MENU_NEXT, 4, "xt", "it", 0, subtest_xt, 0},
+ {MENU_NEXT, 1, "cbt", "it", 0, subtest_cbt, 0},
+ {MENU_NEXT, 6, "in", 0, 0, subtest_in, 0},
+ {MENU_NEXT, 1, "da) (db", 0, 0, subtest_dadb, 0},
+ {MENU_LAST, 0, 0, 0, 0, 0, 0}
+};
+
+/*
+** subtest_os(test_list, status, ch)
+**
+** test over strike mode (os)
+*/
+static void
+subtest_os(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ ptext("(os) should be true, not false.");
+ put_cr();
+ ptextln("(os) should be false.");
+ sprintf(temp, "(os) over-strike is %s in the data base. ",
+ over_strike ? "true" : "false");
+ ptext(temp);
+ generic_done_message(t, state, ch);
+}
+
+/*
+** subtest_rmam(test_list, status, ch)
+**
+** test exit automatic margins mode (rmam)
+*/
+static void
+subtest_rmam(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int j;
+
+ if (!exit_am_mode) {
+ ptext("(rmam) not present. ");
+ } else
+ if (!can_go_home) {
+ ptext("(rmam) not tested, no way to home cursor. ");
+ } else
+ if (over_strike) {
+ put_clear();
+ go_home();
+ tc_putp(exit_am_mode);
+ ptext("\n(rmam) will reset (am)");
+ go_home();
+ for (j = 0; j < columns; j++)
+ put_this(' ');
+ ptext("(rmam) will not reset (am)");
+ go_home();
+ put_newlines(2);
+ } else {
+ put_clear();
+ go_home();
+ tc_putp(exit_am_mode);
+ ptext("\n(rmam) will reset (am)");
+ go_home();
+ for (j = 0; j < columns; j++)
+ put_this(' ');
+ ptext("(rmam) will not reset (am) ");
+ go_home();
+ put_str(" ");
+ go_home();
+ put_newlines(2);
+ }
+ ptext("Exit-automatic-margins ");
+ generic_done_message(t, state, ch);
+}
+
+/*
+** subtest_smam(test_list, status, ch)
+**
+** test enter automatic margins mode (smam)
+*/
+static void
+subtest_smam(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int i, j;
+
+ if (!enter_am_mode) {
+ ptext("(smam) not present. ");
+ } else
+ if (!can_go_home) {
+ ptext("(smam) not tested, no way to home cursor. ");
+ } else
+ if (over_strike) {
+ put_clear();
+ go_home();
+ tc_putp(enter_am_mode);
+ ptext("\n(smam) will ");
+ i = char_count;
+ ptext("not set (am)");
+ go_home();
+ for (j = -i; j < columns; j++)
+ put_this(' ');
+ put_str("@@@");
+ put_newlines(2);
+ } else {
+ put_clear();
+ go_home();
+ tc_putp(enter_am_mode);
+ ptext("\n(smam) will not set (am)");
+ go_home();
+ for (j = 0; j < columns; j++)
+ put_this(' ');
+ ptext("(smam) will set (am) ");
+ go_home();
+ put_str(" ");
+ put_newlines(2);
+ }
+ ptext("Enter-automatic-margins ");
+ generic_done_message(t, state, ch);
+}
+
+/*
+** subtest_am(test_list, status, ch)
+**
+** test automatic margins (am)
+*/
+static void
+subtest_am(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int i, j;
+
+ if (!can_go_home) {
+ ptextln("(am) not tested, no way to home cursor. ");
+ } else
+ if (over_strike) {
+ put_clear();
+ go_home();
+ ptext("\n(am) should ");
+ i = char_count;
+ ptext("not be set");
+ go_home();
+ for (j = -i; j < columns; j++)
+ put_this(' ');
+ put_str("@@@");
+ go_home();
+ put_newlines(2);
+ sprintf(temp, "(am) is %s in the data base",
+ auto_right_margin ? "true" : "false");
+ ptextln(temp);
+ } else {
+ put_clear();
+ go_home();
+ ptext("\n(am) should not be set");
+ go_home();
+ for (j = 0; j < columns; j++)
+ put_this(' ');
+ ptext("(am) should be set ");
+ go_home();
+ put_str(" \n\n");
+ sprintf(temp, "(am) is %s in the data base",
+ auto_right_margin ? "true" : "false");
+ ptextln(temp);
+ }
+ ptext("Automatic-right-margin ");
+ generic_done_message(t, state, ch);
+}
+
+/* Note: uprint() sends underscore back-space character, and
+ ucprint() sends character back-space underscore. */
+
+/*
+** uprint(string)
+**
+** underline string for (ul) test
+*/
+static void
+uprint(const char *s)
+{
+ if (s) {
+ while (*s) {
+ put_str("_\b");
+ putchp(*s++);
+ }
+ }
+}
+
+/*
+** ucprint(string)
+**
+** underline string for (uc) test
+*/
+static void
+ucprint(const char *s)
+{
+ if (s) {
+ while (*s) {
+ putchp(*s++);
+ putchp('\b');
+ tc_putp(underline_char);
+ }
+ }
+}
+
+/*
+** subtest_ul(test_list, status, ch)
+**
+** test transparent underline (ul)
+*/
+static void
+subtest_ul(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ if (!over_strike) {
+ /* (ul) is used only if (os) is reset */
+ put_crlf();
+ sprintf(temp, "This text should %sbe underlined.",
+ transparent_underline ? "" : "not ");
+ uprint(temp);
+ put_crlf();
+ ptextln("If the above line is not underlined the (ul) should be false.");
+ sprintf(temp, "(ul) Transparent-underline is %s in the data base",
+ transparent_underline ? "true" : "false");
+ ptextln(temp);
+ generic_done_message(t, state, ch);
+ }
+}
+
+/*
+** subtest_uc(test_list, status, ch)
+**
+** test underline character (uc)
+*/
+static void
+subtest_uc(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ if (!over_strike) {
+ if (underline_char) {
+ ucprint("This text should be underlined.");
+ put_crlf();
+ ptextln("If the above text is not underlined the (uc) has failed.");
+ ptext("Underline-character ");
+ } else {
+ ptext("(uc) underline-character is not defined. ");
+ }
+ generic_done_message(t, state, ch);
+ }
+}
+
+/*
+** subtest_bw(test_list, status, ch)
+**
+** test auto left margin (bw)
+*/
+static void
+subtest_bw(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int i, j;
+
+ if (over_strike) {
+ /* test (bw) */
+ ptext("\n(bw) should ");
+ i = char_count;
+ ptextln("not be set.");
+ for (j = i; j < columns; j++)
+ put_str("\b");
+ put_str("@@@");
+ put_crlf();
+ sprintf(temp, "(bw) Auto-left-margin is %s in the data base",
+ auto_left_margin ? "true" : "false");
+ ptextln(temp);
+ } else {
+ /* test (bw) */
+ ptextln("(bw) should not be set.");
+ for (i = 12; i < columns; i++)
+ put_str("\b");
+ if (delete_character) {
+ for (i = 0; i < 4; i++)
+ tc_putp(delete_character);
+ } else {
+ put_str(" ");
+ }
+ put_crlf();
+ sprintf(temp, "(bw) Auto-left-margin is %s in the data base",
+ auto_left_margin ? "true" : "false");
+ ptextln(temp);
+ }
+ generic_done_message(t, state, ch);
+}
+
+/*
+** subtest_tbc(test_list, status, ch)
+**
+** test clear tabs (tbc)
+*/
+static void
+subtest_tbc(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int tabat; /* the tab spacing we end up with */
+ int i;
+
+ if (clear_all_tabs && !set_tab) {
+ ptext("(tbc) Clear-all-tabs is defined but (hts) set-tab is not. ");
+ ptext("Once the tabs are cleared there is no way to set them. ");
+ } else
+ if (clear_all_tabs) {
+ tabat = set_tab ? 8 : init_tabs;
+ tc_putp(clear_all_tabs);
+ ptext("Clear tabs (tbc)");
+ go_home();
+ put_crlf();
+ putchp('\t');
+ putchp('T');
+ go_home();
+ put_newlines(2);
+ for (i = 0; i < columns; i++) {
+ if (i == tabat) {
+ putchp('T');
+ } else {
+ putchp('.');
+ }
+ }
+ go_home();
+ ptext("\n\n\nIf the above two lines have T's in the same column then (tbc) has failed. ");
+ } else {
+ ptext("(tbc) Clear-all-tabs is not defined. ");
+ }
+ generic_done_message(t, state, ch);
+}
+
+/*
+** subtest_hts(test_list, status, ch)
+**
+** (ht) and set tabs with (hts)
+*/
+static void
+subtest_hts(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int tabat; /* the tab spacing we end up with */
+ int i;
+
+ tabat = init_tabs;
+ if (set_tab) {
+ ptext("Tabs set with (hts)");
+ put_crlf();
+ for (i = 1; i < columns; i++) {
+ if (i % 8 == 1) {
+ tc_putp(set_tab);
+ }
+ putchp(' ');
+ }
+ tabat = 8;
+ } else {
+ sprintf(temp, "(hts) Set-tabs not defined. (it) Initial-tabs at %d", init_tabs);
+ ptext(temp);
+ }
+ go_home();
+ put_newlines(2);
+ if (tabat <= 0) {
+ tabat = 8;
+ }
+ for (i = tabat; i < columns; i += tabat) {
+ putchp('\t');
+ putchp('T');
+ }
+ go_home();
+ put_newlines(3);
+ for (i = 1; i < columns; i++) {
+ putchp('.');
+ }
+ go_home();
+ put_newlines(3);
+ for (i = tabat; i < columns; i += tabat) {
+ putchp('\t');
+ putchp('T');
+ }
+ go_home();
+ put_newlines(4);
+ putchp('.');
+ for (i = 2; i < columns; i++) {
+ if (i % tabat == 1) {
+ putchp('T');
+ } else {
+ putchp('.');
+ }
+ }
+ go_home();
+ put_newlines(5);
+ if (set_tab) {
+ ptextln("If the last two lines are not the same then (hts) has failed.");
+ } else
+ if (init_tabs > 0) {
+ ptextln("If the last two lines are not the same then (it) is wrong.");
+ } else {
+ ptextln("If the last two lines are the same then maybe you do have tabs and (it) should be changed.");
+ }
+ generic_done_message(t, state, ch);
+}
+
+/*
+** subtest_xt(test_list, status, ch)
+**
+** (xt) glitch
+*/
+static void
+subtest_xt(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int tabat; /* the tab spacing we end up with */
+ int cc;
+
+ tabat = set_tab ? 8 : init_tabs;
+ if (!over_strike && (tabat > 0)) {
+ ptext("(xt) should not ");
+ put_cr();
+ ptext("(xt) should");
+ cc = char_count;
+ while (cc < 16) {
+ putchp('\t');
+ cc = ((cc / tabat) + 1) * tabat;
+ }
+ putln("be set.");
+ sprintf(temp, "(xt) Destructive-tab is %s in the data base.",
+ dest_tabs_magic_smso ? "true" : "false");
+ ptextln(temp);
+ generic_done_message(t, state, ch);
+ }
+}
+
+/*
+** subtest_cbt(test_list, status, ch)
+**
+** (cbt) back tab
+*/
+static void
+subtest_cbt(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int i;
+
+ if (back_tab) {
+ put_clear();
+ ptext("Back-tab (cbt)");
+ go_home();
+ put_crlf();
+ for (i = 1; i < columns; i++) {
+ putchp(' ');
+ }
+ for (i = 0; i < columns; i += 8) {
+ tc_putp(back_tab);
+ putchp('T');
+ tc_putp(back_tab);
+ }
+ go_home();
+ put_newlines(2);
+ for (i = 1; i < columns; i++) {
+ if (i % 8 == 1) {
+ putchp('T');
+ } else {
+ putchp(' ');
+ }
+ }
+ go_home();
+ put_newlines(3);
+ ptextln("The preceding two lines should be the same.");
+ } else {
+ ptextln("(cbt) Back-tab not present");
+ }
+ generic_done_message(t, state, ch);
+}
+
+/*
+** subtest_xenl(test_list, status, ch)
+**
+** (xenl) eat newline glitch
+*/
+static void
+subtest_xenl(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int i, j, k;
+
+ if (over_strike) {
+ /* test (xenl) on overstrike terminals */
+ if (!can_go_home || !can_clear_screen) {
+ ptextln("(xenl) Newline-glitch not tested, can't home cursor and clear.");
+ generic_done_message(t, state, ch);
+ return;
+ }
+ put_clear();
+ /*
+ this test must be done in raw mode. Otherwise UNIX will
+ translate CR to CRLF.
+ */
+ if (stty_query(TTY_OUT_TRANS))
+ tty_raw(1, char_mask);
+ ptext("\nreset (xenl). Does ");
+ i = char_count;
+ put_str("not ignore CR, does ");
+ k = char_count;
+ put_str("not ignore LF");
+ go_home();
+ for (j = 0; j < columns; j++)
+ put_this(' ');
+ put_cr();
+ for (j = 0; j < i; j++)
+ putchp(' ');
+ put_str("@@@\n@@");
+ go_home();
+ for (j = 0; j < columns; j++)
+ put_this(' ');
+ put_lf();
+ for (j = 0; j < k; j++)
+ putchp(' ');
+ put_str("@@@\r@@");
+ tty_set();
+ go_home();
+ put_newlines(4);
+ sprintf(temp, "(xenl) Newline-glitch is %s in the data base",
+ eat_newline_glitch ? "true" : "false");
+ ptextln(temp);
+ } else {
+ /* test (xenl) when (os) is reset */
+ if (!can_go_home) {
+ ptextln("(xenl) Newline-glitch not tested, can't home cursor");
+ generic_done_message(t, state, ch);
+ return;
+ }
+ /* (xenl) test */
+ put_clear();
+ /*
+ this test must be done in raw mode. Otherwise
+ UNIX will translate CR to CRLF.
+ */
+ if (stty_query(TTY_OUT_TRANS))
+ tty_raw(1, char_mask);
+ for (j = 0; j < columns; j++)
+ put_this(' ');
+ put_cr();
+ ptext("(xenl) should be set. Does not ignore CR");
+ go_home();
+ put_crlf();
+ for (j = 0; j < columns; j++)
+ put_this(' ');
+ put_lf(); /* test (cud1) */
+ ptext("(xenl) should be set. Ignores (cud1)");
+ go_home();
+ put_newlines(3);
+ if (scroll_forward && cursor_down &&
+ strcmp(scroll_forward, cursor_down)) {
+ for (j = 0; j < columns; j++)
+ put_this(' ');
+ put_ind(); /* test (ind) */
+ ptext("(xenl) should be set. Ignores (ind)");
+ go_home();
+ put_newlines(5);
+ }
+ tty_set();
+ ptextln("If you don't see text above telling you to set it, (xenl) should be false");
+ sprintf(temp, "(xenl) Newline-glitch is %s in the data base",
+ eat_newline_glitch ? "true" : "false");
+ ptextln(temp);
+ }
+ generic_done_message(t, state, ch);
+}
+
+/*
+** subtest_eo(test_list, status, ch)
+**
+** (eo) erase overstrike
+*/
+static void
+subtest_eo(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ if (transparent_underline || over_strike || underline_char) {
+ ptext("(eo) should ");
+ if (underline_char) {
+ ucprint("not");
+ } else {
+ uprint("not");
+ }
+ put_cr();
+ ptextln("(eo) should be set");
+ sprintf(temp, "\n(eo) Erase-overstrike is %s in the data base",
+ erase_overstrike ? "true" : "false");
+ ptextln(temp);
+ generic_done_message(t, state, ch);
+ }
+}
+
+/*
+** subtest_xmc(test_list, status, ch)
+**
+** (xmc) magic cookie glitch
+*/
+static void
+subtest_xmc(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int i, j;
+
+ if (enter_standout_mode) {
+ sprintf(temp, "\n(xmc) Magic-cookie-glitch is %d in the data base", magic_cookie_glitch);
+ ptextln(temp);
+ j = magic_cookie_glitch * 8;
+ for (i = 0; i < j; i++) {
+ put_str(" ");
+ }
+ ptextln(" These two lines should line up.");
+ if (j > 0) {
+ char_count += j;
+ }
+ for (i = 0; i < 4; i++) {
+ put_mode(enter_standout_mode);
+ putchp(' ');
+ put_mode(exit_standout_mode);
+ putchp(' ');
+ }
+ ptextln("These two lines should line up.");
+ ptext("If they don't line up then (xmc) magic-cookie-glitch should be greater than zero. ");
+ generic_done_message(t, state, ch);
+ }
+}
+
+/*
+** subtest_xhp(test_list, status, ch)
+**
+** (xhp) erase does not clear standout mode
+*/
+static void
+subtest_xhp(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ if (enter_standout_mode) {
+ put_crlf();
+ put_mode(enter_standout_mode);
+ put_str("Stand out");
+ put_mode(exit_standout_mode);
+ put_cr();
+ ptextln("If any part of this line is standout then (xhp) should be set.");
+ sprintf(temp, "(xhp) Erase-standout-glitch is %s in the data base",
+ ceol_standout_glitch ? "true" : "false");
+ ptextln(temp);
+ generic_done_message(t, state, ch);
+ }
+}
+
+/*
+** subtest_mir(test_list, status, ch)
+**
+** (mir) move in insert mode
+*/
+static void
+subtest_mir(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int i;
+ char *s;
+
+ if (enter_insert_mode && exit_insert_mode && cursor_address) {
+ put_clear();
+ i = line_count;
+ put_str("\nXXX\nXXX\nXXX\nXXX");
+ tc_putp(enter_insert_mode);
+ s = tparm(cursor_address, i + 1, 0);
+ tputs(s, lines, tc_putch);
+ putchp('X');
+ s = tparm(cursor_address, i + 2, 1);
+ tputs(s, lines, tc_putch);
+ putchp('X');
+ s = tparm(cursor_address, i + 3, 2);
+ tputs(s, lines, tc_putch);
+ putchp('X');
+ s = tparm(cursor_address, i + 4, 3);
+ tputs(s, lines, tc_putch);
+ putchp('X');
+ tc_putp(exit_insert_mode);
+ put_newlines(2);
+ ptextln("If you see a 4 by 4 block of X's then (mir) should be true.");
+ sprintf(temp, "(mir) Move-in-insert-mode is %s in the data base",
+ move_insert_mode ? "true" : "false");
+ ptextln(temp);
+ } else {
+ ptext("(mir) Move-in-insert-mode not tested, ");
+ if (!enter_insert_mode) {
+ ptext("(smir) ");
+ }
+ if (!exit_insert_mode) {
+ ptext("(rmir) ");
+ }
+ if (!cursor_address) {
+ ptext("(cup) ");
+ }
+ ptext("not present. ");
+ }
+ generic_done_message(t, state, ch);
+}
+
+/*
+** subtest_msgr(test_list, status, ch)
+**
+** (msgr) move in sgr mode
+*/
+static void
+subtest_msgr(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int i;
+
+ if (cursor_address &&
+ ((enter_standout_mode && exit_standout_mode) ||
+ (enter_alt_charset_mode && exit_alt_charset_mode))) {
+ put_crlf();
+ i = line_count + 1;
+ tputs(tparm(cursor_address, i, 0), lines, tc_putch);
+ put_mode(enter_alt_charset_mode);
+ put_crlf();
+ /*
+ some versions of the wy-120 can not clear lines or
+ screen when in alt charset mode. If (el) and (ed)
+ are defined then I can test them. If they are not
+ defined then they can not break (msgr)
+ */
+ tc_putp(clr_eos);
+ tc_putp(clr_eol);
+ put_mode(exit_alt_charset_mode);
+ put_mode(enter_standout_mode);
+ putchp('X');
+ tputs(tparm(cursor_address, i + 2, 1), lines, tc_putch);
+ putchp('X');
+ tputs(tparm(cursor_address, i + 3, 2), lines, tc_putch);
+ putchp('X');
+ tputs(tparm(cursor_address, i + 4, 3), lines, tc_putch);
+ putchp('X');
+ put_mode(exit_standout_mode);
+ put_crlf();
+ tc_putp(clr_eos); /* OK if missing */
+ put_crlf();
+ ptextln("If you see a diagonal line of standout X's then (msgr) should be true. If any of the blanks are standout then (msgr) should be false.");
+ sprintf(temp, "(msgr) Move-in-SGR-mode is %s in the data base",
+ move_standout_mode ? "true" : "false");
+ ptextln(temp);
+ } else {
+ ptextln("(smso) (rmso) (smacs) (rmacs) missing; (msgr) Move-in-SGR-mode not tested.");
+ }
+ generic_done_message(t, state, ch);
+}
+
+/*
+** subtest_in(test_list, status, ch)
+**
+** (in) insert null glitch
+*/
+static void
+subtest_in(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ if (enter_insert_mode && exit_insert_mode) {
+ ptextln("\nTesting (in) with (smir) and (rmir)");
+ putln("\tIf these two lines line up ...");
+ put_str("\tIf these two lines line up ...");
+ put_cr();
+ tc_putp(enter_insert_mode);
+ putchp(' ');
+ tc_putp(exit_insert_mode);
+ ptext("\nthen (in) should be set. ");
+ sprintf(temp,
+ "(in) Insert-null-glitch is %s in the data base.",
+ insert_null_glitch ? "true" : "false");
+ ptextln(temp);
+ generic_done_message(t, state, ch);
+ }
+}
+
+/*
+** subtest_dadb(test_list, status, ch)
+**
+** (da) (db) data above, (db) data below
+*/
+static void
+subtest_dadb(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ if (can_clear_screen && scroll_reverse && scroll_forward) {
+ put_clear();
+ if (scroll_reverse)
+ ptext("(da) Data-above should be set\r");
+ home_down();
+ if (scroll_forward)
+ ptext("(db) Data-below should be set\r");
+ tc_putp(scroll_forward);
+ go_home();
+ tc_putp(scroll_reverse);
+ tc_putp(scroll_reverse);
+ home_down();
+ tc_putp(scroll_forward);
+ go_home();
+ ptextln("\n\n\n\n\nIf the top line is blank then (da) should be false.");
+ ptextln("If the bottom line is blank then (db) should be false.");
+ sprintf(temp, "\n(da) Data-above is %s, and (db) Data-below is %s, in the data base.",
+ memory_above ? "true" : "false",
+ memory_below ? "true" : "false");
+ ptextln(temp);
+ line_count = lines;
+ } else {
+ ptextln("(da) Data-above, (db) Data-below not tested, scrolls or (clear) is missing.");
+ }
+ generic_done_message(t, state, ch);
+}
diff --git a/contrib/ncurses/tack/modules b/contrib/ncurses/tack/modules
new file mode 100644
index 000000000000..79c2d2265f7b
--- /dev/null
+++ b/contrib/ncurses/tack/modules
@@ -0,0 +1,18 @@
+# $Id: modules,v 1.4 1999/04/18 01:43:32 tom Exp $
+@ base
+ansi progs $(srcdir) $(srcdir)/tack.h ../include/term.h
+charset progs $(srcdir) $(srcdir)/tack.h ../include/term.h
+color progs $(srcdir) $(srcdir)/tack.h ../include/term.h
+control progs $(srcdir) $(srcdir)/tack.h ../include/term.h
+crum progs $(srcdir) $(srcdir)/tack.h ../include/term.h
+edit progs $(srcdir) $(srcdir)/tack.h ../include/term.h $(INCDIR)/tic.h
+fun progs $(srcdir) $(srcdir)/tack.h ../include/term.h
+init progs $(srcdir) $(srcdir)/tack.h ../include/term.h
+menu progs $(srcdir) $(srcdir)/tack.h ../include/term.h
+modes progs $(srcdir) $(srcdir)/tack.h ../include/term.h
+output progs $(srcdir) $(srcdir)/tack.h ../include/term.h
+pad progs $(srcdir) $(srcdir)/tack.h ../include/term.h
+scan progs $(srcdir) $(srcdir)/tack.h ../include/term.h
+sync progs $(srcdir) $(srcdir)/tack.h ../include/term.h
+sysdep progs $(srcdir) $(srcdir)/tack.h ../include/term.h
+tack progs $(srcdir) $(srcdir)/tack.h ../include/term.h
diff --git a/contrib/ncurses/tack/output.c b/contrib/ncurses/tack/output.c
new file mode 100644
index 000000000000..3c419a8b48bc
--- /dev/null
+++ b/contrib/ncurses/tack/output.c
@@ -0,0 +1,818 @@
+/*
+** Copyright (C) 1991, 1997 Free Software Foundation, Inc.
+**
+** This file is part of TACK.
+**
+** TACK is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2, or (at your option)
+** any later version.
+**
+** TACK is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with TACK; see the file COPYING. If not, write to
+** the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA 02111-1307, USA.
+*/
+/* screen formatting and I/O utility functions */
+
+#include <tack.h>
+#include <time.h>
+
+MODULE_ID("$Id: output.c,v 1.4 1999/06/16 00:46:53 tom Exp $")
+
+/* globals */
+long char_sent; /* number of characters sent */
+int char_count; /* counts characters */
+int line_count; /* counts line feeds */
+int expand_chars; /* length of expand() string */
+int replace_mode; /* used to output replace mode padding */
+int can_go_home; /* TRUE if we can fashion a home command */
+int can_clear_screen; /* TRUE if we can somehow clear the screen */
+int raw_characters_sent; /* Total output characters */
+int log_count; /* Number of characters on a log line */
+
+/* translate mode default strings */
+#define TM_carriage_return TM_string[0].value
+#define TM_cursor_down TM_string[1].value
+#define TM_scroll_forward TM_string[2].value
+#define TM_newline TM_string[3].value
+#define TM_cursor_left TM_string[4].value
+#define TM_bell TM_string[5].value
+#define TM_form_feed TM_string[6].value
+#define TM_tab TM_string[7].value
+
+struct default_string_list TM_string[TM_last] = {
+ {"cr", "\r", 0},
+ {"cud1", "\n", 0},
+ {"ind", "\n", 0},
+ {"nel", "\r\n", 0},
+ {"cub1", "\b", 0},
+ {"bel", "\007", 0},
+ {"ff", "\f", 0},
+ {"ht", "\t", 0}
+};
+
+static const char *c0[32] = {
+ "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK",
+ "BEL", "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI",
+ "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
+ "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US"
+};
+
+static const char *c1[32] = {
+ "", "", "", "", "IND", "NEL", "SSA", "ESA",
+ "HTS", "HTJ", "VTS", "PLD", "PLU", "RI", "SS2", "SS3",
+ "DCS", "PU1", "PU2", "STS", "CCH", "MW", "SPA", "EPA",
+ "", "", "", "CSI", "ST", "OSC", "PM", "APC"
+};
+
+int
+getnext(int mask)
+{ /* get the next character without scan mode
+ conversion */
+ int ch;
+ unsigned char buf;
+
+ tc_putp(req_for_input);
+ fflush(stdout);
+ if (nodelay_read)
+ while (1) {
+ ch = read(fileno(stdin), &buf, 1);
+ if (ch == -1)
+ return EOF;
+ if (ch == 1)
+ return buf;
+ }
+ ch = getchar();
+ if (ch == EOF)
+ return EOF;
+ return ch & mask;
+}
+
+
+int
+getchp(int mask)
+{ /* read a character with scan mode conversion */
+ if (scan_mode) {
+ tc_putp(req_for_input);
+ fflush(stdout);
+ return scan_key();
+ } else
+ return getnext(mask);
+}
+
+/*
+** tc_putch(c)
+**
+** Output one character
+*/
+int
+tc_putch(int c)
+{
+ char_sent++;
+ raw_characters_sent++;
+ putchar(c);
+ if ((raw_characters_sent & 31) == 31) {
+ fflush(stdout);
+ }
+ if (log_fp) {
+ /* terminal output logging */
+ c &= 0xff;
+ if (c < 32) {
+ fprintf(log_fp, "<%s>", c0[c]);
+ log_count += 5;
+ } else
+ if (c < 127) {
+ fprintf(log_fp, "%c", c);
+ log_count += 1;
+ } else {
+ fprintf(log_fp, "<%02x>", c);
+ log_count += 4;
+ }
+ if (c == '\n' || log_count >= 80) {
+ fprintf(log_fp, "\n");
+ log_count = 0;
+ }
+ }
+ return (c);
+}
+
+/*
+** tt_tputs(string, reps)
+**
+** Output a string with tputs() translation.
+** Use this function inside timing tests.
+*/
+void
+tt_tputs(const char *string, int reps)
+{
+ int i;
+
+ if (string) {
+ for (i = 0; i < TT_MAX; i++) {
+ if (i >= ttp) {
+ tt_cap[i] = string;
+ tt_affected[i] = reps;
+ tt_count[i] = 1;
+ tt_delay[i] = msec_cost(string, reps);
+ ttp++;
+ break;
+ }
+ if (string == tt_cap[i] && reps == tt_affected[i]) {
+ tt_count[i]++;
+ tt_delay_used += tt_delay[i];
+ break;
+ }
+ }
+ (void) tputs(string, reps, tc_putch);
+ }
+}
+
+/*
+** tt_putp(string)
+**
+** Output a string with tputs() translation.
+** Use this function inside timing tests.
+*/
+void
+tt_putp(const char *string)
+{
+ tt_tputs(string, 1);
+}
+
+/*
+** tt_putparm(string, reps, arg1, arg2, ...)
+**
+** Send tt_tputs(tparm(string, args...), reps)
+** Use this function inside timing tests.
+*/
+void
+tt_putparm(
+ NCURSES_CONST char *string,
+ int reps,
+ int arg1,
+ int arg2)
+{
+ int i;
+
+ if (string) {
+ for (i = 0; i < TT_MAX; i++) {
+ if (i >= ttp) {
+ tt_cap[i] = string;
+ tt_affected[i] = reps;
+ tt_count[i] = 1;
+ tt_delay[i] = msec_cost(string, reps);
+ ttp++;
+ break;
+ }
+ if (string == tt_cap[i] && reps == tt_affected[i]) {
+ tt_count[i]++;
+ tt_delay_used += tt_delay[i];
+ break;
+ }
+ }
+ (void) tputs(tparm((NCURSES_CONST char *)string, arg1, arg2), reps, tc_putch);
+ }
+}
+
+/*
+** tc_putp(string)
+**
+** Output a string with tputs() translation.
+** Use this function instead of putp() so we can track
+** the actual number of characters sent.
+*/
+int
+tc_putp(const char *string)
+{
+ return tputs(string, 1, tc_putch);
+}
+
+
+void
+put_this(int c)
+{ /* output one character (with padding) */
+ tc_putch(c);
+ if (char_padding && replace_mode)
+ tt_putp(char_padding);
+}
+
+
+void
+put_cr(void)
+{
+ if (translate_mode && carriage_return) {
+ tt_putp(carriage_return);
+ } else {
+ tt_putp(TM_carriage_return);
+ }
+ char_count = 0;
+}
+
+
+void
+put_lf(void)
+{ /* send a linefeed (only works in RAW or
+ CBREAK mode) */
+ if (translate_mode && cursor_down) {
+ tt_putp(cursor_down);
+ } else {
+ tt_putp(TM_cursor_down);
+ }
+ line_count++;
+}
+
+
+void
+put_ind(void)
+{ /* scroll forward (only works in RAW or
+ CBREAK mode) */
+ if (translate_mode && scroll_forward) {
+ tt_putp(scroll_forward);
+ } else {
+ tt_putp(TM_scroll_forward);
+ }
+ line_count++;
+}
+
+/*
+** put_crlf()
+**
+** Send (nel) or <cr> <lf>
+*/
+void
+put_crlf(void)
+{
+ if (translate_mode && newline) {
+ tt_putp(newline);
+ } else {
+ tt_putp(TM_newline);
+ }
+ char_count = 0;
+ line_count++;
+}
+
+/*
+** put_new_lines(count)
+**
+** Send a number of newlines. (nel)
+*/
+void
+put_newlines(int n)
+{
+ while (n-- > 0) {
+ put_crlf();
+ }
+}
+
+/*
+** putchp(character)
+**
+** Send one character to the terminal.
+** This function does translation of control characters.
+*/
+void
+putchp(int c)
+{
+ switch (c) {
+ case '\b':
+ if (translate_mode && cursor_left) {
+ tt_putp(cursor_left);
+ } else {
+ tt_putp(TM_cursor_left);
+ }
+ char_count--;
+ break;
+ case 7:
+ if (translate_mode && bell) {
+ tt_putp(bell);
+ } else {
+ tt_putp(TM_bell);
+ }
+ break;
+ case '\f':
+ if (translate_mode && form_feed) {
+ tt_putp(form_feed);
+ } else {
+ tt_putp(TM_form_feed);
+ }
+ char_count = 0;
+ line_count++;
+ break;
+ case '\n':
+ put_crlf();
+ break;
+ case '\r':
+ put_cr();
+ break;
+ case '\t':
+ if (translate_mode && tab) {
+ tt_putp(tab);
+ } else {
+ tt_putp(TM_tab);
+ }
+ char_count = ((char_count / 8) + 1) * 8;
+ break;
+ default:
+ put_this(c);
+ char_count++;
+ break;
+ }
+}
+
+
+void
+put_str(const char *s)
+{ /* send the string to the terminal */
+ for (; *s; putchp(*s++));
+}
+
+
+void
+putln(const char *s)
+{ /* output a string followed by a CR LF */
+ for (; *s; putchp(*s++));
+ put_crlf();
+}
+
+
+void
+put_columns(const char *s, int len, int w)
+{ /* put out s in column format */
+ int l;
+
+ if (char_count + w > columns) {
+ put_crlf();
+ }
+ l = char_count % w;
+ if (l) {
+ while (l < w) {
+ putchp(' ');
+ l++;
+ }
+ }
+ if (char_count && char_count + len >= columns) {
+ put_crlf();
+ }
+ l = char_count;
+ put_str(s);
+ char_count = l + len;
+}
+
+
+/*
+** ptext(string)
+**
+** Output a string but do not assume the terminal will wrap to a
+** new line. Break the line at a word boundry then send a CR LF.
+** This is more estetic on 40 column terminals.
+*/
+void
+ptext(const char *s)
+{
+ const char *t;
+
+ while (*s) {
+ for (t = s + 1; *t > ' '; t++);
+ if ((char_count != 0) && ((t - s) + char_count >= columns)) {
+ put_crlf();
+ while (*s == ' ')
+ s++;
+ }
+ while (s < t) {
+ putchp(*s++);
+ }
+ }
+}
+
+
+void
+put_dec(char *f, int i)
+{ /* print a line with a decimal number in it */
+ char tm[128];
+
+ sprintf(tm, f, i / 10, i % 10);
+ ptext(tm);
+}
+
+
+void
+three_digit(char *tx, int i)
+{ /* convert the decimal number to a string of
+ at least 3 digits */
+ if (i < 1000)
+ sprintf(tx, "%d.%d", i / 10, i % 10);
+ else
+ sprintf(tx, "%d", i / 10);
+}
+
+
+void
+ptextln(const char *s)
+{ /* print the text using ptext() then add a CR
+ LF */
+ ptext(s);
+ put_crlf();
+}
+
+
+static void
+expand_one(int ch, char **v)
+{ /* expand one character */
+ char *t = *v;
+
+ if (ch & 0x80) { /* dump it in octal (yuck) */
+ *t++ = '\\';
+ *t++ = '0' + ((ch >> 6) & 3);
+ *t++ = '0' + ((ch >> 3) & 7);
+ *t++ = '0' + (ch & 7);
+ expand_chars += 4;
+ } else if (ch == 127) { /* DEL */
+ *t++ = '^';
+ *t++ = '?';
+ expand_chars += 2;
+ } else if (ch >= ' ') {
+ *t++ = ch;
+ expand_chars++;
+ } else { /* control characters */
+ *t++ = '^';
+ *t++ = ch + '@';
+ expand_chars += 2;
+ }
+ *v = t;
+}
+
+
+char *
+expand(const char *s)
+{ /* convert the string to printable form */
+ static char buf[4096];
+ char *t, *v;
+ int ch;
+
+ if (magic_cookie_glitch <= 0 && exit_attribute_mode) {
+ v = enter_reverse_mode;
+ } else {
+ v = NULL;
+ }
+ expand_chars = 0;
+ t = buf;
+ if (s) {
+ for (; (ch = *s); s++) {
+ if ((ch & 0x80) && v) { /* print it in reverse video
+ mode */
+ strcpy(t, liberated(tparm(v)));
+ for (; *t; t++);
+ expand_one(ch & 0x7f, &t);
+ strcpy(t, liberated(tparm(exit_attribute_mode)));
+ for (; *t; t++);
+ } else {
+ expand_one(ch, &t);
+ }
+ }
+ }
+ *t = '\0';
+ return buf;
+}
+
+
+char *
+print_expand(char *s)
+{ /* convert the string to 7-bit printable form */
+ static char buf[4096];
+ char *t;
+ int ch;
+
+ expand_chars = 0;
+ t = buf;
+ if (s) {
+ for (; (ch = *s); s++) {
+ expand_one(ch, &t);
+ }
+ }
+ *t = '\0';
+ return buf;
+}
+
+
+char *
+expand_to(char *s, int l)
+{ /* expand s to length l */
+ char *t;
+
+ for (s = t = expand(s); *t; t++);
+ for (; expand_chars < l; expand_chars++) {
+ *t++ = ' ';
+ }
+ *t = '\0';
+ return s;
+}
+
+
+char *
+hex_expand_to(char *s, int l)
+{ /* expand s to length l in hex */
+ static char buf[4096];
+ char *t;
+
+ for (t = buf; *s; s++) {
+ sprintf(t, "%02X ", *s & 0xff);
+ t += 3;
+ if (t - buf > (int) sizeof(buf) - 4) {
+ break;
+ }
+ }
+ for (; t - buf < l;) {
+ *t++ = ' ';
+ }
+ *t = '\0';
+ expand_chars = t - buf;
+ return buf;
+}
+
+
+char *
+expand_command(const char *c)
+{ /* expand an ANSI escape sequence */
+ static char buf[256];
+ int i, j, ch;
+ char *s;
+
+ s = buf;
+ for (i = FALSE; (ch = (*c & 0xff)); c++) {
+ if (i) {
+ *s++ = ' ';
+ }
+ i = TRUE;
+ if (ch < 32) {
+ j = c[1] & 0xff;
+ if (ch == '\033' && j >= '@' && j <= '_') {
+ ch = j - '@';
+ c++;
+ for (j = 0; (*s = c1[ch][j++]); s++);
+ } else
+ for (j = 0; (*s = c0[ch][j++]); s++);
+ } else {
+ *s++ = ch;
+ j = c[1] & 0xff;
+ if (ch >= '0' && ch <= '9' &&
+ j >= '0' && j <= '9') {
+ i = FALSE;
+ }
+ }
+ }
+ *s = '\0';
+ return buf;
+}
+
+/*
+** go_home()
+**
+** Move the cursor to the home position
+*/
+void
+go_home(void)
+{
+ int i;
+
+ if (cursor_home)
+ tt_putp(cursor_home);
+ else if (cursor_address)
+ tt_putparm(cursor_address, lines, 0, 0);
+ else if (row_address) { /* use (vpa) */
+ put_cr();
+ tt_putparm(row_address, 1, 0, 0);
+ } else if (cursor_up && cursor_to_ll) {
+ tt_putp(cursor_to_ll);
+ for (i = 1; i < lines; i++) {
+ tt_putp(cursor_up);
+ }
+ } else {
+ can_go_home = FALSE;
+ return;
+ }
+ char_count = line_count = 0;
+ can_go_home = TRUE;
+}
+
+
+void
+home_down(void)
+{ /* move the cursor to the lower left hand
+ corner */
+ int i;
+
+ if (cursor_to_ll)
+ tt_putp(cursor_to_ll);
+ else if (cursor_address)
+ tt_putparm(cursor_address, lines, lines - 1, 0);
+ else if (row_address) { /* use (vpa) */
+ put_cr();
+ tt_putparm(row_address, 1, lines - 1, 0);
+ } else if (cursor_down && cursor_home) {
+ tt_putp(cursor_home);
+ for (i = 1; i < lines; i++)
+ tt_putp(cursor_down);
+ } else
+ return;
+ char_count = 0;
+ line_count = lines - 1;
+}
+
+
+void
+put_clear(void)
+{ /* clear the screen */
+ int i;
+
+ if (clear_screen)
+ tt_tputs(clear_screen, lines);
+ else if (clr_eos && can_go_home) {
+ go_home();
+ tt_tputs(clr_eos, lines);
+ } else if (scroll_forward && !over_strike && (can_go_home || cursor_up)) {
+ /* clear the screen by scrolling */
+ put_cr();
+ if (cursor_to_ll) {
+ tt_putp(cursor_to_ll);
+ } else if (cursor_address) {
+ tt_putparm(cursor_address, lines, lines - 1, 0);
+ } else if (row_address) {
+ tt_putparm(row_address, 1, lines - 1, 0);
+ } else {
+ for (i = 1; i < lines; i++) {
+ tt_putp(scroll_forward);
+ }
+ }
+ for (i = 1; i < lines; i++) {
+ tt_putp(scroll_forward);
+ }
+ if (can_go_home) {
+ go_home();
+ } else {
+ for (i = 1; i < lines; i++) {
+ tt_putp(cursor_up);
+ }
+ }
+ } else {
+ can_clear_screen = FALSE;
+ return;
+ }
+ char_count = line_count = 0;
+ can_clear_screen = TRUE;
+}
+
+/*
+** wait_here()
+**
+** read one character from the input stream
+** If the terminal is not in RAW mode then this function will
+** wait for a <cr> or <lf>.
+*/
+int
+wait_here(void)
+{
+ char ch, cc[64];
+ char message[16];
+ int i, j;
+
+ for (i = 0; i < (int) sizeof(cc); i++) {
+ cc[i] = ch = getchp(STRIP_PARITY);
+ if (ch == '\r' || ch == '\n') {
+ put_crlf();
+ char_sent = 0;
+ return cc[i ? i - 1 : 0];
+ }
+ if (ch >= ' ') {
+ if (stty_query(TTY_CHAR_MODE)) {
+ put_crlf();
+ char_sent = 0;
+ return ch;
+ }
+ continue;
+ }
+ if (ch == 023) { /* Control S */
+ /* ignore control S, but tell me about it */
+ while (ch == 023 || ch == 021) {
+ ch = getchp(STRIP_PARITY);
+ if (i < (int) sizeof(cc))
+ cc[++i] = ch;
+ }
+ put_str("\nThe terminal sent a ^S -");
+ for (j = 0; j <= i; j++) {
+ sprintf(message, " %02X", cc[j] & 0xFF);
+ put_str(message);
+ }
+ put_crlf();
+ i = -1;
+ } else if (ch != 021) { /* Not Control Q */
+ /* could be abort character */
+ spin_flush();
+ if (tty_can_sync == SYNC_TESTED) {
+ (void) tty_sync_error();
+ } else {
+ put_str("\n? ");
+ }
+ }
+ }
+ return '?';
+}
+
+
+/*
+** read_string(buffer, length)
+**
+** Read a string of characters from the input stream.
+*/
+void
+read_string(
+ char *buf,
+ int length)
+{
+ int ch, i;
+
+ for (i = 0; i < length - 1; ) {
+ ch = getchp(STRIP_PARITY);
+ if (ch == '\r' || ch == '\n') {
+ break;
+ }
+ if (ch == '\b' || ch == 127) {
+ if (i) {
+ putchp('\b');
+ putchp(' ');
+ putchp('\b');
+ i--;
+ }
+ } else {
+ buf[i++] = ch;
+ putchp(ch);
+ }
+ }
+ buf[i] = '\0';
+ put_crlf();
+ char_sent = 0;
+}
+
+/*
+** maybe_wait(lines)
+**
+** wait if near the end of the screen, then clear screen
+*/
+void
+maybe_wait(int n)
+{
+ if (line_count + n >= lines) {
+ if (char_sent != 0) {
+ ptext("Go? ");
+ (void) wait_here();
+ }
+ put_clear();
+ } else {
+ put_crlf();
+ }
+}
diff --git a/contrib/ncurses/tack/pad.c b/contrib/ncurses/tack/pad.c
new file mode 100644
index 000000000000..bc6c6933e614
--- /dev/null
+++ b/contrib/ncurses/tack/pad.c
@@ -0,0 +1,1955 @@
+/*
+** Copyright (C) 1991, 1997 Free Software Foundation, Inc.
+**
+** This file is part of TACK.
+**
+** TACK is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2, or (at your option)
+** any later version.
+**
+** TACK is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with TACK; see the file COPYING. If not, write to
+** the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA 02111-1307, USA.
+*/
+
+#include <tack.h>
+
+MODULE_ID("$Id: pad.c,v 1.1 1998/01/10 00:30:27 tom Exp $")
+
+/* test the pad counts on the terminal */
+
+static void pad_standard(struct test_list *, int *, int *);
+static void init_xon_xoff(struct test_list *, int *, int *);
+static void init_cup(struct test_list *, int *, int *);
+static void pad_rmxon(struct test_list *, int *, int *);
+static void pad_home1(struct test_list *, int *, int *);
+static void pad_home2(struct test_list *, int *, int *);
+static void pad_clear(struct test_list *, int *, int *);
+static void pad_ech(struct test_list *, int *, int *);
+static void pad_el1(struct test_list *, int *, int *);
+static void pad_el(struct test_list *, int *, int *);
+static void pad_smdc(struct test_list *, int *, int *);
+static void pad_dch(struct test_list *, int *, int *);
+static void pad_dch1(struct test_list *, int *, int *);
+static void pad_smir(struct test_list *, int *, int *);
+static void pad_ich(struct test_list *, int *, int *);
+static void pad_ich1(struct test_list *, int *, int *);
+static void pad_xch1(struct test_list *, int *, int *);
+static void pad_rep(struct test_list *, int *, int *);
+static void pad_cup(struct test_list *, int *, int *);
+static void pad_hd(struct test_list *, int *, int *);
+static void pad_hu(struct test_list *, int *, int *);
+static void pad_rin(struct test_list *, int *, int *);
+static void pad_il(struct test_list *, int *, int *);
+static void pad_indn(struct test_list *, int *, int *);
+static void pad_dl(struct test_list *, int *, int *);
+static void pad_xl(struct test_list *, int *, int *);
+static void pad_scrc(struct test_list *, int *, int *);
+static void pad_csrind(struct test_list *, int *, int *);
+static void pad_sccsrrc(struct test_list *, int *, int *);
+static void pad_csr_nel(struct test_list *, int *, int *);
+static void pad_csr_cup(struct test_list *, int *, int *);
+static void pad_ht(struct test_list *, int *, int *);
+static void pad_smso(struct test_list *, int *, int *);
+static void pad_smacs(struct test_list *, int *, int *);
+static void pad_crash(struct test_list *, int *, int *);
+
+extern struct test_menu change_pad_menu;
+
+/*
+ Any command found in this list, executed from a "Done" prompt
+ will force the default action to repeat rather than next.
+*/
+const char *pad_repeat_test = {"ep-+<>"};
+
+struct test_list pad_test_list[] = {
+ {0, 0, 0, 0, "e) edit terminfo", 0, &edit_menu},
+ {0, 0, 0, 0, "p) change padding", 0, &change_pad_menu},
+ {0, 0, 0, 0, "@) display statistics about the last test", dump_test_stats, 0},
+ {0, 0, 0, 0, "c) clear screen", menu_clear_screen, 0},
+ {0, 0, 0, 0, "i) send reset and init", menu_reset_init, 0},
+ {0, 0, 0, 0, txt_longer_test_time, longer_test_time, 0},
+ {0, 0, 0, 0, txt_shorter_test_time, shorter_test_time, 0},
+ {0, 0, 0, 0, txt_longer_augment, longer_augment, 0},
+ {0, 0, 0, 0, txt_shorter_augment, shorter_augment, 0},
+ /***
+ Phase 1: Test initialization and reset strings.
+
+ (rs1) (rs2) (rs3) (is1) (is2) (is3) are very difficult to test.
+ They have no defined output. To make matters worse, the cap
+ builder could partition (rs1) (rs2) (rs3) by length, leaving the
+ terminal in some unknown state between (rs1) and (rs2) or between
+ (r2) and (rs3). Some reset strings clear the screen when done.
+
+ We have no control over this. The only thing we can do for
+ certain is to test the pad times by checking for overruns.
+ ***/
+ {MENU_NEXT, 3, "rs1", 0, 0, pad_standard, 0},
+ {MENU_NEXT, 3, "rs2", 0, 0, pad_standard, 0},
+ {MENU_NEXT, 3, "rs3", 0, 0, pad_standard, 0},
+ {MENU_NEXT | MENU_INIT, 0, 0, 0, 0, init_xon_xoff, 0},
+ {MENU_NEXT, 3, "is1", 0, 0, pad_standard, 0},
+ {MENU_NEXT, 3, "is2", 0, 0, pad_standard, 0},
+ {MENU_NEXT, 3, "is3", 0, 0, pad_standard, 0},
+ {MENU_NEXT, 3, "rmxon", "smxon", 0, pad_rmxon, 0},
+ {MENU_NEXT | MENU_INIT, 0, 0, 0, 0, init_cup, 0},
+ /*
+ Phase 2: Test home, screen clears and erases.
+ */
+ {MENU_NEXT, 0, "home", 0, 0, pad_home1, 0},
+ {MENU_NEXT, 0, "home) (nel", 0, 0, pad_home2, 0},
+ {MENU_NEXT | 1, 0, "clear", 0, 0, pad_clear, 0},
+ {MENU_NEXT | MENU_LM1, 0, "ed", 0, 0, pad_clear, 0},
+ {MENU_NEXT | MENU_80c, 0, "ech", 0, 0, pad_ech, 0},
+ {MENU_NEXT | MENU_80c, 0, "el1", "cub1 nel", 0, pad_el1, 0},
+ {MENU_NEXT | MENU_10c, 0, "el", "nel", 0, pad_el, 0},
+ /*
+ Phase 3: Character deletions and insertions
+ */
+ {MENU_NEXT, 0, "smdc) (rmdc", 0, 0, pad_smdc, 0},
+ {MENU_NEXT | MENU_80c, 0, "dch", "smdc rmdc", 0, pad_dch, 0},
+ {MENU_NEXT | MENU_80c, 0, "dch1", "smdc rmdc", 0, pad_dch1, 0},
+ {MENU_NEXT, 0, "smir) (rmir", 0, 0, pad_smir, 0},
+ {MENU_NEXT | MENU_90c, 0, "ich) (ip", "smir rmir", 0, pad_ich, 0},
+ {MENU_NEXT | MENU_90c, 0, "ich1) (ip", "smir rmir", 0, pad_ich1, 0},
+ {MENU_NEXT, 4, "ich1) (dch1", "smir rmir", 0, pad_xch1, 0},
+ {MENU_NEXT | MENU_90c, 0, "rep", 0, 0, pad_rep, 0},
+ /*
+ Phase 4: Test cursor addressing pads.
+ */
+ {MENU_NEXT, 0, "cup", 0, 0, pad_cup, 0},
+ /*
+ Phase 5: Test scrolling and cursor save/restore.
+ */
+ {MENU_NEXT, 0, "hd", 0, 0, pad_hd, 0},
+ {MENU_NEXT, 0, "hu", 0, 0, pad_hu, 0},
+ {MENU_NEXT | MENU_LM1 | 1, 0, "rin", 0, 0, pad_rin, 0},
+ {MENU_NEXT, 0, "ri", 0, 0, pad_rin, 0},
+ {MENU_NEXT | MENU_LM1 | 1, 0, "il", 0, 0, pad_il, 0},
+ {MENU_NEXT, 0, "il1", 0, 0, pad_il, 0},
+ {MENU_NEXT | MENU_LM1 | 1, 0, "indn", 0, 0, pad_indn, 0},
+ {MENU_NEXT, 0, "ind", 0, 0, pad_indn, 0},
+ {MENU_NEXT | MENU_LM1 | 1, 0, "dl", 0, 0, pad_dl, 0},
+ {MENU_NEXT, 0, "dl1", 0, 0, pad_dl, 0},
+ {MENU_NEXT, 0, "il1) (dl1", 0, 0, pad_xl, 0},
+ {MENU_NEXT, 0, "sc) (rc", 0, 0, pad_scrc, 0},
+ {MENU_NEXT | MENU_50l, 0, "csr) (ind", 0, 0, pad_csrind, 0},
+ {MENU_NEXT, 0, "sc) (csr) (rc", 0, 0, pad_sccsrrc, 0},
+ {MENU_NEXT, 0, "csr) (nel", "sc rc", 0, pad_csr_nel, 0},
+ {MENU_NEXT, 0, "csr) (cup", 0, 0, pad_csr_cup, 0},
+ /*
+ Phase 6: Test tabs.
+ */
+ {MENU_NEXT, 0, "ht", 0, 0, pad_ht, 0},
+ /*
+ Phase 7: Test character-set-switch pads.
+ */
+ {MENU_NEXT, 0, "smso) (rmso", 0, 0, pad_smso, 0},
+ {MENU_NEXT, 0, "smacs) (rmacs", 0, 0, pad_smacs, 0},
+ /*
+ Phase 8: Tests for miscellaneous mode-switch pads.
+ */
+ {MENU_NEXT, 3, "flash", 0, 0, pad_standard, 0},
+ {MENU_NEXT, 3, "smkx", 0, 0, pad_standard, 0},
+ {MENU_NEXT, 3, "rmkx", 0, 0, pad_standard, 0},
+ {MENU_NEXT, 3, "smm", 0, 0, pad_standard, 0},
+ {MENU_NEXT, 3, "rmm", 0, 0, pad_standard, 0},
+ /*
+ Phase 9: Test crash-and-burn properties of unpadded (clear).
+ */
+ {0, 0, "clear", "xon", "k) run clear test with no padding", pad_crash, 0},
+ {MENU_LAST, 0, 0, 0, 0, 0, 0}
+};
+
+extern int test_complete; /* counts number of tests completed */
+
+/* globals */
+int hzcc; /* horizontal character count */
+char letter; /* current character being displayed */
+int letter_number; /* points into letters[] */
+int augment, repeats; /* number of characters (or lines) effected */
+char letters[] = "AbCdefghiJklmNopQrStuVwXyZ";
+
+static char every_line[] = "This text should be on every line.";
+static char all_lines[] = "Each char on any line should be the same. ";
+static char above_line[] = "The above lines should be all Xs. ";
+static char no_visual[] = "This loop test has no visual failure indicator. ";
+
+/*
+** pad_standard(test_list, status, ch)
+**
+** Run a single cap pad test.
+*/
+static void
+pad_standard(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ const char *long_name;
+ char *cap;
+ int l = 2, i;
+ char tbuf[128];
+
+ if ((cap = get_string_cap_byname(t->caps_done, &long_name))) {
+ sprintf(tbuf, "(%s) %s, start testing", t->caps_done,
+ long_name);
+ if (skip_pad_test(t, state, ch, tbuf)) {
+ return;
+ }
+ i = 1;
+ pad_test_startup(1);
+ do {
+ if (i >= columns) {
+ page_loop();
+ l++;
+ i = 1;
+ }
+ tt_putp(cap);
+ putchp(letter);
+ i++;
+ } while(still_testing());
+ pad_test_shutdown(t, 0);
+ if (l >= lines) {
+ home_down();
+ } else {
+ put_crlf();
+ }
+ ptextln(no_visual);
+ } else {
+ CAP_NOT_FOUND;
+ /* Note: get_string_cap_byname() always sets long_name */
+ sprintf(temp, "(%s) %s, not present. ", t->caps_done,
+ long_name);
+ ptext(temp);
+ }
+ pad_done_message(t, state, ch);
+}
+
+/*
+** init_xon_xoff(test_list, status, ch)
+**
+** Initialize the xon_xoff values
+*/
+static void
+init_xon_xoff(
+ struct test_list *t GCC_UNUSED,
+ int *state GCC_UNUSED,
+ int *ch GCC_UNUSED)
+{
+ /* the reset strings may dink with the XON/XOFF modes */
+ if (select_xon_xoff == 0 && exit_xon_mode) {
+ tc_putp(exit_xon_mode);
+ }
+ if (select_xon_xoff == 1 && enter_xon_mode) {
+ tc_putp(enter_xon_mode);
+ }
+}
+
+/*
+** pad_rmxon(test_list, status, ch)
+**
+** Test (rmxon) exit XON/XOFF mode
+*/
+static void
+pad_rmxon(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ if (select_xon_xoff == 0 && exit_xon_mode) {
+ pad_standard(t, state, ch);
+ }
+}
+
+/*
+** init_cup(test_list, status, ch)
+**
+** Send the initialization strings for XON/XOFF and (smcup)
+** Stop pad testing if clear screen is missing.
+*/
+static void
+init_cup(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ init_xon_xoff(t, state, ch);
+ if (enter_ca_mode) {
+ tc_putp(enter_ca_mode);
+ }
+ if (!can_clear_screen) {
+ ptext("(clear) clear screen not present,");
+ ptext(" pad processing terminated. ");
+ pad_done_message(t, state, ch);
+ if (*ch == 0 || *ch == 'n' || *ch == 's' || *ch == 'r') {
+ *ch = '?';
+ }
+ return;
+ }
+}
+
+/*
+** pad_home1(test_list, status, ch)
+**
+** Test (home) when (am) is set.
+*/
+static void
+pad_home1(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int j, k;
+
+ if (can_go_home && auto_right_margin) {
+ /*
+ truly brain damaged terminals will fail this test because
+ they cannot accept data at full rate
+ */
+ if (skip_pad_test(t, state, ch, "(home) Home start testing")) {
+ return;
+ }
+ pad_test_startup(1);
+ do {
+ go_home();
+ for (j = 1; j < lines; j++) {
+ for (k = 0; k < columns; k++) {
+ if (k & 0xF) {
+ put_this(letter);
+ } else {
+ put_this('.');
+ }
+ }
+ SLOW_TERMINAL_EXIT;
+ }
+ NEXT_LETTER;
+ } while(still_testing());
+ pad_test_shutdown(t, 0);
+ ptext("All the dots should line up. ");
+ pad_done_message(t, state, ch);
+ put_clear();
+ }
+}
+
+/*
+** pad_home2(test_list, status, ch)
+**
+** Test (home) and (nel). (am) is reset.
+*/
+static void
+pad_home2(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int j, k;
+
+ if (can_go_home) {
+ if (skip_pad_test(t, state, ch,
+ "(home) Home, (nel) newline start testing")) {
+ return;
+ }
+ pad_test_startup(1);
+ do {
+ go_home();
+ for (j = 1; j < lines; j++) {
+ for (k = 2; k < columns; k++) {
+ if (k & 0xF) {
+ put_this(letter);
+ } else {
+ put_this('.');
+ }
+ }
+ put_crlf(); /* this does the (nel) */
+ SLOW_TERMINAL_EXIT;
+ }
+ NEXT_LETTER;
+ } while(still_testing());
+ pad_test_shutdown(t, 0);
+ ptext("All the dots should line up. ");
+ pad_done_message(t, state, ch);
+ put_clear();
+ }
+}
+
+/*
+** pad_clear(test_list, status, ch)
+**
+** Test (clear) and (ed)
+** run the clear screen tests (also clear-to-end-of-screen)
+**
+** 0) full page
+** 1) sparse page
+** 2) short lines
+** 3) one full line
+** 4) one short line
+*/
+static void
+pad_clear(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ const char *end_message = 0;
+ const char *txt;
+ int j, k, is_clear;
+ int clear_select; /* select the test number */
+
+ is_clear = t->flags & 1;
+ clear_select = auto_right_margin ? 0 : 1;
+ if (is_clear) {
+ txt = "(clear) clear-screen start testing";
+ } else {
+ if (!clr_eos) {
+ CAP_NOT_FOUND;
+ ptext("(ed) erase-to-end-of-display, not present. ");
+ pad_done_message(t, state, ch);
+ return;
+ }
+ txt = "(ed) erase-to-end-of-display start testing";
+ }
+ if (skip_pad_test(t, state, ch, txt)) {
+ return;
+ }
+ if (enter_am_mode) {
+ tc_putp(enter_am_mode);
+ clear_select = 0;
+ }
+ for (; clear_select < 5; clear_select++) {
+ if (augment > lines || is_clear || !cursor_address) {
+ augment = lines;
+ } else {
+ if (augment <= 1) {
+ augment = 2;
+ }
+ if (augment < lines) {
+ put_clear();
+ tt_putparm(cursor_address, 1,
+ lines - augment - 1, 0);
+ ptextln("This line should not be erased (ed)");
+ }
+ }
+ repeats = augment;
+ switch (clear_select) {
+ case 0:
+ end_message = "Clear full screen. ";
+ break;
+ case 1:
+ end_message = "Clear sparse screen. ";
+ if (cursor_down) {
+ break;
+ }
+ clear_select++;
+ case 2:
+ end_message = "Clear one character per line. ";
+ if (newline) {
+ break;
+ }
+ clear_select++;
+ case 3:
+ end_message = "Clear one full line. ";
+ break;
+ case 4:
+ end_message = "Clear single short line. ";
+ break;
+ }
+ pad_test_startup(0);
+ do {
+ switch (clear_select) {
+ case 0: /* full screen test */
+ for (j = 1; j < repeats; j++) {
+ for (k = 0; k < columns; k++) {
+ if (k & 0xF) {
+ put_this(letter);
+ } else {
+ put_this('.');
+ }
+ }
+ SLOW_TERMINAL_EXIT;
+ }
+ break;
+ case 1: /* sparse screen test */
+ for (j = columns - repeats; j > 2; j--) {
+ put_this(letter);
+ }
+ for (j = 2; j < repeats; j++) {
+ tt_putp(cursor_down);
+ put_this(letter);
+ }
+ break;
+ case 2: /* short lines */
+ for (j = 2; j < repeats; j++) {
+ put_this(letter);
+ tt_putp(newline);
+ }
+ put_this(letter);
+ break;
+ case 3: /* one full line */
+ for (j = columns - 5; j > 1; j--) {
+ put_this(letter);
+ }
+ break;
+ case 4: /* one short line */
+ put_str("Erase this!");
+ break;
+ }
+ if (is_clear) {
+ put_clear();
+ } else {
+ if (augment == lines) {
+ go_home();
+ } else {
+ tt_putparm(cursor_address, 1,
+ lines - repeats, 0);
+ }
+ tt_tputs(clr_eos, repeats);
+ }
+ NEXT_LETTER;
+ } while(still_testing());
+ pad_test_shutdown(t, 1);
+ ptext(end_message);
+
+ pad_done_message(t, state, ch);
+
+ if (*ch != 0 && *ch != 'n') {
+ return;
+ }
+ }
+}
+
+/*
+** pad_ech(test_list, status, ch)
+**
+** Test (ech) erase characters
+*/
+static void
+pad_ech(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int i, j;
+
+ if (!erase_chars) {
+ CAP_NOT_FOUND;
+ ptext("(ech) Erase-characters, not present. ");
+ pad_done_message(t, state, ch);
+ return;
+ }
+ if (skip_pad_test(t, state, ch,
+ "(ech) Erase-characters start testing")) {
+ return;
+ }
+ if (augment > columns - 2) {
+ augment = columns - 2;
+ }
+ pad_test_startup(1);
+ do {
+ go_home();
+ for (i = 2; i < lines; i++) {
+ for (j = 0; j <= repeats; j++) {
+ putchp(letter);
+ }
+ put_cr();
+ tt_putparm(erase_chars, repeats, repeats, 0);
+ put_crlf();
+ SLOW_TERMINAL_EXIT;
+ }
+ for (i = 1; i <= repeats; i++) {
+ putchp(' ');
+ }
+ putchp(letter);
+ put_crlf();
+ NEXT_LETTER;
+ } while(still_testing());
+ pad_test_shutdown(t, 0);
+ ptext(all_lines);
+ pad_done_message(t, state, ch);
+ put_clear();
+}
+
+/*
+** pad_el1(test_list, status, ch)
+**
+** Test (el1) erase to start of line also (cub1) and (nel)
+*/
+static void
+pad_el1(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int i, j;
+
+ if (!clr_bol) {
+ CAP_NOT_FOUND;
+ ptext("(el1) Erase-to-beginning-of-line, not present. ");
+ pad_done_message(t, state, ch);
+ return;
+ }
+ if (skip_pad_test(t, state, ch,
+ "(el1) Erase-to-beginning-of-line start testing")) {
+ return;
+ }
+ if (augment > columns - 2) {
+ augment = columns - 2;
+ }
+ pad_test_startup(1);
+ do {
+ go_home();
+ for (i = 2; i < lines; i++) {
+ for (j = 0; j <= repeats; j++) {
+ putchp(letter);
+ }
+ tt_putp(cursor_left);
+ tt_putp(cursor_left);
+ tt_tputs(clr_bol, repeats);
+ put_crlf();
+ SLOW_TERMINAL_EXIT;
+ }
+ for (i = 1; i <= repeats; i++) {
+ putchp(' ');
+ }
+ putchp(letter);
+ put_crlf();
+ NEXT_LETTER;
+ } while(still_testing());
+ pad_test_shutdown(t, 0);
+ ptext(all_lines);
+ pad_done_message(t, state, ch);
+ put_clear();
+}
+
+/*
+** pad_el(test_list, status, ch)
+**
+** Test (el) clear to end of line also (nel)
+*/
+static void
+pad_el(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int i, j;
+
+ if (!clr_eol) {
+ CAP_NOT_FOUND;
+ ptext("(el) Clear-to-end-of-line, not present. ");
+ pad_done_message(t, state, ch);
+ return;
+ }
+ if (skip_pad_test(t, state, ch,
+ "(el) Clear-to-end-of-line start testing")) {
+ return;
+ }
+ hzcc = columns * 8 / 10; /* horizontal character count */
+ if (augment > hzcc) {
+ augment = hzcc;
+ }
+ pad_test_startup(1);
+ do {
+ go_home();
+ for (i = 2; i < lines; i++) {
+ for (j = -1; j < augment; j++) {
+ putchp(letter);
+ }
+ put_cr();
+ putchp(letter);
+ tt_putp(clr_eol);
+ put_crlf();
+ SLOW_TERMINAL_EXIT;
+ }
+ putchp(letter);
+ put_crlf();
+ NEXT_LETTER;
+ } while(still_testing());
+ pad_test_shutdown(t, 0);
+ ptext(all_lines);
+ pad_done_message(t, state, ch);
+ put_clear();
+}
+
+/*
+** pad_smdc(test_list, status, ch)
+**
+** Test (smdc) (rmdc) Delete mode
+*/
+static void
+pad_smdc(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int i;
+
+ if (!enter_delete_mode) {
+ CAP_NOT_FOUND;
+ ptext("(smdc) Enter-delete-mode");
+ if (!exit_delete_mode) {
+ ptext(", (rmdc) Exit-delete-mode");
+ }
+ ptext(", not present. ");
+ pad_done_message(t, state, ch);
+ return;
+ }
+ if (skip_pad_test(t, state, ch,
+ "(smdc) (rmdc) Enter/Exit-delete-mode start testing")) {
+ return;
+ }
+ pad_test_startup(1);
+ do {
+ page_loop();
+ for (i = 1; i < columns; i++) {
+ tt_putp(enter_delete_mode);
+ tt_putp(exit_delete_mode);
+ putchp(letter);
+ }
+ } while(still_testing());
+ pad_test_shutdown(t, 0);
+ home_down();
+ ptext(no_visual);
+ pad_done_message(t, state, ch);
+ put_clear();
+}
+
+/*
+** pad_dch(test_list, status, ch)
+**
+** Test (smdc) (rmdc) Delete mode and (dch)
+*/
+static void
+pad_dch(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int i, j;
+
+ if (!parm_dch) {
+ CAP_NOT_FOUND;
+ ptext("(dch) Delete-characters, not present. ");
+ pad_done_message(t, state, ch);
+ return;
+ }
+ if (skip_pad_test(t, state, ch,
+ "(dch) Delete-characters start testing")) {
+ return;
+ }
+ hzcc = columns * 8 / 10; /* horizontal character count */
+ if (augment > hzcc) {
+ augment = hzcc;
+ }
+ pad_test_startup(1);
+ do {
+ go_home();
+ for (i = 2; i < lines; i++) {
+ for (j = 0; j <= repeats; j++) {
+ putchp(letter);
+ }
+ put_cr();
+ tt_putp(enter_delete_mode);
+ tt_putparm(parm_dch, repeats, repeats, 0);
+ tt_putp(exit_delete_mode);
+ put_crlf();
+ SLOW_TERMINAL_EXIT;
+ }
+ putchp(letter);
+ put_crlf();
+ NEXT_LETTER;
+ } while(still_testing());
+ pad_test_shutdown(t, 0);
+ home_down();
+ ptext(all_lines);
+ pad_done_message(t, state, ch);
+ put_clear();
+}
+
+/*
+** pad_dch1(test_list, status, ch)
+**
+** Test (smdc) (rmdc) Delete mode and (dch1)
+*/
+static void
+pad_dch1(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int i, j;
+
+ if (!delete_character) {
+ if (parm_dch) {
+ /* if the other one is defined then its OK */
+ return;
+ }
+ CAP_NOT_FOUND;
+ ptext("(dch1) Delete-character, not present. ");
+ pad_done_message(t, state, ch);
+ return;
+ }
+ if (skip_pad_test(t, state, ch,
+ "(dch1) Delete-character start testing")) {
+ return;
+ }
+ hzcc = columns * 8 / 10; /* horizontal character count */
+ if (augment > hzcc) {
+ augment = hzcc;
+ }
+ pad_test_startup(1);
+ do {
+ go_home();
+ for (i = 2; i < lines; i++) {
+ for (j = -1; j < augment; j++) {
+ putchp(letter);
+ }
+ put_cr();
+ tt_putp(enter_delete_mode);
+ for (j = 0; j < augment; j++) {
+ tt_putp(delete_character);
+ }
+ tt_putp(exit_delete_mode);
+ put_crlf();
+ SLOW_TERMINAL_EXIT;
+ }
+ putchp(letter);
+ put_crlf();
+ NEXT_LETTER;
+ } while(still_testing());
+ pad_test_shutdown(t, 0);
+ ptext(all_lines);
+ pad_done_message(t, state, ch);
+ put_clear();
+}
+
+/*
+** pad_smir(test_list, status, ch)
+**
+** Test (smir) (rmir) Insert mode
+*/
+static void
+pad_smir(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int i;
+
+ if (!enter_insert_mode) {
+ CAP_NOT_FOUND;
+ ptext("(smir) Enter-insert-mode");
+ if (!exit_insert_mode) {
+ ptext(", (rmir) Exit-insert-mode");
+ }
+ ptext(", not present. ");
+ pad_done_message(t, state, ch);
+ return;
+ }
+ if (skip_pad_test(t, state, ch,
+ "(smir) (rmir) Enter/Exit-insert-mode start testing")) {
+ return;
+ }
+ pad_test_startup(1);
+ do {
+ page_loop();
+ for (i = 1; i < columns; i++) {
+ tt_putp(enter_insert_mode);
+ tt_putp(exit_insert_mode);
+ putchp(letter);
+ }
+ } while(still_testing());
+ pad_test_shutdown(t, 0);
+ home_down();
+ ptext(no_visual);
+ pad_done_message(t, state, ch);
+ put_clear();
+}
+
+/*
+** pad_ich(test_list, status, ch)
+**
+** Test (smir) (rmir) Insert mode and (ich) and (ip)
+*/
+static void
+pad_ich(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int i, j;
+
+ if (!parm_ich) {
+ CAP_NOT_FOUND;
+ ptext("(ich) Insert-characters, not present. ");
+ pad_done_message(t, state, ch);
+ return;
+ }
+ if (skip_pad_test(t, state, ch,
+ "(ich) Insert-characters, (ip) Insert-padding start testing")) {
+ return;
+ }
+ j = columns * 9 / 10;
+ if (augment > j) {
+ augment = j;
+ }
+ pad_test_startup(1);
+ do {
+ go_home();
+ for (i = 2; i < lines; i++) {
+ putchp(letter);
+ put_cr();
+ tt_putp(enter_insert_mode);
+ replace_mode = 0;
+ tt_putparm(parm_ich, repeats, repeats, 0);
+ tt_putp(exit_insert_mode);
+ replace_mode = 1;
+ put_crlf();
+ SLOW_TERMINAL_EXIT;
+ }
+ for (i = 0; i < repeats; i++) {
+ putchp(' ');
+ }
+ putchp(letter);
+ NEXT_LETTER;
+ put_crlf();
+ } while(still_testing());
+ pad_test_shutdown(t, 0);
+ ptext(all_lines);
+ pad_done_message(t, state, ch);
+ tc_putp(exit_insert_mode);
+}
+
+/*
+** pad_ich1(test_list, status, ch)
+**
+** Test (smir) (rmir) Insert mode and (ich1) and (ip)
+*/
+static void
+pad_ich1(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int i, j;
+
+ if (!insert_character) {
+ CAP_NOT_FOUND;
+ ptext("(ich1) Insert-character, not present. ");
+ pad_done_message(t, state, ch);
+ return;
+ }
+ if (skip_pad_test(t, state, ch,
+ "(ich1) Insert-character, (ip) Insert-padding start testing")) {
+ return;
+ }
+ if (augment > columns - 2) {
+ augment = columns - 2;
+ }
+ pad_test_startup(1);
+ do {
+ put_clear();
+ for (i = 2; i < lines; i++) {
+ putchp(letter);
+ put_cr();
+ tt_putp(enter_insert_mode);
+ replace_mode = 0;
+ if (!insert_padding && !insert_character) {
+ /* only enter/exit is needed */
+ for (j = 0; j < augment; j++) {
+ putchp('.');
+ }
+ } else {
+ for (j = 0; j < augment; j++) {
+ tt_putp(insert_character);
+ putchp('.');
+ tt_putp(insert_padding);
+ }
+ }
+ tt_putp(exit_insert_mode);
+ replace_mode = 1;
+ put_crlf();
+ SLOW_TERMINAL_EXIT;
+ }
+ for (j = 0; j < augment; j++) {
+ putchp('.');
+ }
+ putchp(letter);
+ NEXT_LETTER;
+ put_crlf();
+ } while(still_testing());
+ pad_test_shutdown(t, 0);
+ ptext(all_lines);
+ pad_done_message(t, state, ch);
+ tc_putp(exit_insert_mode);
+}
+
+/*
+** pad_xch1(test_list, status, ch)
+**
+** Test (ich1) (ip) (dch1)
+*/
+static void
+pad_xch1(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ static char xch1[] =
+ "This line should not be garbled. It should be left justified.";
+
+ if (enter_insert_mode || exit_insert_mode ||
+ enter_delete_mode || exit_delete_mode ||
+ !insert_character || !delete_character) {
+ /* this test is quitely ignored */
+ return;
+ }
+ if (skip_pad_test(t, state, ch,
+ "(ich1) Insert-character, (dch1) Delete-character start testing")) {
+ return;
+ }
+ put_crlf();
+ ptext(xch1);
+ put_cr();
+ pad_test_startup(0);
+ do {
+ tt_putp(insert_character);
+ tt_putp(delete_character);
+ } while(still_testing());
+ pad_test_shutdown(t, 1);
+ ptextln(xch1);
+ ptext("The preceeding two lines should be the same. ");
+ pad_done_message(t, state, ch);
+}
+
+/*
+** pad_rep(test_list, status, ch)
+**
+** Test (rep) repeat character
+*/
+static void
+pad_rep(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int i, j;
+
+ if (!repeat_char) {
+ CAP_NOT_FOUND;
+ ptext("(rep) Repeat-character, not present. ");
+ pad_done_message(t, state, ch);
+ return;
+ }
+ if (skip_pad_test(t, state, ch,
+ "(rep) Repeat-character start testing")) {
+ return;
+ }
+ if (augment > columns - 2) {
+ augment = columns - 2;
+ }
+ if (augment < 2) {
+ augment = 2;
+ }
+ pad_test_startup(1);
+ do {
+ go_home();
+ for (i = 2; i < lines; i++) {
+ tt_putparm(repeat_char, repeats, letter, repeats);
+ put_crlf();
+ }
+ for (j = 0; j < repeats; j++) {
+ putchp(letter);
+ }
+ put_crlf();
+ NEXT_LETTER;
+ } while(still_testing());
+ pad_test_shutdown(t, 0);
+ ptextln(all_lines);
+ pad_done_message(t, state, ch);
+}
+
+/*
+** pad_cup(test_list, status, ch)
+**
+** Test (cup) Cursor address
+*/
+static void
+pad_cup(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int i, j, l, r, c;
+
+ if (!cursor_address) {
+ CAP_NOT_FOUND;
+ ptext("(cup) Cursor-address not present. ");
+ pad_done_message(t, state, ch);
+ return;
+ }
+ if (skip_pad_test(t, state, ch,
+ "(cup) Cursor-address start testing")) {
+ return;
+ }
+ put_clear();
+ ptext("Each line should be filled with the same letter. There should");
+ ptext(" be no gaps, or single letters scattered over the screen. ");
+ if (char_count + 15 > columns) {
+ put_crlf();
+ }
+ if (((lines - line_count) & 1) == 0) {
+ /* this removes the gap in the middle of the test when the
+ number of lines is odd. */
+ put_crlf();
+ }
+ r = line_count;
+ c = char_count;
+ l = (columns - 4) >> 1;
+ pad_test_startup(0);
+ do {
+ for (i = 1; i + i + r < lines; i++) {
+ for (j = 0; j <= l; j++) {
+ tt_putparm(cursor_address, 1, r + i, j);
+ putchp(letter);
+ tt_putparm(cursor_address, 1, r + i, l + l + 1 - j);
+ putchp(letter);
+ tt_putparm(cursor_address, 1, lines - i, j);
+ putchp(letter);
+ tt_putparm(cursor_address, 1, lines - i, l + l + 1 - j);
+ putchp(letter);
+ }
+ SLOW_TERMINAL_EXIT;
+ }
+ NEXT_LETTER;
+ } while(still_testing());
+ pad_test_shutdown(t, 0);
+ tt_putparm(cursor_address, 1, line_count = r, char_count = c);
+ pad_done_message(t, state, ch);
+ put_clear();
+}
+
+/*
+** pad_hd(test_list, status, ch)
+**
+** Test (hd) Half down
+*/
+static void
+pad_hd(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int i, j, k;
+
+ if (!down_half_line) {
+ CAP_NOT_FOUND;
+ ptext("(hd) Half-line-down not present. ");
+ pad_done_message(t, state, ch);
+ return;
+ }
+ if (skip_pad_test(t, state, ch,
+ "(hd) Half-line-down start testing")) {
+ return;
+ }
+ pad_test_startup(1);
+ do {
+ for (i = 1; i < columns; i += 2) {
+ for (j = 1; j < i; ++j) {
+ putchp(' ');
+ }
+ tt_putp(down_half_line);
+ for (k = lines + lines; k > 4; k--) {
+ if (j++ >= columns) {
+ break;
+ }
+ tt_putp(down_half_line);
+ putchp(letter);
+ }
+ go_home();
+ SLOW_TERMINAL_EXIT;
+ }
+ NEXT_LETTER;
+ } while(still_testing());
+ pad_test_shutdown(t, 0);
+ pad_done_message(t, state, ch);
+ put_clear();
+}
+
+/*
+** pad_hu(test_list, status, ch)
+**
+** Test (hu) Half line up
+*/
+static void
+pad_hu(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int i, j, k;
+
+ if (!up_half_line) {
+ CAP_NOT_FOUND;
+ ptext("(hu) Half-line-up not present. ");
+ pad_done_message(t, state, ch);
+ return;
+ }
+ if (skip_pad_test(t, state, ch,
+ "(hu) Half-line-up start testing")) {
+ return;
+ }
+ pad_test_startup(1);
+ do {
+ for (i = 1; i < columns; i += 2) {
+ home_down();
+ for (j = 1; j < i; ++j) {
+ putchp(' ');
+ }
+ tt_putp(up_half_line);
+ for (k = lines + lines; k > 4; k--) {
+ if (j++ >= columns) {
+ break;
+ }
+ tt_putp(up_half_line);
+ putchp(letter);
+ }
+ SLOW_TERMINAL_EXIT;
+ }
+ go_home();
+ NEXT_LETTER;
+ } while(still_testing());
+ pad_test_shutdown(t, 0);
+ pad_done_message(t, state, ch);
+ put_clear();
+}
+
+/*
+** pad_rin(test_list, status, ch)
+**
+** Test (rin) and (ri) Reverse index
+*/
+static void
+pad_rin(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int i;
+ const char *start_message;
+
+ if (t->flags & 1) {
+ /* rin */
+ if (!parm_rindex) {
+ CAP_NOT_FOUND;
+ ptext("(rin) Scroll-reverse-n-lines not present. ");
+ pad_done_message(t, state, ch);
+ return;
+ }
+ start_message = "(rin) Scroll-reverse-n-lines start testing";
+ } else {
+ /* ri */
+ if (!scroll_reverse) {
+ CAP_NOT_FOUND;
+ ptext("(ri) Scroll-reverse not present. ");
+ pad_done_message(t, state, ch);
+ return;
+ }
+ start_message = "(ri) Scroll-reverse start testing";
+ augment = 1;
+ }
+ if (skip_pad_test(t, state, ch, start_message)) {
+ return;
+ }
+ pad_test_startup(1);
+ do {
+ sprintf(temp, "%d\r", test_complete);
+ put_str(temp);
+ if (scroll_reverse && augment == 1) {
+ tt_putp(scroll_reverse);
+ } else {
+ tt_putparm(parm_rindex, repeats, repeats, 0);
+ }
+ } while(still_testing());
+ put_str("This line should be on the bottom.\r");
+ if (scroll_reverse && augment == 1) {
+ for (i = 1; i < lines; i++) {
+ tt_putp(scroll_reverse);
+ }
+ } else {
+ tt_putparm(parm_rindex, lines - 1, lines - 1, 0);
+ }
+ putln("The screen should have text on the bottom line.");
+ sprintf(temp, "Scroll reverse %d line%s. ", augment,
+ augment == 1 ? "" : "s");
+ put_str(temp);
+ pad_test_shutdown(t, 0);
+ pad_done_message(t, state, ch);
+ put_clear();
+}
+
+/*
+** pad_il(test_list, status, ch)
+**
+** Test (il) and (il1) Insert line
+*/
+static void
+pad_il(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int i;
+ const char *start_message;
+
+ if (t->flags & 1) {
+ /* il */
+ if (!parm_insert_line) {
+ CAP_NOT_FOUND;
+ ptext("(il) Insert-lines not present. ");
+ pad_done_message(t, state, ch);
+ return;
+ }
+ start_message = "(il) Insert-lines start testing";
+ } else {
+ /* il1 */
+ if (!insert_line) {
+ CAP_NOT_FOUND;
+ ptext("(il1) Insert-line not present. ");
+ pad_done_message(t, state, ch);
+ return;
+ }
+ start_message = "(il1) Insert-line start testing";
+ augment = 1;
+ }
+ if (skip_pad_test(t, state, ch, start_message)) {
+ return;
+ }
+ pad_test_startup(1);
+ do {
+ sprintf(temp, "%d\r", test_complete);
+ put_str(temp);
+ if (insert_line && repeats == 1) {
+ tt_putp(insert_line);
+ } else {
+ tt_putparm(parm_insert_line, repeats, repeats, 0);
+ }
+ } while(still_testing());
+ put_str("This line should be on the bottom.\r");
+ if (scroll_reverse && augment == 1) {
+ for (i = 1; i < lines; i++) {
+ tt_putp(insert_line);
+ }
+ } else {
+ tt_putparm(parm_insert_line, lines - 1, lines - 1, 0);
+ }
+ putln("The screen should have text on the bottom line.");
+ sprintf(temp, "Insert %d line%s. ", augment,
+ augment == 1 ? "" : "s");
+ put_str(temp);
+ pad_test_shutdown(t, 0);
+ pad_done_message(t, state, ch);
+ put_clear();
+}
+
+/*
+** pad_indn(test_list, status, ch)
+**
+** Test (indn) and (ind) Scroll forward
+*/
+static void
+pad_indn(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int i;
+ const char *start_message;
+
+ if (t->flags & 1) {
+ /* indn */
+ if (!parm_index) {
+ CAP_NOT_FOUND;
+ ptext("(indn) Scroll-forward-n-lines not present. ");
+ pad_done_message(t, state, ch);
+ return;
+ }
+ start_message = "(indn) Scroll-forward-n-lines start testing";
+ } else {
+ /* ind */
+ if (!scroll_forward && over_strike) {
+ CAP_NOT_FOUND;
+ ptext("(ind) Scroll-forward not tested on overstrike terminals. ");
+ pad_done_message(t, state, ch);
+ return;
+ }
+ start_message = "(ind) Scroll-forward start testing";
+ augment = 1;
+ }
+ if (skip_pad_test(t, state, ch, start_message)) {
+ return;
+ }
+ pad_test_startup(1);
+ /* go to the bottom of the screen */
+ home_down();
+ do {
+ sprintf(temp, "%d\r", test_complete);
+ put_str(temp);
+ if (augment > 1) {
+ tt_putparm(parm_index, repeats, repeats, 0);
+ } else {
+ put_ind();
+ }
+ } while(still_testing());
+ put_str("This line should be on the top.\r");
+ if (augment == 1) {
+ for (i = 1; i < lines; i++) {
+ put_ind();
+ }
+ } else {
+ tt_putparm(parm_index, lines - 1, lines - 1, 0);
+ }
+ go_home();
+ sprintf(temp, "\nScroll forward %d line%s. ", augment,
+ augment == 1 ? "" : "s");
+ put_str(temp);
+ pad_test_shutdown(t, 0);
+ pad_done_message(t, state, ch);
+}
+
+/*
+** pad_dl(test_list, status, ch)
+**
+** Test (dl) and (dl1) Delete lines
+*/
+static void
+pad_dl(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int i = 0;
+ const char *start_message;
+
+ if (t->flags & 1) {
+ /* dl */
+ if (!parm_delete_line) {
+ CAP_NOT_FOUND;
+ ptext("(dl) Delete-lines not present. ");
+ pad_done_message(t, state, ch);
+ return;
+ }
+ start_message = "(dl) Delete-lines start testing";
+ } else {
+ /* dl1 */
+ if (!delete_line) {
+ CAP_NOT_FOUND;
+ ptext("(dl1) Delete-line not present. ");
+ pad_done_message(t, state, ch);
+ return;
+ }
+ start_message = "(dl1) Delete-line start testing";
+ augment = 1;
+ }
+ if (skip_pad_test(t, state, ch, start_message)) {
+ return;
+ }
+ pad_test_startup(1);
+ do {
+ sprintf(temp, "%d\r", test_complete);
+ if ((i & 0x7f) == 0 && augment < lines - 1) {
+ go_home();
+ putln(temp);
+ }
+ put_str(temp);
+ if (repeats || !delete_line) {
+ tt_putparm(parm_delete_line, repeats, repeats, 0);
+ } else {
+ tt_putp(delete_line);
+ }
+ } while(still_testing());
+ home_down();
+ put_str("This line should be on the top.");
+ go_home();
+ if (repeats || !delete_line) {
+ tt_putparm(parm_delete_line, lines - 1, lines - 1, 0);
+ } else {
+ for (i = 1; i < lines; i++) {
+ tt_putp(delete_line);
+ }
+ }
+ sprintf(temp, "\nDelete %d line%s. ", augment,
+ augment == 1 ? "" : "s");
+ put_str(temp);
+ pad_test_shutdown(t, 0);
+ pad_done_message(t, state, ch);
+}
+
+/*
+** pad_xl(test_list, status, ch)
+**
+** Test (il1) Insert and (dl1) Delete lines
+*/
+static void
+pad_xl(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ if (!insert_line && !delete_line) {
+ /* quietly skip this test */
+ return;
+ }
+ if (skip_pad_test(t, state, ch,
+ "(il1) Insert-line, (dl1) Delete-line start testing")) {
+ return;
+ }
+ put_clear();
+ putln("\rThis text is written on the first line.");
+ ptext("This sentence begins on the second line. As this");
+ ptext(" test runs the bottom part of this paragraph will");
+ ptext(" jump up and down. Don't worry, that's normal. When");
+ ptext(" the jumping stops, the entire paragraph should");
+ ptext(" still be on the screen and in the same place as when");
+ ptext(" the test started. If this paragraph has scrolled");
+ ptext(" off the top or bottom of the screen then the test");
+ ptext(" has failed. Scrolling off the top of the screen");
+ ptext(" usually means that the delete line capability is");
+ ptext(" working better than the insert line capability. If");
+ ptext(" the text scrolls off the bottom then delete line may");
+ ptext(" be broken. If parts of the text are missing then");
+ ptext(" you should get professional help.");
+ put_crlf();
+ go_home();
+ put_newlines(2);
+ pad_test_startup(0);
+ do {
+ tt_putp(insert_line);
+ put_cr();
+ tt_putp(delete_line);
+ } while(still_testing());
+ pad_test_shutdown(t, 0);
+ home_down();
+ ptext("The top of the screen should have a paragraph of text. ");
+ pad_done_message(t, state, ch);
+}
+
+/*
+** pad_scrc(test_list, status, ch)
+**
+** Test (sc) (rc) Save/restore cursor
+*/
+static void
+pad_scrc(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int i;
+
+ if (!save_cursor || !restore_cursor) {
+ CAP_NOT_FOUND;
+ if (save_cursor) {
+ ptext("(rc) Restore-cursor");
+ } else
+ if (restore_cursor) {
+ ptext("(sc) Save-cursor");
+ } else {
+ ptext("(sc) Save-cursor, (rc) Restore-cursor");
+ }
+ ptext(" not present. ");
+ pad_done_message(t, state, ch);
+ return;
+ }
+ if (skip_pad_test(t, state, ch,
+ "(sc) (rc) Save/Restore-cursor start testing")) {
+ return;
+ }
+ pad_test_startup(1);
+ do {
+ page_loop();
+ for (i = 1; i < columns; i++) {
+ tt_putp(save_cursor);
+ putchp(letter);
+ tt_putp(restore_cursor);
+ putchp('X');
+ }
+ } while(still_testing());
+ pad_test_shutdown(t, 0);
+ home_down();
+ ptext(above_line);
+ pad_done_message(t, state, ch);
+}
+
+/*
+** pad_csrind(test_list, status, ch)
+**
+** Test (csr) and (ind) Change scroll region and index.
+*/
+static void
+pad_csrind(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int i;
+
+ if (!change_scroll_region) {
+ CAP_NOT_FOUND;
+ ptext("(csr) Change-scroll-region not present. ");
+ pad_done_message(t, state, ch);
+ return;
+ }
+ if (skip_pad_test(t, state, ch,
+ "(csr) Save/Restore-cursor, (ind) index start testing")) {
+ return;
+ }
+ if (augment < 2) {
+ augment = 2;
+ }
+ if (augment > lines - 1) {
+ augment = lines - 1;
+ }
+ put_clear();
+ ptext("This text is on the top line.");
+ tt_putparm(change_scroll_region, 1, lines - augment, lines - 1);
+ /* go to the bottom of the screen */
+ home_down();
+ pad_test_startup(0);
+ do {
+ sprintf(temp, "%d\r", test_complete);
+ put_str(temp);
+ put_ind();
+ } while(still_testing());
+ ptextln("(csr) is broken.");
+ for (i = augment; i > 1; i--) {
+ put_ind();
+ }
+ pad_test_shutdown(t, 0);
+ ptext("All but top and bottom lines should be blank. ");
+ pad_done_message(t, state, ch);
+ tt_putparm(change_scroll_region, 1, 0, lines - 1);
+ put_clear();
+}
+
+/*
+** pad_sccsrrc(test_list, status, ch)
+**
+** Test (sc) (csr) and (rc) Save/Change/Restore scroll region
+*/
+static void
+pad_sccsrrc(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int i;
+
+ if (!save_cursor || !change_scroll_region || !restore_cursor) {
+ /* quietly ignore this test */
+ return;
+ }
+ if (skip_pad_test(t, state, ch,
+ "(sc) (csr) (rc) Save/Change/Restore-cursor, start testing")) {
+ return;
+ }
+ pad_test_startup(1);
+ do {
+ page_loop();
+ for (i = 1; i < columns; i++) {
+ tt_putp(save_cursor);
+ putchp(letter);
+ tt_putparm(change_scroll_region, 1, 0, lines - 1);
+ tt_putp(restore_cursor);
+ putchp('X');
+ }
+ } while(still_testing());
+ pad_test_shutdown(t, 0);
+ home_down();
+ ptext(above_line);
+ pad_done_message(t, state, ch);
+ tt_putparm(change_scroll_region, 1, 0, lines - 1);
+}
+
+/*
+** pad_csr_nel(test_list, status, ch)
+**
+** Test (sc) (csr) (nel) and (rc) Save/Change/Restore scroll region
+*/
+static void
+pad_csr_nel(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int i, j;
+
+ if (!save_cursor || !change_scroll_region || !restore_cursor) {
+ /* quietly ignore this test */
+ return;
+ }
+ if (skip_pad_test(t, state, ch,
+ "(csr) Change-scroll-region, (nel) newline start testing")) {
+ return;
+ }
+ pad_test_startup(1);
+ do {
+ for (i = 0; i < lines; i++) {
+ for (j = lines - i; j > 0; j--) {
+ put_crlf();
+ }
+ tt_putp(save_cursor);
+ tt_putparm(change_scroll_region, 1, i, lines - 1);
+ tt_putp(restore_cursor);
+ put_str(every_line);
+ }
+ tt_putp(save_cursor);
+ tt_putparm(change_scroll_region, 1, 0, lines - 1);
+ tt_putp(restore_cursor);
+ } while(still_testing());
+ pad_test_shutdown(t, 0);
+ put_str(" ");
+ pad_done_message(t, state, ch);
+ tt_putparm(change_scroll_region, 1, 0, lines - 1);
+}
+
+/*
+** pad_csr_cup(test_list, status, ch)
+**
+** Test (csr) (cup) Change scroll region and cursor address
+*/
+static void
+pad_csr_cup(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int i, j;
+
+ if (!change_scroll_region || !cursor_address) {
+ /* quietly ignore this test */
+ return;
+ }
+ if (skip_pad_test(t, state, ch,
+ "(csr) Change-scroll-region, (cup) cursor-address start testing")) {
+ return;
+ }
+ pad_test_startup(1);
+ do {
+ for (i = 0; i < lines; i++) {
+ for (j = lines - i; j > 0; j--) {
+ put_crlf();
+ }
+ tt_putparm(change_scroll_region, 1, i, lines - 1);
+ tt_putparm(cursor_address, 1, lines - 1, 0);
+ put_str(every_line);
+ }
+ tt_putparm(change_scroll_region, 1, 0, lines - 1);
+ tt_putparm(cursor_address, 1, lines - 1, strlen(every_line));
+ } while(still_testing());
+ pad_test_shutdown(t, 0);
+ put_str(" ");
+ pad_done_message(t, state, ch);
+ tt_putparm(change_scroll_region, 1, 0, lines - 1);
+}
+
+/*
+** pad_ht(test_list, status, ch)
+**
+** Test (ht) Tabs
+*/
+static void
+pad_ht(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int i, j;
+
+ if (!set_tab && init_tabs <= 0) {
+ CAP_NOT_FOUND;
+ ptext("(ht) Tab not tested. (hts) Set-tabs and (it) initial-tabs not present. ");
+ pad_done_message(t, state, ch);
+ return;
+ }
+ if (skip_pad_test(t, state, ch, "(ht) Tab start testing")) {
+ return;
+ }
+ pad_test_startup(1);
+ do {
+ /*
+ it is not always possible to test tabs with caps
+ that do not already have padding. The following
+ test uses a mixed bag of tests in order to avoid
+ this problem. Note: I do not scroll
+ */
+ if (auto_right_margin && can_go_home)
+ for (i = 1, go_home(); i < lines - 2; i++) {
+ for (j = 8; j < columns; j += 8) {
+ putchp('\t');
+ }
+ put_str("A ");
+ }
+ if (cursor_down && can_go_home)
+ for (i = 1, go_home(); i < lines - 2; i++) {
+ for (j = 8; j < columns; j += 8) {
+ putchp('\t');
+ }
+ put_str("D\r");
+ tt_putp(cursor_down);
+ }
+ if (cursor_address)
+ for (i = 1; i < lines - 2; i++) {
+ tt_putparm(cursor_address, 1, i - 1, 0);
+ for (j = 8; j < columns; j += 8) {
+ putchp('\t');
+ }
+ put_str("C");
+ }
+ go_home();
+ for (i = 1; i < lines - 2; i++) {
+ for (j = 8; j < columns; j += 8) {
+ putchp('\t');
+ }
+ putln("N");
+ }
+ } while(still_testing());
+ pad_test_shutdown(t, 0);
+ ptextln("Letters on the screen other than Ns at the right margin indicate failure.");
+ ptext("A-(am) D-(cud1) C-(cup) N-(nel) ");
+ pad_done_message(t, state, ch);
+}
+
+/*
+** pad_smso(test_list, status, ch)
+**
+** Test (smso) (rmso) Enter/exit mode
+*/
+static void
+pad_smso(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int i, j;
+
+ if (!enter_standout_mode || !exit_standout_mode) {
+ CAP_NOT_FOUND;
+ ptext("(smso) (rmso) Enter/Exit-standout-mode not present. ");
+ pad_done_message(t, state, ch);
+ return;
+ }
+ if (skip_pad_test(t, state, ch,
+ "(smso) (rmso) Enter/Exit-standout-mode start testing")) {
+ return;
+ }
+ /*
+ In terminals that emulate non-hidden attributes with hidden
+ attributes, the amount of time that it takes to fill the screen
+ with an attribute is nontrivial. The following test is designed to
+ catch those delays
+ */
+ pad_test_startup(1);
+ do {
+ page_loop();
+ j = magic_cookie_glitch > 0 ? magic_cookie_glitch : 0;
+ for (i = 2 + j + j; i < columns;) {
+ put_mode(enter_standout_mode);
+ i += j + j + 2;
+ putchp('X');
+ put_mode(exit_standout_mode);
+ putchp('X');
+ }
+ } while(still_testing());
+ pad_test_shutdown(t, 0);
+ home_down();
+ ptext(above_line);
+ pad_done_message(t, state, ch);
+ put_mode(exit_standout_mode);
+}
+
+/*
+** pad_smacs(test_list, status, ch)
+**
+** Test (smacs) (rmacs) Enter/exit altcharset mode
+*/
+static void
+pad_smacs(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int i, j;
+
+ /* test enter even if exit is missing */
+ if (!enter_alt_charset_mode) {
+ CAP_NOT_FOUND;
+ ptext("(smacs) Enter-altcharset-mode not present. ");
+ pad_done_message(t, state, ch);
+ return;
+ }
+ if (skip_pad_test(t, state, ch,
+ "(smacs) (rmacs) Enter/Exit-altcharset-mode start testing")) {
+ return;
+ }
+ pad_test_startup(1);
+ do {
+ page_loop();
+ j = magic_cookie_glitch > 0 ? magic_cookie_glitch : 0;
+ for (i = 2 + j + j; i < columns;) {
+ put_mode(enter_alt_charset_mode);
+ i += j + j + 2;
+ putchp(letter);
+ put_mode(exit_alt_charset_mode);
+ putchp(letter);
+ }
+ } while(still_testing());
+ pad_test_shutdown(t, 0);
+ home_down();
+ ptext("Every other character is from the alternate character set. ");
+ pad_done_message(t, state, ch);
+ put_mode(exit_alt_charset_mode);
+}
+
+/*
+** pad_crash(test_list, status, ch)
+**
+** Test (clear) without padding
+*/
+static void
+pad_crash(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int save_xon_xoff;
+
+ if (!clear_screen) {
+ ptext("(clear) Clear-screen not present. ");
+ pad_done_message(t, state, ch);
+ return;
+ }
+ ptext("If you would like to see if the terminal will really lock up.");
+ ptextln(" I will send the clear screen sequence without the pads.");
+ if (skip_pad_test(t, state, ch,
+ "(clear) Clear-screen start crash testing")) {
+ return;
+ }
+ save_xon_xoff = xon_xoff;
+ xon_xoff = 1;
+ pad_test_startup(0);
+ do {
+ put_str("Erase this!");
+ tt_putp(clear_screen);
+ } while(still_testing());
+ xon_xoff = save_xon_xoff;
+ pad_test_shutdown(t, 1);
+ pad_done_message(t, state, ch);
+}
diff --git a/contrib/ncurses/tack/scan.c b/contrib/ncurses/tack/scan.c
new file mode 100644
index 000000000000..d9429c96ee5a
--- /dev/null
+++ b/contrib/ncurses/tack/scan.c
@@ -0,0 +1,261 @@
+/*
+** Copyright (C) 1991, 1997 Free Software Foundation, Inc.
+**
+** This file is part of TACK.
+**
+** TACK is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2, or (at your option)
+** any later version.
+**
+** TACK is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with TACK; see the file COPYING. If not, write to
+** the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA 02111-1307, USA.
+*/
+/* scan mode keyboard support */
+
+#include <tack.h>
+
+MODULE_ID("$Id: scan.c,v 1.2 1999/08/21 23:09:35 tom Exp $")
+
+int scan_max; /* length of longest scan code */
+char **scan_up, **scan_down, **scan_name;
+int *scan_tested, *scan_length, *scan_value;
+
+static int shift_state;
+static char *str;
+static int debug_char_count;
+
+#define SHIFT_KEY 0x100
+#define CONTROL_KEY 0x200
+#define META_KEY 0x400
+#define CAPS_LOCK 0x800
+
+static const struct {
+ const char *name;
+ int type;
+} scan_special[] = {
+ {"<shift>", SHIFT_KEY},
+ {"<left shift>", SHIFT_KEY},
+ {"<right shift>", SHIFT_KEY},
+ {"<control>", CONTROL_KEY},
+ {"<left control>", CONTROL_KEY},
+ {"<right control>", CONTROL_KEY},
+ {"<meta>", META_KEY},
+ {"<left meta>", META_KEY},
+ {"<right meta>", META_KEY},
+ {"<caps lock>", CAPS_LOCK},
+ {"<tab>", '\t'},
+ {"<space>", ' '},
+ {"<return>", '\r'},
+ {"<linefeed>", '\n'},
+ {"<formfeed>", '\f'},
+ {"<backspace>", '\b'},
+ {0, 0}
+};
+
+static void
+scan_blanks(void)
+{ /* scan past the white space */
+ while (*str == ' ' || *str == '\t')
+ str++;
+}
+
+static char *
+smash(void)
+{ /* convert a string to hex */
+ char *s, *t;
+ int ch, i, j;
+
+ t = s = str;
+ for (i = 0; (ch = *str); str++) {
+ if (ch >= '0' && ch <= '9')
+ j = ch - '0';
+ else if (ch >= 'a' && ch <= 'f')
+ j = 10 - 'a' + ch;
+ else if (ch >= 'A' && ch <= 'F')
+ j = 10 - 'A' + ch;
+ else if (ch == ' ' || ch == '\t')
+ break;
+ else
+ continue;
+ if (i) {
+ *s |= j;
+ s++;
+ } else
+ *s = j << 4;
+ i ^= 1;
+ }
+ *s = '\0';
+ return t;
+}
+
+void
+scan_init(char *fn)
+{ /* read the scan mode key definitions */
+ char *s, *sl;
+ FILE *fp;
+ int ch, i, j;
+ char home[512];
+
+ if ((str = getenv("HOME")))
+ strcpy(home, str);
+ else
+ home[0] = '\0';
+ fp = NULL;
+ if ((str = getenv("KEYBOARD"))) {
+ if (!(fp = fopen(str, "r")) && home[0]) {
+ sprintf(temp, "%s/.scan.%s", home, str);
+ fp = fopen(temp, "r");
+ }
+ }
+ if (!fp) {
+ sprintf(temp, ".scan.%s", fn);
+ fp = fopen(temp, "r");
+ }
+ if (!fp && home[0]) {
+ sprintf(temp, "%s/.scan.%s", home, fn);
+ fp = fopen(temp, "r");
+ }
+ if (!fp) {
+ ptext("Unable to open scanfile: ");
+ ptextln(temp);
+ bye_kids(1);
+ return;
+ }
+ /*
+ scan file format:
+
+ <down value> <up value> <name>
+
+ values are in hex. <name> may be any string of characters
+
+ */
+ scan_up = (char **) malloc(sizeof(char *) * MAX_SCAN);
+ scan_down = (char **) malloc(sizeof(char *) * MAX_SCAN);
+ scan_name = (char **) malloc(sizeof(char *) * MAX_SCAN);
+ scan_tested = (int *) malloc(sizeof(int *) * MAX_SCAN);
+ scan_length = (int *) malloc(sizeof(int *) * MAX_SCAN);
+ scan_value = (int *) malloc(sizeof(int *) * MAX_SCAN);
+ scan_up[0] = scan_down[0] = scan_name[0] = (char *) 0;
+ str = (char *) malloc(4096); /* buffer space */
+ sl = str + 4000; /* an upper limit */
+ scan_max = 1;
+ for (i = 0;;) {
+ for (s = str; (ch = getc(fp)) != EOF;) {
+ if (ch == '\n' || ch == '\r')
+ break;
+ *s++ = ch;
+ }
+ *s++ = '\0';
+ if (ch == EOF)
+ break;
+ if (*str == '#' || *str == '\0')
+ continue;
+ scan_down[i] = smash();
+ scan_blanks();
+ scan_up[i] = smash();
+ scan_blanks();
+ scan_name[i] = str;
+
+ scan_length[i] = strlen(scan_down[i]);
+ ch = strlen(scan_up[i]) + scan_length[i];
+ if (ch > scan_max)
+ scan_max = ch;
+
+ scan_value[i] = scan_name[i][0];
+ if (scan_name[i][1]) /* multi-character name */
+ for (j = 0; scan_special[j].name; j++) {
+ if (!strcmp(scan_name[i], scan_special[j].name)) {
+ scan_value[i] = scan_special[j].type;
+ break;
+ }
+ }
+
+ i++;
+ if (str > sl) {
+ str = (char *) malloc(4096);
+ sl = str + 4000;
+ } else
+ str = s;
+ }
+ fclose(fp);
+#ifdef notdef
+ for (i = 0; scan_down[i]; i++) {
+ put_str(hex_expand_to(scan_down[i], 3));
+ put_str(hex_expand_to(scan_up[i], 3));
+ put_str(" ");
+ put_str(scan_name[i]);
+ put_crlf();
+ }
+ (void) wait_here();
+#endif
+}
+
+int
+scan_key(void)
+{ /* read a key and translate scan mode to
+ ASCII */
+ int i, j, ch;
+ char buf[64];
+
+ for (i = 1;; i++) {
+ ch = getchar();
+ if (ch == EOF)
+ return EOF;
+ if (debug_fp) {
+ fprintf(debug_fp, "%02X ", ch);
+ debug_char_count += 3;
+ if (debug_char_count > 72) {
+ fprintf(debug_fp, "\n");
+ debug_char_count = 0;
+ }
+ }
+ buf[i - 1] = ch;
+ buf[i] = '\0';
+ if (buf[0] & 0x80) { /* scan up */
+ for (j = 0; scan_up[j]; j++) {
+ if (i == scan_length[j] &&
+ !strcmp(buf, scan_up[j])) {
+ i = 0;
+ shift_state &= ~scan_value[j];
+ break;
+ }
+ }
+ continue;
+ }
+ for (j = 0; scan_down[j]; j++) {
+ if (i == scan_length[j] && !strcmp(buf, scan_down[j])) {
+ i = 0;
+ shift_state |= scan_value[j];
+ ch = scan_value[j];
+ if (ch == CAPS_LOCK)
+ shift_state ^= SHIFT_KEY;
+ if (ch >= 256)
+ break;
+ if (shift_state & SHIFT_KEY) {
+ if (ch >= 0x60)
+ ch -= 0x20;
+ else if (ch >= 0x30 && ch <= 0x3f)
+ ch -= 0x10;
+ }
+ if (shift_state & CONTROL_KEY) {
+ if ((ch | 0x20) >= 0x60 &&
+ (ch | 0x20) <= 0x7f)
+ ch = (ch | 0x20) - 0x60;
+ }
+ if (shift_state & META_KEY)
+ ch |= 0x80;
+ return ch;
+ }
+ }
+ if (i > scan_max)
+ i = 1;
+ }
+}
diff --git a/contrib/ncurses/tack/sync.c b/contrib/ncurses/tack/sync.c
new file mode 100644
index 000000000000..d8866a0e5ebb
--- /dev/null
+++ b/contrib/ncurses/tack/sync.c
@@ -0,0 +1,424 @@
+/*
+** Copyright (C) 1991, 1997 Free Software Foundation, Inc.
+**
+** This file is part of TACK.
+**
+** TACK is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2, or (at your option)
+** any later version.
+**
+** TACK is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with TACK; see the file COPYING. If not, write to
+** the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA 02111-1307, USA.
+*/
+
+#include <tack.h>
+#include <time.h>
+
+MODULE_ID("$Id: sync.c,v 1.1 1998/01/10 00:31:07 tom Exp $")
+
+/* terminal-synchronization and performance tests */
+
+static void sync_home(struct test_list *, int *, int *);
+static void sync_lines(struct test_list *, int *, int *);
+static void sync_clear(struct test_list *, int *, int *);
+static void sync_summary(struct test_list *, int *, int *);
+
+struct test_list sync_test_list[] = {
+ {MENU_NEXT, 0, 0, 0, "b) baud rate test", sync_home, 0},
+ {MENU_NEXT, 0, 0, 0, "l) scroll performance", sync_lines, 0},
+ {MENU_NEXT, 0, 0, 0, "c) clear screen performance", sync_clear, 0},
+ {MENU_NEXT, 0, 0, 0, "p) summary of results", sync_summary, 0},
+ {0, 0, 0, 0, txt_longer_test_time, longer_test_time, 0},
+ {0, 0, 0, 0, txt_shorter_test_time, shorter_test_time, 0},
+ {MENU_LAST, 0, 0, 0, 0, 0, 0}
+};
+
+struct test_menu sync_menu = {
+ 0, 'n', 0,
+ "Performance tests", "perf", "n) run standard tests",
+ sync_test, sync_test_list, 0, 0, 0
+};
+
+int tty_can_sync; /* TRUE if tty_sync_error() returned FALSE */
+int tty_newline_rate; /* The number of newlines per second */
+int tty_clear_rate; /* The number of clear-screens per second */
+int tty_cps; /* The number of characters per second */
+
+#define TTY_ACK_SIZE 64
+
+int ACK_terminator; /* terminating ACK character */
+int ACK_length; /* length of ACK string */
+const char *tty_ENQ; /* enquire string */
+char tty_ACK[TTY_ACK_SIZE]; /* ACK response, set by tty_sync_error() */
+
+/*****************************************************************************
+ *
+ * Terminal synchronization.
+ *
+ * These functions handle the messy business of enq-ack handshaking
+ * for timing purposes.
+ *
+ *****************************************************************************/
+
+int
+tty_sync_error(void)
+{
+ int ch, trouble, ack;
+
+ trouble = FALSE;
+ for (;;) {
+ tt_putp(tty_ENQ); /* send ENQ */
+ ch = getnext(STRIP_PARITY);
+ event_start(TIME_SYNC); /* start the timer */
+
+ /*
+ The timer doesn't start until we get the first character.
+ After that I expect to get the remaining characters of
+ the acknowledge string in a short period of time. If
+ that is not true then these characters are coming from
+ the user and we need to send the ENQ sequence out again.
+ */
+ for (ack = 0; ; ) {
+ if (ack < TTY_ACK_SIZE - 2) {
+ tty_ACK[ack] = ch;
+ tty_ACK[ack + 1] = '\0';
+ }
+ if (ch == ACK_terminator) {
+ return trouble;
+ }
+ if (++ack >= ACK_length) {
+ return trouble;
+ }
+ ch = getnext(STRIP_PARITY);
+ if (event_time(TIME_SYNC) > 400000) {
+ break;
+ }
+ }
+
+ set_attr(0); /* just in case */
+ put_crlf();
+ if (trouble) {
+ /* The terminal won't sync. Life is not good. */
+ return TRUE;
+ }
+ put_str(" -- sync -- ");
+ trouble = TRUE;
+ }
+}
+
+/*
+** flush_input()
+**
+** Throw away any output.
+*/
+void
+flush_input(void)
+{
+ if (tty_can_sync == SYNC_TESTED && ACK_terminator >= 0) {
+ (void) tty_sync_error();
+ } else {
+ spin_flush();
+ }
+}
+
+/*
+** probe_enq_ok()
+**
+** does the terminal do enq/ack handshaking?
+*/
+static void
+probe_enq_ok(void)
+{
+ int tc, len, ulen;
+
+ put_str("Testing ENQ/ACK, standby...");
+ fflush(stdout);
+ can_test("u8 u9", FLAG_TESTED);
+
+ tty_ENQ = user9 ? user9 : "\005";
+ tc_putp(tty_ENQ);
+ event_start(TIME_SYNC); /* start the timer */
+ read_key(tty_ACK, TTY_ACK_SIZE - 1);
+
+ if (event_time(TIME_SYNC) > 400000 || tty_ACK[0] == '\0') {
+ /* These characters came from the user. Sigh. */
+ tty_can_sync = SYNC_FAILED;
+ ptext("\nThis program expects the ENQ sequence to be");
+ ptext(" answered with the ACK character. This will help");
+ ptext(" the program reestablish synchronization when");
+ ptextln(" the terminal is overrun with data.");
+ ptext("\nENQ sequence from (u9): ");
+ putln(expand(tty_ENQ));
+ ptext("ACK recieved: ");
+ putln(expand(tty_ACK));
+ len = user8 ? strlen(user8) : 0;
+ sprintf(temp, "Length of ACK %d. Expected length of ACK %d.",
+ (int) strlen(tty_ACK), len);
+ ptextln(temp);
+ if (len) {
+ temp[0] = user8[len - 1];
+ temp[1] = '\0';
+ ptext("Terminating character found in (u8): ");
+ putln(expand(temp));
+ }
+ return;
+ }
+
+ tty_can_sync = SYNC_TESTED;
+ if ((len = strlen(tty_ACK)) == 1) {
+ /* single character acknowledge string */
+ ACK_terminator = tty_ACK[0];
+ ACK_length = 4096;
+ return;
+ }
+ tc = tty_ACK[len - 1];
+ if (user8) {
+ ulen = strlen(user8);
+ if (tc == user8[ulen - 1]) {
+ /* ANSI style acknowledge string */
+ ACK_terminator = tc;
+ ACK_length = 4096;
+ return;
+ }
+ }
+ /* fixed length acknowledge string */
+ ACK_length = len;
+ ACK_terminator = -2;
+}
+
+/*
+** verify_time()
+**
+** verify that the time tests are ready to run.
+** If the baud rate is not set then compute it.
+*/
+void
+verify_time(void)
+{
+ int status, ch;
+
+ if (tty_can_sync == SYNC_FAILED) {
+ return;
+ }
+ probe_enq_ok();
+ put_crlf();
+ if (tty_can_sync == SYNC_TESTED) {
+ put_crlf();
+ if (ACK_terminator >= 0) {
+ ptext("ACK terminating character: ");
+ temp[0] = ACK_terminator;
+ temp[1] = '\0';
+ ptextln(expand(temp));
+ } else {
+ sprintf(temp, "Fixed length ACK, %d characters",
+ ACK_length);
+ ptextln(temp);
+ }
+ }
+ if (tty_baud_rate == 0) {
+ sync_home(&sync_test_list[0], &status, &ch);
+ }
+}
+
+/*****************************************************************************
+ *
+ * Terminal performance tests
+ *
+ * Find out how fast the terminal can:
+ * 1) accept characters
+ * 2) scroll the screen
+ * 3) clear the screen
+ *
+ *****************************************************************************/
+
+/*
+** sync_home(test_list, status, ch)
+**
+** Baudrate test
+*/
+void
+sync_home(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int j, k;
+ unsigned long rate;
+
+ if (!cursor_home && !cursor_address && !row_address) {
+ ptext("Terminal can not home cursor. ");
+ generic_done_message(t, state, ch);
+ return;
+ }
+ if (skip_pad_test(t, state, ch,
+ "(home) Start baudrate search")) {
+ return;
+ }
+ pad_test_startup(1);
+ do {
+ go_home();
+ for (j = 1; j < lines; j++) {
+ for (k = 0; k < columns; k++) {
+ if (k & 0xF) {
+ put_this(letter);
+ } else {
+ put_this('.');
+ }
+ }
+ SLOW_TERMINAL_EXIT;
+ }
+ NEXT_LETTER;
+ } while(still_testing());
+ pad_test_shutdown(t, auto_right_margin == 0);
+ /* note: tty_frame_size is the real framesize times two.
+ This takes care of half bits. */
+ rate = (tx_cps * tty_frame_size) >> 1;
+ if (rate > tty_baud_rate) {
+ tty_baud_rate = rate;
+ }
+ if (tx_cps > tty_cps) {
+ tty_cps = tx_cps;
+ }
+ sprintf(temp, "%d characters per second. Baudrate %d ", tx_cps, j);
+ ptext(temp);
+ generic_done_message(t, state, ch);
+}
+
+/*
+** sync_lines(test_list, status, ch)
+**
+** How many newlines/second?
+*/
+static void
+sync_lines(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int j;
+
+ if (skip_pad_test(t, state, ch,
+ "(nel) Start scroll performance test")) {
+ return;
+ }
+ pad_test_startup(0);
+ repeats = 100;
+ do {
+ sprintf(temp, "%d", test_complete);
+ put_str(temp);
+ put_newlines(repeats);
+ } while(still_testing());
+ pad_test_shutdown(t, 0);
+ j = sliding_scale(tx_count[0], 1000000, usec_run_time);
+ if (j > tty_newline_rate) {
+ tty_newline_rate = j;
+ }
+ sprintf(temp, "%d linefeeds per second. ", j);
+ ptext(temp);
+ generic_done_message(t, state, ch);
+}
+
+/*
+** sync_clear(test_list, status, ch)
+**
+** How many clear-screens/second?
+*/
+static void
+sync_clear(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ int j;
+
+ if (!clear_screen) {
+ ptext("Terminal can not clear-screen. ");
+ generic_done_message(t, state, ch);
+ return;
+ }
+ if (skip_pad_test(t, state, ch,
+ "(clear) Start clear-screen performance test")) {
+ return;
+ }
+ pad_test_startup(0);
+ repeats = 20;
+ do {
+ sprintf(temp, "%d", test_complete);
+ put_str(temp);
+ for (j = 0; j < repeats; j++) {
+ put_clear();
+ }
+ } while(still_testing());
+ pad_test_shutdown(t, 0);
+ j = sliding_scale(tx_count[0], 1000000, usec_run_time);
+ if (j > tty_clear_rate) {
+ tty_clear_rate = j;
+ }
+ sprintf(temp, "%d clear-screens per second. ", j);
+ ptext(temp);
+ generic_done_message(t, state, ch);
+}
+
+/*
+** sync_symmary(test_list, status, ch)
+**
+** Print out the test results.
+*/
+static void
+sync_summary(
+ struct test_list *t,
+ int *state,
+ int *ch)
+{
+ char size[32];
+
+ put_crlf();
+ ptextln("Terminal size characters/sec linefeeds/sec clears/sec");
+ sprintf(size, "%dx%d", columns, lines);
+ sprintf(temp, "%-10s%-11s%11d %11d %11d", tty_basename, size,
+ tty_cps, tty_newline_rate, tty_clear_rate);
+ ptextln(temp);
+ generic_done_message(t, state, ch);
+}
+
+/*
+** sync_test(menu)
+**
+** Run at the beginning of the pad tests and function key tests
+*/
+void
+sync_test(
+ struct test_menu *menu)
+{
+ control_init();
+ if (tty_can_sync == SYNC_NOT_TESTED) {
+ verify_time();
+ }
+ if (menu->menu_title) {
+ put_crlf();
+ ptextln(menu->menu_title);
+ }
+}
+
+/*
+** sync_handshake(test_list, status, ch)
+**
+** Test or retest the ENQ/ACK handshake
+*/
+void
+sync_handshake(
+ struct test_list *t GCC_UNUSED,
+ int *state GCC_UNUSED,
+ int *ch GCC_UNUSED)
+{
+ tty_can_sync = SYNC_NOT_TESTED;
+ verify_time();
+}
diff --git a/contrib/ncurses/tack/sysdep.c b/contrib/ncurses/tack/sysdep.c
new file mode 100644
index 000000000000..763cc66e2a90
--- /dev/null
+++ b/contrib/ncurses/tack/sysdep.c
@@ -0,0 +1,455 @@
+/*
+** Copyright (C) 1991, 1997 Free Software Foundation, Inc.
+**
+** This file is part of TACK.
+**
+** TACK is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2, or (at your option)
+** any later version.
+**
+** TACK is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with TACK; see the file COPYING. If not, write to
+** the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA 02111-1307, USA.
+*/
+/*
+ * Operating system dependant functions. We assume the POSIX API.
+ * Note: on strict-POSIX systems (including BSD/OS) the select_delay_type
+ * global has no effect.
+ */
+
+#include <tack.h>
+
+#include <signal.h>
+#include <term.h>
+#include <errno.h>
+
+#if HAVE_SELECT
+#if HAVE_SYS_TIME_H && HAVE_SYS_TIME_SELECT
+#include <sys/time.h>
+#endif
+#if HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#endif
+
+MODULE_ID("$Id: sysdep.c,v 1.5 1999/08/21 21:42:25 tom Exp $")
+
+#if DECL_ERRNO
+extern int errno;
+#endif
+
+/* globals */
+int tty_frame_size; /* asynch frame size times 2 */
+unsigned long tty_baud_rate; /* baud rate - bits per second */
+int not_a_tty; /* TRUE if output is not a tty (i.e. pipe) */
+int nodelay_read; /* TRUE if NDELAY is set */
+
+#define TTY_IS_NOECHO !(new_modes.c_lflag & ECHO)
+#define TTY_IS_OUT_TRANS (new_modes.c_oflag & OPOST)
+#define TTY_IS_CHAR_MODE !(new_modes.c_lflag & ICANON)
+#define TTY_WAS_CS8 ((old_modes.c_cflag & CSIZE) == CS8)
+#define TTY_WAS_XON_XOFF (old_modes.c_iflag & (IXON|IXOFF))
+
+static TTY old_modes, new_modes;
+
+void catchsig(void);
+
+/*
+ * These are a sneaky way of conditionalizing bit unsets so strict-POSIX
+ * systems won't see them.
+ */
+#ifndef XCASE
+#define XCASE 0
+#endif
+#ifndef OLCUC
+#define OLCUC 0
+#endif
+#ifndef IUCLC
+#define IUCLC 0
+#endif
+#ifndef TABDLY
+#define TABDLY 0
+#endif
+#ifndef IXANY
+#define IXANY 0
+#endif
+
+void
+tty_raw(int minch GCC_UNUSED, int mask)
+{ /* set tty to raw noecho */
+ new_modes = old_modes;
+#if HAVE_SELECT
+ new_modes.c_cc[VMIN] = 1;
+#else
+ new_modes.c_cc[VMIN] = minch;
+#endif
+ new_modes.c_cc[VTIME] = 2;
+ new_modes.c_lflag &=
+ ~(ISIG | ICANON | XCASE | ECHO | ECHOE | ECHOK | ECHONL);
+#ifdef LOBLK
+ new_modes.c_lflag &= ~LOBLK;
+#endif
+ new_modes.c_oflag &= ~(OPOST | OLCUC | TABDLY);
+ if (mask == ALLOW_PARITY) {
+ new_modes.c_cflag &= ~(CSIZE | PARENB | HUPCL);
+ new_modes.c_cflag |= CS8;
+ }
+ new_modes.c_iflag &=
+ ~(IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK | ISTRIP | INLCR | IGNCR | ICRNL |
+ IUCLC | IXON | IXANY | IXOFF);
+ if (not_a_tty)
+ return;
+ tcsetattr(fileno(stdin), TCSAFLUSH, &new_modes);
+}
+
+void
+tty_set(void)
+{ /* set tty to special modes */
+ new_modes = old_modes;
+ new_modes.c_cc[VMIN] = 1;
+ new_modes.c_cc[VTIME] = 1;
+ new_modes.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL);
+#if defined(ONLCR) && defined(OCRNL) && defined(ONLRET) && defined(OFILL)
+ new_modes.c_oflag &= ~(ONLCR | OCRNL | ONLRET | OFILL);
+#else
+ new_modes.c_oflag &= ~(OPOST);
+#endif
+ if (char_mask == ALLOW_PARITY)
+ new_modes.c_iflag &= ~ISTRIP;
+ switch (select_xon_xoff) {
+ case 0:
+ new_modes.c_iflag &= ~(IXON | IXOFF);
+ break;
+ case 1:
+#if sequent
+ /* the sequent System V emulation is broken */
+ new_modes = old_modes;
+ new_modes.c_cc[VEOL] = 6; /* control F (ACK) */
+#endif
+ new_modes.c_iflag |= IXON | IXOFF;
+ break;
+ }
+ switch (select_delay_type) {
+ case 0:
+#ifdef NLDLY
+ new_modes.c_oflag &=
+ ~(NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY);
+#endif /* NLDLY */
+ break;
+ case 1:
+#ifdef NLDLY
+ new_modes.c_oflag &=
+ ~(NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY);
+#endif /* NLDLY */
+#ifdef NL1
+ new_modes.c_oflag |= NL1 | CR2;
+#endif /* NL1 */
+ break;
+ }
+ if (!(new_modes.c_oflag & ~OPOST))
+ new_modes.c_oflag &= ~OPOST;
+ if (not_a_tty)
+ return;
+ tcsetattr(fileno(stdin), TCSAFLUSH, &new_modes);
+}
+
+
+void
+tty_reset(void)
+{ /* reset the tty to the original modes */
+ fflush(stdout);
+ if (not_a_tty)
+ return;
+ tcsetattr(fileno(stdin), TCSAFLUSH, &old_modes);
+}
+
+
+void
+tty_init(void)
+{ /* ATT terminal init */
+#ifdef F_GETFL
+ int flags;
+
+ flags = fcntl(fileno(stdin), F_GETFL, 0);
+ nodelay_read = flags & O_NDELAY;
+#else
+ nodelay_read = FALSE;
+#endif
+ not_a_tty = FALSE;
+ if (tcgetattr(fileno(stdin), &old_modes) == -1) {
+ if (errno == ENOTTY) {
+ tty_frame_size = 20;
+ not_a_tty = TRUE;
+ return;
+ }
+ printf("tcgetattr error: %d\n", errno);
+ exit(1);
+ }
+ /* if TAB3 is set then setterm() wipes out tabs (ht) */
+ new_modes = old_modes;
+#ifdef TABDLY
+ new_modes.c_oflag &= ~TABDLY;
+#endif /* TABDLY */
+ if (tcsetattr(fileno(stdin), TCSAFLUSH, &new_modes) == -1) {
+ printf("tcsetattr error: %d\n", errno);
+ exit(1);
+ }
+#ifdef sequent
+ /* the sequent ATT emulation is broken soooo. */
+ old_modes.c_cflag &= ~(CSIZE | CSTOPB);
+ old_modes.c_cflag |= CS7 | PARENB;
+#endif
+ catchsig();
+ switch (old_modes.c_cflag & CSIZE) {
+#if defined(CS5) && (CS5 != 0)
+ case CS5:
+ tty_frame_size = 10;
+ break;
+#endif
+#if defined(CS6) && (CS6 != 0)
+ case CS6:
+ tty_frame_size = 12;
+ break;
+#endif
+#if defined(CS7) && (CS7 != 0)
+ case CS7:
+ tty_frame_size = 14;
+ break;
+#endif
+#if defined(CS8) && (CS8 != 0)
+ case CS8:
+ tty_frame_size = 16;
+ break;
+#endif
+ }
+ tty_frame_size += 2 +
+ ((old_modes.c_cflag & PARENB) ? 2 : 0) +
+ ((old_modes.c_cflag & CSTOPB) ? 4 : 2);
+}
+
+/*
+** stty_query(question)
+**
+** Does the current driver settings have this property?
+*/
+int
+stty_query(int q)
+{
+ switch (q) {
+ case TTY_NOECHO:
+ return TTY_IS_NOECHO;
+ case TTY_OUT_TRANS:
+ return TTY_IS_OUT_TRANS;
+ case TTY_CHAR_MODE:
+ return TTY_IS_CHAR_MODE;
+ }
+ return (-1);
+}
+
+/*
+** initial_stty_query(question)
+**
+** Did the initial driver settings have this property?
+*/
+int
+initial_stty_query(int q)
+{
+ switch (q) {
+ case TTY_8_BIT:
+ return TTY_WAS_CS8;
+ case TTY_XON_XOFF:
+ return TTY_WAS_XON_XOFF;
+ }
+ return (-1);
+}
+
+#if HAVE_SELECT && defined(FD_ZERO)
+static int
+char_ready(void)
+{
+ int n;
+ fd_set ifds;
+ struct timeval tv;
+
+ FD_ZERO(&ifds);
+ FD_SET(fileno(stdin), &ifds);
+ tv.tv_sec = 0;
+ tv.tv_usec = 200000;
+ n = select(fileno(stdin)+1, &ifds, NULL, NULL, &tv);
+ return (n != 0);
+}
+
+#else
+#ifdef FIONREAD
+int
+char_ready(void)
+{
+ int i, j;
+
+ /* the following loop has to be tuned for each computer */
+ for (j = 0; j < 1000; j++) {
+ ioctl(fileno(stdin), FIONREAD, &i);
+ if (i)
+ return i;
+ }
+ return i;
+}
+
+#else
+#define char_ready() 1
+#endif
+#endif
+
+/*
+** spin_flush()
+**
+** Wait for the input stream to stop.
+** Throw away all input characters.
+*/
+void
+spin_flush(void)
+{
+ unsigned char buf[64];
+
+ fflush(stdout);
+ event_start(TIME_FLUSH); /* start the timer */
+ do {
+ if (char_ready()) {
+ (void) read(fileno(stdin), &buf, sizeof(buf));
+ }
+ } while (event_time(TIME_FLUSH) < 400000);
+}
+
+/*
+** read_key(input-buffer, length-of-buffer)
+**
+** read one function key from the input stream.
+** A null character is converted to 0x80.
+*/
+void
+read_key(char *buf, int max)
+{
+ int got, ask, i, l;
+ char *s;
+
+ *buf = '\0';
+ s = buf;
+ fflush(stdout);
+ /* ATT unix may return 0 or 1, Berkeley Unix should be 1 */
+ while (read(fileno(stdin), s, 1) == 0);
+ ++s;
+ --max;
+ while (max > 0 && (ask = char_ready())) {
+ if (ask > max) {
+ ask = max;
+ }
+ if ((got = read(fileno(stdin), s, ask))) {
+ s += got;
+ } else {
+ break;
+ }
+ max -= got;
+ }
+ *s = '\0';
+ l = s - buf;
+ for (s = buf, i = 0; i < l; i++) {
+ if ((*s & 0x7f) == 0) {
+ /* convert nulls to 0x80 */
+ *(unsigned char *)s = 128;
+ } else {
+ /* strip high order bits (if any) */
+ *s &= char_mask;
+ }
+ }
+}
+
+
+void
+ignoresig(void)
+{
+ /* ignore signals */
+ signal(SIGINT, SIG_IGN);
+ signal(SIGHUP, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ signal(SIGTERM, SIG_IGN);
+ signal(SIGALRM, SIG_IGN);
+}
+
+ /*
+ onintr( )
+
+ is the interrupt handling routine onintr turns off interrupts while doing
+ clean-up
+
+ onintr always exits fatally
+ */
+
+
+static RETSIGTYPE
+onintr(int sig GCC_UNUSED)
+{
+ ignoresig();
+ tty_reset();
+ exit(1);
+}
+
+
+ /*
+ catchsig( )
+
+ set up to field interrupts (via function onintr( )) so that if interrupted
+ we can restore the correct terminal modes
+
+ catchsig simply returns
+ */
+
+
+void
+catchsig(void)
+{
+ if ((signal(SIGINT, SIG_IGN)) == SIG_DFL)
+ signal(SIGINT, onintr);
+
+ if ((signal(SIGHUP, SIG_IGN)) == SIG_DFL)
+ signal(SIGHUP, onintr);
+
+ if ((signal(SIGQUIT, SIG_IGN)) == SIG_DFL)
+ signal(SIGQUIT, onintr);
+
+ if ((signal(SIGTERM, SIG_IGN)) == SIG_DFL)
+ signal(SIGTERM, onintr);
+
+}
+
+/*
+** alarm_event(sig)
+**
+** Come here for an alarm event
+*/
+static void
+alarm_event(
+ int sig GCC_UNUSED)
+{
+ no_alarm_event = 0;
+}
+
+/*
+** set_alarm_clock(seconds)
+**
+** Set the alarm clock to fire in <seconds>
+*/
+void
+set_alarm_clock(
+ int seconds)
+{
+ signal(SIGALRM, alarm_event);
+ no_alarm_event = 1;
+ (void) alarm(seconds);
+}
diff --git a/contrib/ncurses/tack/tack.1 b/contrib/ncurses/tack/tack.1
new file mode 100644
index 000000000000..be74e5852cc9
--- /dev/null
+++ b/contrib/ncurses/tack/tack.1
@@ -0,0 +1,311 @@
+.TH tack 1M ""
+.ds n 5
+.ds d @TERMINFO@
+.SH NAME
+\fBtack\fR - \fIterminfo\fR action checker
+.SH SYNOPSIS
+\fBtack\fR [-itV] [term]
+.br
+.SH DESCRIPTION
+The \fBtack\fR program has three purposes:
+(1) to help you build a new terminfo entry describing an unknown terminal,
+(2) to test the correctness of an existing entry, and
+(3) to develop the correct pad timings needed to ensure that screen updates
+don't fall behind the incoming data stream.
+.PP
+\fBTack\fR presents a series of screen-painting and interactive
+tests in ways which are intended to make any mismatches between the
+terminfo entry and reality visually obvious.
+\fBTack\fR also provides tools that can help in understanding how
+the terminal operates.
+.SS OPTIONS
+.TP
+.I "\-i"
+Usually \fBtack\fR will send the reset and init strings to the terminal
+when the program starts up. The \fI-i\fR option will inhibit the
+terminal initialization.
+.TP
+.I "\-t"
+Tell \fBtack\fR to override the terminfo settings for basic terminal
+functions. When this option is set \fBtack\fR will translate
+(cr) to \\r, (cud1) to \\n, (ind) to \\n, (nel) to \\r\\n,
+(cub1) to \\b, (bel) to \\007, (ff) to \\f and (ht) to \\t.
+.TP
+.I "\-V"
+Display the version information and exit.
+.TP
+.I "term"
+Terminfo terminal name to be tested. If not present then the $TERM
+environment variable will be used.
+.SH OVERVIEW
+Since \fBtack\fR is designed to test terminfo's it is not possible
+to rely on the correctness of the terminfo data base. Because of this
+the menuing system used with \fBtack\fR is vary primitive. When a
+menu is printed it will scroll the entire screen. To compensate
+for this verbose menu system \fBtack\fR permits menu selection
+type ahead.
+If you already know what action you would like \fBtack\fR to perform
+then you can enter that value immediately and avoid the menu display.
+When in doubt the question mark (?) is a good character to type.
+A carriage return will execute the default action. These default
+actions are designed to run all the standard tests.
+.PP
+When \fBtack\fR first comes up it will display some basic information
+about the terminal. Take some time to verify this information.
+If it is wrong many of the subsequent tests will fail. The most
+important item is the screen size. If the screen size is wrong there
+is no point in proceeding. (home) and (clear) are also critical
+to the success of subsequent tests. The values of (cr) (ind)
+(cub1) and (ht) may effect the tests if they are defined incorrectly.
+If they are undefined \fBtack\fR will set them to reasonable defaults.
+The last two entries on the display are the enquire and acknowledge strings.
+These strings are taken from the user strings (u9) and (u8).
+.PP
+By now you must be wondering why the terminfo names are enclosed
+in parenthesis. This has no profound meaning other than it makes
+them stand out. The \fBtack\fR program uses this convention any time
+it displays a terminfo name. Remember \fBtack\fR is designed to
+rely on as little of the terminfo entry as possible.
+.SH CREATING NEW ENTRIES
+\fBTack\fR has a number of tools that are designed to help gather
+information about the terminal. Although these functions are not
+dependent on terminal type, you may wish to execute \fBtack\fR
+with options \fI\-it\fR. This will turn off initialization
+and default the standard entries.
+.PP
+These tools may be reached from the main menu by selecting
+the 'tools' entry.
+.PP
+\fBEcho tool\fR: All data typed from the keyboard will be echoed back
+to the terminal. Control characters are not translated to the up arrow format
+but are sent as control characters. This allows you to test an escape
+sequence and see what it actually does. You may also elect to
+\fBenable hex output on echo tool\fR this will echo the characters in
+hexadecimal. Once the test is running you may enter the 'lines'
+or 'columns' keywords which will display a pattern that will help
+you determine your screen size. A complete list of keywords will
+be displayed when the test starts. Type 'help' to redisplay
+the list of available commands.
+.PP
+\fBReply tool\fR: This tool acts much like the echo tool, but
+control characters that are sent from the terminal more than one character
+after a carriage return will be expanded to the up arrow format. For example
+on a standard ANSI terminal you may type:
+
+ CR ESC [ c
+
+and the response will be echoed as something like:
+
+ ^[ [ ? 6 c
+.PP
+\fBANSI sgr display\fR: This test assumes you have an ANSI terminal. It
+goes through attribute numbers 0 to 79, displaying each in turn and using that
+SGR number to write the text. This shows you which of the SGR
+modes are actually implemented by the terminal. Note: some terminals (such as
+Tektronix color) use the private use characters to augment the functionality of
+the SGR command. These private use characters may be interjected into the
+escape sequence by typing the character ( <, =, >, ? ) after the original
+display has been shown.
+.PP
+\fBANSI status reports\fR: This test queries the terminal in standard
+ANSI/VT-100 fashion. The results of this test may help
+determine what options are supported by your terminal.
+.PP
+\fBANSI character sets\fR: This test displays the character sets
+available on a ANSI/VT-100 style terminal.
+Character sets on a real VT-100 terminal are usually defined
+with smacs=\\E(0 and rmacs=\\E(B. The first character after the
+escape defines the font bank. The second character defines the
+character set. This test allows you to view any of the possible
+combinations. Private use character sets are defined by the digits.
+Standard character sets are located in the alphabetic range.
+.SH VERIFYING AN EXISTING ENTRY
+.PP
+You can verify the correctness of an entry with the `begin testing'
+function. This entry is the default action and will be chosen
+if you hit carriage return (or enter). This will bring up a
+secondary menu that allows you to select more specific tests.
+.PP
+The general philosophy of the program is, for each capability, to send an
+appropriate test pattern to the terminal then send a description of
+what the user should expect. Occasionally (as when checking function-key
+capabilities) the program will ask you to enter input for it to check.
+.PP
+If the test fails then you have the option of dynamically changing
+the terminfo entry and re-running the test. This is done with
+the 'edit terminfo' menu item. The edit submenu allows you to change
+the offending terminfo entry and immediately retest the capability.
+The edit menu lets you do other things with the terminfo, such as;
+display the entire terminfo entry,
+display which caps have been tested and display which caps cannot
+be tested. This menu also allows you to write the newly modified
+terminfo to disc. If you have made any modifications to the
+terminfo \fBtack\fR will ask you if you want to save the file
+to disc before it exits. The filename will be the same as the terminal name.
+After the program exits you can run the tic(1M) compiler on the
+new terminfo to install it in the terminfo data base.
+.PP
+.SH CORRECTING PAD TIMINGS
+.SS Theory of Overruns and Padding
+.PP
+Some terminals require significant amounts of time (that is, more than one
+transmitted-character interval) to do screen updates that change large
+portions of the screen, such as screen clears, line insertions,
+line deletions, and scrolls (including scrolls triggered by line feeds
+or a write to the lowest, right-hand-most cell of the screen).
+.PP
+If the computer continues to send characters to the terminal while one
+of these time-consuming operations is going on, the screen may be garbled.
+Since the length of a character transmission time varies inversely with
+transmission speed in cps, entries which function at lower speeds may
+break at higher speeds.
+.PP
+Similar problems result if the host machine is simply sending characters at a
+sustained rate faster than the terminal can buffer and process them. In either
+case, when the terminal cannot process them and can't tell the host to stop
+soon enough, it will just drop them. The dropped characters could be text,
+escape sequences or the escape character itself, causing some really
+strange-looking displays. This kind of glitch is called an \fIoverrun\fR.
+.PP
+In terminfo entries, you can attach a \fBpad time\fR to each string capability
+that is a number of milliseconds to delay after sending it. This will give
+the terminal time to catch up and avoid overruns.
+.PP
+If you are running a software terminal emulator, or you are on an X pseudo-tty,
+or your terminal is on an RS-232C line which correctly handles RTS/CTS
+hardware flow control, then pads are not strictly necessary. However, some
+display packages (such as ncurses(3X)) use the pad counts to calculate
+the fastest way to implement certain functions.
+For example: scrolling the screen may be faster than deleting the top line.
+.PP
+One common way to avoid overruns is with XON/XOFF handshaking.
+But even this handshake may have problems at high baud rates.
+This is a result of the way XON/XOFF works. The terminal tells
+the host to stop with an XOFF. When the host gets this character, it stops
+sending. However, there is a small amount of time between the stop request and
+the actual stop. During this window, the terminal must continue to accept
+characters even though it has told the host to stop. If the terminal sends
+the stop request too late, then its internal buffer will overflow. If it sends
+the stop character too early, then the terminal is not getting the most
+efficient use out of its internal buffers. In a real application at high baud
+rates, a terminal could get a dozen or more characters before the host gets
+around to suspending transmission. Connecting the terminal over a network
+will make the problem much worse.
+.PP
+(RTS/CTS handshaking does not have this problem because the UARTs are
+signal-connected and the "stop flow" is done at the lowest level, without
+software intervention).
+.PP
+.SS Timing your terminal
+.PP
+In order to get accurate timings from your terminal \fBtack\fR
+needs to know when the terminal has finished processing all the
+characters that were sent. This requires a different type of handshaking
+than the XON/XOFF that is supported by most terminals. \fBTack\fR
+needs to send a request to the terminal and wait for its reply.
+Many terminals will respond with an ACK when they receive an ENQ.
+This is the preferred method since the sequence is short.
+ANSI/VT-100 style terminals can mimic this handshake with the
+escape sequence that requests 'primary device attributes'.
+
+ ESC [ c
+
+The terminal will respond with a sequence like:
+
+ ESC [ ? 1 ; 0 c
+
+\fBTack\fR assumes that (u9) is the enquire sequence and that (u8) is the
+acknowledge string. A VT-100 style terminal could set u9=\\E[c
+and u8=\\E[?1;0c.
+Acknowledge strings fall into two categories.
+1) Strings with a unique terminating character and,
+2) strings of fixed length.
+The acknowledge string for the VT-100 is of the first type since
+it always ends with the letter 'c'. Some Tektronics terminals
+have fixed length acknowledge strings. \fBTack\fR supports both
+types of strings by scanning for the terminating character until
+the length of the expected acknowledge string has arrived.
+(u8) should be set to some typical acknowledge that will be
+returned when (u9) is sent.
+.PP
+\fBTack\fR will test this sequence before running any of the pad
+tests or the function key tests. \fBTack\fR will ask you the following:
+
+ Hit lower case g to start testing...
+
+After it sends this message it will send the enquire string.
+It will then read characters from the terminal until it sees the
+letter g.
+.PP
+.SS Testing and Repairing Pad Timings
+.PP
+The pad timings in distributed terminfo entries are often incorrect. One
+major motivation for this program is to make it relatively easy to tune these
+timings.
+.PP
+You can verify and edit the pad timings for a terminal with
+the `test string capabilities'
+function (this is also part of the `normal test sequence' function).
+.PP
+The key to determining pad times is to find out the effective baud rate of
+the terminal. The effective baud rate determines the number of characters
+per second that the terminal can accept without either handshaking or
+losing data. This rate is frequently less than the nominal cps rate on the
+RS-232 line.
+.PP
+\fBTack\fR uses the effective baud rate to judge the duration of the test and
+how much a particular escape sequence will perturb the terminal.
+.PP
+Each pad test has two associated variables that can be tweaked to help verify
+the correctness of the pad timings. One is the pad test length. The other is
+the pad multiplier, which is used if the pad prefix includes `*'. In curses
+use, it is often the first parameter of the capability (if there is one).
+For a capability like (dch) or (il) this will be the number of character
+positions or lines affected, respectively.
+.PP
+\fBTack\fR will run the pad tests and display the results to the terminal.
+On capabilities that have multipliers \fBtack\fR will not tell you
+if the pad needs the multiplier or not. You must make this decision
+yourself by rerunning the test with a different multiplier.
+If the padding changes in proportion to the multiplier than the
+multiplier is required. If the multiplier has little or no effect on
+the suggested padding then the multiplier is not needed.
+Some capabilities will take several runs to get a good feel for
+the correct values. You may wish to make the test longer
+to get more accurate results. System load will also effect the
+results (a heavily loaded system will not stress the
+terminal as much, possibly leading to pad timings that are too short).
+.PP
+.SH NOTE
+The tests done at the beginning of the program are assumed to be correct later
+in the code. In particular, \fBtack\fR displays the number of lines and
+columns indicated in the terminfo entry as part of its initial output.
+If these values are wrong a large number of tests will fail or give incorrect
+results.
+.SH FILES
+.TP 12
+tack.log
+If logging is enabled then all characters written to the terminal
+will also be written to the log file. This gives you the ability
+to see how the tests were performed. This feature is disabled by default.
+.TP 12
+.I "term"
+If you make changes to the terminfo entry \fBtack\fR will save
+the new terminfo to a file. The file will have the same name
+as the terminal name.
+.SH SEE ALSO
+\fBterminfo\fR(\*n), \fBncurses\fR(3X), \fBtic\fR(1m), \fBinfocmp\fR(1m).
+You should also have the documentation supplied by the terminal
+manufacturer.
+.SH BUGS
+If the screen size is incorrect, many of the tests will fail.
+.SH AUTHOR
+Concept, design, and original implementation by
+Daniel Weaver <danw@znyx.com>. Portions of the code and
+documentation are by Eric S. Raymond <esr@snark.thyrsus.com>.
+.\"#
+.\"# The following sets edit modes for GNU EMACS
+.\"# Local Variables:
+.\"# mode:nroff
+.\"# fill-column:79
+.\"# End:
diff --git a/contrib/ncurses/tack/tack.c b/contrib/ncurses/tack/tack.c
new file mode 100644
index 000000000000..8ada023ff4b0
--- /dev/null
+++ b/contrib/ncurses/tack/tack.c
@@ -0,0 +1,620 @@
+/*
+** Copyright (C) 1991, 1997 Free Software Foundation, Inc.
+**
+** This file is part of TACK.
+**
+** TACK is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2, or (at your option)
+** any later version.
+**
+** TACK is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with TACK; see the file COPYING. If not, write to
+** the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA 02111-1307, USA.
+*/
+
+#include <tack.h>
+
+MODULE_ID("$Id: tack.c,v 1.1 1998/01/10 01:34:45 tom Exp $")
+
+/*
+ This program is designed to test terminfo, not curses. Therefore
+ I have used as little of curses as possible.
+
+ Pads associated with the following capabilities are used to set
+ delay times in the handler: (cr), (ind), (cub1), (ff), (tab).
+
+ I use the (nxon) capability to set the tty handler with/without
+ xon/xoff. If (smxon)/(rmxon) is defined I will change the terminal
+ too.
+
+ (xon) inhibits the sending of delay characters in putp().
+ If the terminal is defined with no padding then the (xon) boolean
+ is a don't care. In this case I recommend that it be reset.
+ */
+
+/*****************************************************************************
+ *
+ * Option processing
+ *
+ *****************************************************************************/
+
+/* options and modes */
+int debug_level; /* debugging level */
+int translate_mode; /* translate tab, bs, cr, lf, ff */
+int scan_mode; /* use scan codes */
+int char_mask; /* either 0xFF else 0x7F, eight bit data mask */
+int select_delay_type; /* set handler delays for <cr><lf> */
+int select_xon_xoff; /* TTY driver XON/XOFF mode select */
+int hex_out; /* Display output in hex */
+int send_reset_init; /* Send the reset and initialization strings */
+FILE *log_fp; /* Terminal logfile */
+
+/*****************************************************************************
+ *
+ * Menu definitions
+ *
+ *****************************************************************************/
+
+extern struct test_menu sync_menu;
+
+static void tools_hex_echo(struct test_list *, int *, int *);
+static void tools_debug(struct test_list *, int *, int *);
+
+static char hex_echo_menu_entry[80];
+
+struct test_list tools_test_list[] = {
+ {0, 0, 0, 0, "s) ANSI status reports", tools_status, 0},
+ {0, 0, 0, 0, "g) ANSI SGR modes (bold, underline, reverse)", tools_sgr, 0},
+ {0, 0, 0, 0, "c) ANSI character sets", tools_charset, 0},
+ {0, 0, 0, 0, hex_echo_menu_entry, tools_hex_echo, 0},
+ {0, 0, 0, 0, "e) echo tool", tools_report, 0},
+ {1, 0, 0, 0, "r) reply tool", tools_report, 0},
+ {0, 0, 0, 0, "p) performance testing", 0, &sync_menu},
+ {0, 0, 0, 0, "i) send reset and init", menu_reset_init, 0},
+ {0, 0, "u8) (u9", 0, "u) test ENQ/ACK handshake", sync_handshake, 0},
+ {0, 0, 0, 0, "d) change debug level", tools_debug, 0},
+ {MENU_LAST, 0, 0, 0, 0, 0, 0}
+};
+
+struct test_menu tools_menu = {
+ 0, 'q', 0, "Tools Menu", "tools",
+ 0, 0, tools_test_list, 0, 0, 0
+};
+
+static void tty_width(struct test_list *, int *, int *);
+static void tty_delay(struct test_list *, int *, int *);
+static void tty_xon(struct test_list *, int *, int *);
+static void tty_trans(struct test_list *, int *, int *);
+static void tty_show_state(struct test_menu *);
+
+static char tty_width_menu[80];
+static char tty_delay_menu[80];
+static char tty_xon_menu[80];
+static char tty_trans_menu[80];
+static char enable_xon_xoff[] = {"x) enable xon/xoff"};
+static char disable_xon_xoff[] = {"x) disable xon/xoff"};
+
+static struct test_list tty_test_list[] = {
+ {0, 0, 0, 0, tty_width_menu, tty_width, 0},
+ {0, 0, 0, 0, tty_delay_menu, tty_delay, 0},
+ {0, 0, 0, 0, tty_xon_menu, tty_xon, 0},
+ {0, 0, 0, 0, tty_trans_menu, tty_trans, 0},
+ {MENU_LAST, 0, 0, 0, 0, 0, 0}
+};
+
+static struct test_menu tty_menu = {
+ 0, 'q', 0, "Terminal and driver configuration",
+ "tty", 0,
+ tty_show_state, tty_test_list, 0, 0, 0
+};
+
+extern struct test_list edit_test_list[];
+
+struct test_menu edit_menu = {
+ 0, 'q', 0, "Edit terminfo menu",
+ "edit", 0,
+ 0, edit_test_list, 0, 0, 0
+};
+
+extern struct test_list mode_test_list[];
+
+struct test_menu mode_menu = {
+ 0, 'n', 0, "Mode test menu",
+ "mode", "n) run standard tests",
+ 0, mode_test_list, 0, 0, 0
+};
+
+extern struct test_list acs_test_list[];
+
+static struct test_menu acs_menu = {
+ 0, 'n', 0,
+ "Alternate character set and graphics rendition test menu",
+ "acs", "n) run standard tests",
+ 0, acs_test_list, 0, 0, 0
+};
+
+extern struct test_list color_test_list[];
+
+struct test_menu color_menu = {
+ 0, 'n', 0,
+ "Color test menu",
+ "color", "n) run standard tests",
+ 0, color_test_list, 0, 0, 0
+};
+
+extern struct test_list crum_test_list[];
+
+static struct test_menu crum_menu = {
+ 0, 'n', 0,
+ "Cursor movement test menu",
+ "move", "n) run standard tests",
+ 0, crum_test_list, 0, 0, 0
+};
+
+extern struct test_list funkey_test_list[];
+
+static struct test_menu funkey_menu = {
+ 0, 'n', 0,
+ "Function key test menu",
+ "fkey", "n) run standard tests",
+ sync_test, funkey_test_list, 0, 0, 0
+};
+
+extern struct test_list printer_test_list[];
+
+static struct test_menu printer_menu = {
+ 0, 'n', 0,
+ "Printer test menu",
+ "printer", "n) run standard tests",
+ 0, printer_test_list, 0, 0, 0
+};
+
+static void pad_gen(struct test_list *, int *, int *);
+extern struct test_list pad_test_list[];
+
+static struct test_menu pad_menu = {
+ 0, 'n', 0,
+ "Pad test menu",
+ "pad", "n) run standard tests",
+ sync_test, pad_test_list, 0, 0, 0
+};
+
+static struct test_list normal_test_list[] = {
+ {0, 0, 0, 0, "e) edit terminfo", 0, &edit_menu},
+ {0, 0, 0, 0, "i) send reset and init", menu_reset_init, 0},
+ {MENU_NEXT, 0, 0, 0, "x) test modes and glitches", 0, &mode_menu},
+ {MENU_NEXT, 0, 0, 0, "a) test alternate character sets", 0, &acs_menu},
+ {MENU_NEXT, 0, 0, 0, "c) test color", 0, &color_menu},
+ {MENU_NEXT, 0, 0, 0, "m) test cursor movement", 0, &crum_menu},
+ {MENU_NEXT, 0, 0, 0, "f) test function keys", 0, &funkey_menu},
+ {MENU_NEXT, 0, 0, 0, "p) test string capabilities", 0, &pad_menu},
+ {0, 0, 0, 0, "P) test printer", 0, &printer_menu},
+ {MENU_MENU, 0, 0, 0, "/) test a specific capability", 0, 0},
+ {0, 0, 0, 0, "t) auto generate pad delays", pad_gen, &pad_menu},
+ {0, 0, "u8) (u9", 0, 0, sync_handshake, 0},
+ {MENU_LAST, 0, 0, 0, 0, 0, 0}
+};
+
+
+struct test_menu normal_menu = {
+ 0, 'n', 0, "Main test menu",
+ "test", "n) run standard tests",
+ 0, normal_test_list, 0, 0, 0
+};
+
+static void start_tools(struct test_list *, int *, int *);
+static void start_modes(struct test_list *, int *, int *);
+static void start_basic(struct test_list *, int *, int *);
+static void start_log(struct test_list *, int *, int *);
+
+static char logging_menu_entry[80] = "l) start logging";
+
+struct test_list start_test_list[] = {
+ {0, 0, 0, 0, "b) display basic information", start_basic, 0},
+ {0, 0, 0, 0, "m) change modes", start_modes, 0},
+ {0, 0, 0, 0, "t) tools", start_tools, 0},
+ {MENU_COMPLETE, 0, 0, 0, "n) begin testing", 0, &normal_menu},
+ {0, 0, 0, 0, logging_menu_entry, start_log, 0},
+ {MENU_LAST, 0, 0, 0, 0, 0, 0}
+};
+
+
+struct test_menu start_menu = {
+ 0, 'n', 0, "Main Menu", "tack", 0,
+ 0, start_test_list, 0, 0, 0
+};
+
+static struct test_list write_terminfo_list[] = {
+ {0, 0, 0, 0, "w) write the current terminfo to a file", save_info, 0},
+ {MENU_LAST, 0, 0, 0, 0, 0, 0}
+};
+
+/*****************************************************************************
+ *
+ * Menu command interpretation.
+ *
+ *****************************************************************************/
+
+/*
+** tools_hex_echo(testlist, state, ch)
+**
+** Flip the hex echo flag.
+*/
+static void
+tools_hex_echo(
+ struct test_list *t GCC_UNUSED,
+ int *state GCC_UNUSED,
+ int *ch GCC_UNUSED)
+{
+ if (hex_out) {
+ hex_out = FALSE;
+ strcpy(hex_echo_menu_entry,
+ "h) enable hex output on echo tool");
+ } else {
+ hex_out = TRUE;
+ strcpy(hex_echo_menu_entry,
+ "h) disable hex output on echo tool");
+ }
+}
+
+/*
+** tools_debug(testlist, state, ch)
+**
+** Change the debug level.
+*/
+static void
+tools_debug(
+ struct test_list *t GCC_UNUSED,
+ int *state GCC_UNUSED,
+ int *ch)
+{
+ char buf[32];
+
+ ptext("Enter a new value: ");
+ read_string(buf, sizeof(buf));
+ if (buf[0]) {
+ sscanf(buf, "%d", &debug_level);
+ }
+ sprintf(temp, "Debug level is now %d", debug_level);
+ ptext(temp);
+ *ch = REQUEST_PROMPT;
+}
+
+/*
+** start_tools(testlist, state, ch)
+**
+** Run the generic test tools
+*/
+static void
+start_tools(
+ struct test_list *t GCC_UNUSED,
+ int *state GCC_UNUSED,
+ int *ch GCC_UNUSED)
+{
+ if (hex_out) {
+ strcpy(hex_echo_menu_entry,
+ "h) disable hex output on echo tool");
+ } else {
+ strcpy(hex_echo_menu_entry,
+ "h) enable hex output on echo tool");
+ }
+ menu_display(&tools_menu, 0);
+}
+
+/*
+** tty_show_state()
+**
+** Display the current state on the tty driver settings
+*/
+static void
+tty_show_state(
+ struct test_menu *menu GCC_UNUSED)
+{
+ put_crlf();
+ (void) sprintf(temp,
+ "Accepting %d bits, UNIX delays %d, XON/XOFF %sabled, speed %ld, translate %s, scan-code mode %s.",
+ (char_mask == ALLOW_PARITY) ? 8 : 7,
+ select_delay_type,
+ select_xon_xoff ? "en" : "dis",
+ tty_baud_rate,
+ translate_mode ? "on" : "off",
+ scan_mode ? "on" : "off");
+ ptextln(temp);
+ put_crlf();
+}
+
+/*
+** tty_width(testlist, state, ch)
+**
+** Change the character width
+*/
+static void
+tty_width(
+ struct test_list *t GCC_UNUSED,
+ int *state GCC_UNUSED,
+ int *ch GCC_UNUSED)
+{
+ if (char_mask == STRIP_PARITY) {
+ char_mask = ALLOW_PARITY;
+ strcpy(tty_width_menu, "7) treat terminal as 7-bit");
+ } else {
+ char_mask = STRIP_PARITY;
+ strcpy(tty_width_menu, "8) treat terminal as 8-bit");
+ }
+}
+
+/*
+** tty_delay(testlist, state, ch)
+**
+** Change the delay for <cr><lf> in the TTY driver
+*/
+static void
+tty_delay(
+ struct test_list *t GCC_UNUSED,
+ int *state GCC_UNUSED,
+ int *ch GCC_UNUSED)
+{
+ if (select_delay_type) {
+ select_delay_type = FALSE;
+ strcpy(tty_delay_menu,
+ "d) enable UNIX tty driver delays for <cr><lf>");
+ } else {
+ select_delay_type = TRUE;
+ strcpy(tty_delay_menu,
+ "d) disable UNIX tty driver delays for <cr><lf>");
+ }
+}
+
+/*
+** tty_xon(testlist, state, ch)
+**
+** Change the XON/XOFF flags in the TTY driver
+*/
+static void
+tty_xon(
+ struct test_list *t GCC_UNUSED,
+ int *state GCC_UNUSED,
+ int *ch GCC_UNUSED)
+{
+ if (select_xon_xoff) {
+ if (needs_xon_xoff) {
+ ptextln("This terminal is marked as needing XON/XOFF protocol with (nxon)");
+ }
+ if (exit_xon_mode) {
+ tc_putp(exit_xon_mode);
+ }
+ xon_xoff = select_xon_xoff = FALSE;
+ strcpy(tty_xon_menu, enable_xon_xoff);
+ } else {
+ if (enter_xon_mode) {
+ tc_putp(enter_xon_mode);
+ }
+ xon_xoff = select_xon_xoff = TRUE;
+ strcpy(tty_xon_menu, disable_xon_xoff);
+ }
+ tty_set();
+}
+
+/*
+** tty_trans(testlist, state, ch)
+**
+** Change the translation mode for special characters
+*/
+static void
+tty_trans(
+ struct test_list *t GCC_UNUSED,
+ int *state GCC_UNUSED,
+ int *ch GCC_UNUSED)
+{
+ if (translate_mode) {
+ translate_mode = FALSE;
+ strcpy(tty_trans_menu,
+ "t) use terminfo values for \\b\\f\\n\\r\\t");
+ } else {
+ translate_mode = TRUE;
+ strcpy(tty_trans_menu,
+ "t) override terminfo values for \\b\\f\\n\\r\\t");
+ }
+}
+
+/*
+** pad_gen(testlist, state, ch)
+**
+** Menu function for automatic pad generation
+*/
+static void
+pad_gen(
+ struct test_list *t,
+ int *state GCC_UNUSED,
+ int *ch)
+{
+ control_init();
+ if (tty_can_sync == SYNC_NOT_TESTED) {
+ verify_time();
+ }
+ auto_pad_mode = TRUE;
+ menu_display(t->sub_menu, ch);
+ auto_pad_mode = FALSE;
+}
+
+/*
+** start_modes(testlist, state, ch)
+**
+** Change the TTY modes
+*/
+static void
+start_modes(
+ struct test_list *t GCC_UNUSED,
+ int *state GCC_UNUSED,
+ int *ch GCC_UNUSED)
+{
+
+ if (select_delay_type) {
+ strcpy(tty_delay_menu,
+ "d) disable UNIX tty driver delays for <cr><lf>");
+ } else {
+ strcpy(tty_delay_menu,
+ "d) enable UNIX tty driver delays for <cr><lf>");
+ }
+ if (char_mask == ALLOW_PARITY) {
+ strcpy(tty_width_menu,
+ "7) treat terminal as 7-bit");
+ } else {
+ strcpy(tty_width_menu,
+ "8) treat terminal as 8-bit");
+ }
+ if (select_xon_xoff) {
+ strcpy(tty_xon_menu, disable_xon_xoff);
+ } else {
+ strcpy(tty_xon_menu, enable_xon_xoff);
+ }
+ if (translate_mode) {
+ strcpy(tty_trans_menu,
+ "t) override terminfo values for \\b\\f\\n\\r\\t");
+ } else {
+ strcpy(tty_trans_menu,
+ "t) use terminfo values for \\b\\f\\n\\r\\t");
+ }
+ menu_display(&tty_menu, 0);
+ tty_set();
+}
+
+/*
+** start_basic(testlist, state, ch)
+**
+** Display basic terminal information
+*/
+static void
+start_basic(
+ struct test_list *t GCC_UNUSED,
+ int *state GCC_UNUSED,
+ int *ch)
+{
+ display_basic();
+ *ch = REQUEST_PROMPT;
+}
+
+/*
+** start_log(testlist, state, ch)
+**
+** Start/stop in logging function
+*/
+static void
+start_log(
+ struct test_list *t GCC_UNUSED,
+ int *state GCC_UNUSED,
+ int *ch GCC_UNUSED)
+{
+ if (logging_menu_entry[5] == 'a') {
+ ptextln("The log file will capture all characters sent to the terminal.");
+ if ((log_fp = fopen("tack.log", "w"))) {
+ ptextln("Start logging to file: tack.log");
+ strcpy(logging_menu_entry, "l) stop logging");
+ } else {
+ ptextln("File open error: tack.log");
+ }
+ } else {
+ if (log_fp) {
+ fclose(log_fp);
+ log_fp = 0;
+ }
+ ptextln("Terminal output logging stopped.");
+ strcpy(logging_menu_entry, "l) start logging");
+ }
+}
+
+/*
+** show_usage()
+**
+** Tell the user how its done.
+*/
+void
+show_usage(
+ char *name)
+{
+ (void) fprintf(stderr, "usage: %s [-itV] [term]\n", name);
+}
+
+/*
+** print_version()
+**
+** Print version and other useful information.
+*/
+void
+print_version(void)
+{
+ printf("tack version %d.%02d\n", MAJOR_VERSION, MINOR_VERSION);
+ printf("Copyright (C) 1997 Free Software Foundation, Inc.\n");
+ printf("Tack comes with NO WARRANTY, to the extent permitted by law.\n");
+ printf("You may redistribute copies of Tack under the terms of the\n");
+ printf("GNU General Public License. For more information about\n");
+ printf("these matters, see the file named COPYING.\n");
+}
+
+
+/*****************************************************************************
+ *
+ * Main sequence
+ *
+ *****************************************************************************/
+
+int
+main(int argc, char *argv[])
+{
+ int i, j;
+ char *term_variable;
+
+ /* scan the option flags */
+ send_reset_init = TRUE;
+ translate_mode = FALSE;
+ term_variable = getenv("TERM");
+ tty_can_sync = SYNC_NOT_TESTED;
+ for (i = 1; i < argc; i++) {
+ if (argv[i][0] == '-') {
+ for (j = 1; argv[i][j]; j++) {
+ switch (argv[i][j]) {
+ case 'V':
+ print_version();
+ return (1);
+ case 'i':
+ send_reset_init = FALSE;
+ break;
+ case 't':
+ translate_mode = FALSE;
+ break;
+ default:
+ show_usage(argv[0]);
+ return (0);
+ }
+ }
+ } else {
+ term_variable = argv[i];
+ }
+ }
+ (void) strcpy(tty_basename, term_variable);
+
+ curses_setup(argv[0]);
+
+ menu_can_scan(&normal_menu); /* extract which caps can be tested */
+ menu_display(&start_menu, 0);
+
+ if (user_modified()) {
+ sprintf(temp, "Hit y to save changes to file: %s ? ",
+ tty_basename);
+ ptext(temp);
+ if (wait_here() == 'y') {
+ save_info(write_terminfo_list, &i, &j);
+ }
+ }
+
+ put_str("\nTerminal test complete\n");
+ bye_kids(0);
+ return (0);
+}
diff --git a/contrib/ncurses/tack/tack.h b/contrib/ncurses/tack/tack.h
new file mode 100644
index 000000000000..22e15af57444
--- /dev/null
+++ b/contrib/ncurses/tack/tack.h
@@ -0,0 +1,403 @@
+/*
+** Copyright (C) 1991, 1997 Free Software Foundation, Inc.
+**
+** This file is part of TACK.
+**
+** TACK is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2, or (at your option)
+** any later version.
+**
+** TACK is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with TACK; see the file COPYING. If not, write to
+** the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA 02111-1307, USA.
+*/
+
+/* $Id: tack.h,v 1.5 1999/06/26 22:14:07 tom Exp $ */
+
+#ifndef _TACK_H
+#define _TACK_H 1
+
+/* terminfo action checker include file */
+
+#define MAJOR_VERSION 1
+#define MINOR_VERSION 0
+
+#ifdef HAVE_CONFIG_H
+#include <ncurses_cfg.h>
+#else
+#define RETSIGTYPE void
+#define GCC_UNUSED /*nothing*/
+#define HAVE_GETTIMEOFDAY 1
+#define HAVE_SELECT 1
+#define HAVE_SYS_TIME_H 1
+#define HAVE_SYS_TIME_SELECT 1
+#endif
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <string.h>
+
+#include <curses.h>
+#include <term_entry.h>
+
+#if USE_RCS_IDS
+#define MODULE_ID(id) static const char Ident[] = id;
+#else
+#define MODULE_ID(id) /*nothing*/
+#endif
+
+#if !HAVE_STRSTR
+extern char *_nc_strstr(const char *, const char *);
+#define strstr(h,n) _nc_strstr(h,n)
+#endif
+
+extern FILE *log_fp;
+extern FILE *debug_fp;
+extern int debug_level;
+extern char temp[];
+extern char tty_basename[];
+extern char tty_shortname[];
+
+#define SYNC_FAILED 0
+#define SYNC_TESTED 1
+#define SYNC_NOT_TESTED 2
+#define SYNC_NEEDED 3
+
+extern int tty_can_sync;
+extern int total_pads_sent; /* count pad characters sent */
+extern int total_caps_sent; /* count caps sent */
+extern int total_printing_characters; /* count printing characters sent */
+extern int no_alarm_event; /* TRUE if the alarm has not gone off yet */
+extern int usec_run_time; /* length of last test in microseconds */
+extern int raw_characters_sent; /* Total output characters */
+
+/* Stopwatch event timers */
+#define TIME_TEST 0
+#define TIME_SYNC 1
+#define TIME_FLUSH 2
+#define MAX_TIMERS 3
+
+/* definitions for pad.c */
+
+#define EXIT_CONDITION (no_alarm_event && (tt_delay_used < tt_delay_max))
+#define SLOW_TERMINAL_EXIT if (!test_complete && !EXIT_CONDITION) { break; }
+#define CAP_NOT_FOUND if (auto_pad_mode) return
+
+extern char letters[26+1];
+#define NEXT_LETTER letter = letters[letter_number =\
+ letters[letter_number + 1] ? letter_number + 1 : 0]
+
+extern int test_complete; /* counts number of tests completed */
+extern char letter;
+extern int letter_number;
+extern int augment, repeats;
+extern long char_sent;
+extern const char *pad_repeat_test; /* commands that force repeat */
+
+extern int replace_mode;
+extern int char_count, line_count, expand_chars;
+extern int can_go_home, can_clear_screen;
+
+extern int translate_mode, scan_mode;
+extern int auto_pad_mode; /* TRUE for auto time tests */
+extern int char_mask;
+extern int hex_out; /* Display output in hex */
+
+/* Parity bit macros */
+#define STRIP_PARITY 0x7f
+#define ALLOW_PARITY 0xff
+
+/* select_delay_type: 0 -> reset all delays
+ 1 -> force long delays
+ 2 -> do not change the delays */
+extern int select_delay_type;
+
+/* select_xon_xoff: 0 -> reset xon/xoff
+ 1 -> set xon/xoff
+ 2 -> do not change xon/xoff */
+extern int select_xon_xoff;
+
+extern int tty_frame_size;
+extern unsigned long tty_baud_rate;
+extern int tty_cps; /* The number of characters per second */
+extern int not_a_tty, nodelay_read;
+extern int send_reset_init;
+
+/* definitions for stty_query() and initial_stty_query() */
+#define TTY_CHAR_MODE 0
+#define TTY_NOECHO 1
+#define TTY_OUT_TRANS 2
+#define TTY_8_BIT 3
+#define TTY_XON_XOFF 4
+
+/* scan code definitions */
+#define MAX_SCAN 256
+
+/* translate mode default strings */
+struct default_string_list {
+ const char *name; /* terminfo name */
+ const char *value; /* value of default string */
+ int index; /* index into the strfname[] array */
+};
+
+#define TM_last 8
+extern struct default_string_list TM_string[TM_last];
+
+/* attribute structure definition */
+struct mode_list {
+ const char *name;
+ const char *begin_mode;
+ const char *end_mode;
+ int number;
+};
+
+extern const struct mode_list alt_modes[];
+extern const int mode_map[];
+
+/* Test data base */
+
+#define FLAG_CAN_TEST 1
+#define FLAG_TESTED 2
+#define FLAG_LABEL 4
+#define FLAG_FUNCTION_KEY 8
+
+/* caps under test data base */
+
+#define TT_MAX 8
+#define MAX_CHANGES (TT_MAX+2)
+
+extern int tt_delay_max; /* max number of milliseconds we can delay */
+extern int tt_delay_used; /* number of milliseconds consumed in delay */
+extern const char *tt_cap[TT_MAX]; /* value of string */
+extern int tt_affected[TT_MAX]; /* lines or columns effected (repitition
+ factor) */
+extern int tt_count[TT_MAX]; /* Number of times sent */
+extern int tt_delay[TT_MAX]; /* Number of milliseconds delay */
+extern int ttp; /* number of entries used */
+
+extern const char *tx_cap[TT_MAX]; /* value of string */
+extern int tx_affected[TT_MAX]; /* lines or columns effected (repitition
+ factor) */
+extern int tx_count[TT_MAX]; /* Number of times sent */
+extern int tx_delay[TT_MAX]; /* Number of milliseconds delay */
+extern int tx_index[TT_MAX]; /* String index */
+extern int txp; /* number of entries used */
+extern int tx_characters; /* printing characters sent by test */
+extern int tx_cps; /* characters per second */
+
+/*
+ Menu control for tack.
+*/
+
+struct test_results {
+ struct test_results *next; /* point to next entry */
+ struct test_list *test; /* Test which got these results */
+ int reps; /* repeat count */
+ int delay; /* delay times 10 */
+};
+
+struct test_list {
+ int flags; /* Test description flags */
+ int lines_needed; /* Lines needed for test (0->no action) */
+ const char *caps_done; /* Caps shown in Done message */
+ const char *caps_tested; /* Other caps also being tested */
+ const char *menu_entry; /* Menu entry text (optional) */
+ /* Function that does testing */
+ void (*test_procedure)(struct test_list *, int *, int *);
+ struct test_menu *sub_menu; /* Nested sub-menu */
+};
+
+struct test_menu {
+ int flags; /* Menu feature flag */
+ int default_action; /* Default command if <cr> <lf> entered */
+ const char *menu_text; /* Describe this test_menu */
+ const char *menu_title; /* Title for the menu */
+ const char *ident; /* short menu name */
+ const char *standard_tests; /* Standard test text */
+ /* print current settings (optional) */
+ void (*menu_function)(struct test_menu *);
+ struct test_list *tests; /* Pointer to the menu/function pairs */
+ struct test_list *resume_tests; /* Standard test resume point */
+ int resume_state; /* resume state of test group */
+ int resume_char; /* resume ch of test group */
+};
+
+
+/* menu flags */
+#define MENU_100c 0x00001a00 /* Augment 100% of columns */
+#define MENU_90c 0x00001900 /* Augment 90% of columns */
+#define MENU_80c 0x00001800 /* Augment 80% of columns */
+#define MENU_70c 0x00001700 /* Augment 70% of columns */
+#define MENU_60c 0x00001600 /* Augment 60% of columns */
+#define MENU_50c 0x00001500 /* Augment 50% of columns */
+#define MENU_40c 0x00001400 /* Augment 40% of columns */
+#define MENU_30c 0x00001300 /* Augment 30% of columns */
+#define MENU_20c 0x00001200 /* Augment 20% of columns */
+#define MENU_10c 0x00001100 /* Augment 10% of columns */
+#define MENU_LM1 0x00002e00 /* Augment lines - 1 */
+#define MENU_100l 0x00002a00 /* Augment 100% of lines */
+#define MENU_90l 0x00002900 /* Augment 90% of lines */
+#define MENU_50l 0x00002500 /* Augment 50% of lines */
+#define MENU_lines 0x00002000 /* Augment of lines */
+#define MENU_columns 0x00001000 /* Augment of columns */
+#define MENU_LC_MASK 0x00003000 /* Augment mask for lines and columns */
+#define MENU_1L 0x00002f00 /* Augment == one */
+#define MENU_1C 0x00001f00 /* Augment == one */
+#define MENU_ONE 0x00000f00 /* Augment == one */
+#define MENU_ONE_MASK 0x00000f00 /* Augment == one mask */
+#define MENU_REP_MASK 0x00003f00 /* Augment mask */
+
+#define MENU_CLEAR 0x00010000 /* clear screen */
+#define MENU_INIT 0x00020000 /* Initialization function */
+#define MENU_NEXT 0x00040000 /* Next test in sequence */
+#define MENU_LAST 0x00080000 /* End of menu list */
+#define MENU_STOP 0x00100000 /* Stop testing next-in-sequence */
+#define MENU_COMPLETE 0x00200000 /* Test complete after this */
+#define MENU_MENU 0x00400000 /* Pass the menu name not test name */
+
+#define REQUEST_PROMPT 256
+
+extern char prompt_string[80]; /* menu prompt storage */
+extern struct test_menu edit_menu;
+extern struct test_list *augment_test;
+
+/* tack.c */
+extern void show_usage(char *);
+extern void print_version(void);
+
+/* output.c */
+extern void tt_tputs(const char *, int);
+extern void tt_putp(const char *);
+extern void tt_putparm(NCURSES_CONST char *, int, int, int);
+extern int tc_putp(const char *);
+extern int tc_putch(int);
+extern void putchp(int);
+extern void put_cr(void);
+extern void put_crlf(void);
+extern void put_clear(void);
+extern void put_dec(char *, int);
+extern void put_str(const char *);
+extern void put_lf(void);
+extern void put_ind(void);
+extern void put_newlines(int);
+extern void put_columns(const char *, int, int);
+extern void put_this(int);
+extern void putln(const char *);
+extern void ptext(const char *);
+extern void ptextln(const char *);
+extern void home_down(void);
+extern void go_home(void);
+extern void three_digit(char *, int);
+extern int getchp(int);
+extern char *expand(const char *);
+extern char *expand_to(char *, int);
+extern char *expand_command(const char *);
+extern char *hex_expand_to(char *, int);
+extern char *print_expand(char *);
+extern void maybe_wait(int);
+extern int wait_here(void);
+extern void read_string(char *, int);
+extern int getnext(int);
+
+/* control.c */
+extern void event_start(int);
+extern long event_time(int);
+extern char *liberated(char *);
+extern void page_loop(void);
+extern void control_init(void);
+extern int msec_cost(const char *const, int);
+extern int skip_pad_test(struct test_list *, int *, int *, const char *);
+extern void pad_test_startup(int);
+extern int still_testing(void);
+extern void pad_test_shutdown(struct test_list *, int);
+extern void dump_test_stats(struct test_list *, int *, int *);
+extern void longer_test_time(struct test_list *, int *, int *);
+extern void shorter_test_time(struct test_list *, int *, int *);
+extern char txt_longer_test_time[80];
+extern char txt_shorter_test_time[80];
+extern void set_augment_txt(void);
+extern void longer_augment(struct test_list *, int *, int *);
+extern void shorter_augment(struct test_list *, int *, int *);
+extern char txt_longer_augment[80];
+extern char txt_shorter_augment[80];
+extern int sliding_scale(int, int, int);
+
+/* sync.c */
+extern void verify_time(void);
+extern int tty_sync_error(void);
+extern void flush_input(void);
+extern void sync_test(struct test_menu *);
+extern void sync_handshake(struct test_list *, int *, int *);
+
+/* charset.c */
+extern void set_attr(int);
+extern void eat_cookie(void);
+extern void put_mode(char *);
+
+/* init.c */
+extern void reset_init(void);
+extern void display_basic(void);
+extern void put_name(const char *, const char *);
+extern void charset_can_test(void);
+extern void curses_setup(char *);
+extern void bye_kids(int);
+
+/* scan.c */
+extern int scan_key(void);
+extern void scan_init(char *fn);
+
+/* ansi.c */
+extern void tools_status(struct test_list *, int *, int *);
+extern void tools_charset(struct test_list *, int *, int *);
+extern void tools_sgr(struct test_list *, int *, int *);
+
+/* pad.c */
+
+/* fun.c */
+extern void enter_key(const char *, char *, char *);
+extern int tty_meta_prep(void);
+extern void tools_report(struct test_list *, int *, int *);
+
+/* sysdep.c */
+extern void tty_set(void);
+extern void tty_raw(int, int);
+extern void tty_init(void);
+extern void tty_reset(void);
+extern void spin_flush(void);
+extern void read_key(char *, int);
+extern void set_alarm_clock(int);
+extern void ignoresig(void);
+extern int stty_query(int);
+extern int initial_stty_query(int);
+
+/* edit.c */
+extern int user_modified(void);
+extern void save_info(struct test_list *, int *, int *);
+extern void can_test(const char *, int);
+extern void cap_index(const char *, int *);
+extern int cap_match(const char *names, const char *cap);
+extern void edit_init(void);
+extern char *get_string_cap_byname(const char *, const char **);
+extern int get_string_cap_byvalue(const char *);
+extern void show_report(struct test_list *, int *, int *);
+
+/* menu.c */
+extern void menu_prompt(void);
+extern void menu_can_scan(const struct test_menu *);
+extern void menu_display(struct test_menu *, int *);
+extern void generic_done_message(struct test_list *, int *, int *);
+extern void pad_done_message(struct test_list *, int *, int *);
+extern void menu_clear_screen(struct test_list *, int *, int *);
+extern void menu_reset_init(struct test_list *, int *, int *);
+extern int subtest_menu(struct test_list *, int *, int *);
+
+#endif /* _TACK_H */