diff options
Diffstat (limited to 'contrib/ncurses/tack')
-rw-r--r-- | contrib/ncurses/tack/COPYING | 340 | ||||
-rw-r--r-- | contrib/ncurses/tack/HISTORY | 42 | ||||
-rw-r--r-- | contrib/ncurses/tack/Makefile.in | 155 | ||||
-rw-r--r-- | contrib/ncurses/tack/README | 5 | ||||
-rw-r--r-- | contrib/ncurses/tack/ansi.c | 889 | ||||
-rw-r--r-- | contrib/ncurses/tack/charset.c | 709 | ||||
-rw-r--r-- | contrib/ncurses/tack/color.c | 767 | ||||
-rw-r--r-- | contrib/ncurses/tack/control.c | 657 | ||||
-rw-r--r-- | contrib/ncurses/tack/crum.c | 426 | ||||
-rw-r--r-- | contrib/ncurses/tack/edit.c | 977 | ||||
-rw-r--r-- | contrib/ncurses/tack/fun.c | 912 | ||||
-rw-r--r-- | contrib/ncurses/tack/init.c | 300 | ||||
-rw-r--r-- | contrib/ncurses/tack/menu.c | 421 | ||||
-rw-r--r-- | contrib/ncurses/tack/modes.c | 913 | ||||
-rw-r--r-- | contrib/ncurses/tack/modules | 18 | ||||
-rw-r--r-- | contrib/ncurses/tack/output.c | 818 | ||||
-rw-r--r-- | contrib/ncurses/tack/pad.c | 1955 | ||||
-rw-r--r-- | contrib/ncurses/tack/scan.c | 261 | ||||
-rw-r--r-- | contrib/ncurses/tack/sync.c | 424 | ||||
-rw-r--r-- | contrib/ncurses/tack/sysdep.c | 455 | ||||
-rw-r--r-- | contrib/ncurses/tack/tack.1 | 311 | ||||
-rw-r--r-- | contrib/ncurses/tack/tack.c | 620 | ||||
-rw-r--r-- | contrib/ncurses/tack/tack.h | 403 |
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(¤t_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 */ |