xref: /freebsd/contrib/ncurses/progs/tic.c (revision e18651243efbc1fe285af34e4937fd697612f1c7)
10e3d5408SPeter Wemm /****************************************************************************
2*e1865124SBaptiste Daroussin  * Copyright 2018-2019,2020 Thomas E. Dickey                                *
3*e1865124SBaptiste Daroussin  * Copyright 1998-2017,2018 Free Software Foundation, Inc.                  *
40e3d5408SPeter Wemm  *                                                                          *
50e3d5408SPeter Wemm  * Permission is hereby granted, free of charge, to any person obtaining a  *
60e3d5408SPeter Wemm  * copy of this software and associated documentation files (the            *
70e3d5408SPeter Wemm  * "Software"), to deal in the Software without restriction, including      *
80e3d5408SPeter Wemm  * without limitation the rights to use, copy, modify, merge, publish,      *
90e3d5408SPeter Wemm  * distribute, distribute with modifications, sublicense, and/or sell       *
100e3d5408SPeter Wemm  * copies of the Software, and to permit persons to whom the Software is    *
110e3d5408SPeter Wemm  * furnished to do so, subject to the following conditions:                 *
120e3d5408SPeter Wemm  *                                                                          *
130e3d5408SPeter Wemm  * The above copyright notice and this permission notice shall be included  *
140e3d5408SPeter Wemm  * in all copies or substantial portions of the Software.                   *
150e3d5408SPeter Wemm  *                                                                          *
160e3d5408SPeter Wemm  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
170e3d5408SPeter Wemm  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
180e3d5408SPeter Wemm  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
190e3d5408SPeter Wemm  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
200e3d5408SPeter Wemm  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
210e3d5408SPeter Wemm  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
220e3d5408SPeter Wemm  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
230e3d5408SPeter Wemm  *                                                                          *
240e3d5408SPeter Wemm  * Except as contained in this notice, the name(s) of the above copyright   *
250e3d5408SPeter Wemm  * holders shall not be used in advertising or otherwise to promote the     *
260e3d5408SPeter Wemm  * sale, use or other dealings in this Software without prior written       *
270e3d5408SPeter Wemm  * authorization.                                                           *
280e3d5408SPeter Wemm  ****************************************************************************/
290e3d5408SPeter Wemm 
300e3d5408SPeter Wemm /****************************************************************************
310e3d5408SPeter Wemm  *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
320e3d5408SPeter Wemm  *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
33b82face1SPeter Wemm  *     and: Thomas E. Dickey                        1996 on                 *
340e3d5408SPeter Wemm  ****************************************************************************/
350e3d5408SPeter Wemm 
360e3d5408SPeter Wemm /*
370e3d5408SPeter Wemm  *	tic.c --- Main program for terminfo compiler
380e3d5408SPeter Wemm  *			by Eric S. Raymond
3973f0a83dSXin LI  *			and Thomas E Dickey
400e3d5408SPeter Wemm  *
410e3d5408SPeter Wemm  */
420e3d5408SPeter Wemm 
430e3d5408SPeter Wemm #include <progs.priv.h>
4418259542SPeter Wemm #include <sys/stat.h>
450e3d5408SPeter Wemm 
460e3d5408SPeter Wemm #include <dump_entry.h>
47aae38d10SBaptiste Daroussin #include <tparm_type.h>
4873f0a83dSXin LI #include <hashed_db.h>
49aae38d10SBaptiste Daroussin #include <parametrized.h>
5018259542SPeter Wemm #include <transform.h>
510e3d5408SPeter Wemm 
52*e1865124SBaptiste Daroussin MODULE_ID("$Id: tic.c,v 1.282 2020/02/02 23:34:34 tom Exp $")
5373f0a83dSXin LI 
5473f0a83dSXin LI #define STDIN_NAME "<stdin>"
550e3d5408SPeter Wemm 
560e3d5408SPeter Wemm const char *_nc_progname = "tic";
570e3d5408SPeter Wemm 
580e3d5408SPeter Wemm static FILE *log_fp;
590e3d5408SPeter Wemm static FILE *tmp_fp;
604a1a9510SRong-En Fan static bool capdump = FALSE;	/* running as infotocap? */
614a1a9510SRong-En Fan static bool infodump = FALSE;	/* running as captoinfo? */
620e3d5408SPeter Wemm static bool showsummary = FALSE;
63aae38d10SBaptiste Daroussin static unsigned debug_level;
6473f0a83dSXin LI static char **namelst = 0;
650e3d5408SPeter Wemm static const char *to_remove;
660e3d5408SPeter Wemm 
67aae38d10SBaptiste Daroussin #if NCURSES_XNAMES
68aae38d10SBaptiste Daroussin static bool using_extensions = FALSE;
69aae38d10SBaptiste Daroussin #endif
70aae38d10SBaptiste Daroussin 
71aae38d10SBaptiste Daroussin static void (*save_check_termtype) (TERMTYPE2 *, bool);
72aae38d10SBaptiste Daroussin static void check_termtype(TERMTYPE2 *tt, bool);
730e3d5408SPeter Wemm 
744a1a9510SRong-En Fan static const char usage_string[] = "\
754a1a9510SRong-En Fan [-e names] \
764a1a9510SRong-En Fan [-o dir] \
774a1a9510SRong-En Fan [-R name] \
784a1a9510SRong-En Fan [-v[n]] \
794a1a9510SRong-En Fan [-V] \
804a1a9510SRong-En Fan [-w[n]] \
814a1a9510SRong-En Fan [-\
824a1a9510SRong-En Fan 1\
834a1a9510SRong-En Fan a\
844a1a9510SRong-En Fan C\
8573f0a83dSXin LI D\
864a1a9510SRong-En Fan c\
874a1a9510SRong-En Fan f\
884a1a9510SRong-En Fan G\
894a1a9510SRong-En Fan g\
904a1a9510SRong-En Fan I\
9173f0a83dSXin LI K\
924a1a9510SRong-En Fan L\
934a1a9510SRong-En Fan N\
944a1a9510SRong-En Fan r\
954a1a9510SRong-En Fan s\
964a1a9510SRong-En Fan T\
974a1a9510SRong-En Fan t\
984a1a9510SRong-En Fan U\
994a1a9510SRong-En Fan x\
1004a1a9510SRong-En Fan ] \
1014a1a9510SRong-En Fan source-file\n";
1020e3d5408SPeter Wemm 
1035d08fb1fSRong-En Fan #if NO_LEAKS
10415589c42SPeter Wemm static void
1055d08fb1fSRong-En Fan free_namelist(char **src)
1060e3d5408SPeter Wemm {
1075d08fb1fSRong-En Fan     if (src != 0) {
1085d08fb1fSRong-En Fan 	int n;
1095d08fb1fSRong-En Fan 	for (n = 0; src[n] != 0; ++n)
1105d08fb1fSRong-En Fan 	    free(src[n]);
1115d08fb1fSRong-En Fan 	free(src);
1125d08fb1fSRong-En Fan     }
1135d08fb1fSRong-En Fan }
1145d08fb1fSRong-En Fan #endif
1155d08fb1fSRong-En Fan 
1165d08fb1fSRong-En Fan static void
11773f0a83dSXin LI cleanup(void)
1185d08fb1fSRong-En Fan {
11973f0a83dSXin LI     int rc;
12073f0a83dSXin LI 
1215d08fb1fSRong-En Fan #if NO_LEAKS
1225d08fb1fSRong-En Fan     free_namelist(namelst);
123aae38d10SBaptiste Daroussin     _nc_leaks_dump_entry();
1245d08fb1fSRong-En Fan #endif
1250e3d5408SPeter Wemm     if (tmp_fp != 0)
1260e3d5408SPeter Wemm 	fclose(tmp_fp);
1270e3d5408SPeter Wemm     if (to_remove != 0) {
1280e3d5408SPeter Wemm #if HAVE_REMOVE
12973f0a83dSXin LI 	rc = remove(to_remove);
1300e3d5408SPeter Wemm #else
13173f0a83dSXin LI 	rc = unlink(to_remove);
1320e3d5408SPeter Wemm #endif
13373f0a83dSXin LI 	if (rc != 0)
13473f0a83dSXin LI 	    perror(to_remove);
1350e3d5408SPeter Wemm     }
1360e3d5408SPeter Wemm }
1370e3d5408SPeter Wemm 
13815589c42SPeter Wemm static void
13915589c42SPeter Wemm failed(const char *msg)
1400e3d5408SPeter Wemm {
1410e3d5408SPeter Wemm     perror(msg);
1424a1a9510SRong-En Fan     ExitProgram(EXIT_FAILURE);
1430e3d5408SPeter Wemm }
1440e3d5408SPeter Wemm 
14515589c42SPeter Wemm static void
14615589c42SPeter Wemm usage(void)
1470e3d5408SPeter Wemm {
148aae38d10SBaptiste Daroussin #define DATA(s) s "\n"
149aae38d10SBaptiste Daroussin     static const char options_string[] =
15015589c42SPeter Wemm     {
151aae38d10SBaptiste Daroussin 	DATA("Options:")
152aae38d10SBaptiste Daroussin 	DATA("  -0         format translation output all capabilities on one line")
153aae38d10SBaptiste Daroussin 	DATA("  -1         format translation output one capability per line")
15415589c42SPeter Wemm #if NCURSES_XNAMES
155aae38d10SBaptiste Daroussin 	DATA("  -a         retain commented-out capabilities (sets -x also)")
15615589c42SPeter Wemm #endif
157aae38d10SBaptiste Daroussin 	DATA("  -C         translate entries to termcap source form")
158aae38d10SBaptiste Daroussin 	DATA("  -D         print list of tic's database locations (first must be writable)")
159aae38d10SBaptiste Daroussin 	DATA("  -c         check only, validate input without compiling or translating")
160aae38d10SBaptiste Daroussin 	DATA("  -e<names>  translate/compile only entries named by comma-separated list")
161aae38d10SBaptiste Daroussin 	DATA("  -f         format complex strings for readability")
162aae38d10SBaptiste Daroussin 	DATA("  -G         format %{number} to %'char'")
163aae38d10SBaptiste Daroussin 	DATA("  -g         format %'char' to %{number}")
164aae38d10SBaptiste Daroussin 	DATA("  -I         translate entries to terminfo source form")
165aae38d10SBaptiste Daroussin 	DATA("  -K         translate entries to termcap source form with BSD syntax")
166aae38d10SBaptiste Daroussin 	DATA("  -L         translate entries to full terminfo source form")
167aae38d10SBaptiste Daroussin 	DATA("  -N         disable smart defaults for source translation")
168aae38d10SBaptiste Daroussin 	DATA("  -o<dir>    set output directory for compiled entry writes")
169aae38d10SBaptiste Daroussin 	DATA("  -Q[n]      dump compiled description")
170aae38d10SBaptiste Daroussin 	DATA("  -q    brief listing, removes headers")
171aae38d10SBaptiste Daroussin 	DATA("  -R<name>   restrict translation to given terminfo/termcap version")
172aae38d10SBaptiste Daroussin 	DATA("  -r         force resolution of all use entries in source translation")
173aae38d10SBaptiste Daroussin 	DATA("  -s         print summary statistics")
174aae38d10SBaptiste Daroussin 	DATA("  -T         remove size-restrictions on compiled description")
1754a1a9510SRong-En Fan #if NCURSES_XNAMES
176aae38d10SBaptiste Daroussin 	DATA("  -t         suppress commented-out capabilities")
1774a1a9510SRong-En Fan #endif
178aae38d10SBaptiste Daroussin 	DATA("  -U         suppress post-processing of entries")
179aae38d10SBaptiste Daroussin 	DATA("  -V         print version")
180aae38d10SBaptiste Daroussin 	DATA("  -W         wrap long strings according to -w[n] option")
181aae38d10SBaptiste Daroussin 	DATA("  -v[n]      set verbosity level")
182aae38d10SBaptiste Daroussin 	DATA("  -w[n]      set format width for translation output")
1830e3d5408SPeter Wemm #if NCURSES_XNAMES
184aae38d10SBaptiste Daroussin 	DATA("  -x         treat unknown capabilities as user-defined")
1850e3d5408SPeter Wemm #endif
186aae38d10SBaptiste Daroussin 	DATA("")
187aae38d10SBaptiste Daroussin 	DATA("Parameters:")
188aae38d10SBaptiste Daroussin 	DATA("  <file>     file to translate or compile")
1890e3d5408SPeter Wemm     };
190aae38d10SBaptiste Daroussin #undef DATA
1910e3d5408SPeter Wemm 
19215589c42SPeter Wemm     fprintf(stderr, "Usage: %s %s\n", _nc_progname, usage_string);
193aae38d10SBaptiste Daroussin     fputs(options_string, stderr);
1944a1a9510SRong-En Fan     ExitProgram(EXIT_FAILURE);
1950e3d5408SPeter Wemm }
1960e3d5408SPeter Wemm 
1970e3d5408SPeter Wemm #define L_BRACE '{'
1980e3d5408SPeter Wemm #define R_BRACE '}'
19973f0a83dSXin LI #define S_QUOTE '\''
2000e3d5408SPeter Wemm 
20115589c42SPeter Wemm static void
20215589c42SPeter Wemm write_it(ENTRY * ep)
2030e3d5408SPeter Wemm {
2040e3d5408SPeter Wemm     unsigned n;
2050e3d5408SPeter Wemm     int ch;
2060e3d5408SPeter Wemm     char *s, *d, *t;
2070e3d5408SPeter Wemm     char result[MAX_ENTRY_SIZE];
2080e3d5408SPeter Wemm 
2090e3d5408SPeter Wemm     /*
2100e3d5408SPeter Wemm      * Look for strings that contain %{number}, convert them to %'char',
2110e3d5408SPeter Wemm      * which is shorter and runs a little faster.
2120e3d5408SPeter Wemm      */
2130e3d5408SPeter Wemm     for (n = 0; n < STRCOUNT; n++) {
2140e3d5408SPeter Wemm 	s = ep->tterm.Strings[n];
2150e3d5408SPeter Wemm 	if (VALID_STRING(s)
2160e3d5408SPeter Wemm 	    && strchr(s, L_BRACE) != 0) {
2170e3d5408SPeter Wemm 	    d = result;
2180e3d5408SPeter Wemm 	    t = s;
2190e3d5408SPeter Wemm 	    while ((ch = *t++) != 0) {
2205d08fb1fSRong-En Fan 		*d++ = (char) ch;
2210e3d5408SPeter Wemm 		if (ch == '\\') {
222aae38d10SBaptiste Daroussin 		    if ((*d++ = *t++) == '\0')
223aae38d10SBaptiste Daroussin 			break;
2240e3d5408SPeter Wemm 		} else if ((ch == '%')
2250e3d5408SPeter Wemm 			   && (*t == L_BRACE)) {
2260e3d5408SPeter Wemm 		    char *v = 0;
2270e3d5408SPeter Wemm 		    long value = strtol(t + 1, &v, 0);
2280e3d5408SPeter Wemm 		    if (v != 0
2290e3d5408SPeter Wemm 			&& *v == R_BRACE
2300e3d5408SPeter Wemm 			&& value > 0
2310e3d5408SPeter Wemm 			&& value != '\\'	/* FIXME */
2320e3d5408SPeter Wemm 			&& value < 127
2330e3d5408SPeter Wemm 			&& isprint((int) value)) {
2340e3d5408SPeter Wemm 			*d++ = S_QUOTE;
2355d08fb1fSRong-En Fan 			*d++ = (char) value;
2360e3d5408SPeter Wemm 			*d++ = S_QUOTE;
2370e3d5408SPeter Wemm 			t = (v + 1);
2380e3d5408SPeter Wemm 		    }
2390e3d5408SPeter Wemm 		}
2400e3d5408SPeter Wemm 	    }
2410e3d5408SPeter Wemm 	    *d = 0;
2420e3d5408SPeter Wemm 	    if (strlen(result) < strlen(s))
24373f0a83dSXin LI 		_nc_STRCPY(s, result, strlen(s) + 1);
2440e3d5408SPeter Wemm 	}
2450e3d5408SPeter Wemm     }
2460e3d5408SPeter Wemm 
2470e3d5408SPeter Wemm     _nc_set_type(_nc_first_name(ep->tterm.term_names));
24873f0a83dSXin LI     _nc_curr_line = (int) ep->startline;
2490e3d5408SPeter Wemm     _nc_write_entry(&ep->tterm);
2500e3d5408SPeter Wemm }
2510e3d5408SPeter Wemm 
25215589c42SPeter Wemm static bool
25315589c42SPeter Wemm immedhook(ENTRY * ep GCC_UNUSED)
2540e3d5408SPeter Wemm /* write out entries with no use capabilities immediately to save storage */
2550e3d5408SPeter Wemm {
25618259542SPeter Wemm #if !HAVE_BIG_CORE
2570e3d5408SPeter Wemm     /*
2580e3d5408SPeter Wemm      * This is strictly a core-economy kluge.  The really clean way to handle
2590e3d5408SPeter Wemm      * compilation is to slurp the whole file into core and then do all the
2600e3d5408SPeter Wemm      * name-collision checks and entry writes in one swell foop.  But the
2610e3d5408SPeter Wemm      * terminfo master file is large enough that some core-poor systems swap
2620e3d5408SPeter Wemm      * like crazy when you compile it this way...there have been reports of
2630e3d5408SPeter Wemm      * this process taking *three hours*, rather than the twenty seconds or
2640e3d5408SPeter Wemm      * less typical on my development box.
2650e3d5408SPeter Wemm      *
2660e3d5408SPeter Wemm      * So.  This hook *immediately* writes out the referenced entry if it
2670e3d5408SPeter Wemm      * has no use capabilities.  The compiler main loop refrains from
2680e3d5408SPeter Wemm      * adding the entry to the in-core list when this hook fires.  If some
2690e3d5408SPeter Wemm      * other entry later needs to reference an entry that got written
2700e3d5408SPeter Wemm      * immediately, that's OK; the resolution code will fetch it off disk
2710e3d5408SPeter Wemm      * when it can't find it in core.
2720e3d5408SPeter Wemm      *
2730e3d5408SPeter Wemm      * Name collisions will still be detected, just not as cleanly.  The
2740e3d5408SPeter Wemm      * write_entry() code complains before overwriting an entry that
2750e3d5408SPeter Wemm      * postdates the time of tic's first call to write_entry().  Thus
2760e3d5408SPeter Wemm      * it will complain about overwriting entries newly made during the
2770e3d5408SPeter Wemm      * tic run, but not about overwriting ones that predate it.
2780e3d5408SPeter Wemm      *
2790e3d5408SPeter Wemm      * The reason this is a hook, and not in line with the rest of the
2800e3d5408SPeter Wemm      * compiler code, is that the support for termcap fallback cannot assume
2810e3d5408SPeter Wemm      * it has anywhere to spool out these entries!
2820e3d5408SPeter Wemm      *
2830e3d5408SPeter Wemm      * The _nc_set_type() call here requires a compensating one in
2840e3d5408SPeter Wemm      * _nc_parse_entry().
2850e3d5408SPeter Wemm      *
2860e3d5408SPeter Wemm      * If you define HAVE_BIG_CORE, you'll disable this kluge.  This will
2870e3d5408SPeter Wemm      * make tic a bit faster (because the resolution code won't have to do
2880e3d5408SPeter Wemm      * disk I/O nearly as often).
2890e3d5408SPeter Wemm      */
29015589c42SPeter Wemm     if (ep->nuses == 0) {
2910e3d5408SPeter Wemm 	int oldline = _nc_curr_line;
2920e3d5408SPeter Wemm 
2930e3d5408SPeter Wemm 	write_it(ep);
2940e3d5408SPeter Wemm 	_nc_curr_line = oldline;
2950e3d5408SPeter Wemm 	free(ep->tterm.str_table);
2960e3d5408SPeter Wemm 	return (TRUE);
2970e3d5408SPeter Wemm     }
2980e3d5408SPeter Wemm #endif /* HAVE_BIG_CORE */
2990e3d5408SPeter Wemm     return (FALSE);
3000e3d5408SPeter Wemm }
3010e3d5408SPeter Wemm 
30215589c42SPeter Wemm static void
30315589c42SPeter Wemm put_translate(int c)
3040e3d5408SPeter Wemm /* emit a comment char, translating terminfo names to termcap names */
3050e3d5408SPeter Wemm {
3060e3d5408SPeter Wemm     static bool in_name = FALSE;
30715589c42SPeter Wemm     static size_t have, used;
30815589c42SPeter Wemm     static char *namebuf, *suffix;
3090e3d5408SPeter Wemm 
31015589c42SPeter Wemm     if (in_name) {
31115589c42SPeter Wemm 	if (used + 1 >= have) {
31215589c42SPeter Wemm 	    have += 132;
31373f0a83dSXin LI 	    if ((namebuf = typeRealloc(char, have, namebuf)) == 0)
31473f0a83dSXin LI 		  failed("put_translate namebuf");
31573f0a83dSXin LI 	    if ((suffix = typeRealloc(char, have, suffix)) == 0)
31673f0a83dSXin LI 		  failed("put_translate suffix");
3170e3d5408SPeter Wemm 	}
31815589c42SPeter Wemm 	if (c == '\n' || c == '@') {
31915589c42SPeter Wemm 	    namebuf[used++] = '\0';
3200e3d5408SPeter Wemm 	    (void) putchar('<');
3210e3d5408SPeter Wemm 	    (void) fputs(namebuf, stdout);
3220e3d5408SPeter Wemm 	    putchar(c);
3230e3d5408SPeter Wemm 	    in_name = FALSE;
32415589c42SPeter Wemm 	} else if (c != '>') {
3255d08fb1fSRong-En Fan 	    namebuf[used++] = (char) c;
32615589c42SPeter Wemm 	} else {		/* ah! candidate name! */
3270e3d5408SPeter Wemm 	    char *up;
3280e3d5408SPeter Wemm 	    NCURSES_CONST char *tp;
3290e3d5408SPeter Wemm 
33015589c42SPeter Wemm 	    namebuf[used++] = '\0';
3310e3d5408SPeter Wemm 	    in_name = FALSE;
3320e3d5408SPeter Wemm 
3330e3d5408SPeter Wemm 	    suffix[0] = '\0';
3340e3d5408SPeter Wemm 	    if ((up = strchr(namebuf, '#')) != 0
3350e3d5408SPeter Wemm 		|| (up = strchr(namebuf, '=')) != 0
33615589c42SPeter Wemm 		|| ((up = strchr(namebuf, '@')) != 0 && up[1] == '>')) {
33773f0a83dSXin LI 		_nc_STRCPY(suffix, up, have);
3380e3d5408SPeter Wemm 		*up = '\0';
3390e3d5408SPeter Wemm 	    }
3400e3d5408SPeter Wemm 
34115589c42SPeter Wemm 	    if ((tp = nametrans(namebuf)) != 0) {
3420e3d5408SPeter Wemm 		(void) putchar(':');
3430e3d5408SPeter Wemm 		(void) fputs(tp, stdout);
3440e3d5408SPeter Wemm 		(void) fputs(suffix, stdout);
3450e3d5408SPeter Wemm 		(void) putchar(':');
34615589c42SPeter Wemm 	    } else {
3470e3d5408SPeter Wemm 		/* couldn't find a translation, just dump the name */
3480e3d5408SPeter Wemm 		(void) putchar('<');
3490e3d5408SPeter Wemm 		(void) fputs(namebuf, stdout);
3500e3d5408SPeter Wemm 		(void) fputs(suffix, stdout);
3510e3d5408SPeter Wemm 		(void) putchar('>');
3520e3d5408SPeter Wemm 	    }
35315589c42SPeter Wemm 	}
35415589c42SPeter Wemm     } else {
35515589c42SPeter Wemm 	used = 0;
35615589c42SPeter Wemm 	if (c == '<') {
35715589c42SPeter Wemm 	    in_name = TRUE;
35815589c42SPeter Wemm 	} else {
35915589c42SPeter Wemm 	    putchar(c);
36015589c42SPeter Wemm 	}
3610e3d5408SPeter Wemm     }
3620e3d5408SPeter Wemm }
3630e3d5408SPeter Wemm 
3640e3d5408SPeter Wemm /* Returns a string, stripped of leading/trailing whitespace */
36515589c42SPeter Wemm static char *
36615589c42SPeter Wemm stripped(char *src)
3670e3d5408SPeter Wemm {
36873f0a83dSXin LI     char *dst = 0;
36973f0a83dSXin LI 
37039f2269fSPeter Wemm     while (isspace(UChar(*src)))
3710e3d5408SPeter Wemm 	src++;
37273f0a83dSXin LI 
3730e3d5408SPeter Wemm     if (*src != '\0') {
37406bfebdeSXin LI 	size_t len;
37506bfebdeSXin LI 
37673f0a83dSXin LI 	if ((dst = strdup(src)) == NULL) {
37706bfebdeSXin LI 	    failed("strdup");
37873f0a83dSXin LI 	} else {
37906bfebdeSXin LI 	    len = strlen(dst);
38039f2269fSPeter Wemm 	    while (--len != 0 && isspace(UChar(dst[len])))
3810e3d5408SPeter Wemm 		dst[len] = '\0';
3820e3d5408SPeter Wemm 	}
38373f0a83dSXin LI     }
38473f0a83dSXin LI     return dst;
3850e3d5408SPeter Wemm }
3860e3d5408SPeter Wemm 
38718259542SPeter Wemm static FILE *
38873f0a83dSXin LI open_tempfile(char *filename)
38918259542SPeter Wemm {
39073f0a83dSXin LI     FILE *result = 0;
39173f0a83dSXin LI 
39273f0a83dSXin LI     _nc_STRCPY(filename, "/tmp/XXXXXX", PATH_MAX);
39373f0a83dSXin LI #if HAVE_MKSTEMP
39473f0a83dSXin LI     {
39573f0a83dSXin LI 	int oldmask = (int) umask(077);
39673f0a83dSXin LI 	int fd = mkstemp(filename);
39773f0a83dSXin LI 	if (fd >= 0)
39873f0a83dSXin LI 	    result = fdopen(fd, "w");
39973f0a83dSXin LI 	umask((mode_t) oldmask);
40073f0a83dSXin LI     }
40173f0a83dSXin LI #else
40273f0a83dSXin LI     if (tmpnam(filename) != 0)
40373f0a83dSXin LI 	result = fopen(filename, "w");
40473f0a83dSXin LI #endif
40573f0a83dSXin LI     return result;
40673f0a83dSXin LI }
40773f0a83dSXin LI 
40873f0a83dSXin LI static FILE *
40973f0a83dSXin LI copy_input(FILE *source, const char *filename, char *alt_file)
41073f0a83dSXin LI {
41173f0a83dSXin LI     char my_altfile[PATH_MAX];
41273f0a83dSXin LI     FILE *result = 0;
41373f0a83dSXin LI     FILE *target = 0;
41473f0a83dSXin LI     int ch;
41573f0a83dSXin LI 
41673f0a83dSXin LI     if (alt_file == 0)
41773f0a83dSXin LI 	alt_file = my_altfile;
41873f0a83dSXin LI 
41973f0a83dSXin LI     if (source == 0) {
42073f0a83dSXin LI 	failed("copy_input (source)");
42173f0a83dSXin LI     } else if ((target = open_tempfile(alt_file)) == 0) {
42273f0a83dSXin LI 	failed("copy_input (target)");
42373f0a83dSXin LI     } else {
42473f0a83dSXin LI 	clearerr(source);
42573f0a83dSXin LI 	for (;;) {
42673f0a83dSXin LI 	    ch = fgetc(source);
42773f0a83dSXin LI 	    if (feof(source)) {
42873f0a83dSXin LI 		break;
42973f0a83dSXin LI 	    } else if (ferror(source)) {
43073f0a83dSXin LI 		failed(filename);
43173f0a83dSXin LI 	    } else if (ch == 0) {
43273f0a83dSXin LI 		/* don't loop in case someone wants to convert /dev/zero */
43373f0a83dSXin LI 		fprintf(stderr, "%s: %s is not a text-file\n", _nc_progname, filename);
43473f0a83dSXin LI 		ExitProgram(EXIT_FAILURE);
43573f0a83dSXin LI 	    }
43673f0a83dSXin LI 	    fputc(ch, target);
43773f0a83dSXin LI 	}
43873f0a83dSXin LI 	fclose(source);
43973f0a83dSXin LI 	/*
44073f0a83dSXin LI 	 * rewind() does not force the target file's data to disk (not does
44173f0a83dSXin LI 	 * fflush()...).  So open a second stream on the data and then close
44273f0a83dSXin LI 	 * the one that we were writing on before starting to read from the
44373f0a83dSXin LI 	 * second stream.
44473f0a83dSXin LI 	 */
44573f0a83dSXin LI 	result = fopen(alt_file, "r+");
44673f0a83dSXin LI 	fclose(target);
44773f0a83dSXin LI 	to_remove = strdup(alt_file);
44873f0a83dSXin LI     }
44973f0a83dSXin LI     return result;
45073f0a83dSXin LI }
45173f0a83dSXin LI 
45273f0a83dSXin LI static FILE *
45373f0a83dSXin LI open_input(const char *filename, char *alt_file)
45473f0a83dSXin LI {
45573f0a83dSXin LI     FILE *fp;
45618259542SPeter Wemm     struct stat sb;
45773f0a83dSXin LI     int mode;
45873f0a83dSXin LI 
45973f0a83dSXin LI     if (!strcmp(filename, "-")) {
46073f0a83dSXin LI 	fp = copy_input(stdin, STDIN_NAME, alt_file);
46173f0a83dSXin LI     } else if (stat(filename, &sb) < 0) {
46273f0a83dSXin LI 	fprintf(stderr, "%s: %s %s\n", _nc_progname, filename, strerror(errno));
46373f0a83dSXin LI 	ExitProgram(EXIT_FAILURE);
46473f0a83dSXin LI     } else if ((mode = (sb.st_mode & S_IFMT)) == S_IFDIR
465aae38d10SBaptiste Daroussin 	       || (mode != S_IFREG && mode != S_IFCHR && mode != S_IFIFO)) {
46673f0a83dSXin LI 	fprintf(stderr, "%s: %s is not a file\n", _nc_progname, filename);
46773f0a83dSXin LI 	ExitProgram(EXIT_FAILURE);
46873f0a83dSXin LI     } else {
46973f0a83dSXin LI 	fp = fopen(filename, "r");
47018259542SPeter Wemm 
47118259542SPeter Wemm 	if (fp == 0) {
47218259542SPeter Wemm 	    fprintf(stderr, "%s: Can't open %s\n", _nc_progname, filename);
4734a1a9510SRong-En Fan 	    ExitProgram(EXIT_FAILURE);
47418259542SPeter Wemm 	}
47573f0a83dSXin LI 	if (mode != S_IFREG) {
47673f0a83dSXin LI 	    if (alt_file != 0) {
47773f0a83dSXin LI 		FILE *fp2 = copy_input(fp, filename, alt_file);
47873f0a83dSXin LI 		fp = fp2;
47973f0a83dSXin LI 	    } else {
48018259542SPeter Wemm 		fprintf(stderr, "%s: %s is not a file\n", _nc_progname, filename);
4814a1a9510SRong-En Fan 		ExitProgram(EXIT_FAILURE);
48218259542SPeter Wemm 	    }
48373f0a83dSXin LI 	}
48473f0a83dSXin LI     }
48518259542SPeter Wemm     return fp;
48618259542SPeter Wemm }
48718259542SPeter Wemm 
4880e3d5408SPeter Wemm /* Parse the "-e" option-value into a list of names */
4895ca44d1cSRong-En Fan static char **
49015589c42SPeter Wemm make_namelist(char *src)
4910e3d5408SPeter Wemm {
4925ca44d1cSRong-En Fan     char **dst = 0;
4930e3d5408SPeter Wemm 
4940e3d5408SPeter Wemm     char *s, *base;
4950e3d5408SPeter Wemm     unsigned pass, n, nn;
4960e3d5408SPeter Wemm     char buffer[BUFSIZ];
4970e3d5408SPeter Wemm 
4980e3d5408SPeter Wemm     if (src == 0) {
4990e3d5408SPeter Wemm 	/* EMPTY */ ;
5000e3d5408SPeter Wemm     } else if (strchr(src, '/') != 0) {		/* a filename */
50173f0a83dSXin LI 	FILE *fp = open_input(src, (char *) 0);
5020e3d5408SPeter Wemm 
5030e3d5408SPeter Wemm 	for (pass = 1; pass <= 2; pass++) {
5040e3d5408SPeter Wemm 	    nn = 0;
5050e3d5408SPeter Wemm 	    while (fgets(buffer, sizeof(buffer), fp) != 0) {
5060e3d5408SPeter Wemm 		if ((s = stripped(buffer)) != 0) {
5070e3d5408SPeter Wemm 		    if (dst != 0)
5080e3d5408SPeter Wemm 			dst[nn] = s;
5095ca44d1cSRong-En Fan 		    else
5105ca44d1cSRong-En Fan 			free(s);
5110e3d5408SPeter Wemm 		    nn++;
5120e3d5408SPeter Wemm 		}
5130e3d5408SPeter Wemm 	    }
5140e3d5408SPeter Wemm 	    if (pass == 1) {
51573f0a83dSXin LI 		if ((dst = typeCalloc(char *, nn + 1)) == 0)
51673f0a83dSXin LI 		      failed("make_namelist");
5170e3d5408SPeter Wemm 		rewind(fp);
5180e3d5408SPeter Wemm 	    }
5190e3d5408SPeter Wemm 	}
5200e3d5408SPeter Wemm 	fclose(fp);
5210e3d5408SPeter Wemm     } else {			/* literal list of names */
5220e3d5408SPeter Wemm 	for (pass = 1; pass <= 2; pass++) {
5230e3d5408SPeter Wemm 	    for (n = nn = 0, base = src;; n++) {
5240e3d5408SPeter Wemm 		int mark = src[n];
5250e3d5408SPeter Wemm 		if (mark == ',' || mark == '\0') {
5260e3d5408SPeter Wemm 		    if (pass == 1) {
5270e3d5408SPeter Wemm 			nn++;
5280e3d5408SPeter Wemm 		    } else {
5290e3d5408SPeter Wemm 			src[n] = '\0';
5300e3d5408SPeter Wemm 			if ((s = stripped(base)) != 0)
5310e3d5408SPeter Wemm 			    dst[nn++] = s;
5320e3d5408SPeter Wemm 			base = &src[n + 1];
5330e3d5408SPeter Wemm 		    }
5340e3d5408SPeter Wemm 		}
5350e3d5408SPeter Wemm 		if (mark == '\0')
5360e3d5408SPeter Wemm 		    break;
5370e3d5408SPeter Wemm 	    }
53873f0a83dSXin LI 	    if (pass == 1) {
53973f0a83dSXin LI 		if ((dst = typeCalloc(char *, nn + 1)) == 0)
54073f0a83dSXin LI 		      failed("make_namelist");
54173f0a83dSXin LI 	    }
5420e3d5408SPeter Wemm 	}
5430e3d5408SPeter Wemm     }
5445ca44d1cSRong-En Fan     if (showsummary && (dst != 0)) {
5450e3d5408SPeter Wemm 	fprintf(log_fp, "Entries that will be compiled:\n");
5460e3d5408SPeter Wemm 	for (n = 0; dst[n] != 0; n++)
5474a1a9510SRong-En Fan 	    fprintf(log_fp, "%u:%s\n", n + 1, dst[n]);
5480e3d5408SPeter Wemm     }
5490e3d5408SPeter Wemm     return dst;
5500e3d5408SPeter Wemm }
5510e3d5408SPeter Wemm 
55215589c42SPeter Wemm static bool
5535ca44d1cSRong-En Fan matches(char **needle, const char *haystack)
5540e3d5408SPeter Wemm /* does entry in needle list match |-separated field in haystack? */
5550e3d5408SPeter Wemm {
5560e3d5408SPeter Wemm     bool code = FALSE;
5570e3d5408SPeter Wemm     size_t n;
5580e3d5408SPeter Wemm 
55915589c42SPeter Wemm     if (needle != 0) {
56015589c42SPeter Wemm 	for (n = 0; needle[n] != 0; n++) {
56115589c42SPeter Wemm 	    if (_nc_name_match(haystack, needle[n], "|")) {
5620e3d5408SPeter Wemm 		code = TRUE;
5630e3d5408SPeter Wemm 		break;
5640e3d5408SPeter Wemm 	    }
5650e3d5408SPeter Wemm 	}
56615589c42SPeter Wemm     } else
5670e3d5408SPeter Wemm 	code = TRUE;
5680e3d5408SPeter Wemm     return (code);
5690e3d5408SPeter Wemm }
5700e3d5408SPeter Wemm 
57173f0a83dSXin LI static char *
57273f0a83dSXin LI valid_db_path(const char *nominal)
57315589c42SPeter Wemm {
57473f0a83dSXin LI     struct stat sb;
57573f0a83dSXin LI #if USE_HASHED_DB
57673f0a83dSXin LI     char suffix[] = DBM_SUFFIX;
57773f0a83dSXin LI     size_t need = strlen(nominal) + sizeof(suffix);
57873f0a83dSXin LI     char *result = malloc(need);
57973f0a83dSXin LI 
58073f0a83dSXin LI     if (result == 0)
58173f0a83dSXin LI 	failed("valid_db_path");
58273f0a83dSXin LI     _nc_STRCPY(result, nominal, need);
58373f0a83dSXin LI     if (strcmp(result + need - sizeof(suffix), suffix)) {
58473f0a83dSXin LI 	_nc_STRCAT(result, suffix, need);
58573f0a83dSXin LI     }
58615589c42SPeter Wemm #else
58773f0a83dSXin LI     char *result = strdup(nominal);
58815589c42SPeter Wemm #endif
58973f0a83dSXin LI 
59073f0a83dSXin LI     DEBUG(1, ("** stat(%s)", result));
59173f0a83dSXin LI     if (stat(result, &sb) >= 0) {
59273f0a83dSXin LI #if USE_HASHED_DB
59373f0a83dSXin LI 	if (!S_ISREG(sb.st_mode)
59473f0a83dSXin LI 	    || access(result, R_OK | W_OK) != 0) {
59573f0a83dSXin LI 	    DEBUG(1, ("...not a writable file"));
59673f0a83dSXin LI 	    free(result);
59773f0a83dSXin LI 	    result = 0;
59873f0a83dSXin LI 	}
59973f0a83dSXin LI #else
60073f0a83dSXin LI 	if (!S_ISDIR(sb.st_mode)
60173f0a83dSXin LI 	    || access(result, R_OK | W_OK | X_OK) != 0) {
60273f0a83dSXin LI 	    DEBUG(1, ("...not a writable directory"));
60373f0a83dSXin LI 	    free(result);
60473f0a83dSXin LI 	    result = 0;
60573f0a83dSXin LI 	}
60673f0a83dSXin LI #endif
60773f0a83dSXin LI     } else {
60873f0a83dSXin LI 	/* check if parent is directory and is writable */
60973f0a83dSXin LI 	unsigned leaf = _nc_pathlast(result);
61073f0a83dSXin LI 
61173f0a83dSXin LI 	DEBUG(1, ("...not found"));
61273f0a83dSXin LI 	if (leaf) {
61373f0a83dSXin LI 	    char save = result[leaf];
61473f0a83dSXin LI 	    result[leaf] = 0;
61573f0a83dSXin LI 	    if (stat(result, &sb) >= 0
61673f0a83dSXin LI 		&& S_ISDIR(sb.st_mode)
61773f0a83dSXin LI 		&& access(result, R_OK | W_OK | X_OK) == 0) {
61873f0a83dSXin LI 		result[leaf] = save;
61973f0a83dSXin LI 	    } else {
62073f0a83dSXin LI 		DEBUG(1, ("...parent directory %s is not writable", result));
62173f0a83dSXin LI 		free(result);
62273f0a83dSXin LI 		result = 0;
62373f0a83dSXin LI 	    }
62473f0a83dSXin LI 	} else {
62573f0a83dSXin LI 	    DEBUG(1, ("... no parent directory"));
62673f0a83dSXin LI 	    free(result);
62773f0a83dSXin LI 	    result = 0;
62873f0a83dSXin LI 	}
62973f0a83dSXin LI     }
63015589c42SPeter Wemm     return result;
63115589c42SPeter Wemm }
63215589c42SPeter Wemm 
63373f0a83dSXin LI /*
63473f0a83dSXin LI  * Show the databases to which tic could write.  The location to which it
63573f0a83dSXin LI  * writes is always the first one.  If none are writable, print an error
63673f0a83dSXin LI  * message.
63773f0a83dSXin LI  */
63873f0a83dSXin LI static void
63973f0a83dSXin LI show_databases(const char *outdir)
64073f0a83dSXin LI {
64173f0a83dSXin LI     bool specific = (outdir != 0) || getenv("TERMINFO") != 0;
64273f0a83dSXin LI     char *result;
64373f0a83dSXin LI     const char *tried = 0;
64473f0a83dSXin LI 
64573f0a83dSXin LI     if (outdir == 0) {
64673f0a83dSXin LI 	outdir = _nc_tic_dir(0);
64773f0a83dSXin LI     }
64873f0a83dSXin LI     if ((result = valid_db_path(outdir)) != 0) {
64973f0a83dSXin LI 	printf("%s\n", result);
65073f0a83dSXin LI 	free(result);
65173f0a83dSXin LI     } else {
65273f0a83dSXin LI 	tried = outdir;
65373f0a83dSXin LI     }
65473f0a83dSXin LI 
65573f0a83dSXin LI     if ((outdir = _nc_home_terminfo())) {
65673f0a83dSXin LI 	if ((result = valid_db_path(outdir)) != 0) {
65773f0a83dSXin LI 	    printf("%s\n", result);
65873f0a83dSXin LI 	    free(result);
65973f0a83dSXin LI 	} else if (!specific) {
66073f0a83dSXin LI 	    tried = outdir;
66173f0a83dSXin LI 	}
66273f0a83dSXin LI     }
66373f0a83dSXin LI 
66473f0a83dSXin LI     /*
66573f0a83dSXin LI      * If we can write in neither location, give an error message.
66673f0a83dSXin LI      */
66773f0a83dSXin LI     if (tried) {
66873f0a83dSXin LI 	fflush(stdout);
66973f0a83dSXin LI 	fprintf(stderr, "%s: %s (no permission)\n", _nc_progname, tried);
67073f0a83dSXin LI 	ExitProgram(EXIT_FAILURE);
67173f0a83dSXin LI     }
67273f0a83dSXin LI }
67373f0a83dSXin LI 
674aae38d10SBaptiste Daroussin static void
675aae38d10SBaptiste Daroussin add_digit(int *target, int source)
676aae38d10SBaptiste Daroussin {
677aae38d10SBaptiste Daroussin     *target = (*target * 10) + (source - '0');
678aae38d10SBaptiste Daroussin }
67973f0a83dSXin LI 
68015589c42SPeter Wemm int
68115589c42SPeter Wemm main(int argc, char *argv[])
6820e3d5408SPeter Wemm {
6830e3d5408SPeter Wemm     char my_tmpname[PATH_MAX];
68473f0a83dSXin LI     char my_altfile[PATH_MAX];
68573f0a83dSXin LI     int v_opt = -1;
6860e3d5408SPeter Wemm     int smart_defaults = TRUE;
6870e3d5408SPeter Wemm     char *termcap;
6880e3d5408SPeter Wemm     ENTRY *qp;
6890e3d5408SPeter Wemm 
6900e3d5408SPeter Wemm     int this_opt, last_opt = '?';
6910e3d5408SPeter Wemm 
6920e3d5408SPeter Wemm     int outform = F_TERMINFO;	/* output format */
6930e3d5408SPeter Wemm     int sortmode = S_TERMINFO;	/* sort_mode */
6940e3d5408SPeter Wemm 
6950e3d5408SPeter Wemm     int width = 60;
69673f0a83dSXin LI     int height = 65535;
6970e3d5408SPeter Wemm     bool formatted = FALSE;	/* reformat complex strings? */
6984a1a9510SRong-En Fan     bool literal = FALSE;	/* suppress post-processing? */
6990e3d5408SPeter Wemm     int numbers = 0;		/* format "%'char'" to/from "%{number}" */
7000e3d5408SPeter Wemm     bool forceresolve = FALSE;	/* force resolution */
7010e3d5408SPeter Wemm     bool limited = TRUE;
7020e3d5408SPeter Wemm     char *tversion = (char *) NULL;
7030e3d5408SPeter Wemm     const char *source_file = "terminfo";
7040e3d5408SPeter Wemm     char *outdir = (char *) NULL;
7050e3d5408SPeter Wemm     bool check_only = FALSE;
7064a1a9510SRong-En Fan     bool suppress_untranslatable = FALSE;
707aae38d10SBaptiste Daroussin     int quickdump = 0;
708aae38d10SBaptiste Daroussin     bool quiet = FALSE;
709aae38d10SBaptiste Daroussin     bool wrap_strings = FALSE;
7100e3d5408SPeter Wemm 
7110e3d5408SPeter Wemm     log_fp = stderr;
7120e3d5408SPeter Wemm 
71339f2269fSPeter Wemm     _nc_progname = _nc_rootname(argv[0]);
71473f0a83dSXin LI     atexit(cleanup);
7150e3d5408SPeter Wemm 
71606bfebdeSXin LI     if ((infodump = same_program(_nc_progname, PROG_CAPTOINFO)) != FALSE) {
71715589c42SPeter Wemm 	outform = F_TERMINFO;
71815589c42SPeter Wemm 	sortmode = S_TERMINFO;
71915589c42SPeter Wemm     }
72006bfebdeSXin LI     if ((capdump = same_program(_nc_progname, PROG_INFOTOCAP)) != FALSE) {
72115589c42SPeter Wemm 	outform = F_TERMCAP;
72215589c42SPeter Wemm 	sortmode = S_TERMCAP;
72315589c42SPeter Wemm     }
7240e3d5408SPeter Wemm #if NCURSES_XNAMES
7250e3d5408SPeter Wemm     use_extended_names(FALSE);
7260e3d5408SPeter Wemm #endif
72773f0a83dSXin LI     _nc_strict_bsd = 0;
7280e3d5408SPeter Wemm 
7290e3d5408SPeter Wemm     /*
7300e3d5408SPeter Wemm      * Processing arguments is a little complicated, since someone made a
7310e3d5408SPeter Wemm      * design decision to allow the numeric values for -w, -v options to
7320e3d5408SPeter Wemm      * be optional.
7330e3d5408SPeter Wemm      */
73415589c42SPeter Wemm     while ((this_opt = getopt(argc, argv,
735aae38d10SBaptiste Daroussin 			      "0123456789CDIKLNQR:TUVWace:fGgo:qrstvwx")) != -1) {
7360e3d5408SPeter Wemm 	if (isdigit(this_opt)) {
7370e3d5408SPeter Wemm 	    switch (last_opt) {
738aae38d10SBaptiste Daroussin 	    case 'Q':
739aae38d10SBaptiste Daroussin 		add_digit(&quickdump, this_opt);
740aae38d10SBaptiste Daroussin 		break;
7410e3d5408SPeter Wemm 	    case 'v':
742aae38d10SBaptiste Daroussin 		add_digit(&v_opt, this_opt);
7430e3d5408SPeter Wemm 		break;
7440e3d5408SPeter Wemm 	    case 'w':
745aae38d10SBaptiste Daroussin 		add_digit(&width, this_opt);
7460e3d5408SPeter Wemm 		break;
7470e3d5408SPeter Wemm 	    default:
74873f0a83dSXin LI 		switch (this_opt) {
74973f0a83dSXin LI 		case '0':
75073f0a83dSXin LI 		    last_opt = this_opt;
75173f0a83dSXin LI 		    width = 65535;
75273f0a83dSXin LI 		    height = 1;
75373f0a83dSXin LI 		    break;
75473f0a83dSXin LI 		case '1':
7550e3d5408SPeter Wemm 		    last_opt = this_opt;
7560e3d5408SPeter Wemm 		    width = 0;
75773f0a83dSXin LI 		    break;
75873f0a83dSXin LI 		default:
75973f0a83dSXin LI 		    usage();
76073f0a83dSXin LI 		}
7610e3d5408SPeter Wemm 	    }
7620e3d5408SPeter Wemm 	    continue;
7630e3d5408SPeter Wemm 	}
7640e3d5408SPeter Wemm 	switch (this_opt) {
76573f0a83dSXin LI 	case 'K':
76673f0a83dSXin LI 	    _nc_strict_bsd = 1;
76773f0a83dSXin LI 	    /* the initial version of -K in 20110730 fell-thru here, but the
76873f0a83dSXin LI 	     * same flag is useful when reading sources -TD
76973f0a83dSXin LI 	     */
77073f0a83dSXin LI 	    break;
7710e3d5408SPeter Wemm 	case 'C':
7720e3d5408SPeter Wemm 	    capdump = TRUE;
7730e3d5408SPeter Wemm 	    outform = F_TERMCAP;
7740e3d5408SPeter Wemm 	    sortmode = S_TERMCAP;
7750e3d5408SPeter Wemm 	    break;
77673f0a83dSXin LI 	case 'D':
77773f0a83dSXin LI 	    debug_level = VtoTrace(v_opt);
77873f0a83dSXin LI 	    set_trace_level(debug_level);
77973f0a83dSXin LI 	    show_databases(outdir);
78073f0a83dSXin LI 	    ExitProgram(EXIT_SUCCESS);
78173f0a83dSXin LI 	    break;
7820e3d5408SPeter Wemm 	case 'I':
7830e3d5408SPeter Wemm 	    infodump = TRUE;
7840e3d5408SPeter Wemm 	    outform = F_TERMINFO;
7850e3d5408SPeter Wemm 	    sortmode = S_TERMINFO;
7860e3d5408SPeter Wemm 	    break;
7870e3d5408SPeter Wemm 	case 'L':
7880e3d5408SPeter Wemm 	    infodump = TRUE;
7890e3d5408SPeter Wemm 	    outform = F_VARIABLE;
7900e3d5408SPeter Wemm 	    sortmode = S_VARIABLE;
7910e3d5408SPeter Wemm 	    break;
7920e3d5408SPeter Wemm 	case 'N':
7930e3d5408SPeter Wemm 	    smart_defaults = FALSE;
7944a1a9510SRong-En Fan 	    literal = TRUE;
7950e3d5408SPeter Wemm 	    break;
796aae38d10SBaptiste Daroussin 	case 'Q':
797aae38d10SBaptiste Daroussin 	    quickdump = 0;
798aae38d10SBaptiste Daroussin 	    break;
7990e3d5408SPeter Wemm 	case 'R':
8000e3d5408SPeter Wemm 	    tversion = optarg;
8010e3d5408SPeter Wemm 	    break;
8020e3d5408SPeter Wemm 	case 'T':
8030e3d5408SPeter Wemm 	    limited = FALSE;
8040e3d5408SPeter Wemm 	    break;
8054a1a9510SRong-En Fan 	case 'U':
8064a1a9510SRong-En Fan 	    literal = TRUE;
8074a1a9510SRong-En Fan 	    break;
8080e3d5408SPeter Wemm 	case 'V':
80918259542SPeter Wemm 	    puts(curses_version());
8105d08fb1fSRong-En Fan 	    ExitProgram(EXIT_SUCCESS);
811aae38d10SBaptiste Daroussin 	case 'W':
812aae38d10SBaptiste Daroussin 	    wrap_strings = TRUE;
813aae38d10SBaptiste Daroussin 	    break;
8140e3d5408SPeter Wemm 	case 'c':
8150e3d5408SPeter Wemm 	    check_only = TRUE;
8160e3d5408SPeter Wemm 	    break;
8170e3d5408SPeter Wemm 	case 'e':
8180e3d5408SPeter Wemm 	    namelst = make_namelist(optarg);
8190e3d5408SPeter Wemm 	    break;
8200e3d5408SPeter Wemm 	case 'f':
8210e3d5408SPeter Wemm 	    formatted = TRUE;
8220e3d5408SPeter Wemm 	    break;
8230e3d5408SPeter Wemm 	case 'G':
8240e3d5408SPeter Wemm 	    numbers = 1;
8250e3d5408SPeter Wemm 	    break;
8260e3d5408SPeter Wemm 	case 'g':
8270e3d5408SPeter Wemm 	    numbers = -1;
8280e3d5408SPeter Wemm 	    break;
8290e3d5408SPeter Wemm 	case 'o':
8300e3d5408SPeter Wemm 	    outdir = optarg;
8310e3d5408SPeter Wemm 	    break;
832aae38d10SBaptiste Daroussin 	case 'q':
833aae38d10SBaptiste Daroussin 	    quiet = TRUE;
834aae38d10SBaptiste Daroussin 	    break;
8350e3d5408SPeter Wemm 	case 'r':
8360e3d5408SPeter Wemm 	    forceresolve = TRUE;
8370e3d5408SPeter Wemm 	    break;
8380e3d5408SPeter Wemm 	case 's':
8390e3d5408SPeter Wemm 	    showsummary = TRUE;
8400e3d5408SPeter Wemm 	    break;
8410e3d5408SPeter Wemm 	case 'v':
8420e3d5408SPeter Wemm 	    v_opt = 0;
8430e3d5408SPeter Wemm 	    break;
8440e3d5408SPeter Wemm 	case 'w':
8450e3d5408SPeter Wemm 	    width = 0;
8460e3d5408SPeter Wemm 	    break;
8470e3d5408SPeter Wemm #if NCURSES_XNAMES
8484a1a9510SRong-En Fan 	case 't':
8494a1a9510SRong-En Fan 	    _nc_disable_period = FALSE;
8504a1a9510SRong-En Fan 	    suppress_untranslatable = TRUE;
8514a1a9510SRong-En Fan 	    break;
85215589c42SPeter Wemm 	case 'a':
85315589c42SPeter Wemm 	    _nc_disable_period = TRUE;
85415589c42SPeter Wemm 	    /* FALLTHRU */
8550e3d5408SPeter Wemm 	case 'x':
8560e3d5408SPeter Wemm 	    use_extended_names(TRUE);
857aae38d10SBaptiste Daroussin 	    using_extensions = TRUE;
8580e3d5408SPeter Wemm 	    break;
8590e3d5408SPeter Wemm #endif
8600e3d5408SPeter Wemm 	default:
8610e3d5408SPeter Wemm 	    usage();
8620e3d5408SPeter Wemm 	}
8630e3d5408SPeter Wemm 	last_opt = this_opt;
8640e3d5408SPeter Wemm     }
8650e3d5408SPeter Wemm 
86673f0a83dSXin LI     debug_level = VtoTrace(v_opt);
86715589c42SPeter Wemm     set_trace_level(debug_level);
8680e3d5408SPeter Wemm 
86915589c42SPeter Wemm     if (_nc_tracing) {
8704a1a9510SRong-En Fan 	save_check_termtype = _nc_check_termtype2;
8714a1a9510SRong-En Fan 	_nc_check_termtype2 = check_termtype;
8720e3d5408SPeter Wemm     }
87318259542SPeter Wemm #if !HAVE_BIG_CORE
8740e3d5408SPeter Wemm     /*
8750e3d5408SPeter Wemm      * Aaargh! immedhook seriously hoses us!
8760e3d5408SPeter Wemm      *
8770e3d5408SPeter Wemm      * One problem with immedhook is it means we can't do -e.  Problem
8780e3d5408SPeter Wemm      * is that we can't guarantee that for each terminal listed, all the
8790e3d5408SPeter Wemm      * terminals it depends on will have been kept in core for reference
8800e3d5408SPeter Wemm      * resolution -- in fact it's certain the primitive types at the end
8810e3d5408SPeter Wemm      * of reference chains *won't* be in core unless they were explicitly
8820e3d5408SPeter Wemm      * in the select list themselves.
8830e3d5408SPeter Wemm      */
88415589c42SPeter Wemm     if (namelst && (!infodump && !capdump)) {
8850e3d5408SPeter Wemm 	(void) fprintf(stderr,
88673f0a83dSXin LI 		       "%s: Sorry, -e can't be used without -I or -C\n",
88773f0a83dSXin LI 		       _nc_progname);
8884a1a9510SRong-En Fan 	ExitProgram(EXIT_FAILURE);
8890e3d5408SPeter Wemm     }
8900e3d5408SPeter Wemm #endif /* HAVE_BIG_CORE */
8910e3d5408SPeter Wemm 
8920e3d5408SPeter Wemm     if (optind < argc) {
8930e3d5408SPeter Wemm 	source_file = argv[optind++];
8940e3d5408SPeter Wemm 	if (optind < argc) {
8950e3d5408SPeter Wemm 	    fprintf(stderr,
8960e3d5408SPeter Wemm 		    "%s: Too many file names.  Usage:\n\t%s %s",
8970e3d5408SPeter Wemm 		    _nc_progname,
8980e3d5408SPeter Wemm 		    _nc_progname,
8990e3d5408SPeter Wemm 		    usage_string);
9004a1a9510SRong-En Fan 	    ExitProgram(EXIT_FAILURE);
9010e3d5408SPeter Wemm 	}
9020e3d5408SPeter Wemm     } else {
9030e3d5408SPeter Wemm 	if (infodump == TRUE) {
9040e3d5408SPeter Wemm 	    /* captoinfo's no-argument case */
9050e3d5408SPeter Wemm 	    source_file = "/etc/termcap";
9060e3d5408SPeter Wemm 	    if ((termcap = getenv("TERMCAP")) != 0
9070e3d5408SPeter Wemm 		&& (namelst = make_namelist(getenv("TERM"))) != 0) {
9080e3d5408SPeter Wemm 		if (access(termcap, F_OK) == 0) {
9090e3d5408SPeter Wemm 		    /* file exists */
9100e3d5408SPeter Wemm 		    source_file = termcap;
91173f0a83dSXin LI 		} else {
91273f0a83dSXin LI 		    if ((tmp_fp = open_tempfile(my_tmpname)) != 0) {
91315589c42SPeter Wemm 			source_file = my_tmpname;
9140e3d5408SPeter Wemm 			fprintf(tmp_fp, "%s\n", termcap);
9150e3d5408SPeter Wemm 			fclose(tmp_fp);
91673f0a83dSXin LI 			tmp_fp = open_input(source_file, (char *) 0);
9170e3d5408SPeter Wemm 			to_remove = source_file;
9180e3d5408SPeter Wemm 		    } else {
9190e3d5408SPeter Wemm 			failed("tmpnam");
9200e3d5408SPeter Wemm 		    }
9210e3d5408SPeter Wemm 		}
92273f0a83dSXin LI 	    }
9230e3d5408SPeter Wemm 	} else {
9240e3d5408SPeter Wemm 	    /* tic */
9250e3d5408SPeter Wemm 	    fprintf(stderr,
9260e3d5408SPeter Wemm 		    "%s: File name needed.  Usage:\n\t%s %s",
9270e3d5408SPeter Wemm 		    _nc_progname,
9280e3d5408SPeter Wemm 		    _nc_progname,
9290e3d5408SPeter Wemm 		    usage_string);
9304a1a9510SRong-En Fan 	    ExitProgram(EXIT_FAILURE);
9310e3d5408SPeter Wemm 	}
9320e3d5408SPeter Wemm     }
9330e3d5408SPeter Wemm 
93473f0a83dSXin LI     if (tmp_fp == 0) {
93573f0a83dSXin LI 	tmp_fp = open_input(source_file, my_altfile);
93673f0a83dSXin LI 	if (!strcmp(source_file, "-")) {
93773f0a83dSXin LI 	    source_file = STDIN_NAME;
93873f0a83dSXin LI 	}
93973f0a83dSXin LI     }
9400e3d5408SPeter Wemm 
941aae38d10SBaptiste Daroussin     if (infodump || check_only) {
9420e3d5408SPeter Wemm 	dump_init(tversion,
943aae38d10SBaptiste Daroussin 		  (smart_defaults
9440e3d5408SPeter Wemm 		   ? outform
945aae38d10SBaptiste Daroussin 		   : F_LITERAL),
946aae38d10SBaptiste Daroussin 		  sortmode,
947aae38d10SBaptiste Daroussin 		  wrap_strings, width, height,
948aae38d10SBaptiste Daroussin 		  debug_level, formatted || check_only, check_only, quickdump);
94973f0a83dSXin LI     } else if (capdump) {
9500e3d5408SPeter Wemm 	dump_init(tversion,
9510e3d5408SPeter Wemm 		  outform,
952aae38d10SBaptiste Daroussin 		  sortmode,
953aae38d10SBaptiste Daroussin 		  wrap_strings, width, height,
954aae38d10SBaptiste Daroussin 		  debug_level, FALSE, FALSE, FALSE);
95573f0a83dSXin LI     }
9560e3d5408SPeter Wemm 
9570e3d5408SPeter Wemm     /* parse entries out of the source file */
9580e3d5408SPeter Wemm     _nc_set_source(source_file);
95918259542SPeter Wemm #if !HAVE_BIG_CORE
9600e3d5408SPeter Wemm     if (!(check_only || infodump || capdump))
9610e3d5408SPeter Wemm 	_nc_set_writedir(outdir);
9620e3d5408SPeter Wemm #endif /* HAVE_BIG_CORE */
9630e3d5408SPeter Wemm     _nc_read_entry_source(tmp_fp, (char *) NULL,
9644a1a9510SRong-En Fan 			  !smart_defaults || literal, FALSE,
9654a1a9510SRong-En Fan 			  ((check_only || infodump || capdump)
9664a1a9510SRong-En Fan 			   ? NULLHOOK
9674a1a9510SRong-En Fan 			   : immedhook));
9680e3d5408SPeter Wemm 
9690e3d5408SPeter Wemm     /* do use resolution */
9700e3d5408SPeter Wemm     if (check_only || (!infodump && !capdump) || forceresolve) {
9714a1a9510SRong-En Fan 	if (!_nc_resolve_uses2(TRUE, literal) && !check_only) {
9724a1a9510SRong-En Fan 	    ExitProgram(EXIT_FAILURE);
9730e3d5408SPeter Wemm 	}
9740e3d5408SPeter Wemm     }
9750e3d5408SPeter Wemm 
9760e3d5408SPeter Wemm     /* length check */
977aae38d10SBaptiste Daroussin     if (check_only && limited && (capdump || infodump)) {
97815589c42SPeter Wemm 	for_entry_list(qp) {
97915589c42SPeter Wemm 	    if (matches(namelst, qp->tterm.term_names)) {
9804a1a9510SRong-En Fan 		int len = fmt_entry(&qp->tterm, NULL, FALSE, TRUE, infodump, numbers);
9810e3d5408SPeter Wemm 
9820e3d5408SPeter Wemm 		if (len > (infodump ? MAX_TERMINFO_LENGTH : MAX_TERMCAP_LENGTH))
9830e3d5408SPeter Wemm 		    (void) fprintf(stderr,
984aae38d10SBaptiste Daroussin 				   "%s: resolved %s entry is %d bytes long\n",
985aae38d10SBaptiste Daroussin 				   _nc_progname,
9860e3d5408SPeter Wemm 				   _nc_first_name(qp->tterm.term_names),
9870e3d5408SPeter Wemm 				   len);
9880e3d5408SPeter Wemm 	    }
9890e3d5408SPeter Wemm 	}
9900e3d5408SPeter Wemm     }
9910e3d5408SPeter Wemm 
9920e3d5408SPeter Wemm     /* write or dump all entries */
993aae38d10SBaptiste Daroussin     if (check_only) {
994aae38d10SBaptiste Daroussin 	/* this is in case infotocap() generates warnings */
995aae38d10SBaptiste Daroussin 	_nc_curr_col = _nc_curr_line = -1;
996aae38d10SBaptiste Daroussin 
997aae38d10SBaptiste Daroussin 	for_entry_list(qp) {
998aae38d10SBaptiste Daroussin 	    if (matches(namelst, qp->tterm.term_names)) {
999aae38d10SBaptiste Daroussin 		/* this is in case infotocap() generates warnings */
1000aae38d10SBaptiste Daroussin 		_nc_set_type(_nc_first_name(qp->tterm.term_names));
1001aae38d10SBaptiste Daroussin 		_nc_curr_line = (int) qp->startline;
1002aae38d10SBaptiste Daroussin 		repair_acsc(&qp->tterm);
1003aae38d10SBaptiste Daroussin 		dump_entry(&qp->tterm, suppress_untranslatable,
1004aae38d10SBaptiste Daroussin 			   limited, numbers, NULL);
1005aae38d10SBaptiste Daroussin 	    }
1006aae38d10SBaptiste Daroussin 	}
1007aae38d10SBaptiste Daroussin     } else {
100815589c42SPeter Wemm 	if (!infodump && !capdump) {
10090e3d5408SPeter Wemm 	    _nc_set_writedir(outdir);
101015589c42SPeter Wemm 	    for_entry_list(qp) {
10110e3d5408SPeter Wemm 		if (matches(namelst, qp->tterm.term_names))
10120e3d5408SPeter Wemm 		    write_it(qp);
10130e3d5408SPeter Wemm 	    }
101415589c42SPeter Wemm 	} else {
10150e3d5408SPeter Wemm 	    /* this is in case infotocap() generates warnings */
10160e3d5408SPeter Wemm 	    _nc_curr_col = _nc_curr_line = -1;
10170e3d5408SPeter Wemm 
101815589c42SPeter Wemm 	    for_entry_list(qp) {
101915589c42SPeter Wemm 		if (matches(namelst, qp->tterm.term_names)) {
102073f0a83dSXin LI 		    long j = qp->cend - qp->cstart;
10210e3d5408SPeter Wemm 		    int len = 0;
10220e3d5408SPeter Wemm 
10230e3d5408SPeter Wemm 		    /* this is in case infotocap() generates warnings */
10240e3d5408SPeter Wemm 		    _nc_set_type(_nc_first_name(qp->tterm.term_names));
10250e3d5408SPeter Wemm 
1026aae38d10SBaptiste Daroussin 		    if (!quiet) {
10270e3d5408SPeter Wemm 			(void) fseek(tmp_fp, qp->cstart, SEEK_SET);
10284a1a9510SRong-En Fan 			while (j-- > 0) {
1029aae38d10SBaptiste Daroussin 			    int ch = fgetc(tmp_fp);
1030aae38d10SBaptiste Daroussin 			    if (ch == EOF || ferror(tmp_fp)) {
1031aae38d10SBaptiste Daroussin 				break;
1032aae38d10SBaptiste Daroussin 			    } else if (infodump) {
1033aae38d10SBaptiste Daroussin 				(void) putchar(ch);
1034aae38d10SBaptiste Daroussin 			    } else {
1035aae38d10SBaptiste Daroussin 				put_translate(ch);
1036aae38d10SBaptiste Daroussin 			    }
1037aae38d10SBaptiste Daroussin 			}
103815589c42SPeter Wemm 		    }
10390e3d5408SPeter Wemm 
104006bfebdeSXin LI 		    repair_acsc(&qp->tterm);
10414a1a9510SRong-En Fan 		    dump_entry(&qp->tterm, suppress_untranslatable,
10424a1a9510SRong-En Fan 			       limited, numbers, NULL);
104373f0a83dSXin LI 		    for (j = 0; j < (long) qp->nuses; j++)
10444a1a9510SRong-En Fan 			dump_uses(qp->uses[j].name, !capdump);
10454a1a9510SRong-En Fan 		    len = show_entry();
10460e3d5408SPeter Wemm 		    if (debug_level != 0 && !limited)
10470e3d5408SPeter Wemm 			printf("# length=%d\n", len);
10480e3d5408SPeter Wemm 		}
104915589c42SPeter Wemm 	    }
1050aae38d10SBaptiste Daroussin 	    if (!namelst && _nc_tail && !quiet) {
10510e3d5408SPeter Wemm 		int c, oldc = '\0';
10520e3d5408SPeter Wemm 		bool in_comment = FALSE;
10530e3d5408SPeter Wemm 		bool trailing_comment = FALSE;
10540e3d5408SPeter Wemm 
10550e3d5408SPeter Wemm 		(void) fseek(tmp_fp, _nc_tail->cend, SEEK_SET);
105615589c42SPeter Wemm 		while ((c = fgetc(tmp_fp)) != EOF) {
10570e3d5408SPeter Wemm 		    if (oldc == '\n') {
10580e3d5408SPeter Wemm 			if (c == '#') {
10590e3d5408SPeter Wemm 			    trailing_comment = TRUE;
10600e3d5408SPeter Wemm 			    in_comment = TRUE;
10610e3d5408SPeter Wemm 			} else {
10620e3d5408SPeter Wemm 			    in_comment = FALSE;
10630e3d5408SPeter Wemm 			}
10640e3d5408SPeter Wemm 		    }
10650e3d5408SPeter Wemm 		    if (trailing_comment
10660e3d5408SPeter Wemm 			&& (in_comment || (oldc == '\n' && c == '\n')))
10670e3d5408SPeter Wemm 			putchar(c);
10680e3d5408SPeter Wemm 		    oldc = c;
10690e3d5408SPeter Wemm 		}
10700e3d5408SPeter Wemm 	    }
10710e3d5408SPeter Wemm 	}
10720e3d5408SPeter Wemm     }
10730e3d5408SPeter Wemm 
10740e3d5408SPeter Wemm     /* Show the directory into which entries were written, and the total
10750e3d5408SPeter Wemm      * number of entries
10760e3d5408SPeter Wemm      */
10770e3d5408SPeter Wemm     if (showsummary
10780e3d5408SPeter Wemm 	&& (!(check_only || infodump || capdump))) {
10790e3d5408SPeter Wemm 	int total = _nc_tic_written();
10800e3d5408SPeter Wemm 	if (total != 0)
10810e3d5408SPeter Wemm 	    fprintf(log_fp, "%d entries written to %s\n",
10820e3d5408SPeter Wemm 		    total,
10830e3d5408SPeter Wemm 		    _nc_tic_dir((char *) 0));
10840e3d5408SPeter Wemm 	else
10850e3d5408SPeter Wemm 	    fprintf(log_fp, "No entries written\n");
10860e3d5408SPeter Wemm     }
10874a1a9510SRong-En Fan     ExitProgram(EXIT_SUCCESS);
10880e3d5408SPeter Wemm }
10890e3d5408SPeter Wemm 
10900e3d5408SPeter Wemm /*
10910e3d5408SPeter Wemm  * This bit of legerdemain turns all the terminfo variable names into
10920e3d5408SPeter Wemm  * references to locations in the arrays Booleans, Numbers, and Strings ---
10930e3d5408SPeter Wemm  * precisely what's needed (see comp_parse.c).
10940e3d5408SPeter Wemm  */
10950e3d5408SPeter Wemm #undef CUR
10960e3d5408SPeter Wemm #define CUR tp->
10970e3d5408SPeter Wemm 
109815589c42SPeter Wemm /*
10994a1a9510SRong-En Fan  * Check if the alternate character-set capabilities are consistent.
11004a1a9510SRong-En Fan  */
11014a1a9510SRong-En Fan static void
1102aae38d10SBaptiste Daroussin check_acs(TERMTYPE2 *tp)
11034a1a9510SRong-En Fan {
1104aae38d10SBaptiste Daroussin     int vt100_smacs = 0;
1105aae38d10SBaptiste Daroussin     int vt100_rmacs = 0;
1106aae38d10SBaptiste Daroussin     int vt100_enacs = 0;
1107aae38d10SBaptiste Daroussin 
1108aae38d10SBaptiste Daroussin     /*
1109aae38d10SBaptiste Daroussin      * ena_acs is not always necessary, but if it is present, the enter/exit
1110aae38d10SBaptiste Daroussin      * capabilities should be.
1111aae38d10SBaptiste Daroussin      */
1112aae38d10SBaptiste Daroussin     ANDMISSING(ena_acs, enter_alt_charset_mode);
1113aae38d10SBaptiste Daroussin     ANDMISSING(ena_acs, exit_alt_charset_mode);
1114aae38d10SBaptiste Daroussin     PAIRED(exit_alt_charset_mode, exit_alt_charset_mode);
1115aae38d10SBaptiste Daroussin 
1116aae38d10SBaptiste Daroussin     /*
1117aae38d10SBaptiste Daroussin      * vt100-like is frequently used, but perhaps ena_acs is missing, etc.
1118aae38d10SBaptiste Daroussin      */
1119aae38d10SBaptiste Daroussin     if (VALID_STRING(enter_alt_charset_mode)) {
1120aae38d10SBaptiste Daroussin 	vt100_smacs = (!strcmp("\033(0", enter_alt_charset_mode)
1121aae38d10SBaptiste Daroussin 		       ? 2
1122aae38d10SBaptiste Daroussin 		       : (!strcmp("\016", enter_alt_charset_mode)
1123aae38d10SBaptiste Daroussin 			  ? 1
1124aae38d10SBaptiste Daroussin 			  : 0));
1125aae38d10SBaptiste Daroussin     }
1126aae38d10SBaptiste Daroussin     if (VALID_STRING(exit_alt_charset_mode)) {
1127aae38d10SBaptiste Daroussin 	vt100_rmacs = (!strcmp("\033(B", exit_alt_charset_mode)
1128aae38d10SBaptiste Daroussin 		       ? 2
1129aae38d10SBaptiste Daroussin 		       : (!strcmp("\017", exit_alt_charset_mode)
1130aae38d10SBaptiste Daroussin 			  ? 1
1131aae38d10SBaptiste Daroussin 			  : 0));
1132aae38d10SBaptiste Daroussin     }
1133aae38d10SBaptiste Daroussin     if (VALID_STRING(ena_acs)) {
1134aae38d10SBaptiste Daroussin 	vt100_enacs = (!strcmp("\033(B\033)0", ena_acs)
1135aae38d10SBaptiste Daroussin 		       ? 2
1136aae38d10SBaptiste Daroussin 		       : 0);
1137aae38d10SBaptiste Daroussin     }
1138aae38d10SBaptiste Daroussin     if (vt100_rmacs && vt100_smacs && (vt100_rmacs != vt100_smacs)) {
1139aae38d10SBaptiste Daroussin 	_nc_warning("rmacs/smacs are inconsistent");
1140aae38d10SBaptiste Daroussin     }
1141aae38d10SBaptiste Daroussin     if ((vt100_rmacs == 2) && (vt100_smacs == 2) && vt100_enacs) {
1142aae38d10SBaptiste Daroussin 	_nc_warning("rmacs/smacs make enacs redundant");
1143aae38d10SBaptiste Daroussin     }
1144aae38d10SBaptiste Daroussin     if ((vt100_rmacs == 1) && (vt100_smacs == 1) && !vt100_enacs) {
1145aae38d10SBaptiste Daroussin 	_nc_warning("VT100-style rmacs/smacs require enacs");
1146aae38d10SBaptiste Daroussin     }
1147aae38d10SBaptiste Daroussin 
11484a1a9510SRong-En Fan     if (VALID_STRING(acs_chars)) {
11494a1a9510SRong-En Fan 	const char *boxes = "lmkjtuvwqxn";
11504a1a9510SRong-En Fan 	char mapped[256];
11514a1a9510SRong-En Fan 	char missing[256];
11524a1a9510SRong-En Fan 	const char *p;
11534a1a9510SRong-En Fan 	char *q;
11544a1a9510SRong-En Fan 
11554a1a9510SRong-En Fan 	memset(mapped, 0, sizeof(mapped));
11564a1a9510SRong-En Fan 	for (p = acs_chars; *p != '\0'; p += 2) {
11574a1a9510SRong-En Fan 	    if (p[1] == '\0') {
11584a1a9510SRong-En Fan 		_nc_warning("acsc has odd number of characters");
11594a1a9510SRong-En Fan 		break;
11604a1a9510SRong-En Fan 	    }
11614a1a9510SRong-En Fan 	    mapped[UChar(p[0])] = p[1];
11624a1a9510SRong-En Fan 	}
11635d08fb1fSRong-En Fan 
11644a1a9510SRong-En Fan 	if (mapped[UChar('I')] && !mapped[UChar('i')]) {
11654a1a9510SRong-En Fan 	    _nc_warning("acsc refers to 'I', which is probably an error");
11664a1a9510SRong-En Fan 	}
11675d08fb1fSRong-En Fan 
11684a1a9510SRong-En Fan 	for (p = boxes, q = missing; *p != '\0'; ++p) {
11694a1a9510SRong-En Fan 	    if (!mapped[UChar(p[0])]) {
11704a1a9510SRong-En Fan 		*q++ = p[0];
11714a1a9510SRong-En Fan 	    }
11724a1a9510SRong-En Fan 	}
11735d08fb1fSRong-En Fan 	*q = '\0';
11745d08fb1fSRong-En Fan 
11755d08fb1fSRong-En Fan 	assert(strlen(missing) <= strlen(boxes));
11764a1a9510SRong-En Fan 	if (*missing != '\0' && strcmp(missing, boxes)) {
11774a1a9510SRong-En Fan 	    _nc_warning("acsc is missing some line-drawing mapping: %s", missing);
11784a1a9510SRong-En Fan 	}
11794a1a9510SRong-En Fan     }
11804a1a9510SRong-En Fan }
11814a1a9510SRong-En Fan 
1182aae38d10SBaptiste Daroussin static bool
1183aae38d10SBaptiste Daroussin same_color(NCURSES_CONST char *oldcap, NCURSES_CONST char *newcap, int limit)
1184aae38d10SBaptiste Daroussin {
1185aae38d10SBaptiste Daroussin     bool result = FALSE;
1186aae38d10SBaptiste Daroussin     if (limit > 16)
1187aae38d10SBaptiste Daroussin 	limit = 16;
1188aae38d10SBaptiste Daroussin     if (limit >= 8) {
1189aae38d10SBaptiste Daroussin 	int n;
1190aae38d10SBaptiste Daroussin 	int same;
1191aae38d10SBaptiste Daroussin 	for (n = same = 0; n < limit; ++n) {
1192aae38d10SBaptiste Daroussin 	    char *oldvalue = strdup(TPARM_1(oldcap, n));
1193aae38d10SBaptiste Daroussin 	    char *newvalue = strdup(TPARM_1(newcap, n));
1194aae38d10SBaptiste Daroussin 	    same += !strcmp(oldvalue, newvalue);
1195aae38d10SBaptiste Daroussin 	    free(oldvalue);
1196aae38d10SBaptiste Daroussin 	    free(newvalue);
1197aae38d10SBaptiste Daroussin 	}
1198aae38d10SBaptiste Daroussin 	result = (same == limit);
1199aae38d10SBaptiste Daroussin     }
1200aae38d10SBaptiste Daroussin     return result;
1201aae38d10SBaptiste Daroussin }
1202aae38d10SBaptiste Daroussin 
12034a1a9510SRong-En Fan /*
12044a1a9510SRong-En Fan  * Check if the color capabilities are consistent
12054a1a9510SRong-En Fan  */
12064a1a9510SRong-En Fan static void
1207aae38d10SBaptiste Daroussin check_colors(TERMTYPE2 *tp)
12084a1a9510SRong-En Fan {
1209aae38d10SBaptiste Daroussin     char *value;
1210aae38d10SBaptiste Daroussin 
12114a1a9510SRong-En Fan     if ((max_colors > 0) != (max_pairs > 0)
12124a1a9510SRong-En Fan 	|| ((max_colors > max_pairs) && (initialize_pair == 0)))
12134a1a9510SRong-En Fan 	_nc_warning("inconsistent values for max_colors (%d) and max_pairs (%d)",
12144a1a9510SRong-En Fan 		    max_colors, max_pairs);
12154a1a9510SRong-En Fan 
12164a1a9510SRong-En Fan     PAIRED(set_foreground, set_background);
12174a1a9510SRong-En Fan     PAIRED(set_a_foreground, set_a_background);
12184a1a9510SRong-En Fan     PAIRED(set_color_pair, initialize_pair);
12194a1a9510SRong-En Fan 
12204a1a9510SRong-En Fan     if (VALID_STRING(set_foreground)
1221aae38d10SBaptiste Daroussin 	&& VALID_STRING(set_a_foreground)) {
1222aae38d10SBaptiste Daroussin 	if (!_nc_capcmp(set_foreground, set_a_foreground)) {
12234a1a9510SRong-En Fan 	    _nc_warning("expected setf/setaf to be different");
1224aae38d10SBaptiste Daroussin 	} else if (same_color(set_foreground, set_a_foreground, max_colors)) {
1225aae38d10SBaptiste Daroussin 	    _nc_warning("setf/setaf are equivalent");
1226aae38d10SBaptiste Daroussin 	}
1227aae38d10SBaptiste Daroussin     }
12284a1a9510SRong-En Fan 
12294a1a9510SRong-En Fan     if (VALID_STRING(set_background)
1230aae38d10SBaptiste Daroussin 	&& VALID_STRING(set_a_background)) {
1231aae38d10SBaptiste Daroussin 	if (!_nc_capcmp(set_background, set_a_background)) {
12324a1a9510SRong-En Fan 	    _nc_warning("expected setb/setab to be different");
1233aae38d10SBaptiste Daroussin 	} else if (same_color(set_background, set_a_background, max_colors)) {
1234aae38d10SBaptiste Daroussin 	    _nc_warning("setb/setab are equivalent");
1235aae38d10SBaptiste Daroussin 	}
1236aae38d10SBaptiste Daroussin     }
12374a1a9510SRong-En Fan 
12384a1a9510SRong-En Fan     /* see: has_colors() */
12394a1a9510SRong-En Fan     if (VALID_NUMERIC(max_colors) && VALID_NUMERIC(max_pairs)
1240aae38d10SBaptiste Daroussin 	&& ((VALID_STRING(set_foreground)
1241aae38d10SBaptiste Daroussin 	     && VALID_STRING(set_background))
1242aae38d10SBaptiste Daroussin 	    || (VALID_STRING(set_a_foreground)
1243aae38d10SBaptiste Daroussin 		&& VALID_STRING(set_a_background))
12444a1a9510SRong-En Fan 	    || set_color_pair)) {
12454a1a9510SRong-En Fan 	if (!VALID_STRING(orig_pair) && !VALID_STRING(orig_colors))
12464a1a9510SRong-En Fan 	    _nc_warning("expected either op/oc string for resetting colors");
12474a1a9510SRong-En Fan     }
1248aae38d10SBaptiste Daroussin     if (can_change) {
1249aae38d10SBaptiste Daroussin 	if (!VALID_STRING(initialize_pair) &&
1250aae38d10SBaptiste Daroussin 	    !VALID_STRING(initialize_color)) {
1251aae38d10SBaptiste Daroussin 	    _nc_warning("expected initc or initp because ccc is given");
1252aae38d10SBaptiste Daroussin 	}
1253aae38d10SBaptiste Daroussin     } else {
1254aae38d10SBaptiste Daroussin 	if (VALID_STRING(initialize_pair) ||
1255aae38d10SBaptiste Daroussin 	    VALID_STRING(initialize_color)) {
1256aae38d10SBaptiste Daroussin 	    _nc_warning("expected ccc because initc is given");
1257aae38d10SBaptiste Daroussin 	}
1258aae38d10SBaptiste Daroussin     }
1259aae38d10SBaptiste Daroussin     value = tigetstr("RGB");
1260aae38d10SBaptiste Daroussin     if (VALID_STRING(value)) {
1261aae38d10SBaptiste Daroussin 	int r, g, b;
1262aae38d10SBaptiste Daroussin 	char bad;
1263aae38d10SBaptiste Daroussin 	int code = sscanf(value, "%d/%d/%d%c", &r, &g, &b, &bad);
1264aae38d10SBaptiste Daroussin 	if (code != 3 || r <= 0 || g <= 0 || b <= 0) {
1265aae38d10SBaptiste Daroussin 	    _nc_warning("unexpected value for RGB capability: %s", value);
1266aae38d10SBaptiste Daroussin 	}
1267aae38d10SBaptiste Daroussin     }
1268aae38d10SBaptiste Daroussin }
1269aae38d10SBaptiste Daroussin 
1270aae38d10SBaptiste Daroussin static int
1271aae38d10SBaptiste Daroussin csi_length(const char *value)
1272aae38d10SBaptiste Daroussin {
1273aae38d10SBaptiste Daroussin     int result = 0;
1274aae38d10SBaptiste Daroussin 
1275aae38d10SBaptiste Daroussin     if (value[0] == '\033' && value[1] == '[') {
1276aae38d10SBaptiste Daroussin 	result = 2;
1277aae38d10SBaptiste Daroussin     } else if (UChar(value[0]) == 0x9a) {
1278aae38d10SBaptiste Daroussin 	result = 1;
1279aae38d10SBaptiste Daroussin     }
1280aae38d10SBaptiste Daroussin     return result;
12814a1a9510SRong-En Fan }
12824a1a9510SRong-En Fan 
12835d08fb1fSRong-En Fan static char
12844a1a9510SRong-En Fan keypad_final(const char *string)
12854a1a9510SRong-En Fan {
12865d08fb1fSRong-En Fan     char result = '\0';
12874a1a9510SRong-En Fan 
12884a1a9510SRong-En Fan     if (VALID_STRING(string)
12894a1a9510SRong-En Fan 	&& *string++ == '\033'
12904a1a9510SRong-En Fan 	&& *string++ == 'O'
12914a1a9510SRong-En Fan 	&& strlen(string) == 1) {
12924a1a9510SRong-En Fan 	result = *string;
12934a1a9510SRong-En Fan     }
12944a1a9510SRong-En Fan 
12954a1a9510SRong-En Fan     return result;
12964a1a9510SRong-En Fan }
12974a1a9510SRong-En Fan 
129873f0a83dSXin LI static long
12994a1a9510SRong-En Fan keypad_index(const char *string)
13004a1a9510SRong-En Fan {
13014a1a9510SRong-En Fan     char *test;
13024a1a9510SRong-En Fan     const char *list = "PQRSwxymtuvlqrsPpn";	/* app-keypad except "Enter" */
13034a1a9510SRong-En Fan     int ch;
130473f0a83dSXin LI     long result = -1;
13054a1a9510SRong-En Fan 
13064a1a9510SRong-En Fan     if ((ch = keypad_final(string)) != '\0') {
130773f0a83dSXin LI 	test = (strchr) (list, ch);
13084a1a9510SRong-En Fan 	if (test != 0)
130973f0a83dSXin LI 	    result = (long) (test - list);
13104a1a9510SRong-En Fan     }
13114a1a9510SRong-En Fan     return result;
13124a1a9510SRong-En Fan }
13134a1a9510SRong-En Fan 
131406bfebdeSXin LI /*
131506bfebdeSXin LI  * list[] is down, up, left, right
131606bfebdeSXin LI  * "left" may be ^H rather than \E[D
131706bfebdeSXin LI  * "down" may be ^J rather than \E[B
131806bfebdeSXin LI  * But up/right are generally consistently escape sequences for ANSI terminals.
131906bfebdeSXin LI  */
132006bfebdeSXin LI static void
132106bfebdeSXin LI check_ansi_cursor(char *list[4])
132206bfebdeSXin LI {
132306bfebdeSXin LI     int j, k;
132406bfebdeSXin LI     int want;
132506bfebdeSXin LI     size_t suffix;
132606bfebdeSXin LI     bool skip[4];
132706bfebdeSXin LI     bool repeated = FALSE;
132806bfebdeSXin LI 
132906bfebdeSXin LI     for (j = 0; j < 4; ++j) {
133006bfebdeSXin LI 	skip[j] = FALSE;
133106bfebdeSXin LI 	for (k = 0; k < j; ++k) {
133206bfebdeSXin LI 	    if (j != k
133306bfebdeSXin LI 		&& !strcmp(list[j], list[k])) {
133406bfebdeSXin LI 		char *value = _nc_tic_expand(list[k], TRUE, 0);
133506bfebdeSXin LI 		_nc_warning("repeated cursor control %s\n", value);
133606bfebdeSXin LI 		repeated = TRUE;
133706bfebdeSXin LI 	    }
133806bfebdeSXin LI 	}
133906bfebdeSXin LI     }
134006bfebdeSXin LI     if (!repeated) {
134106bfebdeSXin LI 	char *up = list[1];
1342aae38d10SBaptiste Daroussin 	size_t prefix = (size_t) csi_length(up);
134306bfebdeSXin LI 
134406bfebdeSXin LI 	if (prefix) {
134506bfebdeSXin LI 	    suffix = prefix;
134606bfebdeSXin LI 	    while (up[suffix] && isdigit(UChar(up[suffix])))
134706bfebdeSXin LI 		++suffix;
134806bfebdeSXin LI 	}
134906bfebdeSXin LI 	if (prefix && up[suffix] == 'A') {
135006bfebdeSXin LI 	    skip[1] = TRUE;
135106bfebdeSXin LI 	    if (!strcmp(list[0], "\n"))
135206bfebdeSXin LI 		skip[0] = TRUE;
135306bfebdeSXin LI 	    if (!strcmp(list[2], "\b"))
135406bfebdeSXin LI 		skip[2] = TRUE;
135506bfebdeSXin LI 
135606bfebdeSXin LI 	    for (j = 0; j < 4; ++j) {
135706bfebdeSXin LI 		if (skip[j] || strlen(list[j]) == 1)
135806bfebdeSXin LI 		    continue;
135906bfebdeSXin LI 		if (memcmp(list[j], up, prefix)) {
136006bfebdeSXin LI 		    char *value = _nc_tic_expand(list[j], TRUE, 0);
136106bfebdeSXin LI 		    _nc_warning("inconsistent prefix for %s\n", value);
136206bfebdeSXin LI 		    continue;
136306bfebdeSXin LI 		}
136406bfebdeSXin LI 		if (strlen(list[j]) < suffix) {
136506bfebdeSXin LI 		    char *value = _nc_tic_expand(list[j], TRUE, 0);
136606bfebdeSXin LI 		    _nc_warning("inconsistent length for %s, expected %d\n",
136706bfebdeSXin LI 				value, (int) suffix + 1);
136806bfebdeSXin LI 		    continue;
136906bfebdeSXin LI 		}
137006bfebdeSXin LI 		want = "BADC"[j];
137106bfebdeSXin LI 		if (list[j][suffix] != want) {
137206bfebdeSXin LI 		    char *value = _nc_tic_expand(list[j], TRUE, 0);
137306bfebdeSXin LI 		    _nc_warning("inconsistent suffix for %s, expected %c, have %c\n",
137406bfebdeSXin LI 				value, want, list[j][suffix]);
137506bfebdeSXin LI 		}
137606bfebdeSXin LI 	    }
137706bfebdeSXin LI 	}
137806bfebdeSXin LI     }
137906bfebdeSXin LI }
138006bfebdeSXin LI 
138106bfebdeSXin LI #define EXPECTED(name) if (!PRESENT(name)) _nc_warning("expected " #name)
138273f0a83dSXin LI #define UNEXPECTED(name) if (PRESENT(name)) _nc_warning("unexpected " #name ", for %s", why)
138373f0a83dSXin LI 
138473f0a83dSXin LI static void
1385aae38d10SBaptiste Daroussin check_noaddress(TERMTYPE2 *tp, const char *why)
138673f0a83dSXin LI {
138773f0a83dSXin LI     UNEXPECTED(column_address);
138873f0a83dSXin LI     UNEXPECTED(cursor_address);
138973f0a83dSXin LI     UNEXPECTED(cursor_home);
139073f0a83dSXin LI     UNEXPECTED(cursor_mem_address);
139173f0a83dSXin LI     UNEXPECTED(cursor_to_ll);
139273f0a83dSXin LI     UNEXPECTED(row_address);
139373f0a83dSXin LI     UNEXPECTED(row_address);
139473f0a83dSXin LI }
139506bfebdeSXin LI 
139606bfebdeSXin LI static void
1397aae38d10SBaptiste Daroussin check_cursor(TERMTYPE2 *tp)
139806bfebdeSXin LI {
139906bfebdeSXin LI     int count;
140006bfebdeSXin LI     char *list[4];
140106bfebdeSXin LI 
140273f0a83dSXin LI     if (hard_copy) {
140373f0a83dSXin LI 	check_noaddress(tp, "hard_copy");
140473f0a83dSXin LI     } else if (generic_type) {
140573f0a83dSXin LI 	check_noaddress(tp, "generic_type");
140673f0a83dSXin LI     } else if (strchr(tp->term_names, '+') == 0) {
140773f0a83dSXin LI 	int y = 0;
140873f0a83dSXin LI 	int x = 0;
140973f0a83dSXin LI 	if (PRESENT(column_address))
141073f0a83dSXin LI 	    ++y;
141173f0a83dSXin LI 	if (PRESENT(cursor_address))
141273f0a83dSXin LI 	    y = x = 10;
141373f0a83dSXin LI 	if (PRESENT(cursor_home))
141473f0a83dSXin LI 	    ++y, ++x;
141573f0a83dSXin LI 	if (PRESENT(cursor_mem_address))
141673f0a83dSXin LI 	    y = x = 10;
141773f0a83dSXin LI 	if (PRESENT(cursor_to_ll))
141873f0a83dSXin LI 	    ++y, ++x;
141973f0a83dSXin LI 	if (PRESENT(row_address))
142073f0a83dSXin LI 	    ++x;
142173f0a83dSXin LI 	if (PRESENT(cursor_down))
142273f0a83dSXin LI 	    ++y;
142373f0a83dSXin LI 	if (PRESENT(cursor_up))
142473f0a83dSXin LI 	    ++y;
142573f0a83dSXin LI 	if (PRESENT(cursor_left))
142673f0a83dSXin LI 	    ++x;
142773f0a83dSXin LI 	if (PRESENT(cursor_right))
142873f0a83dSXin LI 	    ++x;
142973f0a83dSXin LI 	if (x < 2 && y < 2) {
143073f0a83dSXin LI 	    _nc_warning("terminal lacks cursor addressing");
143173f0a83dSXin LI 	} else {
143273f0a83dSXin LI 	    if (x < 2)
143373f0a83dSXin LI 		_nc_warning("terminal lacks cursor column-addressing");
143473f0a83dSXin LI 	    if (y < 2)
143573f0a83dSXin LI 		_nc_warning("terminal lacks cursor row-addressing");
143673f0a83dSXin LI 	}
143773f0a83dSXin LI     }
143873f0a83dSXin LI 
143973f0a83dSXin LI     /* it is rare to have an insert-line feature without a matching delete */
144073f0a83dSXin LI     ANDMISSING(parm_insert_line, insert_line);
144173f0a83dSXin LI     ANDMISSING(parm_delete_line, delete_line);
144273f0a83dSXin LI     ANDMISSING(parm_insert_line, parm_delete_line);
144373f0a83dSXin LI 
144406bfebdeSXin LI     /* if we have a parameterized form, then the non-parameterized is easy */
144506bfebdeSXin LI     ANDMISSING(parm_down_cursor, cursor_down);
144606bfebdeSXin LI     ANDMISSING(parm_up_cursor, cursor_up);
144706bfebdeSXin LI     ANDMISSING(parm_left_cursor, cursor_left);
144806bfebdeSXin LI     ANDMISSING(parm_right_cursor, cursor_right);
144906bfebdeSXin LI 
145006bfebdeSXin LI     /* Given any of a set of cursor movement, the whole set should be present.
145106bfebdeSXin LI      * Technically this is not true (we could use cursor_address to fill in
145206bfebdeSXin LI      * unsupported controls), but it is likely.
145306bfebdeSXin LI      */
145406bfebdeSXin LI     count = 0;
145506bfebdeSXin LI     if (PRESENT(parm_down_cursor)) {
145606bfebdeSXin LI 	list[count++] = parm_down_cursor;
145706bfebdeSXin LI     }
145806bfebdeSXin LI     if (PRESENT(parm_up_cursor)) {
145906bfebdeSXin LI 	list[count++] = parm_up_cursor;
146006bfebdeSXin LI     }
146106bfebdeSXin LI     if (PRESENT(parm_left_cursor)) {
146206bfebdeSXin LI 	list[count++] = parm_left_cursor;
146306bfebdeSXin LI     }
146406bfebdeSXin LI     if (PRESENT(parm_right_cursor)) {
146506bfebdeSXin LI 	list[count++] = parm_right_cursor;
146606bfebdeSXin LI     }
146706bfebdeSXin LI     if (count == 4) {
146806bfebdeSXin LI 	check_ansi_cursor(list);
146906bfebdeSXin LI     } else if (count != 0) {
147006bfebdeSXin LI 	EXPECTED(parm_down_cursor);
147106bfebdeSXin LI 	EXPECTED(parm_up_cursor);
147206bfebdeSXin LI 	EXPECTED(parm_left_cursor);
147306bfebdeSXin LI 	EXPECTED(parm_right_cursor);
147406bfebdeSXin LI     }
147506bfebdeSXin LI 
147606bfebdeSXin LI     count = 0;
147706bfebdeSXin LI     if (PRESENT(cursor_down)) {
147806bfebdeSXin LI 	list[count++] = cursor_down;
147906bfebdeSXin LI     }
148006bfebdeSXin LI     if (PRESENT(cursor_up)) {
148106bfebdeSXin LI 	list[count++] = cursor_up;
148206bfebdeSXin LI     }
148306bfebdeSXin LI     if (PRESENT(cursor_left)) {
148406bfebdeSXin LI 	list[count++] = cursor_left;
148506bfebdeSXin LI     }
148606bfebdeSXin LI     if (PRESENT(cursor_right)) {
148706bfebdeSXin LI 	list[count++] = cursor_right;
148806bfebdeSXin LI     }
148906bfebdeSXin LI     if (count == 4) {
149006bfebdeSXin LI 	check_ansi_cursor(list);
149106bfebdeSXin LI     } else if (count != 0) {
149206bfebdeSXin LI 	count = 0;
149306bfebdeSXin LI 	if (PRESENT(cursor_down) && strcmp(cursor_down, "\n"))
149406bfebdeSXin LI 	    ++count;
149506bfebdeSXin LI 	if (PRESENT(cursor_left) && strcmp(cursor_left, "\b"))
149606bfebdeSXin LI 	    ++count;
149706bfebdeSXin LI 	if (PRESENT(cursor_up) && strlen(cursor_up) > 1)
149806bfebdeSXin LI 	    ++count;
149906bfebdeSXin LI 	if (PRESENT(cursor_right) && strlen(cursor_right) > 1)
150006bfebdeSXin LI 	    ++count;
150106bfebdeSXin LI 	if (count) {
150206bfebdeSXin LI 	    EXPECTED(cursor_down);
150306bfebdeSXin LI 	    EXPECTED(cursor_up);
150406bfebdeSXin LI 	    EXPECTED(cursor_left);
150506bfebdeSXin LI 	    EXPECTED(cursor_right);
150606bfebdeSXin LI 	}
150706bfebdeSXin LI     }
150806bfebdeSXin LI }
150906bfebdeSXin LI 
15105d08fb1fSRong-En Fan #define MAX_KP 5
15114a1a9510SRong-En Fan /*
15124a1a9510SRong-En Fan  * Do a quick sanity-check for vt100-style keypads to see if the 5-key keypad
15134a1a9510SRong-En Fan  * is mapped inconsistently.
15144a1a9510SRong-En Fan  */
15154a1a9510SRong-En Fan static void
1516aae38d10SBaptiste Daroussin check_keypad(TERMTYPE2 *tp)
15174a1a9510SRong-En Fan {
15184a1a9510SRong-En Fan     char show[80];
15194a1a9510SRong-En Fan 
15204a1a9510SRong-En Fan     if (VALID_STRING(key_a1) &&
15214a1a9510SRong-En Fan 	VALID_STRING(key_a3) &&
15224a1a9510SRong-En Fan 	VALID_STRING(key_b2) &&
15234a1a9510SRong-En Fan 	VALID_STRING(key_c1) &&
15244a1a9510SRong-En Fan 	VALID_STRING(key_c3)) {
15255d08fb1fSRong-En Fan 	char final[MAX_KP + 1];
152673f0a83dSXin LI 	long list[MAX_KP];
15274a1a9510SRong-En Fan 	int increase = 0;
15284a1a9510SRong-En Fan 	int j, k, kk;
152973f0a83dSXin LI 	long last;
153073f0a83dSXin LI 	long test;
15314a1a9510SRong-En Fan 
15324a1a9510SRong-En Fan 	final[0] = keypad_final(key_a1);
15334a1a9510SRong-En Fan 	final[1] = keypad_final(key_a3);
15344a1a9510SRong-En Fan 	final[2] = keypad_final(key_b2);
15354a1a9510SRong-En Fan 	final[3] = keypad_final(key_c1);
15364a1a9510SRong-En Fan 	final[4] = keypad_final(key_c3);
15374a1a9510SRong-En Fan 	final[5] = '\0';
15384a1a9510SRong-En Fan 
15394a1a9510SRong-En Fan 	/* special case: legacy coding using 1,2,3,0,. on the bottom */
15405d08fb1fSRong-En Fan 	assert(strlen(final) <= MAX_KP);
15414a1a9510SRong-En Fan 	if (!strcmp(final, "qsrpn"))
15424a1a9510SRong-En Fan 	    return;
15434a1a9510SRong-En Fan 
15444a1a9510SRong-En Fan 	list[0] = keypad_index(key_a1);
15454a1a9510SRong-En Fan 	list[1] = keypad_index(key_a3);
15464a1a9510SRong-En Fan 	list[2] = keypad_index(key_b2);
15474a1a9510SRong-En Fan 	list[3] = keypad_index(key_c1);
15484a1a9510SRong-En Fan 	list[4] = keypad_index(key_c3);
15494a1a9510SRong-En Fan 
15504a1a9510SRong-En Fan 	/* check that they're all vt100 keys */
15515d08fb1fSRong-En Fan 	for (j = 0; j < MAX_KP; ++j) {
15524a1a9510SRong-En Fan 	    if (list[j] < 0) {
15534a1a9510SRong-En Fan 		return;
15544a1a9510SRong-En Fan 	    }
15554a1a9510SRong-En Fan 	}
15564a1a9510SRong-En Fan 
15574a1a9510SRong-En Fan 	/* check if they're all in increasing order */
15585d08fb1fSRong-En Fan 	for (j = 1; j < MAX_KP; ++j) {
15594a1a9510SRong-En Fan 	    if (list[j] > list[j - 1]) {
15604a1a9510SRong-En Fan 		++increase;
15614a1a9510SRong-En Fan 	    }
15624a1a9510SRong-En Fan 	}
15635d08fb1fSRong-En Fan 	if (increase != (MAX_KP - 1)) {
15644a1a9510SRong-En Fan 	    show[0] = '\0';
15654a1a9510SRong-En Fan 
15665d08fb1fSRong-En Fan 	    for (j = 0, last = -1; j < MAX_KP; ++j) {
15674a1a9510SRong-En Fan 		for (k = 0, kk = -1, test = 100; k < 5; ++k) {
15684a1a9510SRong-En Fan 		    if (list[k] > last &&
15694a1a9510SRong-En Fan 			list[k] < test) {
15704a1a9510SRong-En Fan 			test = list[k];
15714a1a9510SRong-En Fan 			kk = k;
15724a1a9510SRong-En Fan 		    }
15734a1a9510SRong-En Fan 		}
15744a1a9510SRong-En Fan 		last = test;
15755d08fb1fSRong-En Fan 		assert(strlen(show) < (MAX_KP * 4));
15764a1a9510SRong-En Fan 		switch (kk) {
15774a1a9510SRong-En Fan 		case 0:
157873f0a83dSXin LI 		    _nc_STRCAT(show, " ka1", sizeof(show));
15794a1a9510SRong-En Fan 		    break;
15804a1a9510SRong-En Fan 		case 1:
158173f0a83dSXin LI 		    _nc_STRCAT(show, " ka3", sizeof(show));
15824a1a9510SRong-En Fan 		    break;
15834a1a9510SRong-En Fan 		case 2:
158473f0a83dSXin LI 		    _nc_STRCAT(show, " kb2", sizeof(show));
15854a1a9510SRong-En Fan 		    break;
15864a1a9510SRong-En Fan 		case 3:
158773f0a83dSXin LI 		    _nc_STRCAT(show, " kc1", sizeof(show));
15884a1a9510SRong-En Fan 		    break;
15894a1a9510SRong-En Fan 		case 4:
159073f0a83dSXin LI 		    _nc_STRCAT(show, " kc3", sizeof(show));
15914a1a9510SRong-En Fan 		    break;
15924a1a9510SRong-En Fan 		}
15934a1a9510SRong-En Fan 	    }
15944a1a9510SRong-En Fan 
15954a1a9510SRong-En Fan 	    _nc_warning("vt100 keypad order inconsistent: %s", show);
15964a1a9510SRong-En Fan 	}
15974a1a9510SRong-En Fan 
15984a1a9510SRong-En Fan     } else if (VALID_STRING(key_a1) ||
15994a1a9510SRong-En Fan 	       VALID_STRING(key_a3) ||
16004a1a9510SRong-En Fan 	       VALID_STRING(key_b2) ||
16014a1a9510SRong-En Fan 	       VALID_STRING(key_c1) ||
16024a1a9510SRong-En Fan 	       VALID_STRING(key_c3)) {
16034a1a9510SRong-En Fan 	show[0] = '\0';
16044a1a9510SRong-En Fan 	if (keypad_index(key_a1) >= 0)
160573f0a83dSXin LI 	    _nc_STRCAT(show, " ka1", sizeof(show));
16064a1a9510SRong-En Fan 	if (keypad_index(key_a3) >= 0)
160773f0a83dSXin LI 	    _nc_STRCAT(show, " ka3", sizeof(show));
16084a1a9510SRong-En Fan 	if (keypad_index(key_b2) >= 0)
160973f0a83dSXin LI 	    _nc_STRCAT(show, " kb2", sizeof(show));
16104a1a9510SRong-En Fan 	if (keypad_index(key_c1) >= 0)
161173f0a83dSXin LI 	    _nc_STRCAT(show, " kc1", sizeof(show));
16124a1a9510SRong-En Fan 	if (keypad_index(key_c3) >= 0)
161373f0a83dSXin LI 	    _nc_STRCAT(show, " kc3", sizeof(show));
16144a1a9510SRong-En Fan 	if (*show != '\0')
16154a1a9510SRong-En Fan 	    _nc_warning("vt100 keypad map incomplete:%s", show);
16164a1a9510SRong-En Fan     }
161773f0a83dSXin LI 
161873f0a83dSXin LI     /*
161973f0a83dSXin LI      * These warnings are useful for consistency checks - it is possible that
162073f0a83dSXin LI      * there are real terminals with mismatches in these
162173f0a83dSXin LI      */
162273f0a83dSXin LI     ANDMISSING(key_ic, key_dc);
16234a1a9510SRong-En Fan }
16244a1a9510SRong-En Fan 
162506bfebdeSXin LI static void
1626aae38d10SBaptiste Daroussin check_printer(TERMTYPE2 *tp)
162706bfebdeSXin LI {
1628aae38d10SBaptiste Daroussin     (void) tp;
1629aae38d10SBaptiste Daroussin #if defined(enter_doublewide_mode) && defined(exit_doublewide_mode)
163006bfebdeSXin LI     PAIRED(enter_doublewide_mode, exit_doublewide_mode);
1631aae38d10SBaptiste Daroussin #endif
1632aae38d10SBaptiste Daroussin #if defined(enter_italics_mode) && defined(exit_italics_mode)
163306bfebdeSXin LI     PAIRED(enter_italics_mode, exit_italics_mode);
1634aae38d10SBaptiste Daroussin #endif
1635aae38d10SBaptiste Daroussin #if defined(enter_leftward_mode) && defined(exit_leftward_mode)
163606bfebdeSXin LI     PAIRED(enter_leftward_mode, exit_leftward_mode);
1637aae38d10SBaptiste Daroussin #endif
1638aae38d10SBaptiste Daroussin #if defined(enter_micro_mode) && defined(exit_micro_mode)
163906bfebdeSXin LI     PAIRED(enter_micro_mode, exit_micro_mode);
1640aae38d10SBaptiste Daroussin #endif
1641aae38d10SBaptiste Daroussin #if defined(enter_shadow_mode) && defined(exit_shadow_mode)
164206bfebdeSXin LI     PAIRED(enter_shadow_mode, exit_shadow_mode);
1643aae38d10SBaptiste Daroussin #endif
1644aae38d10SBaptiste Daroussin #if defined(enter_subscript_mode) && defined(exit_subscript_mode)
164506bfebdeSXin LI     PAIRED(enter_subscript_mode, exit_subscript_mode);
1646aae38d10SBaptiste Daroussin #endif
1647aae38d10SBaptiste Daroussin #if defined(enter_superscript_mode) && defined(exit_superscript_mode)
164806bfebdeSXin LI     PAIRED(enter_superscript_mode, exit_superscript_mode);
1649aae38d10SBaptiste Daroussin #endif
1650aae38d10SBaptiste Daroussin #if defined(enter_upward_mode) && defined(exit_upward_mode)
165106bfebdeSXin LI     PAIRED(enter_upward_mode, exit_upward_mode);
1652aae38d10SBaptiste Daroussin #endif
165306bfebdeSXin LI 
1654aae38d10SBaptiste Daroussin #if defined(start_char_set_def) && defined(stop_char_set_def)
165506bfebdeSXin LI     ANDMISSING(start_char_set_def, stop_char_set_def);
1656aae38d10SBaptiste Daroussin #endif
165706bfebdeSXin LI 
165806bfebdeSXin LI     /* if we have a parameterized form, then the non-parameterized is easy */
1659aae38d10SBaptiste Daroussin #if defined(set_bottom_margin_parm) && defined(set_bottom_margin)
166006bfebdeSXin LI     ANDMISSING(set_bottom_margin_parm, set_bottom_margin);
1661aae38d10SBaptiste Daroussin #endif
1662aae38d10SBaptiste Daroussin #if defined(set_left_margin_parm) && defined(set_left_margin)
166306bfebdeSXin LI     ANDMISSING(set_left_margin_parm, set_left_margin);
1664aae38d10SBaptiste Daroussin #endif
1665aae38d10SBaptiste Daroussin #if defined(set_right_margin_parm) && defined(set_right_margin)
166606bfebdeSXin LI     ANDMISSING(set_right_margin_parm, set_right_margin);
1667aae38d10SBaptiste Daroussin #endif
1668aae38d10SBaptiste Daroussin #if defined(set_top_margin_parm) && defined(set_top_margin)
166906bfebdeSXin LI     ANDMISSING(set_top_margin_parm, set_top_margin);
1670aae38d10SBaptiste Daroussin #endif
167106bfebdeSXin LI 
1672aae38d10SBaptiste Daroussin #if defined(parm_down_micro) && defined(micro_down)
167306bfebdeSXin LI     ANDMISSING(parm_down_micro, micro_down);
1674aae38d10SBaptiste Daroussin #endif
1675aae38d10SBaptiste Daroussin #if defined(parm_left_micro) && defined(micro_left)
167606bfebdeSXin LI     ANDMISSING(parm_left_micro, micro_left);
1677aae38d10SBaptiste Daroussin #endif
1678aae38d10SBaptiste Daroussin #if defined(parm_right_micro) && defined(micro_right)
167906bfebdeSXin LI     ANDMISSING(parm_right_micro, micro_right);
1680aae38d10SBaptiste Daroussin #endif
1681aae38d10SBaptiste Daroussin #if defined(parm_up_micro) && defined(micro_up)
168206bfebdeSXin LI     ANDMISSING(parm_up_micro, micro_up);
1683aae38d10SBaptiste Daroussin #endif
168406bfebdeSXin LI }
168506bfebdeSXin LI 
1686aae38d10SBaptiste Daroussin #if NCURSES_XNAMES
168773f0a83dSXin LI static bool
168873f0a83dSXin LI uses_SGR_39_49(const char *value)
168973f0a83dSXin LI {
169073f0a83dSXin LI     return (strstr(value, "39;49") != 0
169173f0a83dSXin LI 	    || strstr(value, "49;39") != 0);
169273f0a83dSXin LI }
169373f0a83dSXin LI 
169473f0a83dSXin LI /*
169573f0a83dSXin LI  * Check consistency of termcap extensions related to "screen".
169673f0a83dSXin LI  */
169773f0a83dSXin LI static void
1698aae38d10SBaptiste Daroussin check_screen(TERMTYPE2 *tp)
169973f0a83dSXin LI {
170073f0a83dSXin LI     if (_nc_user_definable) {
170173f0a83dSXin LI 	int have_XT = tigetflag("XT");
170273f0a83dSXin LI 	int have_XM = tigetflag("XM");
170373f0a83dSXin LI 	int have_bce = back_color_erase;
170473f0a83dSXin LI 	bool have_kmouse = FALSE;
170573f0a83dSXin LI 	bool use_sgr_39_49 = FALSE;
170673f0a83dSXin LI 	char *name = _nc_first_name(tp->term_names);
1707aae38d10SBaptiste Daroussin 	bool is_screen = !strncmp(name, "screen", 6);
1708aae38d10SBaptiste Daroussin 	bool screen_base = (is_screen
1709aae38d10SBaptiste Daroussin 			    && strchr(name, '.') == 0);
171073f0a83dSXin LI 
171173f0a83dSXin LI 	if (!VALID_BOOLEAN(have_bce)) {
171273f0a83dSXin LI 	    have_bce = FALSE;
171373f0a83dSXin LI 	}
171473f0a83dSXin LI 	if (!VALID_BOOLEAN(have_XM)) {
171573f0a83dSXin LI 	    have_XM = FALSE;
171673f0a83dSXin LI 	}
171773f0a83dSXin LI 	if (!VALID_BOOLEAN(have_XT)) {
171873f0a83dSXin LI 	    have_XT = FALSE;
171973f0a83dSXin LI 	}
172073f0a83dSXin LI 	if (VALID_STRING(key_mouse)) {
172173f0a83dSXin LI 	    have_kmouse = !strcmp("\033[M", key_mouse);
172273f0a83dSXin LI 	}
172373f0a83dSXin LI 	if (VALID_STRING(orig_colors)) {
172473f0a83dSXin LI 	    use_sgr_39_49 = uses_SGR_39_49(orig_colors);
172573f0a83dSXin LI 	} else if (VALID_STRING(orig_pair)) {
172673f0a83dSXin LI 	    use_sgr_39_49 = uses_SGR_39_49(orig_pair);
172773f0a83dSXin LI 	}
172873f0a83dSXin LI 
172973f0a83dSXin LI 	if (have_XM && have_XT) {
1730aae38d10SBaptiste Daroussin 	    _nc_warning("screen's XT capability conflicts with XM");
1731aae38d10SBaptiste Daroussin 	} else if (have_XT && screen_base) {
1732aae38d10SBaptiste Daroussin 	    _nc_warning("screen's \"screen\" entries should not have XT set");
173373f0a83dSXin LI 	} else if (have_XT) {
1734aae38d10SBaptiste Daroussin 	    if (!have_kmouse && is_screen) {
173573f0a83dSXin LI 		if (VALID_STRING(key_mouse)) {
1736aae38d10SBaptiste Daroussin 		    _nc_warning("value of kmous inconsistent with screen's usage");
173773f0a83dSXin LI 		} else {
1738aae38d10SBaptiste Daroussin 		    _nc_warning("expected kmous capability with XT");
173973f0a83dSXin LI 		}
174073f0a83dSXin LI 	    }
174173f0a83dSXin LI 	    if (!have_bce && max_colors > 0)
1742aae38d10SBaptiste Daroussin 		_nc_warning("expected bce capability with XT");
174373f0a83dSXin LI 	    if (!use_sgr_39_49 && have_bce && max_colors > 0)
1744aae38d10SBaptiste Daroussin 		_nc_warning("expected orig_colors capability with XT to have 39/49 parameters");
174573f0a83dSXin LI 	    if (VALID_STRING(to_status_line))
174673f0a83dSXin LI 		_nc_warning("\"tsl\" capability is redundant, given XT");
174773f0a83dSXin LI 	} else {
1748aae38d10SBaptiste Daroussin 	    if (have_kmouse
1749aae38d10SBaptiste Daroussin 		&& !have_XM
1750aae38d10SBaptiste Daroussin 		&& !screen_base && strchr(name, '+') == 0) {
1751aae38d10SBaptiste Daroussin 		_nc_warning("expected XT to be set, given kmous");
175273f0a83dSXin LI 	    }
175373f0a83dSXin LI 	}
1754aae38d10SBaptiste Daroussin     }
1755aae38d10SBaptiste Daroussin }
1756aae38d10SBaptiste Daroussin #else
1757aae38d10SBaptiste Daroussin #define check_screen(tp)	/* nothing */
175873f0a83dSXin LI #endif
175973f0a83dSXin LI 
17604a1a9510SRong-En Fan /*
176118259542SPeter Wemm  * Returns the expected number of parameters for the given capability.
176218259542SPeter Wemm  */
176318259542SPeter Wemm static int
17647a69bbfbSPeter Wemm expected_params(const char *name)
176518259542SPeter Wemm {
1766aae38d10SBaptiste Daroussin #define DATA(name,count) { { name }, count }
176718259542SPeter Wemm     /* *INDENT-OFF* */
176818259542SPeter Wemm     static const struct {
1769aae38d10SBaptiste Daroussin 	const char name[9];
177018259542SPeter Wemm 	int count;
177118259542SPeter Wemm     } table[] = {
1772aae38d10SBaptiste Daroussin 	DATA( "S0",		1 ),	/* 'screen' extension */
1773aae38d10SBaptiste Daroussin 	DATA( "birep",		2 ),
1774aae38d10SBaptiste Daroussin 	DATA( "chr",		1 ),
1775aae38d10SBaptiste Daroussin 	DATA( "colornm",	1 ),
1776aae38d10SBaptiste Daroussin 	DATA( "cpi",		1 ),
1777aae38d10SBaptiste Daroussin 	DATA( "csnm",		1 ),
1778aae38d10SBaptiste Daroussin 	DATA( "csr",		2 ),
1779aae38d10SBaptiste Daroussin 	DATA( "cub",		1 ),
1780aae38d10SBaptiste Daroussin 	DATA( "cud",		1 ),
1781aae38d10SBaptiste Daroussin 	DATA( "cuf",		1 ),
1782aae38d10SBaptiste Daroussin 	DATA( "cup",		2 ),
1783aae38d10SBaptiste Daroussin 	DATA( "cuu",		1 ),
1784aae38d10SBaptiste Daroussin 	DATA( "cvr",		1 ),
1785aae38d10SBaptiste Daroussin 	DATA( "cwin",		5 ),
1786aae38d10SBaptiste Daroussin 	DATA( "dch",		1 ),
1787aae38d10SBaptiste Daroussin 	DATA( "defc",		3 ),
1788aae38d10SBaptiste Daroussin 	DATA( "dial",		1 ),
1789aae38d10SBaptiste Daroussin 	DATA( "dispc",		1 ),
1790aae38d10SBaptiste Daroussin 	DATA( "dl",		1 ),
1791aae38d10SBaptiste Daroussin 	DATA( "ech",		1 ),
1792aae38d10SBaptiste Daroussin 	DATA( "getm",		1 ),
1793aae38d10SBaptiste Daroussin 	DATA( "hpa",		1 ),
1794aae38d10SBaptiste Daroussin 	DATA( "ich",		1 ),
1795aae38d10SBaptiste Daroussin 	DATA( "il",		1 ),
1796aae38d10SBaptiste Daroussin 	DATA( "indn",		1 ),
1797aae38d10SBaptiste Daroussin 	DATA( "initc",		4 ),
1798aae38d10SBaptiste Daroussin 	DATA( "initp",		7 ),
1799aae38d10SBaptiste Daroussin 	DATA( "lpi",		1 ),
1800aae38d10SBaptiste Daroussin 	DATA( "mc5p",		1 ),
1801aae38d10SBaptiste Daroussin 	DATA( "mrcup",		2 ),
1802aae38d10SBaptiste Daroussin 	DATA( "mvpa",		1 ),
1803aae38d10SBaptiste Daroussin 	DATA( "pfkey",		2 ),
1804aae38d10SBaptiste Daroussin 	DATA( "pfloc",		2 ),
1805aae38d10SBaptiste Daroussin 	DATA( "pfx",		2 ),
1806aae38d10SBaptiste Daroussin 	DATA( "pfxl",		3 ),
1807aae38d10SBaptiste Daroussin 	DATA( "pln",		2 ),
1808aae38d10SBaptiste Daroussin 	DATA( "qdial",		1 ),
1809aae38d10SBaptiste Daroussin 	DATA( "rcsd",		1 ),
1810aae38d10SBaptiste Daroussin 	DATA( "rep",		2 ),
1811aae38d10SBaptiste Daroussin 	DATA( "rin",		1 ),
1812aae38d10SBaptiste Daroussin 	DATA( "sclk",		3 ),
1813aae38d10SBaptiste Daroussin 	DATA( "scp",		1 ),
1814aae38d10SBaptiste Daroussin 	DATA( "scs",		1 ),
1815aae38d10SBaptiste Daroussin 	DATA( "scsd",		2 ),
1816aae38d10SBaptiste Daroussin 	DATA( "setab",		1 ),
1817aae38d10SBaptiste Daroussin 	DATA( "setaf",		1 ),
1818aae38d10SBaptiste Daroussin 	DATA( "setb",		1 ),
1819aae38d10SBaptiste Daroussin 	DATA( "setcolor",	1 ),
1820aae38d10SBaptiste Daroussin 	DATA( "setf",		1 ),
1821aae38d10SBaptiste Daroussin 	DATA( "sgr",		9 ),
1822aae38d10SBaptiste Daroussin 	DATA( "sgr1",		6 ),
1823aae38d10SBaptiste Daroussin 	DATA( "slength",	1 ),
1824aae38d10SBaptiste Daroussin 	DATA( "slines",		1 ),
1825aae38d10SBaptiste Daroussin 	DATA( "smgbp",		1 ),	/* 2 if smgtp is not given */
1826aae38d10SBaptiste Daroussin 	DATA( "smglp",		1 ),
1827aae38d10SBaptiste Daroussin 	DATA( "smglr",		2 ),
1828aae38d10SBaptiste Daroussin 	DATA( "smgrp",		1 ),
1829aae38d10SBaptiste Daroussin 	DATA( "smgtb",		2 ),
1830aae38d10SBaptiste Daroussin 	DATA( "smgtp",		1 ),
1831aae38d10SBaptiste Daroussin 	DATA( "tsl",		1 ),
1832aae38d10SBaptiste Daroussin 	DATA( "u6",		-1 ),
1833aae38d10SBaptiste Daroussin 	DATA( "vpa",		1 ),
1834aae38d10SBaptiste Daroussin 	DATA( "wind",		4 ),
1835aae38d10SBaptiste Daroussin 	DATA( "wingo",		1 ),
183618259542SPeter Wemm     };
183718259542SPeter Wemm     /* *INDENT-ON* */
183818259542SPeter Wemm 
1839aae38d10SBaptiste Daroussin #undef DATA
1840aae38d10SBaptiste Daroussin 
184118259542SPeter Wemm     unsigned n;
184218259542SPeter Wemm     int result = 0;		/* function-keys, etc., use none */
184318259542SPeter Wemm 
184418259542SPeter Wemm     for (n = 0; n < SIZEOF(table); n++) {
184518259542SPeter Wemm 	if (!strcmp(name, table[n].name)) {
184618259542SPeter Wemm 	    result = table[n].count;
184718259542SPeter Wemm 	    break;
184818259542SPeter Wemm 	}
184918259542SPeter Wemm     }
185018259542SPeter Wemm 
185118259542SPeter Wemm     return result;
185218259542SPeter Wemm }
185318259542SPeter Wemm 
185418259542SPeter Wemm /*
1855aae38d10SBaptiste Daroussin  * Check for user-capabilities that happen to be used in ncurses' terminal
1856aae38d10SBaptiste Daroussin  * database.
1857aae38d10SBaptiste Daroussin  */
1858aae38d10SBaptiste Daroussin #if NCURSES_XNAMES
1859aae38d10SBaptiste Daroussin static struct user_table_entry const *
1860aae38d10SBaptiste Daroussin lookup_user_capability(const char *name)
1861aae38d10SBaptiste Daroussin {
1862aae38d10SBaptiste Daroussin     struct user_table_entry const *result = 0;
1863aae38d10SBaptiste Daroussin     if (*name != 'k') {
1864aae38d10SBaptiste Daroussin 	result = _nc_find_user_entry(name);
1865aae38d10SBaptiste Daroussin     }
1866aae38d10SBaptiste Daroussin     return result;
1867aae38d10SBaptiste Daroussin }
1868aae38d10SBaptiste Daroussin #endif
1869aae38d10SBaptiste Daroussin 
1870aae38d10SBaptiste Daroussin /*
1871aae38d10SBaptiste Daroussin  * If a given name is likely to be a user-capability, return the number of
1872aae38d10SBaptiste Daroussin  * parameters it would be used with.  If not, return -1.
1873aae38d10SBaptiste Daroussin  *
1874aae38d10SBaptiste Daroussin  * ncurses assumes that u6 could be used for getting the cursor-position, but
1875aae38d10SBaptiste Daroussin  * that is not implemented.  Make a special case for that, to quiet needless
1876aae38d10SBaptiste Daroussin  * warnings.
1877aae38d10SBaptiste Daroussin  *
1878aae38d10SBaptiste Daroussin  * The other string-capability extensions (see terminfo.src) which could have
1879aae38d10SBaptiste Daroussin  * parameters such as "Ss", "%u", are not used by ncurses.  But we check those
1880aae38d10SBaptiste Daroussin  * anyway, to validate the terminfo database.
1881aae38d10SBaptiste Daroussin  */
1882aae38d10SBaptiste Daroussin static int
1883aae38d10SBaptiste Daroussin is_user_capability(const char *name)
1884aae38d10SBaptiste Daroussin {
1885aae38d10SBaptiste Daroussin     int result = -1;
1886aae38d10SBaptiste Daroussin     if (name[0] == 'u' &&
1887aae38d10SBaptiste Daroussin 	(name[1] >= '0' && name[1] <= '9') &&
1888aae38d10SBaptiste Daroussin 	name[2] == '\0') {
1889aae38d10SBaptiste Daroussin 	result = (name[1] == '6') ? 2 : 0;
1890aae38d10SBaptiste Daroussin     }
1891aae38d10SBaptiste Daroussin #if NCURSES_XNAMES
1892aae38d10SBaptiste Daroussin     else if (using_extensions) {
1893aae38d10SBaptiste Daroussin 	struct user_table_entry const *p = lookup_user_capability(name);
1894aae38d10SBaptiste Daroussin 	if (p != 0) {
1895aae38d10SBaptiste Daroussin 	    result = (int) p->ute_argc;
1896aae38d10SBaptiste Daroussin 	}
1897aae38d10SBaptiste Daroussin     }
1898aae38d10SBaptiste Daroussin #endif
1899aae38d10SBaptiste Daroussin     return result;
1900aae38d10SBaptiste Daroussin }
1901aae38d10SBaptiste Daroussin 
1902aae38d10SBaptiste Daroussin /*
190318259542SPeter Wemm  * Make a quick sanity check for the parameters which are used in the given
190418259542SPeter Wemm  * strings.  If there are no "%p" tokens, then there should be no other "%"
190518259542SPeter Wemm  * markers.
190618259542SPeter Wemm  */
190718259542SPeter Wemm static void
1908aae38d10SBaptiste Daroussin check_params(TERMTYPE2 *tp, const char *name, char *value, int extended)
190918259542SPeter Wemm {
191018259542SPeter Wemm     int expected = expected_params(name);
191118259542SPeter Wemm     int actual = 0;
191218259542SPeter Wemm     int n;
1913aae38d10SBaptiste Daroussin     bool params[NUM_PARM];
191418259542SPeter Wemm     char *s = value;
191518259542SPeter Wemm 
19164a1a9510SRong-En Fan #ifdef set_top_margin_parm
1917b82face1SPeter Wemm     if (!strcmp(name, "smgbp")
1918b82face1SPeter Wemm 	&& set_top_margin_parm == 0)
1919b82face1SPeter Wemm 	expected = 2;
19204a1a9510SRong-En Fan #endif
1921b82face1SPeter Wemm 
1922aae38d10SBaptiste Daroussin     for (n = 0; n < NUM_PARM; n++)
192318259542SPeter Wemm 	params[n] = FALSE;
192418259542SPeter Wemm 
192518259542SPeter Wemm     while (*s != 0) {
192618259542SPeter Wemm 	if (*s == '%') {
192718259542SPeter Wemm 	    if (*++s == '\0') {
192818259542SPeter Wemm 		_nc_warning("expected character after %% in %s", name);
192918259542SPeter Wemm 		break;
193018259542SPeter Wemm 	    } else if (*s == 'p') {
193118259542SPeter Wemm 		if (*++s == '\0' || !isdigit((int) *s)) {
193218259542SPeter Wemm 		    _nc_warning("expected digit after %%p in %s", name);
193318259542SPeter Wemm 		    return;
193418259542SPeter Wemm 		} else {
193518259542SPeter Wemm 		    n = (*s - '0');
193618259542SPeter Wemm 		    if (n > actual)
193718259542SPeter Wemm 			actual = n;
193818259542SPeter Wemm 		    params[n] = TRUE;
193918259542SPeter Wemm 		}
194018259542SPeter Wemm 	    }
194118259542SPeter Wemm 	}
194218259542SPeter Wemm 	s++;
194318259542SPeter Wemm     }
194418259542SPeter Wemm 
1945aae38d10SBaptiste Daroussin #if NCURSES_XNAMES
1946aae38d10SBaptiste Daroussin     if (extended) {
1947aae38d10SBaptiste Daroussin 	int check = is_user_capability(name);
1948aae38d10SBaptiste Daroussin 	if (check != actual && (check >= 0 && actual >= 0)) {
1949aae38d10SBaptiste Daroussin 	    _nc_warning("extended %s capability has %d parameters, expected %d",
1950aae38d10SBaptiste Daroussin 			name, actual, check);
1951aae38d10SBaptiste Daroussin 	} else if (debug_level > 1) {
1952aae38d10SBaptiste Daroussin 	    _nc_warning("extended %s capability has %d parameters, as expected",
1953aae38d10SBaptiste Daroussin 			name, actual);
1954aae38d10SBaptiste Daroussin 	}
1955aae38d10SBaptiste Daroussin 	expected = actual;
1956aae38d10SBaptiste Daroussin     }
1957aae38d10SBaptiste Daroussin #else
1958aae38d10SBaptiste Daroussin     (void) extended;
1959aae38d10SBaptiste Daroussin #endif
1960aae38d10SBaptiste Daroussin 
196118259542SPeter Wemm     if (params[0]) {
196218259542SPeter Wemm 	_nc_warning("%s refers to parameter 0 (%%p0), which is not allowed", name);
196318259542SPeter Wemm     }
196418259542SPeter Wemm     if (value == set_attributes || expected < 0) {
196518259542SPeter Wemm 	;
196618259542SPeter Wemm     } else if (expected != actual) {
196718259542SPeter Wemm 	_nc_warning("%s uses %d parameters, expected %d", name,
196818259542SPeter Wemm 		    actual, expected);
196918259542SPeter Wemm 	for (n = 1; n < actual; n++) {
197018259542SPeter Wemm 	    if (!params[n])
197118259542SPeter Wemm 		_nc_warning("%s omits parameter %d", name, n);
197218259542SPeter Wemm 	}
197318259542SPeter Wemm     }
1974aae38d10SBaptiste Daroussin 
1975aae38d10SBaptiste Daroussin     /*
1976aae38d10SBaptiste Daroussin      * Counting "%p" markers does not account for termcap expressions which
1977aae38d10SBaptiste Daroussin      * may not have been fully translated.  Also, tparm does its own analysis.
1978aae38d10SBaptiste Daroussin      * Report differences here.
1979aae38d10SBaptiste Daroussin      */
1980aae38d10SBaptiste Daroussin     if (actual >= 0) {
1981aae38d10SBaptiste Daroussin 	char *p_is_s[NUM_PARM];
1982aae38d10SBaptiste Daroussin 	int popcount;
1983aae38d10SBaptiste Daroussin 	int analyzed = _nc_tparm_analyze(value, p_is_s, &popcount);
1984aae38d10SBaptiste Daroussin 	if (analyzed < popcount) {
1985aae38d10SBaptiste Daroussin 	    analyzed = popcount;
1986aae38d10SBaptiste Daroussin 	}
1987aae38d10SBaptiste Daroussin 	if (actual != analyzed && expected != analyzed) {
1988aae38d10SBaptiste Daroussin #if NCURSES_XNAMES
1989aae38d10SBaptiste Daroussin 	    int user_cap = is_user_capability(name);
1990aae38d10SBaptiste Daroussin 	    if ((user_cap == analyzed) && using_extensions) {
1991aae38d10SBaptiste Daroussin 		;		/* ignore */
1992aae38d10SBaptiste Daroussin 	    } else if (user_cap >= 0) {
1993aae38d10SBaptiste Daroussin 		_nc_warning("tparm will use %d parameters for %s, expected %d",
1994aae38d10SBaptiste Daroussin 			    analyzed, name, user_cap);
1995aae38d10SBaptiste Daroussin 	    } else
1996aae38d10SBaptiste Daroussin #endif
1997aae38d10SBaptiste Daroussin 	    {
1998aae38d10SBaptiste Daroussin 		_nc_warning("tparm analyzed %d parameters for %s, expected %d",
1999aae38d10SBaptiste Daroussin 			    analyzed, name, actual);
2000aae38d10SBaptiste Daroussin 	    }
2001aae38d10SBaptiste Daroussin 	}
2002aae38d10SBaptiste Daroussin     }
2003aae38d10SBaptiste Daroussin }
2004aae38d10SBaptiste Daroussin 
2005aae38d10SBaptiste Daroussin static bool
2006aae38d10SBaptiste Daroussin line_capability(const char *name)
2007aae38d10SBaptiste Daroussin {
2008aae38d10SBaptiste Daroussin     bool result = FALSE;
2009aae38d10SBaptiste Daroussin     static const char *table[] =
2010aae38d10SBaptiste Daroussin     {
2011aae38d10SBaptiste Daroussin 	"csr",			/* change_scroll_region          */
2012aae38d10SBaptiste Daroussin 	"clear",		/* clear_screen                  */
2013aae38d10SBaptiste Daroussin 	"ed",			/* clr_eos                       */
2014aae38d10SBaptiste Daroussin 	"cwin",			/* create_window                 */
2015aae38d10SBaptiste Daroussin 	"cup",			/* cursor_address                */
2016aae38d10SBaptiste Daroussin 	"cud1",			/* cursor_down                   */
2017aae38d10SBaptiste Daroussin 	"home",			/* cursor_home                   */
2018aae38d10SBaptiste Daroussin 	"mrcup",		/* cursor_mem_address            */
2019aae38d10SBaptiste Daroussin 	"ll",			/* cursor_to_ll                  */
2020aae38d10SBaptiste Daroussin 	"cuu1",			/* cursor_up                     */
2021aae38d10SBaptiste Daroussin 	"dl1",			/* delete_line                   */
2022aae38d10SBaptiste Daroussin 	"hd",			/* down_half_line                */
2023aae38d10SBaptiste Daroussin 	"flash",		/* flash_screen                  */
2024aae38d10SBaptiste Daroussin 	"ff",			/* form_feed                     */
2025aae38d10SBaptiste Daroussin 	"il1",			/* insert_line                   */
2026aae38d10SBaptiste Daroussin 	"nel",			/* newline                       */
2027aae38d10SBaptiste Daroussin 	"dl",			/* parm_delete_line              */
2028aae38d10SBaptiste Daroussin 	"cud",			/* parm_down_cursor              */
2029aae38d10SBaptiste Daroussin 	"indn",			/* parm_index                    */
2030aae38d10SBaptiste Daroussin 	"il",			/* parm_insert_line              */
2031aae38d10SBaptiste Daroussin 	"rin",			/* parm_rindex                   */
2032aae38d10SBaptiste Daroussin 	"cuu",			/* parm_up_cursor                */
2033aae38d10SBaptiste Daroussin 	"mc0",			/* print_screen                  */
2034aae38d10SBaptiste Daroussin 	"vpa",			/* row_address                   */
2035aae38d10SBaptiste Daroussin 	"ind",			/* scroll_forward                */
2036aae38d10SBaptiste Daroussin 	"ri",			/* scroll_reverse                */
2037aae38d10SBaptiste Daroussin 	"hu",			/* up_half_line                  */
2038aae38d10SBaptiste Daroussin     };
2039aae38d10SBaptiste Daroussin     size_t n;
2040aae38d10SBaptiste Daroussin     for (n = 0; n < SIZEOF(table); ++n) {
2041aae38d10SBaptiste Daroussin 	if (!strcmp(name, table[n])) {
2042aae38d10SBaptiste Daroussin 	    result = TRUE;
2043aae38d10SBaptiste Daroussin 	    break;
2044aae38d10SBaptiste Daroussin 	}
2045aae38d10SBaptiste Daroussin     }
2046aae38d10SBaptiste Daroussin     return result;
2047aae38d10SBaptiste Daroussin }
2048aae38d10SBaptiste Daroussin 
2049aae38d10SBaptiste Daroussin /*
2050aae38d10SBaptiste Daroussin  * Check for DEC VT100 private mode for reverse video.
2051aae38d10SBaptiste Daroussin  */
2052aae38d10SBaptiste Daroussin static const char *
2053aae38d10SBaptiste Daroussin skip_DECSCNM(const char *value, int *flag)
2054aae38d10SBaptiste Daroussin {
2055aae38d10SBaptiste Daroussin     *flag = -1;
2056aae38d10SBaptiste Daroussin     if (value != 0) {
2057aae38d10SBaptiste Daroussin 	int skip = csi_length(value);
2058aae38d10SBaptiste Daroussin 	if (skip > 0 &&
2059aae38d10SBaptiste Daroussin 	    value[skip++] == '?' &&
2060aae38d10SBaptiste Daroussin 	    value[skip++] == '5') {
2061aae38d10SBaptiste Daroussin 	    if (value[skip] == 'h') {
2062aae38d10SBaptiste Daroussin 		*flag = 1;
2063aae38d10SBaptiste Daroussin 	    } else if (value[skip] == 'l') {
2064aae38d10SBaptiste Daroussin 		*flag = 0;
2065aae38d10SBaptiste Daroussin 	    }
2066aae38d10SBaptiste Daroussin 	    value += skip + 1;
2067aae38d10SBaptiste Daroussin 	}
2068aae38d10SBaptiste Daroussin     }
2069aae38d10SBaptiste Daroussin     return value;
2070aae38d10SBaptiste Daroussin }
2071aae38d10SBaptiste Daroussin 
2072aae38d10SBaptiste Daroussin static void
2073aae38d10SBaptiste Daroussin check_delays(TERMTYPE2 *tp, const char *name, const char *value)
2074aae38d10SBaptiste Daroussin {
2075aae38d10SBaptiste Daroussin     const char *p, *q;
2076aae38d10SBaptiste Daroussin     const char *first = 0;
2077aae38d10SBaptiste Daroussin     const char *last = 0;
2078aae38d10SBaptiste Daroussin 
2079aae38d10SBaptiste Daroussin     for (p = value; *p != '\0'; ++p) {
2080aae38d10SBaptiste Daroussin 	if (p[0] == '$' && p[1] == '<') {
2081aae38d10SBaptiste Daroussin 	    const char *base = p + 2;
2082aae38d10SBaptiste Daroussin 	    const char *mark = 0;
2083aae38d10SBaptiste Daroussin 	    bool maybe = TRUE;
2084aae38d10SBaptiste Daroussin 	    bool mixed = FALSE;
2085aae38d10SBaptiste Daroussin 	    int proportional = 0;
2086aae38d10SBaptiste Daroussin 	    int mandatory = 0;
2087aae38d10SBaptiste Daroussin 
2088aae38d10SBaptiste Daroussin 	    first = p;
2089aae38d10SBaptiste Daroussin 
2090aae38d10SBaptiste Daroussin 	    for (q = base; *q != '\0'; ++q) {
2091aae38d10SBaptiste Daroussin 		if (*q == '>') {
2092aae38d10SBaptiste Daroussin 		    if (mark == 0)
2093aae38d10SBaptiste Daroussin 			mark = q;
2094aae38d10SBaptiste Daroussin 		    break;
2095aae38d10SBaptiste Daroussin 		} else if (*q == '*' || *q == '/') {
2096aae38d10SBaptiste Daroussin 		    if (*q == '*')
2097aae38d10SBaptiste Daroussin 			++proportional;
2098aae38d10SBaptiste Daroussin 		    if (*q == '/')
2099aae38d10SBaptiste Daroussin 			++mandatory;
2100aae38d10SBaptiste Daroussin 		    if (mark == 0)
2101aae38d10SBaptiste Daroussin 			mark = q;
2102aae38d10SBaptiste Daroussin 		} else if (!(isalnum(UChar(*q)) || strchr("+-.", *q) != 0)) {
2103aae38d10SBaptiste Daroussin 		    maybe = FALSE;
2104aae38d10SBaptiste Daroussin 		    break;
2105aae38d10SBaptiste Daroussin 		} else if (proportional || mandatory) {
2106aae38d10SBaptiste Daroussin 		    mixed = TRUE;
2107aae38d10SBaptiste Daroussin 		}
2108aae38d10SBaptiste Daroussin 	    }
2109aae38d10SBaptiste Daroussin 	    last = *q ? (q + 1) : q;
2110aae38d10SBaptiste Daroussin 	    if (*q == '\0') {
2111aae38d10SBaptiste Daroussin 		maybe = FALSE;	/* just an isolated "$<" */
2112aae38d10SBaptiste Daroussin 	    } else if (maybe) {
2113aae38d10SBaptiste Daroussin 		float check_f;
2114aae38d10SBaptiste Daroussin 		char check_c;
2115aae38d10SBaptiste Daroussin 		int rc = sscanf(base, "%f%c", &check_f, &check_c);
2116aae38d10SBaptiste Daroussin 		if ((rc != 2) || (check_c != *mark) || mixed) {
2117aae38d10SBaptiste Daroussin 		    _nc_warning("syntax error in %s delay '%.*s'", name,
2118aae38d10SBaptiste Daroussin 				(int) (q - base), base);
2119aae38d10SBaptiste Daroussin 		} else if (*name == 'k') {
2120aae38d10SBaptiste Daroussin 		    _nc_warning("function-key %s has delay", name);
2121aae38d10SBaptiste Daroussin 		} else if (proportional && !line_capability(name)) {
2122aae38d10SBaptiste Daroussin 		    _nc_warning("non-line capability using proportional delay: %s", name);
2123aae38d10SBaptiste Daroussin 		} else if (!xon_xoff &&
2124aae38d10SBaptiste Daroussin 			   !mandatory &&
2125aae38d10SBaptiste Daroussin 			   strchr(_nc_first_name(tp->term_names), '+') == 0) {
2126aae38d10SBaptiste Daroussin 		    _nc_warning("%s in %s is used since no xon/xoff",
2127aae38d10SBaptiste Daroussin 				(proportional
2128aae38d10SBaptiste Daroussin 				 ? "proportional delay"
2129aae38d10SBaptiste Daroussin 				 : "delay"),
2130aae38d10SBaptiste Daroussin 				name);
2131aae38d10SBaptiste Daroussin 		}
2132aae38d10SBaptiste Daroussin 	    } else {
2133aae38d10SBaptiste Daroussin 		p = q - 1;	/* restart scan */
2134aae38d10SBaptiste Daroussin 	    }
2135aae38d10SBaptiste Daroussin 	}
2136aae38d10SBaptiste Daroussin     }
2137aae38d10SBaptiste Daroussin 
2138aae38d10SBaptiste Daroussin     if (!strcmp(name, "flash") ||
2139aae38d10SBaptiste Daroussin 	!strcmp(name, "beep")) {
2140aae38d10SBaptiste Daroussin 
2141aae38d10SBaptiste Daroussin 	if (first != 0) {
2142aae38d10SBaptiste Daroussin 	    if (first == value || *last == 0) {
2143aae38d10SBaptiste Daroussin 		/*
2144aae38d10SBaptiste Daroussin 		 * Delay is on one end or the other.
2145aae38d10SBaptiste Daroussin 		 */
2146aae38d10SBaptiste Daroussin 		_nc_warning("expected delay embedded within %s", name);
2147aae38d10SBaptiste Daroussin 	    }
2148aae38d10SBaptiste Daroussin 	} else {
2149aae38d10SBaptiste Daroussin 	    int flag;
2150aae38d10SBaptiste Daroussin 
2151aae38d10SBaptiste Daroussin 	    /*
2152aae38d10SBaptiste Daroussin 	     * Check for missing delay when using VT100 reverse-video.
2153aae38d10SBaptiste Daroussin 	     * A real VT100 might not need this, but terminal emulators do.
2154aae38d10SBaptiste Daroussin 	     */
2155aae38d10SBaptiste Daroussin 	    if ((p = skip_DECSCNM(value, &flag)) != 0 &&
2156aae38d10SBaptiste Daroussin 		flag > 0 &&
2157aae38d10SBaptiste Daroussin 		(q = skip_DECSCNM(p, &flag)) != 0 &&
2158aae38d10SBaptiste Daroussin 		flag == 0) {
2159aae38d10SBaptiste Daroussin 		_nc_warning("expected a delay in %s", name);
2160aae38d10SBaptiste Daroussin 	    }
2161aae38d10SBaptiste Daroussin 	}
2162aae38d10SBaptiste Daroussin     }
2163aae38d10SBaptiste Daroussin }
2164aae38d10SBaptiste Daroussin 
2165aae38d10SBaptiste Daroussin static char *
2166aae38d10SBaptiste Daroussin check_1_infotocap(const char *name, NCURSES_CONST char *value, int count)
2167aae38d10SBaptiste Daroussin {
2168aae38d10SBaptiste Daroussin     int k;
2169aae38d10SBaptiste Daroussin     int ignored;
2170aae38d10SBaptiste Daroussin     long numbers[1 + NUM_PARM];
2171aae38d10SBaptiste Daroussin     char *strings[1 + NUM_PARM];
2172aae38d10SBaptiste Daroussin     char *p_is_s[NUM_PARM];
2173aae38d10SBaptiste Daroussin     char *result;
2174aae38d10SBaptiste Daroussin     char blob[NUM_PARM * 10];
2175aae38d10SBaptiste Daroussin     char *next = blob;
2176aae38d10SBaptiste Daroussin 
2177aae38d10SBaptiste Daroussin     *next++ = '\0';
2178aae38d10SBaptiste Daroussin     for (k = 1; k <= NUM_PARM; k++) {
2179aae38d10SBaptiste Daroussin 	numbers[k] = count;
2180aae38d10SBaptiste Daroussin 	_nc_SPRINTF(next,
2181aae38d10SBaptiste Daroussin 		    _nc_SLIMIT(sizeof(blob) - (size_t) (next - blob))
2182aae38d10SBaptiste Daroussin 		    "XYZ%d", count);
2183aae38d10SBaptiste Daroussin 	strings[k] = next;
2184aae38d10SBaptiste Daroussin 	next += strlen(next) + 1;
2185aae38d10SBaptiste Daroussin     }
2186aae38d10SBaptiste Daroussin 
2187aae38d10SBaptiste Daroussin     switch (tparm_type(name)) {
2188aae38d10SBaptiste Daroussin     case Num_Str:
2189aae38d10SBaptiste Daroussin 	result = TPARM_2(value, numbers[1], strings[2]);
2190aae38d10SBaptiste Daroussin 	break;
2191aae38d10SBaptiste Daroussin     case Num_Str_Str:
2192aae38d10SBaptiste Daroussin 	result = TPARM_3(value, numbers[1], strings[2], strings[3]);
2193aae38d10SBaptiste Daroussin 	break;
2194aae38d10SBaptiste Daroussin     case Numbers:
2195aae38d10SBaptiste Daroussin     default:
2196aae38d10SBaptiste Daroussin 	(void) _nc_tparm_analyze(value, p_is_s, &ignored);
2197aae38d10SBaptiste Daroussin #define myParam(n) (p_is_s[n - 1] != 0 ? ((TPARM_ARG) strings[n]) : numbers[n])
2198aae38d10SBaptiste Daroussin 	result = TPARM_9(value,
2199aae38d10SBaptiste Daroussin 			 myParam(1),
2200aae38d10SBaptiste Daroussin 			 myParam(2),
2201aae38d10SBaptiste Daroussin 			 myParam(3),
2202aae38d10SBaptiste Daroussin 			 myParam(4),
2203aae38d10SBaptiste Daroussin 			 myParam(5),
2204aae38d10SBaptiste Daroussin 			 myParam(6),
2205aae38d10SBaptiste Daroussin 			 myParam(7),
2206aae38d10SBaptiste Daroussin 			 myParam(8),
2207aae38d10SBaptiste Daroussin 			 myParam(9));
2208aae38d10SBaptiste Daroussin 	break;
2209aae38d10SBaptiste Daroussin     }
2210aae38d10SBaptiste Daroussin     return strdup(result);
2211aae38d10SBaptiste Daroussin }
2212aae38d10SBaptiste Daroussin 
2213aae38d10SBaptiste Daroussin #define IsDelay(ch) ((ch) == '.' || isdigit(UChar(ch)))
2214aae38d10SBaptiste Daroussin 
2215aae38d10SBaptiste Daroussin static const char *
2216aae38d10SBaptiste Daroussin parse_delay_value(const char *src, double *delays, int *always)
2217aae38d10SBaptiste Daroussin {
2218aae38d10SBaptiste Daroussin     int star = 0;
2219aae38d10SBaptiste Daroussin 
2220aae38d10SBaptiste Daroussin     *delays = 0.0;
2221aae38d10SBaptiste Daroussin     if (always)
2222aae38d10SBaptiste Daroussin 	*always = 0;
2223aae38d10SBaptiste Daroussin 
2224aae38d10SBaptiste Daroussin     while (isdigit(UChar(*src))) {
2225aae38d10SBaptiste Daroussin 	(*delays) = (*delays) * 10 + (*src++ - '0');
2226aae38d10SBaptiste Daroussin     }
2227aae38d10SBaptiste Daroussin     if (*src == '.') {
2228aae38d10SBaptiste Daroussin 	int gotdot = 1;
2229aae38d10SBaptiste Daroussin 
2230aae38d10SBaptiste Daroussin 	++src;
2231aae38d10SBaptiste Daroussin 	while (isdigit(UChar(*src))) {
2232aae38d10SBaptiste Daroussin 	    gotdot *= 10;
2233aae38d10SBaptiste Daroussin 	    (*delays) += (*src++ - '0') / gotdot;
2234aae38d10SBaptiste Daroussin 	}
2235aae38d10SBaptiste Daroussin     }
2236aae38d10SBaptiste Daroussin     while (*src == '*' || *src == '/') {
2237aae38d10SBaptiste Daroussin 	if (always == 0 && *src == '/')
2238aae38d10SBaptiste Daroussin 	    break;
2239aae38d10SBaptiste Daroussin 	if (*src++ == '*') {
2240aae38d10SBaptiste Daroussin 	    star = 1;
2241aae38d10SBaptiste Daroussin 	} else {
2242aae38d10SBaptiste Daroussin 	    *always = 1;
2243aae38d10SBaptiste Daroussin 	}
2244aae38d10SBaptiste Daroussin     }
2245aae38d10SBaptiste Daroussin     if (star)
2246aae38d10SBaptiste Daroussin 	*delays = -(*delays);
2247aae38d10SBaptiste Daroussin     return src;
2248aae38d10SBaptiste Daroussin }
2249aae38d10SBaptiste Daroussin 
2250aae38d10SBaptiste Daroussin static const char *
2251aae38d10SBaptiste Daroussin parse_ti_delay(const char *ti, double *delays)
2252aae38d10SBaptiste Daroussin {
2253aae38d10SBaptiste Daroussin     *delays = 0.0;
2254aae38d10SBaptiste Daroussin     while (*ti != '\0') {
2255aae38d10SBaptiste Daroussin 	if (*ti == '\\') {
2256aae38d10SBaptiste Daroussin 	    ++ti;
2257aae38d10SBaptiste Daroussin 	}
2258aae38d10SBaptiste Daroussin 	if (ti[0] == '$'
2259aae38d10SBaptiste Daroussin 	    && ti[1] == '<'
2260aae38d10SBaptiste Daroussin 	    && IsDelay(UChar(ti[2]))) {
2261aae38d10SBaptiste Daroussin 	    int ignored;
2262aae38d10SBaptiste Daroussin 	    const char *last = parse_delay_value(ti + 2, delays, &ignored);
2263aae38d10SBaptiste Daroussin 	    if (*last == '>') {
2264aae38d10SBaptiste Daroussin 		ti = last;
2265aae38d10SBaptiste Daroussin 	    }
2266aae38d10SBaptiste Daroussin 	} else {
2267aae38d10SBaptiste Daroussin 	    ++ti;
2268aae38d10SBaptiste Daroussin 	}
2269aae38d10SBaptiste Daroussin     }
2270aae38d10SBaptiste Daroussin     return ti;
2271aae38d10SBaptiste Daroussin }
2272aae38d10SBaptiste Daroussin 
2273aae38d10SBaptiste Daroussin static const char *
2274aae38d10SBaptiste Daroussin parse_tc_delay(const char *tc, double *delays)
2275aae38d10SBaptiste Daroussin {
2276aae38d10SBaptiste Daroussin     return parse_delay_value(tc, delays, (int *) 0);
2277aae38d10SBaptiste Daroussin }
2278aae38d10SBaptiste Daroussin 
2279aae38d10SBaptiste Daroussin /*
2280aae38d10SBaptiste Daroussin  * Compare terminfo- and termcap-strings, factoring out delays.
2281aae38d10SBaptiste Daroussin  */
2282aae38d10SBaptiste Daroussin static bool
2283aae38d10SBaptiste Daroussin same_ti_tc(const char *ti, const char *tc, bool * embedded)
2284aae38d10SBaptiste Daroussin {
2285aae38d10SBaptiste Daroussin     bool same = TRUE;
2286aae38d10SBaptiste Daroussin     double ti_delay = 0.0;
2287aae38d10SBaptiste Daroussin     double tc_delay = 0.0;
2288aae38d10SBaptiste Daroussin     const char *ti_last;
2289aae38d10SBaptiste Daroussin 
2290aae38d10SBaptiste Daroussin     *embedded = FALSE;
2291aae38d10SBaptiste Daroussin     ti_last = parse_ti_delay(ti, &ti_delay);
2292aae38d10SBaptiste Daroussin     tc = parse_tc_delay(tc, &tc_delay);
2293aae38d10SBaptiste Daroussin 
2294aae38d10SBaptiste Daroussin     while ((ti < ti_last) && *tc) {
2295aae38d10SBaptiste Daroussin 	if (*ti == '\\' && ispunct(UChar(ti[1]))) {
2296aae38d10SBaptiste Daroussin 	    ++ti;
2297aae38d10SBaptiste Daroussin 	    if ((*ti == '^') && !strncmp(tc, "\\136", 4)) {
2298aae38d10SBaptiste Daroussin 		ti += 1;
2299aae38d10SBaptiste Daroussin 		tc += 4;
2300aae38d10SBaptiste Daroussin 		continue;
2301aae38d10SBaptiste Daroussin 	    }
2302aae38d10SBaptiste Daroussin 	} else if (ti[0] == '$' && ti[1] == '<') {
2303aae38d10SBaptiste Daroussin 	    double no_delay;
2304aae38d10SBaptiste Daroussin 	    const char *ss = parse_ti_delay(ti, &no_delay);
2305aae38d10SBaptiste Daroussin 	    if (ss != ti) {
2306aae38d10SBaptiste Daroussin 		*embedded = TRUE;
2307aae38d10SBaptiste Daroussin 		ti = ss;
2308aae38d10SBaptiste Daroussin 		continue;
2309aae38d10SBaptiste Daroussin 	    }
2310aae38d10SBaptiste Daroussin 	}
2311aae38d10SBaptiste Daroussin 	if (*tc == '\\' && ispunct(UChar(tc[1]))) {
2312aae38d10SBaptiste Daroussin 	    ++tc;
2313aae38d10SBaptiste Daroussin 	}
2314aae38d10SBaptiste Daroussin 	if (*ti++ != *tc++) {
2315aae38d10SBaptiste Daroussin 	    same = FALSE;
2316aae38d10SBaptiste Daroussin 	    break;
2317aae38d10SBaptiste Daroussin 	}
2318aae38d10SBaptiste Daroussin     }
2319aae38d10SBaptiste Daroussin 
2320aae38d10SBaptiste Daroussin     if (*embedded) {
2321aae38d10SBaptiste Daroussin 	if (same) {
2322aae38d10SBaptiste Daroussin 	    same = FALSE;
2323aae38d10SBaptiste Daroussin 	} else {
2324aae38d10SBaptiste Daroussin 	    *embedded = FALSE;	/* report only one problem */
2325aae38d10SBaptiste Daroussin 	}
2326aae38d10SBaptiste Daroussin     }
2327aae38d10SBaptiste Daroussin 
2328aae38d10SBaptiste Daroussin     return same;
2329aae38d10SBaptiste Daroussin }
2330aae38d10SBaptiste Daroussin 
2331aae38d10SBaptiste Daroussin /*
2332aae38d10SBaptiste Daroussin  * Check terminfo to termcap translation.
2333aae38d10SBaptiste Daroussin  */
2334aae38d10SBaptiste Daroussin static void
2335aae38d10SBaptiste Daroussin check_infotocap(TERMTYPE2 *tp, int i, const char *value)
2336aae38d10SBaptiste Daroussin {
2337aae38d10SBaptiste Daroussin     const char *name = ExtStrname(tp, i, strnames);
2338aae38d10SBaptiste Daroussin     int params = ((i < (int) SIZEOF(parametrized))
2339aae38d10SBaptiste Daroussin 		  ? parametrized[i]
2340aae38d10SBaptiste Daroussin 		  : ((*value == 'k')
2341aae38d10SBaptiste Daroussin 		     ? 0
2342aae38d10SBaptiste Daroussin 		     : has_params(value)));
2343aae38d10SBaptiste Daroussin     int to_char = 0;
2344aae38d10SBaptiste Daroussin     char *ti_value;
2345aae38d10SBaptiste Daroussin     char *tc_value;
2346aae38d10SBaptiste Daroussin     bool embedded;
2347aae38d10SBaptiste Daroussin 
2348aae38d10SBaptiste Daroussin     assert(SIZEOF(parametrized) == STRCOUNT);
2349aae38d10SBaptiste Daroussin     if ((ti_value = _nc_tic_expand(value, TRUE, to_char)) == ABSENT_STRING) {
2350aae38d10SBaptiste Daroussin 	_nc_warning("tic-expansion of %s failed", name);
2351aae38d10SBaptiste Daroussin     } else if ((tc_value = _nc_infotocap(name, ti_value, params)) == ABSENT_STRING) {
2352aae38d10SBaptiste Daroussin 	_nc_warning("tic-conversion of %s failed", name);
2353aae38d10SBaptiste Daroussin     } else if (params > 0) {
2354aae38d10SBaptiste Daroussin 	int limit = 5;
2355aae38d10SBaptiste Daroussin 	int count;
2356aae38d10SBaptiste Daroussin 	bool first = TRUE;
2357aae38d10SBaptiste Daroussin 
2358aae38d10SBaptiste Daroussin 	if (!strcmp(name, "setf")
2359aae38d10SBaptiste Daroussin 	    || !strcmp(name, "setb")
2360aae38d10SBaptiste Daroussin 	    || !strcmp(name, "setaf")
2361aae38d10SBaptiste Daroussin 	    || !strcmp(name, "setab")) {
2362aae38d10SBaptiste Daroussin 	    if ((limit = max_colors) > 16)
2363aae38d10SBaptiste Daroussin 		limit = 16;
2364aae38d10SBaptiste Daroussin 	}
2365aae38d10SBaptiste Daroussin 	for (count = 0; count < limit; ++count) {
2366aae38d10SBaptiste Daroussin 	    char *ti_check = check_1_infotocap(name, ti_value, count);
2367aae38d10SBaptiste Daroussin 	    char *tc_check = check_1_infotocap(name, tc_value, count);
2368aae38d10SBaptiste Daroussin 
2369aae38d10SBaptiste Daroussin 	    if (strcmp(ti_check, tc_check)) {
2370aae38d10SBaptiste Daroussin 		if (first) {
2371aae38d10SBaptiste Daroussin 		    fprintf(stderr, "check_infotocap(%s)\n", name);
2372aae38d10SBaptiste Daroussin 		    fprintf(stderr, "...ti '%s'\n", ti_value);
2373aae38d10SBaptiste Daroussin 		    fprintf(stderr, "...tc '%s'\n", tc_value);
2374aae38d10SBaptiste Daroussin 		    first = FALSE;
2375aae38d10SBaptiste Daroussin 		}
2376aae38d10SBaptiste Daroussin 		_nc_warning("tparm-conversion of %s(%d) differs between\n\tterminfo %s\n\ttermcap  %s",
2377aae38d10SBaptiste Daroussin 			    name, count, ti_check, tc_check);
2378aae38d10SBaptiste Daroussin 	    }
2379aae38d10SBaptiste Daroussin 	    free(ti_check);
2380aae38d10SBaptiste Daroussin 	    free(tc_check);
2381aae38d10SBaptiste Daroussin 	}
2382aae38d10SBaptiste Daroussin     } else if (params == 0 && !same_ti_tc(ti_value, tc_value, &embedded)) {
2383aae38d10SBaptiste Daroussin 	if (embedded) {
2384aae38d10SBaptiste Daroussin 	    _nc_warning("termcap equivalent of %s cannot use embedded delay", name);
2385aae38d10SBaptiste Daroussin 	} else {
2386aae38d10SBaptiste Daroussin 	    _nc_warning("tic-conversion of %s changed value\n\tfrom %s\n\tto   %s",
2387aae38d10SBaptiste Daroussin 			name, ti_value, tc_value);
2388aae38d10SBaptiste Daroussin 	}
2389aae38d10SBaptiste Daroussin     }
239018259542SPeter Wemm }
239118259542SPeter Wemm 
2392b82face1SPeter Wemm static char *
2393b82face1SPeter Wemm skip_delay(char *s)
2394b82face1SPeter Wemm {
2395b82face1SPeter Wemm     while (*s == '/' || isdigit(UChar(*s)))
2396b82face1SPeter Wemm 	++s;
2397b82face1SPeter Wemm     return s;
2398b82face1SPeter Wemm }
2399b82face1SPeter Wemm 
240018259542SPeter Wemm /*
24014a1a9510SRong-En Fan  * Skip a delay altogether, e.g., when comparing a simple string to sgr,
24024a1a9510SRong-En Fan  * the latter may have a worst-case delay on the end.
24034a1a9510SRong-En Fan  */
24044a1a9510SRong-En Fan static char *
24054a1a9510SRong-En Fan ignore_delays(char *s)
24064a1a9510SRong-En Fan {
24074a1a9510SRong-En Fan     int delaying = 0;
24084a1a9510SRong-En Fan 
24094a1a9510SRong-En Fan     do {
24104a1a9510SRong-En Fan 	switch (*s) {
24114a1a9510SRong-En Fan 	case '$':
24124a1a9510SRong-En Fan 	    if (delaying == 0)
24134a1a9510SRong-En Fan 		delaying = 1;
24144a1a9510SRong-En Fan 	    break;
24154a1a9510SRong-En Fan 	case '<':
24164a1a9510SRong-En Fan 	    if (delaying == 1)
24174a1a9510SRong-En Fan 		delaying = 2;
24184a1a9510SRong-En Fan 	    break;
24194a1a9510SRong-En Fan 	case '\0':
24204a1a9510SRong-En Fan 	    delaying = 0;
24214a1a9510SRong-En Fan 	    break;
24224a1a9510SRong-En Fan 	default:
24234a1a9510SRong-En Fan 	    if (delaying) {
24244a1a9510SRong-En Fan 		s = skip_delay(s);
24254a1a9510SRong-En Fan 		if (*s == '>')
24264a1a9510SRong-En Fan 		    ++s;
24274a1a9510SRong-En Fan 		delaying = 0;
24284a1a9510SRong-En Fan 	    }
24294a1a9510SRong-En Fan 	    break;
24304a1a9510SRong-En Fan 	}
24314a1a9510SRong-En Fan 	if (delaying)
24324a1a9510SRong-En Fan 	    ++s;
24334a1a9510SRong-En Fan     } while (delaying);
24344a1a9510SRong-En Fan     return s;
24354a1a9510SRong-En Fan }
24364a1a9510SRong-En Fan 
2437aae38d10SBaptiste Daroussin #define DATA(name) { #name }
2438aae38d10SBaptiste Daroussin static const char sgr_names[][11] =
2439aae38d10SBaptiste Daroussin {
2440aae38d10SBaptiste Daroussin     DATA(none),
2441aae38d10SBaptiste Daroussin     DATA(standout),
2442aae38d10SBaptiste Daroussin     DATA(underline),
2443aae38d10SBaptiste Daroussin     DATA(reverse),
2444aae38d10SBaptiste Daroussin     DATA(blink),
2445aae38d10SBaptiste Daroussin     DATA(dim),
2446aae38d10SBaptiste Daroussin     DATA(bold),
2447aae38d10SBaptiste Daroussin     DATA(invis),
2448aae38d10SBaptiste Daroussin     DATA(protect),
2449aae38d10SBaptiste Daroussin     DATA(altcharset),
2450aae38d10SBaptiste Daroussin     ""
2451aae38d10SBaptiste Daroussin };
2452aae38d10SBaptiste Daroussin #undef DATA
2453aae38d10SBaptiste Daroussin 
24544a1a9510SRong-En Fan /*
245515589c42SPeter Wemm  * An sgr string may contain several settings other than the one we're
245615589c42SPeter Wemm  * interested in, essentially sgr0 + rmacs + whatever.  As long as the
245715589c42SPeter Wemm  * "whatever" is contained in the sgr string, that is close enough for our
245815589c42SPeter Wemm  * sanity check.
245915589c42SPeter Wemm  */
246015589c42SPeter Wemm static bool
2461b82face1SPeter Wemm similar_sgr(int num, char *a, char *b)
246215589c42SPeter Wemm {
2463b82face1SPeter Wemm     char *base_a = a;
2464b82face1SPeter Wemm     char *base_b = b;
2465b82face1SPeter Wemm     int delaying = 0;
2466b82face1SPeter Wemm 
246715589c42SPeter Wemm     while (*b != 0) {
246815589c42SPeter Wemm 	while (*a != *b) {
24697a69bbfbSPeter Wemm 	    if (*a == 0) {
2470aae38d10SBaptiste Daroussin 		if (num < 0) {
2471aae38d10SBaptiste Daroussin 		    ;
2472aae38d10SBaptiste Daroussin 		} else if (b[0] == '$'
24737a69bbfbSPeter Wemm 			   && b[1] == '<') {
2474aae38d10SBaptiste Daroussin 		    _nc_warning("did not find delay %s", _nc_visbuf(b));
24757a69bbfbSPeter Wemm 		} else {
2476b82face1SPeter Wemm 		    _nc_warning("checking sgr(%s) %s\n\tcompare to %s\n\tunmatched %s",
2477aae38d10SBaptiste Daroussin 				sgr_names[num], _nc_visbuf2(1, base_a),
2478b82face1SPeter Wemm 				_nc_visbuf2(2, base_b),
2479b82face1SPeter Wemm 				_nc_visbuf2(3, b));
24807a69bbfbSPeter Wemm 		}
248115589c42SPeter Wemm 		return FALSE;
2482b82face1SPeter Wemm 	    } else if (delaying) {
2483b82face1SPeter Wemm 		a = skip_delay(a);
2484b82face1SPeter Wemm 		b = skip_delay(b);
248506bfebdeSXin LI 	    } else if ((*b == '0' || (*b == ';')) && *a == 'm') {
248606bfebdeSXin LI 		b++;
2487b82face1SPeter Wemm 	    } else {
248815589c42SPeter Wemm 		a++;
248915589c42SPeter Wemm 	    }
2490b82face1SPeter Wemm 	}
2491b82face1SPeter Wemm 	switch (*a) {
2492b82face1SPeter Wemm 	case '$':
2493b82face1SPeter Wemm 	    if (delaying == 0)
2494b82face1SPeter Wemm 		delaying = 1;
2495b82face1SPeter Wemm 	    break;
2496b82face1SPeter Wemm 	case '<':
2497b82face1SPeter Wemm 	    if (delaying == 1)
2498b82face1SPeter Wemm 		delaying = 2;
2499b82face1SPeter Wemm 	    break;
2500b82face1SPeter Wemm 	default:
2501b82face1SPeter Wemm 	    delaying = 0;
2502b82face1SPeter Wemm 	    break;
2503b82face1SPeter Wemm 	}
250415589c42SPeter Wemm 	a++;
250515589c42SPeter Wemm 	b++;
250615589c42SPeter Wemm     }
25074a1a9510SRong-En Fan     /* ignore delays on the end of the string */
25084a1a9510SRong-En Fan     a = ignore_delays(a);
25094a1a9510SRong-En Fan     return ((num != 0) || (*a == 0));
251015589c42SPeter Wemm }
251115589c42SPeter Wemm 
25124a1a9510SRong-En Fan static char *
2513aae38d10SBaptiste Daroussin check_sgr(TERMTYPE2 *tp, char *zero, int num, char *cap, const char *name)
251415589c42SPeter Wemm {
25154a1a9510SRong-En Fan     char *test;
25164a1a9510SRong-En Fan 
25174a1a9510SRong-En Fan     _nc_tparm_err = 0;
25184a1a9510SRong-En Fan     test = TPARM_9(set_attributes,
251915589c42SPeter Wemm 		   num == 1,
252015589c42SPeter Wemm 		   num == 2,
252115589c42SPeter Wemm 		   num == 3,
252215589c42SPeter Wemm 		   num == 4,
252315589c42SPeter Wemm 		   num == 5,
252415589c42SPeter Wemm 		   num == 6,
252515589c42SPeter Wemm 		   num == 7,
252615589c42SPeter Wemm 		   num == 8,
252715589c42SPeter Wemm 		   num == 9);
252815589c42SPeter Wemm     if (test != 0) {
252915589c42SPeter Wemm 	if (PRESENT(cap)) {
2530b82face1SPeter Wemm 	    if (!similar_sgr(num, test, cap)) {
2531b82face1SPeter Wemm 		_nc_warning("%s differs from sgr(%d)\n\t%s=%s\n\tsgr(%d)=%s",
2532b82face1SPeter Wemm 			    name, num,
2533b82face1SPeter Wemm 			    name, _nc_visbuf2(1, cap),
2534b82face1SPeter Wemm 			    num, _nc_visbuf2(2, test));
253515589c42SPeter Wemm 	    }
25364a1a9510SRong-En Fan 	} else if (_nc_capcmp(test, zero)) {
253715589c42SPeter Wemm 	    _nc_warning("sgr(%d) present, but not %s", num, name);
253815589c42SPeter Wemm 	}
253915589c42SPeter Wemm     } else if (PRESENT(cap)) {
254015589c42SPeter Wemm 	_nc_warning("sgr(%d) missing, but %s present", num, name);
254115589c42SPeter Wemm     }
25424a1a9510SRong-En Fan     if (_nc_tparm_err)
25434a1a9510SRong-En Fan 	_nc_warning("stack error in sgr(%d) string", num);
25444a1a9510SRong-En Fan     return test;
254515589c42SPeter Wemm }
254615589c42SPeter Wemm 
254715589c42SPeter Wemm #define CHECK_SGR(num,name) check_sgr(tp, zero, num, name, #name)
254815589c42SPeter Wemm 
25494a1a9510SRong-En Fan #ifdef TRACE
25504a1a9510SRong-En Fan /*
25514a1a9510SRong-En Fan  * If tic is compiled with TRACE, we'll be able to see the output from the
25524a1a9510SRong-En Fan  * DEBUG() macro.  But since it doesn't use traceon(), it always goes to
25534a1a9510SRong-En Fan  * the standard error.  Use this function to make it simpler to follow the
25544a1a9510SRong-En Fan  * resulting debug traces.
25554a1a9510SRong-En Fan  */
25564a1a9510SRong-En Fan static void
25574a1a9510SRong-En Fan show_where(unsigned level)
25584a1a9510SRong-En Fan {
25594a1a9510SRong-En Fan     if (_nc_tracing >= DEBUG_LEVEL(level)) {
256073f0a83dSXin LI 	char my_name[MAX_NAME_SIZE];
25614a1a9510SRong-En Fan 	_nc_get_type(my_name);
256206bfebdeSXin LI 	_tracef("\"%s\", line %d, '%s'",
25634a1a9510SRong-En Fan 		_nc_get_source(),
25644a1a9510SRong-En Fan 		_nc_curr_line, my_name);
25654a1a9510SRong-En Fan     }
25664a1a9510SRong-En Fan }
25674a1a9510SRong-En Fan 
25684a1a9510SRong-En Fan #else
25694a1a9510SRong-En Fan #define show_where(level)	/* nothing */
25704a1a9510SRong-En Fan #endif
25714a1a9510SRong-En Fan 
257273f0a83dSXin LI typedef struct {
257373f0a83dSXin LI     int keycode;
257473f0a83dSXin LI     const char *name;
257573f0a83dSXin LI     const char *value;
257673f0a83dSXin LI } NAME_VALUE;
257773f0a83dSXin LI 
257873f0a83dSXin LI static NAME_VALUE *
2579aae38d10SBaptiste Daroussin get_fkey_list(TERMTYPE2 *tp)
258073f0a83dSXin LI {
258173f0a83dSXin LI     NAME_VALUE *result = typeMalloc(NAME_VALUE, NUM_STRINGS(tp) + 1);
258273f0a83dSXin LI     const struct tinfo_fkeys *all_fkeys = _nc_tinfo_fkeys;
258373f0a83dSXin LI     int used = 0;
2584aae38d10SBaptiste Daroussin     unsigned j;
258573f0a83dSXin LI 
258673f0a83dSXin LI     if (result == 0)
258773f0a83dSXin LI 	failed("get_fkey_list");
258873f0a83dSXin LI 
258973f0a83dSXin LI     for (j = 0; all_fkeys[j].code; j++) {
259073f0a83dSXin LI 	char *a = tp->Strings[all_fkeys[j].offset];
259173f0a83dSXin LI 	if (VALID_STRING(a)) {
259273f0a83dSXin LI 	    result[used].keycode = (int) all_fkeys[j].code;
259373f0a83dSXin LI 	    result[used].name = strnames[all_fkeys[j].offset];
259473f0a83dSXin LI 	    result[used].value = a;
259573f0a83dSXin LI 	    ++used;
259673f0a83dSXin LI 	}
259773f0a83dSXin LI     }
259873f0a83dSXin LI #if NCURSES_XNAMES
259973f0a83dSXin LI     for (j = STRCOUNT; j < NUM_STRINGS(tp); ++j) {
2600aae38d10SBaptiste Daroussin 	const char *name = ExtStrname(tp, (int) j, strnames);
260173f0a83dSXin LI 	if (*name == 'k') {
260273f0a83dSXin LI 	    result[used].keycode = -1;
260373f0a83dSXin LI 	    result[used].name = name;
260473f0a83dSXin LI 	    result[used].value = tp->Strings[j];
260573f0a83dSXin LI 	    ++used;
260673f0a83dSXin LI 	}
260773f0a83dSXin LI     }
260873f0a83dSXin LI #endif
260973f0a83dSXin LI     result[used].keycode = 0;
261073f0a83dSXin LI     return result;
261173f0a83dSXin LI }
261273f0a83dSXin LI 
261373f0a83dSXin LI static void
261473f0a83dSXin LI show_fkey_name(NAME_VALUE * data)
261573f0a83dSXin LI {
261673f0a83dSXin LI     if (data->keycode > 0) {
261773f0a83dSXin LI 	fprintf(stderr, " %s", keyname(data->keycode));
261873f0a83dSXin LI 	fprintf(stderr, " (capability \"%s\")", data->name);
261973f0a83dSXin LI     } else {
262073f0a83dSXin LI 	fprintf(stderr, " capability \"%s\"", data->name);
262173f0a83dSXin LI     }
262273f0a83dSXin LI }
262373f0a83dSXin LI 
2624aae38d10SBaptiste Daroussin /*
2625aae38d10SBaptiste Daroussin  * A terminal entry may contain more than one keycode assigned to a given
2626aae38d10SBaptiste Daroussin  * string (e.g., KEY_END and KEY_LL).  But curses will only return one (the
2627aae38d10SBaptiste Daroussin  * last one assigned).
26280e3d5408SPeter Wemm  */
262915589c42SPeter Wemm static void
2630aae38d10SBaptiste Daroussin check_conflict(TERMTYPE2 *tp)
26310e3d5408SPeter Wemm {
26320e3d5408SPeter Wemm     bool conflict = FALSE;
26330e3d5408SPeter Wemm     unsigned j, k;
26340e3d5408SPeter Wemm 
26354a1a9510SRong-En Fan     if (!(_nc_syntax == SYN_TERMCAP && capdump)) {
263673f0a83dSXin LI 	char *check = calloc((size_t) (NUM_STRINGS(tp) + 1), sizeof(char));
263773f0a83dSXin LI 	NAME_VALUE *given = get_fkey_list(tp);
263873f0a83dSXin LI 
263973f0a83dSXin LI 	if (check == 0)
2640aae38d10SBaptiste Daroussin 	    failed("check_conflict");
264173f0a83dSXin LI 
264273f0a83dSXin LI 	for (j = 0; given[j].keycode; ++j) {
264373f0a83dSXin LI 	    const char *a = given[j].value;
26440e3d5408SPeter Wemm 	    bool first = TRUE;
264573f0a83dSXin LI 
2646aae38d10SBaptiste Daroussin 	    if (!VALID_STRING(a))
2647aae38d10SBaptiste Daroussin 		continue;
2648aae38d10SBaptiste Daroussin 
264973f0a83dSXin LI 	    for (k = j + 1; given[k].keycode; k++) {
265073f0a83dSXin LI 		const char *b = given[k].value;
2651aae38d10SBaptiste Daroussin 
2652aae38d10SBaptiste Daroussin 		if (!VALID_STRING(b))
2653aae38d10SBaptiste Daroussin 		    continue;
265473f0a83dSXin LI 		if (check[k])
26550e3d5408SPeter Wemm 		    continue;
2656aae38d10SBaptiste Daroussin 
26574a1a9510SRong-En Fan 		if (!_nc_capcmp(a, b)) {
265873f0a83dSXin LI 		    check[j] = 1;
265973f0a83dSXin LI 		    check[k] = 1;
26600e3d5408SPeter Wemm 		    if (first) {
26610e3d5408SPeter Wemm 			if (!conflict) {
2662aae38d10SBaptiste Daroussin 			    _nc_warning("conflicting key definitions (using the last)");
26630e3d5408SPeter Wemm 			    conflict = TRUE;
26640e3d5408SPeter Wemm 			}
266573f0a83dSXin LI 			fprintf(stderr, "...");
266673f0a83dSXin LI 			show_fkey_name(given + j);
266773f0a83dSXin LI 			fprintf(stderr, " is the same as");
266873f0a83dSXin LI 			show_fkey_name(given + k);
26690e3d5408SPeter Wemm 			first = FALSE;
26700e3d5408SPeter Wemm 		    } else {
267173f0a83dSXin LI 			fprintf(stderr, ", ");
267273f0a83dSXin LI 			show_fkey_name(given + k);
26730e3d5408SPeter Wemm 		    }
26740e3d5408SPeter Wemm 		}
26750e3d5408SPeter Wemm 	    }
26760e3d5408SPeter Wemm 	    if (!first)
26770e3d5408SPeter Wemm 		fprintf(stderr, "\n");
26780e3d5408SPeter Wemm 	}
2679aae38d10SBaptiste Daroussin #if NCURSES_XNAMES
2680aae38d10SBaptiste Daroussin 	if (using_extensions) {
2681aae38d10SBaptiste Daroussin 	    /* *INDENT-OFF* */
2682aae38d10SBaptiste Daroussin 	    static struct {
2683aae38d10SBaptiste Daroussin 		const char *xcurses;
2684aae38d10SBaptiste Daroussin 		const char *shifted;
2685aae38d10SBaptiste Daroussin 	    } table[] = {
2686aae38d10SBaptiste Daroussin 		{ "kDC",  NULL },
2687aae38d10SBaptiste Daroussin 		{ "kDN",  "kind" },
2688aae38d10SBaptiste Daroussin 		{ "kEND", NULL },
2689aae38d10SBaptiste Daroussin 		{ "kHOM", NULL },
2690aae38d10SBaptiste Daroussin 		{ "kLFT", NULL },
2691aae38d10SBaptiste Daroussin 		{ "kNXT", NULL },
2692aae38d10SBaptiste Daroussin 		{ "kPRV", NULL },
2693aae38d10SBaptiste Daroussin 		{ "kRIT", NULL },
2694aae38d10SBaptiste Daroussin 		{ "kUP",  "kri" },
2695aae38d10SBaptiste Daroussin 		{ NULL,   NULL },
2696aae38d10SBaptiste Daroussin 	    };
2697aae38d10SBaptiste Daroussin 	    /* *INDENT-ON* */
2698aae38d10SBaptiste Daroussin 
2699aae38d10SBaptiste Daroussin 	    /*
2700aae38d10SBaptiste Daroussin 	     * SVr4 curses defines the "xcurses" names listed above except for
2701aae38d10SBaptiste Daroussin 	     * the special cases in the "shifted" column.  When using these
2702aae38d10SBaptiste Daroussin 	     * names for xterm's extensions, that was confusing, and resulted
2703aae38d10SBaptiste Daroussin 	     * in adding extended capabilities with "2" (shift) suffix.  This
2704aae38d10SBaptiste Daroussin 	     * check warns about unnecessary use of extensions for this quirk.
2705aae38d10SBaptiste Daroussin 	     */
2706aae38d10SBaptiste Daroussin 	    for (j = 0; given[j].keycode; ++j) {
2707aae38d10SBaptiste Daroussin 		const char *find = given[j].name;
2708aae38d10SBaptiste Daroussin 		int value;
2709aae38d10SBaptiste Daroussin 		char ch;
2710aae38d10SBaptiste Daroussin 
2711aae38d10SBaptiste Daroussin 		if (!VALID_STRING(given[j].value))
2712aae38d10SBaptiste Daroussin 		    continue;
2713aae38d10SBaptiste Daroussin 
2714aae38d10SBaptiste Daroussin 		for (k = 0; table[k].xcurses; ++k) {
2715aae38d10SBaptiste Daroussin 		    const char *test = table[k].xcurses;
2716aae38d10SBaptiste Daroussin 		    size_t size = strlen(test);
2717aae38d10SBaptiste Daroussin 
2718aae38d10SBaptiste Daroussin 		    if (!strncmp(find, test, size) && strcmp(find, test)) {
2719aae38d10SBaptiste Daroussin 			switch (sscanf(find + size, "%d%c", &value, &ch)) {
2720aae38d10SBaptiste Daroussin 			case 1:
2721aae38d10SBaptiste Daroussin 			    if (value == 2) {
2722aae38d10SBaptiste Daroussin 				_nc_warning("expected '%s' rather than '%s'",
2723aae38d10SBaptiste Daroussin 					    (table[k].shifted
2724aae38d10SBaptiste Daroussin 					     ? table[k].shifted
2725aae38d10SBaptiste Daroussin 					     : test), find);
2726aae38d10SBaptiste Daroussin 			    } else if (value < 2 || value > 15) {
2727aae38d10SBaptiste Daroussin 				_nc_warning("expected numeric 2..15 '%s'", find);
2728aae38d10SBaptiste Daroussin 			    }
2729aae38d10SBaptiste Daroussin 			    break;
2730aae38d10SBaptiste Daroussin 			default:
2731aae38d10SBaptiste Daroussin 			    _nc_warning("expected numeric suffix for '%s'", find);
2732aae38d10SBaptiste Daroussin 			    break;
2733aae38d10SBaptiste Daroussin 			}
2734aae38d10SBaptiste Daroussin 			break;
2735aae38d10SBaptiste Daroussin 		    }
2736aae38d10SBaptiste Daroussin 		}
2737aae38d10SBaptiste Daroussin 	    }
2738aae38d10SBaptiste Daroussin 	}
2739aae38d10SBaptiste Daroussin #endif
274073f0a83dSXin LI 	free(given);
274173f0a83dSXin LI 	free(check);
27424a1a9510SRong-En Fan     }
2743aae38d10SBaptiste Daroussin }
2744aae38d10SBaptiste Daroussin 
2745aae38d10SBaptiste Daroussin /*
2746aae38d10SBaptiste Daroussin  * Exiting a video mode should not duplicate sgr0
2747aae38d10SBaptiste Daroussin  */
2748aae38d10SBaptiste Daroussin static void
2749aae38d10SBaptiste Daroussin check_exit_attribute(const char *name, char *test, char *trimmed, char *untrimmed)
2750aae38d10SBaptiste Daroussin {
2751aae38d10SBaptiste Daroussin     if (VALID_STRING(test) && (trimmed != 0)) {
2752aae38d10SBaptiste Daroussin 	if (similar_sgr(-1, trimmed, test) ||
2753aae38d10SBaptiste Daroussin 	    similar_sgr(-1, untrimmed, test)) {
2754aae38d10SBaptiste Daroussin 	    _nc_warning("%s matches exit_attribute_mode", name);
2755aae38d10SBaptiste Daroussin 	}
2756aae38d10SBaptiste Daroussin     }
2757aae38d10SBaptiste Daroussin }
2758aae38d10SBaptiste Daroussin 
2759aae38d10SBaptiste Daroussin /*
2760aae38d10SBaptiste Daroussin  * Returns true if the string looks like a standard SGR string.
2761aae38d10SBaptiste Daroussin  */
2762aae38d10SBaptiste Daroussin static bool
2763aae38d10SBaptiste Daroussin is_sgr_string(char *value)
2764aae38d10SBaptiste Daroussin {
2765aae38d10SBaptiste Daroussin     bool result = FALSE;
2766aae38d10SBaptiste Daroussin 
2767aae38d10SBaptiste Daroussin     if (VALID_STRING(value)) {
2768aae38d10SBaptiste Daroussin 	int skip = csi_length(value);
2769aae38d10SBaptiste Daroussin 
2770aae38d10SBaptiste Daroussin 	if (skip) {
2771aae38d10SBaptiste Daroussin 	    int ch;
2772aae38d10SBaptiste Daroussin 
2773aae38d10SBaptiste Daroussin 	    result = TRUE;
2774aae38d10SBaptiste Daroussin 	    value += skip;
2775aae38d10SBaptiste Daroussin 	    while ((ch = UChar(*value++)) != '\0') {
2776aae38d10SBaptiste Daroussin 		if (isdigit(ch) || ch == ';') {
2777aae38d10SBaptiste Daroussin 		    ;
2778aae38d10SBaptiste Daroussin 		} else if (ch == 'm' && *value == '\0') {
2779aae38d10SBaptiste Daroussin 		    ;
2780aae38d10SBaptiste Daroussin 		} else {
2781aae38d10SBaptiste Daroussin 		    result = FALSE;
2782aae38d10SBaptiste Daroussin 		    break;
2783aae38d10SBaptiste Daroussin 		}
2784aae38d10SBaptiste Daroussin 	    }
2785aae38d10SBaptiste Daroussin 	}
2786aae38d10SBaptiste Daroussin     }
2787aae38d10SBaptiste Daroussin     return result;
2788aae38d10SBaptiste Daroussin }
2789aae38d10SBaptiste Daroussin 
2790aae38d10SBaptiste Daroussin /*
2791aae38d10SBaptiste Daroussin  * Check if the given capability contains a given SGR attribute.
2792aae38d10SBaptiste Daroussin  */
2793aae38d10SBaptiste Daroussin static void
2794aae38d10SBaptiste Daroussin check_sgr_param(TERMTYPE2 *tp, int code, const char *name, char *value)
2795aae38d10SBaptiste Daroussin {
2796aae38d10SBaptiste Daroussin     if (VALID_STRING(value)) {
2797aae38d10SBaptiste Daroussin 	int ncv = ((code != 0) ? (1 << (code - 1)) : 0);
2798aae38d10SBaptiste Daroussin 	char *test = tgoto(value, 0, 0);
2799aae38d10SBaptiste Daroussin 	if (is_sgr_string(test)) {
2800aae38d10SBaptiste Daroussin 	    int param = 0;
2801aae38d10SBaptiste Daroussin 	    int count = 0;
2802aae38d10SBaptiste Daroussin 	    int skips = 0;
2803aae38d10SBaptiste Daroussin 	    int color = (value == set_a_foreground ||
2804aae38d10SBaptiste Daroussin 			 value == set_a_background ||
2805aae38d10SBaptiste Daroussin 			 value == set_foreground ||
2806aae38d10SBaptiste Daroussin 			 value == set_background);
2807aae38d10SBaptiste Daroussin 	    while (*test != 0) {
2808aae38d10SBaptiste Daroussin 		if (isdigit(UChar(*test))) {
2809aae38d10SBaptiste Daroussin 		    param = 10 * param + (*test - '0');
2810aae38d10SBaptiste Daroussin 		    ++count;
2811aae38d10SBaptiste Daroussin 		} else {
2812aae38d10SBaptiste Daroussin 		    if (count) {
2813aae38d10SBaptiste Daroussin 			/*
2814aae38d10SBaptiste Daroussin 			 * Avoid unnecessary warning for xterm 256color codes.
2815aae38d10SBaptiste Daroussin 			 */
2816aae38d10SBaptiste Daroussin 			if (color && (param == 38 || param == 48))
2817aae38d10SBaptiste Daroussin 			    skips = 3;
2818aae38d10SBaptiste Daroussin 			if ((skips-- <= 0) && (param == code))
2819aae38d10SBaptiste Daroussin 			    break;
2820aae38d10SBaptiste Daroussin 		    }
2821aae38d10SBaptiste Daroussin 		    count = 0;
2822aae38d10SBaptiste Daroussin 		    param = 0;
2823aae38d10SBaptiste Daroussin 		}
2824aae38d10SBaptiste Daroussin 		++test;
2825aae38d10SBaptiste Daroussin 	    }
2826aae38d10SBaptiste Daroussin 	    if (count != 0 && param == code) {
2827aae38d10SBaptiste Daroussin 		if (code == 0 ||
2828aae38d10SBaptiste Daroussin 		    no_color_video < 0 ||
2829aae38d10SBaptiste Daroussin 		    !(no_color_video & ncv)) {
2830aae38d10SBaptiste Daroussin 		    _nc_warning("\"%s\" SGR-attribute used in %s",
2831aae38d10SBaptiste Daroussin 				sgr_names[code],
2832aae38d10SBaptiste Daroussin 				name);
2833aae38d10SBaptiste Daroussin 		}
2834aae38d10SBaptiste Daroussin 	    }
2835aae38d10SBaptiste Daroussin 	}
2836aae38d10SBaptiste Daroussin     }
2837aae38d10SBaptiste Daroussin }
2838aae38d10SBaptiste Daroussin 
2839aae38d10SBaptiste Daroussin #if NCURSES_XNAMES
2840aae38d10SBaptiste Daroussin static int
2841aae38d10SBaptiste Daroussin standard_type(const char *name)
2842aae38d10SBaptiste Daroussin {
2843aae38d10SBaptiste Daroussin     int result = -1;
2844aae38d10SBaptiste Daroussin     const struct name_table_entry *np;
2845aae38d10SBaptiste Daroussin 
2846aae38d10SBaptiste Daroussin     if ((np = _nc_find_entry(name, _nc_get_hash_table(0))) != 0) {
2847aae38d10SBaptiste Daroussin 	result = np->nte_type;
2848aae38d10SBaptiste Daroussin     }
2849aae38d10SBaptiste Daroussin     return result;
2850aae38d10SBaptiste Daroussin }
2851aae38d10SBaptiste Daroussin 
2852aae38d10SBaptiste Daroussin static const char *
2853aae38d10SBaptiste Daroussin name_of_type(int type)
2854aae38d10SBaptiste Daroussin {
2855aae38d10SBaptiste Daroussin     const char *result = "unknown";
2856aae38d10SBaptiste Daroussin     switch (type) {
2857aae38d10SBaptiste Daroussin     case BOOLEAN:
2858aae38d10SBaptiste Daroussin 	result = "boolean";
2859aae38d10SBaptiste Daroussin 	break;
2860aae38d10SBaptiste Daroussin     case NUMBER:
2861aae38d10SBaptiste Daroussin 	result = "number";
2862aae38d10SBaptiste Daroussin 	break;
2863aae38d10SBaptiste Daroussin     case STRING:
2864aae38d10SBaptiste Daroussin 	result = "string";
2865aae38d10SBaptiste Daroussin 	break;
2866aae38d10SBaptiste Daroussin     }
2867aae38d10SBaptiste Daroussin     return result;
2868aae38d10SBaptiste Daroussin }
2869aae38d10SBaptiste Daroussin 
2870aae38d10SBaptiste Daroussin static void
2871aae38d10SBaptiste Daroussin check_user_capability_type(const char *name, int actual)
2872aae38d10SBaptiste Daroussin {
2873aae38d10SBaptiste Daroussin     if (lookup_user_capability(name) == 0) {
2874aae38d10SBaptiste Daroussin 	int expected = standard_type(name);
2875aae38d10SBaptiste Daroussin 	if (expected >= 0) {
2876aae38d10SBaptiste Daroussin 	    _nc_warning("expected %s to be %s, but actually %s",
2877aae38d10SBaptiste Daroussin 			name,
2878aae38d10SBaptiste Daroussin 			name_of_type(actual),
2879aae38d10SBaptiste Daroussin 			name_of_type(expected)
2880aae38d10SBaptiste Daroussin 		);
2881aae38d10SBaptiste Daroussin 	} else if (*name != 'k') {
2882aae38d10SBaptiste Daroussin 	    _nc_warning("undocumented %s capability %s",
2883aae38d10SBaptiste Daroussin 			name_of_type(actual),
2884aae38d10SBaptiste Daroussin 			name);
2885aae38d10SBaptiste Daroussin 	}
2886aae38d10SBaptiste Daroussin     }
2887aae38d10SBaptiste Daroussin }
2888aae38d10SBaptiste Daroussin #endif
2889aae38d10SBaptiste Daroussin 
2890aae38d10SBaptiste Daroussin /* other sanity-checks (things that we don't want in the normal
2891aae38d10SBaptiste Daroussin  * logic that reads a terminfo entry)
2892aae38d10SBaptiste Daroussin  */
2893aae38d10SBaptiste Daroussin static void
2894aae38d10SBaptiste Daroussin check_termtype(TERMTYPE2 *tp, bool literal)
2895aae38d10SBaptiste Daroussin {
2896aae38d10SBaptiste Daroussin     unsigned j;
2897aae38d10SBaptiste Daroussin 
2898aae38d10SBaptiste Daroussin     check_conflict(tp);
28990e3d5408SPeter Wemm 
290073f0a83dSXin LI     for_each_string(j, tp) {
290118259542SPeter Wemm 	char *a = tp->Strings[j];
2902aae38d10SBaptiste Daroussin 	if (VALID_STRING(a)) {
2903aae38d10SBaptiste Daroussin 	    const char *name = ExtStrname(tp, (int) j, strnames);
2904aae38d10SBaptiste Daroussin 	    /*
2905aae38d10SBaptiste Daroussin 	     * If we expect parameters, or if there might be parameters,
2906aae38d10SBaptiste Daroussin 	     * check for consistent number of parameters.
2907aae38d10SBaptiste Daroussin 	     */
2908aae38d10SBaptiste Daroussin 	    if (j >= SIZEOF(parametrized) ||
2909aae38d10SBaptiste Daroussin 		is_user_capability(name) >= 0 ||
2910aae38d10SBaptiste Daroussin 		parametrized[j] > 0) {
2911aae38d10SBaptiste Daroussin 		check_params(tp, name, a, (j >= STRCOUNT));
291218259542SPeter Wemm 	    }
2913aae38d10SBaptiste Daroussin 	    check_delays(tp, ExtStrname(tp, (int) j, strnames), a);
2914aae38d10SBaptiste Daroussin 	    if (capdump) {
2915aae38d10SBaptiste Daroussin 		check_infotocap(tp, (int) j, a);
2916aae38d10SBaptiste Daroussin 	    }
2917aae38d10SBaptiste Daroussin 	}
2918aae38d10SBaptiste Daroussin     }
2919aae38d10SBaptiste Daroussin #if NCURSES_XNAMES
2920aae38d10SBaptiste Daroussin     /* in extended mode, verify that each extension is expected type */
2921aae38d10SBaptiste Daroussin     for_each_ext_boolean(j, tp) {
2922aae38d10SBaptiste Daroussin 	check_user_capability_type(ExtBoolname(tp, (int) j, strnames), BOOLEAN);
2923aae38d10SBaptiste Daroussin     }
2924aae38d10SBaptiste Daroussin     for_each_ext_number(j, tp) {
2925aae38d10SBaptiste Daroussin 	check_user_capability_type(ExtNumname(tp, (int) j, strnames), NUMBER);
2926aae38d10SBaptiste Daroussin     }
2927aae38d10SBaptiste Daroussin     for_each_ext_string(j, tp) {
2928aae38d10SBaptiste Daroussin 	check_user_capability_type(ExtStrname(tp, (int) j, strnames), STRING);
2929aae38d10SBaptiste Daroussin     }
2930aae38d10SBaptiste Daroussin #endif /* NCURSES_XNAMES */
293118259542SPeter Wemm 
29324a1a9510SRong-En Fan     check_acs(tp);
29334a1a9510SRong-En Fan     check_colors(tp);
293406bfebdeSXin LI     check_cursor(tp);
29354a1a9510SRong-En Fan     check_keypad(tp);
293606bfebdeSXin LI     check_printer(tp);
293773f0a83dSXin LI     check_screen(tp);
29380e3d5408SPeter Wemm 
29390e3d5408SPeter Wemm     /*
2940aae38d10SBaptiste Daroussin      * These are probably both or none.
2941aae38d10SBaptiste Daroussin      */
2942aae38d10SBaptiste Daroussin     PAIRED(parm_index, parm_rindex);
2943aae38d10SBaptiste Daroussin     PAIRED(parm_ich, parm_dch);
2944aae38d10SBaptiste Daroussin 
2945aae38d10SBaptiste Daroussin     /*
29460e3d5408SPeter Wemm      * These may be mismatched because the terminal description relies on
29470e3d5408SPeter Wemm      * restoring the cursor visibility by resetting it.
29480e3d5408SPeter Wemm      */
294915589c42SPeter Wemm     ANDMISSING(cursor_invisible, cursor_normal);
295015589c42SPeter Wemm     ANDMISSING(cursor_visible, cursor_normal);
295115589c42SPeter Wemm 
295215589c42SPeter Wemm     if (PRESENT(cursor_visible) && PRESENT(cursor_normal)
29534a1a9510SRong-En Fan 	&& !_nc_capcmp(cursor_visible, cursor_normal))
295415589c42SPeter Wemm 	_nc_warning("cursor_visible is same as cursor_normal");
29550e3d5408SPeter Wemm 
29560e3d5408SPeter Wemm     /*
29570e3d5408SPeter Wemm      * From XSI & O'Reilly, we gather that sc/rc are required if csr is
29580e3d5408SPeter Wemm      * given, because the cursor position after the scrolling operation is
29590e3d5408SPeter Wemm      * performed is undefined.
29600e3d5408SPeter Wemm      */
296115589c42SPeter Wemm     ANDMISSING(change_scroll_region, save_cursor);
296215589c42SPeter Wemm     ANDMISSING(change_scroll_region, restore_cursor);
296315589c42SPeter Wemm 
296406bfebdeSXin LI     /*
296506bfebdeSXin LI      * If we can clear tabs, we should be able to initialize them.
296606bfebdeSXin LI      */
296706bfebdeSXin LI     ANDMISSING(clear_all_tabs, set_tab);
296806bfebdeSXin LI 
296915589c42SPeter Wemm     if (PRESENT(set_attributes)) {
29704a1a9510SRong-En Fan 	char *zero = 0;
297115589c42SPeter Wemm 
29724a1a9510SRong-En Fan 	_nc_tparm_err = 0;
29734a1a9510SRong-En Fan 	if (PRESENT(exit_attribute_mode)) {
29744a1a9510SRong-En Fan 	    zero = strdup(CHECK_SGR(0, exit_attribute_mode));
29754a1a9510SRong-En Fan 	} else {
29764a1a9510SRong-En Fan 	    zero = strdup(TPARM_9(set_attributes, 0, 0, 0, 0, 0, 0, 0, 0, 0));
29774a1a9510SRong-En Fan 	}
29784a1a9510SRong-En Fan 	if (_nc_tparm_err)
29794a1a9510SRong-En Fan 	    _nc_warning("stack error in sgr(0) string");
29804a1a9510SRong-En Fan 
29814a1a9510SRong-En Fan 	if (zero != 0) {
298215589c42SPeter Wemm 	    CHECK_SGR(1, enter_standout_mode);
298315589c42SPeter Wemm 	    CHECK_SGR(2, enter_underline_mode);
298415589c42SPeter Wemm 	    CHECK_SGR(3, enter_reverse_mode);
298515589c42SPeter Wemm 	    CHECK_SGR(4, enter_blink_mode);
298615589c42SPeter Wemm 	    CHECK_SGR(5, enter_dim_mode);
298715589c42SPeter Wemm 	    CHECK_SGR(6, enter_bold_mode);
298815589c42SPeter Wemm 	    CHECK_SGR(7, enter_secure_mode);
298915589c42SPeter Wemm 	    CHECK_SGR(8, enter_protected_mode);
299015589c42SPeter Wemm 	    CHECK_SGR(9, enter_alt_charset_mode);
299115589c42SPeter Wemm 	    free(zero);
29924a1a9510SRong-En Fan 	} else {
29934a1a9510SRong-En Fan 	    _nc_warning("sgr(0) did not return a value");
299415589c42SPeter Wemm 	}
29954a1a9510SRong-En Fan     } else if (PRESENT(exit_attribute_mode) &&
29964a1a9510SRong-En Fan 	       set_attributes != CANCELLED_STRING) {
29974a1a9510SRong-En Fan 	if (_nc_syntax == SYN_TERMINFO)
29984a1a9510SRong-En Fan 	    _nc_warning("missing sgr string");
29994a1a9510SRong-En Fan     }
3000aae38d10SBaptiste Daroussin #define CHECK_SGR0(name) check_exit_attribute(#name, name, check_sgr0, exit_attribute_mode)
30014a1a9510SRong-En Fan     if (PRESENT(exit_attribute_mode)) {
30024a1a9510SRong-En Fan 	char *check_sgr0 = _nc_trim_sgr0(tp);
30034a1a9510SRong-En Fan 
30044a1a9510SRong-En Fan 	if (check_sgr0 == 0 || *check_sgr0 == '\0') {
30054a1a9510SRong-En Fan 	    _nc_warning("trimmed sgr0 is empty");
30064a1a9510SRong-En Fan 	} else {
30074a1a9510SRong-En Fan 	    show_where(2);
30084a1a9510SRong-En Fan 	    if (check_sgr0 != exit_attribute_mode) {
30094a1a9510SRong-En Fan 		DEBUG(2,
30104a1a9510SRong-En Fan 		      ("will trim sgr0\n\toriginal sgr0=%s\n\ttrimmed  sgr0=%s",
30114a1a9510SRong-En Fan 		       _nc_visbuf2(1, exit_attribute_mode),
30124a1a9510SRong-En Fan 		       _nc_visbuf2(2, check_sgr0)));
30134a1a9510SRong-En Fan 	    } else {
30144a1a9510SRong-En Fan 		DEBUG(2,
30154a1a9510SRong-En Fan 		      ("will not trim sgr0\n\toriginal sgr0=%s",
30164a1a9510SRong-En Fan 		       _nc_visbuf(exit_attribute_mode)));
30174a1a9510SRong-En Fan 	    }
30184a1a9510SRong-En Fan 	}
3019aae38d10SBaptiste Daroussin #if defined(exit_italics_mode)
3020aae38d10SBaptiste Daroussin 	CHECK_SGR0(exit_italics_mode);
3021aae38d10SBaptiste Daroussin #endif
3022aae38d10SBaptiste Daroussin 	CHECK_SGR0(exit_standout_mode);
3023aae38d10SBaptiste Daroussin 	CHECK_SGR0(exit_underline_mode);
3024aae38d10SBaptiste Daroussin 	if (check_sgr0 != exit_attribute_mode) {
3025aae38d10SBaptiste Daroussin 	    free(check_sgr0);
3026aae38d10SBaptiste Daroussin 	}
3027aae38d10SBaptiste Daroussin     }
3028aae38d10SBaptiste Daroussin #define CHECK_SGR_PARAM(code, name) check_sgr_param(tp, (int)code, #name, name)
3029aae38d10SBaptiste Daroussin     for (j = 0; *sgr_names[j] != '\0'; ++j) {
3030aae38d10SBaptiste Daroussin 	CHECK_SGR_PARAM(j, set_a_foreground);
3031aae38d10SBaptiste Daroussin 	CHECK_SGR_PARAM(j, set_a_background);
3032aae38d10SBaptiste Daroussin 	CHECK_SGR_PARAM(j, set_foreground);
3033aae38d10SBaptiste Daroussin 	CHECK_SGR_PARAM(j, set_background);
30344a1a9510SRong-En Fan     }
30354a1a9510SRong-En Fan #ifdef TRACE
30364a1a9510SRong-En Fan     show_where(2);
30374a1a9510SRong-En Fan     if (!auto_right_margin) {
30384a1a9510SRong-En Fan 	DEBUG(2,
30394a1a9510SRong-En Fan 	      ("can write to lower-right directly"));
30404a1a9510SRong-En Fan     } else if (PRESENT(enter_am_mode) && PRESENT(exit_am_mode)) {
30414a1a9510SRong-En Fan 	DEBUG(2,
30424a1a9510SRong-En Fan 	      ("can write to lower-right by suppressing automargin"));
30434a1a9510SRong-En Fan     } else if ((PRESENT(enter_insert_mode) && PRESENT(exit_insert_mode))
30444a1a9510SRong-En Fan 	       || PRESENT(insert_character) || PRESENT(parm_ich)) {
30454a1a9510SRong-En Fan 	DEBUG(2,
30464a1a9510SRong-En Fan 	      ("can write to lower-right by using inserts"));
30474a1a9510SRong-En Fan     } else {
30484a1a9510SRong-En Fan 	DEBUG(2,
30494a1a9510SRong-En Fan 	      ("cannot write to lower-right"));
30504a1a9510SRong-En Fan     }
30514a1a9510SRong-En Fan #endif
30520e3d5408SPeter Wemm 
30530e3d5408SPeter Wemm     /*
30540e3d5408SPeter Wemm      * Some standard applications (e.g., vi) and some non-curses
30554a1a9510SRong-En Fan      * applications (e.g., jove) get confused if we have both ich1 and
30560e3d5408SPeter Wemm      * smir/rmir.  Let's be nice and warn about that, too, even though
30570e3d5408SPeter Wemm      * ncurses handles it.
30580e3d5408SPeter Wemm      */
30590e3d5408SPeter Wemm     if ((PRESENT(enter_insert_mode) || PRESENT(exit_insert_mode))
3060aae38d10SBaptiste Daroussin 	&& PRESENT(insert_character)) {
30614a1a9510SRong-En Fan 	_nc_warning("non-curses applications may be confused by ich1 with smir/rmir");
30620e3d5408SPeter Wemm     }
30630e3d5408SPeter Wemm 
30640e3d5408SPeter Wemm     /*
30650e3d5408SPeter Wemm      * Finally, do the non-verbose checks
30660e3d5408SPeter Wemm      */
30670e3d5408SPeter Wemm     if (save_check_termtype != 0)
30684a1a9510SRong-En Fan 	save_check_termtype(tp, literal);
30690e3d5408SPeter Wemm }
3070