xref: /freebsd/contrib/ncurses/progs/tic.c (revision 5d08fb1f777aa988958a4f0c45887b0cbfaef9a0)
10e3d5408SPeter Wemm /****************************************************************************
25d08fb1fSRong-En Fan  * Copyright (c) 1998-2007,2008 Free Software Foundation, Inc.              *
30e3d5408SPeter Wemm  *                                                                          *
40e3d5408SPeter Wemm  * Permission is hereby granted, free of charge, to any person obtaining a  *
50e3d5408SPeter Wemm  * copy of this software and associated documentation files (the            *
60e3d5408SPeter Wemm  * "Software"), to deal in the Software without restriction, including      *
70e3d5408SPeter Wemm  * without limitation the rights to use, copy, modify, merge, publish,      *
80e3d5408SPeter Wemm  * distribute, distribute with modifications, sublicense, and/or sell       *
90e3d5408SPeter Wemm  * copies of the Software, and to permit persons to whom the Software is    *
100e3d5408SPeter Wemm  * furnished to do so, subject to the following conditions:                 *
110e3d5408SPeter Wemm  *                                                                          *
120e3d5408SPeter Wemm  * The above copyright notice and this permission notice shall be included  *
130e3d5408SPeter Wemm  * in all copies or substantial portions of the Software.                   *
140e3d5408SPeter Wemm  *                                                                          *
150e3d5408SPeter Wemm  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
160e3d5408SPeter Wemm  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
170e3d5408SPeter Wemm  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
180e3d5408SPeter Wemm  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
190e3d5408SPeter Wemm  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
200e3d5408SPeter Wemm  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
210e3d5408SPeter Wemm  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
220e3d5408SPeter Wemm  *                                                                          *
230e3d5408SPeter Wemm  * Except as contained in this notice, the name(s) of the above copyright   *
240e3d5408SPeter Wemm  * holders shall not be used in advertising or otherwise to promote the     *
250e3d5408SPeter Wemm  * sale, use or other dealings in this Software without prior written       *
260e3d5408SPeter Wemm  * authorization.                                                           *
270e3d5408SPeter Wemm  ****************************************************************************/
280e3d5408SPeter Wemm 
290e3d5408SPeter Wemm /****************************************************************************
300e3d5408SPeter Wemm  *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
310e3d5408SPeter Wemm  *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
32b82face1SPeter Wemm  *     and: Thomas E. Dickey                        1996 on                 *
330e3d5408SPeter Wemm  ****************************************************************************/
340e3d5408SPeter Wemm 
350e3d5408SPeter Wemm /*
360e3d5408SPeter Wemm  *	tic.c --- Main program for terminfo compiler
370e3d5408SPeter Wemm  *			by Eric S. Raymond
380e3d5408SPeter Wemm  *
390e3d5408SPeter Wemm  */
400e3d5408SPeter Wemm 
410e3d5408SPeter Wemm #include <progs.priv.h>
4218259542SPeter Wemm #include <sys/stat.h>
430e3d5408SPeter Wemm 
440e3d5408SPeter Wemm #include <dump_entry.h>
4518259542SPeter Wemm #include <transform.h>
460e3d5408SPeter Wemm 
475d08fb1fSRong-En Fan MODULE_ID("$Id: tic.c,v 1.137 2008/09/13 16:59:24 tom Exp $")
480e3d5408SPeter Wemm 
490e3d5408SPeter Wemm const char *_nc_progname = "tic";
500e3d5408SPeter Wemm 
510e3d5408SPeter Wemm static FILE *log_fp;
520e3d5408SPeter Wemm static FILE *tmp_fp;
534a1a9510SRong-En Fan static bool capdump = FALSE;	/* running as infotocap? */
544a1a9510SRong-En Fan static bool infodump = FALSE;	/* running as captoinfo? */
550e3d5408SPeter Wemm static bool showsummary = FALSE;
560e3d5408SPeter Wemm static const char *to_remove;
570e3d5408SPeter Wemm 
584a1a9510SRong-En Fan static void (*save_check_termtype) (TERMTYPE *, bool);
594a1a9510SRong-En Fan static void check_termtype(TERMTYPE *tt, bool);
600e3d5408SPeter Wemm 
614a1a9510SRong-En Fan static const char usage_string[] = "\
624a1a9510SRong-En Fan [-e names] \
634a1a9510SRong-En Fan [-o dir] \
644a1a9510SRong-En Fan [-R name] \
654a1a9510SRong-En Fan [-v[n]] \
664a1a9510SRong-En Fan [-V] \
674a1a9510SRong-En Fan [-w[n]] \
684a1a9510SRong-En Fan [-\
694a1a9510SRong-En Fan 1\
704a1a9510SRong-En Fan a\
714a1a9510SRong-En Fan C\
724a1a9510SRong-En Fan c\
734a1a9510SRong-En Fan f\
744a1a9510SRong-En Fan G\
754a1a9510SRong-En Fan g\
764a1a9510SRong-En Fan I\
774a1a9510SRong-En Fan L\
784a1a9510SRong-En Fan N\
794a1a9510SRong-En Fan r\
804a1a9510SRong-En Fan s\
814a1a9510SRong-En Fan T\
824a1a9510SRong-En Fan t\
834a1a9510SRong-En Fan U\
844a1a9510SRong-En Fan x\
854a1a9510SRong-En Fan ] \
864a1a9510SRong-En Fan source-file\n";
870e3d5408SPeter Wemm 
885d08fb1fSRong-En Fan #if NO_LEAKS
8915589c42SPeter Wemm static void
905d08fb1fSRong-En Fan free_namelist(char **src)
910e3d5408SPeter Wemm {
925d08fb1fSRong-En Fan     if (src != 0) {
935d08fb1fSRong-En Fan 	int n;
945d08fb1fSRong-En Fan 	for (n = 0; src[n] != 0; ++n)
955d08fb1fSRong-En Fan 	    free(src[n]);
965d08fb1fSRong-En Fan 	free(src);
975d08fb1fSRong-En Fan     }
985d08fb1fSRong-En Fan }
995d08fb1fSRong-En Fan #endif
1005d08fb1fSRong-En Fan 
1015d08fb1fSRong-En Fan static void
1025d08fb1fSRong-En Fan cleanup(char **namelst GCC_UNUSED)
1035d08fb1fSRong-En Fan {
1045d08fb1fSRong-En Fan #if NO_LEAKS
1055d08fb1fSRong-En Fan     free_namelist(namelst);
1065d08fb1fSRong-En Fan #endif
1070e3d5408SPeter Wemm     if (tmp_fp != 0)
1080e3d5408SPeter Wemm 	fclose(tmp_fp);
1090e3d5408SPeter Wemm     if (to_remove != 0) {
1100e3d5408SPeter Wemm #if HAVE_REMOVE
1110e3d5408SPeter Wemm 	remove(to_remove);
1120e3d5408SPeter Wemm #else
1130e3d5408SPeter Wemm 	unlink(to_remove);
1140e3d5408SPeter Wemm #endif
1150e3d5408SPeter Wemm     }
1160e3d5408SPeter Wemm }
1170e3d5408SPeter Wemm 
11815589c42SPeter Wemm static void
11915589c42SPeter Wemm failed(const char *msg)
1200e3d5408SPeter Wemm {
1210e3d5408SPeter Wemm     perror(msg);
1225d08fb1fSRong-En Fan     cleanup((char **) 0);
1234a1a9510SRong-En Fan     ExitProgram(EXIT_FAILURE);
1240e3d5408SPeter Wemm }
1250e3d5408SPeter Wemm 
12615589c42SPeter Wemm static void
12715589c42SPeter Wemm usage(void)
1280e3d5408SPeter Wemm {
12915589c42SPeter Wemm     static const char *const tbl[] =
13015589c42SPeter Wemm     {
1310e3d5408SPeter Wemm 	"Options:",
1320e3d5408SPeter Wemm 	"  -1         format translation output one capability per line",
13315589c42SPeter Wemm #if NCURSES_XNAMES
13415589c42SPeter Wemm 	"  -a         retain commented-out capabilities (sets -x also)",
13515589c42SPeter Wemm #endif
1364a1a9510SRong-En Fan 	"  -C         translate entries to termcap source form",
1370e3d5408SPeter Wemm 	"  -c         check only, validate input without compiling or translating",
1384a1a9510SRong-En Fan 	"  -e<names>  translate/compile only entries named by comma-separated list",
1390e3d5408SPeter Wemm 	"  -f         format complex strings for readability",
1400e3d5408SPeter Wemm 	"  -G         format %{number} to %'char'",
1410e3d5408SPeter Wemm 	"  -g         format %'char' to %{number}",
1424a1a9510SRong-En Fan 	"  -I         translate entries to terminfo source form",
1434a1a9510SRong-En Fan 	"  -L         translate entries to full terminfo source form",
1444a1a9510SRong-En Fan 	"  -N         disable smart defaults for source translation",
1450e3d5408SPeter Wemm 	"  -o<dir>    set output directory for compiled entry writes",
1464a1a9510SRong-En Fan 	"  -R<name>   restrict translation to given terminfo/termcap version",
1470e3d5408SPeter Wemm 	"  -r         force resolution of all use entries in source translation",
1480e3d5408SPeter Wemm 	"  -s         print summary statistics",
1494a1a9510SRong-En Fan 	"  -T         remove size-restrictions on compiled description",
1504a1a9510SRong-En Fan #if NCURSES_XNAMES
1514a1a9510SRong-En Fan 	"  -t         suppress commented-out capabilities",
1524a1a9510SRong-En Fan #endif
1534a1a9510SRong-En Fan 	"  -U         suppress post-processing of entries",
1544a1a9510SRong-En Fan 	"  -V         print version",
1550e3d5408SPeter Wemm 	"  -v[n]      set verbosity level",
1560e3d5408SPeter Wemm 	"  -w[n]      set format width for translation output",
1570e3d5408SPeter Wemm #if NCURSES_XNAMES
1580e3d5408SPeter Wemm 	"  -x         treat unknown capabilities as user-defined",
1590e3d5408SPeter Wemm #endif
1600e3d5408SPeter Wemm 	"",
1610e3d5408SPeter Wemm 	"Parameters:",
1620e3d5408SPeter Wemm 	"  <file>     file to translate or compile"
1630e3d5408SPeter Wemm     };
1640e3d5408SPeter Wemm     size_t j;
1650e3d5408SPeter Wemm 
16615589c42SPeter Wemm     fprintf(stderr, "Usage: %s %s\n", _nc_progname, usage_string);
16718259542SPeter Wemm     for (j = 0; j < SIZEOF(tbl); j++) {
16815589c42SPeter Wemm 	fputs(tbl[j], stderr);
16915589c42SPeter Wemm 	putc('\n', stderr);
17015589c42SPeter Wemm     }
1714a1a9510SRong-En Fan     ExitProgram(EXIT_FAILURE);
1720e3d5408SPeter Wemm }
1730e3d5408SPeter Wemm 
1740e3d5408SPeter Wemm #define L_BRACE '{'
1750e3d5408SPeter Wemm #define R_BRACE '}'
1760e3d5408SPeter Wemm #define S_QUOTE '\'';
1770e3d5408SPeter Wemm 
17815589c42SPeter Wemm static void
17915589c42SPeter Wemm write_it(ENTRY * ep)
1800e3d5408SPeter Wemm {
1810e3d5408SPeter Wemm     unsigned n;
1820e3d5408SPeter Wemm     int ch;
1830e3d5408SPeter Wemm     char *s, *d, *t;
1840e3d5408SPeter Wemm     char result[MAX_ENTRY_SIZE];
1850e3d5408SPeter Wemm 
1860e3d5408SPeter Wemm     /*
1870e3d5408SPeter Wemm      * Look for strings that contain %{number}, convert them to %'char',
1880e3d5408SPeter Wemm      * which is shorter and runs a little faster.
1890e3d5408SPeter Wemm      */
1900e3d5408SPeter Wemm     for (n = 0; n < STRCOUNT; n++) {
1910e3d5408SPeter Wemm 	s = ep->tterm.Strings[n];
1920e3d5408SPeter Wemm 	if (VALID_STRING(s)
1930e3d5408SPeter Wemm 	    && strchr(s, L_BRACE) != 0) {
1940e3d5408SPeter Wemm 	    d = result;
1950e3d5408SPeter Wemm 	    t = s;
1960e3d5408SPeter Wemm 	    while ((ch = *t++) != 0) {
1975d08fb1fSRong-En Fan 		*d++ = (char) ch;
1980e3d5408SPeter Wemm 		if (ch == '\\') {
1990e3d5408SPeter Wemm 		    *d++ = *t++;
2000e3d5408SPeter Wemm 		} else if ((ch == '%')
2010e3d5408SPeter Wemm 			   && (*t == L_BRACE)) {
2020e3d5408SPeter Wemm 		    char *v = 0;
2030e3d5408SPeter Wemm 		    long value = strtol(t + 1, &v, 0);
2040e3d5408SPeter Wemm 		    if (v != 0
2050e3d5408SPeter Wemm 			&& *v == R_BRACE
2060e3d5408SPeter Wemm 			&& value > 0
2070e3d5408SPeter Wemm 			&& value != '\\'	/* FIXME */
2080e3d5408SPeter Wemm 			&& value < 127
2090e3d5408SPeter Wemm 			&& isprint((int) value)) {
2100e3d5408SPeter Wemm 			*d++ = S_QUOTE;
2115d08fb1fSRong-En Fan 			*d++ = (char) value;
2120e3d5408SPeter Wemm 			*d++ = S_QUOTE;
2130e3d5408SPeter Wemm 			t = (v + 1);
2140e3d5408SPeter Wemm 		    }
2150e3d5408SPeter Wemm 		}
2160e3d5408SPeter Wemm 	    }
2170e3d5408SPeter Wemm 	    *d = 0;
2180e3d5408SPeter Wemm 	    if (strlen(result) < strlen(s))
2190e3d5408SPeter Wemm 		strcpy(s, result);
2200e3d5408SPeter Wemm 	}
2210e3d5408SPeter Wemm     }
2220e3d5408SPeter Wemm 
2230e3d5408SPeter Wemm     _nc_set_type(_nc_first_name(ep->tterm.term_names));
2240e3d5408SPeter Wemm     _nc_curr_line = ep->startline;
2250e3d5408SPeter Wemm     _nc_write_entry(&ep->tterm);
2260e3d5408SPeter Wemm }
2270e3d5408SPeter Wemm 
22815589c42SPeter Wemm static bool
22915589c42SPeter Wemm immedhook(ENTRY * ep GCC_UNUSED)
2300e3d5408SPeter Wemm /* write out entries with no use capabilities immediately to save storage */
2310e3d5408SPeter Wemm {
23218259542SPeter Wemm #if !HAVE_BIG_CORE
2330e3d5408SPeter Wemm     /*
2340e3d5408SPeter Wemm      * This is strictly a core-economy kluge.  The really clean way to handle
2350e3d5408SPeter Wemm      * compilation is to slurp the whole file into core and then do all the
2360e3d5408SPeter Wemm      * name-collision checks and entry writes in one swell foop.  But the
2370e3d5408SPeter Wemm      * terminfo master file is large enough that some core-poor systems swap
2380e3d5408SPeter Wemm      * like crazy when you compile it this way...there have been reports of
2390e3d5408SPeter Wemm      * this process taking *three hours*, rather than the twenty seconds or
2400e3d5408SPeter Wemm      * less typical on my development box.
2410e3d5408SPeter Wemm      *
2420e3d5408SPeter Wemm      * So.  This hook *immediately* writes out the referenced entry if it
2430e3d5408SPeter Wemm      * has no use capabilities.  The compiler main loop refrains from
2440e3d5408SPeter Wemm      * adding the entry to the in-core list when this hook fires.  If some
2450e3d5408SPeter Wemm      * other entry later needs to reference an entry that got written
2460e3d5408SPeter Wemm      * immediately, that's OK; the resolution code will fetch it off disk
2470e3d5408SPeter Wemm      * when it can't find it in core.
2480e3d5408SPeter Wemm      *
2490e3d5408SPeter Wemm      * Name collisions will still be detected, just not as cleanly.  The
2500e3d5408SPeter Wemm      * write_entry() code complains before overwriting an entry that
2510e3d5408SPeter Wemm      * postdates the time of tic's first call to write_entry().  Thus
2520e3d5408SPeter Wemm      * it will complain about overwriting entries newly made during the
2530e3d5408SPeter Wemm      * tic run, but not about overwriting ones that predate it.
2540e3d5408SPeter Wemm      *
2550e3d5408SPeter Wemm      * The reason this is a hook, and not in line with the rest of the
2560e3d5408SPeter Wemm      * compiler code, is that the support for termcap fallback cannot assume
2570e3d5408SPeter Wemm      * it has anywhere to spool out these entries!
2580e3d5408SPeter Wemm      *
2590e3d5408SPeter Wemm      * The _nc_set_type() call here requires a compensating one in
2600e3d5408SPeter Wemm      * _nc_parse_entry().
2610e3d5408SPeter Wemm      *
2620e3d5408SPeter Wemm      * If you define HAVE_BIG_CORE, you'll disable this kluge.  This will
2630e3d5408SPeter Wemm      * make tic a bit faster (because the resolution code won't have to do
2640e3d5408SPeter Wemm      * disk I/O nearly as often).
2650e3d5408SPeter Wemm      */
26615589c42SPeter Wemm     if (ep->nuses == 0) {
2670e3d5408SPeter Wemm 	int oldline = _nc_curr_line;
2680e3d5408SPeter Wemm 
2690e3d5408SPeter Wemm 	write_it(ep);
2700e3d5408SPeter Wemm 	_nc_curr_line = oldline;
2710e3d5408SPeter Wemm 	free(ep->tterm.str_table);
2720e3d5408SPeter Wemm 	return (TRUE);
2730e3d5408SPeter Wemm     }
2740e3d5408SPeter Wemm #endif /* HAVE_BIG_CORE */
2750e3d5408SPeter Wemm     return (FALSE);
2760e3d5408SPeter Wemm }
2770e3d5408SPeter Wemm 
27815589c42SPeter Wemm static void
27915589c42SPeter Wemm put_translate(int c)
2800e3d5408SPeter Wemm /* emit a comment char, translating terminfo names to termcap names */
2810e3d5408SPeter Wemm {
2820e3d5408SPeter Wemm     static bool in_name = FALSE;
28315589c42SPeter Wemm     static size_t have, used;
28415589c42SPeter Wemm     static char *namebuf, *suffix;
2850e3d5408SPeter Wemm 
28615589c42SPeter Wemm     if (in_name) {
28715589c42SPeter Wemm 	if (used + 1 >= have) {
28815589c42SPeter Wemm 	    have += 132;
28915589c42SPeter Wemm 	    namebuf = typeRealloc(char, have, namebuf);
29015589c42SPeter Wemm 	    suffix = typeRealloc(char, have, suffix);
2910e3d5408SPeter Wemm 	}
29215589c42SPeter Wemm 	if (c == '\n' || c == '@') {
29315589c42SPeter Wemm 	    namebuf[used++] = '\0';
2940e3d5408SPeter Wemm 	    (void) putchar('<');
2950e3d5408SPeter Wemm 	    (void) fputs(namebuf, stdout);
2960e3d5408SPeter Wemm 	    putchar(c);
2970e3d5408SPeter Wemm 	    in_name = FALSE;
29815589c42SPeter Wemm 	} else if (c != '>') {
2995d08fb1fSRong-En Fan 	    namebuf[used++] = (char) c;
30015589c42SPeter Wemm 	} else {		/* ah! candidate name! */
3010e3d5408SPeter Wemm 	    char *up;
3020e3d5408SPeter Wemm 	    NCURSES_CONST char *tp;
3030e3d5408SPeter Wemm 
30415589c42SPeter Wemm 	    namebuf[used++] = '\0';
3050e3d5408SPeter Wemm 	    in_name = FALSE;
3060e3d5408SPeter Wemm 
3070e3d5408SPeter Wemm 	    suffix[0] = '\0';
3080e3d5408SPeter Wemm 	    if ((up = strchr(namebuf, '#')) != 0
3090e3d5408SPeter Wemm 		|| (up = strchr(namebuf, '=')) != 0
31015589c42SPeter Wemm 		|| ((up = strchr(namebuf, '@')) != 0 && up[1] == '>')) {
3110e3d5408SPeter Wemm 		(void) strcpy(suffix, up);
3120e3d5408SPeter Wemm 		*up = '\0';
3130e3d5408SPeter Wemm 	    }
3140e3d5408SPeter Wemm 
31515589c42SPeter Wemm 	    if ((tp = nametrans(namebuf)) != 0) {
3160e3d5408SPeter Wemm 		(void) putchar(':');
3170e3d5408SPeter Wemm 		(void) fputs(tp, stdout);
3180e3d5408SPeter Wemm 		(void) fputs(suffix, stdout);
3190e3d5408SPeter Wemm 		(void) putchar(':');
32015589c42SPeter Wemm 	    } else {
3210e3d5408SPeter Wemm 		/* couldn't find a translation, just dump the name */
3220e3d5408SPeter Wemm 		(void) putchar('<');
3230e3d5408SPeter Wemm 		(void) fputs(namebuf, stdout);
3240e3d5408SPeter Wemm 		(void) fputs(suffix, stdout);
3250e3d5408SPeter Wemm 		(void) putchar('>');
3260e3d5408SPeter Wemm 	    }
32715589c42SPeter Wemm 	}
32815589c42SPeter Wemm     } else {
32915589c42SPeter Wemm 	used = 0;
33015589c42SPeter Wemm 	if (c == '<') {
33115589c42SPeter Wemm 	    in_name = TRUE;
33215589c42SPeter Wemm 	} else {
33315589c42SPeter Wemm 	    putchar(c);
33415589c42SPeter Wemm 	}
3350e3d5408SPeter Wemm     }
3360e3d5408SPeter Wemm }
3370e3d5408SPeter Wemm 
3380e3d5408SPeter Wemm /* Returns a string, stripped of leading/trailing whitespace */
33915589c42SPeter Wemm static char *
34015589c42SPeter Wemm stripped(char *src)
3410e3d5408SPeter Wemm {
34239f2269fSPeter Wemm     while (isspace(UChar(*src)))
3430e3d5408SPeter Wemm 	src++;
3440e3d5408SPeter Wemm     if (*src != '\0') {
3454a1a9510SRong-En Fan 	char *dst = strcpy((char *) malloc(strlen(src) + 1), src);
3460e3d5408SPeter Wemm 	size_t len = strlen(dst);
34739f2269fSPeter Wemm 	while (--len != 0 && isspace(UChar(dst[len])))
3480e3d5408SPeter Wemm 	    dst[len] = '\0';
3490e3d5408SPeter Wemm 	return dst;
3500e3d5408SPeter Wemm     }
3510e3d5408SPeter Wemm     return 0;
3520e3d5408SPeter Wemm }
3530e3d5408SPeter Wemm 
35418259542SPeter Wemm static FILE *
35518259542SPeter Wemm open_input(const char *filename)
35618259542SPeter Wemm {
35718259542SPeter Wemm     FILE *fp = fopen(filename, "r");
35818259542SPeter Wemm     struct stat sb;
35918259542SPeter Wemm 
36018259542SPeter Wemm     if (fp == 0) {
36118259542SPeter Wemm 	fprintf(stderr, "%s: Can't open %s\n", _nc_progname, filename);
3624a1a9510SRong-En Fan 	ExitProgram(EXIT_FAILURE);
36318259542SPeter Wemm     }
36418259542SPeter Wemm     if (fstat(fileno(fp), &sb) < 0
36518259542SPeter Wemm 	|| (sb.st_mode & S_IFMT) != S_IFREG) {
36618259542SPeter Wemm 	fprintf(stderr, "%s: %s is not a file\n", _nc_progname, filename);
3674a1a9510SRong-En Fan 	ExitProgram(EXIT_FAILURE);
36818259542SPeter Wemm     }
36918259542SPeter Wemm     return fp;
37018259542SPeter Wemm }
37118259542SPeter Wemm 
3720e3d5408SPeter Wemm /* Parse the "-e" option-value into a list of names */
3735ca44d1cSRong-En Fan static char **
37415589c42SPeter Wemm make_namelist(char *src)
3750e3d5408SPeter Wemm {
3765ca44d1cSRong-En Fan     char **dst = 0;
3770e3d5408SPeter Wemm 
3780e3d5408SPeter Wemm     char *s, *base;
3790e3d5408SPeter Wemm     unsigned pass, n, nn;
3800e3d5408SPeter Wemm     char buffer[BUFSIZ];
3810e3d5408SPeter Wemm 
3820e3d5408SPeter Wemm     if (src == 0) {
3830e3d5408SPeter Wemm 	/* EMPTY */ ;
3840e3d5408SPeter Wemm     } else if (strchr(src, '/') != 0) {		/* a filename */
38518259542SPeter Wemm 	FILE *fp = open_input(src);
3860e3d5408SPeter Wemm 
3870e3d5408SPeter Wemm 	for (pass = 1; pass <= 2; pass++) {
3880e3d5408SPeter Wemm 	    nn = 0;
3890e3d5408SPeter Wemm 	    while (fgets(buffer, sizeof(buffer), fp) != 0) {
3900e3d5408SPeter Wemm 		if ((s = stripped(buffer)) != 0) {
3910e3d5408SPeter Wemm 		    if (dst != 0)
3920e3d5408SPeter Wemm 			dst[nn] = s;
3935ca44d1cSRong-En Fan 		    else
3945ca44d1cSRong-En Fan 			free(s);
3950e3d5408SPeter Wemm 		    nn++;
3960e3d5408SPeter Wemm 		}
3970e3d5408SPeter Wemm 	    }
3980e3d5408SPeter Wemm 	    if (pass == 1) {
3995ca44d1cSRong-En Fan 		dst = typeCalloc(char *, nn + 1);
4000e3d5408SPeter Wemm 		rewind(fp);
4010e3d5408SPeter Wemm 	    }
4020e3d5408SPeter Wemm 	}
4030e3d5408SPeter Wemm 	fclose(fp);
4040e3d5408SPeter Wemm     } else {			/* literal list of names */
4050e3d5408SPeter Wemm 	for (pass = 1; pass <= 2; pass++) {
4060e3d5408SPeter Wemm 	    for (n = nn = 0, base = src;; n++) {
4070e3d5408SPeter Wemm 		int mark = src[n];
4080e3d5408SPeter Wemm 		if (mark == ',' || mark == '\0') {
4090e3d5408SPeter Wemm 		    if (pass == 1) {
4100e3d5408SPeter Wemm 			nn++;
4110e3d5408SPeter Wemm 		    } else {
4120e3d5408SPeter Wemm 			src[n] = '\0';
4130e3d5408SPeter Wemm 			if ((s = stripped(base)) != 0)
4140e3d5408SPeter Wemm 			    dst[nn++] = s;
4150e3d5408SPeter Wemm 			base = &src[n + 1];
4160e3d5408SPeter Wemm 		    }
4170e3d5408SPeter Wemm 		}
4180e3d5408SPeter Wemm 		if (mark == '\0')
4190e3d5408SPeter Wemm 		    break;
4200e3d5408SPeter Wemm 	    }
4210e3d5408SPeter Wemm 	    if (pass == 1)
4225ca44d1cSRong-En Fan 		dst = typeCalloc(char *, nn + 1);
4230e3d5408SPeter Wemm 	}
4240e3d5408SPeter Wemm     }
4255ca44d1cSRong-En Fan     if (showsummary && (dst != 0)) {
4260e3d5408SPeter Wemm 	fprintf(log_fp, "Entries that will be compiled:\n");
4270e3d5408SPeter Wemm 	for (n = 0; dst[n] != 0; n++)
4284a1a9510SRong-En Fan 	    fprintf(log_fp, "%u:%s\n", n + 1, dst[n]);
4290e3d5408SPeter Wemm     }
4300e3d5408SPeter Wemm     return dst;
4310e3d5408SPeter Wemm }
4320e3d5408SPeter Wemm 
43315589c42SPeter Wemm static bool
4345ca44d1cSRong-En Fan matches(char **needle, const char *haystack)
4350e3d5408SPeter Wemm /* does entry in needle list match |-separated field in haystack? */
4360e3d5408SPeter Wemm {
4370e3d5408SPeter Wemm     bool code = FALSE;
4380e3d5408SPeter Wemm     size_t n;
4390e3d5408SPeter Wemm 
44015589c42SPeter Wemm     if (needle != 0) {
44115589c42SPeter Wemm 	for (n = 0; needle[n] != 0; n++) {
44215589c42SPeter Wemm 	    if (_nc_name_match(haystack, needle[n], "|")) {
4430e3d5408SPeter Wemm 		code = TRUE;
4440e3d5408SPeter Wemm 		break;
4450e3d5408SPeter Wemm 	    }
4460e3d5408SPeter Wemm 	}
44715589c42SPeter Wemm     } else
4480e3d5408SPeter Wemm 	code = TRUE;
4490e3d5408SPeter Wemm     return (code);
4500e3d5408SPeter Wemm }
4510e3d5408SPeter Wemm 
45215589c42SPeter Wemm static FILE *
45315589c42SPeter Wemm open_tempfile(char *name)
45415589c42SPeter Wemm {
45515589c42SPeter Wemm     FILE *result = 0;
45615589c42SPeter Wemm #if HAVE_MKSTEMP
45715589c42SPeter Wemm     int fd = mkstemp(name);
45815589c42SPeter Wemm     if (fd >= 0)
45915589c42SPeter Wemm 	result = fdopen(fd, "w");
46015589c42SPeter Wemm #else
46115589c42SPeter Wemm     if (tmpnam(name) != 0)
46215589c42SPeter Wemm 	result = fopen(name, "w");
46315589c42SPeter Wemm #endif
46415589c42SPeter Wemm     return result;
46515589c42SPeter Wemm }
46615589c42SPeter Wemm 
46715589c42SPeter Wemm int
46815589c42SPeter Wemm main(int argc, char *argv[])
4690e3d5408SPeter Wemm {
4700e3d5408SPeter Wemm     char my_tmpname[PATH_MAX];
4710e3d5408SPeter Wemm     int v_opt = -1, debug_level;
4720e3d5408SPeter Wemm     int smart_defaults = TRUE;
4730e3d5408SPeter Wemm     char *termcap;
4740e3d5408SPeter Wemm     ENTRY *qp;
4750e3d5408SPeter Wemm 
4760e3d5408SPeter Wemm     int this_opt, last_opt = '?';
4770e3d5408SPeter Wemm 
4780e3d5408SPeter Wemm     int outform = F_TERMINFO;	/* output format */
4790e3d5408SPeter Wemm     int sortmode = S_TERMINFO;	/* sort_mode */
4800e3d5408SPeter Wemm 
4810e3d5408SPeter Wemm     int width = 60;
4820e3d5408SPeter Wemm     bool formatted = FALSE;	/* reformat complex strings? */
4834a1a9510SRong-En Fan     bool literal = FALSE;	/* suppress post-processing? */
4840e3d5408SPeter Wemm     int numbers = 0;		/* format "%'char'" to/from "%{number}" */
4850e3d5408SPeter Wemm     bool forceresolve = FALSE;	/* force resolution */
4860e3d5408SPeter Wemm     bool limited = TRUE;
4870e3d5408SPeter Wemm     char *tversion = (char *) NULL;
4880e3d5408SPeter Wemm     const char *source_file = "terminfo";
4895ca44d1cSRong-En Fan     char **namelst = 0;
4900e3d5408SPeter Wemm     char *outdir = (char *) NULL;
4910e3d5408SPeter Wemm     bool check_only = FALSE;
4924a1a9510SRong-En Fan     bool suppress_untranslatable = FALSE;
4930e3d5408SPeter Wemm 
4940e3d5408SPeter Wemm     log_fp = stderr;
4950e3d5408SPeter Wemm 
49639f2269fSPeter Wemm     _nc_progname = _nc_rootname(argv[0]);
4970e3d5408SPeter Wemm 
49818259542SPeter Wemm     if ((infodump = (strcmp(_nc_progname, PROG_CAPTOINFO) == 0)) != FALSE) {
49915589c42SPeter Wemm 	outform = F_TERMINFO;
50015589c42SPeter Wemm 	sortmode = S_TERMINFO;
50115589c42SPeter Wemm     }
50218259542SPeter Wemm     if ((capdump = (strcmp(_nc_progname, PROG_INFOTOCAP) == 0)) != FALSE) {
50315589c42SPeter Wemm 	outform = F_TERMCAP;
50415589c42SPeter Wemm 	sortmode = S_TERMCAP;
50515589c42SPeter Wemm     }
5060e3d5408SPeter Wemm #if NCURSES_XNAMES
5070e3d5408SPeter Wemm     use_extended_names(FALSE);
5080e3d5408SPeter Wemm #endif
5090e3d5408SPeter Wemm 
5100e3d5408SPeter Wemm     /*
5110e3d5408SPeter Wemm      * Processing arguments is a little complicated, since someone made a
5120e3d5408SPeter Wemm      * design decision to allow the numeric values for -w, -v options to
5130e3d5408SPeter Wemm      * be optional.
5140e3d5408SPeter Wemm      */
51515589c42SPeter Wemm     while ((this_opt = getopt(argc, argv,
5165ca44d1cSRong-En Fan 			      "0123456789CILNR:TUVace:fGgo:rstvwx")) != -1) {
5170e3d5408SPeter Wemm 	if (isdigit(this_opt)) {
5180e3d5408SPeter Wemm 	    switch (last_opt) {
5190e3d5408SPeter Wemm 	    case 'v':
5200e3d5408SPeter Wemm 		v_opt = (v_opt * 10) + (this_opt - '0');
5210e3d5408SPeter Wemm 		break;
5220e3d5408SPeter Wemm 	    case 'w':
5230e3d5408SPeter Wemm 		width = (width * 10) + (this_opt - '0');
5240e3d5408SPeter Wemm 		break;
5250e3d5408SPeter Wemm 	    default:
5260e3d5408SPeter Wemm 		if (this_opt != '1')
5270e3d5408SPeter Wemm 		    usage();
5280e3d5408SPeter Wemm 		last_opt = this_opt;
5290e3d5408SPeter Wemm 		width = 0;
5300e3d5408SPeter Wemm 	    }
5310e3d5408SPeter Wemm 	    continue;
5320e3d5408SPeter Wemm 	}
5330e3d5408SPeter Wemm 	switch (this_opt) {
5340e3d5408SPeter Wemm 	case 'C':
5350e3d5408SPeter Wemm 	    capdump = TRUE;
5360e3d5408SPeter Wemm 	    outform = F_TERMCAP;
5370e3d5408SPeter Wemm 	    sortmode = S_TERMCAP;
5380e3d5408SPeter Wemm 	    break;
5390e3d5408SPeter Wemm 	case 'I':
5400e3d5408SPeter Wemm 	    infodump = TRUE;
5410e3d5408SPeter Wemm 	    outform = F_TERMINFO;
5420e3d5408SPeter Wemm 	    sortmode = S_TERMINFO;
5430e3d5408SPeter Wemm 	    break;
5440e3d5408SPeter Wemm 	case 'L':
5450e3d5408SPeter Wemm 	    infodump = TRUE;
5460e3d5408SPeter Wemm 	    outform = F_VARIABLE;
5470e3d5408SPeter Wemm 	    sortmode = S_VARIABLE;
5480e3d5408SPeter Wemm 	    break;
5490e3d5408SPeter Wemm 	case 'N':
5500e3d5408SPeter Wemm 	    smart_defaults = FALSE;
5514a1a9510SRong-En Fan 	    literal = TRUE;
5520e3d5408SPeter Wemm 	    break;
5530e3d5408SPeter Wemm 	case 'R':
5540e3d5408SPeter Wemm 	    tversion = optarg;
5550e3d5408SPeter Wemm 	    break;
5560e3d5408SPeter Wemm 	case 'T':
5570e3d5408SPeter Wemm 	    limited = FALSE;
5580e3d5408SPeter Wemm 	    break;
5594a1a9510SRong-En Fan 	case 'U':
5604a1a9510SRong-En Fan 	    literal = TRUE;
5614a1a9510SRong-En Fan 	    break;
5620e3d5408SPeter Wemm 	case 'V':
56318259542SPeter Wemm 	    puts(curses_version());
5645d08fb1fSRong-En Fan 	    cleanup(namelst);
5655d08fb1fSRong-En Fan 	    ExitProgram(EXIT_SUCCESS);
5660e3d5408SPeter Wemm 	case 'c':
5670e3d5408SPeter Wemm 	    check_only = TRUE;
5680e3d5408SPeter Wemm 	    break;
5690e3d5408SPeter Wemm 	case 'e':
5700e3d5408SPeter Wemm 	    namelst = make_namelist(optarg);
5710e3d5408SPeter Wemm 	    break;
5720e3d5408SPeter Wemm 	case 'f':
5730e3d5408SPeter Wemm 	    formatted = TRUE;
5740e3d5408SPeter Wemm 	    break;
5750e3d5408SPeter Wemm 	case 'G':
5760e3d5408SPeter Wemm 	    numbers = 1;
5770e3d5408SPeter Wemm 	    break;
5780e3d5408SPeter Wemm 	case 'g':
5790e3d5408SPeter Wemm 	    numbers = -1;
5800e3d5408SPeter Wemm 	    break;
5810e3d5408SPeter Wemm 	case 'o':
5820e3d5408SPeter Wemm 	    outdir = optarg;
5830e3d5408SPeter Wemm 	    break;
5840e3d5408SPeter Wemm 	case 'r':
5850e3d5408SPeter Wemm 	    forceresolve = TRUE;
5860e3d5408SPeter Wemm 	    break;
5870e3d5408SPeter Wemm 	case 's':
5880e3d5408SPeter Wemm 	    showsummary = TRUE;
5890e3d5408SPeter Wemm 	    break;
5900e3d5408SPeter Wemm 	case 'v':
5910e3d5408SPeter Wemm 	    v_opt = 0;
5920e3d5408SPeter Wemm 	    break;
5930e3d5408SPeter Wemm 	case 'w':
5940e3d5408SPeter Wemm 	    width = 0;
5950e3d5408SPeter Wemm 	    break;
5960e3d5408SPeter Wemm #if NCURSES_XNAMES
5974a1a9510SRong-En Fan 	case 't':
5984a1a9510SRong-En Fan 	    _nc_disable_period = FALSE;
5994a1a9510SRong-En Fan 	    suppress_untranslatable = TRUE;
6004a1a9510SRong-En Fan 	    break;
60115589c42SPeter Wemm 	case 'a':
60215589c42SPeter Wemm 	    _nc_disable_period = TRUE;
60315589c42SPeter Wemm 	    /* FALLTHRU */
6040e3d5408SPeter Wemm 	case 'x':
6050e3d5408SPeter Wemm 	    use_extended_names(TRUE);
6060e3d5408SPeter Wemm 	    break;
6070e3d5408SPeter Wemm #endif
6080e3d5408SPeter Wemm 	default:
6090e3d5408SPeter Wemm 	    usage();
6100e3d5408SPeter Wemm 	}
6110e3d5408SPeter Wemm 	last_opt = this_opt;
6120e3d5408SPeter Wemm     }
6130e3d5408SPeter Wemm 
6140e3d5408SPeter Wemm     debug_level = (v_opt > 0) ? v_opt : (v_opt == 0);
61515589c42SPeter Wemm     set_trace_level(debug_level);
6160e3d5408SPeter Wemm 
61715589c42SPeter Wemm     if (_nc_tracing) {
6184a1a9510SRong-En Fan 	save_check_termtype = _nc_check_termtype2;
6194a1a9510SRong-En Fan 	_nc_check_termtype2 = check_termtype;
6200e3d5408SPeter Wemm     }
62118259542SPeter Wemm #if !HAVE_BIG_CORE
6220e3d5408SPeter Wemm     /*
6230e3d5408SPeter Wemm      * Aaargh! immedhook seriously hoses us!
6240e3d5408SPeter Wemm      *
6250e3d5408SPeter Wemm      * One problem with immedhook is it means we can't do -e.  Problem
6260e3d5408SPeter Wemm      * is that we can't guarantee that for each terminal listed, all the
6270e3d5408SPeter Wemm      * terminals it depends on will have been kept in core for reference
6280e3d5408SPeter Wemm      * resolution -- in fact it's certain the primitive types at the end
6290e3d5408SPeter Wemm      * of reference chains *won't* be in core unless they were explicitly
6300e3d5408SPeter Wemm      * in the select list themselves.
6310e3d5408SPeter Wemm      */
63215589c42SPeter Wemm     if (namelst && (!infodump && !capdump)) {
6330e3d5408SPeter Wemm 	(void) fprintf(stderr,
6340e3d5408SPeter Wemm 		       "Sorry, -e can't be used without -I or -C\n");
6355d08fb1fSRong-En Fan 	cleanup(namelst);
6364a1a9510SRong-En Fan 	ExitProgram(EXIT_FAILURE);
6370e3d5408SPeter Wemm     }
6380e3d5408SPeter Wemm #endif /* HAVE_BIG_CORE */
6390e3d5408SPeter Wemm 
6400e3d5408SPeter Wemm     if (optind < argc) {
6410e3d5408SPeter Wemm 	source_file = argv[optind++];
6420e3d5408SPeter Wemm 	if (optind < argc) {
6430e3d5408SPeter Wemm 	    fprintf(stderr,
6440e3d5408SPeter Wemm 		    "%s: Too many file names.  Usage:\n\t%s %s",
6450e3d5408SPeter Wemm 		    _nc_progname,
6460e3d5408SPeter Wemm 		    _nc_progname,
6470e3d5408SPeter Wemm 		    usage_string);
6484a1a9510SRong-En Fan 	    ExitProgram(EXIT_FAILURE);
6490e3d5408SPeter Wemm 	}
6500e3d5408SPeter Wemm     } else {
6510e3d5408SPeter Wemm 	if (infodump == TRUE) {
6520e3d5408SPeter Wemm 	    /* captoinfo's no-argument case */
6530e3d5408SPeter Wemm 	    source_file = "/etc/termcap";
6540e3d5408SPeter Wemm 	    if ((termcap = getenv("TERMCAP")) != 0
6550e3d5408SPeter Wemm 		&& (namelst = make_namelist(getenv("TERM"))) != 0) {
6560e3d5408SPeter Wemm 		if (access(termcap, F_OK) == 0) {
6570e3d5408SPeter Wemm 		    /* file exists */
6580e3d5408SPeter Wemm 		    source_file = termcap;
65918259542SPeter Wemm 		} else if ((tmp_fp = open_tempfile(strcpy(my_tmpname,
66018259542SPeter Wemm 							  "/tmp/XXXXXX")))
66118259542SPeter Wemm 			   != 0) {
66215589c42SPeter Wemm 		    source_file = my_tmpname;
6630e3d5408SPeter Wemm 		    fprintf(tmp_fp, "%s\n", termcap);
6640e3d5408SPeter Wemm 		    fclose(tmp_fp);
66518259542SPeter Wemm 		    tmp_fp = open_input(source_file);
6660e3d5408SPeter Wemm 		    to_remove = source_file;
6670e3d5408SPeter Wemm 		} else {
6680e3d5408SPeter Wemm 		    failed("tmpnam");
6690e3d5408SPeter Wemm 		}
6700e3d5408SPeter Wemm 	    }
6710e3d5408SPeter Wemm 	} else {
6720e3d5408SPeter Wemm 	    /* tic */
6730e3d5408SPeter Wemm 	    fprintf(stderr,
6740e3d5408SPeter Wemm 		    "%s: File name needed.  Usage:\n\t%s %s",
6750e3d5408SPeter Wemm 		    _nc_progname,
6760e3d5408SPeter Wemm 		    _nc_progname,
6770e3d5408SPeter Wemm 		    usage_string);
6785d08fb1fSRong-En Fan 	    cleanup(namelst);
6794a1a9510SRong-En Fan 	    ExitProgram(EXIT_FAILURE);
6800e3d5408SPeter Wemm 	}
6810e3d5408SPeter Wemm     }
6820e3d5408SPeter Wemm 
68318259542SPeter Wemm     if (tmp_fp == 0)
68418259542SPeter Wemm 	tmp_fp = open_input(source_file);
6850e3d5408SPeter Wemm 
6860e3d5408SPeter Wemm     if (infodump)
6870e3d5408SPeter Wemm 	dump_init(tversion,
6880e3d5408SPeter Wemm 		  smart_defaults
6890e3d5408SPeter Wemm 		  ? outform
6900e3d5408SPeter Wemm 		  : F_LITERAL,
6910e3d5408SPeter Wemm 		  sortmode, width, debug_level, formatted);
6920e3d5408SPeter Wemm     else if (capdump)
6930e3d5408SPeter Wemm 	dump_init(tversion,
6940e3d5408SPeter Wemm 		  outform,
6950e3d5408SPeter Wemm 		  sortmode, width, debug_level, FALSE);
6960e3d5408SPeter Wemm 
6970e3d5408SPeter Wemm     /* parse entries out of the source file */
6980e3d5408SPeter Wemm     _nc_set_source(source_file);
69918259542SPeter Wemm #if !HAVE_BIG_CORE
7000e3d5408SPeter Wemm     if (!(check_only || infodump || capdump))
7010e3d5408SPeter Wemm 	_nc_set_writedir(outdir);
7020e3d5408SPeter Wemm #endif /* HAVE_BIG_CORE */
7030e3d5408SPeter Wemm     _nc_read_entry_source(tmp_fp, (char *) NULL,
7044a1a9510SRong-En Fan 			  !smart_defaults || literal, FALSE,
7054a1a9510SRong-En Fan 			  ((check_only || infodump || capdump)
7064a1a9510SRong-En Fan 			   ? NULLHOOK
7074a1a9510SRong-En Fan 			   : immedhook));
7080e3d5408SPeter Wemm 
7090e3d5408SPeter Wemm     /* do use resolution */
7100e3d5408SPeter Wemm     if (check_only || (!infodump && !capdump) || forceresolve) {
7114a1a9510SRong-En Fan 	if (!_nc_resolve_uses2(TRUE, literal) && !check_only) {
7125d08fb1fSRong-En Fan 	    cleanup(namelst);
7134a1a9510SRong-En Fan 	    ExitProgram(EXIT_FAILURE);
7140e3d5408SPeter Wemm 	}
7150e3d5408SPeter Wemm     }
7160e3d5408SPeter Wemm 
7170e3d5408SPeter Wemm     /* length check */
71815589c42SPeter Wemm     if (check_only && (capdump || infodump)) {
71915589c42SPeter Wemm 	for_entry_list(qp) {
72015589c42SPeter Wemm 	    if (matches(namelst, qp->tterm.term_names)) {
7214a1a9510SRong-En Fan 		int len = fmt_entry(&qp->tterm, NULL, FALSE, TRUE, infodump, numbers);
7220e3d5408SPeter Wemm 
7230e3d5408SPeter Wemm 		if (len > (infodump ? MAX_TERMINFO_LENGTH : MAX_TERMCAP_LENGTH))
7240e3d5408SPeter Wemm 		    (void) fprintf(stderr,
7250e3d5408SPeter Wemm 				   "warning: resolved %s entry is %d bytes long\n",
7260e3d5408SPeter Wemm 				   _nc_first_name(qp->tterm.term_names),
7270e3d5408SPeter Wemm 				   len);
7280e3d5408SPeter Wemm 	    }
7290e3d5408SPeter Wemm 	}
7300e3d5408SPeter Wemm     }
7310e3d5408SPeter Wemm 
7320e3d5408SPeter Wemm     /* write or dump all entries */
73315589c42SPeter Wemm     if (!check_only) {
73415589c42SPeter Wemm 	if (!infodump && !capdump) {
7350e3d5408SPeter Wemm 	    _nc_set_writedir(outdir);
73615589c42SPeter Wemm 	    for_entry_list(qp) {
7370e3d5408SPeter Wemm 		if (matches(namelst, qp->tterm.term_names))
7380e3d5408SPeter Wemm 		    write_it(qp);
7390e3d5408SPeter Wemm 	    }
74015589c42SPeter Wemm 	} else {
7410e3d5408SPeter Wemm 	    /* this is in case infotocap() generates warnings */
7420e3d5408SPeter Wemm 	    _nc_curr_col = _nc_curr_line = -1;
7430e3d5408SPeter Wemm 
74415589c42SPeter Wemm 	    for_entry_list(qp) {
74515589c42SPeter Wemm 		if (matches(namelst, qp->tterm.term_names)) {
7460e3d5408SPeter Wemm 		    int j = qp->cend - qp->cstart;
7470e3d5408SPeter Wemm 		    int len = 0;
7480e3d5408SPeter Wemm 
7490e3d5408SPeter Wemm 		    /* this is in case infotocap() generates warnings */
7500e3d5408SPeter Wemm 		    _nc_set_type(_nc_first_name(qp->tterm.term_names));
7510e3d5408SPeter Wemm 
7520e3d5408SPeter Wemm 		    (void) fseek(tmp_fp, qp->cstart, SEEK_SET);
7534a1a9510SRong-En Fan 		    while (j-- > 0) {
7540e3d5408SPeter Wemm 			if (infodump)
7550e3d5408SPeter Wemm 			    (void) putchar(fgetc(tmp_fp));
7560e3d5408SPeter Wemm 			else
7570e3d5408SPeter Wemm 			    put_translate(fgetc(tmp_fp));
75815589c42SPeter Wemm 		    }
7590e3d5408SPeter Wemm 
7604a1a9510SRong-En Fan 		    dump_entry(&qp->tterm, suppress_untranslatable,
7614a1a9510SRong-En Fan 			       limited, numbers, NULL);
7625d08fb1fSRong-En Fan 		    for (j = 0; j < (int) qp->nuses; j++)
7634a1a9510SRong-En Fan 			dump_uses(qp->uses[j].name, !capdump);
7644a1a9510SRong-En Fan 		    len = show_entry();
7650e3d5408SPeter Wemm 		    if (debug_level != 0 && !limited)
7660e3d5408SPeter Wemm 			printf("# length=%d\n", len);
7670e3d5408SPeter Wemm 		}
76815589c42SPeter Wemm 	    }
7697a69bbfbSPeter Wemm 	    if (!namelst && _nc_tail) {
7700e3d5408SPeter Wemm 		int c, oldc = '\0';
7710e3d5408SPeter Wemm 		bool in_comment = FALSE;
7720e3d5408SPeter Wemm 		bool trailing_comment = FALSE;
7730e3d5408SPeter Wemm 
7740e3d5408SPeter Wemm 		(void) fseek(tmp_fp, _nc_tail->cend, SEEK_SET);
77515589c42SPeter Wemm 		while ((c = fgetc(tmp_fp)) != EOF) {
7760e3d5408SPeter Wemm 		    if (oldc == '\n') {
7770e3d5408SPeter Wemm 			if (c == '#') {
7780e3d5408SPeter Wemm 			    trailing_comment = TRUE;
7790e3d5408SPeter Wemm 			    in_comment = TRUE;
7800e3d5408SPeter Wemm 			} else {
7810e3d5408SPeter Wemm 			    in_comment = FALSE;
7820e3d5408SPeter Wemm 			}
7830e3d5408SPeter Wemm 		    }
7840e3d5408SPeter Wemm 		    if (trailing_comment
7850e3d5408SPeter Wemm 			&& (in_comment || (oldc == '\n' && c == '\n')))
7860e3d5408SPeter Wemm 			putchar(c);
7870e3d5408SPeter Wemm 		    oldc = c;
7880e3d5408SPeter Wemm 		}
7890e3d5408SPeter Wemm 	    }
7900e3d5408SPeter Wemm 	}
7910e3d5408SPeter Wemm     }
7920e3d5408SPeter Wemm 
7930e3d5408SPeter Wemm     /* Show the directory into which entries were written, and the total
7940e3d5408SPeter Wemm      * number of entries
7950e3d5408SPeter Wemm      */
7960e3d5408SPeter Wemm     if (showsummary
7970e3d5408SPeter Wemm 	&& (!(check_only || infodump || capdump))) {
7980e3d5408SPeter Wemm 	int total = _nc_tic_written();
7990e3d5408SPeter Wemm 	if (total != 0)
8000e3d5408SPeter Wemm 	    fprintf(log_fp, "%d entries written to %s\n",
8010e3d5408SPeter Wemm 		    total,
8020e3d5408SPeter Wemm 		    _nc_tic_dir((char *) 0));
8030e3d5408SPeter Wemm 	else
8040e3d5408SPeter Wemm 	    fprintf(log_fp, "No entries written\n");
8050e3d5408SPeter Wemm     }
8065d08fb1fSRong-En Fan     cleanup(namelst);
8074a1a9510SRong-En Fan     ExitProgram(EXIT_SUCCESS);
8080e3d5408SPeter Wemm }
8090e3d5408SPeter Wemm 
8100e3d5408SPeter Wemm /*
8110e3d5408SPeter Wemm  * This bit of legerdemain turns all the terminfo variable names into
8120e3d5408SPeter Wemm  * references to locations in the arrays Booleans, Numbers, and Strings ---
8130e3d5408SPeter Wemm  * precisely what's needed (see comp_parse.c).
8140e3d5408SPeter Wemm  */
8150e3d5408SPeter Wemm #undef CUR
8160e3d5408SPeter Wemm #define CUR tp->
8170e3d5408SPeter Wemm 
81815589c42SPeter Wemm /*
8194a1a9510SRong-En Fan  * Check if the alternate character-set capabilities are consistent.
8204a1a9510SRong-En Fan  */
8214a1a9510SRong-En Fan static void
8224a1a9510SRong-En Fan check_acs(TERMTYPE *tp)
8234a1a9510SRong-En Fan {
8244a1a9510SRong-En Fan     if (VALID_STRING(acs_chars)) {
8254a1a9510SRong-En Fan 	const char *boxes = "lmkjtuvwqxn";
8264a1a9510SRong-En Fan 	char mapped[256];
8274a1a9510SRong-En Fan 	char missing[256];
8284a1a9510SRong-En Fan 	const char *p;
8294a1a9510SRong-En Fan 	char *q;
8304a1a9510SRong-En Fan 
8314a1a9510SRong-En Fan 	memset(mapped, 0, sizeof(mapped));
8324a1a9510SRong-En Fan 	for (p = acs_chars; *p != '\0'; p += 2) {
8334a1a9510SRong-En Fan 	    if (p[1] == '\0') {
8344a1a9510SRong-En Fan 		_nc_warning("acsc has odd number of characters");
8354a1a9510SRong-En Fan 		break;
8364a1a9510SRong-En Fan 	    }
8374a1a9510SRong-En Fan 	    mapped[UChar(p[0])] = p[1];
8384a1a9510SRong-En Fan 	}
8395d08fb1fSRong-En Fan 
8404a1a9510SRong-En Fan 	if (mapped[UChar('I')] && !mapped[UChar('i')]) {
8414a1a9510SRong-En Fan 	    _nc_warning("acsc refers to 'I', which is probably an error");
8424a1a9510SRong-En Fan 	}
8435d08fb1fSRong-En Fan 
8444a1a9510SRong-En Fan 	for (p = boxes, q = missing; *p != '\0'; ++p) {
8454a1a9510SRong-En Fan 	    if (!mapped[UChar(p[0])]) {
8464a1a9510SRong-En Fan 		*q++ = p[0];
8474a1a9510SRong-En Fan 	    }
8484a1a9510SRong-En Fan 	}
8495d08fb1fSRong-En Fan 	*q = '\0';
8505d08fb1fSRong-En Fan 
8515d08fb1fSRong-En Fan 	assert(strlen(missing) <= strlen(boxes));
8524a1a9510SRong-En Fan 	if (*missing != '\0' && strcmp(missing, boxes)) {
8534a1a9510SRong-En Fan 	    _nc_warning("acsc is missing some line-drawing mapping: %s", missing);
8544a1a9510SRong-En Fan 	}
8554a1a9510SRong-En Fan     }
8564a1a9510SRong-En Fan }
8574a1a9510SRong-En Fan 
8584a1a9510SRong-En Fan /*
8594a1a9510SRong-En Fan  * Check if the color capabilities are consistent
8604a1a9510SRong-En Fan  */
8614a1a9510SRong-En Fan static void
8624a1a9510SRong-En Fan check_colors(TERMTYPE *tp)
8634a1a9510SRong-En Fan {
8644a1a9510SRong-En Fan     if ((max_colors > 0) != (max_pairs > 0)
8654a1a9510SRong-En Fan 	|| ((max_colors > max_pairs) && (initialize_pair == 0)))
8664a1a9510SRong-En Fan 	_nc_warning("inconsistent values for max_colors (%d) and max_pairs (%d)",
8674a1a9510SRong-En Fan 		    max_colors, max_pairs);
8684a1a9510SRong-En Fan 
8694a1a9510SRong-En Fan     PAIRED(set_foreground, set_background);
8704a1a9510SRong-En Fan     PAIRED(set_a_foreground, set_a_background);
8714a1a9510SRong-En Fan     PAIRED(set_color_pair, initialize_pair);
8724a1a9510SRong-En Fan 
8734a1a9510SRong-En Fan     if (VALID_STRING(set_foreground)
8744a1a9510SRong-En Fan 	&& VALID_STRING(set_a_foreground)
8754a1a9510SRong-En Fan 	&& !_nc_capcmp(set_foreground, set_a_foreground))
8764a1a9510SRong-En Fan 	_nc_warning("expected setf/setaf to be different");
8774a1a9510SRong-En Fan 
8784a1a9510SRong-En Fan     if (VALID_STRING(set_background)
8794a1a9510SRong-En Fan 	&& VALID_STRING(set_a_background)
8804a1a9510SRong-En Fan 	&& !_nc_capcmp(set_background, set_a_background))
8814a1a9510SRong-En Fan 	_nc_warning("expected setb/setab to be different");
8824a1a9510SRong-En Fan 
8834a1a9510SRong-En Fan     /* see: has_colors() */
8844a1a9510SRong-En Fan     if (VALID_NUMERIC(max_colors) && VALID_NUMERIC(max_pairs)
8854a1a9510SRong-En Fan 	&& (((set_foreground != NULL)
8864a1a9510SRong-En Fan 	     && (set_background != NULL))
8874a1a9510SRong-En Fan 	    || ((set_a_foreground != NULL)
8884a1a9510SRong-En Fan 		&& (set_a_background != NULL))
8894a1a9510SRong-En Fan 	    || set_color_pair)) {
8904a1a9510SRong-En Fan 	if (!VALID_STRING(orig_pair) && !VALID_STRING(orig_colors))
8914a1a9510SRong-En Fan 	    _nc_warning("expected either op/oc string for resetting colors");
8924a1a9510SRong-En Fan     }
8934a1a9510SRong-En Fan }
8944a1a9510SRong-En Fan 
8955d08fb1fSRong-En Fan static char
8964a1a9510SRong-En Fan keypad_final(const char *string)
8974a1a9510SRong-En Fan {
8985d08fb1fSRong-En Fan     char result = '\0';
8994a1a9510SRong-En Fan 
9004a1a9510SRong-En Fan     if (VALID_STRING(string)
9014a1a9510SRong-En Fan 	&& *string++ == '\033'
9024a1a9510SRong-En Fan 	&& *string++ == 'O'
9034a1a9510SRong-En Fan 	&& strlen(string) == 1) {
9044a1a9510SRong-En Fan 	result = *string;
9054a1a9510SRong-En Fan     }
9064a1a9510SRong-En Fan 
9074a1a9510SRong-En Fan     return result;
9084a1a9510SRong-En Fan }
9094a1a9510SRong-En Fan 
9104a1a9510SRong-En Fan static int
9114a1a9510SRong-En Fan keypad_index(const char *string)
9124a1a9510SRong-En Fan {
9134a1a9510SRong-En Fan     char *test;
9144a1a9510SRong-En Fan     const char *list = "PQRSwxymtuvlqrsPpn";	/* app-keypad except "Enter" */
9154a1a9510SRong-En Fan     int ch;
9164a1a9510SRong-En Fan     int result = -1;
9174a1a9510SRong-En Fan 
9184a1a9510SRong-En Fan     if ((ch = keypad_final(string)) != '\0') {
9194a1a9510SRong-En Fan 	test = strchr(list, ch);
9204a1a9510SRong-En Fan 	if (test != 0)
9214a1a9510SRong-En Fan 	    result = (test - list);
9224a1a9510SRong-En Fan     }
9234a1a9510SRong-En Fan     return result;
9244a1a9510SRong-En Fan }
9254a1a9510SRong-En Fan 
9265d08fb1fSRong-En Fan #define MAX_KP 5
9274a1a9510SRong-En Fan /*
9284a1a9510SRong-En Fan  * Do a quick sanity-check for vt100-style keypads to see if the 5-key keypad
9294a1a9510SRong-En Fan  * is mapped inconsistently.
9304a1a9510SRong-En Fan  */
9314a1a9510SRong-En Fan static void
9324a1a9510SRong-En Fan check_keypad(TERMTYPE *tp)
9334a1a9510SRong-En Fan {
9344a1a9510SRong-En Fan     char show[80];
9354a1a9510SRong-En Fan 
9364a1a9510SRong-En Fan     if (VALID_STRING(key_a1) &&
9374a1a9510SRong-En Fan 	VALID_STRING(key_a3) &&
9384a1a9510SRong-En Fan 	VALID_STRING(key_b2) &&
9394a1a9510SRong-En Fan 	VALID_STRING(key_c1) &&
9404a1a9510SRong-En Fan 	VALID_STRING(key_c3)) {
9415d08fb1fSRong-En Fan 	char final[MAX_KP + 1];
9425d08fb1fSRong-En Fan 	int list[MAX_KP];
9434a1a9510SRong-En Fan 	int increase = 0;
9444a1a9510SRong-En Fan 	int j, k, kk;
9454a1a9510SRong-En Fan 	int last;
9464a1a9510SRong-En Fan 	int test;
9474a1a9510SRong-En Fan 
9484a1a9510SRong-En Fan 	final[0] = keypad_final(key_a1);
9494a1a9510SRong-En Fan 	final[1] = keypad_final(key_a3);
9504a1a9510SRong-En Fan 	final[2] = keypad_final(key_b2);
9514a1a9510SRong-En Fan 	final[3] = keypad_final(key_c1);
9524a1a9510SRong-En Fan 	final[4] = keypad_final(key_c3);
9534a1a9510SRong-En Fan 	final[5] = '\0';
9544a1a9510SRong-En Fan 
9554a1a9510SRong-En Fan 	/* special case: legacy coding using 1,2,3,0,. on the bottom */
9565d08fb1fSRong-En Fan 	assert(strlen(final) <= MAX_KP);
9574a1a9510SRong-En Fan 	if (!strcmp(final, "qsrpn"))
9584a1a9510SRong-En Fan 	    return;
9594a1a9510SRong-En Fan 
9604a1a9510SRong-En Fan 	list[0] = keypad_index(key_a1);
9614a1a9510SRong-En Fan 	list[1] = keypad_index(key_a3);
9624a1a9510SRong-En Fan 	list[2] = keypad_index(key_b2);
9634a1a9510SRong-En Fan 	list[3] = keypad_index(key_c1);
9644a1a9510SRong-En Fan 	list[4] = keypad_index(key_c3);
9654a1a9510SRong-En Fan 
9664a1a9510SRong-En Fan 	/* check that they're all vt100 keys */
9675d08fb1fSRong-En Fan 	for (j = 0; j < MAX_KP; ++j) {
9684a1a9510SRong-En Fan 	    if (list[j] < 0) {
9694a1a9510SRong-En Fan 		return;
9704a1a9510SRong-En Fan 	    }
9714a1a9510SRong-En Fan 	}
9724a1a9510SRong-En Fan 
9734a1a9510SRong-En Fan 	/* check if they're all in increasing order */
9745d08fb1fSRong-En Fan 	for (j = 1; j < MAX_KP; ++j) {
9754a1a9510SRong-En Fan 	    if (list[j] > list[j - 1]) {
9764a1a9510SRong-En Fan 		++increase;
9774a1a9510SRong-En Fan 	    }
9784a1a9510SRong-En Fan 	}
9795d08fb1fSRong-En Fan 	if (increase != (MAX_KP - 1)) {
9804a1a9510SRong-En Fan 	    show[0] = '\0';
9814a1a9510SRong-En Fan 
9825d08fb1fSRong-En Fan 	    for (j = 0, last = -1; j < MAX_KP; ++j) {
9834a1a9510SRong-En Fan 		for (k = 0, kk = -1, test = 100; k < 5; ++k) {
9844a1a9510SRong-En Fan 		    if (list[k] > last &&
9854a1a9510SRong-En Fan 			list[k] < test) {
9864a1a9510SRong-En Fan 			test = list[k];
9874a1a9510SRong-En Fan 			kk = k;
9884a1a9510SRong-En Fan 		    }
9894a1a9510SRong-En Fan 		}
9904a1a9510SRong-En Fan 		last = test;
9915d08fb1fSRong-En Fan 		assert(strlen(show) < (MAX_KP * 4));
9924a1a9510SRong-En Fan 		switch (kk) {
9934a1a9510SRong-En Fan 		case 0:
9944a1a9510SRong-En Fan 		    strcat(show, " ka1");
9954a1a9510SRong-En Fan 		    break;
9964a1a9510SRong-En Fan 		case 1:
9974a1a9510SRong-En Fan 		    strcat(show, " ka3");
9984a1a9510SRong-En Fan 		    break;
9994a1a9510SRong-En Fan 		case 2:
10004a1a9510SRong-En Fan 		    strcat(show, " kb2");
10014a1a9510SRong-En Fan 		    break;
10024a1a9510SRong-En Fan 		case 3:
10034a1a9510SRong-En Fan 		    strcat(show, " kc1");
10044a1a9510SRong-En Fan 		    break;
10054a1a9510SRong-En Fan 		case 4:
10064a1a9510SRong-En Fan 		    strcat(show, " kc3");
10074a1a9510SRong-En Fan 		    break;
10084a1a9510SRong-En Fan 		}
10094a1a9510SRong-En Fan 	    }
10104a1a9510SRong-En Fan 
10114a1a9510SRong-En Fan 	    _nc_warning("vt100 keypad order inconsistent: %s", show);
10124a1a9510SRong-En Fan 	}
10134a1a9510SRong-En Fan 
10144a1a9510SRong-En Fan     } else if (VALID_STRING(key_a1) ||
10154a1a9510SRong-En Fan 	       VALID_STRING(key_a3) ||
10164a1a9510SRong-En Fan 	       VALID_STRING(key_b2) ||
10174a1a9510SRong-En Fan 	       VALID_STRING(key_c1) ||
10184a1a9510SRong-En Fan 	       VALID_STRING(key_c3)) {
10194a1a9510SRong-En Fan 	show[0] = '\0';
10204a1a9510SRong-En Fan 	if (keypad_index(key_a1) >= 0)
10214a1a9510SRong-En Fan 	    strcat(show, " ka1");
10224a1a9510SRong-En Fan 	if (keypad_index(key_a3) >= 0)
10234a1a9510SRong-En Fan 	    strcat(show, " ka3");
10244a1a9510SRong-En Fan 	if (keypad_index(key_b2) >= 0)
10254a1a9510SRong-En Fan 	    strcat(show, " kb2");
10264a1a9510SRong-En Fan 	if (keypad_index(key_c1) >= 0)
10274a1a9510SRong-En Fan 	    strcat(show, " kc1");
10284a1a9510SRong-En Fan 	if (keypad_index(key_c3) >= 0)
10294a1a9510SRong-En Fan 	    strcat(show, " kc3");
10304a1a9510SRong-En Fan 	if (*show != '\0')
10314a1a9510SRong-En Fan 	    _nc_warning("vt100 keypad map incomplete:%s", show);
10324a1a9510SRong-En Fan     }
10334a1a9510SRong-En Fan }
10344a1a9510SRong-En Fan 
10354a1a9510SRong-En Fan /*
103618259542SPeter Wemm  * Returns the expected number of parameters for the given capability.
103718259542SPeter Wemm  */
103818259542SPeter Wemm static int
10397a69bbfbSPeter Wemm expected_params(const char *name)
104018259542SPeter Wemm {
104118259542SPeter Wemm     /* *INDENT-OFF* */
104218259542SPeter Wemm     static const struct {
104318259542SPeter Wemm 	const char *name;
104418259542SPeter Wemm 	int count;
104518259542SPeter Wemm     } table[] = {
10467a69bbfbSPeter Wemm 	{ "S0",			1 },	/* 'screen' extension */
104718259542SPeter Wemm 	{ "birep",		2 },
104818259542SPeter Wemm 	{ "chr",		1 },
104918259542SPeter Wemm 	{ "colornm",		1 },
105018259542SPeter Wemm 	{ "cpi",		1 },
10517a69bbfbSPeter Wemm 	{ "csnm",		1 },
105218259542SPeter Wemm 	{ "csr",		2 },
105318259542SPeter Wemm 	{ "cub",		1 },
105418259542SPeter Wemm 	{ "cud",		1 },
105518259542SPeter Wemm 	{ "cuf",		1 },
105618259542SPeter Wemm 	{ "cup",		2 },
105718259542SPeter Wemm 	{ "cuu",		1 },
10587a69bbfbSPeter Wemm 	{ "cvr",		1 },
105918259542SPeter Wemm 	{ "cwin",		5 },
106018259542SPeter Wemm 	{ "dch",		1 },
10617a69bbfbSPeter Wemm 	{ "defc",		3 },
106218259542SPeter Wemm 	{ "dial",		1 },
106318259542SPeter Wemm 	{ "dispc",		1 },
106418259542SPeter Wemm 	{ "dl",			1 },
106518259542SPeter Wemm 	{ "ech",		1 },
106618259542SPeter Wemm 	{ "getm",		1 },
106718259542SPeter Wemm 	{ "hpa",		1 },
106818259542SPeter Wemm 	{ "ich",		1 },
106918259542SPeter Wemm 	{ "il",			1 },
107018259542SPeter Wemm 	{ "indn",		1 },
107118259542SPeter Wemm 	{ "initc",		4 },
107218259542SPeter Wemm 	{ "initp",		7 },
107318259542SPeter Wemm 	{ "lpi",		1 },
107418259542SPeter Wemm 	{ "mc5p",		1 },
107518259542SPeter Wemm 	{ "mrcup",		2 },
107618259542SPeter Wemm 	{ "mvpa",		1 },
107718259542SPeter Wemm 	{ "pfkey",		2 },
107818259542SPeter Wemm 	{ "pfloc",		2 },
107918259542SPeter Wemm 	{ "pfx",		2 },
108018259542SPeter Wemm 	{ "pfxl",		3 },
108118259542SPeter Wemm 	{ "pln",		2 },
108218259542SPeter Wemm 	{ "qdial",		1 },
10837a69bbfbSPeter Wemm 	{ "rcsd",		1 },
108418259542SPeter Wemm 	{ "rep",		2 },
108518259542SPeter Wemm 	{ "rin",		1 },
108618259542SPeter Wemm 	{ "sclk",		3 },
108718259542SPeter Wemm 	{ "scp",		1 },
108818259542SPeter Wemm 	{ "scs",		1 },
10897a69bbfbSPeter Wemm 	{ "scsd",		2 },
109018259542SPeter Wemm 	{ "setab",		1 },
109118259542SPeter Wemm 	{ "setaf",		1 },
109218259542SPeter Wemm 	{ "setb",		1 },
109318259542SPeter Wemm 	{ "setcolor",		1 },
109418259542SPeter Wemm 	{ "setf",		1 },
109518259542SPeter Wemm 	{ "sgr",		9 },
109618259542SPeter Wemm 	{ "sgr1",		6 },
109718259542SPeter Wemm 	{ "slength",		1 },
109818259542SPeter Wemm 	{ "slines",		1 },
1099b82face1SPeter Wemm 	{ "smgbp",		1 },	/* 2 if smgtp is not given */
1100b82face1SPeter Wemm 	{ "smglp",		1 },
110118259542SPeter Wemm 	{ "smglr",		2 },
110218259542SPeter Wemm 	{ "smgrp",		1 },
110318259542SPeter Wemm 	{ "smgtb",		2 },
11047a69bbfbSPeter Wemm 	{ "smgtp",		1 },
110518259542SPeter Wemm 	{ "tsl",		1 },
110618259542SPeter Wemm 	{ "u6",			-1 },
110718259542SPeter Wemm 	{ "vpa",		1 },
110818259542SPeter Wemm 	{ "wind",		4 },
110918259542SPeter Wemm 	{ "wingo",		1 },
111018259542SPeter Wemm     };
111118259542SPeter Wemm     /* *INDENT-ON* */
111218259542SPeter Wemm 
111318259542SPeter Wemm     unsigned n;
111418259542SPeter Wemm     int result = 0;		/* function-keys, etc., use none */
111518259542SPeter Wemm 
111618259542SPeter Wemm     for (n = 0; n < SIZEOF(table); n++) {
111718259542SPeter Wemm 	if (!strcmp(name, table[n].name)) {
111818259542SPeter Wemm 	    result = table[n].count;
111918259542SPeter Wemm 	    break;
112018259542SPeter Wemm 	}
112118259542SPeter Wemm     }
112218259542SPeter Wemm 
112318259542SPeter Wemm     return result;
112418259542SPeter Wemm }
112518259542SPeter Wemm 
112618259542SPeter Wemm /*
112718259542SPeter Wemm  * Make a quick sanity check for the parameters which are used in the given
112818259542SPeter Wemm  * strings.  If there are no "%p" tokens, then there should be no other "%"
112918259542SPeter Wemm  * markers.
113018259542SPeter Wemm  */
113118259542SPeter Wemm static void
11327a69bbfbSPeter Wemm check_params(TERMTYPE *tp, const char *name, char *value)
113318259542SPeter Wemm {
113418259542SPeter Wemm     int expected = expected_params(name);
113518259542SPeter Wemm     int actual = 0;
113618259542SPeter Wemm     int n;
113718259542SPeter Wemm     bool params[10];
113818259542SPeter Wemm     char *s = value;
113918259542SPeter Wemm 
11404a1a9510SRong-En Fan #ifdef set_top_margin_parm
1141b82face1SPeter Wemm     if (!strcmp(name, "smgbp")
1142b82face1SPeter Wemm 	&& set_top_margin_parm == 0)
1143b82face1SPeter Wemm 	expected = 2;
11444a1a9510SRong-En Fan #endif
1145b82face1SPeter Wemm 
114618259542SPeter Wemm     for (n = 0; n < 10; n++)
114718259542SPeter Wemm 	params[n] = FALSE;
114818259542SPeter Wemm 
114918259542SPeter Wemm     while (*s != 0) {
115018259542SPeter Wemm 	if (*s == '%') {
115118259542SPeter Wemm 	    if (*++s == '\0') {
115218259542SPeter Wemm 		_nc_warning("expected character after %% in %s", name);
115318259542SPeter Wemm 		break;
115418259542SPeter Wemm 	    } else if (*s == 'p') {
115518259542SPeter Wemm 		if (*++s == '\0' || !isdigit((int) *s)) {
115618259542SPeter Wemm 		    _nc_warning("expected digit after %%p in %s", name);
115718259542SPeter Wemm 		    return;
115818259542SPeter Wemm 		} else {
115918259542SPeter Wemm 		    n = (*s - '0');
116018259542SPeter Wemm 		    if (n > actual)
116118259542SPeter Wemm 			actual = n;
116218259542SPeter Wemm 		    params[n] = TRUE;
116318259542SPeter Wemm 		}
116418259542SPeter Wemm 	    }
116518259542SPeter Wemm 	}
116618259542SPeter Wemm 	s++;
116718259542SPeter Wemm     }
116818259542SPeter Wemm 
116918259542SPeter Wemm     if (params[0]) {
117018259542SPeter Wemm 	_nc_warning("%s refers to parameter 0 (%%p0), which is not allowed", name);
117118259542SPeter Wemm     }
117218259542SPeter Wemm     if (value == set_attributes || expected < 0) {
117318259542SPeter Wemm 	;
117418259542SPeter Wemm     } else if (expected != actual) {
117518259542SPeter Wemm 	_nc_warning("%s uses %d parameters, expected %d", name,
117618259542SPeter Wemm 		    actual, expected);
117718259542SPeter Wemm 	for (n = 1; n < actual; n++) {
117818259542SPeter Wemm 	    if (!params[n])
117918259542SPeter Wemm 		_nc_warning("%s omits parameter %d", name, n);
118018259542SPeter Wemm 	}
118118259542SPeter Wemm     }
118218259542SPeter Wemm }
118318259542SPeter Wemm 
1184b82face1SPeter Wemm static char *
1185b82face1SPeter Wemm skip_delay(char *s)
1186b82face1SPeter Wemm {
1187b82face1SPeter Wemm     while (*s == '/' || isdigit(UChar(*s)))
1188b82face1SPeter Wemm 	++s;
1189b82face1SPeter Wemm     return s;
1190b82face1SPeter Wemm }
1191b82face1SPeter Wemm 
119218259542SPeter Wemm /*
11934a1a9510SRong-En Fan  * Skip a delay altogether, e.g., when comparing a simple string to sgr,
11944a1a9510SRong-En Fan  * the latter may have a worst-case delay on the end.
11954a1a9510SRong-En Fan  */
11964a1a9510SRong-En Fan static char *
11974a1a9510SRong-En Fan ignore_delays(char *s)
11984a1a9510SRong-En Fan {
11994a1a9510SRong-En Fan     int delaying = 0;
12004a1a9510SRong-En Fan 
12014a1a9510SRong-En Fan     do {
12024a1a9510SRong-En Fan 	switch (*s) {
12034a1a9510SRong-En Fan 	case '$':
12044a1a9510SRong-En Fan 	    if (delaying == 0)
12054a1a9510SRong-En Fan 		delaying = 1;
12064a1a9510SRong-En Fan 	    break;
12074a1a9510SRong-En Fan 	case '<':
12084a1a9510SRong-En Fan 	    if (delaying == 1)
12094a1a9510SRong-En Fan 		delaying = 2;
12104a1a9510SRong-En Fan 	    break;
12114a1a9510SRong-En Fan 	case '\0':
12124a1a9510SRong-En Fan 	    delaying = 0;
12134a1a9510SRong-En Fan 	    break;
12144a1a9510SRong-En Fan 	default:
12154a1a9510SRong-En Fan 	    if (delaying) {
12164a1a9510SRong-En Fan 		s = skip_delay(s);
12174a1a9510SRong-En Fan 		if (*s == '>')
12184a1a9510SRong-En Fan 		    ++s;
12194a1a9510SRong-En Fan 		delaying = 0;
12204a1a9510SRong-En Fan 	    }
12214a1a9510SRong-En Fan 	    break;
12224a1a9510SRong-En Fan 	}
12234a1a9510SRong-En Fan 	if (delaying)
12244a1a9510SRong-En Fan 	    ++s;
12254a1a9510SRong-En Fan     } while (delaying);
12264a1a9510SRong-En Fan     return s;
12274a1a9510SRong-En Fan }
12284a1a9510SRong-En Fan 
12294a1a9510SRong-En Fan /*
123015589c42SPeter Wemm  * An sgr string may contain several settings other than the one we're
123115589c42SPeter Wemm  * interested in, essentially sgr0 + rmacs + whatever.  As long as the
123215589c42SPeter Wemm  * "whatever" is contained in the sgr string, that is close enough for our
123315589c42SPeter Wemm  * sanity check.
123415589c42SPeter Wemm  */
123515589c42SPeter Wemm static bool
1236b82face1SPeter Wemm similar_sgr(int num, char *a, char *b)
123715589c42SPeter Wemm {
1238b82face1SPeter Wemm     static const char *names[] =
1239b82face1SPeter Wemm     {
1240b82face1SPeter Wemm 	"none"
1241b82face1SPeter Wemm 	,"standout"
1242b82face1SPeter Wemm 	,"underline"
1243b82face1SPeter Wemm 	,"reverse"
1244b82face1SPeter Wemm 	,"blink"
1245b82face1SPeter Wemm 	,"dim"
1246b82face1SPeter Wemm 	,"bold"
1247b82face1SPeter Wemm 	,"invis"
1248b82face1SPeter Wemm 	,"protect"
1249b82face1SPeter Wemm 	,"altcharset"
1250b82face1SPeter Wemm     };
1251b82face1SPeter Wemm     char *base_a = a;
1252b82face1SPeter Wemm     char *base_b = b;
1253b82face1SPeter Wemm     int delaying = 0;
1254b82face1SPeter Wemm 
125515589c42SPeter Wemm     while (*b != 0) {
125615589c42SPeter Wemm 	while (*a != *b) {
12577a69bbfbSPeter Wemm 	    if (*a == 0) {
12587a69bbfbSPeter Wemm 		if (b[0] == '$'
12597a69bbfbSPeter Wemm 		    && b[1] == '<') {
12607a69bbfbSPeter Wemm 		    _nc_warning("Did not find delay %s", _nc_visbuf(b));
12617a69bbfbSPeter Wemm 		} else {
1262b82face1SPeter Wemm 		    _nc_warning("checking sgr(%s) %s\n\tcompare to %s\n\tunmatched %s",
1263b82face1SPeter Wemm 				names[num], _nc_visbuf2(1, base_a),
1264b82face1SPeter Wemm 				_nc_visbuf2(2, base_b),
1265b82face1SPeter Wemm 				_nc_visbuf2(3, b));
12667a69bbfbSPeter Wemm 		}
126715589c42SPeter Wemm 		return FALSE;
1268b82face1SPeter Wemm 	    } else if (delaying) {
1269b82face1SPeter Wemm 		a = skip_delay(a);
1270b82face1SPeter Wemm 		b = skip_delay(b);
1271b82face1SPeter Wemm 	    } else {
127215589c42SPeter Wemm 		a++;
127315589c42SPeter Wemm 	    }
1274b82face1SPeter Wemm 	}
1275b82face1SPeter Wemm 	switch (*a) {
1276b82face1SPeter Wemm 	case '$':
1277b82face1SPeter Wemm 	    if (delaying == 0)
1278b82face1SPeter Wemm 		delaying = 1;
1279b82face1SPeter Wemm 	    break;
1280b82face1SPeter Wemm 	case '<':
1281b82face1SPeter Wemm 	    if (delaying == 1)
1282b82face1SPeter Wemm 		delaying = 2;
1283b82face1SPeter Wemm 	    break;
1284b82face1SPeter Wemm 	default:
1285b82face1SPeter Wemm 	    delaying = 0;
1286b82face1SPeter Wemm 	    break;
1287b82face1SPeter Wemm 	}
128815589c42SPeter Wemm 	a++;
128915589c42SPeter Wemm 	b++;
129015589c42SPeter Wemm     }
12914a1a9510SRong-En Fan     /* ignore delays on the end of the string */
12924a1a9510SRong-En Fan     a = ignore_delays(a);
12934a1a9510SRong-En Fan     return ((num != 0) || (*a == 0));
129415589c42SPeter Wemm }
129515589c42SPeter Wemm 
12964a1a9510SRong-En Fan static char *
129715589c42SPeter Wemm check_sgr(TERMTYPE *tp, char *zero, int num, char *cap, const char *name)
129815589c42SPeter Wemm {
12994a1a9510SRong-En Fan     char *test;
13004a1a9510SRong-En Fan 
13014a1a9510SRong-En Fan     _nc_tparm_err = 0;
13024a1a9510SRong-En Fan     test = TPARM_9(set_attributes,
130315589c42SPeter Wemm 		   num == 1,
130415589c42SPeter Wemm 		   num == 2,
130515589c42SPeter Wemm 		   num == 3,
130615589c42SPeter Wemm 		   num == 4,
130715589c42SPeter Wemm 		   num == 5,
130815589c42SPeter Wemm 		   num == 6,
130915589c42SPeter Wemm 		   num == 7,
131015589c42SPeter Wemm 		   num == 8,
131115589c42SPeter Wemm 		   num == 9);
131215589c42SPeter Wemm     if (test != 0) {
131315589c42SPeter Wemm 	if (PRESENT(cap)) {
1314b82face1SPeter Wemm 	    if (!similar_sgr(num, test, cap)) {
1315b82face1SPeter Wemm 		_nc_warning("%s differs from sgr(%d)\n\t%s=%s\n\tsgr(%d)=%s",
1316b82face1SPeter Wemm 			    name, num,
1317b82face1SPeter Wemm 			    name, _nc_visbuf2(1, cap),
1318b82face1SPeter Wemm 			    num, _nc_visbuf2(2, test));
131915589c42SPeter Wemm 	    }
13204a1a9510SRong-En Fan 	} else if (_nc_capcmp(test, zero)) {
132115589c42SPeter Wemm 	    _nc_warning("sgr(%d) present, but not %s", num, name);
132215589c42SPeter Wemm 	}
132315589c42SPeter Wemm     } else if (PRESENT(cap)) {
132415589c42SPeter Wemm 	_nc_warning("sgr(%d) missing, but %s present", num, name);
132515589c42SPeter Wemm     }
13264a1a9510SRong-En Fan     if (_nc_tparm_err)
13274a1a9510SRong-En Fan 	_nc_warning("stack error in sgr(%d) string", num);
13284a1a9510SRong-En Fan     return test;
132915589c42SPeter Wemm }
133015589c42SPeter Wemm 
133115589c42SPeter Wemm #define CHECK_SGR(num,name) check_sgr(tp, zero, num, name, #name)
133215589c42SPeter Wemm 
13334a1a9510SRong-En Fan #ifdef TRACE
13344a1a9510SRong-En Fan /*
13354a1a9510SRong-En Fan  * If tic is compiled with TRACE, we'll be able to see the output from the
13364a1a9510SRong-En Fan  * DEBUG() macro.  But since it doesn't use traceon(), it always goes to
13374a1a9510SRong-En Fan  * the standard error.  Use this function to make it simpler to follow the
13384a1a9510SRong-En Fan  * resulting debug traces.
13394a1a9510SRong-En Fan  */
13404a1a9510SRong-En Fan static void
13414a1a9510SRong-En Fan show_where(unsigned level)
13424a1a9510SRong-En Fan {
13434a1a9510SRong-En Fan     if (_nc_tracing >= DEBUG_LEVEL(level)) {
13444a1a9510SRong-En Fan 	char my_name[256];
13454a1a9510SRong-En Fan 	_nc_get_type(my_name);
13464a1a9510SRong-En Fan 	fprintf(stderr, "\"%s\", line %d, '%s' ",
13474a1a9510SRong-En Fan 		_nc_get_source(),
13484a1a9510SRong-En Fan 		_nc_curr_line, my_name);
13494a1a9510SRong-En Fan     }
13504a1a9510SRong-En Fan }
13514a1a9510SRong-En Fan 
13524a1a9510SRong-En Fan #else
13534a1a9510SRong-En Fan #define show_where(level)	/* nothing */
13544a1a9510SRong-En Fan #endif
13554a1a9510SRong-En Fan 
13560e3d5408SPeter Wemm /* other sanity-checks (things that we don't want in the normal
13570e3d5408SPeter Wemm  * logic that reads a terminfo entry)
13580e3d5408SPeter Wemm  */
135915589c42SPeter Wemm static void
13604a1a9510SRong-En Fan check_termtype(TERMTYPE *tp, bool literal)
13610e3d5408SPeter Wemm {
13620e3d5408SPeter Wemm     bool conflict = FALSE;
13630e3d5408SPeter Wemm     unsigned j, k;
13640e3d5408SPeter Wemm     char fkeys[STRCOUNT];
13650e3d5408SPeter Wemm 
13660e3d5408SPeter Wemm     /*
13670e3d5408SPeter Wemm      * A terminal entry may contain more than one keycode assigned to
13680e3d5408SPeter Wemm      * a given string (e.g., KEY_END and KEY_LL).  But curses will only
13690e3d5408SPeter Wemm      * return one (the last one assigned).
13700e3d5408SPeter Wemm      */
13714a1a9510SRong-En Fan     if (!(_nc_syntax == SYN_TERMCAP && capdump)) {
13720e3d5408SPeter Wemm 	memset(fkeys, 0, sizeof(fkeys));
13730e3d5408SPeter Wemm 	for (j = 0; _nc_tinfo_fkeys[j].code; j++) {
13740e3d5408SPeter Wemm 	    char *a = tp->Strings[_nc_tinfo_fkeys[j].offset];
13750e3d5408SPeter Wemm 	    bool first = TRUE;
13760e3d5408SPeter Wemm 	    if (!VALID_STRING(a))
13770e3d5408SPeter Wemm 		continue;
13780e3d5408SPeter Wemm 	    for (k = j + 1; _nc_tinfo_fkeys[k].code; k++) {
13790e3d5408SPeter Wemm 		char *b = tp->Strings[_nc_tinfo_fkeys[k].offset];
13800e3d5408SPeter Wemm 		if (!VALID_STRING(b)
13810e3d5408SPeter Wemm 		    || fkeys[k])
13820e3d5408SPeter Wemm 		    continue;
13834a1a9510SRong-En Fan 		if (!_nc_capcmp(a, b)) {
13840e3d5408SPeter Wemm 		    fkeys[j] = 1;
13850e3d5408SPeter Wemm 		    fkeys[k] = 1;
13860e3d5408SPeter Wemm 		    if (first) {
13870e3d5408SPeter Wemm 			if (!conflict) {
13880e3d5408SPeter Wemm 			    _nc_warning("Conflicting key definitions (using the last)");
13890e3d5408SPeter Wemm 			    conflict = TRUE;
13900e3d5408SPeter Wemm 			}
13910e3d5408SPeter Wemm 			fprintf(stderr, "... %s is the same as %s",
13924a1a9510SRong-En Fan 				keyname((int) _nc_tinfo_fkeys[j].code),
13934a1a9510SRong-En Fan 				keyname((int) _nc_tinfo_fkeys[k].code));
13940e3d5408SPeter Wemm 			first = FALSE;
13950e3d5408SPeter Wemm 		    } else {
13960e3d5408SPeter Wemm 			fprintf(stderr, ", %s",
13974a1a9510SRong-En Fan 				keyname((int) _nc_tinfo_fkeys[k].code));
13980e3d5408SPeter Wemm 		    }
13990e3d5408SPeter Wemm 		}
14000e3d5408SPeter Wemm 	    }
14010e3d5408SPeter Wemm 	    if (!first)
14020e3d5408SPeter Wemm 		fprintf(stderr, "\n");
14030e3d5408SPeter Wemm 	}
14044a1a9510SRong-En Fan     }
14050e3d5408SPeter Wemm 
140618259542SPeter Wemm     for (j = 0; j < NUM_STRINGS(tp); j++) {
140718259542SPeter Wemm 	char *a = tp->Strings[j];
140818259542SPeter Wemm 	if (VALID_STRING(a))
140918259542SPeter Wemm 	    check_params(tp, ExtStrname(tp, j, strnames), a);
141018259542SPeter Wemm     }
141118259542SPeter Wemm 
14124a1a9510SRong-En Fan     check_acs(tp);
14134a1a9510SRong-En Fan     check_colors(tp);
14144a1a9510SRong-En Fan     check_keypad(tp);
14150e3d5408SPeter Wemm 
14160e3d5408SPeter Wemm     /*
14170e3d5408SPeter Wemm      * These may be mismatched because the terminal description relies on
14180e3d5408SPeter Wemm      * restoring the cursor visibility by resetting it.
14190e3d5408SPeter Wemm      */
142015589c42SPeter Wemm     ANDMISSING(cursor_invisible, cursor_normal);
142115589c42SPeter Wemm     ANDMISSING(cursor_visible, cursor_normal);
142215589c42SPeter Wemm 
142315589c42SPeter Wemm     if (PRESENT(cursor_visible) && PRESENT(cursor_normal)
14244a1a9510SRong-En Fan 	&& !_nc_capcmp(cursor_visible, cursor_normal))
142515589c42SPeter Wemm 	_nc_warning("cursor_visible is same as cursor_normal");
14260e3d5408SPeter Wemm 
14270e3d5408SPeter Wemm     /*
14280e3d5408SPeter Wemm      * From XSI & O'Reilly, we gather that sc/rc are required if csr is
14290e3d5408SPeter Wemm      * given, because the cursor position after the scrolling operation is
14300e3d5408SPeter Wemm      * performed is undefined.
14310e3d5408SPeter Wemm      */
143215589c42SPeter Wemm     ANDMISSING(change_scroll_region, save_cursor);
143315589c42SPeter Wemm     ANDMISSING(change_scroll_region, restore_cursor);
143415589c42SPeter Wemm 
143515589c42SPeter Wemm     if (PRESENT(set_attributes)) {
14364a1a9510SRong-En Fan 	char *zero = 0;
143715589c42SPeter Wemm 
14384a1a9510SRong-En Fan 	_nc_tparm_err = 0;
14394a1a9510SRong-En Fan 	if (PRESENT(exit_attribute_mode)) {
14404a1a9510SRong-En Fan 	    zero = strdup(CHECK_SGR(0, exit_attribute_mode));
14414a1a9510SRong-En Fan 	} else {
14424a1a9510SRong-En Fan 	    zero = strdup(TPARM_9(set_attributes, 0, 0, 0, 0, 0, 0, 0, 0, 0));
14434a1a9510SRong-En Fan 	}
14444a1a9510SRong-En Fan 	if (_nc_tparm_err)
14454a1a9510SRong-En Fan 	    _nc_warning("stack error in sgr(0) string");
14464a1a9510SRong-En Fan 
14474a1a9510SRong-En Fan 	if (zero != 0) {
144815589c42SPeter Wemm 	    CHECK_SGR(1, enter_standout_mode);
144915589c42SPeter Wemm 	    CHECK_SGR(2, enter_underline_mode);
145015589c42SPeter Wemm 	    CHECK_SGR(3, enter_reverse_mode);
145115589c42SPeter Wemm 	    CHECK_SGR(4, enter_blink_mode);
145215589c42SPeter Wemm 	    CHECK_SGR(5, enter_dim_mode);
145315589c42SPeter Wemm 	    CHECK_SGR(6, enter_bold_mode);
145415589c42SPeter Wemm 	    CHECK_SGR(7, enter_secure_mode);
145515589c42SPeter Wemm 	    CHECK_SGR(8, enter_protected_mode);
145615589c42SPeter Wemm 	    CHECK_SGR(9, enter_alt_charset_mode);
145715589c42SPeter Wemm 	    free(zero);
14584a1a9510SRong-En Fan 	} else {
14594a1a9510SRong-En Fan 	    _nc_warning("sgr(0) did not return a value");
146015589c42SPeter Wemm 	}
14614a1a9510SRong-En Fan     } else if (PRESENT(exit_attribute_mode) &&
14624a1a9510SRong-En Fan 	       set_attributes != CANCELLED_STRING) {
14634a1a9510SRong-En Fan 	if (_nc_syntax == SYN_TERMINFO)
14644a1a9510SRong-En Fan 	    _nc_warning("missing sgr string");
14654a1a9510SRong-En Fan     }
14664a1a9510SRong-En Fan 
14674a1a9510SRong-En Fan     if (PRESENT(exit_attribute_mode)) {
14684a1a9510SRong-En Fan 	char *check_sgr0 = _nc_trim_sgr0(tp);
14694a1a9510SRong-En Fan 
14704a1a9510SRong-En Fan 	if (check_sgr0 == 0 || *check_sgr0 == '\0') {
14714a1a9510SRong-En Fan 	    _nc_warning("trimmed sgr0 is empty");
14724a1a9510SRong-En Fan 	} else {
14734a1a9510SRong-En Fan 	    show_where(2);
14744a1a9510SRong-En Fan 	    if (check_sgr0 != exit_attribute_mode) {
14754a1a9510SRong-En Fan 		DEBUG(2,
14764a1a9510SRong-En Fan 		      ("will trim sgr0\n\toriginal sgr0=%s\n\ttrimmed  sgr0=%s",
14774a1a9510SRong-En Fan 		       _nc_visbuf2(1, exit_attribute_mode),
14784a1a9510SRong-En Fan 		       _nc_visbuf2(2, check_sgr0)));
14794a1a9510SRong-En Fan 		free(check_sgr0);
14804a1a9510SRong-En Fan 	    } else {
14814a1a9510SRong-En Fan 		DEBUG(2,
14824a1a9510SRong-En Fan 		      ("will not trim sgr0\n\toriginal sgr0=%s",
14834a1a9510SRong-En Fan 		       _nc_visbuf(exit_attribute_mode)));
14844a1a9510SRong-En Fan 	    }
14854a1a9510SRong-En Fan 	}
14864a1a9510SRong-En Fan     }
14874a1a9510SRong-En Fan #ifdef TRACE
14884a1a9510SRong-En Fan     show_where(2);
14894a1a9510SRong-En Fan     if (!auto_right_margin) {
14904a1a9510SRong-En Fan 	DEBUG(2,
14914a1a9510SRong-En Fan 	      ("can write to lower-right directly"));
14924a1a9510SRong-En Fan     } else if (PRESENT(enter_am_mode) && PRESENT(exit_am_mode)) {
14934a1a9510SRong-En Fan 	DEBUG(2,
14944a1a9510SRong-En Fan 	      ("can write to lower-right by suppressing automargin"));
14954a1a9510SRong-En Fan     } else if ((PRESENT(enter_insert_mode) && PRESENT(exit_insert_mode))
14964a1a9510SRong-En Fan 	       || PRESENT(insert_character) || PRESENT(parm_ich)) {
14974a1a9510SRong-En Fan 	DEBUG(2,
14984a1a9510SRong-En Fan 	      ("can write to lower-right by using inserts"));
14994a1a9510SRong-En Fan     } else {
15004a1a9510SRong-En Fan 	DEBUG(2,
15014a1a9510SRong-En Fan 	      ("cannot write to lower-right"));
15024a1a9510SRong-En Fan     }
15034a1a9510SRong-En Fan #endif
15040e3d5408SPeter Wemm 
15050e3d5408SPeter Wemm     /*
15060e3d5408SPeter Wemm      * Some standard applications (e.g., vi) and some non-curses
15074a1a9510SRong-En Fan      * applications (e.g., jove) get confused if we have both ich1 and
15080e3d5408SPeter Wemm      * smir/rmir.  Let's be nice and warn about that, too, even though
15090e3d5408SPeter Wemm      * ncurses handles it.
15100e3d5408SPeter Wemm      */
15110e3d5408SPeter Wemm     if ((PRESENT(enter_insert_mode) || PRESENT(exit_insert_mode))
15124a1a9510SRong-En Fan 	&& PRESENT(parm_ich)) {
15134a1a9510SRong-En Fan 	_nc_warning("non-curses applications may be confused by ich1 with smir/rmir");
15140e3d5408SPeter Wemm     }
15150e3d5408SPeter Wemm 
15160e3d5408SPeter Wemm     /*
15170e3d5408SPeter Wemm      * Finally, do the non-verbose checks
15180e3d5408SPeter Wemm      */
15190e3d5408SPeter Wemm     if (save_check_termtype != 0)
15204a1a9510SRong-En Fan 	save_check_termtype(tp, literal);
15210e3d5408SPeter Wemm }
1522