xref: /freebsd/contrib/ncurses/progs/tic.c (revision 21817992b3314c908ab50f0bb88d2ee750b9c4ac)
10e3d5408SPeter Wemm /****************************************************************************
2*21817992SBaptiste Daroussin  * Copyright 2018-2023,2024 Thomas E. Dickey                                *
3e1865124SBaptiste 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*21817992SBaptiste Daroussin MODULE_ID("$Id: tic.c,v 1.325 2024/03/02 19:33:22 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
free_namelist(char ** src)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
cleanup(void)11773f0a83dSXin LI cleanup(void)
1185d08fb1fSRong-En Fan {
1195d08fb1fSRong-En Fan #if NO_LEAKS
1205d08fb1fSRong-En Fan     free_namelist(namelst);
121aae38d10SBaptiste Daroussin     _nc_leaks_dump_entry();
1225d08fb1fSRong-En Fan #endif
1230e3d5408SPeter Wemm     if (tmp_fp != 0)
1240e3d5408SPeter Wemm 	fclose(tmp_fp);
1250e3d5408SPeter Wemm     if (to_remove != 0) {
126*21817992SBaptiste Daroussin 	int rc;
127*21817992SBaptiste Daroussin 
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
failed(const char * msg)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
usage(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
write_it(ENTRY * ep)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
immedhook(ENTRY * ep GCC_UNUSED)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
put_translate(int c)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;
307*21817992SBaptiste Daroussin     static size_t used;
3080e3d5408SPeter Wemm 
30915589c42SPeter Wemm     if (in_name) {
310*21817992SBaptiste Daroussin 	static size_t have;
311*21817992SBaptiste Daroussin 	static char *namebuf, *suffix;
312*21817992SBaptiste Daroussin 
31315589c42SPeter Wemm 	if (used + 1 >= have) {
31415589c42SPeter Wemm 	    have += 132;
315*21817992SBaptiste Daroussin 	    if ((namebuf = typeRealloc(char, have, namebuf)) == NULL)
31673f0a83dSXin LI 		  failed("put_translate namebuf");
317*21817992SBaptiste Daroussin 	    if ((suffix = typeRealloc(char, have, suffix)) == NULL)
31873f0a83dSXin LI 		  failed("put_translate suffix");
3190e3d5408SPeter Wemm 	}
32015589c42SPeter Wemm 	if (c == '\n' || c == '@') {
32115589c42SPeter Wemm 	    namebuf[used++] = '\0';
3220e3d5408SPeter Wemm 	    (void) putchar('<');
3230e3d5408SPeter Wemm 	    (void) fputs(namebuf, stdout);
3240e3d5408SPeter Wemm 	    putchar(c);
3250e3d5408SPeter Wemm 	    in_name = FALSE;
32615589c42SPeter Wemm 	} else if (c != '>') {
3275d08fb1fSRong-En Fan 	    namebuf[used++] = (char) c;
32815589c42SPeter Wemm 	} else {		/* ah! candidate name! */
3290e3d5408SPeter Wemm 	    char *up;
3300e3d5408SPeter Wemm 	    NCURSES_CONST char *tp;
3310e3d5408SPeter Wemm 
33215589c42SPeter Wemm 	    namebuf[used++] = '\0';
3330e3d5408SPeter Wemm 	    in_name = FALSE;
3340e3d5408SPeter Wemm 
3350e3d5408SPeter Wemm 	    suffix[0] = '\0';
3360e3d5408SPeter Wemm 	    if ((up = strchr(namebuf, '#')) != 0
3370e3d5408SPeter Wemm 		|| (up = strchr(namebuf, '=')) != 0
33815589c42SPeter Wemm 		|| ((up = strchr(namebuf, '@')) != 0 && up[1] == '>')) {
33973f0a83dSXin LI 		_nc_STRCPY(suffix, up, have);
3400e3d5408SPeter Wemm 		*up = '\0';
3410e3d5408SPeter Wemm 	    }
3420e3d5408SPeter Wemm 
34315589c42SPeter Wemm 	    if ((tp = nametrans(namebuf)) != 0) {
3440e3d5408SPeter Wemm 		(void) putchar(':');
3450e3d5408SPeter Wemm 		(void) fputs(tp, stdout);
3460e3d5408SPeter Wemm 		(void) fputs(suffix, stdout);
3470e3d5408SPeter Wemm 		(void) putchar(':');
34815589c42SPeter Wemm 	    } else {
3490e3d5408SPeter Wemm 		/* couldn't find a translation, just dump the name */
3500e3d5408SPeter Wemm 		(void) putchar('<');
3510e3d5408SPeter Wemm 		(void) fputs(namebuf, stdout);
3520e3d5408SPeter Wemm 		(void) fputs(suffix, stdout);
3530e3d5408SPeter Wemm 		(void) putchar('>');
3540e3d5408SPeter Wemm 	    }
35515589c42SPeter Wemm 	}
35615589c42SPeter Wemm     } else {
35715589c42SPeter Wemm 	used = 0;
35815589c42SPeter Wemm 	if (c == '<') {
35915589c42SPeter Wemm 	    in_name = TRUE;
36015589c42SPeter Wemm 	} else {
36115589c42SPeter Wemm 	    putchar(c);
36215589c42SPeter Wemm 	}
3630e3d5408SPeter Wemm     }
3640e3d5408SPeter Wemm }
3650e3d5408SPeter Wemm 
3660e3d5408SPeter Wemm /* Returns a string, stripped of leading/trailing whitespace */
36715589c42SPeter Wemm static char *
stripped(char * src)36815589c42SPeter Wemm stripped(char *src)
3690e3d5408SPeter Wemm {
37073f0a83dSXin LI     char *dst = 0;
37173f0a83dSXin LI 
37239f2269fSPeter Wemm     while (isspace(UChar(*src)))
3730e3d5408SPeter Wemm 	src++;
37473f0a83dSXin LI 
3750e3d5408SPeter Wemm     if (*src != '\0') {
37673f0a83dSXin LI 	if ((dst = strdup(src)) == NULL) {
37706bfebdeSXin LI 	    failed("strdup");
37873f0a83dSXin LI 	} else {
379*21817992SBaptiste Daroussin 	    size_t 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 *
open_tempfile(char * filename)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)
403*21817992SBaptiste Daroussin 	result = safe_fopen(filename, "w");
40473f0a83dSXin LI #endif
40573f0a83dSXin LI     return result;
40673f0a83dSXin LI }
40773f0a83dSXin LI 
40873f0a83dSXin LI static FILE *
copy_input(FILE * source,const char * filename,char * alt_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;
413*21817992SBaptiste Daroussin     FILE *target;
41473f0a83dSXin LI     int ch;
41573f0a83dSXin LI 
416*21817992SBaptiste Daroussin     if (alt_file == NULL)
41773f0a83dSXin LI 	alt_file = my_altfile;
41873f0a83dSXin LI 
419*21817992SBaptiste Daroussin     if (source == NULL) {
42073f0a83dSXin LI 	failed("copy_input (source)");
421*21817992SBaptiste Daroussin     } else if ((target = open_tempfile(alt_file)) == NULL) {
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 	 */
445*21817992SBaptiste Daroussin 	result = safe_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 *
open_input(const char * filename,char * alt_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);
461*21817992SBaptiste Daroussin     } else if (stat(filename, &sb) == -1) {
462*21817992SBaptiste Daroussin 	fprintf(stderr, "%s: cannot open '%s': %s\n", _nc_progname,
463*21817992SBaptiste Daroussin 		filename, strerror(errno));
46473f0a83dSXin LI 	ExitProgram(EXIT_FAILURE);
46573f0a83dSXin LI     } else if ((mode = (sb.st_mode & S_IFMT)) == S_IFDIR
466aae38d10SBaptiste Daroussin 	       || (mode != S_IFREG && mode != S_IFCHR && mode != S_IFIFO)) {
467*21817992SBaptiste Daroussin 	fprintf(stderr, "%s: cannot open '%s'; it is not a file\n",
468*21817992SBaptiste Daroussin 		_nc_progname, filename);
46973f0a83dSXin LI 	ExitProgram(EXIT_FAILURE);
47073f0a83dSXin LI     } else {
471*21817992SBaptiste Daroussin 	fp = safe_fopen(filename, "r");
47218259542SPeter Wemm 
473*21817992SBaptiste Daroussin 	if (fp == NULL) {
474*21817992SBaptiste Daroussin 	    fprintf(stderr, "%s: cannot open '%s': %s\n", _nc_progname,
475*21817992SBaptiste Daroussin 		    filename, strerror(errno));
4764a1a9510SRong-En Fan 	    ExitProgram(EXIT_FAILURE);
47718259542SPeter Wemm 	}
47873f0a83dSXin LI 	if (mode != S_IFREG) {
47973f0a83dSXin LI 	    if (alt_file != 0) {
48073f0a83dSXin LI 		FILE *fp2 = copy_input(fp, filename, alt_file);
48173f0a83dSXin LI 		fp = fp2;
48273f0a83dSXin LI 	    } else {
483*21817992SBaptiste Daroussin 		fprintf(stderr, "%s: cannot open '%s'; it is not a"
484*21817992SBaptiste Daroussin 			" file\n", _nc_progname, filename);
4854a1a9510SRong-En Fan 		ExitProgram(EXIT_FAILURE);
48618259542SPeter Wemm 	    }
48773f0a83dSXin LI 	}
48873f0a83dSXin LI     }
48918259542SPeter Wemm     return fp;
49018259542SPeter Wemm }
49118259542SPeter Wemm 
4920e3d5408SPeter Wemm /* Parse the "-e" option-value into a list of names */
4935ca44d1cSRong-En Fan static char **
make_namelist(char * src)49415589c42SPeter Wemm make_namelist(char *src)
4950e3d5408SPeter Wemm {
4965ca44d1cSRong-En Fan     char **dst = 0;
4970e3d5408SPeter Wemm 
4980e3d5408SPeter Wemm     char *s, *base;
4990e3d5408SPeter Wemm     unsigned pass, n, nn;
5000e3d5408SPeter Wemm     char buffer[BUFSIZ];
5010e3d5408SPeter Wemm 
502*21817992SBaptiste Daroussin     if (src == NULL) {
5030e3d5408SPeter Wemm 	/* EMPTY */ ;
5040e3d5408SPeter Wemm     } else if (strchr(src, '/') != 0) {		/* a filename */
50573f0a83dSXin LI 	FILE *fp = open_input(src, (char *) 0);
5060e3d5408SPeter Wemm 
5070e3d5408SPeter Wemm 	for (pass = 1; pass <= 2; pass++) {
5080e3d5408SPeter Wemm 	    nn = 0;
5090e3d5408SPeter Wemm 	    while (fgets(buffer, sizeof(buffer), fp) != 0) {
5100e3d5408SPeter Wemm 		if ((s = stripped(buffer)) != 0) {
5110e3d5408SPeter Wemm 		    if (dst != 0)
5120e3d5408SPeter Wemm 			dst[nn] = s;
5135ca44d1cSRong-En Fan 		    else
5145ca44d1cSRong-En Fan 			free(s);
5150e3d5408SPeter Wemm 		    nn++;
5160e3d5408SPeter Wemm 		}
5170e3d5408SPeter Wemm 	    }
5180e3d5408SPeter Wemm 	    if (pass == 1) {
519*21817992SBaptiste Daroussin 		if ((dst = typeCalloc(char *, nn + 1)) == NULL)
52073f0a83dSXin LI 		      failed("make_namelist");
5210e3d5408SPeter Wemm 		rewind(fp);
5220e3d5408SPeter Wemm 	    }
5230e3d5408SPeter Wemm 	}
5240e3d5408SPeter Wemm 	fclose(fp);
5250e3d5408SPeter Wemm     } else {			/* literal list of names */
5260e3d5408SPeter Wemm 	for (pass = 1; pass <= 2; pass++) {
5270e3d5408SPeter Wemm 	    for (n = nn = 0, base = src;; n++) {
5280e3d5408SPeter Wemm 		int mark = src[n];
5290e3d5408SPeter Wemm 		if (mark == ',' || mark == '\0') {
5300e3d5408SPeter Wemm 		    if (pass == 1) {
5310e3d5408SPeter Wemm 			nn++;
5320e3d5408SPeter Wemm 		    } else {
5330e3d5408SPeter Wemm 			src[n] = '\0';
5340e3d5408SPeter Wemm 			if ((s = stripped(base)) != 0)
5350e3d5408SPeter Wemm 			    dst[nn++] = s;
5360e3d5408SPeter Wemm 			base = &src[n + 1];
5370e3d5408SPeter Wemm 		    }
5380e3d5408SPeter Wemm 		}
5390e3d5408SPeter Wemm 		if (mark == '\0')
5400e3d5408SPeter Wemm 		    break;
5410e3d5408SPeter Wemm 	    }
54273f0a83dSXin LI 	    if (pass == 1) {
543*21817992SBaptiste Daroussin 		if ((dst = typeCalloc(char *, nn + 1)) == NULL)
54473f0a83dSXin LI 		      failed("make_namelist");
54573f0a83dSXin LI 	    }
5460e3d5408SPeter Wemm 	}
5470e3d5408SPeter Wemm     }
5485ca44d1cSRong-En Fan     if (showsummary && (dst != 0)) {
5490e3d5408SPeter Wemm 	fprintf(log_fp, "Entries that will be compiled:\n");
5500e3d5408SPeter Wemm 	for (n = 0; dst[n] != 0; n++)
5514a1a9510SRong-En Fan 	    fprintf(log_fp, "%u:%s\n", n + 1, dst[n]);
5520e3d5408SPeter Wemm     }
5530e3d5408SPeter Wemm     return dst;
5540e3d5408SPeter Wemm }
5550e3d5408SPeter Wemm 
55615589c42SPeter Wemm static bool
matches(char ** needle,const char * haystack)5575ca44d1cSRong-En Fan matches(char **needle, const char *haystack)
5580e3d5408SPeter Wemm /* does entry in needle list match |-separated field in haystack? */
5590e3d5408SPeter Wemm {
5600e3d5408SPeter Wemm     bool code = FALSE;
5610e3d5408SPeter Wemm 
56215589c42SPeter Wemm     if (needle != 0) {
563*21817992SBaptiste Daroussin 	size_t n;
564*21817992SBaptiste Daroussin 
56515589c42SPeter Wemm 	for (n = 0; needle[n] != 0; n++) {
56615589c42SPeter Wemm 	    if (_nc_name_match(haystack, needle[n], "|")) {
5670e3d5408SPeter Wemm 		code = TRUE;
5680e3d5408SPeter Wemm 		break;
5690e3d5408SPeter Wemm 	    }
5700e3d5408SPeter Wemm 	}
57115589c42SPeter Wemm     } else
5720e3d5408SPeter Wemm 	code = TRUE;
5730e3d5408SPeter Wemm     return (code);
5740e3d5408SPeter Wemm }
5750e3d5408SPeter Wemm 
57673f0a83dSXin LI static char *
valid_db_path(const char * nominal)57773f0a83dSXin LI valid_db_path(const char *nominal)
57815589c42SPeter Wemm {
57973f0a83dSXin LI     struct stat sb;
58073f0a83dSXin LI #if USE_HASHED_DB
58173f0a83dSXin LI     char suffix[] = DBM_SUFFIX;
58273f0a83dSXin LI     size_t need = strlen(nominal) + sizeof(suffix);
58373f0a83dSXin LI     char *result = malloc(need);
58473f0a83dSXin LI 
585*21817992SBaptiste Daroussin     if (result == NULL)
58673f0a83dSXin LI 	failed("valid_db_path");
58773f0a83dSXin LI     _nc_STRCPY(result, nominal, need);
58873f0a83dSXin LI     if (strcmp(result + need - sizeof(suffix), suffix)) {
58973f0a83dSXin LI 	_nc_STRCAT(result, suffix, need);
59073f0a83dSXin LI     }
59115589c42SPeter Wemm #else
59273f0a83dSXin LI     char *result = strdup(nominal);
59315589c42SPeter Wemm #endif
59473f0a83dSXin LI 
59573f0a83dSXin LI     DEBUG(1, ("** stat(%s)", result));
59673f0a83dSXin LI     if (stat(result, &sb) >= 0) {
59773f0a83dSXin LI #if USE_HASHED_DB
59873f0a83dSXin LI 	if (!S_ISREG(sb.st_mode)
59973f0a83dSXin LI 	    || access(result, R_OK | W_OK) != 0) {
60073f0a83dSXin LI 	    DEBUG(1, ("...not a writable file"));
60173f0a83dSXin LI 	    free(result);
60273f0a83dSXin LI 	    result = 0;
60373f0a83dSXin LI 	}
60473f0a83dSXin LI #else
60573f0a83dSXin LI 	if (!S_ISDIR(sb.st_mode)
60673f0a83dSXin LI 	    || access(result, R_OK | W_OK | X_OK) != 0) {
60773f0a83dSXin LI 	    DEBUG(1, ("...not a writable directory"));
60873f0a83dSXin LI 	    free(result);
60973f0a83dSXin LI 	    result = 0;
61073f0a83dSXin LI 	}
61173f0a83dSXin LI #endif
61273f0a83dSXin LI     } else {
61373f0a83dSXin LI 	/* check if parent is directory and is writable */
61473f0a83dSXin LI 	unsigned leaf = _nc_pathlast(result);
61573f0a83dSXin LI 
61673f0a83dSXin LI 	DEBUG(1, ("...not found"));
61773f0a83dSXin LI 	if (leaf) {
61873f0a83dSXin LI 	    char save = result[leaf];
61973f0a83dSXin LI 	    result[leaf] = 0;
62073f0a83dSXin LI 	    if (stat(result, &sb) >= 0
62173f0a83dSXin LI 		&& S_ISDIR(sb.st_mode)
62273f0a83dSXin LI 		&& access(result, R_OK | W_OK | X_OK) == 0) {
62373f0a83dSXin LI 		result[leaf] = save;
62473f0a83dSXin LI 	    } else {
62573f0a83dSXin LI 		DEBUG(1, ("...parent directory %s is not writable", result));
62673f0a83dSXin LI 		free(result);
62773f0a83dSXin LI 		result = 0;
62873f0a83dSXin LI 	    }
62973f0a83dSXin LI 	} else {
63073f0a83dSXin LI 	    DEBUG(1, ("... no parent directory"));
63173f0a83dSXin LI 	    free(result);
63273f0a83dSXin LI 	    result = 0;
63373f0a83dSXin LI 	}
63473f0a83dSXin LI     }
63515589c42SPeter Wemm     return result;
63615589c42SPeter Wemm }
63715589c42SPeter Wemm 
63873f0a83dSXin LI /*
63973f0a83dSXin LI  * Show the databases to which tic could write.  The location to which it
64073f0a83dSXin LI  * writes is always the first one.  If none are writable, print an error
64173f0a83dSXin LI  * message.
64273f0a83dSXin LI  */
64373f0a83dSXin LI static void
show_databases(const char * outdir)64473f0a83dSXin LI show_databases(const char *outdir)
64573f0a83dSXin LI {
64673f0a83dSXin LI     bool specific = (outdir != 0) || getenv("TERMINFO") != 0;
64773f0a83dSXin LI     char *result;
64873f0a83dSXin LI     const char *tried = 0;
64973f0a83dSXin LI 
650*21817992SBaptiste Daroussin     if (outdir == NULL) {
651*21817992SBaptiste Daroussin 	outdir = _nc_tic_dir(NULL);
65273f0a83dSXin LI     }
65373f0a83dSXin LI     if ((result = valid_db_path(outdir)) != 0) {
65473f0a83dSXin LI 	printf("%s\n", result);
65573f0a83dSXin LI 	free(result);
65673f0a83dSXin LI     } else {
65773f0a83dSXin LI 	tried = outdir;
65873f0a83dSXin LI     }
65973f0a83dSXin LI 
66073f0a83dSXin LI     if ((outdir = _nc_home_terminfo())) {
66173f0a83dSXin LI 	if ((result = valid_db_path(outdir)) != 0) {
66273f0a83dSXin LI 	    printf("%s\n", result);
66373f0a83dSXin LI 	    free(result);
66473f0a83dSXin LI 	} else if (!specific) {
66573f0a83dSXin LI 	    tried = outdir;
66673f0a83dSXin LI 	}
66773f0a83dSXin LI     }
66873f0a83dSXin LI 
66973f0a83dSXin LI     /*
67073f0a83dSXin LI      * If we can write in neither location, give an error message.
67173f0a83dSXin LI      */
67273f0a83dSXin LI     if (tried) {
67373f0a83dSXin LI 	fflush(stdout);
67473f0a83dSXin LI 	fprintf(stderr, "%s: %s (no permission)\n", _nc_progname, tried);
67573f0a83dSXin LI 	ExitProgram(EXIT_FAILURE);
67673f0a83dSXin LI     }
67773f0a83dSXin LI }
67873f0a83dSXin LI 
679aae38d10SBaptiste Daroussin static void
add_digit(int * target,int source)680aae38d10SBaptiste Daroussin add_digit(int *target, int source)
681aae38d10SBaptiste Daroussin {
682aae38d10SBaptiste Daroussin     *target = (*target * 10) + (source - '0');
683aae38d10SBaptiste Daroussin }
68473f0a83dSXin LI 
68515589c42SPeter Wemm int
main(int argc,char * argv[])68615589c42SPeter Wemm main(int argc, char *argv[])
6870e3d5408SPeter Wemm {
6880e3d5408SPeter Wemm     char my_tmpname[PATH_MAX];
68973f0a83dSXin LI     int v_opt = -1;
6900e3d5408SPeter Wemm     int smart_defaults = TRUE;
6910e3d5408SPeter Wemm     char *termcap;
6920e3d5408SPeter Wemm     ENTRY *qp;
6930e3d5408SPeter Wemm 
6940e3d5408SPeter Wemm     int this_opt, last_opt = '?';
6950e3d5408SPeter Wemm 
6960e3d5408SPeter Wemm     int outform = F_TERMINFO;	/* output format */
6970e3d5408SPeter Wemm     int sortmode = S_TERMINFO;	/* sort_mode */
6980e3d5408SPeter Wemm 
6990e3d5408SPeter Wemm     int width = 60;
70073f0a83dSXin LI     int height = 65535;
7010e3d5408SPeter Wemm     bool formatted = FALSE;	/* reformat complex strings? */
7024a1a9510SRong-En Fan     bool literal = FALSE;	/* suppress post-processing? */
7030e3d5408SPeter Wemm     int numbers = 0;		/* format "%'char'" to/from "%{number}" */
7040e3d5408SPeter Wemm     bool forceresolve = FALSE;	/* force resolution */
7050e3d5408SPeter Wemm     bool limited = TRUE;
7060e3d5408SPeter Wemm     char *tversion = (char *) NULL;
707*21817992SBaptiste Daroussin     const char *source_file;
7080e3d5408SPeter Wemm     char *outdir = (char *) NULL;
7090e3d5408SPeter Wemm     bool check_only = FALSE;
7104a1a9510SRong-En Fan     bool suppress_untranslatable = FALSE;
711aae38d10SBaptiste Daroussin     int quickdump = 0;
712aae38d10SBaptiste Daroussin     bool quiet = FALSE;
713aae38d10SBaptiste Daroussin     bool wrap_strings = FALSE;
7140e3d5408SPeter Wemm 
7150e3d5408SPeter Wemm     log_fp = stderr;
7160e3d5408SPeter Wemm 
71739f2269fSPeter Wemm     _nc_progname = _nc_rootname(argv[0]);
71873f0a83dSXin LI     atexit(cleanup);
7190e3d5408SPeter Wemm 
72006bfebdeSXin LI     if ((infodump = same_program(_nc_progname, PROG_CAPTOINFO)) != FALSE) {
72115589c42SPeter Wemm 	outform = F_TERMINFO;
72215589c42SPeter Wemm 	sortmode = S_TERMINFO;
72315589c42SPeter Wemm     }
72406bfebdeSXin LI     if ((capdump = same_program(_nc_progname, PROG_INFOTOCAP)) != FALSE) {
72515589c42SPeter Wemm 	outform = F_TERMCAP;
72615589c42SPeter Wemm 	sortmode = S_TERMCAP;
72715589c42SPeter Wemm     }
7280e3d5408SPeter Wemm #if NCURSES_XNAMES
729*21817992SBaptiste Daroussin     /* set this directly to avoid interaction with -v and -D options */
730*21817992SBaptiste Daroussin     _nc_user_definable = FALSE;
7310e3d5408SPeter Wemm #endif
73273f0a83dSXin LI     _nc_strict_bsd = 0;
7330e3d5408SPeter Wemm 
7340e3d5408SPeter Wemm     /*
7350e3d5408SPeter Wemm      * Processing arguments is a little complicated, since someone made a
7360e3d5408SPeter Wemm      * design decision to allow the numeric values for -w, -v options to
7370e3d5408SPeter Wemm      * be optional.
7380e3d5408SPeter Wemm      */
73915589c42SPeter Wemm     while ((this_opt = getopt(argc, argv,
740aae38d10SBaptiste Daroussin 			      "0123456789CDIKLNQR:TUVWace:fGgo:qrstvwx")) != -1) {
7410e3d5408SPeter Wemm 	if (isdigit(this_opt)) {
7420e3d5408SPeter Wemm 	    switch (last_opt) {
743aae38d10SBaptiste Daroussin 	    case 'Q':
744aae38d10SBaptiste Daroussin 		add_digit(&quickdump, this_opt);
745aae38d10SBaptiste Daroussin 		break;
7460e3d5408SPeter Wemm 	    case 'v':
747aae38d10SBaptiste Daroussin 		add_digit(&v_opt, this_opt);
7480e3d5408SPeter Wemm 		break;
7490e3d5408SPeter Wemm 	    case 'w':
750aae38d10SBaptiste Daroussin 		add_digit(&width, this_opt);
7510e3d5408SPeter Wemm 		break;
7520e3d5408SPeter Wemm 	    default:
75373f0a83dSXin LI 		switch (this_opt) {
75473f0a83dSXin LI 		case '0':
75573f0a83dSXin LI 		    last_opt = this_opt;
75673f0a83dSXin LI 		    width = 65535;
75773f0a83dSXin LI 		    height = 1;
75873f0a83dSXin LI 		    break;
75973f0a83dSXin LI 		case '1':
7600e3d5408SPeter Wemm 		    last_opt = this_opt;
7610e3d5408SPeter Wemm 		    width = 0;
76273f0a83dSXin LI 		    break;
76373f0a83dSXin LI 		default:
76473f0a83dSXin LI 		    usage();
76573f0a83dSXin LI 		}
7660e3d5408SPeter Wemm 	    }
7670e3d5408SPeter Wemm 	    continue;
7680e3d5408SPeter Wemm 	}
7690e3d5408SPeter Wemm 	switch (this_opt) {
77073f0a83dSXin LI 	case 'K':
77173f0a83dSXin LI 	    _nc_strict_bsd = 1;
77273f0a83dSXin LI 	    /* the initial version of -K in 20110730 fell-thru here, but the
77373f0a83dSXin LI 	     * same flag is useful when reading sources -TD
77473f0a83dSXin LI 	     */
77573f0a83dSXin LI 	    break;
7760e3d5408SPeter Wemm 	case 'C':
7770e3d5408SPeter Wemm 	    capdump = TRUE;
7780e3d5408SPeter Wemm 	    outform = F_TERMCAP;
7790e3d5408SPeter Wemm 	    sortmode = S_TERMCAP;
7800e3d5408SPeter Wemm 	    break;
78173f0a83dSXin LI 	case 'D':
78273f0a83dSXin LI 	    debug_level = VtoTrace(v_opt);
783*21817992SBaptiste Daroussin 	    use_verbosity(debug_level);
78473f0a83dSXin LI 	    show_databases(outdir);
78573f0a83dSXin LI 	    ExitProgram(EXIT_SUCCESS);
78673f0a83dSXin LI 	    break;
7870e3d5408SPeter Wemm 	case 'I':
7880e3d5408SPeter Wemm 	    infodump = TRUE;
7890e3d5408SPeter Wemm 	    outform = F_TERMINFO;
7900e3d5408SPeter Wemm 	    sortmode = S_TERMINFO;
7910e3d5408SPeter Wemm 	    break;
7920e3d5408SPeter Wemm 	case 'L':
7930e3d5408SPeter Wemm 	    infodump = TRUE;
7940e3d5408SPeter Wemm 	    outform = F_VARIABLE;
7950e3d5408SPeter Wemm 	    sortmode = S_VARIABLE;
7960e3d5408SPeter Wemm 	    break;
7970e3d5408SPeter Wemm 	case 'N':
7980e3d5408SPeter Wemm 	    smart_defaults = FALSE;
7994a1a9510SRong-En Fan 	    literal = TRUE;
8000e3d5408SPeter Wemm 	    break;
801aae38d10SBaptiste Daroussin 	case 'Q':
802aae38d10SBaptiste Daroussin 	    quickdump = 0;
803aae38d10SBaptiste Daroussin 	    break;
8040e3d5408SPeter Wemm 	case 'R':
8050e3d5408SPeter Wemm 	    tversion = optarg;
8060e3d5408SPeter Wemm 	    break;
8070e3d5408SPeter Wemm 	case 'T':
8080e3d5408SPeter Wemm 	    limited = FALSE;
8090e3d5408SPeter Wemm 	    break;
8104a1a9510SRong-En Fan 	case 'U':
8114a1a9510SRong-En Fan 	    literal = TRUE;
8124a1a9510SRong-En Fan 	    break;
8130e3d5408SPeter Wemm 	case 'V':
81418259542SPeter Wemm 	    puts(curses_version());
8155d08fb1fSRong-En Fan 	    ExitProgram(EXIT_SUCCESS);
816aae38d10SBaptiste Daroussin 	case 'W':
817aae38d10SBaptiste Daroussin 	    wrap_strings = TRUE;
818aae38d10SBaptiste Daroussin 	    break;
8190e3d5408SPeter Wemm 	case 'c':
8200e3d5408SPeter Wemm 	    check_only = TRUE;
8210e3d5408SPeter Wemm 	    break;
8220e3d5408SPeter Wemm 	case 'e':
8230e3d5408SPeter Wemm 	    namelst = make_namelist(optarg);
8240e3d5408SPeter Wemm 	    break;
8250e3d5408SPeter Wemm 	case 'f':
8260e3d5408SPeter Wemm 	    formatted = TRUE;
8270e3d5408SPeter Wemm 	    break;
8280e3d5408SPeter Wemm 	case 'G':
8290e3d5408SPeter Wemm 	    numbers = 1;
8300e3d5408SPeter Wemm 	    break;
8310e3d5408SPeter Wemm 	case 'g':
8320e3d5408SPeter Wemm 	    numbers = -1;
8330e3d5408SPeter Wemm 	    break;
8340e3d5408SPeter Wemm 	case 'o':
8350e3d5408SPeter Wemm 	    outdir = optarg;
8360e3d5408SPeter Wemm 	    break;
837aae38d10SBaptiste Daroussin 	case 'q':
838aae38d10SBaptiste Daroussin 	    quiet = TRUE;
839aae38d10SBaptiste Daroussin 	    break;
8400e3d5408SPeter Wemm 	case 'r':
8410e3d5408SPeter Wemm 	    forceresolve = TRUE;
8420e3d5408SPeter Wemm 	    break;
8430e3d5408SPeter Wemm 	case 's':
8440e3d5408SPeter Wemm 	    showsummary = TRUE;
8450e3d5408SPeter Wemm 	    break;
8460e3d5408SPeter Wemm 	case 'v':
8470e3d5408SPeter Wemm 	    v_opt = 0;
8480e3d5408SPeter Wemm 	    break;
8490e3d5408SPeter Wemm 	case 'w':
8500e3d5408SPeter Wemm 	    width = 0;
8510e3d5408SPeter Wemm 	    break;
8520e3d5408SPeter Wemm #if NCURSES_XNAMES
8534a1a9510SRong-En Fan 	case 't':
8544a1a9510SRong-En Fan 	    _nc_disable_period = FALSE;
8554a1a9510SRong-En Fan 	    suppress_untranslatable = TRUE;
8564a1a9510SRong-En Fan 	    break;
85715589c42SPeter Wemm 	case 'a':
85815589c42SPeter Wemm 	    _nc_disable_period = TRUE;
85915589c42SPeter Wemm 	    /* FALLTHRU */
8600e3d5408SPeter Wemm 	case 'x':
861aae38d10SBaptiste Daroussin 	    using_extensions = TRUE;
8620e3d5408SPeter Wemm 	    break;
8630e3d5408SPeter Wemm #endif
8640e3d5408SPeter Wemm 	default:
8650e3d5408SPeter Wemm 	    usage();
8660e3d5408SPeter Wemm 	}
8670e3d5408SPeter Wemm 	last_opt = this_opt;
8680e3d5408SPeter Wemm     }
8690e3d5408SPeter Wemm 
870*21817992SBaptiste Daroussin     /*
871*21817992SBaptiste Daroussin      * If the -v option is set, it may override the $NCURSES_TRACE environment
872*21817992SBaptiste Daroussin      * variable, e.g., for -v3 and up.
873*21817992SBaptiste Daroussin      */
87473f0a83dSXin LI     debug_level = VtoTrace(v_opt);
875*21817992SBaptiste Daroussin     use_verbosity(debug_level);
876*21817992SBaptiste Daroussin 
877*21817992SBaptiste Daroussin     /*
878*21817992SBaptiste Daroussin      * Do this after setting debug_level, since the function calls START_TRACE,
879*21817992SBaptiste Daroussin      * which uses the $NCURSES_TRACE environment variable if _nc_tracing bits
880*21817992SBaptiste Daroussin      * for tracing are zero.
881*21817992SBaptiste Daroussin      */
882*21817992SBaptiste Daroussin #if NCURSES_XNAMES
883*21817992SBaptiste Daroussin     if (using_extensions) {
884*21817992SBaptiste Daroussin 	use_extended_names(TRUE);
885*21817992SBaptiste Daroussin     }
886*21817992SBaptiste Daroussin #endif
8870e3d5408SPeter Wemm 
88815589c42SPeter Wemm     if (_nc_tracing) {
8894a1a9510SRong-En Fan 	save_check_termtype = _nc_check_termtype2;
8904a1a9510SRong-En Fan 	_nc_check_termtype2 = check_termtype;
8910e3d5408SPeter Wemm     }
89218259542SPeter Wemm #if !HAVE_BIG_CORE
8930e3d5408SPeter Wemm     /*
8940e3d5408SPeter Wemm      * Aaargh! immedhook seriously hoses us!
8950e3d5408SPeter Wemm      *
8960e3d5408SPeter Wemm      * One problem with immedhook is it means we can't do -e.  Problem
8970e3d5408SPeter Wemm      * is that we can't guarantee that for each terminal listed, all the
8980e3d5408SPeter Wemm      * terminals it depends on will have been kept in core for reference
899*21817992SBaptiste Daroussin      * resolution -- in fact it is certain the primitive types at the end
9000e3d5408SPeter Wemm      * of reference chains *won't* be in core unless they were explicitly
9010e3d5408SPeter Wemm      * in the select list themselves.
9020e3d5408SPeter Wemm      */
90315589c42SPeter Wemm     if (namelst && (!infodump && !capdump)) {
9040e3d5408SPeter Wemm 	(void) fprintf(stderr,
90573f0a83dSXin LI 		       "%s: Sorry, -e can't be used without -I or -C\n",
90673f0a83dSXin LI 		       _nc_progname);
9074a1a9510SRong-En Fan 	ExitProgram(EXIT_FAILURE);
9080e3d5408SPeter Wemm     }
9090e3d5408SPeter Wemm #endif /* HAVE_BIG_CORE */
9100e3d5408SPeter Wemm 
9110e3d5408SPeter Wemm     if (optind < argc) {
9120e3d5408SPeter Wemm 	source_file = argv[optind++];
9130e3d5408SPeter Wemm 	if (optind < argc) {
9140e3d5408SPeter Wemm 	    fprintf(stderr,
9150e3d5408SPeter Wemm 		    "%s: Too many file names.  Usage:\n\t%s %s",
9160e3d5408SPeter Wemm 		    _nc_progname,
9170e3d5408SPeter Wemm 		    _nc_progname,
9180e3d5408SPeter Wemm 		    usage_string);
9194a1a9510SRong-En Fan 	    ExitProgram(EXIT_FAILURE);
9200e3d5408SPeter Wemm 	}
9210e3d5408SPeter Wemm     } else {
9220e3d5408SPeter Wemm 	if (infodump == TRUE) {
9230e3d5408SPeter Wemm 	    /* captoinfo's no-argument case */
9240e3d5408SPeter Wemm 	    source_file = "/etc/termcap";
9250e3d5408SPeter Wemm 	    if ((termcap = getenv("TERMCAP")) != 0
9260e3d5408SPeter Wemm 		&& (namelst = make_namelist(getenv("TERM"))) != 0) {
9270e3d5408SPeter Wemm 		if (access(termcap, F_OK) == 0) {
9280e3d5408SPeter Wemm 		    /* file exists */
9290e3d5408SPeter Wemm 		    source_file = termcap;
93073f0a83dSXin LI 		} else {
93173f0a83dSXin LI 		    if ((tmp_fp = open_tempfile(my_tmpname)) != 0) {
93215589c42SPeter Wemm 			source_file = my_tmpname;
9330e3d5408SPeter Wemm 			fprintf(tmp_fp, "%s\n", termcap);
9340e3d5408SPeter Wemm 			fclose(tmp_fp);
93573f0a83dSXin LI 			tmp_fp = open_input(source_file, (char *) 0);
9360e3d5408SPeter Wemm 			to_remove = source_file;
9370e3d5408SPeter Wemm 		    } else {
9380e3d5408SPeter Wemm 			failed("tmpnam");
9390e3d5408SPeter Wemm 		    }
9400e3d5408SPeter Wemm 		}
94173f0a83dSXin LI 	    }
9420e3d5408SPeter Wemm 	} else {
9430e3d5408SPeter Wemm 	    /* tic */
9440e3d5408SPeter Wemm 	    fprintf(stderr,
9450e3d5408SPeter Wemm 		    "%s: File name needed.  Usage:\n\t%s %s",
9460e3d5408SPeter Wemm 		    _nc_progname,
9470e3d5408SPeter Wemm 		    _nc_progname,
9480e3d5408SPeter Wemm 		    usage_string);
9494a1a9510SRong-En Fan 	    ExitProgram(EXIT_FAILURE);
9500e3d5408SPeter Wemm 	}
9510e3d5408SPeter Wemm     }
9520e3d5408SPeter Wemm 
953*21817992SBaptiste Daroussin     if (tmp_fp == NULL) {
954*21817992SBaptiste Daroussin 	char my_altfile[PATH_MAX];
95573f0a83dSXin LI 	tmp_fp = open_input(source_file, my_altfile);
95673f0a83dSXin LI 	if (!strcmp(source_file, "-")) {
95773f0a83dSXin LI 	    source_file = STDIN_NAME;
95873f0a83dSXin LI 	}
95973f0a83dSXin LI     }
9600e3d5408SPeter Wemm 
961aae38d10SBaptiste Daroussin     if (infodump || check_only) {
9620e3d5408SPeter Wemm 	dump_init(tversion,
963aae38d10SBaptiste Daroussin 		  (smart_defaults
9640e3d5408SPeter Wemm 		   ? outform
965aae38d10SBaptiste Daroussin 		   : F_LITERAL),
966aae38d10SBaptiste Daroussin 		  sortmode,
967aae38d10SBaptiste Daroussin 		  wrap_strings, width, height,
968aae38d10SBaptiste Daroussin 		  debug_level, formatted || check_only, check_only, quickdump);
96973f0a83dSXin LI     } else if (capdump) {
9700e3d5408SPeter Wemm 	dump_init(tversion,
9710e3d5408SPeter Wemm 		  outform,
972aae38d10SBaptiste Daroussin 		  sortmode,
973aae38d10SBaptiste Daroussin 		  wrap_strings, width, height,
974aae38d10SBaptiste Daroussin 		  debug_level, FALSE, FALSE, FALSE);
97573f0a83dSXin LI     }
9760e3d5408SPeter Wemm 
9770e3d5408SPeter Wemm     /* parse entries out of the source file */
9780e3d5408SPeter Wemm     _nc_set_source(source_file);
97918259542SPeter Wemm #if !HAVE_BIG_CORE
9800e3d5408SPeter Wemm     if (!(check_only || infodump || capdump))
9810e3d5408SPeter Wemm 	_nc_set_writedir(outdir);
9820e3d5408SPeter Wemm #endif /* HAVE_BIG_CORE */
9830e3d5408SPeter Wemm     _nc_read_entry_source(tmp_fp, (char *) NULL,
9844a1a9510SRong-En Fan 			  !smart_defaults || literal, FALSE,
9854a1a9510SRong-En Fan 			  ((check_only || infodump || capdump)
9864a1a9510SRong-En Fan 			   ? NULLHOOK
9874a1a9510SRong-En Fan 			   : immedhook));
9880e3d5408SPeter Wemm 
9890e3d5408SPeter Wemm     /* do use resolution */
9900e3d5408SPeter Wemm     if (check_only || (!infodump && !capdump) || forceresolve) {
9914a1a9510SRong-En Fan 	if (!_nc_resolve_uses2(TRUE, literal) && !check_only) {
9924a1a9510SRong-En Fan 	    ExitProgram(EXIT_FAILURE);
9930e3d5408SPeter Wemm 	}
9940e3d5408SPeter Wemm     }
9950e3d5408SPeter Wemm 
9960e3d5408SPeter Wemm     /* length check */
997aae38d10SBaptiste Daroussin     if (check_only && limited && (capdump || infodump)) {
99815589c42SPeter Wemm 	for_entry_list(qp) {
99915589c42SPeter Wemm 	    if (matches(namelst, qp->tterm.term_names)) {
10004a1a9510SRong-En Fan 		int len = fmt_entry(&qp->tterm, NULL, FALSE, TRUE, infodump, numbers);
10010e3d5408SPeter Wemm 
10020e3d5408SPeter Wemm 		if (len > (infodump ? MAX_TERMINFO_LENGTH : MAX_TERMCAP_LENGTH))
10030e3d5408SPeter Wemm 		    (void) fprintf(stderr,
1004aae38d10SBaptiste Daroussin 				   "%s: resolved %s entry is %d bytes long\n",
1005aae38d10SBaptiste Daroussin 				   _nc_progname,
10060e3d5408SPeter Wemm 				   _nc_first_name(qp->tterm.term_names),
10070e3d5408SPeter Wemm 				   len);
10080e3d5408SPeter Wemm 	    }
10090e3d5408SPeter Wemm 	}
10100e3d5408SPeter Wemm     }
10110e3d5408SPeter Wemm 
10120e3d5408SPeter Wemm     /* write or dump all entries */
1013aae38d10SBaptiste Daroussin     if (check_only) {
1014aae38d10SBaptiste Daroussin 	/* this is in case infotocap() generates warnings */
1015aae38d10SBaptiste Daroussin 	_nc_curr_col = _nc_curr_line = -1;
1016aae38d10SBaptiste Daroussin 
1017aae38d10SBaptiste Daroussin 	for_entry_list(qp) {
1018aae38d10SBaptiste Daroussin 	    if (matches(namelst, qp->tterm.term_names)) {
1019aae38d10SBaptiste Daroussin 		/* this is in case infotocap() generates warnings */
1020aae38d10SBaptiste Daroussin 		_nc_set_type(_nc_first_name(qp->tterm.term_names));
1021aae38d10SBaptiste Daroussin 		_nc_curr_line = (int) qp->startline;
1022aae38d10SBaptiste Daroussin 		repair_acsc(&qp->tterm);
1023aae38d10SBaptiste Daroussin 		dump_entry(&qp->tterm, suppress_untranslatable,
1024aae38d10SBaptiste Daroussin 			   limited, numbers, NULL);
1025aae38d10SBaptiste Daroussin 	    }
1026aae38d10SBaptiste Daroussin 	}
1027aae38d10SBaptiste Daroussin     } else {
102815589c42SPeter Wemm 	if (!infodump && !capdump) {
10290e3d5408SPeter Wemm 	    _nc_set_writedir(outdir);
103015589c42SPeter Wemm 	    for_entry_list(qp) {
10310e3d5408SPeter Wemm 		if (matches(namelst, qp->tterm.term_names))
10320e3d5408SPeter Wemm 		    write_it(qp);
10330e3d5408SPeter Wemm 	    }
103415589c42SPeter Wemm 	} else {
10350e3d5408SPeter Wemm 	    /* this is in case infotocap() generates warnings */
10360e3d5408SPeter Wemm 	    _nc_curr_col = _nc_curr_line = -1;
10370e3d5408SPeter Wemm 
103815589c42SPeter Wemm 	    for_entry_list(qp) {
103915589c42SPeter Wemm 		if (matches(namelst, qp->tterm.term_names)) {
104073f0a83dSXin LI 		    long j = qp->cend - qp->cstart;
10410e3d5408SPeter Wemm 		    int len = 0;
10420e3d5408SPeter Wemm 
10430e3d5408SPeter Wemm 		    /* this is in case infotocap() generates warnings */
10440e3d5408SPeter Wemm 		    _nc_set_type(_nc_first_name(qp->tterm.term_names));
10450e3d5408SPeter Wemm 
1046aae38d10SBaptiste Daroussin 		    if (!quiet) {
10470e3d5408SPeter Wemm 			(void) fseek(tmp_fp, qp->cstart, SEEK_SET);
10484a1a9510SRong-En Fan 			while (j-- > 0) {
1049aae38d10SBaptiste Daroussin 			    int ch = fgetc(tmp_fp);
1050aae38d10SBaptiste Daroussin 			    if (ch == EOF || ferror(tmp_fp)) {
1051aae38d10SBaptiste Daroussin 				break;
1052aae38d10SBaptiste Daroussin 			    } else if (infodump) {
1053aae38d10SBaptiste Daroussin 				(void) putchar(ch);
1054aae38d10SBaptiste Daroussin 			    } else {
1055aae38d10SBaptiste Daroussin 				put_translate(ch);
1056aae38d10SBaptiste Daroussin 			    }
1057aae38d10SBaptiste Daroussin 			}
105815589c42SPeter Wemm 		    }
10590e3d5408SPeter Wemm 
106006bfebdeSXin LI 		    repair_acsc(&qp->tterm);
10614a1a9510SRong-En Fan 		    dump_entry(&qp->tterm, suppress_untranslatable,
10624a1a9510SRong-En Fan 			       limited, numbers, NULL);
106373f0a83dSXin LI 		    for (j = 0; j < (long) qp->nuses; j++)
10644a1a9510SRong-En Fan 			dump_uses(qp->uses[j].name, !capdump);
10654a1a9510SRong-En Fan 		    len = show_entry();
10660e3d5408SPeter Wemm 		    if (debug_level != 0 && !limited)
10670e3d5408SPeter Wemm 			printf("# length=%d\n", len);
10680e3d5408SPeter Wemm 		}
106915589c42SPeter Wemm 	    }
1070aae38d10SBaptiste Daroussin 	    if (!namelst && _nc_tail && !quiet) {
10710e3d5408SPeter Wemm 		int c, oldc = '\0';
10720e3d5408SPeter Wemm 		bool in_comment = FALSE;
10730e3d5408SPeter Wemm 		bool trailing_comment = FALSE;
10740e3d5408SPeter Wemm 
10750e3d5408SPeter Wemm 		(void) fseek(tmp_fp, _nc_tail->cend, SEEK_SET);
107615589c42SPeter Wemm 		while ((c = fgetc(tmp_fp)) != EOF) {
10770e3d5408SPeter Wemm 		    if (oldc == '\n') {
10780e3d5408SPeter Wemm 			if (c == '#') {
10790e3d5408SPeter Wemm 			    trailing_comment = TRUE;
10800e3d5408SPeter Wemm 			    in_comment = TRUE;
10810e3d5408SPeter Wemm 			} else {
10820e3d5408SPeter Wemm 			    in_comment = FALSE;
10830e3d5408SPeter Wemm 			}
10840e3d5408SPeter Wemm 		    }
10850e3d5408SPeter Wemm 		    if (trailing_comment
10860e3d5408SPeter Wemm 			&& (in_comment || (oldc == '\n' && c == '\n')))
10870e3d5408SPeter Wemm 			putchar(c);
10880e3d5408SPeter Wemm 		    oldc = c;
10890e3d5408SPeter Wemm 		}
10900e3d5408SPeter Wemm 	    }
10910e3d5408SPeter Wemm 	}
10920e3d5408SPeter Wemm     }
10930e3d5408SPeter Wemm 
10940e3d5408SPeter Wemm     /* Show the directory into which entries were written, and the total
10950e3d5408SPeter Wemm      * number of entries
10960e3d5408SPeter Wemm      */
10970e3d5408SPeter Wemm     if (showsummary
10980e3d5408SPeter Wemm 	&& (!(check_only || infodump || capdump))) {
10990e3d5408SPeter Wemm 	int total = _nc_tic_written();
11000e3d5408SPeter Wemm 	if (total != 0)
11010e3d5408SPeter Wemm 	    fprintf(log_fp, "%d entries written to %s\n",
11020e3d5408SPeter Wemm 		    total,
1103*21817992SBaptiste Daroussin 		    _nc_tic_dir(NULL));
11040e3d5408SPeter Wemm 	else
11050e3d5408SPeter Wemm 	    fprintf(log_fp, "No entries written\n");
11060e3d5408SPeter Wemm     }
11074a1a9510SRong-En Fan     ExitProgram(EXIT_SUCCESS);
11080e3d5408SPeter Wemm }
11090e3d5408SPeter Wemm 
11100e3d5408SPeter Wemm /*
11110e3d5408SPeter Wemm  * This bit of legerdemain turns all the terminfo variable names into
11120e3d5408SPeter Wemm  * references to locations in the arrays Booleans, Numbers, and Strings ---
11130e3d5408SPeter Wemm  * precisely what's needed (see comp_parse.c).
11140e3d5408SPeter Wemm  */
11150e3d5408SPeter Wemm #undef CUR
11160e3d5408SPeter Wemm #define CUR tp->
11170e3d5408SPeter Wemm 
111815589c42SPeter Wemm /*
11194a1a9510SRong-En Fan  * Check if the alternate character-set capabilities are consistent.
11204a1a9510SRong-En Fan  */
11214a1a9510SRong-En Fan static void
check_acs(TERMTYPE2 * tp)1122aae38d10SBaptiste Daroussin check_acs(TERMTYPE2 *tp)
11234a1a9510SRong-En Fan {
1124aae38d10SBaptiste Daroussin     int vt100_smacs = 0;
1125aae38d10SBaptiste Daroussin     int vt100_rmacs = 0;
1126aae38d10SBaptiste Daroussin     int vt100_enacs = 0;
1127aae38d10SBaptiste Daroussin 
1128aae38d10SBaptiste Daroussin     /*
1129aae38d10SBaptiste Daroussin      * ena_acs is not always necessary, but if it is present, the enter/exit
1130aae38d10SBaptiste Daroussin      * capabilities should be.
1131aae38d10SBaptiste Daroussin      */
1132aae38d10SBaptiste Daroussin     ANDMISSING(ena_acs, enter_alt_charset_mode);
1133aae38d10SBaptiste Daroussin     ANDMISSING(ena_acs, exit_alt_charset_mode);
1134aae38d10SBaptiste Daroussin     PAIRED(exit_alt_charset_mode, exit_alt_charset_mode);
1135aae38d10SBaptiste Daroussin 
1136aae38d10SBaptiste Daroussin     /*
1137aae38d10SBaptiste Daroussin      * vt100-like is frequently used, but perhaps ena_acs is missing, etc.
1138aae38d10SBaptiste Daroussin      */
1139aae38d10SBaptiste Daroussin     if (VALID_STRING(enter_alt_charset_mode)) {
1140aae38d10SBaptiste Daroussin 	vt100_smacs = (!strcmp("\033(0", enter_alt_charset_mode)
1141aae38d10SBaptiste Daroussin 		       ? 2
1142aae38d10SBaptiste Daroussin 		       : (!strcmp("\016", enter_alt_charset_mode)
1143aae38d10SBaptiste Daroussin 			  ? 1
1144aae38d10SBaptiste Daroussin 			  : 0));
1145aae38d10SBaptiste Daroussin     }
1146aae38d10SBaptiste Daroussin     if (VALID_STRING(exit_alt_charset_mode)) {
1147aae38d10SBaptiste Daroussin 	vt100_rmacs = (!strcmp("\033(B", exit_alt_charset_mode)
1148aae38d10SBaptiste Daroussin 		       ? 2
1149aae38d10SBaptiste Daroussin 		       : (!strcmp("\017", exit_alt_charset_mode)
1150aae38d10SBaptiste Daroussin 			  ? 1
1151aae38d10SBaptiste Daroussin 			  : 0));
1152aae38d10SBaptiste Daroussin     }
1153aae38d10SBaptiste Daroussin     if (VALID_STRING(ena_acs)) {
1154aae38d10SBaptiste Daroussin 	vt100_enacs = (!strcmp("\033(B\033)0", ena_acs)
1155aae38d10SBaptiste Daroussin 		       ? 2
1156aae38d10SBaptiste Daroussin 		       : 0);
1157aae38d10SBaptiste Daroussin     }
1158aae38d10SBaptiste Daroussin     if (vt100_rmacs && vt100_smacs && (vt100_rmacs != vt100_smacs)) {
1159aae38d10SBaptiste Daroussin 	_nc_warning("rmacs/smacs are inconsistent");
1160aae38d10SBaptiste Daroussin     }
1161aae38d10SBaptiste Daroussin     if ((vt100_rmacs == 2) && (vt100_smacs == 2) && vt100_enacs) {
1162aae38d10SBaptiste Daroussin 	_nc_warning("rmacs/smacs make enacs redundant");
1163aae38d10SBaptiste Daroussin     }
1164aae38d10SBaptiste Daroussin     if ((vt100_rmacs == 1) && (vt100_smacs == 1) && !vt100_enacs) {
1165aae38d10SBaptiste Daroussin 	_nc_warning("VT100-style rmacs/smacs require enacs");
1166aae38d10SBaptiste Daroussin     }
1167aae38d10SBaptiste Daroussin 
11684a1a9510SRong-En Fan     if (VALID_STRING(acs_chars)) {
11694a1a9510SRong-En Fan 	const char *boxes = "lmkjtuvwqxn";
11704a1a9510SRong-En Fan 	char mapped[256];
11714a1a9510SRong-En Fan 	char missing[256];
11724a1a9510SRong-En Fan 	const char *p;
11734a1a9510SRong-En Fan 	char *q;
11744a1a9510SRong-En Fan 
11754a1a9510SRong-En Fan 	memset(mapped, 0, sizeof(mapped));
1176*21817992SBaptiste Daroussin 	memset(missing, 0, sizeof(missing));
11774a1a9510SRong-En Fan 	for (p = acs_chars; *p != '\0'; p += 2) {
11784a1a9510SRong-En Fan 	    if (p[1] == '\0') {
11794a1a9510SRong-En Fan 		_nc_warning("acsc has odd number of characters");
11804a1a9510SRong-En Fan 		break;
11814a1a9510SRong-En Fan 	    }
11824a1a9510SRong-En Fan 	    mapped[UChar(p[0])] = p[1];
11834a1a9510SRong-En Fan 	}
11845d08fb1fSRong-En Fan 
11854a1a9510SRong-En Fan 	if (mapped[UChar('I')] && !mapped[UChar('i')]) {
11864a1a9510SRong-En Fan 	    _nc_warning("acsc refers to 'I', which is probably an error");
11874a1a9510SRong-En Fan 	}
11885d08fb1fSRong-En Fan 
11894a1a9510SRong-En Fan 	for (p = boxes, q = missing; *p != '\0'; ++p) {
11904a1a9510SRong-En Fan 	    if (!mapped[UChar(p[0])]) {
11914a1a9510SRong-En Fan 		*q++ = p[0];
11924a1a9510SRong-En Fan 	    }
11934a1a9510SRong-En Fan 	}
11945d08fb1fSRong-En Fan 	*q = '\0';
11955d08fb1fSRong-En Fan 
11965d08fb1fSRong-En Fan 	assert(strlen(missing) <= strlen(boxes));
11974a1a9510SRong-En Fan 	if (*missing != '\0' && strcmp(missing, boxes)) {
11984a1a9510SRong-En Fan 	    _nc_warning("acsc is missing some line-drawing mapping: %s", missing);
11994a1a9510SRong-En Fan 	}
12004a1a9510SRong-En Fan     }
12014a1a9510SRong-En Fan }
12024a1a9510SRong-En Fan 
12037a656419SBaptiste Daroussin static char *
safe_strdup(const char * value)12047a656419SBaptiste Daroussin safe_strdup(const char *value)
12057a656419SBaptiste Daroussin {
12067a656419SBaptiste Daroussin     if (value == NULL)
12077a656419SBaptiste Daroussin 	value = "";
12087a656419SBaptiste Daroussin     return strdup(value);
12097a656419SBaptiste Daroussin }
12107a656419SBaptiste Daroussin 
1211aae38d10SBaptiste Daroussin static bool
same_color(NCURSES_CONST char * oldcap,NCURSES_CONST char * newcap,int limit)1212aae38d10SBaptiste Daroussin same_color(NCURSES_CONST char *oldcap, NCURSES_CONST char *newcap, int limit)
1213aae38d10SBaptiste Daroussin {
1214aae38d10SBaptiste Daroussin     bool result = FALSE;
1215aae38d10SBaptiste Daroussin     if (limit > 16)
1216aae38d10SBaptiste Daroussin 	limit = 16;
1217aae38d10SBaptiste Daroussin     if (limit >= 8) {
1218aae38d10SBaptiste Daroussin 	int n;
1219aae38d10SBaptiste Daroussin 	int same;
1220aae38d10SBaptiste Daroussin 	for (n = same = 0; n < limit; ++n) {
12217a656419SBaptiste Daroussin 	    char *oldvalue = safe_strdup(TIPARM_1(oldcap, n));
12227a656419SBaptiste Daroussin 	    char *newvalue = safe_strdup(TIPARM_1(newcap, n));
1223aae38d10SBaptiste Daroussin 	    same += !strcmp(oldvalue, newvalue);
1224aae38d10SBaptiste Daroussin 	    free(oldvalue);
1225aae38d10SBaptiste Daroussin 	    free(newvalue);
1226aae38d10SBaptiste Daroussin 	}
1227aae38d10SBaptiste Daroussin 	result = (same == limit);
1228aae38d10SBaptiste Daroussin     }
1229aae38d10SBaptiste Daroussin     return result;
1230aae38d10SBaptiste Daroussin }
1231aae38d10SBaptiste Daroussin 
12324a1a9510SRong-En Fan /*
12334a1a9510SRong-En Fan  * Check if the color capabilities are consistent
12344a1a9510SRong-En Fan  */
12354a1a9510SRong-En Fan static void
check_colors(TERMTYPE2 * tp)1236aae38d10SBaptiste Daroussin check_colors(TERMTYPE2 *tp)
12374a1a9510SRong-En Fan {
1238aae38d10SBaptiste Daroussin     char *value;
1239aae38d10SBaptiste Daroussin 
12404a1a9510SRong-En Fan     if ((max_colors > 0) != (max_pairs > 0)
1241*21817992SBaptiste Daroussin 	|| ((max_colors > max_pairs) && !VALID_STRING(initialize_pair)))
12424a1a9510SRong-En Fan 	_nc_warning("inconsistent values for max_colors (%d) and max_pairs (%d)",
12434a1a9510SRong-En Fan 		    max_colors, max_pairs);
12444a1a9510SRong-En Fan 
12454a1a9510SRong-En Fan     PAIRED(set_foreground, set_background);
12464a1a9510SRong-En Fan     PAIRED(set_a_foreground, set_a_background);
12474a1a9510SRong-En Fan     PAIRED(set_color_pair, initialize_pair);
12484a1a9510SRong-En Fan 
12494a1a9510SRong-En Fan     if (VALID_STRING(set_foreground)
1250aae38d10SBaptiste Daroussin 	&& VALID_STRING(set_a_foreground)) {
1251aae38d10SBaptiste Daroussin 	if (!_nc_capcmp(set_foreground, set_a_foreground)) {
12524a1a9510SRong-En Fan 	    _nc_warning("expected setf/setaf to be different");
1253aae38d10SBaptiste Daroussin 	} else if (same_color(set_foreground, set_a_foreground, max_colors)) {
1254aae38d10SBaptiste Daroussin 	    _nc_warning("setf/setaf are equivalent");
1255aae38d10SBaptiste Daroussin 	}
1256aae38d10SBaptiste Daroussin     }
12574a1a9510SRong-En Fan 
12584a1a9510SRong-En Fan     if (VALID_STRING(set_background)
1259aae38d10SBaptiste Daroussin 	&& VALID_STRING(set_a_background)) {
1260aae38d10SBaptiste Daroussin 	if (!_nc_capcmp(set_background, set_a_background)) {
12614a1a9510SRong-En Fan 	    _nc_warning("expected setb/setab to be different");
1262aae38d10SBaptiste Daroussin 	} else if (same_color(set_background, set_a_background, max_colors)) {
1263aae38d10SBaptiste Daroussin 	    _nc_warning("setb/setab are equivalent");
1264aae38d10SBaptiste Daroussin 	}
1265aae38d10SBaptiste Daroussin     }
12664a1a9510SRong-En Fan 
12674a1a9510SRong-En Fan     /* see: has_colors() */
12684a1a9510SRong-En Fan     if (VALID_NUMERIC(max_colors) && VALID_NUMERIC(max_pairs)
1269aae38d10SBaptiste Daroussin 	&& ((VALID_STRING(set_foreground)
1270aae38d10SBaptiste Daroussin 	     && VALID_STRING(set_background))
1271aae38d10SBaptiste Daroussin 	    || (VALID_STRING(set_a_foreground)
1272aae38d10SBaptiste Daroussin 		&& VALID_STRING(set_a_background))
12734a1a9510SRong-En Fan 	    || set_color_pair)) {
12744a1a9510SRong-En Fan 	if (!VALID_STRING(orig_pair) && !VALID_STRING(orig_colors))
12754a1a9510SRong-En Fan 	    _nc_warning("expected either op/oc string for resetting colors");
12764a1a9510SRong-En Fan     }
1277aae38d10SBaptiste Daroussin     if (can_change) {
1278aae38d10SBaptiste Daroussin 	if (!VALID_STRING(initialize_pair) &&
1279aae38d10SBaptiste Daroussin 	    !VALID_STRING(initialize_color)) {
1280aae38d10SBaptiste Daroussin 	    _nc_warning("expected initc or initp because ccc is given");
1281aae38d10SBaptiste Daroussin 	}
1282aae38d10SBaptiste Daroussin     } else {
1283aae38d10SBaptiste Daroussin 	if (VALID_STRING(initialize_pair) ||
1284aae38d10SBaptiste Daroussin 	    VALID_STRING(initialize_color)) {
1285aae38d10SBaptiste Daroussin 	    _nc_warning("expected ccc because initc is given");
1286aae38d10SBaptiste Daroussin 	}
1287aae38d10SBaptiste Daroussin     }
1288aae38d10SBaptiste Daroussin     value = tigetstr("RGB");
1289aae38d10SBaptiste Daroussin     if (VALID_STRING(value)) {
1290aae38d10SBaptiste Daroussin 	int r, g, b;
1291aae38d10SBaptiste Daroussin 	char bad;
1292aae38d10SBaptiste Daroussin 	int code = sscanf(value, "%d/%d/%d%c", &r, &g, &b, &bad);
1293aae38d10SBaptiste Daroussin 	if (code != 3 || r <= 0 || g <= 0 || b <= 0) {
1294aae38d10SBaptiste Daroussin 	    _nc_warning("unexpected value for RGB capability: %s", value);
1295aae38d10SBaptiste Daroussin 	}
1296aae38d10SBaptiste Daroussin     }
1297aae38d10SBaptiste Daroussin }
1298aae38d10SBaptiste Daroussin 
1299aae38d10SBaptiste Daroussin static int
csi_length(const char * value)1300aae38d10SBaptiste Daroussin csi_length(const char *value)
1301aae38d10SBaptiste Daroussin {
1302aae38d10SBaptiste Daroussin     int result = 0;
1303aae38d10SBaptiste Daroussin 
1304aae38d10SBaptiste Daroussin     if (value[0] == '\033' && value[1] == '[') {
1305aae38d10SBaptiste Daroussin 	result = 2;
1306aae38d10SBaptiste Daroussin     } else if (UChar(value[0]) == 0x9a) {
1307aae38d10SBaptiste Daroussin 	result = 1;
1308aae38d10SBaptiste Daroussin     }
1309aae38d10SBaptiste Daroussin     return result;
13104a1a9510SRong-En Fan }
13114a1a9510SRong-En Fan 
13125d08fb1fSRong-En Fan static char
keypad_final(const char * string)13134a1a9510SRong-En Fan keypad_final(const char *string)
13144a1a9510SRong-En Fan {
13155d08fb1fSRong-En Fan     char result = '\0';
13164a1a9510SRong-En Fan 
13174a1a9510SRong-En Fan     if (VALID_STRING(string)
13184a1a9510SRong-En Fan 	&& *string++ == '\033'
13194a1a9510SRong-En Fan 	&& *string++ == 'O'
13204a1a9510SRong-En Fan 	&& strlen(string) == 1) {
13214a1a9510SRong-En Fan 	result = *string;
13224a1a9510SRong-En Fan     }
13234a1a9510SRong-En Fan 
13244a1a9510SRong-En Fan     return result;
13254a1a9510SRong-En Fan }
13264a1a9510SRong-En Fan 
132773f0a83dSXin LI static long
keypad_index(const char * string)13284a1a9510SRong-En Fan keypad_index(const char *string)
13294a1a9510SRong-En Fan {
13304a1a9510SRong-En Fan     int ch;
133173f0a83dSXin LI     long result = -1;
13324a1a9510SRong-En Fan 
13334a1a9510SRong-En Fan     if ((ch = keypad_final(string)) != '\0') {
1334*21817992SBaptiste Daroussin 	const char *list = "PQRSwxymtuvlqrsPpn";	/* app-keypad except "Enter" */
1335*21817992SBaptiste Daroussin 	char *test = (strchr) (list, ch);
13364a1a9510SRong-En Fan 	if (test != 0)
133773f0a83dSXin LI 	    result = (long) (test - list);
13384a1a9510SRong-En Fan     }
13394a1a9510SRong-En Fan     return result;
13404a1a9510SRong-En Fan }
13414a1a9510SRong-En Fan 
134206bfebdeSXin LI /*
134306bfebdeSXin LI  * list[] is down, up, left, right
134406bfebdeSXin LI  * "left" may be ^H rather than \E[D
134506bfebdeSXin LI  * "down" may be ^J rather than \E[B
134606bfebdeSXin LI  * But up/right are generally consistently escape sequences for ANSI terminals.
134706bfebdeSXin LI  */
134806bfebdeSXin LI static void
check_ansi_cursor(char * list[4])134906bfebdeSXin LI check_ansi_cursor(char *list[4])
135006bfebdeSXin LI {
135106bfebdeSXin LI     int j, k;
135206bfebdeSXin LI     bool skip[4];
135306bfebdeSXin LI     bool repeated = FALSE;
135406bfebdeSXin LI 
135506bfebdeSXin LI     for (j = 0; j < 4; ++j) {
135606bfebdeSXin LI 	skip[j] = FALSE;
135706bfebdeSXin LI 	for (k = 0; k < j; ++k) {
1358*21817992SBaptiste Daroussin 	    if (!strcmp(list[j], list[k])) {
135906bfebdeSXin LI 		char *value = _nc_tic_expand(list[k], TRUE, 0);
1360*21817992SBaptiste Daroussin 		_nc_warning("repeated cursor control %s", value);
136106bfebdeSXin LI 		repeated = TRUE;
136206bfebdeSXin LI 	    }
136306bfebdeSXin LI 	}
136406bfebdeSXin LI     }
136506bfebdeSXin LI     if (!repeated) {
136606bfebdeSXin LI 	char *up = list[1];
1367aae38d10SBaptiste Daroussin 	size_t prefix = (size_t) csi_length(up);
1368*21817992SBaptiste Daroussin 	size_t suffix;
136906bfebdeSXin LI 
137006bfebdeSXin LI 	if (prefix) {
137106bfebdeSXin LI 	    suffix = prefix;
137206bfebdeSXin LI 	    while (up[suffix] && isdigit(UChar(up[suffix])))
137306bfebdeSXin LI 		++suffix;
137406bfebdeSXin LI 	}
137506bfebdeSXin LI 	if (prefix && up[suffix] == 'A') {
137606bfebdeSXin LI 	    skip[1] = TRUE;
137706bfebdeSXin LI 	    if (!strcmp(list[0], "\n"))
137806bfebdeSXin LI 		skip[0] = TRUE;
137906bfebdeSXin LI 	    if (!strcmp(list[2], "\b"))
138006bfebdeSXin LI 		skip[2] = TRUE;
138106bfebdeSXin LI 
138206bfebdeSXin LI 	    for (j = 0; j < 4; ++j) {
1383*21817992SBaptiste Daroussin 		int want;
1384*21817992SBaptiste Daroussin 
138506bfebdeSXin LI 		if (skip[j] || strlen(list[j]) == 1)
138606bfebdeSXin LI 		    continue;
138706bfebdeSXin LI 		if (memcmp(list[j], up, prefix)) {
138806bfebdeSXin LI 		    char *value = _nc_tic_expand(list[j], TRUE, 0);
1389*21817992SBaptiste Daroussin 		    _nc_warning("inconsistent prefix for %s", value);
139006bfebdeSXin LI 		    continue;
139106bfebdeSXin LI 		}
139206bfebdeSXin LI 		if (strlen(list[j]) < suffix) {
139306bfebdeSXin LI 		    char *value = _nc_tic_expand(list[j], TRUE, 0);
1394*21817992SBaptiste Daroussin 		    _nc_warning("inconsistent length for %s, expected %d",
139506bfebdeSXin LI 				value, (int) suffix + 1);
139606bfebdeSXin LI 		    continue;
139706bfebdeSXin LI 		}
139806bfebdeSXin LI 		want = "BADC"[j];
139906bfebdeSXin LI 		if (list[j][suffix] != want) {
140006bfebdeSXin LI 		    char *value = _nc_tic_expand(list[j], TRUE, 0);
1401*21817992SBaptiste Daroussin 		    _nc_warning("inconsistent suffix for %s, expected %c, have %c",
140206bfebdeSXin LI 				value, want, list[j][suffix]);
140306bfebdeSXin LI 		}
140406bfebdeSXin LI 	    }
140506bfebdeSXin LI 	}
140606bfebdeSXin LI     }
140706bfebdeSXin LI }
140806bfebdeSXin LI 
140906bfebdeSXin LI #define EXPECTED(name) if (!PRESENT(name)) _nc_warning("expected " #name)
141073f0a83dSXin LI #define UNEXPECTED(name) if (PRESENT(name)) _nc_warning("unexpected " #name ", for %s", why)
141173f0a83dSXin LI 
141273f0a83dSXin LI static void
check_noaddress(TERMTYPE2 * tp,const char * why)1413aae38d10SBaptiste Daroussin check_noaddress(TERMTYPE2 *tp, const char *why)
141473f0a83dSXin LI {
141573f0a83dSXin LI     UNEXPECTED(column_address);
141673f0a83dSXin LI     UNEXPECTED(cursor_address);
141773f0a83dSXin LI     UNEXPECTED(cursor_home);
141873f0a83dSXin LI     UNEXPECTED(cursor_mem_address);
141973f0a83dSXin LI     UNEXPECTED(cursor_to_ll);
142073f0a83dSXin LI     UNEXPECTED(row_address);
142173f0a83dSXin LI     UNEXPECTED(row_address);
142273f0a83dSXin LI }
142306bfebdeSXin LI 
142406bfebdeSXin LI static void
check_cursor(TERMTYPE2 * tp)1425aae38d10SBaptiste Daroussin check_cursor(TERMTYPE2 *tp)
142606bfebdeSXin LI {
142706bfebdeSXin LI     int count;
142806bfebdeSXin LI     char *list[4];
142906bfebdeSXin LI 
143073f0a83dSXin LI     if (hard_copy) {
143173f0a83dSXin LI 	check_noaddress(tp, "hard_copy");
143273f0a83dSXin LI     } else if (generic_type) {
143373f0a83dSXin LI 	check_noaddress(tp, "generic_type");
1434*21817992SBaptiste Daroussin     } else if (strchr(tp->term_names, '+') == NULL) {
143573f0a83dSXin LI 	int y = 0;
143673f0a83dSXin LI 	int x = 0;
143773f0a83dSXin LI 	if (PRESENT(column_address))
143873f0a83dSXin LI 	    ++y;
143973f0a83dSXin LI 	if (PRESENT(cursor_address))
144073f0a83dSXin LI 	    y = x = 10;
144173f0a83dSXin LI 	if (PRESENT(cursor_home))
144273f0a83dSXin LI 	    ++y, ++x;
144373f0a83dSXin LI 	if (PRESENT(cursor_mem_address))
144473f0a83dSXin LI 	    y = x = 10;
144573f0a83dSXin LI 	if (PRESENT(cursor_to_ll))
144673f0a83dSXin LI 	    ++y, ++x;
144773f0a83dSXin LI 	if (PRESENT(row_address))
144873f0a83dSXin LI 	    ++x;
144973f0a83dSXin LI 	if (PRESENT(cursor_down))
145073f0a83dSXin LI 	    ++y;
145173f0a83dSXin LI 	if (PRESENT(cursor_up))
145273f0a83dSXin LI 	    ++y;
145373f0a83dSXin LI 	if (PRESENT(cursor_left))
145473f0a83dSXin LI 	    ++x;
145573f0a83dSXin LI 	if (PRESENT(cursor_right))
145673f0a83dSXin LI 	    ++x;
145773f0a83dSXin LI 	if (x < 2 && y < 2) {
145873f0a83dSXin LI 	    _nc_warning("terminal lacks cursor addressing");
145973f0a83dSXin LI 	} else {
146073f0a83dSXin LI 	    if (x < 2)
146173f0a83dSXin LI 		_nc_warning("terminal lacks cursor column-addressing");
146273f0a83dSXin LI 	    if (y < 2)
146373f0a83dSXin LI 		_nc_warning("terminal lacks cursor row-addressing");
146473f0a83dSXin LI 	}
146573f0a83dSXin LI     }
146673f0a83dSXin LI 
146773f0a83dSXin LI     /* it is rare to have an insert-line feature without a matching delete */
146873f0a83dSXin LI     ANDMISSING(parm_insert_line, insert_line);
146973f0a83dSXin LI     ANDMISSING(parm_delete_line, delete_line);
147073f0a83dSXin LI     ANDMISSING(parm_insert_line, parm_delete_line);
147173f0a83dSXin LI 
147206bfebdeSXin LI     /* if we have a parameterized form, then the non-parameterized is easy */
147306bfebdeSXin LI     ANDMISSING(parm_down_cursor, cursor_down);
147406bfebdeSXin LI     ANDMISSING(parm_up_cursor, cursor_up);
147506bfebdeSXin LI     ANDMISSING(parm_left_cursor, cursor_left);
147606bfebdeSXin LI     ANDMISSING(parm_right_cursor, cursor_right);
147706bfebdeSXin LI 
147806bfebdeSXin LI     /* Given any of a set of cursor movement, the whole set should be present.
147906bfebdeSXin LI      * Technically this is not true (we could use cursor_address to fill in
148006bfebdeSXin LI      * unsupported controls), but it is likely.
148106bfebdeSXin LI      */
148206bfebdeSXin LI     count = 0;
148306bfebdeSXin LI     if (PRESENT(parm_down_cursor)) {
148406bfebdeSXin LI 	list[count++] = parm_down_cursor;
148506bfebdeSXin LI     }
148606bfebdeSXin LI     if (PRESENT(parm_up_cursor)) {
148706bfebdeSXin LI 	list[count++] = parm_up_cursor;
148806bfebdeSXin LI     }
148906bfebdeSXin LI     if (PRESENT(parm_left_cursor)) {
149006bfebdeSXin LI 	list[count++] = parm_left_cursor;
149106bfebdeSXin LI     }
149206bfebdeSXin LI     if (PRESENT(parm_right_cursor)) {
149306bfebdeSXin LI 	list[count++] = parm_right_cursor;
149406bfebdeSXin LI     }
149506bfebdeSXin LI     if (count == 4) {
149606bfebdeSXin LI 	check_ansi_cursor(list);
149706bfebdeSXin LI     } else if (count != 0) {
149806bfebdeSXin LI 	EXPECTED(parm_down_cursor);
149906bfebdeSXin LI 	EXPECTED(parm_up_cursor);
150006bfebdeSXin LI 	EXPECTED(parm_left_cursor);
150106bfebdeSXin LI 	EXPECTED(parm_right_cursor);
150206bfebdeSXin LI     }
150306bfebdeSXin LI 
150406bfebdeSXin LI     count = 0;
150506bfebdeSXin LI     if (PRESENT(cursor_down)) {
150606bfebdeSXin LI 	list[count++] = cursor_down;
150706bfebdeSXin LI     }
150806bfebdeSXin LI     if (PRESENT(cursor_up)) {
150906bfebdeSXin LI 	list[count++] = cursor_up;
151006bfebdeSXin LI     }
151106bfebdeSXin LI     if (PRESENT(cursor_left)) {
151206bfebdeSXin LI 	list[count++] = cursor_left;
151306bfebdeSXin LI     }
151406bfebdeSXin LI     if (PRESENT(cursor_right)) {
151506bfebdeSXin LI 	list[count++] = cursor_right;
151606bfebdeSXin LI     }
151706bfebdeSXin LI     if (count == 4) {
151806bfebdeSXin LI 	check_ansi_cursor(list);
151906bfebdeSXin LI     } else if (count != 0) {
152006bfebdeSXin LI 	count = 0;
152106bfebdeSXin LI 	if (PRESENT(cursor_down) && strcmp(cursor_down, "\n"))
152206bfebdeSXin LI 	    ++count;
152306bfebdeSXin LI 	if (PRESENT(cursor_left) && strcmp(cursor_left, "\b"))
152406bfebdeSXin LI 	    ++count;
152506bfebdeSXin LI 	if (PRESENT(cursor_up) && strlen(cursor_up) > 1)
152606bfebdeSXin LI 	    ++count;
152706bfebdeSXin LI 	if (PRESENT(cursor_right) && strlen(cursor_right) > 1)
152806bfebdeSXin LI 	    ++count;
152906bfebdeSXin LI 	if (count) {
153006bfebdeSXin LI 	    EXPECTED(cursor_down);
153106bfebdeSXin LI 	    EXPECTED(cursor_up);
153206bfebdeSXin LI 	    EXPECTED(cursor_left);
153306bfebdeSXin LI 	    EXPECTED(cursor_right);
153406bfebdeSXin LI 	}
153506bfebdeSXin LI     }
153606bfebdeSXin LI }
153706bfebdeSXin LI 
15385d08fb1fSRong-En Fan #define MAX_KP 5
15394a1a9510SRong-En Fan /*
15404a1a9510SRong-En Fan  * Do a quick sanity-check for vt100-style keypads to see if the 5-key keypad
15414a1a9510SRong-En Fan  * is mapped inconsistently.
15424a1a9510SRong-En Fan  */
15434a1a9510SRong-En Fan static void
check_keypad(TERMTYPE2 * tp)1544aae38d10SBaptiste Daroussin check_keypad(TERMTYPE2 *tp)
15454a1a9510SRong-En Fan {
15464a1a9510SRong-En Fan     char show[80];
15474a1a9510SRong-En Fan 
15484a1a9510SRong-En Fan     if (VALID_STRING(key_a1) &&
15494a1a9510SRong-En Fan 	VALID_STRING(key_a3) &&
15504a1a9510SRong-En Fan 	VALID_STRING(key_b2) &&
15514a1a9510SRong-En Fan 	VALID_STRING(key_c1) &&
15524a1a9510SRong-En Fan 	VALID_STRING(key_c3)) {
15535d08fb1fSRong-En Fan 	char final[MAX_KP + 1];
155473f0a83dSXin LI 	long list[MAX_KP];
15554a1a9510SRong-En Fan 	int increase = 0;
1556*21817992SBaptiste Daroussin 	int j;
15574a1a9510SRong-En Fan 
15584a1a9510SRong-En Fan 	final[0] = keypad_final(key_a1);
15594a1a9510SRong-En Fan 	final[1] = keypad_final(key_a3);
15604a1a9510SRong-En Fan 	final[2] = keypad_final(key_b2);
15614a1a9510SRong-En Fan 	final[3] = keypad_final(key_c1);
15624a1a9510SRong-En Fan 	final[4] = keypad_final(key_c3);
15634a1a9510SRong-En Fan 	final[5] = '\0';
15644a1a9510SRong-En Fan 
15654a1a9510SRong-En Fan 	/* special case: legacy coding using 1,2,3,0,. on the bottom */
15665d08fb1fSRong-En Fan 	assert(strlen(final) <= MAX_KP);
15674a1a9510SRong-En Fan 	if (!strcmp(final, "qsrpn"))
15684a1a9510SRong-En Fan 	    return;
15694a1a9510SRong-En Fan 
15704a1a9510SRong-En Fan 	list[0] = keypad_index(key_a1);
15714a1a9510SRong-En Fan 	list[1] = keypad_index(key_a3);
15724a1a9510SRong-En Fan 	list[2] = keypad_index(key_b2);
15734a1a9510SRong-En Fan 	list[3] = keypad_index(key_c1);
15744a1a9510SRong-En Fan 	list[4] = keypad_index(key_c3);
15754a1a9510SRong-En Fan 
15764a1a9510SRong-En Fan 	/* check that they're all vt100 keys */
15775d08fb1fSRong-En Fan 	for (j = 0; j < MAX_KP; ++j) {
15784a1a9510SRong-En Fan 	    if (list[j] < 0) {
15794a1a9510SRong-En Fan 		return;
15804a1a9510SRong-En Fan 	    }
15814a1a9510SRong-En Fan 	}
15824a1a9510SRong-En Fan 
15834a1a9510SRong-En Fan 	/* check if they're all in increasing order */
15845d08fb1fSRong-En Fan 	for (j = 1; j < MAX_KP; ++j) {
15854a1a9510SRong-En Fan 	    if (list[j] > list[j - 1]) {
15864a1a9510SRong-En Fan 		++increase;
15874a1a9510SRong-En Fan 	    }
15884a1a9510SRong-En Fan 	}
1589*21817992SBaptiste Daroussin 
15905d08fb1fSRong-En Fan 	if (increase != (MAX_KP - 1)) {
1591*21817992SBaptiste Daroussin 	    long last;
1592*21817992SBaptiste Daroussin 
15934a1a9510SRong-En Fan 	    show[0] = '\0';
15944a1a9510SRong-En Fan 
15955d08fb1fSRong-En Fan 	    for (j = 0, last = -1; j < MAX_KP; ++j) {
1596*21817992SBaptiste Daroussin 		int k;
1597*21817992SBaptiste Daroussin 		int kk;
1598*21817992SBaptiste Daroussin 		long test;
1599*21817992SBaptiste Daroussin 
16004a1a9510SRong-En Fan 		for (k = 0, kk = -1, test = 100; k < 5; ++k) {
16014a1a9510SRong-En Fan 		    if (list[k] > last &&
16024a1a9510SRong-En Fan 			list[k] < test) {
16034a1a9510SRong-En Fan 			test = list[k];
16044a1a9510SRong-En Fan 			kk = k;
16054a1a9510SRong-En Fan 		    }
16064a1a9510SRong-En Fan 		}
16074a1a9510SRong-En Fan 		last = test;
16085d08fb1fSRong-En Fan 		assert(strlen(show) < (MAX_KP * 4));
16094a1a9510SRong-En Fan 		switch (kk) {
16104a1a9510SRong-En Fan 		case 0:
161173f0a83dSXin LI 		    _nc_STRCAT(show, " ka1", sizeof(show));
16124a1a9510SRong-En Fan 		    break;
16134a1a9510SRong-En Fan 		case 1:
161473f0a83dSXin LI 		    _nc_STRCAT(show, " ka3", sizeof(show));
16154a1a9510SRong-En Fan 		    break;
16164a1a9510SRong-En Fan 		case 2:
161773f0a83dSXin LI 		    _nc_STRCAT(show, " kb2", sizeof(show));
16184a1a9510SRong-En Fan 		    break;
16194a1a9510SRong-En Fan 		case 3:
162073f0a83dSXin LI 		    _nc_STRCAT(show, " kc1", sizeof(show));
16214a1a9510SRong-En Fan 		    break;
16224a1a9510SRong-En Fan 		case 4:
162373f0a83dSXin LI 		    _nc_STRCAT(show, " kc3", sizeof(show));
16244a1a9510SRong-En Fan 		    break;
16254a1a9510SRong-En Fan 		}
16264a1a9510SRong-En Fan 	    }
16274a1a9510SRong-En Fan 
16284a1a9510SRong-En Fan 	    _nc_warning("vt100 keypad order inconsistent: %s", show);
16294a1a9510SRong-En Fan 	}
16304a1a9510SRong-En Fan 
16314a1a9510SRong-En Fan     } else if (VALID_STRING(key_a1) ||
16324a1a9510SRong-En Fan 	       VALID_STRING(key_a3) ||
16334a1a9510SRong-En Fan 	       VALID_STRING(key_b2) ||
16344a1a9510SRong-En Fan 	       VALID_STRING(key_c1) ||
16354a1a9510SRong-En Fan 	       VALID_STRING(key_c3)) {
16364a1a9510SRong-En Fan 	show[0] = '\0';
16374a1a9510SRong-En Fan 	if (keypad_index(key_a1) >= 0)
163873f0a83dSXin LI 	    _nc_STRCAT(show, " ka1", sizeof(show));
16394a1a9510SRong-En Fan 	if (keypad_index(key_a3) >= 0)
164073f0a83dSXin LI 	    _nc_STRCAT(show, " ka3", sizeof(show));
16414a1a9510SRong-En Fan 	if (keypad_index(key_b2) >= 0)
164273f0a83dSXin LI 	    _nc_STRCAT(show, " kb2", sizeof(show));
16434a1a9510SRong-En Fan 	if (keypad_index(key_c1) >= 0)
164473f0a83dSXin LI 	    _nc_STRCAT(show, " kc1", sizeof(show));
16454a1a9510SRong-En Fan 	if (keypad_index(key_c3) >= 0)
164673f0a83dSXin LI 	    _nc_STRCAT(show, " kc3", sizeof(show));
16474a1a9510SRong-En Fan 	if (*show != '\0')
16484a1a9510SRong-En Fan 	    _nc_warning("vt100 keypad map incomplete:%s", show);
16494a1a9510SRong-En Fan     }
165073f0a83dSXin LI 
165173f0a83dSXin LI     /*
165273f0a83dSXin LI      * These warnings are useful for consistency checks - it is possible that
165373f0a83dSXin LI      * there are real terminals with mismatches in these
165473f0a83dSXin LI      */
165573f0a83dSXin LI     ANDMISSING(key_ic, key_dc);
16564a1a9510SRong-En Fan }
16574a1a9510SRong-En Fan 
165806bfebdeSXin LI static void
check_printer(TERMTYPE2 * tp)1659aae38d10SBaptiste Daroussin check_printer(TERMTYPE2 *tp)
166006bfebdeSXin LI {
1661aae38d10SBaptiste Daroussin     (void) tp;
1662aae38d10SBaptiste Daroussin #if defined(enter_doublewide_mode) && defined(exit_doublewide_mode)
166306bfebdeSXin LI     PAIRED(enter_doublewide_mode, exit_doublewide_mode);
1664aae38d10SBaptiste Daroussin #endif
1665aae38d10SBaptiste Daroussin #if defined(enter_italics_mode) && defined(exit_italics_mode)
166606bfebdeSXin LI     PAIRED(enter_italics_mode, exit_italics_mode);
1667aae38d10SBaptiste Daroussin #endif
1668aae38d10SBaptiste Daroussin #if defined(enter_leftward_mode) && defined(exit_leftward_mode)
166906bfebdeSXin LI     PAIRED(enter_leftward_mode, exit_leftward_mode);
1670aae38d10SBaptiste Daroussin #endif
1671aae38d10SBaptiste Daroussin #if defined(enter_micro_mode) && defined(exit_micro_mode)
167206bfebdeSXin LI     PAIRED(enter_micro_mode, exit_micro_mode);
1673aae38d10SBaptiste Daroussin #endif
1674aae38d10SBaptiste Daroussin #if defined(enter_shadow_mode) && defined(exit_shadow_mode)
167506bfebdeSXin LI     PAIRED(enter_shadow_mode, exit_shadow_mode);
1676aae38d10SBaptiste Daroussin #endif
1677aae38d10SBaptiste Daroussin #if defined(enter_subscript_mode) && defined(exit_subscript_mode)
167806bfebdeSXin LI     PAIRED(enter_subscript_mode, exit_subscript_mode);
1679aae38d10SBaptiste Daroussin #endif
1680aae38d10SBaptiste Daroussin #if defined(enter_superscript_mode) && defined(exit_superscript_mode)
168106bfebdeSXin LI     PAIRED(enter_superscript_mode, exit_superscript_mode);
1682aae38d10SBaptiste Daroussin #endif
1683aae38d10SBaptiste Daroussin #if defined(enter_upward_mode) && defined(exit_upward_mode)
168406bfebdeSXin LI     PAIRED(enter_upward_mode, exit_upward_mode);
1685aae38d10SBaptiste Daroussin #endif
168606bfebdeSXin LI 
1687aae38d10SBaptiste Daroussin #if defined(start_char_set_def) && defined(stop_char_set_def)
168806bfebdeSXin LI     ANDMISSING(start_char_set_def, stop_char_set_def);
1689aae38d10SBaptiste Daroussin #endif
169006bfebdeSXin LI 
1691*21817992SBaptiste Daroussin     /*
1692*21817992SBaptiste Daroussin      * If we have a parameterized form, then the non-parameterized is easy.
1693*21817992SBaptiste Daroussin      * note: parameterized/non-parameterized margin settings are unrelated.
1694*21817992SBaptiste Daroussin      */
1695aae38d10SBaptiste Daroussin #if defined(parm_down_micro) && defined(micro_down)
169606bfebdeSXin LI     ANDMISSING(parm_down_micro, micro_down);
1697aae38d10SBaptiste Daroussin #endif
1698aae38d10SBaptiste Daroussin #if defined(parm_left_micro) && defined(micro_left)
169906bfebdeSXin LI     ANDMISSING(parm_left_micro, micro_left);
1700aae38d10SBaptiste Daroussin #endif
1701aae38d10SBaptiste Daroussin #if defined(parm_right_micro) && defined(micro_right)
170206bfebdeSXin LI     ANDMISSING(parm_right_micro, micro_right);
1703aae38d10SBaptiste Daroussin #endif
1704aae38d10SBaptiste Daroussin #if defined(parm_up_micro) && defined(micro_up)
170506bfebdeSXin LI     ANDMISSING(parm_up_micro, micro_up);
1706aae38d10SBaptiste Daroussin #endif
170706bfebdeSXin LI }
170806bfebdeSXin LI 
1709aae38d10SBaptiste Daroussin #if NCURSES_XNAMES
171073f0a83dSXin LI static bool
uses_SGR_39_49(const char * value)171173f0a83dSXin LI uses_SGR_39_49(const char *value)
171273f0a83dSXin LI {
171373f0a83dSXin LI     return (strstr(value, "39;49") != 0
171473f0a83dSXin LI 	    || strstr(value, "49;39") != 0);
171573f0a83dSXin LI }
171673f0a83dSXin LI 
171773f0a83dSXin LI /*
171873f0a83dSXin LI  * Check consistency of termcap extensions related to "screen".
171973f0a83dSXin LI  */
172073f0a83dSXin LI static void
check_screen(TERMTYPE2 * tp)1721aae38d10SBaptiste Daroussin check_screen(TERMTYPE2 *tp)
172273f0a83dSXin LI {
172373f0a83dSXin LI     if (_nc_user_definable) {
172473f0a83dSXin LI 	int have_XT = tigetflag("XT");
172573f0a83dSXin LI 	int have_XM = tigetflag("XM");
172673f0a83dSXin LI 	int have_bce = back_color_erase;
172773f0a83dSXin LI 	bool have_kmouse = FALSE;
172873f0a83dSXin LI 	bool use_sgr_39_49 = FALSE;
17297a656419SBaptiste Daroussin 	const char *name_39_49 = "orig_pair or orig_colors";
173073f0a83dSXin LI 	char *name = _nc_first_name(tp->term_names);
1731aae38d10SBaptiste Daroussin 	bool is_screen = !strncmp(name, "screen", 6);
1732aae38d10SBaptiste Daroussin 	bool screen_base = (is_screen
1733*21817992SBaptiste Daroussin 			    && strchr(name, '.') == NULL);
173473f0a83dSXin LI 
173573f0a83dSXin LI 	if (!VALID_BOOLEAN(have_bce)) {
173673f0a83dSXin LI 	    have_bce = FALSE;
173773f0a83dSXin LI 	}
173873f0a83dSXin LI 	if (!VALID_BOOLEAN(have_XM)) {
173973f0a83dSXin LI 	    have_XM = FALSE;
174073f0a83dSXin LI 	}
174173f0a83dSXin LI 	if (!VALID_BOOLEAN(have_XT)) {
174273f0a83dSXin LI 	    have_XT = FALSE;
174373f0a83dSXin LI 	}
174473f0a83dSXin LI 	if (VALID_STRING(key_mouse)) {
174573f0a83dSXin LI 	    have_kmouse = !strcmp("\033[M", key_mouse);
174673f0a83dSXin LI 	}
17477a656419SBaptiste Daroussin 	if (have_bce) {
17487a656419SBaptiste Daroussin 	    if (VALID_STRING(orig_pair)) {
17497a656419SBaptiste Daroussin 		name_39_49 = "orig_pair";
175073f0a83dSXin LI 		use_sgr_39_49 = uses_SGR_39_49(orig_pair);
175173f0a83dSXin LI 	    }
17527a656419SBaptiste Daroussin 	    if (!use_sgr_39_49 && VALID_STRING(orig_colors)) {
17537a656419SBaptiste Daroussin 		name_39_49 = "orig_colors";
17547a656419SBaptiste Daroussin 		use_sgr_39_49 = uses_SGR_39_49(orig_colors);
17557a656419SBaptiste Daroussin 	    }
17567a656419SBaptiste Daroussin 	}
175773f0a83dSXin LI 
175873f0a83dSXin LI 	if (have_XM && have_XT) {
1759aae38d10SBaptiste Daroussin 	    _nc_warning("screen's XT capability conflicts with XM");
1760aae38d10SBaptiste Daroussin 	} else if (have_XT && screen_base) {
1761aae38d10SBaptiste Daroussin 	    _nc_warning("screen's \"screen\" entries should not have XT set");
176273f0a83dSXin LI 	} else if (have_XT) {
1763*21817992SBaptiste Daroussin 	    char *s;
1764*21817992SBaptiste Daroussin 
1765aae38d10SBaptiste Daroussin 	    if (!have_kmouse && is_screen) {
176673f0a83dSXin LI 		if (VALID_STRING(key_mouse)) {
1767aae38d10SBaptiste Daroussin 		    _nc_warning("value of kmous inconsistent with screen's usage");
176873f0a83dSXin LI 		} else {
1769aae38d10SBaptiste Daroussin 		    _nc_warning("expected kmous capability with XT");
177073f0a83dSXin LI 		}
177173f0a83dSXin LI 	    }
17727a656419SBaptiste Daroussin 	    if (max_colors > 0) {
17737a656419SBaptiste Daroussin 		if (!have_bce) {
1774aae38d10SBaptiste Daroussin 		    _nc_warning("expected bce capability with XT");
17757a656419SBaptiste Daroussin 		} else if (!use_sgr_39_49) {
17767a656419SBaptiste Daroussin 		    _nc_warning("expected %s capability with XT "
17777a656419SBaptiste Daroussin 				"to have 39/49 parameters", name_39_49);
17787a656419SBaptiste Daroussin 		}
17797a656419SBaptiste Daroussin 	    }
1780*21817992SBaptiste Daroussin 	    if (VALID_STRING(to_status_line)
1781*21817992SBaptiste Daroussin 		&& (s = strchr(to_status_line, ';')) != NULL
1782*21817992SBaptiste Daroussin 		&& *++s == '\0')
178373f0a83dSXin LI 		_nc_warning("\"tsl\" capability is redundant, given XT");
178473f0a83dSXin LI 	} else {
1785aae38d10SBaptiste Daroussin 	    if (have_kmouse
1786aae38d10SBaptiste Daroussin 		&& !have_XM
1787*21817992SBaptiste Daroussin 		&& !screen_base && strchr(name, '+') == NULL) {
1788aae38d10SBaptiste Daroussin 		_nc_warning("expected XT to be set, given kmous");
178973f0a83dSXin LI 	    }
179073f0a83dSXin LI 	}
1791aae38d10SBaptiste Daroussin     }
1792aae38d10SBaptiste Daroussin }
1793aae38d10SBaptiste Daroussin #else
1794aae38d10SBaptiste Daroussin #define check_screen(tp)	/* nothing */
179573f0a83dSXin LI #endif
179673f0a83dSXin LI 
17974a1a9510SRong-En Fan /*
179818259542SPeter Wemm  * Returns the expected number of parameters for the given capability.
179918259542SPeter Wemm  */
180018259542SPeter Wemm static int
expected_params(const char * name)18017a69bbfbSPeter Wemm expected_params(const char *name)
180218259542SPeter Wemm {
1803aae38d10SBaptiste Daroussin #define DATA(name,count) { { name }, count }
180418259542SPeter Wemm     /* *INDENT-OFF* */
180518259542SPeter Wemm     static const struct {
1806aae38d10SBaptiste Daroussin 	const char name[9];
180718259542SPeter Wemm 	int count;
180818259542SPeter Wemm     } table[] = {
1809aae38d10SBaptiste Daroussin 	DATA( "S0",		1 ),	/* 'screen' extension */
1810aae38d10SBaptiste Daroussin 	DATA( "birep",		2 ),
1811aae38d10SBaptiste Daroussin 	DATA( "chr",		1 ),
1812aae38d10SBaptiste Daroussin 	DATA( "colornm",	1 ),
1813aae38d10SBaptiste Daroussin 	DATA( "cpi",		1 ),
1814aae38d10SBaptiste Daroussin 	DATA( "csnm",		1 ),
1815aae38d10SBaptiste Daroussin 	DATA( "csr",		2 ),
1816aae38d10SBaptiste Daroussin 	DATA( "cub",		1 ),
1817aae38d10SBaptiste Daroussin 	DATA( "cud",		1 ),
1818aae38d10SBaptiste Daroussin 	DATA( "cuf",		1 ),
1819aae38d10SBaptiste Daroussin 	DATA( "cup",		2 ),
1820aae38d10SBaptiste Daroussin 	DATA( "cuu",		1 ),
1821aae38d10SBaptiste Daroussin 	DATA( "cvr",		1 ),
1822aae38d10SBaptiste Daroussin 	DATA( "cwin",		5 ),
1823aae38d10SBaptiste Daroussin 	DATA( "dch",		1 ),
1824aae38d10SBaptiste Daroussin 	DATA( "defc",		3 ),
1825aae38d10SBaptiste Daroussin 	DATA( "dial",		1 ),
1826aae38d10SBaptiste Daroussin 	DATA( "dispc",		1 ),
1827aae38d10SBaptiste Daroussin 	DATA( "dl",		1 ),
1828aae38d10SBaptiste Daroussin 	DATA( "ech",		1 ),
1829aae38d10SBaptiste Daroussin 	DATA( "getm",		1 ),
1830aae38d10SBaptiste Daroussin 	DATA( "hpa",		1 ),
1831aae38d10SBaptiste Daroussin 	DATA( "ich",		1 ),
1832aae38d10SBaptiste Daroussin 	DATA( "il",		1 ),
1833aae38d10SBaptiste Daroussin 	DATA( "indn",		1 ),
1834aae38d10SBaptiste Daroussin 	DATA( "initc",		4 ),
1835aae38d10SBaptiste Daroussin 	DATA( "initp",		7 ),
1836aae38d10SBaptiste Daroussin 	DATA( "lpi",		1 ),
1837aae38d10SBaptiste Daroussin 	DATA( "mc5p",		1 ),
1838aae38d10SBaptiste Daroussin 	DATA( "mrcup",		2 ),
1839aae38d10SBaptiste Daroussin 	DATA( "mvpa",		1 ),
1840aae38d10SBaptiste Daroussin 	DATA( "pfkey",		2 ),
1841aae38d10SBaptiste Daroussin 	DATA( "pfloc",		2 ),
1842aae38d10SBaptiste Daroussin 	DATA( "pfx",		2 ),
1843aae38d10SBaptiste Daroussin 	DATA( "pfxl",		3 ),
1844aae38d10SBaptiste Daroussin 	DATA( "pln",		2 ),
1845aae38d10SBaptiste Daroussin 	DATA( "qdial",		1 ),
1846aae38d10SBaptiste Daroussin 	DATA( "rcsd",		1 ),
1847aae38d10SBaptiste Daroussin 	DATA( "rep",		2 ),
1848aae38d10SBaptiste Daroussin 	DATA( "rin",		1 ),
1849aae38d10SBaptiste Daroussin 	DATA( "sclk",		3 ),
1850aae38d10SBaptiste Daroussin 	DATA( "scp",		1 ),
1851aae38d10SBaptiste Daroussin 	DATA( "scs",		1 ),
1852aae38d10SBaptiste Daroussin 	DATA( "scsd",		2 ),
1853aae38d10SBaptiste Daroussin 	DATA( "setab",		1 ),
1854aae38d10SBaptiste Daroussin 	DATA( "setaf",		1 ),
1855aae38d10SBaptiste Daroussin 	DATA( "setb",		1 ),
1856aae38d10SBaptiste Daroussin 	DATA( "setcolor",	1 ),
1857aae38d10SBaptiste Daroussin 	DATA( "setf",		1 ),
1858aae38d10SBaptiste Daroussin 	DATA( "sgr",		9 ),
1859aae38d10SBaptiste Daroussin 	DATA( "sgr1",		6 ),
1860aae38d10SBaptiste Daroussin 	DATA( "slength",	1 ),
1861aae38d10SBaptiste Daroussin 	DATA( "slines",		1 ),
1862aae38d10SBaptiste Daroussin 	DATA( "smgbp",		1 ),	/* 2 if smgtp is not given */
1863aae38d10SBaptiste Daroussin 	DATA( "smglp",		1 ),
1864aae38d10SBaptiste Daroussin 	DATA( "smglr",		2 ),
1865aae38d10SBaptiste Daroussin 	DATA( "smgrp",		1 ),
1866aae38d10SBaptiste Daroussin 	DATA( "smgtb",		2 ),
1867aae38d10SBaptiste Daroussin 	DATA( "smgtp",		1 ),
1868aae38d10SBaptiste Daroussin 	DATA( "tsl",		1 ),
1869aae38d10SBaptiste Daroussin 	DATA( "u6",		-1 ),
1870aae38d10SBaptiste Daroussin 	DATA( "vpa",		1 ),
1871aae38d10SBaptiste Daroussin 	DATA( "wind",		4 ),
1872aae38d10SBaptiste Daroussin 	DATA( "wingo",		1 ),
187318259542SPeter Wemm     };
187418259542SPeter Wemm     /* *INDENT-ON* */
1875aae38d10SBaptiste Daroussin #undef DATA
1876aae38d10SBaptiste Daroussin 
187718259542SPeter Wemm     unsigned n;
187818259542SPeter Wemm     int result = 0;		/* function-keys, etc., use none */
187918259542SPeter Wemm 
188018259542SPeter Wemm     for (n = 0; n < SIZEOF(table); n++) {
188118259542SPeter Wemm 	if (!strcmp(name, table[n].name)) {
188218259542SPeter Wemm 	    result = table[n].count;
188318259542SPeter Wemm 	    break;
188418259542SPeter Wemm 	}
188518259542SPeter Wemm     }
188618259542SPeter Wemm 
188718259542SPeter Wemm     return result;
188818259542SPeter Wemm }
188918259542SPeter Wemm 
189018259542SPeter Wemm /*
1891aae38d10SBaptiste Daroussin  * Check for user-capabilities that happen to be used in ncurses' terminal
1892aae38d10SBaptiste Daroussin  * database.
1893aae38d10SBaptiste Daroussin  */
1894aae38d10SBaptiste Daroussin #if NCURSES_XNAMES
1895aae38d10SBaptiste Daroussin static struct user_table_entry const *
lookup_user_capability(const char * name)1896aae38d10SBaptiste Daroussin lookup_user_capability(const char *name)
1897aae38d10SBaptiste Daroussin {
1898aae38d10SBaptiste Daroussin     struct user_table_entry const *result = 0;
1899aae38d10SBaptiste Daroussin     if (*name != 'k') {
1900aae38d10SBaptiste Daroussin 	result = _nc_find_user_entry(name);
1901aae38d10SBaptiste Daroussin     }
1902aae38d10SBaptiste Daroussin     return result;
1903aae38d10SBaptiste Daroussin }
1904aae38d10SBaptiste Daroussin #endif
1905aae38d10SBaptiste Daroussin 
1906aae38d10SBaptiste Daroussin /*
1907aae38d10SBaptiste Daroussin  * If a given name is likely to be a user-capability, return the number of
1908aae38d10SBaptiste Daroussin  * parameters it would be used with.  If not, return -1.
1909aae38d10SBaptiste Daroussin  *
1910aae38d10SBaptiste Daroussin  * ncurses assumes that u6 could be used for getting the cursor-position, but
1911aae38d10SBaptiste Daroussin  * that is not implemented.  Make a special case for that, to quiet needless
1912aae38d10SBaptiste Daroussin  * warnings.
1913aae38d10SBaptiste Daroussin  *
1914aae38d10SBaptiste Daroussin  * The other string-capability extensions (see terminfo.src) which could have
1915aae38d10SBaptiste Daroussin  * parameters such as "Ss", "%u", are not used by ncurses.  But we check those
1916aae38d10SBaptiste Daroussin  * anyway, to validate the terminfo database.
1917aae38d10SBaptiste Daroussin  */
1918aae38d10SBaptiste Daroussin static int
is_user_capability(const char * name)1919aae38d10SBaptiste Daroussin is_user_capability(const char *name)
1920aae38d10SBaptiste Daroussin {
1921aae38d10SBaptiste Daroussin     int result = -1;
1922aae38d10SBaptiste Daroussin     if (name[0] == 'u' &&
1923aae38d10SBaptiste Daroussin 	(name[1] >= '0' && name[1] <= '9') &&
1924aae38d10SBaptiste Daroussin 	name[2] == '\0') {
1925aae38d10SBaptiste Daroussin 	result = (name[1] == '6') ? 2 : 0;
1926aae38d10SBaptiste Daroussin     }
1927aae38d10SBaptiste Daroussin #if NCURSES_XNAMES
1928aae38d10SBaptiste Daroussin     else if (using_extensions) {
1929aae38d10SBaptiste Daroussin 	struct user_table_entry const *p = lookup_user_capability(name);
1930aae38d10SBaptiste Daroussin 	if (p != 0) {
1931aae38d10SBaptiste Daroussin 	    result = (int) p->ute_argc;
1932aae38d10SBaptiste Daroussin 	}
1933aae38d10SBaptiste Daroussin     }
1934aae38d10SBaptiste Daroussin #endif
1935aae38d10SBaptiste Daroussin     return result;
1936aae38d10SBaptiste Daroussin }
1937aae38d10SBaptiste Daroussin 
1938*21817992SBaptiste Daroussin static bool
line_capability(const char * name)1939*21817992SBaptiste Daroussin line_capability(const char *name)
1940*21817992SBaptiste Daroussin {
1941*21817992SBaptiste Daroussin     bool result = FALSE;
1942*21817992SBaptiste Daroussin     static const char *table[] =
1943*21817992SBaptiste Daroussin     {
1944*21817992SBaptiste Daroussin 	"csr",			/* change_scroll_region          */
1945*21817992SBaptiste Daroussin 	"clear",		/* clear_screen                  */
1946*21817992SBaptiste Daroussin 	"ed",			/* clr_eos                       */
1947*21817992SBaptiste Daroussin 	"cwin",			/* create_window                 */
1948*21817992SBaptiste Daroussin 	"cup",			/* cursor_address                */
1949*21817992SBaptiste Daroussin 	"cud1",			/* cursor_down                   */
1950*21817992SBaptiste Daroussin 	"home",			/* cursor_home                   */
1951*21817992SBaptiste Daroussin 	"mrcup",		/* cursor_mem_address            */
1952*21817992SBaptiste Daroussin 	"ll",			/* cursor_to_ll                  */
1953*21817992SBaptiste Daroussin 	"cuu1",			/* cursor_up                     */
1954*21817992SBaptiste Daroussin 	"dl1",			/* delete_line                   */
1955*21817992SBaptiste Daroussin 	"hd",			/* down_half_line                */
1956*21817992SBaptiste Daroussin 	"flash",		/* flash_screen                  */
1957*21817992SBaptiste Daroussin 	"ff",			/* form_feed                     */
1958*21817992SBaptiste Daroussin 	"il1",			/* insert_line                   */
1959*21817992SBaptiste Daroussin 	"nel",			/* newline                       */
1960*21817992SBaptiste Daroussin 	"dl",			/* parm_delete_line              */
1961*21817992SBaptiste Daroussin 	"cud",			/* parm_down_cursor              */
1962*21817992SBaptiste Daroussin 	"indn",			/* parm_index                    */
1963*21817992SBaptiste Daroussin 	"il",			/* parm_insert_line              */
1964*21817992SBaptiste Daroussin 	"rin",			/* parm_rindex                   */
1965*21817992SBaptiste Daroussin 	"cuu",			/* parm_up_cursor                */
1966*21817992SBaptiste Daroussin 	"mc0",			/* print_screen                  */
1967*21817992SBaptiste Daroussin 	"vpa",			/* row_address                   */
1968*21817992SBaptiste Daroussin 	"ind",			/* scroll_forward                */
1969*21817992SBaptiste Daroussin 	"ri",			/* scroll_reverse                */
1970*21817992SBaptiste Daroussin 	"hu",			/* up_half_line                  */
1971*21817992SBaptiste Daroussin     };
1972*21817992SBaptiste Daroussin     size_t n;
1973*21817992SBaptiste Daroussin     for (n = 0; n < SIZEOF(table); ++n) {
1974*21817992SBaptiste Daroussin 	if (!strcmp(name, table[n])) {
1975*21817992SBaptiste Daroussin 	    result = TRUE;
1976*21817992SBaptiste Daroussin 	    break;
1977*21817992SBaptiste Daroussin 	}
1978*21817992SBaptiste Daroussin     }
1979*21817992SBaptiste Daroussin     return result;
1980*21817992SBaptiste Daroussin }
1981*21817992SBaptiste Daroussin 
1982aae38d10SBaptiste Daroussin /*
198318259542SPeter Wemm  * Make a quick sanity check for the parameters which are used in the given
198418259542SPeter Wemm  * strings.  If there are no "%p" tokens, then there should be no other "%"
198518259542SPeter Wemm  * markers.
198618259542SPeter Wemm  */
198718259542SPeter Wemm static void
check_params(TERMTYPE2 * tp,const char * name,const char * value,int extended)1988*21817992SBaptiste Daroussin check_params(TERMTYPE2 *tp, const char *name, const char *value, int extended)
198918259542SPeter Wemm {
199018259542SPeter Wemm     int expected = expected_params(name);
199118259542SPeter Wemm     int actual = 0;
199218259542SPeter Wemm     int n;
19937a656419SBaptiste Daroussin     bool params[1 + NUM_PARM];
1994*21817992SBaptiste Daroussin     const char *s = value;
199518259542SPeter Wemm 
1996*21817992SBaptiste Daroussin #ifdef set_left_margin_parm
1997*21817992SBaptiste Daroussin     if (!strcmp(name, "smgrp")
1998*21817992SBaptiste Daroussin 	&& !VALID_STRING(set_left_margin_parm))
1999*21817992SBaptiste Daroussin 	expected = 2;
2000*21817992SBaptiste Daroussin #endif
2001*21817992SBaptiste Daroussin #ifdef set_right_margin_parm
2002*21817992SBaptiste Daroussin     if (!strcmp(name, "smglp")
2003*21817992SBaptiste Daroussin 	&& !VALID_STRING(set_right_margin_parm))
2004*21817992SBaptiste Daroussin 	expected = 2;
2005*21817992SBaptiste Daroussin #endif
20064a1a9510SRong-En Fan #ifdef set_top_margin_parm
2007b82face1SPeter Wemm     if (!strcmp(name, "smgbp")
2008*21817992SBaptiste Daroussin 	&& !VALID_STRING(set_top_margin_parm))
2009*21817992SBaptiste Daroussin 	expected = 2;
2010*21817992SBaptiste Daroussin #endif
2011*21817992SBaptiste Daroussin #ifdef set_bottom_margin_parm
2012*21817992SBaptiste Daroussin     if (!strcmp(name, "smgtp")
2013*21817992SBaptiste Daroussin 	&& !VALID_STRING(set_bottom_margin_parm))
2014b82face1SPeter Wemm 	expected = 2;
20154a1a9510SRong-En Fan #endif
2016b82face1SPeter Wemm 
20177a656419SBaptiste Daroussin     for (n = 0; n <= NUM_PARM; n++)
201818259542SPeter Wemm 	params[n] = FALSE;
201918259542SPeter Wemm 
202018259542SPeter Wemm     while (*s != 0) {
202118259542SPeter Wemm 	if (*s == '%') {
202218259542SPeter Wemm 	    if (*++s == '\0') {
202318259542SPeter Wemm 		_nc_warning("expected character after %% in %s", name);
202418259542SPeter Wemm 		break;
202518259542SPeter Wemm 	    } else if (*s == 'p') {
202618259542SPeter Wemm 		if (*++s == '\0' || !isdigit((int) *s)) {
202718259542SPeter Wemm 		    _nc_warning("expected digit after %%p in %s", name);
202818259542SPeter Wemm 		    return;
202918259542SPeter Wemm 		} else {
203018259542SPeter Wemm 		    n = (*s - '0');
203118259542SPeter Wemm 		    if (n > actual)
203218259542SPeter Wemm 			actual = n;
203318259542SPeter Wemm 		    params[n] = TRUE;
203418259542SPeter Wemm 		}
203518259542SPeter Wemm 	    }
203618259542SPeter Wemm 	}
203718259542SPeter Wemm 	s++;
203818259542SPeter Wemm     }
203918259542SPeter Wemm 
2040aae38d10SBaptiste Daroussin #if NCURSES_XNAMES
2041aae38d10SBaptiste Daroussin     if (extended) {
2042aae38d10SBaptiste Daroussin 	int check = is_user_capability(name);
2043aae38d10SBaptiste Daroussin 	if (check != actual && (check >= 0 && actual >= 0)) {
2044aae38d10SBaptiste Daroussin 	    _nc_warning("extended %s capability has %d parameters, expected %d",
2045aae38d10SBaptiste Daroussin 			name, actual, check);
2046aae38d10SBaptiste Daroussin 	} else if (debug_level > 1) {
2047aae38d10SBaptiste Daroussin 	    _nc_warning("extended %s capability has %d parameters, as expected",
2048aae38d10SBaptiste Daroussin 			name, actual);
2049aae38d10SBaptiste Daroussin 	}
2050aae38d10SBaptiste Daroussin 	expected = actual;
2051aae38d10SBaptiste Daroussin     }
2052aae38d10SBaptiste Daroussin #else
2053aae38d10SBaptiste Daroussin     (void) extended;
2054aae38d10SBaptiste Daroussin #endif
2055aae38d10SBaptiste Daroussin 
205618259542SPeter Wemm     if (params[0]) {
205718259542SPeter Wemm 	_nc_warning("%s refers to parameter 0 (%%p0), which is not allowed", name);
205818259542SPeter Wemm     }
205918259542SPeter Wemm     if (value == set_attributes || expected < 0) {
206018259542SPeter Wemm 	;
206118259542SPeter Wemm     } else if (expected != actual) {
206218259542SPeter Wemm 	_nc_warning("%s uses %d parameters, expected %d", name,
206318259542SPeter Wemm 		    actual, expected);
206418259542SPeter Wemm 	for (n = 1; n < actual; n++) {
206518259542SPeter Wemm 	    if (!params[n])
206618259542SPeter Wemm 		_nc_warning("%s omits parameter %d", name, n);
206718259542SPeter Wemm 	}
206818259542SPeter Wemm     }
2069aae38d10SBaptiste Daroussin 
2070aae38d10SBaptiste Daroussin     /*
2071aae38d10SBaptiste Daroussin      * Counting "%p" markers does not account for termcap expressions which
2072aae38d10SBaptiste Daroussin      * may not have been fully translated.  Also, tparm does its own analysis.
2073aae38d10SBaptiste Daroussin      * Report differences here.
2074aae38d10SBaptiste Daroussin      */
2075*21817992SBaptiste Daroussin     _nc_reset_tparm(NULL);
2076aae38d10SBaptiste Daroussin     if (actual >= 0) {
2077aae38d10SBaptiste Daroussin 	char *p_is_s[NUM_PARM];
2078aae38d10SBaptiste Daroussin 	int popcount;
2079*21817992SBaptiste Daroussin 	int analyzed = _nc_tparm_analyze(NULL, value, p_is_s, &popcount);
2080aae38d10SBaptiste Daroussin 	if (analyzed < popcount) {
2081aae38d10SBaptiste Daroussin 	    analyzed = popcount;
2082aae38d10SBaptiste Daroussin 	}
2083aae38d10SBaptiste Daroussin 	if (actual != analyzed && expected != analyzed) {
2084aae38d10SBaptiste Daroussin #if NCURSES_XNAMES
2085aae38d10SBaptiste Daroussin 	    int user_cap = is_user_capability(name);
2086aae38d10SBaptiste Daroussin 	    if ((user_cap == analyzed) && using_extensions) {
2087aae38d10SBaptiste Daroussin 		;		/* ignore */
2088aae38d10SBaptiste Daroussin 	    } else if (user_cap >= 0) {
2089aae38d10SBaptiste Daroussin 		_nc_warning("tparm will use %d parameters for %s, expected %d",
2090aae38d10SBaptiste Daroussin 			    analyzed, name, user_cap);
2091aae38d10SBaptiste Daroussin 	    } else
2092aae38d10SBaptiste Daroussin #endif
2093aae38d10SBaptiste Daroussin 	    {
2094aae38d10SBaptiste Daroussin 		_nc_warning("tparm analyzed %d parameters for %s, expected %d",
2095aae38d10SBaptiste Daroussin 			    analyzed, name, actual);
2096aae38d10SBaptiste Daroussin 	    }
2097*21817992SBaptiste Daroussin 	} else if (expected > 0
2098*21817992SBaptiste Daroussin 		   && actual == expected
2099*21817992SBaptiste Daroussin 		   && guess_tparm_type(expected, p_is_s) == Numbers) {
2100*21817992SBaptiste Daroussin 	    int limit = 1;
2101aae38d10SBaptiste Daroussin 
2102*21817992SBaptiste Daroussin 	    if (!strcmp(name, "setf")
2103*21817992SBaptiste Daroussin 		|| !strcmp(name, "setb")
2104*21817992SBaptiste Daroussin 		|| !strcmp(name, "setaf")
2105*21817992SBaptiste Daroussin 		|| !strcmp(name, "setab")) {
2106*21817992SBaptiste Daroussin 		if ((limit = max_colors) > 256)
2107*21817992SBaptiste Daroussin 		    limit = 256;
2108*21817992SBaptiste Daroussin 	    } else if (line_capability(name)) {
2109*21817992SBaptiste Daroussin 		limit = 24;
2110*21817992SBaptiste Daroussin 	    } else if (is_user_capability(name) < 0) {
2111*21817992SBaptiste Daroussin 		limit = 80;
2112*21817992SBaptiste Daroussin 	    }
2113*21817992SBaptiste Daroussin 	    for (n = 0; n < limit; ++n) {
2114*21817992SBaptiste Daroussin 		_nc_reset_tparm(NULL);
2115*21817992SBaptiste Daroussin 		(void) TPARM_9(value, n, n, n, n, n, n, n, n, n);
2116*21817992SBaptiste Daroussin 		if (_nc_tparm_err) {
2117*21817992SBaptiste Daroussin 		    _nc_warning("problem%s in tparm(%s, %d, ...)",
2118*21817992SBaptiste Daroussin 				(_nc_tparm_err == 1) ? "" : "s",
2119*21817992SBaptiste Daroussin 				name, n);
2120*21817992SBaptiste Daroussin 		    if (debug_level < 2)
2121aae38d10SBaptiste Daroussin 			break;
2122aae38d10SBaptiste Daroussin 		}
2123aae38d10SBaptiste Daroussin 	    }
2124*21817992SBaptiste Daroussin 	}
2125*21817992SBaptiste Daroussin     }
2126aae38d10SBaptiste Daroussin }
2127aae38d10SBaptiste Daroussin 
2128aae38d10SBaptiste Daroussin /*
2129aae38d10SBaptiste Daroussin  * Check for DEC VT100 private mode for reverse video.
2130aae38d10SBaptiste Daroussin  */
2131aae38d10SBaptiste Daroussin static const char *
skip_DECSCNM(const char * value,int * flag)2132aae38d10SBaptiste Daroussin skip_DECSCNM(const char *value, int *flag)
2133aae38d10SBaptiste Daroussin {
2134aae38d10SBaptiste Daroussin     *flag = -1;
2135aae38d10SBaptiste Daroussin     if (value != 0) {
2136aae38d10SBaptiste Daroussin 	int skip = csi_length(value);
2137aae38d10SBaptiste Daroussin 	if (skip > 0 &&
2138aae38d10SBaptiste Daroussin 	    value[skip++] == '?' &&
2139aae38d10SBaptiste Daroussin 	    value[skip++] == '5') {
2140aae38d10SBaptiste Daroussin 	    if (value[skip] == 'h') {
2141aae38d10SBaptiste Daroussin 		*flag = 1;
2142aae38d10SBaptiste Daroussin 	    } else if (value[skip] == 'l') {
2143aae38d10SBaptiste Daroussin 		*flag = 0;
2144aae38d10SBaptiste Daroussin 	    }
2145aae38d10SBaptiste Daroussin 	    value += skip + 1;
2146aae38d10SBaptiste Daroussin 	}
2147aae38d10SBaptiste Daroussin     }
2148aae38d10SBaptiste Daroussin     return value;
2149aae38d10SBaptiste Daroussin }
2150aae38d10SBaptiste Daroussin 
2151aae38d10SBaptiste Daroussin static void
check_delays(TERMTYPE2 * tp,const char * name,const char * value)2152aae38d10SBaptiste Daroussin check_delays(TERMTYPE2 *tp, const char *name, const char *value)
2153aae38d10SBaptiste Daroussin {
2154aae38d10SBaptiste Daroussin     const char *p, *q;
2155aae38d10SBaptiste Daroussin     const char *first = 0;
2156aae38d10SBaptiste Daroussin     const char *last = 0;
2157aae38d10SBaptiste Daroussin 
2158aae38d10SBaptiste Daroussin     for (p = value; *p != '\0'; ++p) {
2159aae38d10SBaptiste Daroussin 	if (p[0] == '$' && p[1] == '<') {
2160aae38d10SBaptiste Daroussin 	    const char *base = p + 2;
2161aae38d10SBaptiste Daroussin 	    const char *mark = 0;
2162aae38d10SBaptiste Daroussin 	    bool mixed = FALSE;
2163aae38d10SBaptiste Daroussin 	    int proportional = 0;
2164aae38d10SBaptiste Daroussin 	    int mandatory = 0;
2165aae38d10SBaptiste Daroussin 
2166aae38d10SBaptiste Daroussin 	    first = p;
2167aae38d10SBaptiste Daroussin 
2168aae38d10SBaptiste Daroussin 	    for (q = base; *q != '\0'; ++q) {
2169aae38d10SBaptiste Daroussin 		if (*q == '>') {
2170*21817992SBaptiste Daroussin 		    if (mark == NULL)
2171aae38d10SBaptiste Daroussin 			mark = q;
2172aae38d10SBaptiste Daroussin 		    break;
2173aae38d10SBaptiste Daroussin 		} else if (*q == '*' || *q == '/') {
2174aae38d10SBaptiste Daroussin 		    if (*q == '*')
2175aae38d10SBaptiste Daroussin 			++proportional;
2176aae38d10SBaptiste Daroussin 		    if (*q == '/')
2177aae38d10SBaptiste Daroussin 			++mandatory;
2178*21817992SBaptiste Daroussin 		    if (mark == NULL)
2179aae38d10SBaptiste Daroussin 			mark = q;
2180aae38d10SBaptiste Daroussin 		} else if (!(isalnum(UChar(*q)) || strchr("+-.", *q) != 0)) {
2181aae38d10SBaptiste Daroussin 		    break;
2182aae38d10SBaptiste Daroussin 		} else if (proportional || mandatory) {
2183aae38d10SBaptiste Daroussin 		    mixed = TRUE;
2184aae38d10SBaptiste Daroussin 		}
2185aae38d10SBaptiste Daroussin 	    }
2186aae38d10SBaptiste Daroussin 	    last = *q ? (q + 1) : q;
2187*21817992SBaptiste Daroussin 	    if (*q != '\0') {
2188aae38d10SBaptiste Daroussin 		float check_f;
2189aae38d10SBaptiste Daroussin 		char check_c;
2190aae38d10SBaptiste Daroussin 		int rc = sscanf(base, "%f%c", &check_f, &check_c);
2191*21817992SBaptiste Daroussin 		if ((rc != 2) || (mark != NULL && (check_c != *mark)) || mixed) {
2192aae38d10SBaptiste Daroussin 		    _nc_warning("syntax error in %s delay '%.*s'", name,
2193aae38d10SBaptiste Daroussin 				(int) (q - base), base);
2194aae38d10SBaptiste Daroussin 		} else if (*name == 'k') {
2195aae38d10SBaptiste Daroussin 		    _nc_warning("function-key %s has delay", name);
2196aae38d10SBaptiste Daroussin 		} else if (proportional && !line_capability(name)) {
2197aae38d10SBaptiste Daroussin 		    _nc_warning("non-line capability using proportional delay: %s", name);
2198aae38d10SBaptiste Daroussin 		} else if (!xon_xoff &&
2199aae38d10SBaptiste Daroussin 			   !mandatory &&
2200*21817992SBaptiste Daroussin 			   strchr(_nc_first_name(tp->term_names), '+') == NULL) {
2201aae38d10SBaptiste Daroussin 		    _nc_warning("%s in %s is used since no xon/xoff",
2202aae38d10SBaptiste Daroussin 				(proportional
2203aae38d10SBaptiste Daroussin 				 ? "proportional delay"
2204aae38d10SBaptiste Daroussin 				 : "delay"),
2205aae38d10SBaptiste Daroussin 				name);
2206aae38d10SBaptiste Daroussin 		}
2207aae38d10SBaptiste Daroussin 	    } else {
2208aae38d10SBaptiste Daroussin 		p = q - 1;	/* restart scan */
2209aae38d10SBaptiste Daroussin 	    }
2210aae38d10SBaptiste Daroussin 	}
2211aae38d10SBaptiste Daroussin     }
2212aae38d10SBaptiste Daroussin 
2213aae38d10SBaptiste Daroussin     if (!strcmp(name, "flash") ||
2214aae38d10SBaptiste Daroussin 	!strcmp(name, "beep")) {
2215aae38d10SBaptiste Daroussin 
2216aae38d10SBaptiste Daroussin 	if (first != 0) {
2217aae38d10SBaptiste Daroussin 	    if (first == value || *last == 0) {
2218aae38d10SBaptiste Daroussin 		/*
2219aae38d10SBaptiste Daroussin 		 * Delay is on one end or the other.
2220aae38d10SBaptiste Daroussin 		 */
2221aae38d10SBaptiste Daroussin 		_nc_warning("expected delay embedded within %s", name);
2222aae38d10SBaptiste Daroussin 	    }
2223aae38d10SBaptiste Daroussin 	} else {
2224aae38d10SBaptiste Daroussin 	    int flag;
2225aae38d10SBaptiste Daroussin 
2226aae38d10SBaptiste Daroussin 	    /*
2227aae38d10SBaptiste Daroussin 	     * Check for missing delay when using VT100 reverse-video.
2228aae38d10SBaptiste Daroussin 	     * A real VT100 might not need this, but terminal emulators do.
2229aae38d10SBaptiste Daroussin 	     */
2230aae38d10SBaptiste Daroussin 	    if ((p = skip_DECSCNM(value, &flag)) != 0 &&
2231aae38d10SBaptiste Daroussin 		flag > 0 &&
2232*21817992SBaptiste Daroussin 		skip_DECSCNM(p, &flag) != 0 &&
2233aae38d10SBaptiste Daroussin 		flag == 0) {
2234aae38d10SBaptiste Daroussin 		_nc_warning("expected a delay in %s", name);
2235aae38d10SBaptiste Daroussin 	    }
2236aae38d10SBaptiste Daroussin 	}
2237aae38d10SBaptiste Daroussin     }
2238aae38d10SBaptiste Daroussin }
2239aae38d10SBaptiste Daroussin 
2240aae38d10SBaptiste Daroussin static char *
check_1_infotocap(const char * name,NCURSES_CONST char * value,int count)2241aae38d10SBaptiste Daroussin check_1_infotocap(const char *name, NCURSES_CONST char *value, int count)
2242aae38d10SBaptiste Daroussin {
2243aae38d10SBaptiste Daroussin     int k;
2244aae38d10SBaptiste Daroussin     int ignored;
2245aae38d10SBaptiste Daroussin     long numbers[1 + NUM_PARM];
2246aae38d10SBaptiste Daroussin     char *strings[1 + NUM_PARM];
2247aae38d10SBaptiste Daroussin     char *p_is_s[NUM_PARM];
2248aae38d10SBaptiste Daroussin     char *result;
2249aae38d10SBaptiste Daroussin     char blob[NUM_PARM * 10];
2250aae38d10SBaptiste Daroussin     char *next = blob;
22517a656419SBaptiste Daroussin     TParams expect;
22527a656419SBaptiste Daroussin     TParams actual;
22537a656419SBaptiste Daroussin     int nparam;
2254aae38d10SBaptiste Daroussin 
2255aae38d10SBaptiste Daroussin     *next++ = '\0';
2256aae38d10SBaptiste Daroussin     for (k = 1; k <= NUM_PARM; k++) {
2257aae38d10SBaptiste Daroussin 	numbers[k] = count;
2258aae38d10SBaptiste Daroussin 	_nc_SPRINTF(next,
2259aae38d10SBaptiste Daroussin 		    _nc_SLIMIT(sizeof(blob) - (size_t) (next - blob))
2260aae38d10SBaptiste Daroussin 		    "XYZ%d", count);
2261aae38d10SBaptiste Daroussin 	strings[k] = next;
2262aae38d10SBaptiste Daroussin 	next += strlen(next) + 1;
2263aae38d10SBaptiste Daroussin     }
2264aae38d10SBaptiste Daroussin 
2265*21817992SBaptiste Daroussin     _nc_reset_tparm(NULL);
22667a656419SBaptiste Daroussin     expect = tparm_type(name);
2267*21817992SBaptiste Daroussin     nparam = _nc_tparm_analyze(NULL, value, p_is_s, &ignored);
22687a656419SBaptiste Daroussin     actual = guess_tparm_type(nparam, p_is_s);
22697a656419SBaptiste Daroussin 
22707a656419SBaptiste Daroussin     if (expect != actual) {
22717a656419SBaptiste Daroussin 	_nc_warning("%s has mismatched parameters", name);
22727a656419SBaptiste Daroussin 	actual = Other;
22737a656419SBaptiste Daroussin     }
22747a656419SBaptiste Daroussin 
2275*21817992SBaptiste Daroussin     _nc_reset_tparm(NULL);
22767a656419SBaptiste Daroussin     switch (actual) {
2277*21817992SBaptiste Daroussin     case Str:
2278*21817992SBaptiste Daroussin 	result = TPARM_1(value, strings[1]);
2279*21817992SBaptiste Daroussin 	break;
2280aae38d10SBaptiste Daroussin     case Num_Str:
2281aae38d10SBaptiste Daroussin 	result = TPARM_2(value, numbers[1], strings[2]);
2282aae38d10SBaptiste Daroussin 	break;
2283*21817992SBaptiste Daroussin     case Str_Str:
2284*21817992SBaptiste Daroussin 	result = TPARM_2(value, strings[1], strings[2]);
2285*21817992SBaptiste Daroussin 	break;
2286aae38d10SBaptiste Daroussin     case Num_Str_Str:
2287aae38d10SBaptiste Daroussin 	result = TPARM_3(value, numbers[1], strings[2], strings[3]);
2288aae38d10SBaptiste Daroussin 	break;
2289aae38d10SBaptiste Daroussin     case Numbers:
22907a656419SBaptiste Daroussin #define myParam(n) numbers[n]
22917a656419SBaptiste Daroussin 	result = TIPARM_9(value,
22927a656419SBaptiste Daroussin 			  myParam(1),
22937a656419SBaptiste Daroussin 			  myParam(2),
22947a656419SBaptiste Daroussin 			  myParam(3),
22957a656419SBaptiste Daroussin 			  myParam(4),
22967a656419SBaptiste Daroussin 			  myParam(5),
22977a656419SBaptiste Daroussin 			  myParam(6),
22987a656419SBaptiste Daroussin 			  myParam(7),
22997a656419SBaptiste Daroussin 			  myParam(8),
23007a656419SBaptiste Daroussin 			  myParam(9));
23017a656419SBaptiste Daroussin #undef myParam
23027a656419SBaptiste Daroussin 	break;
23037a656419SBaptiste Daroussin     case Other:
2304aae38d10SBaptiste Daroussin     default:
2305aae38d10SBaptiste Daroussin #define myParam(n) (p_is_s[n - 1] != 0 ? ((TPARM_ARG) strings[n]) : numbers[n])
2306aae38d10SBaptiste Daroussin 	result = TPARM_9(value,
2307aae38d10SBaptiste Daroussin 			 myParam(1),
2308aae38d10SBaptiste Daroussin 			 myParam(2),
2309aae38d10SBaptiste Daroussin 			 myParam(3),
2310aae38d10SBaptiste Daroussin 			 myParam(4),
2311aae38d10SBaptiste Daroussin 			 myParam(5),
2312aae38d10SBaptiste Daroussin 			 myParam(6),
2313aae38d10SBaptiste Daroussin 			 myParam(7),
2314aae38d10SBaptiste Daroussin 			 myParam(8),
2315aae38d10SBaptiste Daroussin 			 myParam(9));
23167a656419SBaptiste Daroussin #undef myParam
2317aae38d10SBaptiste Daroussin 	break;
2318aae38d10SBaptiste Daroussin     }
2319aae38d10SBaptiste Daroussin     return strdup(result);
2320aae38d10SBaptiste Daroussin }
2321aae38d10SBaptiste Daroussin 
2322aae38d10SBaptiste Daroussin #define IsDelay(ch) ((ch) == '.' || isdigit(UChar(ch)))
2323aae38d10SBaptiste Daroussin 
2324aae38d10SBaptiste Daroussin static const char *
parse_delay_value(const char * src,double * delays,int * always)2325aae38d10SBaptiste Daroussin parse_delay_value(const char *src, double *delays, int *always)
2326aae38d10SBaptiste Daroussin {
2327aae38d10SBaptiste Daroussin     int star = 0;
2328aae38d10SBaptiste Daroussin 
2329aae38d10SBaptiste Daroussin     *delays = 0.0;
2330aae38d10SBaptiste Daroussin     if (always)
2331aae38d10SBaptiste Daroussin 	*always = 0;
2332aae38d10SBaptiste Daroussin 
2333aae38d10SBaptiste Daroussin     while (isdigit(UChar(*src))) {
2334aae38d10SBaptiste Daroussin 	(*delays) = (*delays) * 10 + (*src++ - '0');
2335aae38d10SBaptiste Daroussin     }
2336aae38d10SBaptiste Daroussin     if (*src == '.') {
2337aae38d10SBaptiste Daroussin 	int gotdot = 1;
2338aae38d10SBaptiste Daroussin 
2339aae38d10SBaptiste Daroussin 	++src;
2340aae38d10SBaptiste Daroussin 	while (isdigit(UChar(*src))) {
2341aae38d10SBaptiste Daroussin 	    gotdot *= 10;
2342aae38d10SBaptiste Daroussin 	    (*delays) += (*src++ - '0') / gotdot;
2343aae38d10SBaptiste Daroussin 	}
2344aae38d10SBaptiste Daroussin     }
2345aae38d10SBaptiste Daroussin     while (*src == '*' || *src == '/') {
2346*21817992SBaptiste Daroussin 	if (always == NULL && *src == '/')
2347aae38d10SBaptiste Daroussin 	    break;
2348aae38d10SBaptiste Daroussin 	if (*src++ == '*') {
2349aae38d10SBaptiste Daroussin 	    star = 1;
2350aae38d10SBaptiste Daroussin 	} else {
2351aae38d10SBaptiste Daroussin 	    *always = 1;
2352aae38d10SBaptiste Daroussin 	}
2353aae38d10SBaptiste Daroussin     }
2354aae38d10SBaptiste Daroussin     if (star)
2355aae38d10SBaptiste Daroussin 	*delays = -(*delays);
2356aae38d10SBaptiste Daroussin     return src;
2357aae38d10SBaptiste Daroussin }
2358aae38d10SBaptiste Daroussin 
2359aae38d10SBaptiste Daroussin static const char *
parse_ti_delay(const char * ti,double * delays)2360aae38d10SBaptiste Daroussin parse_ti_delay(const char *ti, double *delays)
2361aae38d10SBaptiste Daroussin {
2362aae38d10SBaptiste Daroussin     *delays = 0.0;
2363aae38d10SBaptiste Daroussin     while (*ti != '\0') {
2364aae38d10SBaptiste Daroussin 	if (*ti == '\\') {
2365aae38d10SBaptiste Daroussin 	    ++ti;
2366aae38d10SBaptiste Daroussin 	}
2367aae38d10SBaptiste Daroussin 	if (ti[0] == '$'
2368aae38d10SBaptiste Daroussin 	    && ti[1] == '<'
2369aae38d10SBaptiste Daroussin 	    && IsDelay(UChar(ti[2]))) {
2370aae38d10SBaptiste Daroussin 	    int ignored;
2371aae38d10SBaptiste Daroussin 	    const char *last = parse_delay_value(ti + 2, delays, &ignored);
2372aae38d10SBaptiste Daroussin 	    if (*last == '>') {
2373aae38d10SBaptiste Daroussin 		ti = last;
2374aae38d10SBaptiste Daroussin 	    }
2375aae38d10SBaptiste Daroussin 	} else {
2376aae38d10SBaptiste Daroussin 	    ++ti;
2377aae38d10SBaptiste Daroussin 	}
2378aae38d10SBaptiste Daroussin     }
2379aae38d10SBaptiste Daroussin     return ti;
2380aae38d10SBaptiste Daroussin }
2381aae38d10SBaptiste Daroussin 
2382aae38d10SBaptiste Daroussin static const char *
parse_tc_delay(const char * tc,double * delays)2383aae38d10SBaptiste Daroussin parse_tc_delay(const char *tc, double *delays)
2384aae38d10SBaptiste Daroussin {
2385aae38d10SBaptiste Daroussin     return parse_delay_value(tc, delays, (int *) 0);
2386aae38d10SBaptiste Daroussin }
2387aae38d10SBaptiste Daroussin 
2388aae38d10SBaptiste Daroussin /*
2389aae38d10SBaptiste Daroussin  * Compare terminfo- and termcap-strings, factoring out delays.
2390aae38d10SBaptiste Daroussin  */
2391aae38d10SBaptiste Daroussin static bool
same_ti_tc(const char * ti,const char * tc,bool * embedded)2392aae38d10SBaptiste Daroussin same_ti_tc(const char *ti, const char *tc, bool * embedded)
2393aae38d10SBaptiste Daroussin {
2394aae38d10SBaptiste Daroussin     bool same = TRUE;
2395aae38d10SBaptiste Daroussin     double ti_delay = 0.0;
2396aae38d10SBaptiste Daroussin     double tc_delay = 0.0;
2397aae38d10SBaptiste Daroussin     const char *ti_last;
2398aae38d10SBaptiste Daroussin 
2399aae38d10SBaptiste Daroussin     *embedded = FALSE;
2400aae38d10SBaptiste Daroussin     ti_last = parse_ti_delay(ti, &ti_delay);
2401aae38d10SBaptiste Daroussin     tc = parse_tc_delay(tc, &tc_delay);
2402aae38d10SBaptiste Daroussin 
2403aae38d10SBaptiste Daroussin     while ((ti < ti_last) && *tc) {
2404aae38d10SBaptiste Daroussin 	if (*ti == '\\' && ispunct(UChar(ti[1]))) {
2405aae38d10SBaptiste Daroussin 	    ++ti;
2406aae38d10SBaptiste Daroussin 	    if ((*ti == '^') && !strncmp(tc, "\\136", 4)) {
2407aae38d10SBaptiste Daroussin 		ti += 1;
2408aae38d10SBaptiste Daroussin 		tc += 4;
2409aae38d10SBaptiste Daroussin 		continue;
2410aae38d10SBaptiste Daroussin 	    }
2411aae38d10SBaptiste Daroussin 	} else if (ti[0] == '$' && ti[1] == '<') {
2412aae38d10SBaptiste Daroussin 	    double no_delay;
2413aae38d10SBaptiste Daroussin 	    const char *ss = parse_ti_delay(ti, &no_delay);
2414aae38d10SBaptiste Daroussin 	    if (ss != ti) {
2415aae38d10SBaptiste Daroussin 		*embedded = TRUE;
2416aae38d10SBaptiste Daroussin 		ti = ss;
2417aae38d10SBaptiste Daroussin 		continue;
2418aae38d10SBaptiste Daroussin 	    }
2419aae38d10SBaptiste Daroussin 	}
2420aae38d10SBaptiste Daroussin 	if (*tc == '\\' && ispunct(UChar(tc[1]))) {
2421aae38d10SBaptiste Daroussin 	    ++tc;
2422aae38d10SBaptiste Daroussin 	}
2423aae38d10SBaptiste Daroussin 	if (*ti++ != *tc++) {
2424aae38d10SBaptiste Daroussin 	    same = FALSE;
2425aae38d10SBaptiste Daroussin 	    break;
2426aae38d10SBaptiste Daroussin 	}
2427aae38d10SBaptiste Daroussin     }
2428aae38d10SBaptiste Daroussin 
2429aae38d10SBaptiste Daroussin     if (*embedded) {
2430aae38d10SBaptiste Daroussin 	if (same) {
2431aae38d10SBaptiste Daroussin 	    same = FALSE;
2432aae38d10SBaptiste Daroussin 	} else {
2433aae38d10SBaptiste Daroussin 	    *embedded = FALSE;	/* report only one problem */
2434aae38d10SBaptiste Daroussin 	}
2435aae38d10SBaptiste Daroussin     }
2436aae38d10SBaptiste Daroussin 
2437aae38d10SBaptiste Daroussin     return same;
2438aae38d10SBaptiste Daroussin }
2439aae38d10SBaptiste Daroussin 
2440aae38d10SBaptiste Daroussin /*
2441aae38d10SBaptiste Daroussin  * Check terminfo to termcap translation.
2442aae38d10SBaptiste Daroussin  */
2443aae38d10SBaptiste Daroussin static void
check_infotocap(TERMTYPE2 * tp,int i,const char * value)2444aae38d10SBaptiste Daroussin check_infotocap(TERMTYPE2 *tp, int i, const char *value)
2445aae38d10SBaptiste Daroussin {
2446aae38d10SBaptiste Daroussin     const char *name = ExtStrname(tp, i, strnames);
2447*21817992SBaptiste Daroussin     char *ti_value = NULL;
2448*21817992SBaptiste Daroussin 
2449*21817992SBaptiste Daroussin     assert(SIZEOF(parametrized) == STRCOUNT);
2450*21817992SBaptiste Daroussin     if (!VALID_STRING(value) || (ti_value = strdup(value)) == NULL) {
2451*21817992SBaptiste Daroussin 	_nc_warning("tic-expansion of %s failed", name);
2452*21817992SBaptiste Daroussin     } else {
2453*21817992SBaptiste Daroussin 	char *tc_value;
2454*21817992SBaptiste Daroussin 	bool embedded;
2455aae38d10SBaptiste Daroussin 	int params = ((i < (int) SIZEOF(parametrized))
2456aae38d10SBaptiste Daroussin 		      ? parametrized[i]
2457aae38d10SBaptiste Daroussin 		      : ((*value == 'k')
2458aae38d10SBaptiste Daroussin 			 ? 0
24597a656419SBaptiste Daroussin 			 : has_params(value, FALSE)));
2460aae38d10SBaptiste Daroussin 
2461*21817992SBaptiste Daroussin 	if ((tc_value = _nc_infotocap(name, ti_value, params)) == ABSENT_STRING) {
2462aae38d10SBaptiste Daroussin 	    _nc_warning("tic-conversion of %s failed", name);
2463aae38d10SBaptiste Daroussin 	} else if (params > 0) {
2464aae38d10SBaptiste Daroussin 	    int limit = 5;
2465aae38d10SBaptiste Daroussin 	    int count;
2466aae38d10SBaptiste Daroussin 	    bool first = TRUE;
2467aae38d10SBaptiste Daroussin 
2468aae38d10SBaptiste Daroussin 	    if (!strcmp(name, "setf")
2469aae38d10SBaptiste Daroussin 		|| !strcmp(name, "setb")
2470aae38d10SBaptiste Daroussin 		|| !strcmp(name, "setaf")
2471aae38d10SBaptiste Daroussin 		|| !strcmp(name, "setab")) {
2472*21817992SBaptiste Daroussin 		if ((limit = max_colors) > 256)
2473*21817992SBaptiste Daroussin 		    limit = 256;
2474aae38d10SBaptiste Daroussin 	    }
2475aae38d10SBaptiste Daroussin 	    for (count = 0; count < limit; ++count) {
2476aae38d10SBaptiste Daroussin 		char *ti_check = check_1_infotocap(name, ti_value, count);
2477aae38d10SBaptiste Daroussin 		char *tc_check = check_1_infotocap(name, tc_value, count);
2478aae38d10SBaptiste Daroussin 
2479aae38d10SBaptiste Daroussin 		if (strcmp(ti_check, tc_check)) {
2480aae38d10SBaptiste Daroussin 		    if (first) {
2481aae38d10SBaptiste Daroussin 			fprintf(stderr, "check_infotocap(%s)\n", name);
24827a656419SBaptiste Daroussin 			fprintf(stderr, "...ti '%s'\n", _nc_visbuf2(0, ti_value));
24837a656419SBaptiste Daroussin 			fprintf(stderr, "...tc '%s'\n", _nc_visbuf2(0, tc_value));
2484aae38d10SBaptiste Daroussin 			first = FALSE;
2485aae38d10SBaptiste Daroussin 		    }
2486aae38d10SBaptiste Daroussin 		    _nc_warning("tparm-conversion of %s(%d) differs between\n\tterminfo %s\n\ttermcap  %s",
24877a656419SBaptiste Daroussin 				name, count,
24887a656419SBaptiste Daroussin 				_nc_visbuf2(0, ti_check),
24897a656419SBaptiste Daroussin 				_nc_visbuf2(1, tc_check));
2490aae38d10SBaptiste Daroussin 		}
2491aae38d10SBaptiste Daroussin 		free(ti_check);
2492aae38d10SBaptiste Daroussin 		free(tc_check);
2493aae38d10SBaptiste Daroussin 	    }
2494aae38d10SBaptiste Daroussin 	} else if (params == 0 && !same_ti_tc(ti_value, tc_value, &embedded)) {
2495aae38d10SBaptiste Daroussin 	    if (embedded) {
2496aae38d10SBaptiste Daroussin 		_nc_warning("termcap equivalent of %s cannot use embedded delay", name);
2497aae38d10SBaptiste Daroussin 	    } else {
2498aae38d10SBaptiste Daroussin 		_nc_warning("tic-conversion of %s changed value\n\tfrom %s\n\tto   %s",
2499aae38d10SBaptiste Daroussin 			    name, ti_value, tc_value);
2500aae38d10SBaptiste Daroussin 	    }
2501aae38d10SBaptiste Daroussin 	}
2502*21817992SBaptiste Daroussin 	free(ti_value);
2503*21817992SBaptiste Daroussin     }
250418259542SPeter Wemm }
250518259542SPeter Wemm 
2506b82face1SPeter Wemm static char *
skip_delay(char * s)2507b82face1SPeter Wemm skip_delay(char *s)
2508b82face1SPeter Wemm {
2509b82face1SPeter Wemm     while (*s == '/' || isdigit(UChar(*s)))
2510b82face1SPeter Wemm 	++s;
2511b82face1SPeter Wemm     return s;
2512b82face1SPeter Wemm }
2513b82face1SPeter Wemm 
251418259542SPeter Wemm /*
25154a1a9510SRong-En Fan  * Skip a delay altogether, e.g., when comparing a simple string to sgr,
25164a1a9510SRong-En Fan  * the latter may have a worst-case delay on the end.
25174a1a9510SRong-En Fan  */
25184a1a9510SRong-En Fan static char *
ignore_delays(char * s)25194a1a9510SRong-En Fan ignore_delays(char *s)
25204a1a9510SRong-En Fan {
25214a1a9510SRong-En Fan     int delaying = 0;
25224a1a9510SRong-En Fan 
25234a1a9510SRong-En Fan     do {
25244a1a9510SRong-En Fan 	switch (*s) {
25254a1a9510SRong-En Fan 	case '$':
25264a1a9510SRong-En Fan 	    if (delaying == 0)
25274a1a9510SRong-En Fan 		delaying = 1;
25284a1a9510SRong-En Fan 	    break;
25294a1a9510SRong-En Fan 	case '<':
25304a1a9510SRong-En Fan 	    if (delaying == 1)
25314a1a9510SRong-En Fan 		delaying = 2;
25324a1a9510SRong-En Fan 	    break;
25334a1a9510SRong-En Fan 	case '\0':
25344a1a9510SRong-En Fan 	    delaying = 0;
25354a1a9510SRong-En Fan 	    break;
25364a1a9510SRong-En Fan 	default:
25374a1a9510SRong-En Fan 	    if (delaying) {
25384a1a9510SRong-En Fan 		s = skip_delay(s);
25394a1a9510SRong-En Fan 		if (*s == '>')
25404a1a9510SRong-En Fan 		    ++s;
25414a1a9510SRong-En Fan 		delaying = 0;
25424a1a9510SRong-En Fan 	    }
25434a1a9510SRong-En Fan 	    break;
25444a1a9510SRong-En Fan 	}
25454a1a9510SRong-En Fan 	if (delaying)
25464a1a9510SRong-En Fan 	    ++s;
25474a1a9510SRong-En Fan     } while (delaying);
25484a1a9510SRong-En Fan     return s;
25494a1a9510SRong-En Fan }
25504a1a9510SRong-En Fan 
2551aae38d10SBaptiste Daroussin #define DATA(name) { #name }
2552aae38d10SBaptiste Daroussin static const char sgr_names[][11] =
2553aae38d10SBaptiste Daroussin {
2554aae38d10SBaptiste Daroussin     DATA(none),
2555aae38d10SBaptiste Daroussin     DATA(standout),
2556aae38d10SBaptiste Daroussin     DATA(underline),
2557aae38d10SBaptiste Daroussin     DATA(reverse),
2558aae38d10SBaptiste Daroussin     DATA(blink),
2559aae38d10SBaptiste Daroussin     DATA(dim),
2560aae38d10SBaptiste Daroussin     DATA(bold),
2561aae38d10SBaptiste Daroussin     DATA(invis),
2562aae38d10SBaptiste Daroussin     DATA(protect),
2563aae38d10SBaptiste Daroussin     DATA(altcharset),
2564aae38d10SBaptiste Daroussin     ""
2565aae38d10SBaptiste Daroussin };
2566aae38d10SBaptiste Daroussin #undef DATA
2567aae38d10SBaptiste Daroussin 
25684a1a9510SRong-En Fan /*
256915589c42SPeter Wemm  * An sgr string may contain several settings other than the one we're
257015589c42SPeter Wemm  * interested in, essentially sgr0 + rmacs + whatever.  As long as the
257115589c42SPeter Wemm  * "whatever" is contained in the sgr string, that is close enough for our
257215589c42SPeter Wemm  * sanity check.
257315589c42SPeter Wemm  */
257415589c42SPeter Wemm static bool
similar_sgr(int num,char * a,char * b)2575b82face1SPeter Wemm similar_sgr(int num, char *a, char *b)
257615589c42SPeter Wemm {
2577b82face1SPeter Wemm     char *base_a = a;
2578b82face1SPeter Wemm     char *base_b = b;
2579b82face1SPeter Wemm     int delaying = 0;
2580b82face1SPeter Wemm 
258115589c42SPeter Wemm     while (*b != 0) {
258215589c42SPeter Wemm 	while (*a != *b) {
25837a69bbfbSPeter Wemm 	    if (*a == 0) {
2584aae38d10SBaptiste Daroussin 		if (num < 0) {
2585aae38d10SBaptiste Daroussin 		    ;
2586aae38d10SBaptiste Daroussin 		} else if (b[0] == '$'
25877a69bbfbSPeter Wemm 			   && b[1] == '<') {
2588aae38d10SBaptiste Daroussin 		    _nc_warning("did not find delay %s", _nc_visbuf(b));
25897a69bbfbSPeter Wemm 		} else {
2590b82face1SPeter Wemm 		    _nc_warning("checking sgr(%s) %s\n\tcompare to %s\n\tunmatched %s",
2591aae38d10SBaptiste Daroussin 				sgr_names[num], _nc_visbuf2(1, base_a),
2592b82face1SPeter Wemm 				_nc_visbuf2(2, base_b),
2593b82face1SPeter Wemm 				_nc_visbuf2(3, b));
25947a69bbfbSPeter Wemm 		}
259515589c42SPeter Wemm 		return FALSE;
2596b82face1SPeter Wemm 	    } else if (delaying) {
2597b82face1SPeter Wemm 		a = skip_delay(a);
2598b82face1SPeter Wemm 		b = skip_delay(b);
259906bfebdeSXin LI 	    } else if ((*b == '0' || (*b == ';')) && *a == 'm') {
260006bfebdeSXin LI 		b++;
2601b82face1SPeter Wemm 	    } else {
260215589c42SPeter Wemm 		a++;
260315589c42SPeter Wemm 	    }
2604b82face1SPeter Wemm 	}
2605b82face1SPeter Wemm 	switch (*a) {
2606b82face1SPeter Wemm 	case '$':
2607b82face1SPeter Wemm 	    if (delaying == 0)
2608b82face1SPeter Wemm 		delaying = 1;
2609b82face1SPeter Wemm 	    break;
2610b82face1SPeter Wemm 	case '<':
2611b82face1SPeter Wemm 	    if (delaying == 1)
2612b82face1SPeter Wemm 		delaying = 2;
2613b82face1SPeter Wemm 	    break;
2614b82face1SPeter Wemm 	default:
2615b82face1SPeter Wemm 	    delaying = 0;
2616b82face1SPeter Wemm 	    break;
2617b82face1SPeter Wemm 	}
261815589c42SPeter Wemm 	a++;
261915589c42SPeter Wemm 	b++;
262015589c42SPeter Wemm     }
26214a1a9510SRong-En Fan     /* ignore delays on the end of the string */
26224a1a9510SRong-En Fan     a = ignore_delays(a);
26234a1a9510SRong-En Fan     return ((num != 0) || (*a == 0));
262415589c42SPeter Wemm }
262515589c42SPeter Wemm 
26267a656419SBaptiste Daroussin static void
check_tparm_err(int num)26277a656419SBaptiste Daroussin check_tparm_err(int num)
26287a656419SBaptiste Daroussin {
26297a656419SBaptiste Daroussin     if (_nc_tparm_err)
26307a656419SBaptiste Daroussin 	_nc_warning("tparam error in sgr(%d): %s", num, sgr_names[num]);
26317a656419SBaptiste Daroussin }
26327a656419SBaptiste Daroussin 
26334a1a9510SRong-En Fan static char *
check_sgr(TERMTYPE2 * tp,char * zero,int num,char * cap,const char * name)2634aae38d10SBaptiste Daroussin check_sgr(TERMTYPE2 *tp, char *zero, int num, char *cap, const char *name)
263515589c42SPeter Wemm {
26364a1a9510SRong-En Fan     char *test;
26374a1a9510SRong-En Fan 
26384a1a9510SRong-En Fan     _nc_tparm_err = 0;
26397a656419SBaptiste Daroussin     test = TIPARM_9(set_attributes,
264015589c42SPeter Wemm 		    num == 1,
264115589c42SPeter Wemm 		    num == 2,
264215589c42SPeter Wemm 		    num == 3,
264315589c42SPeter Wemm 		    num == 4,
264415589c42SPeter Wemm 		    num == 5,
264515589c42SPeter Wemm 		    num == 6,
264615589c42SPeter Wemm 		    num == 7,
264715589c42SPeter Wemm 		    num == 8,
264815589c42SPeter Wemm 		    num == 9);
264915589c42SPeter Wemm     if (test != 0) {
265015589c42SPeter Wemm 	if (PRESENT(cap)) {
2651b82face1SPeter Wemm 	    if (!similar_sgr(num, test, cap)) {
2652b82face1SPeter Wemm 		_nc_warning("%s differs from sgr(%d)\n\t%s=%s\n\tsgr(%d)=%s",
2653b82face1SPeter Wemm 			    name, num,
2654b82face1SPeter Wemm 			    name, _nc_visbuf2(1, cap),
2655b82face1SPeter Wemm 			    num, _nc_visbuf2(2, test));
265615589c42SPeter Wemm 	    }
26574a1a9510SRong-En Fan 	} else if (_nc_capcmp(test, zero)) {
265815589c42SPeter Wemm 	    _nc_warning("sgr(%d) present, but not %s", num, name);
265915589c42SPeter Wemm 	}
266015589c42SPeter Wemm     } else if (PRESENT(cap)) {
266115589c42SPeter Wemm 	_nc_warning("sgr(%d) missing, but %s present", num, name);
266215589c42SPeter Wemm     }
26637a656419SBaptiste Daroussin     check_tparm_err(num);
26644a1a9510SRong-En Fan     return test;
266515589c42SPeter Wemm }
266615589c42SPeter Wemm 
266715589c42SPeter Wemm #define CHECK_SGR(num,name) check_sgr(tp, zero, num, name, #name)
266815589c42SPeter Wemm 
26694a1a9510SRong-En Fan #ifdef TRACE
26704a1a9510SRong-En Fan /*
26714a1a9510SRong-En Fan  * If tic is compiled with TRACE, we'll be able to see the output from the
26724a1a9510SRong-En Fan  * DEBUG() macro.  But since it doesn't use traceon(), it always goes to
26734a1a9510SRong-En Fan  * the standard error.  Use this function to make it simpler to follow the
26744a1a9510SRong-En Fan  * resulting debug traces.
26754a1a9510SRong-En Fan  */
26764a1a9510SRong-En Fan static void
show_where(unsigned level)26774a1a9510SRong-En Fan show_where(unsigned level)
26784a1a9510SRong-En Fan {
26794a1a9510SRong-En Fan     if (_nc_tracing >= DEBUG_LEVEL(level)) {
268073f0a83dSXin LI 	char my_name[MAX_NAME_SIZE];
26814a1a9510SRong-En Fan 	_nc_get_type(my_name);
268206bfebdeSXin LI 	_tracef("\"%s\", line %d, '%s'",
26834a1a9510SRong-En Fan 		_nc_get_source(),
26844a1a9510SRong-En Fan 		_nc_curr_line, my_name);
26854a1a9510SRong-En Fan     }
26864a1a9510SRong-En Fan }
26874a1a9510SRong-En Fan 
26884a1a9510SRong-En Fan #else
26894a1a9510SRong-En Fan #define show_where(level)	/* nothing */
26904a1a9510SRong-En Fan #endif
26914a1a9510SRong-En Fan 
269273f0a83dSXin LI typedef struct {
269373f0a83dSXin LI     int keycode;
269473f0a83dSXin LI     const char *name;
269573f0a83dSXin LI     const char *value;
269673f0a83dSXin LI } NAME_VALUE;
269773f0a83dSXin LI 
269873f0a83dSXin LI static NAME_VALUE *
get_fkey_list(TERMTYPE2 * tp)2699aae38d10SBaptiste Daroussin get_fkey_list(TERMTYPE2 *tp)
270073f0a83dSXin LI {
270173f0a83dSXin LI     NAME_VALUE *result = typeMalloc(NAME_VALUE, NUM_STRINGS(tp) + 1);
270273f0a83dSXin LI     const struct tinfo_fkeys *all_fkeys = _nc_tinfo_fkeys;
270373f0a83dSXin LI     int used = 0;
2704aae38d10SBaptiste Daroussin     unsigned j;
270573f0a83dSXin LI 
2706*21817992SBaptiste Daroussin     if (result == NULL)
270773f0a83dSXin LI 	failed("get_fkey_list");
270873f0a83dSXin LI 
270973f0a83dSXin LI     for (j = 0; all_fkeys[j].code; j++) {
271073f0a83dSXin LI 	char *a = tp->Strings[all_fkeys[j].offset];
271173f0a83dSXin LI 	if (VALID_STRING(a)) {
271273f0a83dSXin LI 	    result[used].keycode = (int) all_fkeys[j].code;
271373f0a83dSXin LI 	    result[used].name = strnames[all_fkeys[j].offset];
271473f0a83dSXin LI 	    result[used].value = a;
271573f0a83dSXin LI 	    ++used;
271673f0a83dSXin LI 	}
271773f0a83dSXin LI     }
271873f0a83dSXin LI #if NCURSES_XNAMES
271973f0a83dSXin LI     for (j = STRCOUNT; j < NUM_STRINGS(tp); ++j) {
2720aae38d10SBaptiste Daroussin 	const char *name = ExtStrname(tp, (int) j, strnames);
272173f0a83dSXin LI 	if (*name == 'k') {
272273f0a83dSXin LI 	    result[used].keycode = -1;
272373f0a83dSXin LI 	    result[used].name = name;
272473f0a83dSXin LI 	    result[used].value = tp->Strings[j];
272573f0a83dSXin LI 	    ++used;
272673f0a83dSXin LI 	}
272773f0a83dSXin LI     }
272873f0a83dSXin LI #endif
272973f0a83dSXin LI     result[used].keycode = 0;
273073f0a83dSXin LI     return result;
273173f0a83dSXin LI }
273273f0a83dSXin LI 
273373f0a83dSXin LI static void
show_fkey_name(NAME_VALUE * data)273473f0a83dSXin LI show_fkey_name(NAME_VALUE * data)
273573f0a83dSXin LI {
273673f0a83dSXin LI     if (data->keycode > 0) {
273773f0a83dSXin LI 	fprintf(stderr, " %s", keyname(data->keycode));
273873f0a83dSXin LI 	fprintf(stderr, " (capability \"%s\")", data->name);
273973f0a83dSXin LI     } else {
274073f0a83dSXin LI 	fprintf(stderr, " capability \"%s\"", data->name);
274173f0a83dSXin LI     }
274273f0a83dSXin LI }
274373f0a83dSXin LI 
2744aae38d10SBaptiste Daroussin /*
2745aae38d10SBaptiste Daroussin  * A terminal entry may contain more than one keycode assigned to a given
2746aae38d10SBaptiste Daroussin  * string (e.g., KEY_END and KEY_LL).  But curses will only return one (the
2747aae38d10SBaptiste Daroussin  * last one assigned).
27480e3d5408SPeter Wemm  */
274915589c42SPeter Wemm static void
check_conflict(TERMTYPE2 * tp)2750aae38d10SBaptiste Daroussin check_conflict(TERMTYPE2 *tp)
27510e3d5408SPeter Wemm {
27524a1a9510SRong-En Fan     if (!(_nc_syntax == SYN_TERMCAP && capdump)) {
275373f0a83dSXin LI 	char *check = calloc((size_t) (NUM_STRINGS(tp) + 1), sizeof(char));
275473f0a83dSXin LI 	NAME_VALUE *given = get_fkey_list(tp);
2755*21817992SBaptiste Daroussin 	unsigned j, k;
2756*21817992SBaptiste Daroussin 	bool conflict = FALSE;
275773f0a83dSXin LI 
2758*21817992SBaptiste Daroussin 	if (check == NULL)
2759aae38d10SBaptiste Daroussin 	    failed("check_conflict");
276073f0a83dSXin LI 
276173f0a83dSXin LI 	for (j = 0; given[j].keycode; ++j) {
276273f0a83dSXin LI 	    const char *a = given[j].value;
27630e3d5408SPeter Wemm 	    bool first = TRUE;
276473f0a83dSXin LI 
2765aae38d10SBaptiste Daroussin 	    if (!VALID_STRING(a))
2766aae38d10SBaptiste Daroussin 		continue;
2767aae38d10SBaptiste Daroussin 
276873f0a83dSXin LI 	    for (k = j + 1; given[k].keycode; k++) {
276973f0a83dSXin LI 		const char *b = given[k].value;
2770aae38d10SBaptiste Daroussin 
2771aae38d10SBaptiste Daroussin 		if (!VALID_STRING(b))
2772aae38d10SBaptiste Daroussin 		    continue;
277373f0a83dSXin LI 		if (check[k])
27740e3d5408SPeter Wemm 		    continue;
2775aae38d10SBaptiste Daroussin 
27764a1a9510SRong-En Fan 		if (!_nc_capcmp(a, b)) {
277773f0a83dSXin LI 		    check[j] = 1;
277873f0a83dSXin LI 		    check[k] = 1;
27790e3d5408SPeter Wemm 		    if (first) {
27800e3d5408SPeter Wemm 			if (!conflict) {
2781aae38d10SBaptiste Daroussin 			    _nc_warning("conflicting key definitions (using the last)");
27820e3d5408SPeter Wemm 			    conflict = TRUE;
27830e3d5408SPeter Wemm 			}
278473f0a83dSXin LI 			fprintf(stderr, "...");
278573f0a83dSXin LI 			show_fkey_name(given + j);
278673f0a83dSXin LI 			fprintf(stderr, " is the same as");
278773f0a83dSXin LI 			show_fkey_name(given + k);
27880e3d5408SPeter Wemm 			first = FALSE;
27890e3d5408SPeter Wemm 		    } else {
279073f0a83dSXin LI 			fprintf(stderr, ", ");
279173f0a83dSXin LI 			show_fkey_name(given + k);
27920e3d5408SPeter Wemm 		    }
27930e3d5408SPeter Wemm 		}
27940e3d5408SPeter Wemm 	    }
27950e3d5408SPeter Wemm 	    if (!first)
27960e3d5408SPeter Wemm 		fprintf(stderr, "\n");
27970e3d5408SPeter Wemm 	}
2798aae38d10SBaptiste Daroussin #if NCURSES_XNAMES
2799aae38d10SBaptiste Daroussin 	if (using_extensions) {
2800aae38d10SBaptiste Daroussin 	    /* *INDENT-OFF* */
2801aae38d10SBaptiste Daroussin 	    static struct {
2802aae38d10SBaptiste Daroussin 		const char *xcurses;
2803aae38d10SBaptiste Daroussin 		const char *shifted;
2804aae38d10SBaptiste Daroussin 	    } table[] = {
2805aae38d10SBaptiste Daroussin 		{ "kDC",  NULL },
2806aae38d10SBaptiste Daroussin 		{ "kDN",  "kind" },
2807aae38d10SBaptiste Daroussin 		{ "kEND", NULL },
2808aae38d10SBaptiste Daroussin 		{ "kHOM", NULL },
2809aae38d10SBaptiste Daroussin 		{ "kLFT", NULL },
2810aae38d10SBaptiste Daroussin 		{ "kNXT", NULL },
2811aae38d10SBaptiste Daroussin 		{ "kPRV", NULL },
2812aae38d10SBaptiste Daroussin 		{ "kRIT", NULL },
2813aae38d10SBaptiste Daroussin 		{ "kUP",  "kri" },
2814aae38d10SBaptiste Daroussin 		{ NULL,   NULL },
2815aae38d10SBaptiste Daroussin 	    };
2816aae38d10SBaptiste Daroussin 	    /* *INDENT-ON* */
2817aae38d10SBaptiste Daroussin 	    /*
2818aae38d10SBaptiste Daroussin 	     * SVr4 curses defines the "xcurses" names listed above except for
2819aae38d10SBaptiste Daroussin 	     * the special cases in the "shifted" column.  When using these
2820aae38d10SBaptiste Daroussin 	     * names for xterm's extensions, that was confusing, and resulted
2821aae38d10SBaptiste Daroussin 	     * in adding extended capabilities with "2" (shift) suffix.  This
2822aae38d10SBaptiste Daroussin 	     * check warns about unnecessary use of extensions for this quirk.
2823aae38d10SBaptiste Daroussin 	     */
2824aae38d10SBaptiste Daroussin 	    for (j = 0; given[j].keycode; ++j) {
2825aae38d10SBaptiste Daroussin 		const char *find = given[j].name;
2826aae38d10SBaptiste Daroussin 		int value;
2827aae38d10SBaptiste Daroussin 		char ch;
2828aae38d10SBaptiste Daroussin 
2829aae38d10SBaptiste Daroussin 		if (!VALID_STRING(given[j].value))
2830aae38d10SBaptiste Daroussin 		    continue;
2831aae38d10SBaptiste Daroussin 
2832aae38d10SBaptiste Daroussin 		for (k = 0; table[k].xcurses; ++k) {
2833aae38d10SBaptiste Daroussin 		    const char *test = table[k].xcurses;
2834aae38d10SBaptiste Daroussin 		    size_t size = strlen(test);
2835aae38d10SBaptiste Daroussin 
2836aae38d10SBaptiste Daroussin 		    if (!strncmp(find, test, size) && strcmp(find, test)) {
2837aae38d10SBaptiste Daroussin 			switch (sscanf(find + size, "%d%c", &value, &ch)) {
2838aae38d10SBaptiste Daroussin 			case 1:
2839aae38d10SBaptiste Daroussin 			    if (value == 2) {
2840aae38d10SBaptiste Daroussin 				_nc_warning("expected '%s' rather than '%s'",
2841aae38d10SBaptiste Daroussin 					    (table[k].shifted
2842aae38d10SBaptiste Daroussin 					     ? table[k].shifted
2843aae38d10SBaptiste Daroussin 					     : test), find);
2844aae38d10SBaptiste Daroussin 			    } else if (value < 2 || value > 15) {
2845aae38d10SBaptiste Daroussin 				_nc_warning("expected numeric 2..15 '%s'", find);
2846aae38d10SBaptiste Daroussin 			    }
2847aae38d10SBaptiste Daroussin 			    break;
2848aae38d10SBaptiste Daroussin 			default:
2849aae38d10SBaptiste Daroussin 			    _nc_warning("expected numeric suffix for '%s'", find);
2850aae38d10SBaptiste Daroussin 			    break;
2851aae38d10SBaptiste Daroussin 			}
2852aae38d10SBaptiste Daroussin 			break;
2853aae38d10SBaptiste Daroussin 		    }
2854aae38d10SBaptiste Daroussin 		}
2855aae38d10SBaptiste Daroussin 	    }
2856aae38d10SBaptiste Daroussin 	}
2857aae38d10SBaptiste Daroussin #endif
285873f0a83dSXin LI 	free(given);
285973f0a83dSXin LI 	free(check);
28604a1a9510SRong-En Fan     }
2861aae38d10SBaptiste Daroussin }
2862aae38d10SBaptiste Daroussin 
2863aae38d10SBaptiste Daroussin /*
2864aae38d10SBaptiste Daroussin  * Exiting a video mode should not duplicate sgr0
2865aae38d10SBaptiste Daroussin  */
2866aae38d10SBaptiste Daroussin static void
check_exit_attribute(const char * name,char * test,char * trimmed,char * untrimmed)2867aae38d10SBaptiste Daroussin check_exit_attribute(const char *name, char *test, char *trimmed, char *untrimmed)
2868aae38d10SBaptiste Daroussin {
2869aae38d10SBaptiste Daroussin     if (VALID_STRING(test) && (trimmed != 0)) {
2870aae38d10SBaptiste Daroussin 	if (similar_sgr(-1, trimmed, test) ||
2871aae38d10SBaptiste Daroussin 	    similar_sgr(-1, untrimmed, test)) {
2872aae38d10SBaptiste Daroussin 	    _nc_warning("%s matches exit_attribute_mode", name);
2873aae38d10SBaptiste Daroussin 	}
2874aae38d10SBaptiste Daroussin     }
2875aae38d10SBaptiste Daroussin }
2876aae38d10SBaptiste Daroussin 
2877aae38d10SBaptiste Daroussin /*
2878aae38d10SBaptiste Daroussin  * Returns true if the string looks like a standard SGR string.
2879aae38d10SBaptiste Daroussin  */
2880aae38d10SBaptiste Daroussin static bool
is_sgr_string(char * value)2881aae38d10SBaptiste Daroussin is_sgr_string(char *value)
2882aae38d10SBaptiste Daroussin {
2883aae38d10SBaptiste Daroussin     bool result = FALSE;
2884aae38d10SBaptiste Daroussin 
2885aae38d10SBaptiste Daroussin     if (VALID_STRING(value)) {
2886aae38d10SBaptiste Daroussin 	int skip = csi_length(value);
2887aae38d10SBaptiste Daroussin 
2888aae38d10SBaptiste Daroussin 	if (skip) {
2889aae38d10SBaptiste Daroussin 	    int ch;
2890aae38d10SBaptiste Daroussin 
2891aae38d10SBaptiste Daroussin 	    result = TRUE;
2892aae38d10SBaptiste Daroussin 	    value += skip;
2893aae38d10SBaptiste Daroussin 	    while ((ch = UChar(*value++)) != '\0') {
2894aae38d10SBaptiste Daroussin 		if (isdigit(ch) || ch == ';') {
2895aae38d10SBaptiste Daroussin 		    ;
2896aae38d10SBaptiste Daroussin 		} else if (ch == 'm' && *value == '\0') {
2897aae38d10SBaptiste Daroussin 		    ;
2898aae38d10SBaptiste Daroussin 		} else {
2899aae38d10SBaptiste Daroussin 		    result = FALSE;
2900aae38d10SBaptiste Daroussin 		    break;
2901aae38d10SBaptiste Daroussin 		}
2902aae38d10SBaptiste Daroussin 	    }
2903aae38d10SBaptiste Daroussin 	}
2904aae38d10SBaptiste Daroussin     }
2905aae38d10SBaptiste Daroussin     return result;
2906aae38d10SBaptiste Daroussin }
2907aae38d10SBaptiste Daroussin 
2908aae38d10SBaptiste Daroussin /*
2909aae38d10SBaptiste Daroussin  * Check if the given capability contains a given SGR attribute.
2910aae38d10SBaptiste Daroussin  */
2911aae38d10SBaptiste Daroussin static void
check_sgr_param(TERMTYPE2 * tp,int code,const char * name,char * value)2912aae38d10SBaptiste Daroussin check_sgr_param(TERMTYPE2 *tp, int code, const char *name, char *value)
2913aae38d10SBaptiste Daroussin {
2914aae38d10SBaptiste Daroussin     if (VALID_STRING(value)) {
2915aae38d10SBaptiste Daroussin 	int ncv = ((code != 0) ? (1 << (code - 1)) : 0);
2916aae38d10SBaptiste Daroussin 	char *test = tgoto(value, 0, 0);
2917aae38d10SBaptiste Daroussin 	if (is_sgr_string(test)) {
2918aae38d10SBaptiste Daroussin 	    int param = 0;
2919aae38d10SBaptiste Daroussin 	    int count = 0;
2920aae38d10SBaptiste Daroussin 	    int skips = 0;
2921aae38d10SBaptiste Daroussin 	    int color = (value == set_a_foreground ||
2922aae38d10SBaptiste Daroussin 			 value == set_a_background ||
2923aae38d10SBaptiste Daroussin 			 value == set_foreground ||
2924aae38d10SBaptiste Daroussin 			 value == set_background);
2925aae38d10SBaptiste Daroussin 	    while (*test != 0) {
2926aae38d10SBaptiste Daroussin 		if (isdigit(UChar(*test))) {
2927aae38d10SBaptiste Daroussin 		    param = 10 * param + (*test - '0');
2928aae38d10SBaptiste Daroussin 		    ++count;
2929aae38d10SBaptiste Daroussin 		} else {
2930aae38d10SBaptiste Daroussin 		    if (count) {
2931aae38d10SBaptiste Daroussin 			/*
2932aae38d10SBaptiste Daroussin 			 * Avoid unnecessary warning for xterm 256color codes.
2933aae38d10SBaptiste Daroussin 			 */
2934aae38d10SBaptiste Daroussin 			if (color && (param == 38 || param == 48))
2935aae38d10SBaptiste Daroussin 			    skips = 3;
2936aae38d10SBaptiste Daroussin 			if ((skips-- <= 0) && (param == code))
2937aae38d10SBaptiste Daroussin 			    break;
2938aae38d10SBaptiste Daroussin 		    }
2939aae38d10SBaptiste Daroussin 		    count = 0;
2940aae38d10SBaptiste Daroussin 		    param = 0;
2941aae38d10SBaptiste Daroussin 		}
2942aae38d10SBaptiste Daroussin 		++test;
2943aae38d10SBaptiste Daroussin 	    }
2944aae38d10SBaptiste Daroussin 	    if (count != 0 && param == code) {
2945aae38d10SBaptiste Daroussin 		if (code == 0 ||
2946aae38d10SBaptiste Daroussin 		    no_color_video < 0 ||
2947aae38d10SBaptiste Daroussin 		    !(no_color_video & ncv)) {
2948aae38d10SBaptiste Daroussin 		    _nc_warning("\"%s\" SGR-attribute used in %s",
2949aae38d10SBaptiste Daroussin 				sgr_names[code],
2950aae38d10SBaptiste Daroussin 				name);
2951aae38d10SBaptiste Daroussin 		}
2952aae38d10SBaptiste Daroussin 	    }
2953aae38d10SBaptiste Daroussin 	}
2954aae38d10SBaptiste Daroussin     }
2955aae38d10SBaptiste Daroussin }
2956aae38d10SBaptiste Daroussin 
2957aae38d10SBaptiste Daroussin #if NCURSES_XNAMES
2958aae38d10SBaptiste Daroussin static int
standard_type(const char * name)2959aae38d10SBaptiste Daroussin standard_type(const char *name)
2960aae38d10SBaptiste Daroussin {
2961aae38d10SBaptiste Daroussin     int result = -1;
2962aae38d10SBaptiste Daroussin     const struct name_table_entry *np;
2963aae38d10SBaptiste Daroussin 
2964aae38d10SBaptiste Daroussin     if ((np = _nc_find_entry(name, _nc_get_hash_table(0))) != 0) {
2965aae38d10SBaptiste Daroussin 	result = np->nte_type;
2966aae38d10SBaptiste Daroussin     }
2967aae38d10SBaptiste Daroussin     return result;
2968aae38d10SBaptiste Daroussin }
2969aae38d10SBaptiste Daroussin 
2970aae38d10SBaptiste Daroussin static const char *
name_of_type(int type)2971aae38d10SBaptiste Daroussin name_of_type(int type)
2972aae38d10SBaptiste Daroussin {
2973aae38d10SBaptiste Daroussin     const char *result = "unknown";
2974aae38d10SBaptiste Daroussin     switch (type) {
2975aae38d10SBaptiste Daroussin     case BOOLEAN:
2976aae38d10SBaptiste Daroussin 	result = "boolean";
2977aae38d10SBaptiste Daroussin 	break;
2978aae38d10SBaptiste Daroussin     case NUMBER:
2979aae38d10SBaptiste Daroussin 	result = "number";
2980aae38d10SBaptiste Daroussin 	break;
2981aae38d10SBaptiste Daroussin     case STRING:
2982aae38d10SBaptiste Daroussin 	result = "string";
2983aae38d10SBaptiste Daroussin 	break;
2984aae38d10SBaptiste Daroussin     }
2985aae38d10SBaptiste Daroussin     return result;
2986aae38d10SBaptiste Daroussin }
2987aae38d10SBaptiste Daroussin 
2988aae38d10SBaptiste Daroussin static void
check_user_capability_type(const char * name,int actual)2989aae38d10SBaptiste Daroussin check_user_capability_type(const char *name, int actual)
2990aae38d10SBaptiste Daroussin {
2991aae38d10SBaptiste Daroussin     if (lookup_user_capability(name) == 0) {
2992aae38d10SBaptiste Daroussin 	int expected = standard_type(name);
2993aae38d10SBaptiste Daroussin 	if (expected >= 0) {
2994aae38d10SBaptiste Daroussin 	    _nc_warning("expected %s to be %s, but actually %s",
2995aae38d10SBaptiste Daroussin 			name,
2996aae38d10SBaptiste Daroussin 			name_of_type(actual),
2997aae38d10SBaptiste Daroussin 			name_of_type(expected)
2998aae38d10SBaptiste Daroussin 		);
2999aae38d10SBaptiste Daroussin 	} else if (*name != 'k') {
3000aae38d10SBaptiste Daroussin 	    _nc_warning("undocumented %s capability %s",
3001aae38d10SBaptiste Daroussin 			name_of_type(actual),
3002aae38d10SBaptiste Daroussin 			name);
3003aae38d10SBaptiste Daroussin 	}
3004aae38d10SBaptiste Daroussin     }
3005aae38d10SBaptiste Daroussin }
3006aae38d10SBaptiste Daroussin #endif
3007aae38d10SBaptiste Daroussin 
3008*21817992SBaptiste Daroussin #define IN_DELAY "0123456789*/."
3009*21817992SBaptiste Daroussin 
3010*21817992SBaptiste Daroussin static bool
check_ANSI_cap(const char * value,int nparams,char final)3011*21817992SBaptiste Daroussin check_ANSI_cap(const char *value, int nparams, char final)
3012*21817992SBaptiste Daroussin {
3013*21817992SBaptiste Daroussin     bool result = FALSE;
3014*21817992SBaptiste Daroussin     if (VALID_STRING(value) && csi_length(value) > 0) {
3015*21817992SBaptiste Daroussin 	char *p_is_s[NUM_PARM];
3016*21817992SBaptiste Daroussin 	int popcount;
3017*21817992SBaptiste Daroussin 	int analyzed = _nc_tparm_analyze(NULL, value, p_is_s, &popcount);
3018*21817992SBaptiste Daroussin 	if (analyzed < popcount) {
3019*21817992SBaptiste Daroussin 	    analyzed = popcount;
3020*21817992SBaptiste Daroussin 	}
3021*21817992SBaptiste Daroussin 	if (analyzed == nparams) {
3022*21817992SBaptiste Daroussin 	    bool numbers = TRUE;
3023*21817992SBaptiste Daroussin 	    int p;
3024*21817992SBaptiste Daroussin 	    for (p = 0; p < nparams; ++p) {
3025*21817992SBaptiste Daroussin 		if (p_is_s[p]) {
3026*21817992SBaptiste Daroussin 		    numbers = FALSE;
3027*21817992SBaptiste Daroussin 		    break;
3028*21817992SBaptiste Daroussin 		}
3029*21817992SBaptiste Daroussin 	    }
3030*21817992SBaptiste Daroussin 	    if (numbers) {
3031*21817992SBaptiste Daroussin 		int in_delay = 0;
3032*21817992SBaptiste Daroussin 		p = (int) strlen(value);
3033*21817992SBaptiste Daroussin 		while (p-- > 0) {
3034*21817992SBaptiste Daroussin 		    char ch = value[p];
3035*21817992SBaptiste Daroussin 		    if (ch == final) {
3036*21817992SBaptiste Daroussin 			result = TRUE;
3037*21817992SBaptiste Daroussin 			break;
3038*21817992SBaptiste Daroussin 		    }
3039*21817992SBaptiste Daroussin 		    switch (in_delay) {
3040*21817992SBaptiste Daroussin 		    case 0:
3041*21817992SBaptiste Daroussin 			if (ch == '>')
3042*21817992SBaptiste Daroussin 			    in_delay = 1;
3043*21817992SBaptiste Daroussin 			break;
3044*21817992SBaptiste Daroussin 		    case 1:
3045*21817992SBaptiste Daroussin 			if (strchr(IN_DELAY, value[p]) != NULL)
3046*21817992SBaptiste Daroussin 			    break;
3047*21817992SBaptiste Daroussin 			if (ch != '<')
3048*21817992SBaptiste Daroussin 			    p = 0;
3049*21817992SBaptiste Daroussin 			in_delay = 2;
3050*21817992SBaptiste Daroussin 			break;
3051*21817992SBaptiste Daroussin 		    case 2:
3052*21817992SBaptiste Daroussin 			if (ch != '$')
3053*21817992SBaptiste Daroussin 			    p = 0;
3054*21817992SBaptiste Daroussin 			in_delay = 0;
3055*21817992SBaptiste Daroussin 			break;
3056*21817992SBaptiste Daroussin 		    }
3057*21817992SBaptiste Daroussin 		}
3058*21817992SBaptiste Daroussin 	    }
3059*21817992SBaptiste Daroussin 	}
3060*21817992SBaptiste Daroussin     }
3061*21817992SBaptiste Daroussin     return result;
3062*21817992SBaptiste Daroussin }
3063*21817992SBaptiste Daroussin 
3064*21817992SBaptiste Daroussin static const char *
skip_Delay(const char * value)3065*21817992SBaptiste Daroussin skip_Delay(const char *value)
3066*21817992SBaptiste Daroussin {
3067*21817992SBaptiste Daroussin     const char *result = value;
3068*21817992SBaptiste Daroussin 
3069*21817992SBaptiste Daroussin     if (*value == '$') {
3070*21817992SBaptiste Daroussin 	++result;
3071*21817992SBaptiste Daroussin 	if (*result++ == '<') {
3072*21817992SBaptiste Daroussin 	    while (strchr(IN_DELAY, *result) != NULL)
3073*21817992SBaptiste Daroussin 		++result;
3074*21817992SBaptiste Daroussin 	    if (*result++ != '>') {
3075*21817992SBaptiste Daroussin 		result = value;
3076*21817992SBaptiste Daroussin 	    }
3077*21817992SBaptiste Daroussin 	} else {
3078*21817992SBaptiste Daroussin 	    result = value;
3079*21817992SBaptiste Daroussin 	}
3080*21817992SBaptiste Daroussin     }
3081*21817992SBaptiste Daroussin     return result;
3082*21817992SBaptiste Daroussin }
3083*21817992SBaptiste Daroussin 
3084*21817992SBaptiste Daroussin static bool
isValidString(const char * value,const char * expect)3085*21817992SBaptiste Daroussin isValidString(const char *value, const char *expect)
3086*21817992SBaptiste Daroussin {
3087*21817992SBaptiste Daroussin     bool result = FALSE;
3088*21817992SBaptiste Daroussin     if (VALID_STRING(value)) {
3089*21817992SBaptiste Daroussin 	if (!strcmp(value, expect))
3090*21817992SBaptiste Daroussin 	    result = TRUE;
3091*21817992SBaptiste Daroussin     }
3092*21817992SBaptiste Daroussin     return result;
3093*21817992SBaptiste Daroussin }
3094*21817992SBaptiste Daroussin 
3095*21817992SBaptiste Daroussin static bool
isValidEscape(const char * value,const char * expect)3096*21817992SBaptiste Daroussin isValidEscape(const char *value, const char *expect)
3097*21817992SBaptiste Daroussin {
3098*21817992SBaptiste Daroussin     bool result = FALSE;
3099*21817992SBaptiste Daroussin     if (VALID_STRING(value)) {
3100*21817992SBaptiste Daroussin 	if (*value == '\033') {
3101*21817992SBaptiste Daroussin 	    size_t need = strlen(expect);
3102*21817992SBaptiste Daroussin 	    size_t have = strlen(value) - 1;
3103*21817992SBaptiste Daroussin 	    if (have >= need && !strncmp(value + 1, expect, need)) {
3104*21817992SBaptiste Daroussin 		if (*skip_Delay(value + need + 1) == '\0') {
3105*21817992SBaptiste Daroussin 		    result = TRUE;
3106*21817992SBaptiste Daroussin 		}
3107*21817992SBaptiste Daroussin 	    }
3108*21817992SBaptiste Daroussin 	}
3109*21817992SBaptiste Daroussin     }
3110*21817992SBaptiste Daroussin     return result;
3111*21817992SBaptiste Daroussin }
3112*21817992SBaptiste Daroussin 
3113*21817992SBaptiste Daroussin static int
guess_ANSI_VTxx(TERMTYPE2 * tp)3114*21817992SBaptiste Daroussin guess_ANSI_VTxx(TERMTYPE2 *tp)
3115*21817992SBaptiste Daroussin {
3116*21817992SBaptiste Daroussin     int result = -1;
3117*21817992SBaptiste Daroussin     int checks = 0;
3118*21817992SBaptiste Daroussin 
3119*21817992SBaptiste Daroussin     /* VT100s have scrolling region, but ANSI (ECMA-48) does not specify */
3120*21817992SBaptiste Daroussin     if (check_ANSI_cap(change_scroll_region, 2, 'r') &&
3121*21817992SBaptiste Daroussin 	(isValidEscape(scroll_forward, "D") ||
3122*21817992SBaptiste Daroussin 	 isValidString(scroll_forward, "\n") ||
3123*21817992SBaptiste Daroussin 	 isValidEscape(scroll_forward, "6")) &&
3124*21817992SBaptiste Daroussin 	(isValidEscape(scroll_reverse, "M") ||
3125*21817992SBaptiste Daroussin 	 isValidEscape(scroll_reverse, "9"))) {
3126*21817992SBaptiste Daroussin 	checks |= 2;
3127*21817992SBaptiste Daroussin     }
3128*21817992SBaptiste Daroussin     if (check_ANSI_cap(cursor_address, 2, 'H') &&
3129*21817992SBaptiste Daroussin 	check_ANSI_cap(cursor_up, 0, 'A') &&
3130*21817992SBaptiste Daroussin 	(check_ANSI_cap(cursor_down, 0, 'B') ||
3131*21817992SBaptiste Daroussin 	 isValidString(cursor_down, "\n")) &&
3132*21817992SBaptiste Daroussin 	check_ANSI_cap(cursor_right, 0, 'C') &&
3133*21817992SBaptiste Daroussin 	(check_ANSI_cap(cursor_left, 0, 'D') ||
3134*21817992SBaptiste Daroussin 	 isValidString(cursor_left, "\b")) &&
3135*21817992SBaptiste Daroussin 	check_ANSI_cap(clr_eos, 0, 'J') &&
3136*21817992SBaptiste Daroussin 	check_ANSI_cap(clr_bol, 0, 'K') &&
3137*21817992SBaptiste Daroussin 	check_ANSI_cap(clr_eol, 0, 'K')) {
3138*21817992SBaptiste Daroussin 	checks |= 1;
3139*21817992SBaptiste Daroussin     }
3140*21817992SBaptiste Daroussin     if (checks == 3)
3141*21817992SBaptiste Daroussin 	result = 1;
3142*21817992SBaptiste Daroussin     if (checks == 1)
3143*21817992SBaptiste Daroussin 	result = 0;
3144*21817992SBaptiste Daroussin     return result;
3145*21817992SBaptiste Daroussin }
3146*21817992SBaptiste Daroussin 
3147*21817992SBaptiste Daroussin /*
3148*21817992SBaptiste Daroussin  * u6/u7 and u8/u9 are query/response extensions which most terminals support.
3149*21817992SBaptiste Daroussin  * In particular, any ECMA-48 terminal should support these, though the details
3150*21817992SBaptiste Daroussin  * for u9 are implementation dependent.
3151*21817992SBaptiste Daroussin  */
3152*21817992SBaptiste Daroussin #if defined(user6) && defined(user7) && defined(user8) && defined(user9)
3153*21817992SBaptiste Daroussin static void
check_user_6789(TERMTYPE2 * tp)3154*21817992SBaptiste Daroussin check_user_6789(TERMTYPE2 *tp)
3155*21817992SBaptiste Daroussin {
3156*21817992SBaptiste Daroussin     /*
3157*21817992SBaptiste Daroussin      * Check if the terminal is known to not
3158*21817992SBaptiste Daroussin      */
3159*21817992SBaptiste Daroussin #define NO_QUERY(longname,shortname) \
3160*21817992SBaptiste Daroussin 	if (PRESENT(longname)) _nc_warning(#shortname " is not supported")
3161*21817992SBaptiste Daroussin     if (tigetflag("NQ") > 0) {
3162*21817992SBaptiste Daroussin 	NO_QUERY(user6, u6);
3163*21817992SBaptiste Daroussin 	NO_QUERY(user7, u7);
3164*21817992SBaptiste Daroussin 	NO_QUERY(user8, u8);
3165*21817992SBaptiste Daroussin 	NO_QUERY(user9, u9);
3166*21817992SBaptiste Daroussin 	return;
3167*21817992SBaptiste Daroussin     }
3168*21817992SBaptiste Daroussin 
3169*21817992SBaptiste Daroussin     PAIRED(user6, user7);
3170*21817992SBaptiste Daroussin     PAIRED(user8, user9);
3171*21817992SBaptiste Daroussin 
3172*21817992SBaptiste Daroussin     if (strchr(tp->term_names, '+') != NULL)
3173*21817992SBaptiste Daroussin 	return;
3174*21817992SBaptiste Daroussin 
3175*21817992SBaptiste Daroussin     switch (guess_ANSI_VTxx(tp)) {
3176*21817992SBaptiste Daroussin     case 1:
3177*21817992SBaptiste Daroussin 	if (!PRESENT(user8)) {
3178*21817992SBaptiste Daroussin 	    _nc_warning("expected u8/u9 for device-attributes");
3179*21817992SBaptiste Daroussin 	}
3180*21817992SBaptiste Daroussin 	/* FALLTHRU */
3181*21817992SBaptiste Daroussin     case 0:
3182*21817992SBaptiste Daroussin 	if (!PRESENT(user6)) {
3183*21817992SBaptiste Daroussin 	    _nc_warning("expected u6/u7 for cursor-position");
3184*21817992SBaptiste Daroussin 	}
3185*21817992SBaptiste Daroussin 	break;
3186*21817992SBaptiste Daroussin     }
3187*21817992SBaptiste Daroussin }
3188*21817992SBaptiste Daroussin #else
3189*21817992SBaptiste Daroussin #define check_user_6789(tp)	/* nothing */
3190*21817992SBaptiste Daroussin #endif
3191*21817992SBaptiste Daroussin 
3192aae38d10SBaptiste Daroussin /* other sanity-checks (things that we don't want in the normal
3193aae38d10SBaptiste Daroussin  * logic that reads a terminfo entry)
3194aae38d10SBaptiste Daroussin  */
3195aae38d10SBaptiste Daroussin static void
check_termtype(TERMTYPE2 * tp,bool literal)3196aae38d10SBaptiste Daroussin check_termtype(TERMTYPE2 *tp, bool literal)
3197aae38d10SBaptiste Daroussin {
3198aae38d10SBaptiste Daroussin     unsigned j;
3199aae38d10SBaptiste Daroussin 
3200aae38d10SBaptiste Daroussin     check_conflict(tp);
32010e3d5408SPeter Wemm 
320273f0a83dSXin LI     for_each_string(j, tp) {
320318259542SPeter Wemm 	char *a = tp->Strings[j];
3204aae38d10SBaptiste Daroussin 	if (VALID_STRING(a)) {
3205aae38d10SBaptiste Daroussin 	    const char *name = ExtStrname(tp, (int) j, strnames);
3206aae38d10SBaptiste Daroussin 	    /*
3207aae38d10SBaptiste Daroussin 	     * If we expect parameters, or if there might be parameters,
3208aae38d10SBaptiste Daroussin 	     * check for consistent number of parameters.
3209aae38d10SBaptiste Daroussin 	     */
3210aae38d10SBaptiste Daroussin 	    if (j >= SIZEOF(parametrized) ||
3211aae38d10SBaptiste Daroussin 		is_user_capability(name) >= 0 ||
3212aae38d10SBaptiste Daroussin 		parametrized[j] > 0) {
3213aae38d10SBaptiste Daroussin 		check_params(tp, name, a, (j >= STRCOUNT));
321418259542SPeter Wemm 	    }
3215aae38d10SBaptiste Daroussin 	    check_delays(tp, ExtStrname(tp, (int) j, strnames), a);
3216aae38d10SBaptiste Daroussin 	    if (capdump) {
3217aae38d10SBaptiste Daroussin 		check_infotocap(tp, (int) j, a);
3218aae38d10SBaptiste Daroussin 	    }
3219aae38d10SBaptiste Daroussin 	}
3220aae38d10SBaptiste Daroussin     }
3221aae38d10SBaptiste Daroussin #if NCURSES_XNAMES
3222aae38d10SBaptiste Daroussin     /* in extended mode, verify that each extension is expected type */
3223aae38d10SBaptiste Daroussin     for_each_ext_boolean(j, tp) {
3224aae38d10SBaptiste Daroussin 	check_user_capability_type(ExtBoolname(tp, (int) j, strnames), BOOLEAN);
3225aae38d10SBaptiste Daroussin     }
3226aae38d10SBaptiste Daroussin     for_each_ext_number(j, tp) {
3227aae38d10SBaptiste Daroussin 	check_user_capability_type(ExtNumname(tp, (int) j, strnames), NUMBER);
3228aae38d10SBaptiste Daroussin     }
3229aae38d10SBaptiste Daroussin     for_each_ext_string(j, tp) {
3230aae38d10SBaptiste Daroussin 	check_user_capability_type(ExtStrname(tp, (int) j, strnames), STRING);
3231aae38d10SBaptiste Daroussin     }
3232aae38d10SBaptiste Daroussin #endif /* NCURSES_XNAMES */
323318259542SPeter Wemm 
32344a1a9510SRong-En Fan     check_acs(tp);
32354a1a9510SRong-En Fan     check_colors(tp);
323606bfebdeSXin LI     check_cursor(tp);
32374a1a9510SRong-En Fan     check_keypad(tp);
323806bfebdeSXin LI     check_printer(tp);
323973f0a83dSXin LI     check_screen(tp);
3240*21817992SBaptiste Daroussin     check_user_6789(tp);
32410e3d5408SPeter Wemm 
32420e3d5408SPeter Wemm     /*
3243aae38d10SBaptiste Daroussin      * These are probably both or none.
3244aae38d10SBaptiste Daroussin      */
3245aae38d10SBaptiste Daroussin     PAIRED(parm_index, parm_rindex);
3246aae38d10SBaptiste Daroussin     PAIRED(parm_ich, parm_dch);
3247aae38d10SBaptiste Daroussin 
3248aae38d10SBaptiste Daroussin     /*
32490e3d5408SPeter Wemm      * These may be mismatched because the terminal description relies on
32500e3d5408SPeter Wemm      * restoring the cursor visibility by resetting it.
32510e3d5408SPeter Wemm      */
325215589c42SPeter Wemm     ANDMISSING(cursor_invisible, cursor_normal);
325315589c42SPeter Wemm     ANDMISSING(cursor_visible, cursor_normal);
325415589c42SPeter Wemm 
325515589c42SPeter Wemm     if (PRESENT(cursor_visible) && PRESENT(cursor_normal)
32564a1a9510SRong-En Fan 	&& !_nc_capcmp(cursor_visible, cursor_normal))
325715589c42SPeter Wemm 	_nc_warning("cursor_visible is same as cursor_normal");
32580e3d5408SPeter Wemm 
32590e3d5408SPeter Wemm     /*
32600e3d5408SPeter Wemm      * From XSI & O'Reilly, we gather that sc/rc are required if csr is
32610e3d5408SPeter Wemm      * given, because the cursor position after the scrolling operation is
32620e3d5408SPeter Wemm      * performed is undefined.
32630e3d5408SPeter Wemm      */
326415589c42SPeter Wemm     ANDMISSING(change_scroll_region, save_cursor);
326515589c42SPeter Wemm     ANDMISSING(change_scroll_region, restore_cursor);
326615589c42SPeter Wemm 
326706bfebdeSXin LI     /*
326806bfebdeSXin LI      * If we can clear tabs, we should be able to initialize them.
326906bfebdeSXin LI      */
327006bfebdeSXin LI     ANDMISSING(clear_all_tabs, set_tab);
327106bfebdeSXin LI 
327215589c42SPeter Wemm     if (PRESENT(set_attributes)) {
32734a1a9510SRong-En Fan 	char *zero = 0;
327415589c42SPeter Wemm 
32754a1a9510SRong-En Fan 	_nc_tparm_err = 0;
32764a1a9510SRong-En Fan 	if (PRESENT(exit_attribute_mode)) {
32774a1a9510SRong-En Fan 	    zero = strdup(CHECK_SGR(0, exit_attribute_mode));
32784a1a9510SRong-En Fan 	} else {
32797a656419SBaptiste Daroussin 	    zero = strdup(TIPARM_9(set_attributes, 0, 0, 0, 0, 0, 0, 0, 0, 0));
32804a1a9510SRong-En Fan 	}
32817a656419SBaptiste Daroussin 	check_tparm_err(0);
32824a1a9510SRong-En Fan 
32834a1a9510SRong-En Fan 	if (zero != 0) {
328415589c42SPeter Wemm 	    CHECK_SGR(1, enter_standout_mode);
328515589c42SPeter Wemm 	    CHECK_SGR(2, enter_underline_mode);
328615589c42SPeter Wemm 	    CHECK_SGR(3, enter_reverse_mode);
328715589c42SPeter Wemm 	    CHECK_SGR(4, enter_blink_mode);
328815589c42SPeter Wemm 	    CHECK_SGR(5, enter_dim_mode);
328915589c42SPeter Wemm 	    CHECK_SGR(6, enter_bold_mode);
329015589c42SPeter Wemm 	    CHECK_SGR(7, enter_secure_mode);
329115589c42SPeter Wemm 	    CHECK_SGR(8, enter_protected_mode);
329215589c42SPeter Wemm 	    CHECK_SGR(9, enter_alt_charset_mode);
329315589c42SPeter Wemm 	    free(zero);
32944a1a9510SRong-En Fan 	} else {
32954a1a9510SRong-En Fan 	    _nc_warning("sgr(0) did not return a value");
329615589c42SPeter Wemm 	}
32974a1a9510SRong-En Fan     } else if (PRESENT(exit_attribute_mode) &&
32984a1a9510SRong-En Fan 	       set_attributes != CANCELLED_STRING) {
32994a1a9510SRong-En Fan 	if (_nc_syntax == SYN_TERMINFO)
33004a1a9510SRong-En Fan 	    _nc_warning("missing sgr string");
33014a1a9510SRong-En Fan     }
3302aae38d10SBaptiste Daroussin #define CHECK_SGR0(name) check_exit_attribute(#name, name, check_sgr0, exit_attribute_mode)
33034a1a9510SRong-En Fan     if (PRESENT(exit_attribute_mode)) {
33044a1a9510SRong-En Fan 	char *check_sgr0 = _nc_trim_sgr0(tp);
33054a1a9510SRong-En Fan 
3306*21817992SBaptiste Daroussin 	if (check_sgr0 == NULL || *check_sgr0 == '\0') {
33074a1a9510SRong-En Fan 	    _nc_warning("trimmed sgr0 is empty");
33084a1a9510SRong-En Fan 	} else {
33094a1a9510SRong-En Fan 	    show_where(2);
33104a1a9510SRong-En Fan 	    if (check_sgr0 != exit_attribute_mode) {
33114a1a9510SRong-En Fan 		DEBUG(2,
33124a1a9510SRong-En Fan 		      ("will trim sgr0\n\toriginal sgr0=%s\n\ttrimmed  sgr0=%s",
33134a1a9510SRong-En Fan 		       _nc_visbuf2(1, exit_attribute_mode),
33144a1a9510SRong-En Fan 		       _nc_visbuf2(2, check_sgr0)));
33154a1a9510SRong-En Fan 	    } else {
33164a1a9510SRong-En Fan 		DEBUG(2,
33174a1a9510SRong-En Fan 		      ("will not trim sgr0\n\toriginal sgr0=%s",
33184a1a9510SRong-En Fan 		       _nc_visbuf(exit_attribute_mode)));
33194a1a9510SRong-En Fan 	    }
33204a1a9510SRong-En Fan 	}
3321aae38d10SBaptiste Daroussin #if defined(exit_italics_mode)
3322aae38d10SBaptiste Daroussin 	CHECK_SGR0(exit_italics_mode);
3323aae38d10SBaptiste Daroussin #endif
3324aae38d10SBaptiste Daroussin 	CHECK_SGR0(exit_standout_mode);
3325aae38d10SBaptiste Daroussin 	CHECK_SGR0(exit_underline_mode);
3326aae38d10SBaptiste Daroussin 	if (check_sgr0 != exit_attribute_mode) {
3327aae38d10SBaptiste Daroussin 	    free(check_sgr0);
3328aae38d10SBaptiste Daroussin 	}
3329aae38d10SBaptiste Daroussin     }
3330aae38d10SBaptiste Daroussin #define CHECK_SGR_PARAM(code, name) check_sgr_param(tp, (int)code, #name, name)
3331aae38d10SBaptiste Daroussin     for (j = 0; *sgr_names[j] != '\0'; ++j) {
3332aae38d10SBaptiste Daroussin 	CHECK_SGR_PARAM(j, set_a_foreground);
3333aae38d10SBaptiste Daroussin 	CHECK_SGR_PARAM(j, set_a_background);
3334aae38d10SBaptiste Daroussin 	CHECK_SGR_PARAM(j, set_foreground);
3335aae38d10SBaptiste Daroussin 	CHECK_SGR_PARAM(j, set_background);
33364a1a9510SRong-En Fan     }
33374a1a9510SRong-En Fan #ifdef TRACE
33384a1a9510SRong-En Fan     show_where(2);
33394a1a9510SRong-En Fan     if (!auto_right_margin) {
33404a1a9510SRong-En Fan 	DEBUG(2,
33414a1a9510SRong-En Fan 	      ("can write to lower-right directly"));
33424a1a9510SRong-En Fan     } else if (PRESENT(enter_am_mode) && PRESENT(exit_am_mode)) {
33434a1a9510SRong-En Fan 	DEBUG(2,
33444a1a9510SRong-En Fan 	      ("can write to lower-right by suppressing automargin"));
33454a1a9510SRong-En Fan     } else if ((PRESENT(enter_insert_mode) && PRESENT(exit_insert_mode))
33464a1a9510SRong-En Fan 	       || PRESENT(insert_character) || PRESENT(parm_ich)) {
33474a1a9510SRong-En Fan 	DEBUG(2,
33484a1a9510SRong-En Fan 	      ("can write to lower-right by using inserts"));
33494a1a9510SRong-En Fan     } else {
33504a1a9510SRong-En Fan 	DEBUG(2,
33514a1a9510SRong-En Fan 	      ("cannot write to lower-right"));
33524a1a9510SRong-En Fan     }
33534a1a9510SRong-En Fan #endif
33540e3d5408SPeter Wemm 
33550e3d5408SPeter Wemm     /*
33560e3d5408SPeter Wemm      * Some standard applications (e.g., vi) and some non-curses
33574a1a9510SRong-En Fan      * applications (e.g., jove) get confused if we have both ich1 and
33580e3d5408SPeter Wemm      * smir/rmir.  Let's be nice and warn about that, too, even though
33590e3d5408SPeter Wemm      * ncurses handles it.
33600e3d5408SPeter Wemm      */
33610e3d5408SPeter Wemm     if ((PRESENT(enter_insert_mode) || PRESENT(exit_insert_mode))
3362aae38d10SBaptiste Daroussin 	&& PRESENT(insert_character)) {
33634a1a9510SRong-En Fan 	_nc_warning("non-curses applications may be confused by ich1 with smir/rmir");
33640e3d5408SPeter Wemm     }
33650e3d5408SPeter Wemm 
33660e3d5408SPeter Wemm     /*
33670e3d5408SPeter Wemm      * Finally, do the non-verbose checks
33680e3d5408SPeter Wemm      */
33690e3d5408SPeter Wemm     if (save_check_termtype != 0)
33704a1a9510SRong-En Fan 	save_check_termtype(tp, literal);
33710e3d5408SPeter Wemm }
3372