xref: /dflybsd-src/contrib/ncurses/progs/tic.c (revision 0cadad7e49c6219b0de0675ef6a6f44683d177d4)
15f4613f2SJohn Marino /****************************************************************************
2*32bb5217SDaniel Fojt  * Copyright 2018-2019,2020 Thomas E. Dickey                                *
3*32bb5217SDaniel Fojt  * Copyright 1998-2017,2018 Free Software Foundation, Inc.                  *
45f4613f2SJohn Marino  *                                                                          *
55f4613f2SJohn Marino  * Permission is hereby granted, free of charge, to any person obtaining a  *
65f4613f2SJohn Marino  * copy of this software and associated documentation files (the            *
75f4613f2SJohn Marino  * "Software"), to deal in the Software without restriction, including      *
85f4613f2SJohn Marino  * without limitation the rights to use, copy, modify, merge, publish,      *
95f4613f2SJohn Marino  * distribute, distribute with modifications, sublicense, and/or sell       *
105f4613f2SJohn Marino  * copies of the Software, and to permit persons to whom the Software is    *
115f4613f2SJohn Marino  * furnished to do so, subject to the following conditions:                 *
125f4613f2SJohn Marino  *                                                                          *
135f4613f2SJohn Marino  * The above copyright notice and this permission notice shall be included  *
145f4613f2SJohn Marino  * in all copies or substantial portions of the Software.                   *
155f4613f2SJohn Marino  *                                                                          *
165f4613f2SJohn Marino  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
175f4613f2SJohn Marino  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
185f4613f2SJohn Marino  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
195f4613f2SJohn Marino  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
205f4613f2SJohn Marino  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
215f4613f2SJohn Marino  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
225f4613f2SJohn Marino  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
235f4613f2SJohn Marino  *                                                                          *
245f4613f2SJohn Marino  * Except as contained in this notice, the name(s) of the above copyright   *
255f4613f2SJohn Marino  * holders shall not be used in advertising or otherwise to promote the     *
265f4613f2SJohn Marino  * sale, use or other dealings in this Software without prior written       *
275f4613f2SJohn Marino  * authorization.                                                           *
285f4613f2SJohn Marino  ****************************************************************************/
295f4613f2SJohn Marino 
305f4613f2SJohn Marino /****************************************************************************
315f4613f2SJohn Marino  *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
325f4613f2SJohn Marino  *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
335f4613f2SJohn Marino  *     and: Thomas E. Dickey                        1996 on                 *
345f4613f2SJohn Marino  ****************************************************************************/
355f4613f2SJohn Marino 
365f4613f2SJohn Marino /*
375f4613f2SJohn Marino  *	tic.c --- Main program for terminfo compiler
385f4613f2SJohn Marino  *			by Eric S. Raymond
393468e90cSJohn Marino  *			and Thomas E Dickey
405f4613f2SJohn Marino  *
415f4613f2SJohn Marino  */
425f4613f2SJohn Marino 
435f4613f2SJohn Marino #include <progs.priv.h>
445f4613f2SJohn Marino #include <sys/stat.h>
455f4613f2SJohn Marino 
465f4613f2SJohn Marino #include <dump_entry.h>
473468e90cSJohn Marino #include <tparm_type.h>
483468e90cSJohn Marino #include <hashed_db.h>
493468e90cSJohn Marino #include <parametrized.h>
505f4613f2SJohn Marino #include <transform.h>
515f4613f2SJohn Marino 
52*32bb5217SDaniel Fojt MODULE_ID("$Id: tic.c,v 1.282 2020/02/02 23:34:34 tom Exp $")
533468e90cSJohn Marino 
543468e90cSJohn Marino #define STDIN_NAME "<stdin>"
555f4613f2SJohn Marino 
565f4613f2SJohn Marino const char *_nc_progname = "tic";
575f4613f2SJohn Marino 
585f4613f2SJohn Marino static FILE *log_fp;
595f4613f2SJohn Marino static FILE *tmp_fp;
605f4613f2SJohn Marino static bool capdump = FALSE;	/* running as infotocap? */
615f4613f2SJohn Marino static bool infodump = FALSE;	/* running as captoinfo? */
625f4613f2SJohn Marino static bool showsummary = FALSE;
63*32bb5217SDaniel Fojt static unsigned debug_level;
643468e90cSJohn Marino static char **namelst = 0;
655f4613f2SJohn Marino static const char *to_remove;
665f4613f2SJohn Marino 
67*32bb5217SDaniel Fojt #if NCURSES_XNAMES
68*32bb5217SDaniel Fojt static bool using_extensions = FALSE;
69*32bb5217SDaniel Fojt #endif
70*32bb5217SDaniel Fojt 
71*32bb5217SDaniel Fojt static void (*save_check_termtype) (TERMTYPE2 *, bool);
72*32bb5217SDaniel Fojt static void check_termtype(TERMTYPE2 *tt, bool);
735f4613f2SJohn Marino 
745f4613f2SJohn Marino static const char usage_string[] = "\
755f4613f2SJohn Marino [-e names] \
765f4613f2SJohn Marino [-o dir] \
775f4613f2SJohn Marino [-R name] \
785f4613f2SJohn Marino [-v[n]] \
795f4613f2SJohn Marino [-V] \
805f4613f2SJohn Marino [-w[n]] \
815f4613f2SJohn Marino [-\
825f4613f2SJohn Marino 1\
835f4613f2SJohn Marino a\
845f4613f2SJohn Marino C\
853468e90cSJohn Marino D\
865f4613f2SJohn Marino c\
875f4613f2SJohn Marino f\
885f4613f2SJohn Marino G\
895f4613f2SJohn Marino g\
905f4613f2SJohn Marino I\
913468e90cSJohn Marino K\
925f4613f2SJohn Marino L\
935f4613f2SJohn Marino N\
945f4613f2SJohn Marino r\
955f4613f2SJohn Marino s\
965f4613f2SJohn Marino T\
975f4613f2SJohn Marino t\
985f4613f2SJohn Marino U\
995f4613f2SJohn Marino x\
1005f4613f2SJohn Marino ] \
1015f4613f2SJohn Marino source-file\n";
1025f4613f2SJohn Marino 
1035f4613f2SJohn Marino #if NO_LEAKS
1045f4613f2SJohn Marino static void
free_namelist(char ** src)1055f4613f2SJohn Marino free_namelist(char **src)
1065f4613f2SJohn Marino {
1075f4613f2SJohn Marino     if (src != 0) {
1085f4613f2SJohn Marino 	int n;
1095f4613f2SJohn Marino 	for (n = 0; src[n] != 0; ++n)
1105f4613f2SJohn Marino 	    free(src[n]);
1115f4613f2SJohn Marino 	free(src);
1125f4613f2SJohn Marino     }
1135f4613f2SJohn Marino }
1145f4613f2SJohn Marino #endif
1155f4613f2SJohn Marino 
1165f4613f2SJohn Marino static void
cleanup(void)1173468e90cSJohn Marino cleanup(void)
1185f4613f2SJohn Marino {
1193468e90cSJohn Marino     int rc;
1203468e90cSJohn Marino 
1215f4613f2SJohn Marino #if NO_LEAKS
1225f4613f2SJohn Marino     free_namelist(namelst);
123*32bb5217SDaniel Fojt     _nc_leaks_dump_entry();
1245f4613f2SJohn Marino #endif
1255f4613f2SJohn Marino     if (tmp_fp != 0)
1265f4613f2SJohn Marino 	fclose(tmp_fp);
1275f4613f2SJohn Marino     if (to_remove != 0) {
1285f4613f2SJohn Marino #if HAVE_REMOVE
1293468e90cSJohn Marino 	rc = remove(to_remove);
1305f4613f2SJohn Marino #else
1313468e90cSJohn Marino 	rc = unlink(to_remove);
1325f4613f2SJohn Marino #endif
1333468e90cSJohn Marino 	if (rc != 0)
1343468e90cSJohn Marino 	    perror(to_remove);
1355f4613f2SJohn Marino     }
1365f4613f2SJohn Marino }
1375f4613f2SJohn Marino 
1385f4613f2SJohn Marino static void
failed(const char * msg)1395f4613f2SJohn Marino failed(const char *msg)
1405f4613f2SJohn Marino {
1415f4613f2SJohn Marino     perror(msg);
1425f4613f2SJohn Marino     ExitProgram(EXIT_FAILURE);
1435f4613f2SJohn Marino }
1445f4613f2SJohn Marino 
1455f4613f2SJohn Marino static void
usage(void)1465f4613f2SJohn Marino usage(void)
1475f4613f2SJohn Marino {
1483468e90cSJohn Marino #define DATA(s) s "\n"
1493468e90cSJohn Marino     static const char options_string[] =
1505f4613f2SJohn Marino     {
1513468e90cSJohn Marino 	DATA("Options:")
1523468e90cSJohn Marino 	DATA("  -0         format translation output all capabilities on one line")
1533468e90cSJohn Marino 	DATA("  -1         format translation output one capability per line")
1545f4613f2SJohn Marino #if NCURSES_XNAMES
1553468e90cSJohn Marino 	DATA("  -a         retain commented-out capabilities (sets -x also)")
1565f4613f2SJohn Marino #endif
1573468e90cSJohn Marino 	DATA("  -C         translate entries to termcap source form")
1583468e90cSJohn Marino 	DATA("  -D         print list of tic's database locations (first must be writable)")
1593468e90cSJohn Marino 	DATA("  -c         check only, validate input without compiling or translating")
1603468e90cSJohn Marino 	DATA("  -e<names>  translate/compile only entries named by comma-separated list")
1613468e90cSJohn Marino 	DATA("  -f         format complex strings for readability")
1623468e90cSJohn Marino 	DATA("  -G         format %{number} to %'char'")
1633468e90cSJohn Marino 	DATA("  -g         format %'char' to %{number}")
1643468e90cSJohn Marino 	DATA("  -I         translate entries to terminfo source form")
1653468e90cSJohn Marino 	DATA("  -K         translate entries to termcap source form with BSD syntax")
1663468e90cSJohn Marino 	DATA("  -L         translate entries to full terminfo source form")
1673468e90cSJohn Marino 	DATA("  -N         disable smart defaults for source translation")
1683468e90cSJohn Marino 	DATA("  -o<dir>    set output directory for compiled entry writes")
1693468e90cSJohn Marino 	DATA("  -Q[n]      dump compiled description")
1703468e90cSJohn Marino 	DATA("  -q    brief listing, removes headers")
1713468e90cSJohn Marino 	DATA("  -R<name>   restrict translation to given terminfo/termcap version")
1723468e90cSJohn Marino 	DATA("  -r         force resolution of all use entries in source translation")
1733468e90cSJohn Marino 	DATA("  -s         print summary statistics")
1743468e90cSJohn Marino 	DATA("  -T         remove size-restrictions on compiled description")
1755f4613f2SJohn Marino #if NCURSES_XNAMES
1763468e90cSJohn Marino 	DATA("  -t         suppress commented-out capabilities")
1775f4613f2SJohn Marino #endif
1783468e90cSJohn Marino 	DATA("  -U         suppress post-processing of entries")
1793468e90cSJohn Marino 	DATA("  -V         print version")
180*32bb5217SDaniel Fojt 	DATA("  -W         wrap long strings according to -w[n] option")
1813468e90cSJohn Marino 	DATA("  -v[n]      set verbosity level")
1823468e90cSJohn Marino 	DATA("  -w[n]      set format width for translation output")
1835f4613f2SJohn Marino #if NCURSES_XNAMES
1843468e90cSJohn Marino 	DATA("  -x         treat unknown capabilities as user-defined")
1855f4613f2SJohn Marino #endif
1863468e90cSJohn Marino 	DATA("")
1873468e90cSJohn Marino 	DATA("Parameters:")
1883468e90cSJohn Marino 	DATA("  <file>     file to translate or compile")
1895f4613f2SJohn Marino     };
1903468e90cSJohn Marino #undef DATA
1915f4613f2SJohn Marino 
1925f4613f2SJohn Marino     fprintf(stderr, "Usage: %s %s\n", _nc_progname, usage_string);
1933468e90cSJohn Marino     fputs(options_string, stderr);
1945f4613f2SJohn Marino     ExitProgram(EXIT_FAILURE);
1955f4613f2SJohn Marino }
1965f4613f2SJohn Marino 
1975f4613f2SJohn Marino #define L_BRACE '{'
1985f4613f2SJohn Marino #define R_BRACE '}'
1993468e90cSJohn Marino #define S_QUOTE '\''
2005f4613f2SJohn Marino 
2015f4613f2SJohn Marino static void
write_it(ENTRY * ep)2025f4613f2SJohn Marino write_it(ENTRY * ep)
2035f4613f2SJohn Marino {
2045f4613f2SJohn Marino     unsigned n;
2055f4613f2SJohn Marino     int ch;
2065f4613f2SJohn Marino     char *s, *d, *t;
2075f4613f2SJohn Marino     char result[MAX_ENTRY_SIZE];
2085f4613f2SJohn Marino 
2095f4613f2SJohn Marino     /*
2105f4613f2SJohn Marino      * Look for strings that contain %{number}, convert them to %'char',
2115f4613f2SJohn Marino      * which is shorter and runs a little faster.
2125f4613f2SJohn Marino      */
2135f4613f2SJohn Marino     for (n = 0; n < STRCOUNT; n++) {
2145f4613f2SJohn Marino 	s = ep->tterm.Strings[n];
2155f4613f2SJohn Marino 	if (VALID_STRING(s)
2165f4613f2SJohn Marino 	    && strchr(s, L_BRACE) != 0) {
2175f4613f2SJohn Marino 	    d = result;
2185f4613f2SJohn Marino 	    t = s;
2195f4613f2SJohn Marino 	    while ((ch = *t++) != 0) {
2205f4613f2SJohn Marino 		*d++ = (char) ch;
2215f4613f2SJohn Marino 		if (ch == '\\') {
222*32bb5217SDaniel Fojt 		    if ((*d++ = *t++) == '\0')
223*32bb5217SDaniel Fojt 			break;
2245f4613f2SJohn Marino 		} else if ((ch == '%')
2255f4613f2SJohn Marino 			   && (*t == L_BRACE)) {
2265f4613f2SJohn Marino 		    char *v = 0;
2275f4613f2SJohn Marino 		    long value = strtol(t + 1, &v, 0);
2285f4613f2SJohn Marino 		    if (v != 0
2295f4613f2SJohn Marino 			&& *v == R_BRACE
2305f4613f2SJohn Marino 			&& value > 0
2315f4613f2SJohn Marino 			&& value != '\\'	/* FIXME */
2325f4613f2SJohn Marino 			&& value < 127
2335f4613f2SJohn Marino 			&& isprint((int) value)) {
2345f4613f2SJohn Marino 			*d++ = S_QUOTE;
2355f4613f2SJohn Marino 			*d++ = (char) value;
2365f4613f2SJohn Marino 			*d++ = S_QUOTE;
2375f4613f2SJohn Marino 			t = (v + 1);
2385f4613f2SJohn Marino 		    }
2395f4613f2SJohn Marino 		}
2405f4613f2SJohn Marino 	    }
2415f4613f2SJohn Marino 	    *d = 0;
2425f4613f2SJohn Marino 	    if (strlen(result) < strlen(s))
2433468e90cSJohn Marino 		_nc_STRCPY(s, result, strlen(s) + 1);
2445f4613f2SJohn Marino 	}
2455f4613f2SJohn Marino     }
2465f4613f2SJohn Marino 
2475f4613f2SJohn Marino     _nc_set_type(_nc_first_name(ep->tterm.term_names));
2483468e90cSJohn Marino     _nc_curr_line = (int) ep->startline;
2495f4613f2SJohn Marino     _nc_write_entry(&ep->tterm);
2505f4613f2SJohn Marino }
2515f4613f2SJohn Marino 
2525f4613f2SJohn Marino static bool
immedhook(ENTRY * ep GCC_UNUSED)2535f4613f2SJohn Marino immedhook(ENTRY * ep GCC_UNUSED)
2545f4613f2SJohn Marino /* write out entries with no use capabilities immediately to save storage */
2555f4613f2SJohn Marino {
2565f4613f2SJohn Marino #if !HAVE_BIG_CORE
2575f4613f2SJohn Marino     /*
2585f4613f2SJohn Marino      * This is strictly a core-economy kluge.  The really clean way to handle
2595f4613f2SJohn Marino      * compilation is to slurp the whole file into core and then do all the
2605f4613f2SJohn Marino      * name-collision checks and entry writes in one swell foop.  But the
2615f4613f2SJohn Marino      * terminfo master file is large enough that some core-poor systems swap
2625f4613f2SJohn Marino      * like crazy when you compile it this way...there have been reports of
2635f4613f2SJohn Marino      * this process taking *three hours*, rather than the twenty seconds or
2645f4613f2SJohn Marino      * less typical on my development box.
2655f4613f2SJohn Marino      *
2665f4613f2SJohn Marino      * So.  This hook *immediately* writes out the referenced entry if it
2675f4613f2SJohn Marino      * has no use capabilities.  The compiler main loop refrains from
2685f4613f2SJohn Marino      * adding the entry to the in-core list when this hook fires.  If some
2695f4613f2SJohn Marino      * other entry later needs to reference an entry that got written
2705f4613f2SJohn Marino      * immediately, that's OK; the resolution code will fetch it off disk
2715f4613f2SJohn Marino      * when it can't find it in core.
2725f4613f2SJohn Marino      *
2735f4613f2SJohn Marino      * Name collisions will still be detected, just not as cleanly.  The
2745f4613f2SJohn Marino      * write_entry() code complains before overwriting an entry that
2755f4613f2SJohn Marino      * postdates the time of tic's first call to write_entry().  Thus
2765f4613f2SJohn Marino      * it will complain about overwriting entries newly made during the
2775f4613f2SJohn Marino      * tic run, but not about overwriting ones that predate it.
2785f4613f2SJohn Marino      *
2795f4613f2SJohn Marino      * The reason this is a hook, and not in line with the rest of the
2805f4613f2SJohn Marino      * compiler code, is that the support for termcap fallback cannot assume
2815f4613f2SJohn Marino      * it has anywhere to spool out these entries!
2825f4613f2SJohn Marino      *
2835f4613f2SJohn Marino      * The _nc_set_type() call here requires a compensating one in
2845f4613f2SJohn Marino      * _nc_parse_entry().
2855f4613f2SJohn Marino      *
2865f4613f2SJohn Marino      * If you define HAVE_BIG_CORE, you'll disable this kluge.  This will
2875f4613f2SJohn Marino      * make tic a bit faster (because the resolution code won't have to do
2885f4613f2SJohn Marino      * disk I/O nearly as often).
2895f4613f2SJohn Marino      */
2905f4613f2SJohn Marino     if (ep->nuses == 0) {
2915f4613f2SJohn Marino 	int oldline = _nc_curr_line;
2925f4613f2SJohn Marino 
2935f4613f2SJohn Marino 	write_it(ep);
2945f4613f2SJohn Marino 	_nc_curr_line = oldline;
2955f4613f2SJohn Marino 	free(ep->tterm.str_table);
2965f4613f2SJohn Marino 	return (TRUE);
2975f4613f2SJohn Marino     }
2985f4613f2SJohn Marino #endif /* HAVE_BIG_CORE */
2995f4613f2SJohn Marino     return (FALSE);
3005f4613f2SJohn Marino }
3015f4613f2SJohn Marino 
3025f4613f2SJohn Marino static void
put_translate(int c)3035f4613f2SJohn Marino put_translate(int c)
3045f4613f2SJohn Marino /* emit a comment char, translating terminfo names to termcap names */
3055f4613f2SJohn Marino {
3065f4613f2SJohn Marino     static bool in_name = FALSE;
3075f4613f2SJohn Marino     static size_t have, used;
3085f4613f2SJohn Marino     static char *namebuf, *suffix;
3095f4613f2SJohn Marino 
3105f4613f2SJohn Marino     if (in_name) {
3115f4613f2SJohn Marino 	if (used + 1 >= have) {
3125f4613f2SJohn Marino 	    have += 132;
3133468e90cSJohn Marino 	    if ((namebuf = typeRealloc(char, have, namebuf)) == 0)
3143468e90cSJohn Marino 		  failed("put_translate namebuf");
3153468e90cSJohn Marino 	    if ((suffix = typeRealloc(char, have, suffix)) == 0)
3163468e90cSJohn Marino 		  failed("put_translate suffix");
3175f4613f2SJohn Marino 	}
3185f4613f2SJohn Marino 	if (c == '\n' || c == '@') {
3195f4613f2SJohn Marino 	    namebuf[used++] = '\0';
3205f4613f2SJohn Marino 	    (void) putchar('<');
3215f4613f2SJohn Marino 	    (void) fputs(namebuf, stdout);
3225f4613f2SJohn Marino 	    putchar(c);
3235f4613f2SJohn Marino 	    in_name = FALSE;
3245f4613f2SJohn Marino 	} else if (c != '>') {
3255f4613f2SJohn Marino 	    namebuf[used++] = (char) c;
3265f4613f2SJohn Marino 	} else {		/* ah! candidate name! */
3275f4613f2SJohn Marino 	    char *up;
3285f4613f2SJohn Marino 	    NCURSES_CONST char *tp;
3295f4613f2SJohn Marino 
3305f4613f2SJohn Marino 	    namebuf[used++] = '\0';
3315f4613f2SJohn Marino 	    in_name = FALSE;
3325f4613f2SJohn Marino 
3335f4613f2SJohn Marino 	    suffix[0] = '\0';
3345f4613f2SJohn Marino 	    if ((up = strchr(namebuf, '#')) != 0
3355f4613f2SJohn Marino 		|| (up = strchr(namebuf, '=')) != 0
3365f4613f2SJohn Marino 		|| ((up = strchr(namebuf, '@')) != 0 && up[1] == '>')) {
3373468e90cSJohn Marino 		_nc_STRCPY(suffix, up, have);
3385f4613f2SJohn Marino 		*up = '\0';
3395f4613f2SJohn Marino 	    }
3405f4613f2SJohn Marino 
3415f4613f2SJohn Marino 	    if ((tp = nametrans(namebuf)) != 0) {
3425f4613f2SJohn Marino 		(void) putchar(':');
3435f4613f2SJohn Marino 		(void) fputs(tp, stdout);
3445f4613f2SJohn Marino 		(void) fputs(suffix, stdout);
3455f4613f2SJohn Marino 		(void) putchar(':');
3465f4613f2SJohn Marino 	    } else {
3475f4613f2SJohn Marino 		/* couldn't find a translation, just dump the name */
3485f4613f2SJohn Marino 		(void) putchar('<');
3495f4613f2SJohn Marino 		(void) fputs(namebuf, stdout);
3505f4613f2SJohn Marino 		(void) fputs(suffix, stdout);
3515f4613f2SJohn Marino 		(void) putchar('>');
3525f4613f2SJohn Marino 	    }
3535f4613f2SJohn Marino 	}
3545f4613f2SJohn Marino     } else {
3555f4613f2SJohn Marino 	used = 0;
3565f4613f2SJohn Marino 	if (c == '<') {
3575f4613f2SJohn Marino 	    in_name = TRUE;
3585f4613f2SJohn Marino 	} else {
3595f4613f2SJohn Marino 	    putchar(c);
3605f4613f2SJohn Marino 	}
3615f4613f2SJohn Marino     }
3625f4613f2SJohn Marino }
3635f4613f2SJohn Marino 
3645f4613f2SJohn Marino /* Returns a string, stripped of leading/trailing whitespace */
3655f4613f2SJohn Marino static char *
stripped(char * src)3665f4613f2SJohn Marino stripped(char *src)
3675f4613f2SJohn Marino {
3683468e90cSJohn Marino     char *dst = 0;
3693468e90cSJohn Marino 
3705f4613f2SJohn Marino     while (isspace(UChar(*src)))
3715f4613f2SJohn Marino 	src++;
3723468e90cSJohn Marino 
3735f4613f2SJohn Marino     if (*src != '\0') {
3745f4613f2SJohn Marino 	size_t len;
3755f4613f2SJohn Marino 
3763468e90cSJohn Marino 	if ((dst = strdup(src)) == NULL) {
3775f4613f2SJohn Marino 	    failed("strdup");
3783468e90cSJohn Marino 	} else {
3795f4613f2SJohn Marino 	    len = strlen(dst);
3805f4613f2SJohn Marino 	    while (--len != 0 && isspace(UChar(dst[len])))
3815f4613f2SJohn Marino 		dst[len] = '\0';
3825f4613f2SJohn Marino 	}
3833468e90cSJohn Marino     }
3843468e90cSJohn Marino     return dst;
3855f4613f2SJohn Marino }
3865f4613f2SJohn Marino 
3875f4613f2SJohn Marino static FILE *
open_tempfile(char * filename)3883468e90cSJohn Marino open_tempfile(char *filename)
3895f4613f2SJohn Marino {
3903468e90cSJohn Marino     FILE *result = 0;
3913468e90cSJohn Marino 
3923468e90cSJohn Marino     _nc_STRCPY(filename, "/tmp/XXXXXX", PATH_MAX);
3933468e90cSJohn Marino #if HAVE_MKSTEMP
3943468e90cSJohn Marino     {
3953468e90cSJohn Marino 	int oldmask = (int) umask(077);
3963468e90cSJohn Marino 	int fd = mkstemp(filename);
3973468e90cSJohn Marino 	if (fd >= 0)
3983468e90cSJohn Marino 	    result = fdopen(fd, "w");
3993468e90cSJohn Marino 	umask((mode_t) oldmask);
4003468e90cSJohn Marino     }
4013468e90cSJohn Marino #else
4023468e90cSJohn Marino     if (tmpnam(filename) != 0)
4033468e90cSJohn Marino 	result = fopen(filename, "w");
4043468e90cSJohn Marino #endif
4053468e90cSJohn Marino     return result;
4063468e90cSJohn Marino }
4073468e90cSJohn Marino 
4083468e90cSJohn Marino static FILE *
copy_input(FILE * source,const char * filename,char * alt_file)4093468e90cSJohn Marino copy_input(FILE *source, const char *filename, char *alt_file)
4103468e90cSJohn Marino {
4113468e90cSJohn Marino     char my_altfile[PATH_MAX];
4123468e90cSJohn Marino     FILE *result = 0;
4133468e90cSJohn Marino     FILE *target = 0;
4143468e90cSJohn Marino     int ch;
4153468e90cSJohn Marino 
4163468e90cSJohn Marino     if (alt_file == 0)
4173468e90cSJohn Marino 	alt_file = my_altfile;
4183468e90cSJohn Marino 
4193468e90cSJohn Marino     if (source == 0) {
4203468e90cSJohn Marino 	failed("copy_input (source)");
4213468e90cSJohn Marino     } else if ((target = open_tempfile(alt_file)) == 0) {
4223468e90cSJohn Marino 	failed("copy_input (target)");
4233468e90cSJohn Marino     } else {
4243468e90cSJohn Marino 	clearerr(source);
4253468e90cSJohn Marino 	for (;;) {
4263468e90cSJohn Marino 	    ch = fgetc(source);
4273468e90cSJohn Marino 	    if (feof(source)) {
4283468e90cSJohn Marino 		break;
4293468e90cSJohn Marino 	    } else if (ferror(source)) {
4303468e90cSJohn Marino 		failed(filename);
4313468e90cSJohn Marino 	    } else if (ch == 0) {
4323468e90cSJohn Marino 		/* don't loop in case someone wants to convert /dev/zero */
4333468e90cSJohn Marino 		fprintf(stderr, "%s: %s is not a text-file\n", _nc_progname, filename);
4343468e90cSJohn Marino 		ExitProgram(EXIT_FAILURE);
4353468e90cSJohn Marino 	    }
4363468e90cSJohn Marino 	    fputc(ch, target);
4373468e90cSJohn Marino 	}
4383468e90cSJohn Marino 	fclose(source);
4393468e90cSJohn Marino 	/*
4403468e90cSJohn Marino 	 * rewind() does not force the target file's data to disk (not does
4413468e90cSJohn Marino 	 * fflush()...).  So open a second stream on the data and then close
4423468e90cSJohn Marino 	 * the one that we were writing on before starting to read from the
4433468e90cSJohn Marino 	 * second stream.
4443468e90cSJohn Marino 	 */
4453468e90cSJohn Marino 	result = fopen(alt_file, "r+");
4463468e90cSJohn Marino 	fclose(target);
4473468e90cSJohn Marino 	to_remove = strdup(alt_file);
4483468e90cSJohn Marino     }
4493468e90cSJohn Marino     return result;
4503468e90cSJohn Marino }
4513468e90cSJohn Marino 
4523468e90cSJohn Marino static FILE *
open_input(const char * filename,char * alt_file)4533468e90cSJohn Marino open_input(const char *filename, char *alt_file)
4543468e90cSJohn Marino {
4553468e90cSJohn Marino     FILE *fp;
4565f4613f2SJohn Marino     struct stat sb;
4573468e90cSJohn Marino     int mode;
4583468e90cSJohn Marino 
4593468e90cSJohn Marino     if (!strcmp(filename, "-")) {
4603468e90cSJohn Marino 	fp = copy_input(stdin, STDIN_NAME, alt_file);
4613468e90cSJohn Marino     } else if (stat(filename, &sb) < 0) {
4623468e90cSJohn Marino 	fprintf(stderr, "%s: %s %s\n", _nc_progname, filename, strerror(errno));
4633468e90cSJohn Marino 	ExitProgram(EXIT_FAILURE);
4643468e90cSJohn Marino     } else if ((mode = (sb.st_mode & S_IFMT)) == S_IFDIR
4653468e90cSJohn Marino 	       || (mode != S_IFREG && mode != S_IFCHR && mode != S_IFIFO)) {
4663468e90cSJohn Marino 	fprintf(stderr, "%s: %s is not a file\n", _nc_progname, filename);
4673468e90cSJohn Marino 	ExitProgram(EXIT_FAILURE);
4683468e90cSJohn Marino     } else {
4693468e90cSJohn Marino 	fp = fopen(filename, "r");
4705f4613f2SJohn Marino 
4715f4613f2SJohn Marino 	if (fp == 0) {
4725f4613f2SJohn Marino 	    fprintf(stderr, "%s: Can't open %s\n", _nc_progname, filename);
4735f4613f2SJohn Marino 	    ExitProgram(EXIT_FAILURE);
4745f4613f2SJohn Marino 	}
4753468e90cSJohn Marino 	if (mode != S_IFREG) {
4763468e90cSJohn Marino 	    if (alt_file != 0) {
4773468e90cSJohn Marino 		FILE *fp2 = copy_input(fp, filename, alt_file);
4783468e90cSJohn Marino 		fp = fp2;
4793468e90cSJohn Marino 	    } else {
4805f4613f2SJohn Marino 		fprintf(stderr, "%s: %s is not a file\n", _nc_progname, filename);
4815f4613f2SJohn Marino 		ExitProgram(EXIT_FAILURE);
4825f4613f2SJohn Marino 	    }
4833468e90cSJohn Marino 	}
4843468e90cSJohn Marino     }
4855f4613f2SJohn Marino     return fp;
4865f4613f2SJohn Marino }
4875f4613f2SJohn Marino 
4885f4613f2SJohn Marino /* Parse the "-e" option-value into a list of names */
4895f4613f2SJohn Marino static char **
make_namelist(char * src)4905f4613f2SJohn Marino make_namelist(char *src)
4915f4613f2SJohn Marino {
4925f4613f2SJohn Marino     char **dst = 0;
4935f4613f2SJohn Marino 
4945f4613f2SJohn Marino     char *s, *base;
4955f4613f2SJohn Marino     unsigned pass, n, nn;
4965f4613f2SJohn Marino     char buffer[BUFSIZ];
4975f4613f2SJohn Marino 
4985f4613f2SJohn Marino     if (src == 0) {
4995f4613f2SJohn Marino 	/* EMPTY */ ;
5005f4613f2SJohn Marino     } else if (strchr(src, '/') != 0) {		/* a filename */
5013468e90cSJohn Marino 	FILE *fp = open_input(src, (char *) 0);
5025f4613f2SJohn Marino 
5035f4613f2SJohn Marino 	for (pass = 1; pass <= 2; pass++) {
5045f4613f2SJohn Marino 	    nn = 0;
5055f4613f2SJohn Marino 	    while (fgets(buffer, sizeof(buffer), fp) != 0) {
5065f4613f2SJohn Marino 		if ((s = stripped(buffer)) != 0) {
5075f4613f2SJohn Marino 		    if (dst != 0)
5085f4613f2SJohn Marino 			dst[nn] = s;
5095f4613f2SJohn Marino 		    else
5105f4613f2SJohn Marino 			free(s);
5115f4613f2SJohn Marino 		    nn++;
5125f4613f2SJohn Marino 		}
5135f4613f2SJohn Marino 	    }
5145f4613f2SJohn Marino 	    if (pass == 1) {
5153468e90cSJohn Marino 		if ((dst = typeCalloc(char *, nn + 1)) == 0)
5163468e90cSJohn Marino 		      failed("make_namelist");
5175f4613f2SJohn Marino 		rewind(fp);
5185f4613f2SJohn Marino 	    }
5195f4613f2SJohn Marino 	}
5205f4613f2SJohn Marino 	fclose(fp);
5215f4613f2SJohn Marino     } else {			/* literal list of names */
5225f4613f2SJohn Marino 	for (pass = 1; pass <= 2; pass++) {
5235f4613f2SJohn Marino 	    for (n = nn = 0, base = src;; n++) {
5245f4613f2SJohn Marino 		int mark = src[n];
5255f4613f2SJohn Marino 		if (mark == ',' || mark == '\0') {
5265f4613f2SJohn Marino 		    if (pass == 1) {
5275f4613f2SJohn Marino 			nn++;
5285f4613f2SJohn Marino 		    } else {
5295f4613f2SJohn Marino 			src[n] = '\0';
5305f4613f2SJohn Marino 			if ((s = stripped(base)) != 0)
5315f4613f2SJohn Marino 			    dst[nn++] = s;
5325f4613f2SJohn Marino 			base = &src[n + 1];
5335f4613f2SJohn Marino 		    }
5345f4613f2SJohn Marino 		}
5355f4613f2SJohn Marino 		if (mark == '\0')
5365f4613f2SJohn Marino 		    break;
5375f4613f2SJohn Marino 	    }
5383468e90cSJohn Marino 	    if (pass == 1) {
5393468e90cSJohn Marino 		if ((dst = typeCalloc(char *, nn + 1)) == 0)
5403468e90cSJohn Marino 		      failed("make_namelist");
5413468e90cSJohn Marino 	    }
5425f4613f2SJohn Marino 	}
5435f4613f2SJohn Marino     }
5445f4613f2SJohn Marino     if (showsummary && (dst != 0)) {
5455f4613f2SJohn Marino 	fprintf(log_fp, "Entries that will be compiled:\n");
5465f4613f2SJohn Marino 	for (n = 0; dst[n] != 0; n++)
5475f4613f2SJohn Marino 	    fprintf(log_fp, "%u:%s\n", n + 1, dst[n]);
5485f4613f2SJohn Marino     }
5495f4613f2SJohn Marino     return dst;
5505f4613f2SJohn Marino }
5515f4613f2SJohn Marino 
5525f4613f2SJohn Marino static bool
matches(char ** needle,const char * haystack)5535f4613f2SJohn Marino matches(char **needle, const char *haystack)
5545f4613f2SJohn Marino /* does entry in needle list match |-separated field in haystack? */
5555f4613f2SJohn Marino {
5565f4613f2SJohn Marino     bool code = FALSE;
5575f4613f2SJohn Marino     size_t n;
5585f4613f2SJohn Marino 
5595f4613f2SJohn Marino     if (needle != 0) {
5605f4613f2SJohn Marino 	for (n = 0; needle[n] != 0; n++) {
5615f4613f2SJohn Marino 	    if (_nc_name_match(haystack, needle[n], "|")) {
5625f4613f2SJohn Marino 		code = TRUE;
5635f4613f2SJohn Marino 		break;
5645f4613f2SJohn Marino 	    }
5655f4613f2SJohn Marino 	}
5665f4613f2SJohn Marino     } else
5675f4613f2SJohn Marino 	code = TRUE;
5685f4613f2SJohn Marino     return (code);
5695f4613f2SJohn Marino }
5705f4613f2SJohn Marino 
5713468e90cSJohn Marino static char *
valid_db_path(const char * nominal)5723468e90cSJohn Marino valid_db_path(const char *nominal)
5735f4613f2SJohn Marino {
5743468e90cSJohn Marino     struct stat sb;
5753468e90cSJohn Marino #if USE_HASHED_DB
5763468e90cSJohn Marino     char suffix[] = DBM_SUFFIX;
5773468e90cSJohn Marino     size_t need = strlen(nominal) + sizeof(suffix);
5783468e90cSJohn Marino     char *result = malloc(need);
5793468e90cSJohn Marino 
5803468e90cSJohn Marino     if (result == 0)
5813468e90cSJohn Marino 	failed("valid_db_path");
5823468e90cSJohn Marino     _nc_STRCPY(result, nominal, need);
5833468e90cSJohn Marino     if (strcmp(result + need - sizeof(suffix), suffix)) {
5843468e90cSJohn Marino 	_nc_STRCAT(result, suffix, need);
5853468e90cSJohn Marino     }
5865f4613f2SJohn Marino #else
5873468e90cSJohn Marino     char *result = strdup(nominal);
5885f4613f2SJohn Marino #endif
5893468e90cSJohn Marino 
5903468e90cSJohn Marino     DEBUG(1, ("** stat(%s)", result));
5913468e90cSJohn Marino     if (stat(result, &sb) >= 0) {
5923468e90cSJohn Marino #if USE_HASHED_DB
5933468e90cSJohn Marino 	if (!S_ISREG(sb.st_mode)
5943468e90cSJohn Marino 	    || access(result, R_OK | W_OK) != 0) {
5953468e90cSJohn Marino 	    DEBUG(1, ("...not a writable file"));
5963468e90cSJohn Marino 	    free(result);
5973468e90cSJohn Marino 	    result = 0;
5983468e90cSJohn Marino 	}
5993468e90cSJohn Marino #else
6003468e90cSJohn Marino 	if (!S_ISDIR(sb.st_mode)
6013468e90cSJohn Marino 	    || access(result, R_OK | W_OK | X_OK) != 0) {
6023468e90cSJohn Marino 	    DEBUG(1, ("...not a writable directory"));
6033468e90cSJohn Marino 	    free(result);
6043468e90cSJohn Marino 	    result = 0;
6053468e90cSJohn Marino 	}
6063468e90cSJohn Marino #endif
6073468e90cSJohn Marino     } else {
6083468e90cSJohn Marino 	/* check if parent is directory and is writable */
6093468e90cSJohn Marino 	unsigned leaf = _nc_pathlast(result);
6103468e90cSJohn Marino 
6113468e90cSJohn Marino 	DEBUG(1, ("...not found"));
6123468e90cSJohn Marino 	if (leaf) {
6133468e90cSJohn Marino 	    char save = result[leaf];
6143468e90cSJohn Marino 	    result[leaf] = 0;
6153468e90cSJohn Marino 	    if (stat(result, &sb) >= 0
6163468e90cSJohn Marino 		&& S_ISDIR(sb.st_mode)
6173468e90cSJohn Marino 		&& access(result, R_OK | W_OK | X_OK) == 0) {
6183468e90cSJohn Marino 		result[leaf] = save;
6193468e90cSJohn Marino 	    } else {
6203468e90cSJohn Marino 		DEBUG(1, ("...parent directory %s is not writable", result));
6213468e90cSJohn Marino 		free(result);
6223468e90cSJohn Marino 		result = 0;
6233468e90cSJohn Marino 	    }
6243468e90cSJohn Marino 	} else {
6253468e90cSJohn Marino 	    DEBUG(1, ("... no parent directory"));
6263468e90cSJohn Marino 	    free(result);
6273468e90cSJohn Marino 	    result = 0;
6283468e90cSJohn Marino 	}
6293468e90cSJohn Marino     }
6305f4613f2SJohn Marino     return result;
6315f4613f2SJohn Marino }
6325f4613f2SJohn Marino 
6333468e90cSJohn Marino /*
6343468e90cSJohn Marino  * Show the databases to which tic could write.  The location to which it
6353468e90cSJohn Marino  * writes is always the first one.  If none are writable, print an error
6363468e90cSJohn Marino  * message.
6373468e90cSJohn Marino  */
6383468e90cSJohn Marino static void
show_databases(const char * outdir)6393468e90cSJohn Marino show_databases(const char *outdir)
6403468e90cSJohn Marino {
6413468e90cSJohn Marino     bool specific = (outdir != 0) || getenv("TERMINFO") != 0;
6423468e90cSJohn Marino     char *result;
6433468e90cSJohn Marino     const char *tried = 0;
6443468e90cSJohn Marino 
6453468e90cSJohn Marino     if (outdir == 0) {
6463468e90cSJohn Marino 	outdir = _nc_tic_dir(0);
6473468e90cSJohn Marino     }
6483468e90cSJohn Marino     if ((result = valid_db_path(outdir)) != 0) {
6493468e90cSJohn Marino 	printf("%s\n", result);
6503468e90cSJohn Marino 	free(result);
6513468e90cSJohn Marino     } else {
6523468e90cSJohn Marino 	tried = outdir;
6533468e90cSJohn Marino     }
6543468e90cSJohn Marino 
6553468e90cSJohn Marino     if ((outdir = _nc_home_terminfo())) {
6563468e90cSJohn Marino 	if ((result = valid_db_path(outdir)) != 0) {
6573468e90cSJohn Marino 	    printf("%s\n", result);
6583468e90cSJohn Marino 	    free(result);
6593468e90cSJohn Marino 	} else if (!specific) {
6603468e90cSJohn Marino 	    tried = outdir;
6613468e90cSJohn Marino 	}
6623468e90cSJohn Marino     }
6633468e90cSJohn Marino 
6643468e90cSJohn Marino     /*
6653468e90cSJohn Marino      * If we can write in neither location, give an error message.
6663468e90cSJohn Marino      */
6673468e90cSJohn Marino     if (tried) {
6683468e90cSJohn Marino 	fflush(stdout);
6693468e90cSJohn Marino 	fprintf(stderr, "%s: %s (no permission)\n", _nc_progname, tried);
6703468e90cSJohn Marino 	ExitProgram(EXIT_FAILURE);
6713468e90cSJohn Marino     }
6723468e90cSJohn Marino }
6733468e90cSJohn Marino 
6743468e90cSJohn Marino static void
add_digit(int * target,int source)6753468e90cSJohn Marino add_digit(int *target, int source)
6763468e90cSJohn Marino {
6773468e90cSJohn Marino     *target = (*target * 10) + (source - '0');
6783468e90cSJohn Marino }
6793468e90cSJohn Marino 
6805f4613f2SJohn Marino int
main(int argc,char * argv[])6815f4613f2SJohn Marino main(int argc, char *argv[])
6825f4613f2SJohn Marino {
6835f4613f2SJohn Marino     char my_tmpname[PATH_MAX];
6843468e90cSJohn Marino     char my_altfile[PATH_MAX];
6853468e90cSJohn Marino     int v_opt = -1;
6865f4613f2SJohn Marino     int smart_defaults = TRUE;
6875f4613f2SJohn Marino     char *termcap;
6885f4613f2SJohn Marino     ENTRY *qp;
6895f4613f2SJohn Marino 
6905f4613f2SJohn Marino     int this_opt, last_opt = '?';
6915f4613f2SJohn Marino 
6925f4613f2SJohn Marino     int outform = F_TERMINFO;	/* output format */
6935f4613f2SJohn Marino     int sortmode = S_TERMINFO;	/* sort_mode */
6945f4613f2SJohn Marino 
6955f4613f2SJohn Marino     int width = 60;
6963468e90cSJohn Marino     int height = 65535;
6975f4613f2SJohn Marino     bool formatted = FALSE;	/* reformat complex strings? */
6985f4613f2SJohn Marino     bool literal = FALSE;	/* suppress post-processing? */
6995f4613f2SJohn Marino     int numbers = 0;		/* format "%'char'" to/from "%{number}" */
7005f4613f2SJohn Marino     bool forceresolve = FALSE;	/* force resolution */
7015f4613f2SJohn Marino     bool limited = TRUE;
7025f4613f2SJohn Marino     char *tversion = (char *) NULL;
7035f4613f2SJohn Marino     const char *source_file = "terminfo";
7045f4613f2SJohn Marino     char *outdir = (char *) NULL;
7055f4613f2SJohn Marino     bool check_only = FALSE;
7065f4613f2SJohn Marino     bool suppress_untranslatable = FALSE;
7073468e90cSJohn Marino     int quickdump = 0;
7083468e90cSJohn Marino     bool quiet = FALSE;
709*32bb5217SDaniel Fojt     bool wrap_strings = FALSE;
7105f4613f2SJohn Marino 
7115f4613f2SJohn Marino     log_fp = stderr;
7125f4613f2SJohn Marino 
7135f4613f2SJohn Marino     _nc_progname = _nc_rootname(argv[0]);
7143468e90cSJohn Marino     atexit(cleanup);
7155f4613f2SJohn Marino 
7165f4613f2SJohn Marino     if ((infodump = same_program(_nc_progname, PROG_CAPTOINFO)) != FALSE) {
7175f4613f2SJohn Marino 	outform = F_TERMINFO;
7185f4613f2SJohn Marino 	sortmode = S_TERMINFO;
7195f4613f2SJohn Marino     }
7205f4613f2SJohn Marino     if ((capdump = same_program(_nc_progname, PROG_INFOTOCAP)) != FALSE) {
7215f4613f2SJohn Marino 	outform = F_TERMCAP;
7225f4613f2SJohn Marino 	sortmode = S_TERMCAP;
7235f4613f2SJohn Marino     }
7245f4613f2SJohn Marino #if NCURSES_XNAMES
7255f4613f2SJohn Marino     use_extended_names(FALSE);
7265f4613f2SJohn Marino #endif
7273468e90cSJohn Marino     _nc_strict_bsd = 0;
7285f4613f2SJohn Marino 
7295f4613f2SJohn Marino     /*
7305f4613f2SJohn Marino      * Processing arguments is a little complicated, since someone made a
7315f4613f2SJohn Marino      * design decision to allow the numeric values for -w, -v options to
7325f4613f2SJohn Marino      * be optional.
7335f4613f2SJohn Marino      */
7345f4613f2SJohn Marino     while ((this_opt = getopt(argc, argv,
735*32bb5217SDaniel Fojt 			      "0123456789CDIKLNQR:TUVWace:fGgo:qrstvwx")) != -1) {
7365f4613f2SJohn Marino 	if (isdigit(this_opt)) {
7375f4613f2SJohn Marino 	    switch (last_opt) {
7383468e90cSJohn Marino 	    case 'Q':
7393468e90cSJohn Marino 		add_digit(&quickdump, this_opt);
7403468e90cSJohn Marino 		break;
7415f4613f2SJohn Marino 	    case 'v':
7423468e90cSJohn Marino 		add_digit(&v_opt, this_opt);
7435f4613f2SJohn Marino 		break;
7445f4613f2SJohn Marino 	    case 'w':
7453468e90cSJohn Marino 		add_digit(&width, this_opt);
7465f4613f2SJohn Marino 		break;
7475f4613f2SJohn Marino 	    default:
7483468e90cSJohn Marino 		switch (this_opt) {
7493468e90cSJohn Marino 		case '0':
7503468e90cSJohn Marino 		    last_opt = this_opt;
7513468e90cSJohn Marino 		    width = 65535;
7523468e90cSJohn Marino 		    height = 1;
7533468e90cSJohn Marino 		    break;
7543468e90cSJohn Marino 		case '1':
7555f4613f2SJohn Marino 		    last_opt = this_opt;
7565f4613f2SJohn Marino 		    width = 0;
7573468e90cSJohn Marino 		    break;
7583468e90cSJohn Marino 		default:
7593468e90cSJohn Marino 		    usage();
7603468e90cSJohn Marino 		}
7615f4613f2SJohn Marino 	    }
7625f4613f2SJohn Marino 	    continue;
7635f4613f2SJohn Marino 	}
7645f4613f2SJohn Marino 	switch (this_opt) {
7653468e90cSJohn Marino 	case 'K':
7663468e90cSJohn Marino 	    _nc_strict_bsd = 1;
7673468e90cSJohn Marino 	    /* the initial version of -K in 20110730 fell-thru here, but the
7683468e90cSJohn Marino 	     * same flag is useful when reading sources -TD
7693468e90cSJohn Marino 	     */
7703468e90cSJohn Marino 	    break;
7715f4613f2SJohn Marino 	case 'C':
7725f4613f2SJohn Marino 	    capdump = TRUE;
7735f4613f2SJohn Marino 	    outform = F_TERMCAP;
7745f4613f2SJohn Marino 	    sortmode = S_TERMCAP;
7755f4613f2SJohn Marino 	    break;
7763468e90cSJohn Marino 	case 'D':
7773468e90cSJohn Marino 	    debug_level = VtoTrace(v_opt);
7783468e90cSJohn Marino 	    set_trace_level(debug_level);
7793468e90cSJohn Marino 	    show_databases(outdir);
7803468e90cSJohn Marino 	    ExitProgram(EXIT_SUCCESS);
7813468e90cSJohn Marino 	    break;
7825f4613f2SJohn Marino 	case 'I':
7835f4613f2SJohn Marino 	    infodump = TRUE;
7845f4613f2SJohn Marino 	    outform = F_TERMINFO;
7855f4613f2SJohn Marino 	    sortmode = S_TERMINFO;
7865f4613f2SJohn Marino 	    break;
7875f4613f2SJohn Marino 	case 'L':
7885f4613f2SJohn Marino 	    infodump = TRUE;
7895f4613f2SJohn Marino 	    outform = F_VARIABLE;
7905f4613f2SJohn Marino 	    sortmode = S_VARIABLE;
7915f4613f2SJohn Marino 	    break;
7925f4613f2SJohn Marino 	case 'N':
7935f4613f2SJohn Marino 	    smart_defaults = FALSE;
7945f4613f2SJohn Marino 	    literal = TRUE;
7955f4613f2SJohn Marino 	    break;
7963468e90cSJohn Marino 	case 'Q':
7973468e90cSJohn Marino 	    quickdump = 0;
7983468e90cSJohn Marino 	    break;
7995f4613f2SJohn Marino 	case 'R':
8005f4613f2SJohn Marino 	    tversion = optarg;
8015f4613f2SJohn Marino 	    break;
8025f4613f2SJohn Marino 	case 'T':
8035f4613f2SJohn Marino 	    limited = FALSE;
8045f4613f2SJohn Marino 	    break;
8055f4613f2SJohn Marino 	case 'U':
8065f4613f2SJohn Marino 	    literal = TRUE;
8075f4613f2SJohn Marino 	    break;
8085f4613f2SJohn Marino 	case 'V':
8095f4613f2SJohn Marino 	    puts(curses_version());
8105f4613f2SJohn Marino 	    ExitProgram(EXIT_SUCCESS);
811*32bb5217SDaniel Fojt 	case 'W':
812*32bb5217SDaniel Fojt 	    wrap_strings = TRUE;
813*32bb5217SDaniel Fojt 	    break;
8145f4613f2SJohn Marino 	case 'c':
8155f4613f2SJohn Marino 	    check_only = TRUE;
8165f4613f2SJohn Marino 	    break;
8175f4613f2SJohn Marino 	case 'e':
8185f4613f2SJohn Marino 	    namelst = make_namelist(optarg);
8195f4613f2SJohn Marino 	    break;
8205f4613f2SJohn Marino 	case 'f':
8215f4613f2SJohn Marino 	    formatted = TRUE;
8225f4613f2SJohn Marino 	    break;
8235f4613f2SJohn Marino 	case 'G':
8245f4613f2SJohn Marino 	    numbers = 1;
8255f4613f2SJohn Marino 	    break;
8265f4613f2SJohn Marino 	case 'g':
8275f4613f2SJohn Marino 	    numbers = -1;
8285f4613f2SJohn Marino 	    break;
8295f4613f2SJohn Marino 	case 'o':
8305f4613f2SJohn Marino 	    outdir = optarg;
8315f4613f2SJohn Marino 	    break;
8323468e90cSJohn Marino 	case 'q':
8333468e90cSJohn Marino 	    quiet = TRUE;
8343468e90cSJohn Marino 	    break;
8355f4613f2SJohn Marino 	case 'r':
8365f4613f2SJohn Marino 	    forceresolve = TRUE;
8375f4613f2SJohn Marino 	    break;
8385f4613f2SJohn Marino 	case 's':
8395f4613f2SJohn Marino 	    showsummary = TRUE;
8405f4613f2SJohn Marino 	    break;
8415f4613f2SJohn Marino 	case 'v':
8425f4613f2SJohn Marino 	    v_opt = 0;
8435f4613f2SJohn Marino 	    break;
8445f4613f2SJohn Marino 	case 'w':
8455f4613f2SJohn Marino 	    width = 0;
8465f4613f2SJohn Marino 	    break;
8475f4613f2SJohn Marino #if NCURSES_XNAMES
8485f4613f2SJohn Marino 	case 't':
8495f4613f2SJohn Marino 	    _nc_disable_period = FALSE;
8505f4613f2SJohn Marino 	    suppress_untranslatable = TRUE;
8515f4613f2SJohn Marino 	    break;
8525f4613f2SJohn Marino 	case 'a':
8535f4613f2SJohn Marino 	    _nc_disable_period = TRUE;
8545f4613f2SJohn Marino 	    /* FALLTHRU */
8555f4613f2SJohn Marino 	case 'x':
8565f4613f2SJohn Marino 	    use_extended_names(TRUE);
857*32bb5217SDaniel Fojt 	    using_extensions = TRUE;
8585f4613f2SJohn Marino 	    break;
8595f4613f2SJohn Marino #endif
8605f4613f2SJohn Marino 	default:
8615f4613f2SJohn Marino 	    usage();
8625f4613f2SJohn Marino 	}
8635f4613f2SJohn Marino 	last_opt = this_opt;
8645f4613f2SJohn Marino     }
8655f4613f2SJohn Marino 
8663468e90cSJohn Marino     debug_level = VtoTrace(v_opt);
8675f4613f2SJohn Marino     set_trace_level(debug_level);
8685f4613f2SJohn Marino 
8695f4613f2SJohn Marino     if (_nc_tracing) {
8705f4613f2SJohn Marino 	save_check_termtype = _nc_check_termtype2;
8715f4613f2SJohn Marino 	_nc_check_termtype2 = check_termtype;
8725f4613f2SJohn Marino     }
8735f4613f2SJohn Marino #if !HAVE_BIG_CORE
8745f4613f2SJohn Marino     /*
8755f4613f2SJohn Marino      * Aaargh! immedhook seriously hoses us!
8765f4613f2SJohn Marino      *
8775f4613f2SJohn Marino      * One problem with immedhook is it means we can't do -e.  Problem
8785f4613f2SJohn Marino      * is that we can't guarantee that for each terminal listed, all the
8795f4613f2SJohn Marino      * terminals it depends on will have been kept in core for reference
8805f4613f2SJohn Marino      * resolution -- in fact it's certain the primitive types at the end
8815f4613f2SJohn Marino      * of reference chains *won't* be in core unless they were explicitly
8825f4613f2SJohn Marino      * in the select list themselves.
8835f4613f2SJohn Marino      */
8845f4613f2SJohn Marino     if (namelst && (!infodump && !capdump)) {
8855f4613f2SJohn Marino 	(void) fprintf(stderr,
8863468e90cSJohn Marino 		       "%s: Sorry, -e can't be used without -I or -C\n",
8873468e90cSJohn Marino 		       _nc_progname);
8885f4613f2SJohn Marino 	ExitProgram(EXIT_FAILURE);
8895f4613f2SJohn Marino     }
8905f4613f2SJohn Marino #endif /* HAVE_BIG_CORE */
8915f4613f2SJohn Marino 
8925f4613f2SJohn Marino     if (optind < argc) {
8935f4613f2SJohn Marino 	source_file = argv[optind++];
8945f4613f2SJohn Marino 	if (optind < argc) {
8955f4613f2SJohn Marino 	    fprintf(stderr,
8965f4613f2SJohn Marino 		    "%s: Too many file names.  Usage:\n\t%s %s",
8975f4613f2SJohn Marino 		    _nc_progname,
8985f4613f2SJohn Marino 		    _nc_progname,
8995f4613f2SJohn Marino 		    usage_string);
9005f4613f2SJohn Marino 	    ExitProgram(EXIT_FAILURE);
9015f4613f2SJohn Marino 	}
9025f4613f2SJohn Marino     } else {
9035f4613f2SJohn Marino 	if (infodump == TRUE) {
9045f4613f2SJohn Marino 	    /* captoinfo's no-argument case */
9055f4613f2SJohn Marino 	    source_file = "/etc/termcap";
9065f4613f2SJohn Marino 	    if ((termcap = getenv("TERMCAP")) != 0
9075f4613f2SJohn Marino 		&& (namelst = make_namelist(getenv("TERM"))) != 0) {
9085f4613f2SJohn Marino 		if (access(termcap, F_OK) == 0) {
9095f4613f2SJohn Marino 		    /* file exists */
9105f4613f2SJohn Marino 		    source_file = termcap;
9113468e90cSJohn Marino 		} else {
9123468e90cSJohn Marino 		    if ((tmp_fp = open_tempfile(my_tmpname)) != 0) {
9135f4613f2SJohn Marino 			source_file = my_tmpname;
9145f4613f2SJohn Marino 			fprintf(tmp_fp, "%s\n", termcap);
9155f4613f2SJohn Marino 			fclose(tmp_fp);
9163468e90cSJohn Marino 			tmp_fp = open_input(source_file, (char *) 0);
9175f4613f2SJohn Marino 			to_remove = source_file;
9185f4613f2SJohn Marino 		    } else {
9195f4613f2SJohn Marino 			failed("tmpnam");
9205f4613f2SJohn Marino 		    }
9215f4613f2SJohn Marino 		}
9223468e90cSJohn Marino 	    }
9235f4613f2SJohn Marino 	} else {
9245f4613f2SJohn Marino 	    /* tic */
9255f4613f2SJohn Marino 	    fprintf(stderr,
9265f4613f2SJohn Marino 		    "%s: File name needed.  Usage:\n\t%s %s",
9275f4613f2SJohn Marino 		    _nc_progname,
9285f4613f2SJohn Marino 		    _nc_progname,
9295f4613f2SJohn Marino 		    usage_string);
9305f4613f2SJohn Marino 	    ExitProgram(EXIT_FAILURE);
9315f4613f2SJohn Marino 	}
9325f4613f2SJohn Marino     }
9335f4613f2SJohn Marino 
9343468e90cSJohn Marino     if (tmp_fp == 0) {
9353468e90cSJohn Marino 	tmp_fp = open_input(source_file, my_altfile);
9363468e90cSJohn Marino 	if (!strcmp(source_file, "-")) {
9373468e90cSJohn Marino 	    source_file = STDIN_NAME;
9383468e90cSJohn Marino 	}
9393468e90cSJohn Marino     }
9405f4613f2SJohn Marino 
9413468e90cSJohn Marino     if (infodump || check_only) {
9425f4613f2SJohn Marino 	dump_init(tversion,
943*32bb5217SDaniel Fojt 		  (smart_defaults
9445f4613f2SJohn Marino 		   ? outform
945*32bb5217SDaniel Fojt 		   : F_LITERAL),
946*32bb5217SDaniel Fojt 		  sortmode,
947*32bb5217SDaniel Fojt 		  wrap_strings, width, height,
948*32bb5217SDaniel Fojt 		  debug_level, formatted || check_only, check_only, quickdump);
9493468e90cSJohn Marino     } else if (capdump) {
9505f4613f2SJohn Marino 	dump_init(tversion,
9515f4613f2SJohn Marino 		  outform,
952*32bb5217SDaniel Fojt 		  sortmode,
953*32bb5217SDaniel Fojt 		  wrap_strings, width, height,
954*32bb5217SDaniel Fojt 		  debug_level, FALSE, FALSE, FALSE);
9553468e90cSJohn Marino     }
9565f4613f2SJohn Marino 
9575f4613f2SJohn Marino     /* parse entries out of the source file */
9585f4613f2SJohn Marino     _nc_set_source(source_file);
9595f4613f2SJohn Marino #if !HAVE_BIG_CORE
9605f4613f2SJohn Marino     if (!(check_only || infodump || capdump))
9615f4613f2SJohn Marino 	_nc_set_writedir(outdir);
9625f4613f2SJohn Marino #endif /* HAVE_BIG_CORE */
9635f4613f2SJohn Marino     _nc_read_entry_source(tmp_fp, (char *) NULL,
9645f4613f2SJohn Marino 			  !smart_defaults || literal, FALSE,
9655f4613f2SJohn Marino 			  ((check_only || infodump || capdump)
9665f4613f2SJohn Marino 			   ? NULLHOOK
9675f4613f2SJohn Marino 			   : immedhook));
9685f4613f2SJohn Marino 
9695f4613f2SJohn Marino     /* do use resolution */
9705f4613f2SJohn Marino     if (check_only || (!infodump && !capdump) || forceresolve) {
9715f4613f2SJohn Marino 	if (!_nc_resolve_uses2(TRUE, literal) && !check_only) {
9725f4613f2SJohn Marino 	    ExitProgram(EXIT_FAILURE);
9735f4613f2SJohn Marino 	}
9745f4613f2SJohn Marino     }
9755f4613f2SJohn Marino 
9765f4613f2SJohn Marino     /* length check */
9773468e90cSJohn Marino     if (check_only && limited && (capdump || infodump)) {
9785f4613f2SJohn Marino 	for_entry_list(qp) {
9795f4613f2SJohn Marino 	    if (matches(namelst, qp->tterm.term_names)) {
9805f4613f2SJohn Marino 		int len = fmt_entry(&qp->tterm, NULL, FALSE, TRUE, infodump, numbers);
9815f4613f2SJohn Marino 
9825f4613f2SJohn Marino 		if (len > (infodump ? MAX_TERMINFO_LENGTH : MAX_TERMCAP_LENGTH))
9835f4613f2SJohn Marino 		    (void) fprintf(stderr,
984*32bb5217SDaniel Fojt 				   "%s: resolved %s entry is %d bytes long\n",
985*32bb5217SDaniel Fojt 				   _nc_progname,
9865f4613f2SJohn Marino 				   _nc_first_name(qp->tterm.term_names),
9875f4613f2SJohn Marino 				   len);
9885f4613f2SJohn Marino 	    }
9895f4613f2SJohn Marino 	}
9905f4613f2SJohn Marino     }
9915f4613f2SJohn Marino 
9925f4613f2SJohn Marino     /* write or dump all entries */
9933468e90cSJohn Marino     if (check_only) {
9943468e90cSJohn Marino 	/* this is in case infotocap() generates warnings */
9953468e90cSJohn Marino 	_nc_curr_col = _nc_curr_line = -1;
9963468e90cSJohn Marino 
9973468e90cSJohn Marino 	for_entry_list(qp) {
9983468e90cSJohn Marino 	    if (matches(namelst, qp->tterm.term_names)) {
9993468e90cSJohn Marino 		/* this is in case infotocap() generates warnings */
10003468e90cSJohn Marino 		_nc_set_type(_nc_first_name(qp->tterm.term_names));
10013468e90cSJohn Marino 		_nc_curr_line = (int) qp->startline;
10023468e90cSJohn Marino 		repair_acsc(&qp->tterm);
10033468e90cSJohn Marino 		dump_entry(&qp->tterm, suppress_untranslatable,
10043468e90cSJohn Marino 			   limited, numbers, NULL);
10053468e90cSJohn Marino 	    }
10063468e90cSJohn Marino 	}
10073468e90cSJohn Marino     } else {
10085f4613f2SJohn Marino 	if (!infodump && !capdump) {
10095f4613f2SJohn Marino 	    _nc_set_writedir(outdir);
10105f4613f2SJohn Marino 	    for_entry_list(qp) {
10115f4613f2SJohn Marino 		if (matches(namelst, qp->tterm.term_names))
10125f4613f2SJohn Marino 		    write_it(qp);
10135f4613f2SJohn Marino 	    }
10145f4613f2SJohn Marino 	} else {
10155f4613f2SJohn Marino 	    /* this is in case infotocap() generates warnings */
10165f4613f2SJohn Marino 	    _nc_curr_col = _nc_curr_line = -1;
10175f4613f2SJohn Marino 
10185f4613f2SJohn Marino 	    for_entry_list(qp) {
10195f4613f2SJohn Marino 		if (matches(namelst, qp->tterm.term_names)) {
10203468e90cSJohn Marino 		    long j = qp->cend - qp->cstart;
10215f4613f2SJohn Marino 		    int len = 0;
10225f4613f2SJohn Marino 
10235f4613f2SJohn Marino 		    /* this is in case infotocap() generates warnings */
10245f4613f2SJohn Marino 		    _nc_set_type(_nc_first_name(qp->tterm.term_names));
10255f4613f2SJohn Marino 
10263468e90cSJohn Marino 		    if (!quiet) {
10275f4613f2SJohn Marino 			(void) fseek(tmp_fp, qp->cstart, SEEK_SET);
10285f4613f2SJohn Marino 			while (j-- > 0) {
1029*32bb5217SDaniel Fojt 			    int ch = fgetc(tmp_fp);
1030*32bb5217SDaniel Fojt 			    if (ch == EOF || ferror(tmp_fp)) {
1031*32bb5217SDaniel Fojt 				break;
1032*32bb5217SDaniel Fojt 			    } else if (infodump) {
1033*32bb5217SDaniel Fojt 				(void) putchar(ch);
1034*32bb5217SDaniel Fojt 			    } else {
1035*32bb5217SDaniel Fojt 				put_translate(ch);
1036*32bb5217SDaniel Fojt 			    }
10375f4613f2SJohn Marino 			}
10383468e90cSJohn Marino 		    }
10395f4613f2SJohn Marino 
10405f4613f2SJohn Marino 		    repair_acsc(&qp->tterm);
10415f4613f2SJohn Marino 		    dump_entry(&qp->tterm, suppress_untranslatable,
10425f4613f2SJohn Marino 			       limited, numbers, NULL);
10433468e90cSJohn Marino 		    for (j = 0; j < (long) qp->nuses; j++)
10445f4613f2SJohn Marino 			dump_uses(qp->uses[j].name, !capdump);
10455f4613f2SJohn Marino 		    len = show_entry();
10465f4613f2SJohn Marino 		    if (debug_level != 0 && !limited)
10475f4613f2SJohn Marino 			printf("# length=%d\n", len);
10485f4613f2SJohn Marino 		}
10495f4613f2SJohn Marino 	    }
10503468e90cSJohn Marino 	    if (!namelst && _nc_tail && !quiet) {
10515f4613f2SJohn Marino 		int c, oldc = '\0';
10525f4613f2SJohn Marino 		bool in_comment = FALSE;
10535f4613f2SJohn Marino 		bool trailing_comment = FALSE;
10545f4613f2SJohn Marino 
10555f4613f2SJohn Marino 		(void) fseek(tmp_fp, _nc_tail->cend, SEEK_SET);
10565f4613f2SJohn Marino 		while ((c = fgetc(tmp_fp)) != EOF) {
10575f4613f2SJohn Marino 		    if (oldc == '\n') {
10585f4613f2SJohn Marino 			if (c == '#') {
10595f4613f2SJohn Marino 			    trailing_comment = TRUE;
10605f4613f2SJohn Marino 			    in_comment = TRUE;
10615f4613f2SJohn Marino 			} else {
10625f4613f2SJohn Marino 			    in_comment = FALSE;
10635f4613f2SJohn Marino 			}
10645f4613f2SJohn Marino 		    }
10655f4613f2SJohn Marino 		    if (trailing_comment
10665f4613f2SJohn Marino 			&& (in_comment || (oldc == '\n' && c == '\n')))
10675f4613f2SJohn Marino 			putchar(c);
10685f4613f2SJohn Marino 		    oldc = c;
10695f4613f2SJohn Marino 		}
10705f4613f2SJohn Marino 	    }
10715f4613f2SJohn Marino 	}
10725f4613f2SJohn Marino     }
10735f4613f2SJohn Marino 
10745f4613f2SJohn Marino     /* Show the directory into which entries were written, and the total
10755f4613f2SJohn Marino      * number of entries
10765f4613f2SJohn Marino      */
10775f4613f2SJohn Marino     if (showsummary
10785f4613f2SJohn Marino 	&& (!(check_only || infodump || capdump))) {
10795f4613f2SJohn Marino 	int total = _nc_tic_written();
10805f4613f2SJohn Marino 	if (total != 0)
10815f4613f2SJohn Marino 	    fprintf(log_fp, "%d entries written to %s\n",
10825f4613f2SJohn Marino 		    total,
10835f4613f2SJohn Marino 		    _nc_tic_dir((char *) 0));
10845f4613f2SJohn Marino 	else
10855f4613f2SJohn Marino 	    fprintf(log_fp, "No entries written\n");
10865f4613f2SJohn Marino     }
10875f4613f2SJohn Marino     ExitProgram(EXIT_SUCCESS);
10885f4613f2SJohn Marino }
10895f4613f2SJohn Marino 
10905f4613f2SJohn Marino /*
10915f4613f2SJohn Marino  * This bit of legerdemain turns all the terminfo variable names into
10925f4613f2SJohn Marino  * references to locations in the arrays Booleans, Numbers, and Strings ---
10935f4613f2SJohn Marino  * precisely what's needed (see comp_parse.c).
10945f4613f2SJohn Marino  */
10955f4613f2SJohn Marino #undef CUR
10965f4613f2SJohn Marino #define CUR tp->
10975f4613f2SJohn Marino 
10985f4613f2SJohn Marino /*
10995f4613f2SJohn Marino  * Check if the alternate character-set capabilities are consistent.
11005f4613f2SJohn Marino  */
11015f4613f2SJohn Marino static void
check_acs(TERMTYPE2 * tp)1102*32bb5217SDaniel Fojt check_acs(TERMTYPE2 *tp)
11035f4613f2SJohn Marino {
1104*32bb5217SDaniel Fojt     int vt100_smacs = 0;
1105*32bb5217SDaniel Fojt     int vt100_rmacs = 0;
1106*32bb5217SDaniel Fojt     int vt100_enacs = 0;
1107*32bb5217SDaniel Fojt 
1108*32bb5217SDaniel Fojt     /*
1109*32bb5217SDaniel Fojt      * ena_acs is not always necessary, but if it is present, the enter/exit
1110*32bb5217SDaniel Fojt      * capabilities should be.
1111*32bb5217SDaniel Fojt      */
1112*32bb5217SDaniel Fojt     ANDMISSING(ena_acs, enter_alt_charset_mode);
1113*32bb5217SDaniel Fojt     ANDMISSING(ena_acs, exit_alt_charset_mode);
1114*32bb5217SDaniel Fojt     PAIRED(exit_alt_charset_mode, exit_alt_charset_mode);
1115*32bb5217SDaniel Fojt 
1116*32bb5217SDaniel Fojt     /*
1117*32bb5217SDaniel Fojt      * vt100-like is frequently used, but perhaps ena_acs is missing, etc.
1118*32bb5217SDaniel Fojt      */
1119*32bb5217SDaniel Fojt     if (VALID_STRING(enter_alt_charset_mode)) {
1120*32bb5217SDaniel Fojt 	vt100_smacs = (!strcmp("\033(0", enter_alt_charset_mode)
1121*32bb5217SDaniel Fojt 		       ? 2
1122*32bb5217SDaniel Fojt 		       : (!strcmp("\016", enter_alt_charset_mode)
1123*32bb5217SDaniel Fojt 			  ? 1
1124*32bb5217SDaniel Fojt 			  : 0));
1125*32bb5217SDaniel Fojt     }
1126*32bb5217SDaniel Fojt     if (VALID_STRING(exit_alt_charset_mode)) {
1127*32bb5217SDaniel Fojt 	vt100_rmacs = (!strcmp("\033(B", exit_alt_charset_mode)
1128*32bb5217SDaniel Fojt 		       ? 2
1129*32bb5217SDaniel Fojt 		       : (!strcmp("\017", exit_alt_charset_mode)
1130*32bb5217SDaniel Fojt 			  ? 1
1131*32bb5217SDaniel Fojt 			  : 0));
1132*32bb5217SDaniel Fojt     }
1133*32bb5217SDaniel Fojt     if (VALID_STRING(ena_acs)) {
1134*32bb5217SDaniel Fojt 	vt100_enacs = (!strcmp("\033(B\033)0", ena_acs)
1135*32bb5217SDaniel Fojt 		       ? 2
1136*32bb5217SDaniel Fojt 		       : 0);
1137*32bb5217SDaniel Fojt     }
1138*32bb5217SDaniel Fojt     if (vt100_rmacs && vt100_smacs && (vt100_rmacs != vt100_smacs)) {
1139*32bb5217SDaniel Fojt 	_nc_warning("rmacs/smacs are inconsistent");
1140*32bb5217SDaniel Fojt     }
1141*32bb5217SDaniel Fojt     if ((vt100_rmacs == 2) && (vt100_smacs == 2) && vt100_enacs) {
1142*32bb5217SDaniel Fojt 	_nc_warning("rmacs/smacs make enacs redundant");
1143*32bb5217SDaniel Fojt     }
1144*32bb5217SDaniel Fojt     if ((vt100_rmacs == 1) && (vt100_smacs == 1) && !vt100_enacs) {
1145*32bb5217SDaniel Fojt 	_nc_warning("VT100-style rmacs/smacs require enacs");
1146*32bb5217SDaniel Fojt     }
1147*32bb5217SDaniel Fojt 
11485f4613f2SJohn Marino     if (VALID_STRING(acs_chars)) {
11495f4613f2SJohn Marino 	const char *boxes = "lmkjtuvwqxn";
11505f4613f2SJohn Marino 	char mapped[256];
11515f4613f2SJohn Marino 	char missing[256];
11525f4613f2SJohn Marino 	const char *p;
11535f4613f2SJohn Marino 	char *q;
11545f4613f2SJohn Marino 
11555f4613f2SJohn Marino 	memset(mapped, 0, sizeof(mapped));
11565f4613f2SJohn Marino 	for (p = acs_chars; *p != '\0'; p += 2) {
11575f4613f2SJohn Marino 	    if (p[1] == '\0') {
11585f4613f2SJohn Marino 		_nc_warning("acsc has odd number of characters");
11595f4613f2SJohn Marino 		break;
11605f4613f2SJohn Marino 	    }
11615f4613f2SJohn Marino 	    mapped[UChar(p[0])] = p[1];
11625f4613f2SJohn Marino 	}
11635f4613f2SJohn Marino 
11645f4613f2SJohn Marino 	if (mapped[UChar('I')] && !mapped[UChar('i')]) {
11655f4613f2SJohn Marino 	    _nc_warning("acsc refers to 'I', which is probably an error");
11665f4613f2SJohn Marino 	}
11675f4613f2SJohn Marino 
11685f4613f2SJohn Marino 	for (p = boxes, q = missing; *p != '\0'; ++p) {
11695f4613f2SJohn Marino 	    if (!mapped[UChar(p[0])]) {
11705f4613f2SJohn Marino 		*q++ = p[0];
11715f4613f2SJohn Marino 	    }
11725f4613f2SJohn Marino 	}
11735f4613f2SJohn Marino 	*q = '\0';
11745f4613f2SJohn Marino 
11755f4613f2SJohn Marino 	assert(strlen(missing) <= strlen(boxes));
11765f4613f2SJohn Marino 	if (*missing != '\0' && strcmp(missing, boxes)) {
11775f4613f2SJohn Marino 	    _nc_warning("acsc is missing some line-drawing mapping: %s", missing);
11785f4613f2SJohn Marino 	}
11795f4613f2SJohn Marino     }
11805f4613f2SJohn Marino }
11815f4613f2SJohn Marino 
1182*32bb5217SDaniel Fojt static bool
same_color(NCURSES_CONST char * oldcap,NCURSES_CONST char * newcap,int limit)1183*32bb5217SDaniel Fojt same_color(NCURSES_CONST char *oldcap, NCURSES_CONST char *newcap, int limit)
1184*32bb5217SDaniel Fojt {
1185*32bb5217SDaniel Fojt     bool result = FALSE;
1186*32bb5217SDaniel Fojt     if (limit > 16)
1187*32bb5217SDaniel Fojt 	limit = 16;
1188*32bb5217SDaniel Fojt     if (limit >= 8) {
1189*32bb5217SDaniel Fojt 	int n;
1190*32bb5217SDaniel Fojt 	int same;
1191*32bb5217SDaniel Fojt 	for (n = same = 0; n < limit; ++n) {
1192*32bb5217SDaniel Fojt 	    char *oldvalue = strdup(TPARM_1(oldcap, n));
1193*32bb5217SDaniel Fojt 	    char *newvalue = strdup(TPARM_1(newcap, n));
1194*32bb5217SDaniel Fojt 	    same += !strcmp(oldvalue, newvalue);
1195*32bb5217SDaniel Fojt 	    free(oldvalue);
1196*32bb5217SDaniel Fojt 	    free(newvalue);
1197*32bb5217SDaniel Fojt 	}
1198*32bb5217SDaniel Fojt 	result = (same == limit);
1199*32bb5217SDaniel Fojt     }
1200*32bb5217SDaniel Fojt     return result;
1201*32bb5217SDaniel Fojt }
1202*32bb5217SDaniel Fojt 
12035f4613f2SJohn Marino /*
12045f4613f2SJohn Marino  * Check if the color capabilities are consistent
12055f4613f2SJohn Marino  */
12065f4613f2SJohn Marino static void
check_colors(TERMTYPE2 * tp)1207*32bb5217SDaniel Fojt check_colors(TERMTYPE2 *tp)
12085f4613f2SJohn Marino {
1209*32bb5217SDaniel Fojt     char *value;
1210*32bb5217SDaniel Fojt 
12115f4613f2SJohn Marino     if ((max_colors > 0) != (max_pairs > 0)
12125f4613f2SJohn Marino 	|| ((max_colors > max_pairs) && (initialize_pair == 0)))
12135f4613f2SJohn Marino 	_nc_warning("inconsistent values for max_colors (%d) and max_pairs (%d)",
12145f4613f2SJohn Marino 		    max_colors, max_pairs);
12155f4613f2SJohn Marino 
12165f4613f2SJohn Marino     PAIRED(set_foreground, set_background);
12175f4613f2SJohn Marino     PAIRED(set_a_foreground, set_a_background);
12185f4613f2SJohn Marino     PAIRED(set_color_pair, initialize_pair);
12195f4613f2SJohn Marino 
12205f4613f2SJohn Marino     if (VALID_STRING(set_foreground)
1221*32bb5217SDaniel Fojt 	&& VALID_STRING(set_a_foreground)) {
1222*32bb5217SDaniel Fojt 	if (!_nc_capcmp(set_foreground, set_a_foreground)) {
12235f4613f2SJohn Marino 	    _nc_warning("expected setf/setaf to be different");
1224*32bb5217SDaniel Fojt 	} else if (same_color(set_foreground, set_a_foreground, max_colors)) {
1225*32bb5217SDaniel Fojt 	    _nc_warning("setf/setaf are equivalent");
1226*32bb5217SDaniel Fojt 	}
1227*32bb5217SDaniel Fojt     }
12285f4613f2SJohn Marino 
12295f4613f2SJohn Marino     if (VALID_STRING(set_background)
1230*32bb5217SDaniel Fojt 	&& VALID_STRING(set_a_background)) {
1231*32bb5217SDaniel Fojt 	if (!_nc_capcmp(set_background, set_a_background)) {
12325f4613f2SJohn Marino 	    _nc_warning("expected setb/setab to be different");
1233*32bb5217SDaniel Fojt 	} else if (same_color(set_background, set_a_background, max_colors)) {
1234*32bb5217SDaniel Fojt 	    _nc_warning("setb/setab are equivalent");
1235*32bb5217SDaniel Fojt 	}
1236*32bb5217SDaniel Fojt     }
12375f4613f2SJohn Marino 
12385f4613f2SJohn Marino     /* see: has_colors() */
12395f4613f2SJohn Marino     if (VALID_NUMERIC(max_colors) && VALID_NUMERIC(max_pairs)
1240*32bb5217SDaniel Fojt 	&& ((VALID_STRING(set_foreground)
1241*32bb5217SDaniel Fojt 	     && VALID_STRING(set_background))
1242*32bb5217SDaniel Fojt 	    || (VALID_STRING(set_a_foreground)
1243*32bb5217SDaniel Fojt 		&& VALID_STRING(set_a_background))
12445f4613f2SJohn Marino 	    || set_color_pair)) {
12455f4613f2SJohn Marino 	if (!VALID_STRING(orig_pair) && !VALID_STRING(orig_colors))
12465f4613f2SJohn Marino 	    _nc_warning("expected either op/oc string for resetting colors");
12475f4613f2SJohn Marino     }
12483468e90cSJohn Marino     if (can_change) {
12493468e90cSJohn Marino 	if (!VALID_STRING(initialize_pair) &&
12503468e90cSJohn Marino 	    !VALID_STRING(initialize_color)) {
12513468e90cSJohn Marino 	    _nc_warning("expected initc or initp because ccc is given");
12523468e90cSJohn Marino 	}
12533468e90cSJohn Marino     } else {
12543468e90cSJohn Marino 	if (VALID_STRING(initialize_pair) ||
12553468e90cSJohn Marino 	    VALID_STRING(initialize_color)) {
12563468e90cSJohn Marino 	    _nc_warning("expected ccc because initc is given");
12573468e90cSJohn Marino 	}
12583468e90cSJohn Marino     }
1259*32bb5217SDaniel Fojt     value = tigetstr("RGB");
1260*32bb5217SDaniel Fojt     if (VALID_STRING(value)) {
1261*32bb5217SDaniel Fojt 	int r, g, b;
1262*32bb5217SDaniel Fojt 	char bad;
1263*32bb5217SDaniel Fojt 	int code = sscanf(value, "%d/%d/%d%c", &r, &g, &b, &bad);
1264*32bb5217SDaniel Fojt 	if (code != 3 || r <= 0 || g <= 0 || b <= 0) {
1265*32bb5217SDaniel Fojt 	    _nc_warning("unexpected value for RGB capability: %s", value);
1266*32bb5217SDaniel Fojt 	}
1267*32bb5217SDaniel Fojt     }
1268*32bb5217SDaniel Fojt }
1269*32bb5217SDaniel Fojt 
1270*32bb5217SDaniel Fojt static int
csi_length(const char * value)1271*32bb5217SDaniel Fojt csi_length(const char *value)
1272*32bb5217SDaniel Fojt {
1273*32bb5217SDaniel Fojt     int result = 0;
1274*32bb5217SDaniel Fojt 
1275*32bb5217SDaniel Fojt     if (value[0] == '\033' && value[1] == '[') {
1276*32bb5217SDaniel Fojt 	result = 2;
1277*32bb5217SDaniel Fojt     } else if (UChar(value[0]) == 0x9a) {
1278*32bb5217SDaniel Fojt 	result = 1;
1279*32bb5217SDaniel Fojt     }
1280*32bb5217SDaniel Fojt     return result;
12815f4613f2SJohn Marino }
12825f4613f2SJohn Marino 
12835f4613f2SJohn Marino static char
keypad_final(const char * string)12845f4613f2SJohn Marino keypad_final(const char *string)
12855f4613f2SJohn Marino {
12865f4613f2SJohn Marino     char result = '\0';
12875f4613f2SJohn Marino 
12885f4613f2SJohn Marino     if (VALID_STRING(string)
12895f4613f2SJohn Marino 	&& *string++ == '\033'
12905f4613f2SJohn Marino 	&& *string++ == 'O'
12915f4613f2SJohn Marino 	&& strlen(string) == 1) {
12925f4613f2SJohn Marino 	result = *string;
12935f4613f2SJohn Marino     }
12945f4613f2SJohn Marino 
12955f4613f2SJohn Marino     return result;
12965f4613f2SJohn Marino }
12975f4613f2SJohn Marino 
12983468e90cSJohn Marino static long
keypad_index(const char * string)12995f4613f2SJohn Marino keypad_index(const char *string)
13005f4613f2SJohn Marino {
13015f4613f2SJohn Marino     char *test;
13025f4613f2SJohn Marino     const char *list = "PQRSwxymtuvlqrsPpn";	/* app-keypad except "Enter" */
13035f4613f2SJohn Marino     int ch;
13043468e90cSJohn Marino     long result = -1;
13055f4613f2SJohn Marino 
13065f4613f2SJohn Marino     if ((ch = keypad_final(string)) != '\0') {
13073468e90cSJohn Marino 	test = (strchr) (list, ch);
13085f4613f2SJohn Marino 	if (test != 0)
13093468e90cSJohn Marino 	    result = (long) (test - list);
13105f4613f2SJohn Marino     }
13115f4613f2SJohn Marino     return result;
13125f4613f2SJohn Marino }
13135f4613f2SJohn Marino 
13145f4613f2SJohn Marino /*
13155f4613f2SJohn Marino  * list[] is down, up, left, right
13165f4613f2SJohn Marino  * "left" may be ^H rather than \E[D
13175f4613f2SJohn Marino  * "down" may be ^J rather than \E[B
13185f4613f2SJohn Marino  * But up/right are generally consistently escape sequences for ANSI terminals.
13195f4613f2SJohn Marino  */
13205f4613f2SJohn Marino static void
check_ansi_cursor(char * list[4])13215f4613f2SJohn Marino check_ansi_cursor(char *list[4])
13225f4613f2SJohn Marino {
13235f4613f2SJohn Marino     int j, k;
13245f4613f2SJohn Marino     int want;
13255f4613f2SJohn Marino     size_t suffix;
13265f4613f2SJohn Marino     bool skip[4];
13275f4613f2SJohn Marino     bool repeated = FALSE;
13285f4613f2SJohn Marino 
13295f4613f2SJohn Marino     for (j = 0; j < 4; ++j) {
13305f4613f2SJohn Marino 	skip[j] = FALSE;
13315f4613f2SJohn Marino 	for (k = 0; k < j; ++k) {
13325f4613f2SJohn Marino 	    if (j != k
13335f4613f2SJohn Marino 		&& !strcmp(list[j], list[k])) {
13345f4613f2SJohn Marino 		char *value = _nc_tic_expand(list[k], TRUE, 0);
13355f4613f2SJohn Marino 		_nc_warning("repeated cursor control %s\n", value);
13365f4613f2SJohn Marino 		repeated = TRUE;
13375f4613f2SJohn Marino 	    }
13385f4613f2SJohn Marino 	}
13395f4613f2SJohn Marino     }
13405f4613f2SJohn Marino     if (!repeated) {
13415f4613f2SJohn Marino 	char *up = list[1];
1342*32bb5217SDaniel Fojt 	size_t prefix = (size_t) csi_length(up);
13435f4613f2SJohn Marino 
13445f4613f2SJohn Marino 	if (prefix) {
13455f4613f2SJohn Marino 	    suffix = prefix;
13465f4613f2SJohn Marino 	    while (up[suffix] && isdigit(UChar(up[suffix])))
13475f4613f2SJohn Marino 		++suffix;
13485f4613f2SJohn Marino 	}
13495f4613f2SJohn Marino 	if (prefix && up[suffix] == 'A') {
13505f4613f2SJohn Marino 	    skip[1] = TRUE;
13515f4613f2SJohn Marino 	    if (!strcmp(list[0], "\n"))
13525f4613f2SJohn Marino 		skip[0] = TRUE;
13535f4613f2SJohn Marino 	    if (!strcmp(list[2], "\b"))
13545f4613f2SJohn Marino 		skip[2] = TRUE;
13555f4613f2SJohn Marino 
13565f4613f2SJohn Marino 	    for (j = 0; j < 4; ++j) {
13575f4613f2SJohn Marino 		if (skip[j] || strlen(list[j]) == 1)
13585f4613f2SJohn Marino 		    continue;
13595f4613f2SJohn Marino 		if (memcmp(list[j], up, prefix)) {
13605f4613f2SJohn Marino 		    char *value = _nc_tic_expand(list[j], TRUE, 0);
13615f4613f2SJohn Marino 		    _nc_warning("inconsistent prefix for %s\n", value);
13625f4613f2SJohn Marino 		    continue;
13635f4613f2SJohn Marino 		}
13645f4613f2SJohn Marino 		if (strlen(list[j]) < suffix) {
13655f4613f2SJohn Marino 		    char *value = _nc_tic_expand(list[j], TRUE, 0);
13665f4613f2SJohn Marino 		    _nc_warning("inconsistent length for %s, expected %d\n",
13675f4613f2SJohn Marino 				value, (int) suffix + 1);
13685f4613f2SJohn Marino 		    continue;
13695f4613f2SJohn Marino 		}
13705f4613f2SJohn Marino 		want = "BADC"[j];
13715f4613f2SJohn Marino 		if (list[j][suffix] != want) {
13725f4613f2SJohn Marino 		    char *value = _nc_tic_expand(list[j], TRUE, 0);
13735f4613f2SJohn Marino 		    _nc_warning("inconsistent suffix for %s, expected %c, have %c\n",
13745f4613f2SJohn Marino 				value, want, list[j][suffix]);
13755f4613f2SJohn Marino 		}
13765f4613f2SJohn Marino 	    }
13775f4613f2SJohn Marino 	}
13785f4613f2SJohn Marino     }
13795f4613f2SJohn Marino }
13805f4613f2SJohn Marino 
13815f4613f2SJohn Marino #define EXPECTED(name) if (!PRESENT(name)) _nc_warning("expected " #name)
13823468e90cSJohn Marino #define UNEXPECTED(name) if (PRESENT(name)) _nc_warning("unexpected " #name ", for %s", why)
13833468e90cSJohn Marino 
13843468e90cSJohn Marino static void
check_noaddress(TERMTYPE2 * tp,const char * why)1385*32bb5217SDaniel Fojt check_noaddress(TERMTYPE2 *tp, const char *why)
13863468e90cSJohn Marino {
13873468e90cSJohn Marino     UNEXPECTED(column_address);
13883468e90cSJohn Marino     UNEXPECTED(cursor_address);
13893468e90cSJohn Marino     UNEXPECTED(cursor_home);
13903468e90cSJohn Marino     UNEXPECTED(cursor_mem_address);
13913468e90cSJohn Marino     UNEXPECTED(cursor_to_ll);
13923468e90cSJohn Marino     UNEXPECTED(row_address);
13933468e90cSJohn Marino     UNEXPECTED(row_address);
13943468e90cSJohn Marino }
13955f4613f2SJohn Marino 
13965f4613f2SJohn Marino static void
check_cursor(TERMTYPE2 * tp)1397*32bb5217SDaniel Fojt check_cursor(TERMTYPE2 *tp)
13985f4613f2SJohn Marino {
13995f4613f2SJohn Marino     int count;
14005f4613f2SJohn Marino     char *list[4];
14015f4613f2SJohn Marino 
14023468e90cSJohn Marino     if (hard_copy) {
14033468e90cSJohn Marino 	check_noaddress(tp, "hard_copy");
14043468e90cSJohn Marino     } else if (generic_type) {
14053468e90cSJohn Marino 	check_noaddress(tp, "generic_type");
14063468e90cSJohn Marino     } else if (strchr(tp->term_names, '+') == 0) {
14073468e90cSJohn Marino 	int y = 0;
14083468e90cSJohn Marino 	int x = 0;
14093468e90cSJohn Marino 	if (PRESENT(column_address))
14103468e90cSJohn Marino 	    ++y;
14113468e90cSJohn Marino 	if (PRESENT(cursor_address))
14123468e90cSJohn Marino 	    y = x = 10;
14133468e90cSJohn Marino 	if (PRESENT(cursor_home))
14143468e90cSJohn Marino 	    ++y, ++x;
14153468e90cSJohn Marino 	if (PRESENT(cursor_mem_address))
14163468e90cSJohn Marino 	    y = x = 10;
14173468e90cSJohn Marino 	if (PRESENT(cursor_to_ll))
14183468e90cSJohn Marino 	    ++y, ++x;
14193468e90cSJohn Marino 	if (PRESENT(row_address))
14203468e90cSJohn Marino 	    ++x;
14213468e90cSJohn Marino 	if (PRESENT(cursor_down))
14223468e90cSJohn Marino 	    ++y;
14233468e90cSJohn Marino 	if (PRESENT(cursor_up))
14243468e90cSJohn Marino 	    ++y;
14253468e90cSJohn Marino 	if (PRESENT(cursor_left))
14263468e90cSJohn Marino 	    ++x;
14273468e90cSJohn Marino 	if (PRESENT(cursor_right))
14283468e90cSJohn Marino 	    ++x;
14293468e90cSJohn Marino 	if (x < 2 && y < 2) {
14303468e90cSJohn Marino 	    _nc_warning("terminal lacks cursor addressing");
14313468e90cSJohn Marino 	} else {
14323468e90cSJohn Marino 	    if (x < 2)
14333468e90cSJohn Marino 		_nc_warning("terminal lacks cursor column-addressing");
14343468e90cSJohn Marino 	    if (y < 2)
14353468e90cSJohn Marino 		_nc_warning("terminal lacks cursor row-addressing");
14363468e90cSJohn Marino 	}
14373468e90cSJohn Marino     }
14383468e90cSJohn Marino 
14393468e90cSJohn Marino     /* it is rare to have an insert-line feature without a matching delete */
14403468e90cSJohn Marino     ANDMISSING(parm_insert_line, insert_line);
14413468e90cSJohn Marino     ANDMISSING(parm_delete_line, delete_line);
14423468e90cSJohn Marino     ANDMISSING(parm_insert_line, parm_delete_line);
14433468e90cSJohn Marino 
14445f4613f2SJohn Marino     /* if we have a parameterized form, then the non-parameterized is easy */
14455f4613f2SJohn Marino     ANDMISSING(parm_down_cursor, cursor_down);
14465f4613f2SJohn Marino     ANDMISSING(parm_up_cursor, cursor_up);
14475f4613f2SJohn Marino     ANDMISSING(parm_left_cursor, cursor_left);
14485f4613f2SJohn Marino     ANDMISSING(parm_right_cursor, cursor_right);
14495f4613f2SJohn Marino 
14505f4613f2SJohn Marino     /* Given any of a set of cursor movement, the whole set should be present.
14515f4613f2SJohn Marino      * Technically this is not true (we could use cursor_address to fill in
14525f4613f2SJohn Marino      * unsupported controls), but it is likely.
14535f4613f2SJohn Marino      */
14545f4613f2SJohn Marino     count = 0;
14555f4613f2SJohn Marino     if (PRESENT(parm_down_cursor)) {
14565f4613f2SJohn Marino 	list[count++] = parm_down_cursor;
14575f4613f2SJohn Marino     }
14585f4613f2SJohn Marino     if (PRESENT(parm_up_cursor)) {
14595f4613f2SJohn Marino 	list[count++] = parm_up_cursor;
14605f4613f2SJohn Marino     }
14615f4613f2SJohn Marino     if (PRESENT(parm_left_cursor)) {
14625f4613f2SJohn Marino 	list[count++] = parm_left_cursor;
14635f4613f2SJohn Marino     }
14645f4613f2SJohn Marino     if (PRESENT(parm_right_cursor)) {
14655f4613f2SJohn Marino 	list[count++] = parm_right_cursor;
14665f4613f2SJohn Marino     }
14675f4613f2SJohn Marino     if (count == 4) {
14685f4613f2SJohn Marino 	check_ansi_cursor(list);
14695f4613f2SJohn Marino     } else if (count != 0) {
14705f4613f2SJohn Marino 	EXPECTED(parm_down_cursor);
14715f4613f2SJohn Marino 	EXPECTED(parm_up_cursor);
14725f4613f2SJohn Marino 	EXPECTED(parm_left_cursor);
14735f4613f2SJohn Marino 	EXPECTED(parm_right_cursor);
14745f4613f2SJohn Marino     }
14755f4613f2SJohn Marino 
14765f4613f2SJohn Marino     count = 0;
14775f4613f2SJohn Marino     if (PRESENT(cursor_down)) {
14785f4613f2SJohn Marino 	list[count++] = cursor_down;
14795f4613f2SJohn Marino     }
14805f4613f2SJohn Marino     if (PRESENT(cursor_up)) {
14815f4613f2SJohn Marino 	list[count++] = cursor_up;
14825f4613f2SJohn Marino     }
14835f4613f2SJohn Marino     if (PRESENT(cursor_left)) {
14845f4613f2SJohn Marino 	list[count++] = cursor_left;
14855f4613f2SJohn Marino     }
14865f4613f2SJohn Marino     if (PRESENT(cursor_right)) {
14875f4613f2SJohn Marino 	list[count++] = cursor_right;
14885f4613f2SJohn Marino     }
14895f4613f2SJohn Marino     if (count == 4) {
14905f4613f2SJohn Marino 	check_ansi_cursor(list);
14915f4613f2SJohn Marino     } else if (count != 0) {
14925f4613f2SJohn Marino 	count = 0;
14935f4613f2SJohn Marino 	if (PRESENT(cursor_down) && strcmp(cursor_down, "\n"))
14945f4613f2SJohn Marino 	    ++count;
14955f4613f2SJohn Marino 	if (PRESENT(cursor_left) && strcmp(cursor_left, "\b"))
14965f4613f2SJohn Marino 	    ++count;
14975f4613f2SJohn Marino 	if (PRESENT(cursor_up) && strlen(cursor_up) > 1)
14985f4613f2SJohn Marino 	    ++count;
14995f4613f2SJohn Marino 	if (PRESENT(cursor_right) && strlen(cursor_right) > 1)
15005f4613f2SJohn Marino 	    ++count;
15015f4613f2SJohn Marino 	if (count) {
15025f4613f2SJohn Marino 	    EXPECTED(cursor_down);
15035f4613f2SJohn Marino 	    EXPECTED(cursor_up);
15045f4613f2SJohn Marino 	    EXPECTED(cursor_left);
15055f4613f2SJohn Marino 	    EXPECTED(cursor_right);
15065f4613f2SJohn Marino 	}
15075f4613f2SJohn Marino     }
15085f4613f2SJohn Marino }
15095f4613f2SJohn Marino 
15105f4613f2SJohn Marino #define MAX_KP 5
15115f4613f2SJohn Marino /*
15125f4613f2SJohn Marino  * Do a quick sanity-check for vt100-style keypads to see if the 5-key keypad
15135f4613f2SJohn Marino  * is mapped inconsistently.
15145f4613f2SJohn Marino  */
15155f4613f2SJohn Marino static void
check_keypad(TERMTYPE2 * tp)1516*32bb5217SDaniel Fojt check_keypad(TERMTYPE2 *tp)
15175f4613f2SJohn Marino {
15185f4613f2SJohn Marino     char show[80];
15195f4613f2SJohn Marino 
15205f4613f2SJohn Marino     if (VALID_STRING(key_a1) &&
15215f4613f2SJohn Marino 	VALID_STRING(key_a3) &&
15225f4613f2SJohn Marino 	VALID_STRING(key_b2) &&
15235f4613f2SJohn Marino 	VALID_STRING(key_c1) &&
15245f4613f2SJohn Marino 	VALID_STRING(key_c3)) {
15255f4613f2SJohn Marino 	char final[MAX_KP + 1];
15263468e90cSJohn Marino 	long list[MAX_KP];
15275f4613f2SJohn Marino 	int increase = 0;
15285f4613f2SJohn Marino 	int j, k, kk;
15293468e90cSJohn Marino 	long last;
15303468e90cSJohn Marino 	long test;
15315f4613f2SJohn Marino 
15325f4613f2SJohn Marino 	final[0] = keypad_final(key_a1);
15335f4613f2SJohn Marino 	final[1] = keypad_final(key_a3);
15345f4613f2SJohn Marino 	final[2] = keypad_final(key_b2);
15355f4613f2SJohn Marino 	final[3] = keypad_final(key_c1);
15365f4613f2SJohn Marino 	final[4] = keypad_final(key_c3);
15375f4613f2SJohn Marino 	final[5] = '\0';
15385f4613f2SJohn Marino 
15395f4613f2SJohn Marino 	/* special case: legacy coding using 1,2,3,0,. on the bottom */
15405f4613f2SJohn Marino 	assert(strlen(final) <= MAX_KP);
15415f4613f2SJohn Marino 	if (!strcmp(final, "qsrpn"))
15425f4613f2SJohn Marino 	    return;
15435f4613f2SJohn Marino 
15445f4613f2SJohn Marino 	list[0] = keypad_index(key_a1);
15455f4613f2SJohn Marino 	list[1] = keypad_index(key_a3);
15465f4613f2SJohn Marino 	list[2] = keypad_index(key_b2);
15475f4613f2SJohn Marino 	list[3] = keypad_index(key_c1);
15485f4613f2SJohn Marino 	list[4] = keypad_index(key_c3);
15495f4613f2SJohn Marino 
15505f4613f2SJohn Marino 	/* check that they're all vt100 keys */
15515f4613f2SJohn Marino 	for (j = 0; j < MAX_KP; ++j) {
15525f4613f2SJohn Marino 	    if (list[j] < 0) {
15535f4613f2SJohn Marino 		return;
15545f4613f2SJohn Marino 	    }
15555f4613f2SJohn Marino 	}
15565f4613f2SJohn Marino 
15575f4613f2SJohn Marino 	/* check if they're all in increasing order */
15585f4613f2SJohn Marino 	for (j = 1; j < MAX_KP; ++j) {
15595f4613f2SJohn Marino 	    if (list[j] > list[j - 1]) {
15605f4613f2SJohn Marino 		++increase;
15615f4613f2SJohn Marino 	    }
15625f4613f2SJohn Marino 	}
15635f4613f2SJohn Marino 	if (increase != (MAX_KP - 1)) {
15645f4613f2SJohn Marino 	    show[0] = '\0';
15655f4613f2SJohn Marino 
15665f4613f2SJohn Marino 	    for (j = 0, last = -1; j < MAX_KP; ++j) {
15675f4613f2SJohn Marino 		for (k = 0, kk = -1, test = 100; k < 5; ++k) {
15685f4613f2SJohn Marino 		    if (list[k] > last &&
15695f4613f2SJohn Marino 			list[k] < test) {
15705f4613f2SJohn Marino 			test = list[k];
15715f4613f2SJohn Marino 			kk = k;
15725f4613f2SJohn Marino 		    }
15735f4613f2SJohn Marino 		}
15745f4613f2SJohn Marino 		last = test;
15755f4613f2SJohn Marino 		assert(strlen(show) < (MAX_KP * 4));
15765f4613f2SJohn Marino 		switch (kk) {
15775f4613f2SJohn Marino 		case 0:
15783468e90cSJohn Marino 		    _nc_STRCAT(show, " ka1", sizeof(show));
15795f4613f2SJohn Marino 		    break;
15805f4613f2SJohn Marino 		case 1:
15813468e90cSJohn Marino 		    _nc_STRCAT(show, " ka3", sizeof(show));
15825f4613f2SJohn Marino 		    break;
15835f4613f2SJohn Marino 		case 2:
15843468e90cSJohn Marino 		    _nc_STRCAT(show, " kb2", sizeof(show));
15855f4613f2SJohn Marino 		    break;
15865f4613f2SJohn Marino 		case 3:
15873468e90cSJohn Marino 		    _nc_STRCAT(show, " kc1", sizeof(show));
15885f4613f2SJohn Marino 		    break;
15895f4613f2SJohn Marino 		case 4:
15903468e90cSJohn Marino 		    _nc_STRCAT(show, " kc3", sizeof(show));
15915f4613f2SJohn Marino 		    break;
15925f4613f2SJohn Marino 		}
15935f4613f2SJohn Marino 	    }
15945f4613f2SJohn Marino 
15955f4613f2SJohn Marino 	    _nc_warning("vt100 keypad order inconsistent: %s", show);
15965f4613f2SJohn Marino 	}
15975f4613f2SJohn Marino 
15985f4613f2SJohn Marino     } else if (VALID_STRING(key_a1) ||
15995f4613f2SJohn Marino 	       VALID_STRING(key_a3) ||
16005f4613f2SJohn Marino 	       VALID_STRING(key_b2) ||
16015f4613f2SJohn Marino 	       VALID_STRING(key_c1) ||
16025f4613f2SJohn Marino 	       VALID_STRING(key_c3)) {
16035f4613f2SJohn Marino 	show[0] = '\0';
16045f4613f2SJohn Marino 	if (keypad_index(key_a1) >= 0)
16053468e90cSJohn Marino 	    _nc_STRCAT(show, " ka1", sizeof(show));
16065f4613f2SJohn Marino 	if (keypad_index(key_a3) >= 0)
16073468e90cSJohn Marino 	    _nc_STRCAT(show, " ka3", sizeof(show));
16085f4613f2SJohn Marino 	if (keypad_index(key_b2) >= 0)
16093468e90cSJohn Marino 	    _nc_STRCAT(show, " kb2", sizeof(show));
16105f4613f2SJohn Marino 	if (keypad_index(key_c1) >= 0)
16113468e90cSJohn Marino 	    _nc_STRCAT(show, " kc1", sizeof(show));
16125f4613f2SJohn Marino 	if (keypad_index(key_c3) >= 0)
16133468e90cSJohn Marino 	    _nc_STRCAT(show, " kc3", sizeof(show));
16145f4613f2SJohn Marino 	if (*show != '\0')
16155f4613f2SJohn Marino 	    _nc_warning("vt100 keypad map incomplete:%s", show);
16165f4613f2SJohn Marino     }
16173468e90cSJohn Marino 
16183468e90cSJohn Marino     /*
16193468e90cSJohn Marino      * These warnings are useful for consistency checks - it is possible that
16203468e90cSJohn Marino      * there are real terminals with mismatches in these
16213468e90cSJohn Marino      */
16223468e90cSJohn Marino     ANDMISSING(key_ic, key_dc);
16235f4613f2SJohn Marino }
16245f4613f2SJohn Marino 
16255f4613f2SJohn Marino static void
check_printer(TERMTYPE2 * tp)1626*32bb5217SDaniel Fojt check_printer(TERMTYPE2 *tp)
16275f4613f2SJohn Marino {
1628*32bb5217SDaniel Fojt     (void) tp;
1629*32bb5217SDaniel Fojt #if defined(enter_doublewide_mode) && defined(exit_doublewide_mode)
16305f4613f2SJohn Marino     PAIRED(enter_doublewide_mode, exit_doublewide_mode);
1631*32bb5217SDaniel Fojt #endif
1632*32bb5217SDaniel Fojt #if defined(enter_italics_mode) && defined(exit_italics_mode)
16335f4613f2SJohn Marino     PAIRED(enter_italics_mode, exit_italics_mode);
1634*32bb5217SDaniel Fojt #endif
1635*32bb5217SDaniel Fojt #if defined(enter_leftward_mode) && defined(exit_leftward_mode)
16365f4613f2SJohn Marino     PAIRED(enter_leftward_mode, exit_leftward_mode);
1637*32bb5217SDaniel Fojt #endif
1638*32bb5217SDaniel Fojt #if defined(enter_micro_mode) && defined(exit_micro_mode)
16395f4613f2SJohn Marino     PAIRED(enter_micro_mode, exit_micro_mode);
1640*32bb5217SDaniel Fojt #endif
1641*32bb5217SDaniel Fojt #if defined(enter_shadow_mode) && defined(exit_shadow_mode)
16425f4613f2SJohn Marino     PAIRED(enter_shadow_mode, exit_shadow_mode);
1643*32bb5217SDaniel Fojt #endif
1644*32bb5217SDaniel Fojt #if defined(enter_subscript_mode) && defined(exit_subscript_mode)
16455f4613f2SJohn Marino     PAIRED(enter_subscript_mode, exit_subscript_mode);
1646*32bb5217SDaniel Fojt #endif
1647*32bb5217SDaniel Fojt #if defined(enter_superscript_mode) && defined(exit_superscript_mode)
16485f4613f2SJohn Marino     PAIRED(enter_superscript_mode, exit_superscript_mode);
1649*32bb5217SDaniel Fojt #endif
1650*32bb5217SDaniel Fojt #if defined(enter_upward_mode) && defined(exit_upward_mode)
16515f4613f2SJohn Marino     PAIRED(enter_upward_mode, exit_upward_mode);
1652*32bb5217SDaniel Fojt #endif
16535f4613f2SJohn Marino 
1654*32bb5217SDaniel Fojt #if defined(start_char_set_def) && defined(stop_char_set_def)
16555f4613f2SJohn Marino     ANDMISSING(start_char_set_def, stop_char_set_def);
1656*32bb5217SDaniel Fojt #endif
16575f4613f2SJohn Marino 
16585f4613f2SJohn Marino     /* if we have a parameterized form, then the non-parameterized is easy */
1659*32bb5217SDaniel Fojt #if defined(set_bottom_margin_parm) && defined(set_bottom_margin)
16605f4613f2SJohn Marino     ANDMISSING(set_bottom_margin_parm, set_bottom_margin);
1661*32bb5217SDaniel Fojt #endif
1662*32bb5217SDaniel Fojt #if defined(set_left_margin_parm) && defined(set_left_margin)
16635f4613f2SJohn Marino     ANDMISSING(set_left_margin_parm, set_left_margin);
1664*32bb5217SDaniel Fojt #endif
1665*32bb5217SDaniel Fojt #if defined(set_right_margin_parm) && defined(set_right_margin)
16665f4613f2SJohn Marino     ANDMISSING(set_right_margin_parm, set_right_margin);
1667*32bb5217SDaniel Fojt #endif
1668*32bb5217SDaniel Fojt #if defined(set_top_margin_parm) && defined(set_top_margin)
16695f4613f2SJohn Marino     ANDMISSING(set_top_margin_parm, set_top_margin);
1670*32bb5217SDaniel Fojt #endif
16715f4613f2SJohn Marino 
1672*32bb5217SDaniel Fojt #if defined(parm_down_micro) && defined(micro_down)
16735f4613f2SJohn Marino     ANDMISSING(parm_down_micro, micro_down);
1674*32bb5217SDaniel Fojt #endif
1675*32bb5217SDaniel Fojt #if defined(parm_left_micro) && defined(micro_left)
16765f4613f2SJohn Marino     ANDMISSING(parm_left_micro, micro_left);
1677*32bb5217SDaniel Fojt #endif
1678*32bb5217SDaniel Fojt #if defined(parm_right_micro) && defined(micro_right)
16795f4613f2SJohn Marino     ANDMISSING(parm_right_micro, micro_right);
1680*32bb5217SDaniel Fojt #endif
1681*32bb5217SDaniel Fojt #if defined(parm_up_micro) && defined(micro_up)
16825f4613f2SJohn Marino     ANDMISSING(parm_up_micro, micro_up);
1683*32bb5217SDaniel Fojt #endif
16845f4613f2SJohn Marino }
16855f4613f2SJohn Marino 
1686*32bb5217SDaniel Fojt #if NCURSES_XNAMES
16873468e90cSJohn Marino static bool
uses_SGR_39_49(const char * value)16883468e90cSJohn Marino uses_SGR_39_49(const char *value)
16893468e90cSJohn Marino {
16903468e90cSJohn Marino     return (strstr(value, "39;49") != 0
16913468e90cSJohn Marino 	    || strstr(value, "49;39") != 0);
16923468e90cSJohn Marino }
16933468e90cSJohn Marino 
16943468e90cSJohn Marino /*
16953468e90cSJohn Marino  * Check consistency of termcap extensions related to "screen".
16963468e90cSJohn Marino  */
16973468e90cSJohn Marino static void
check_screen(TERMTYPE2 * tp)1698*32bb5217SDaniel Fojt check_screen(TERMTYPE2 *tp)
16993468e90cSJohn Marino {
17003468e90cSJohn Marino     if (_nc_user_definable) {
17013468e90cSJohn Marino 	int have_XT = tigetflag("XT");
17023468e90cSJohn Marino 	int have_XM = tigetflag("XM");
17033468e90cSJohn Marino 	int have_bce = back_color_erase;
17043468e90cSJohn Marino 	bool have_kmouse = FALSE;
17053468e90cSJohn Marino 	bool use_sgr_39_49 = FALSE;
17063468e90cSJohn Marino 	char *name = _nc_first_name(tp->term_names);
1707*32bb5217SDaniel Fojt 	bool is_screen = !strncmp(name, "screen", 6);
1708*32bb5217SDaniel Fojt 	bool screen_base = (is_screen
1709*32bb5217SDaniel Fojt 			    && strchr(name, '.') == 0);
17103468e90cSJohn Marino 
17113468e90cSJohn Marino 	if (!VALID_BOOLEAN(have_bce)) {
17123468e90cSJohn Marino 	    have_bce = FALSE;
17133468e90cSJohn Marino 	}
17143468e90cSJohn Marino 	if (!VALID_BOOLEAN(have_XM)) {
17153468e90cSJohn Marino 	    have_XM = FALSE;
17163468e90cSJohn Marino 	}
17173468e90cSJohn Marino 	if (!VALID_BOOLEAN(have_XT)) {
17183468e90cSJohn Marino 	    have_XT = FALSE;
17193468e90cSJohn Marino 	}
17203468e90cSJohn Marino 	if (VALID_STRING(key_mouse)) {
17213468e90cSJohn Marino 	    have_kmouse = !strcmp("\033[M", key_mouse);
17223468e90cSJohn Marino 	}
17233468e90cSJohn Marino 	if (VALID_STRING(orig_colors)) {
17243468e90cSJohn Marino 	    use_sgr_39_49 = uses_SGR_39_49(orig_colors);
17253468e90cSJohn Marino 	} else if (VALID_STRING(orig_pair)) {
17263468e90cSJohn Marino 	    use_sgr_39_49 = uses_SGR_39_49(orig_pair);
17273468e90cSJohn Marino 	}
17283468e90cSJohn Marino 
17293468e90cSJohn Marino 	if (have_XM && have_XT) {
1730*32bb5217SDaniel Fojt 	    _nc_warning("screen's XT capability conflicts with XM");
1731*32bb5217SDaniel Fojt 	} else if (have_XT && screen_base) {
1732*32bb5217SDaniel Fojt 	    _nc_warning("screen's \"screen\" entries should not have XT set");
17333468e90cSJohn Marino 	} else if (have_XT) {
1734*32bb5217SDaniel Fojt 	    if (!have_kmouse && is_screen) {
17353468e90cSJohn Marino 		if (VALID_STRING(key_mouse)) {
1736*32bb5217SDaniel Fojt 		    _nc_warning("value of kmous inconsistent with screen's usage");
17373468e90cSJohn Marino 		} else {
1738*32bb5217SDaniel Fojt 		    _nc_warning("expected kmous capability with XT");
17393468e90cSJohn Marino 		}
17403468e90cSJohn Marino 	    }
17413468e90cSJohn Marino 	    if (!have_bce && max_colors > 0)
1742*32bb5217SDaniel Fojt 		_nc_warning("expected bce capability with XT");
17433468e90cSJohn Marino 	    if (!use_sgr_39_49 && have_bce && max_colors > 0)
1744*32bb5217SDaniel Fojt 		_nc_warning("expected orig_colors capability with XT to have 39/49 parameters");
17453468e90cSJohn Marino 	    if (VALID_STRING(to_status_line))
17463468e90cSJohn Marino 		_nc_warning("\"tsl\" capability is redundant, given XT");
17473468e90cSJohn Marino 	} else {
1748*32bb5217SDaniel Fojt 	    if (have_kmouse
1749*32bb5217SDaniel Fojt 		&& !have_XM
1750*32bb5217SDaniel Fojt 		&& !screen_base && strchr(name, '+') == 0) {
1751*32bb5217SDaniel Fojt 		_nc_warning("expected XT to be set, given kmous");
17523468e90cSJohn Marino 	    }
17533468e90cSJohn Marino 	}
1754*32bb5217SDaniel Fojt     }
1755*32bb5217SDaniel Fojt }
1756*32bb5217SDaniel Fojt #else
1757*32bb5217SDaniel Fojt #define check_screen(tp)	/* nothing */
17583468e90cSJohn Marino #endif
17593468e90cSJohn Marino 
17605f4613f2SJohn Marino /*
17615f4613f2SJohn Marino  * Returns the expected number of parameters for the given capability.
17625f4613f2SJohn Marino  */
17635f4613f2SJohn Marino static int
expected_params(const char * name)17645f4613f2SJohn Marino expected_params(const char *name)
17655f4613f2SJohn Marino {
17663468e90cSJohn Marino #define DATA(name,count) { { name }, count }
17675f4613f2SJohn Marino     /* *INDENT-OFF* */
17685f4613f2SJohn Marino     static const struct {
17693468e90cSJohn Marino 	const char name[9];
17705f4613f2SJohn Marino 	int count;
17715f4613f2SJohn Marino     } table[] = {
17723468e90cSJohn Marino 	DATA( "S0",		1 ),	/* 'screen' extension */
17733468e90cSJohn Marino 	DATA( "birep",		2 ),
17743468e90cSJohn Marino 	DATA( "chr",		1 ),
17753468e90cSJohn Marino 	DATA( "colornm",	1 ),
17763468e90cSJohn Marino 	DATA( "cpi",		1 ),
17773468e90cSJohn Marino 	DATA( "csnm",		1 ),
17783468e90cSJohn Marino 	DATA( "csr",		2 ),
17793468e90cSJohn Marino 	DATA( "cub",		1 ),
17803468e90cSJohn Marino 	DATA( "cud",		1 ),
17813468e90cSJohn Marino 	DATA( "cuf",		1 ),
17823468e90cSJohn Marino 	DATA( "cup",		2 ),
17833468e90cSJohn Marino 	DATA( "cuu",		1 ),
17843468e90cSJohn Marino 	DATA( "cvr",		1 ),
17853468e90cSJohn Marino 	DATA( "cwin",		5 ),
17863468e90cSJohn Marino 	DATA( "dch",		1 ),
17873468e90cSJohn Marino 	DATA( "defc",		3 ),
17883468e90cSJohn Marino 	DATA( "dial",		1 ),
17893468e90cSJohn Marino 	DATA( "dispc",		1 ),
17903468e90cSJohn Marino 	DATA( "dl",		1 ),
17913468e90cSJohn Marino 	DATA( "ech",		1 ),
17923468e90cSJohn Marino 	DATA( "getm",		1 ),
17933468e90cSJohn Marino 	DATA( "hpa",		1 ),
17943468e90cSJohn Marino 	DATA( "ich",		1 ),
17953468e90cSJohn Marino 	DATA( "il",		1 ),
17963468e90cSJohn Marino 	DATA( "indn",		1 ),
17973468e90cSJohn Marino 	DATA( "initc",		4 ),
17983468e90cSJohn Marino 	DATA( "initp",		7 ),
17993468e90cSJohn Marino 	DATA( "lpi",		1 ),
18003468e90cSJohn Marino 	DATA( "mc5p",		1 ),
18013468e90cSJohn Marino 	DATA( "mrcup",		2 ),
18023468e90cSJohn Marino 	DATA( "mvpa",		1 ),
18033468e90cSJohn Marino 	DATA( "pfkey",		2 ),
18043468e90cSJohn Marino 	DATA( "pfloc",		2 ),
18053468e90cSJohn Marino 	DATA( "pfx",		2 ),
18063468e90cSJohn Marino 	DATA( "pfxl",		3 ),
18073468e90cSJohn Marino 	DATA( "pln",		2 ),
18083468e90cSJohn Marino 	DATA( "qdial",		1 ),
18093468e90cSJohn Marino 	DATA( "rcsd",		1 ),
18103468e90cSJohn Marino 	DATA( "rep",		2 ),
18113468e90cSJohn Marino 	DATA( "rin",		1 ),
18123468e90cSJohn Marino 	DATA( "sclk",		3 ),
18133468e90cSJohn Marino 	DATA( "scp",		1 ),
18143468e90cSJohn Marino 	DATA( "scs",		1 ),
18153468e90cSJohn Marino 	DATA( "scsd",		2 ),
18163468e90cSJohn Marino 	DATA( "setab",		1 ),
18173468e90cSJohn Marino 	DATA( "setaf",		1 ),
18183468e90cSJohn Marino 	DATA( "setb",		1 ),
18193468e90cSJohn Marino 	DATA( "setcolor",	1 ),
18203468e90cSJohn Marino 	DATA( "setf",		1 ),
18213468e90cSJohn Marino 	DATA( "sgr",		9 ),
18223468e90cSJohn Marino 	DATA( "sgr1",		6 ),
18233468e90cSJohn Marino 	DATA( "slength",	1 ),
18243468e90cSJohn Marino 	DATA( "slines",		1 ),
18253468e90cSJohn Marino 	DATA( "smgbp",		1 ),	/* 2 if smgtp is not given */
18263468e90cSJohn Marino 	DATA( "smglp",		1 ),
18273468e90cSJohn Marino 	DATA( "smglr",		2 ),
18283468e90cSJohn Marino 	DATA( "smgrp",		1 ),
18293468e90cSJohn Marino 	DATA( "smgtb",		2 ),
18303468e90cSJohn Marino 	DATA( "smgtp",		1 ),
18313468e90cSJohn Marino 	DATA( "tsl",		1 ),
18323468e90cSJohn Marino 	DATA( "u6",		-1 ),
18333468e90cSJohn Marino 	DATA( "vpa",		1 ),
18343468e90cSJohn Marino 	DATA( "wind",		4 ),
18353468e90cSJohn Marino 	DATA( "wingo",		1 ),
18365f4613f2SJohn Marino     };
18375f4613f2SJohn Marino     /* *INDENT-ON* */
18385f4613f2SJohn Marino 
18393468e90cSJohn Marino #undef DATA
18403468e90cSJohn Marino 
18415f4613f2SJohn Marino     unsigned n;
18425f4613f2SJohn Marino     int result = 0;		/* function-keys, etc., use none */
18435f4613f2SJohn Marino 
18445f4613f2SJohn Marino     for (n = 0; n < SIZEOF(table); n++) {
18455f4613f2SJohn Marino 	if (!strcmp(name, table[n].name)) {
18465f4613f2SJohn Marino 	    result = table[n].count;
18475f4613f2SJohn Marino 	    break;
18485f4613f2SJohn Marino 	}
18495f4613f2SJohn Marino     }
18505f4613f2SJohn Marino 
18515f4613f2SJohn Marino     return result;
18525f4613f2SJohn Marino }
18535f4613f2SJohn Marino 
18545f4613f2SJohn Marino /*
1855*32bb5217SDaniel Fojt  * Check for user-capabilities that happen to be used in ncurses' terminal
1856*32bb5217SDaniel Fojt  * database.
1857*32bb5217SDaniel Fojt  */
1858*32bb5217SDaniel Fojt #if NCURSES_XNAMES
1859*32bb5217SDaniel Fojt static struct user_table_entry const *
lookup_user_capability(const char * name)1860*32bb5217SDaniel Fojt lookup_user_capability(const char *name)
1861*32bb5217SDaniel Fojt {
1862*32bb5217SDaniel Fojt     struct user_table_entry const *result = 0;
1863*32bb5217SDaniel Fojt     if (*name != 'k') {
1864*32bb5217SDaniel Fojt 	result = _nc_find_user_entry(name);
1865*32bb5217SDaniel Fojt     }
1866*32bb5217SDaniel Fojt     return result;
1867*32bb5217SDaniel Fojt }
1868*32bb5217SDaniel Fojt #endif
1869*32bb5217SDaniel Fojt 
1870*32bb5217SDaniel Fojt /*
1871*32bb5217SDaniel Fojt  * If a given name is likely to be a user-capability, return the number of
1872*32bb5217SDaniel Fojt  * parameters it would be used with.  If not, return -1.
1873*32bb5217SDaniel Fojt  *
1874*32bb5217SDaniel Fojt  * ncurses assumes that u6 could be used for getting the cursor-position, but
1875*32bb5217SDaniel Fojt  * that is not implemented.  Make a special case for that, to quiet needless
1876*32bb5217SDaniel Fojt  * warnings.
1877*32bb5217SDaniel Fojt  *
1878*32bb5217SDaniel Fojt  * The other string-capability extensions (see terminfo.src) which could have
1879*32bb5217SDaniel Fojt  * parameters such as "Ss", "%u", are not used by ncurses.  But we check those
1880*32bb5217SDaniel Fojt  * anyway, to validate the terminfo database.
1881*32bb5217SDaniel Fojt  */
1882*32bb5217SDaniel Fojt static int
is_user_capability(const char * name)1883*32bb5217SDaniel Fojt is_user_capability(const char *name)
1884*32bb5217SDaniel Fojt {
1885*32bb5217SDaniel Fojt     int result = -1;
1886*32bb5217SDaniel Fojt     if (name[0] == 'u' &&
1887*32bb5217SDaniel Fojt 	(name[1] >= '0' && name[1] <= '9') &&
1888*32bb5217SDaniel Fojt 	name[2] == '\0') {
1889*32bb5217SDaniel Fojt 	result = (name[1] == '6') ? 2 : 0;
1890*32bb5217SDaniel Fojt     }
1891*32bb5217SDaniel Fojt #if NCURSES_XNAMES
1892*32bb5217SDaniel Fojt     else if (using_extensions) {
1893*32bb5217SDaniel Fojt 	struct user_table_entry const *p = lookup_user_capability(name);
1894*32bb5217SDaniel Fojt 	if (p != 0) {
1895*32bb5217SDaniel Fojt 	    result = (int) p->ute_argc;
1896*32bb5217SDaniel Fojt 	}
1897*32bb5217SDaniel Fojt     }
1898*32bb5217SDaniel Fojt #endif
1899*32bb5217SDaniel Fojt     return result;
1900*32bb5217SDaniel Fojt }
1901*32bb5217SDaniel Fojt 
1902*32bb5217SDaniel Fojt /*
19035f4613f2SJohn Marino  * Make a quick sanity check for the parameters which are used in the given
19045f4613f2SJohn Marino  * strings.  If there are no "%p" tokens, then there should be no other "%"
19055f4613f2SJohn Marino  * markers.
19065f4613f2SJohn Marino  */
19075f4613f2SJohn Marino static void
check_params(TERMTYPE2 * tp,const char * name,char * value,int extended)1908*32bb5217SDaniel Fojt check_params(TERMTYPE2 *tp, const char *name, char *value, int extended)
19095f4613f2SJohn Marino {
19105f4613f2SJohn Marino     int expected = expected_params(name);
19115f4613f2SJohn Marino     int actual = 0;
19125f4613f2SJohn Marino     int n;
19133468e90cSJohn Marino     bool params[NUM_PARM];
19145f4613f2SJohn Marino     char *s = value;
19155f4613f2SJohn Marino 
19165f4613f2SJohn Marino #ifdef set_top_margin_parm
19175f4613f2SJohn Marino     if (!strcmp(name, "smgbp")
19185f4613f2SJohn Marino 	&& set_top_margin_parm == 0)
19195f4613f2SJohn Marino 	expected = 2;
19205f4613f2SJohn Marino #endif
19215f4613f2SJohn Marino 
19223468e90cSJohn Marino     for (n = 0; n < NUM_PARM; n++)
19235f4613f2SJohn Marino 	params[n] = FALSE;
19245f4613f2SJohn Marino 
19255f4613f2SJohn Marino     while (*s != 0) {
19265f4613f2SJohn Marino 	if (*s == '%') {
19275f4613f2SJohn Marino 	    if (*++s == '\0') {
19285f4613f2SJohn Marino 		_nc_warning("expected character after %% in %s", name);
19295f4613f2SJohn Marino 		break;
19305f4613f2SJohn Marino 	    } else if (*s == 'p') {
19315f4613f2SJohn Marino 		if (*++s == '\0' || !isdigit((int) *s)) {
19325f4613f2SJohn Marino 		    _nc_warning("expected digit after %%p in %s", name);
19335f4613f2SJohn Marino 		    return;
19345f4613f2SJohn Marino 		} else {
19355f4613f2SJohn Marino 		    n = (*s - '0');
19365f4613f2SJohn Marino 		    if (n > actual)
19375f4613f2SJohn Marino 			actual = n;
19385f4613f2SJohn Marino 		    params[n] = TRUE;
19395f4613f2SJohn Marino 		}
19405f4613f2SJohn Marino 	    }
19415f4613f2SJohn Marino 	}
19425f4613f2SJohn Marino 	s++;
19435f4613f2SJohn Marino     }
19445f4613f2SJohn Marino 
1945*32bb5217SDaniel Fojt #if NCURSES_XNAMES
1946*32bb5217SDaniel Fojt     if (extended) {
1947*32bb5217SDaniel Fojt 	int check = is_user_capability(name);
1948*32bb5217SDaniel Fojt 	if (check != actual && (check >= 0 && actual >= 0)) {
1949*32bb5217SDaniel Fojt 	    _nc_warning("extended %s capability has %d parameters, expected %d",
1950*32bb5217SDaniel Fojt 			name, actual, check);
1951*32bb5217SDaniel Fojt 	} else if (debug_level > 1) {
1952*32bb5217SDaniel Fojt 	    _nc_warning("extended %s capability has %d parameters, as expected",
1953*32bb5217SDaniel Fojt 			name, actual);
1954*32bb5217SDaniel Fojt 	}
1955*32bb5217SDaniel Fojt 	expected = actual;
1956*32bb5217SDaniel Fojt     }
1957*32bb5217SDaniel Fojt #else
1958*32bb5217SDaniel Fojt     (void) extended;
1959*32bb5217SDaniel Fojt #endif
1960*32bb5217SDaniel Fojt 
19615f4613f2SJohn Marino     if (params[0]) {
19625f4613f2SJohn Marino 	_nc_warning("%s refers to parameter 0 (%%p0), which is not allowed", name);
19635f4613f2SJohn Marino     }
19645f4613f2SJohn Marino     if (value == set_attributes || expected < 0) {
19655f4613f2SJohn Marino 	;
19665f4613f2SJohn Marino     } else if (expected != actual) {
19675f4613f2SJohn Marino 	_nc_warning("%s uses %d parameters, expected %d", name,
19685f4613f2SJohn Marino 		    actual, expected);
19695f4613f2SJohn Marino 	for (n = 1; n < actual; n++) {
19705f4613f2SJohn Marino 	    if (!params[n])
19715f4613f2SJohn Marino 		_nc_warning("%s omits parameter %d", name, n);
19725f4613f2SJohn Marino 	}
19735f4613f2SJohn Marino     }
1974*32bb5217SDaniel Fojt 
1975*32bb5217SDaniel Fojt     /*
1976*32bb5217SDaniel Fojt      * Counting "%p" markers does not account for termcap expressions which
1977*32bb5217SDaniel Fojt      * may not have been fully translated.  Also, tparm does its own analysis.
1978*32bb5217SDaniel Fojt      * Report differences here.
1979*32bb5217SDaniel Fojt      */
1980*32bb5217SDaniel Fojt     if (actual >= 0) {
1981*32bb5217SDaniel Fojt 	char *p_is_s[NUM_PARM];
1982*32bb5217SDaniel Fojt 	int popcount;
1983*32bb5217SDaniel Fojt 	int analyzed = _nc_tparm_analyze(value, p_is_s, &popcount);
1984*32bb5217SDaniel Fojt 	if (analyzed < popcount) {
1985*32bb5217SDaniel Fojt 	    analyzed = popcount;
1986*32bb5217SDaniel Fojt 	}
1987*32bb5217SDaniel Fojt 	if (actual != analyzed && expected != analyzed) {
1988*32bb5217SDaniel Fojt #if NCURSES_XNAMES
1989*32bb5217SDaniel Fojt 	    int user_cap = is_user_capability(name);
1990*32bb5217SDaniel Fojt 	    if ((user_cap == analyzed) && using_extensions) {
1991*32bb5217SDaniel Fojt 		;		/* ignore */
1992*32bb5217SDaniel Fojt 	    } else if (user_cap >= 0) {
1993*32bb5217SDaniel Fojt 		_nc_warning("tparm will use %d parameters for %s, expected %d",
1994*32bb5217SDaniel Fojt 			    analyzed, name, user_cap);
1995*32bb5217SDaniel Fojt 	    } else
1996*32bb5217SDaniel Fojt #endif
1997*32bb5217SDaniel Fojt 	    {
1998*32bb5217SDaniel Fojt 		_nc_warning("tparm analyzed %d parameters for %s, expected %d",
1999*32bb5217SDaniel Fojt 			    analyzed, name, actual);
2000*32bb5217SDaniel Fojt 	    }
2001*32bb5217SDaniel Fojt 	}
2002*32bb5217SDaniel Fojt     }
2003*32bb5217SDaniel Fojt }
2004*32bb5217SDaniel Fojt 
2005*32bb5217SDaniel Fojt static bool
line_capability(const char * name)2006*32bb5217SDaniel Fojt line_capability(const char *name)
2007*32bb5217SDaniel Fojt {
2008*32bb5217SDaniel Fojt     bool result = FALSE;
2009*32bb5217SDaniel Fojt     static const char *table[] =
2010*32bb5217SDaniel Fojt     {
2011*32bb5217SDaniel Fojt 	"csr",			/* change_scroll_region          */
2012*32bb5217SDaniel Fojt 	"clear",		/* clear_screen                  */
2013*32bb5217SDaniel Fojt 	"ed",			/* clr_eos                       */
2014*32bb5217SDaniel Fojt 	"cwin",			/* create_window                 */
2015*32bb5217SDaniel Fojt 	"cup",			/* cursor_address                */
2016*32bb5217SDaniel Fojt 	"cud1",			/* cursor_down                   */
2017*32bb5217SDaniel Fojt 	"home",			/* cursor_home                   */
2018*32bb5217SDaniel Fojt 	"mrcup",		/* cursor_mem_address            */
2019*32bb5217SDaniel Fojt 	"ll",			/* cursor_to_ll                  */
2020*32bb5217SDaniel Fojt 	"cuu1",			/* cursor_up                     */
2021*32bb5217SDaniel Fojt 	"dl1",			/* delete_line                   */
2022*32bb5217SDaniel Fojt 	"hd",			/* down_half_line                */
2023*32bb5217SDaniel Fojt 	"flash",		/* flash_screen                  */
2024*32bb5217SDaniel Fojt 	"ff",			/* form_feed                     */
2025*32bb5217SDaniel Fojt 	"il1",			/* insert_line                   */
2026*32bb5217SDaniel Fojt 	"nel",			/* newline                       */
2027*32bb5217SDaniel Fojt 	"dl",			/* parm_delete_line              */
2028*32bb5217SDaniel Fojt 	"cud",			/* parm_down_cursor              */
2029*32bb5217SDaniel Fojt 	"indn",			/* parm_index                    */
2030*32bb5217SDaniel Fojt 	"il",			/* parm_insert_line              */
2031*32bb5217SDaniel Fojt 	"rin",			/* parm_rindex                   */
2032*32bb5217SDaniel Fojt 	"cuu",			/* parm_up_cursor                */
2033*32bb5217SDaniel Fojt 	"mc0",			/* print_screen                  */
2034*32bb5217SDaniel Fojt 	"vpa",			/* row_address                   */
2035*32bb5217SDaniel Fojt 	"ind",			/* scroll_forward                */
2036*32bb5217SDaniel Fojt 	"ri",			/* scroll_reverse                */
2037*32bb5217SDaniel Fojt 	"hu",			/* up_half_line                  */
2038*32bb5217SDaniel Fojt     };
2039*32bb5217SDaniel Fojt     size_t n;
2040*32bb5217SDaniel Fojt     for (n = 0; n < SIZEOF(table); ++n) {
2041*32bb5217SDaniel Fojt 	if (!strcmp(name, table[n])) {
2042*32bb5217SDaniel Fojt 	    result = TRUE;
2043*32bb5217SDaniel Fojt 	    break;
2044*32bb5217SDaniel Fojt 	}
2045*32bb5217SDaniel Fojt     }
2046*32bb5217SDaniel Fojt     return result;
2047*32bb5217SDaniel Fojt }
2048*32bb5217SDaniel Fojt 
2049*32bb5217SDaniel Fojt /*
2050*32bb5217SDaniel Fojt  * Check for DEC VT100 private mode for reverse video.
2051*32bb5217SDaniel Fojt  */
2052*32bb5217SDaniel Fojt static const char *
skip_DECSCNM(const char * value,int * flag)2053*32bb5217SDaniel Fojt skip_DECSCNM(const char *value, int *flag)
2054*32bb5217SDaniel Fojt {
2055*32bb5217SDaniel Fojt     *flag = -1;
2056*32bb5217SDaniel Fojt     if (value != 0) {
2057*32bb5217SDaniel Fojt 	int skip = csi_length(value);
2058*32bb5217SDaniel Fojt 	if (skip > 0 &&
2059*32bb5217SDaniel Fojt 	    value[skip++] == '?' &&
2060*32bb5217SDaniel Fojt 	    value[skip++] == '5') {
2061*32bb5217SDaniel Fojt 	    if (value[skip] == 'h') {
2062*32bb5217SDaniel Fojt 		*flag = 1;
2063*32bb5217SDaniel Fojt 	    } else if (value[skip] == 'l') {
2064*32bb5217SDaniel Fojt 		*flag = 0;
2065*32bb5217SDaniel Fojt 	    }
2066*32bb5217SDaniel Fojt 	    value += skip + 1;
2067*32bb5217SDaniel Fojt 	}
2068*32bb5217SDaniel Fojt     }
2069*32bb5217SDaniel Fojt     return value;
2070*32bb5217SDaniel Fojt }
2071*32bb5217SDaniel Fojt 
2072*32bb5217SDaniel Fojt static void
check_delays(TERMTYPE2 * tp,const char * name,const char * value)2073*32bb5217SDaniel Fojt check_delays(TERMTYPE2 *tp, const char *name, const char *value)
2074*32bb5217SDaniel Fojt {
2075*32bb5217SDaniel Fojt     const char *p, *q;
2076*32bb5217SDaniel Fojt     const char *first = 0;
2077*32bb5217SDaniel Fojt     const char *last = 0;
2078*32bb5217SDaniel Fojt 
2079*32bb5217SDaniel Fojt     for (p = value; *p != '\0'; ++p) {
2080*32bb5217SDaniel Fojt 	if (p[0] == '$' && p[1] == '<') {
2081*32bb5217SDaniel Fojt 	    const char *base = p + 2;
2082*32bb5217SDaniel Fojt 	    const char *mark = 0;
2083*32bb5217SDaniel Fojt 	    bool maybe = TRUE;
2084*32bb5217SDaniel Fojt 	    bool mixed = FALSE;
2085*32bb5217SDaniel Fojt 	    int proportional = 0;
2086*32bb5217SDaniel Fojt 	    int mandatory = 0;
2087*32bb5217SDaniel Fojt 
2088*32bb5217SDaniel Fojt 	    first = p;
2089*32bb5217SDaniel Fojt 
2090*32bb5217SDaniel Fojt 	    for (q = base; *q != '\0'; ++q) {
2091*32bb5217SDaniel Fojt 		if (*q == '>') {
2092*32bb5217SDaniel Fojt 		    if (mark == 0)
2093*32bb5217SDaniel Fojt 			mark = q;
2094*32bb5217SDaniel Fojt 		    break;
2095*32bb5217SDaniel Fojt 		} else if (*q == '*' || *q == '/') {
2096*32bb5217SDaniel Fojt 		    if (*q == '*')
2097*32bb5217SDaniel Fojt 			++proportional;
2098*32bb5217SDaniel Fojt 		    if (*q == '/')
2099*32bb5217SDaniel Fojt 			++mandatory;
2100*32bb5217SDaniel Fojt 		    if (mark == 0)
2101*32bb5217SDaniel Fojt 			mark = q;
2102*32bb5217SDaniel Fojt 		} else if (!(isalnum(UChar(*q)) || strchr("+-.", *q) != 0)) {
2103*32bb5217SDaniel Fojt 		    maybe = FALSE;
2104*32bb5217SDaniel Fojt 		    break;
2105*32bb5217SDaniel Fojt 		} else if (proportional || mandatory) {
2106*32bb5217SDaniel Fojt 		    mixed = TRUE;
2107*32bb5217SDaniel Fojt 		}
2108*32bb5217SDaniel Fojt 	    }
2109*32bb5217SDaniel Fojt 	    last = *q ? (q + 1) : q;
2110*32bb5217SDaniel Fojt 	    if (*q == '\0') {
2111*32bb5217SDaniel Fojt 		maybe = FALSE;	/* just an isolated "$<" */
2112*32bb5217SDaniel Fojt 	    } else if (maybe) {
2113*32bb5217SDaniel Fojt 		float check_f;
2114*32bb5217SDaniel Fojt 		char check_c;
2115*32bb5217SDaniel Fojt 		int rc = sscanf(base, "%f%c", &check_f, &check_c);
2116*32bb5217SDaniel Fojt 		if ((rc != 2) || (check_c != *mark) || mixed) {
2117*32bb5217SDaniel Fojt 		    _nc_warning("syntax error in %s delay '%.*s'", name,
2118*32bb5217SDaniel Fojt 				(int) (q - base), base);
2119*32bb5217SDaniel Fojt 		} else if (*name == 'k') {
2120*32bb5217SDaniel Fojt 		    _nc_warning("function-key %s has delay", name);
2121*32bb5217SDaniel Fojt 		} else if (proportional && !line_capability(name)) {
2122*32bb5217SDaniel Fojt 		    _nc_warning("non-line capability using proportional delay: %s", name);
2123*32bb5217SDaniel Fojt 		} else if (!xon_xoff &&
2124*32bb5217SDaniel Fojt 			   !mandatory &&
2125*32bb5217SDaniel Fojt 			   strchr(_nc_first_name(tp->term_names), '+') == 0) {
2126*32bb5217SDaniel Fojt 		    _nc_warning("%s in %s is used since no xon/xoff",
2127*32bb5217SDaniel Fojt 				(proportional
2128*32bb5217SDaniel Fojt 				 ? "proportional delay"
2129*32bb5217SDaniel Fojt 				 : "delay"),
2130*32bb5217SDaniel Fojt 				name);
2131*32bb5217SDaniel Fojt 		}
2132*32bb5217SDaniel Fojt 	    } else {
2133*32bb5217SDaniel Fojt 		p = q - 1;	/* restart scan */
2134*32bb5217SDaniel Fojt 	    }
2135*32bb5217SDaniel Fojt 	}
2136*32bb5217SDaniel Fojt     }
2137*32bb5217SDaniel Fojt 
2138*32bb5217SDaniel Fojt     if (!strcmp(name, "flash") ||
2139*32bb5217SDaniel Fojt 	!strcmp(name, "beep")) {
2140*32bb5217SDaniel Fojt 
2141*32bb5217SDaniel Fojt 	if (first != 0) {
2142*32bb5217SDaniel Fojt 	    if (first == value || *last == 0) {
2143*32bb5217SDaniel Fojt 		/*
2144*32bb5217SDaniel Fojt 		 * Delay is on one end or the other.
2145*32bb5217SDaniel Fojt 		 */
2146*32bb5217SDaniel Fojt 		_nc_warning("expected delay embedded within %s", name);
2147*32bb5217SDaniel Fojt 	    }
2148*32bb5217SDaniel Fojt 	} else {
2149*32bb5217SDaniel Fojt 	    int flag;
2150*32bb5217SDaniel Fojt 
2151*32bb5217SDaniel Fojt 	    /*
2152*32bb5217SDaniel Fojt 	     * Check for missing delay when using VT100 reverse-video.
2153*32bb5217SDaniel Fojt 	     * A real VT100 might not need this, but terminal emulators do.
2154*32bb5217SDaniel Fojt 	     */
2155*32bb5217SDaniel Fojt 	    if ((p = skip_DECSCNM(value, &flag)) != 0 &&
2156*32bb5217SDaniel Fojt 		flag > 0 &&
2157*32bb5217SDaniel Fojt 		(q = skip_DECSCNM(p, &flag)) != 0 &&
2158*32bb5217SDaniel Fojt 		flag == 0) {
2159*32bb5217SDaniel Fojt 		_nc_warning("expected a delay in %s", name);
2160*32bb5217SDaniel Fojt 	    }
2161*32bb5217SDaniel Fojt 	}
2162*32bb5217SDaniel Fojt     }
21635f4613f2SJohn Marino }
21645f4613f2SJohn Marino 
21655f4613f2SJohn Marino static char *
check_1_infotocap(const char * name,NCURSES_CONST char * value,int count)21663468e90cSJohn Marino check_1_infotocap(const char *name, NCURSES_CONST char *value, int count)
21673468e90cSJohn Marino {
21683468e90cSJohn Marino     int k;
21693468e90cSJohn Marino     int ignored;
21703468e90cSJohn Marino     long numbers[1 + NUM_PARM];
21713468e90cSJohn Marino     char *strings[1 + NUM_PARM];
21723468e90cSJohn Marino     char *p_is_s[NUM_PARM];
21733468e90cSJohn Marino     char *result;
21743468e90cSJohn Marino     char blob[NUM_PARM * 10];
21753468e90cSJohn Marino     char *next = blob;
21763468e90cSJohn Marino 
21773468e90cSJohn Marino     *next++ = '\0';
21783468e90cSJohn Marino     for (k = 1; k <= NUM_PARM; k++) {
21793468e90cSJohn Marino 	numbers[k] = count;
2180*32bb5217SDaniel Fojt 	_nc_SPRINTF(next,
2181*32bb5217SDaniel Fojt 		    _nc_SLIMIT(sizeof(blob) - (size_t) (next - blob))
2182*32bb5217SDaniel Fojt 		    "XYZ%d", count);
21833468e90cSJohn Marino 	strings[k] = next;
21843468e90cSJohn Marino 	next += strlen(next) + 1;
21853468e90cSJohn Marino     }
21863468e90cSJohn Marino 
21873468e90cSJohn Marino     switch (tparm_type(name)) {
21883468e90cSJohn Marino     case Num_Str:
21893468e90cSJohn Marino 	result = TPARM_2(value, numbers[1], strings[2]);
21903468e90cSJohn Marino 	break;
21913468e90cSJohn Marino     case Num_Str_Str:
21923468e90cSJohn Marino 	result = TPARM_3(value, numbers[1], strings[2], strings[3]);
21933468e90cSJohn Marino 	break;
21943468e90cSJohn Marino     case Numbers:
21953468e90cSJohn Marino     default:
21963468e90cSJohn Marino 	(void) _nc_tparm_analyze(value, p_is_s, &ignored);
21973468e90cSJohn Marino #define myParam(n) (p_is_s[n - 1] != 0 ? ((TPARM_ARG) strings[n]) : numbers[n])
21983468e90cSJohn Marino 	result = TPARM_9(value,
21993468e90cSJohn Marino 			 myParam(1),
22003468e90cSJohn Marino 			 myParam(2),
22013468e90cSJohn Marino 			 myParam(3),
22023468e90cSJohn Marino 			 myParam(4),
22033468e90cSJohn Marino 			 myParam(5),
22043468e90cSJohn Marino 			 myParam(6),
22053468e90cSJohn Marino 			 myParam(7),
22063468e90cSJohn Marino 			 myParam(8),
22073468e90cSJohn Marino 			 myParam(9));
22083468e90cSJohn Marino 	break;
22093468e90cSJohn Marino     }
2210*32bb5217SDaniel Fojt     return strdup(result);
22113468e90cSJohn Marino }
22123468e90cSJohn Marino 
22133468e90cSJohn Marino #define IsDelay(ch) ((ch) == '.' || isdigit(UChar(ch)))
22143468e90cSJohn Marino 
22153468e90cSJohn Marino static const char *
parse_delay_value(const char * src,double * delays,int * always)22163468e90cSJohn Marino parse_delay_value(const char *src, double *delays, int *always)
22173468e90cSJohn Marino {
22183468e90cSJohn Marino     int star = 0;
22193468e90cSJohn Marino 
22203468e90cSJohn Marino     *delays = 0.0;
22213468e90cSJohn Marino     if (always)
22223468e90cSJohn Marino 	*always = 0;
22233468e90cSJohn Marino 
22243468e90cSJohn Marino     while (isdigit(UChar(*src))) {
22253468e90cSJohn Marino 	(*delays) = (*delays) * 10 + (*src++ - '0');
22263468e90cSJohn Marino     }
22273468e90cSJohn Marino     if (*src == '.') {
22283468e90cSJohn Marino 	int gotdot = 1;
22293468e90cSJohn Marino 
22303468e90cSJohn Marino 	++src;
22313468e90cSJohn Marino 	while (isdigit(UChar(*src))) {
22323468e90cSJohn Marino 	    gotdot *= 10;
22333468e90cSJohn Marino 	    (*delays) += (*src++ - '0') / gotdot;
22343468e90cSJohn Marino 	}
22353468e90cSJohn Marino     }
22363468e90cSJohn Marino     while (*src == '*' || *src == '/') {
22373468e90cSJohn Marino 	if (always == 0 && *src == '/')
22383468e90cSJohn Marino 	    break;
22393468e90cSJohn Marino 	if (*src++ == '*') {
22403468e90cSJohn Marino 	    star = 1;
22413468e90cSJohn Marino 	} else {
22423468e90cSJohn Marino 	    *always = 1;
22433468e90cSJohn Marino 	}
22443468e90cSJohn Marino     }
22453468e90cSJohn Marino     if (star)
22463468e90cSJohn Marino 	*delays = -(*delays);
22473468e90cSJohn Marino     return src;
22483468e90cSJohn Marino }
22493468e90cSJohn Marino 
22503468e90cSJohn Marino static const char *
parse_ti_delay(const char * ti,double * delays)22513468e90cSJohn Marino parse_ti_delay(const char *ti, double *delays)
22523468e90cSJohn Marino {
22533468e90cSJohn Marino     *delays = 0.0;
22543468e90cSJohn Marino     while (*ti != '\0') {
22553468e90cSJohn Marino 	if (*ti == '\\') {
22563468e90cSJohn Marino 	    ++ti;
22573468e90cSJohn Marino 	}
22583468e90cSJohn Marino 	if (ti[0] == '$'
22593468e90cSJohn Marino 	    && ti[1] == '<'
22603468e90cSJohn Marino 	    && IsDelay(UChar(ti[2]))) {
22613468e90cSJohn Marino 	    int ignored;
22623468e90cSJohn Marino 	    const char *last = parse_delay_value(ti + 2, delays, &ignored);
22633468e90cSJohn Marino 	    if (*last == '>') {
22643468e90cSJohn Marino 		ti = last;
22653468e90cSJohn Marino 	    }
22663468e90cSJohn Marino 	} else {
22673468e90cSJohn Marino 	    ++ti;
22683468e90cSJohn Marino 	}
22693468e90cSJohn Marino     }
22703468e90cSJohn Marino     return ti;
22713468e90cSJohn Marino }
22723468e90cSJohn Marino 
22733468e90cSJohn Marino static const char *
parse_tc_delay(const char * tc,double * delays)22743468e90cSJohn Marino parse_tc_delay(const char *tc, double *delays)
22753468e90cSJohn Marino {
22763468e90cSJohn Marino     return parse_delay_value(tc, delays, (int *) 0);
22773468e90cSJohn Marino }
22783468e90cSJohn Marino 
22793468e90cSJohn Marino /*
22803468e90cSJohn Marino  * Compare terminfo- and termcap-strings, factoring out delays.
22813468e90cSJohn Marino  */
22823468e90cSJohn Marino static bool
same_ti_tc(const char * ti,const char * tc,bool * embedded)22833468e90cSJohn Marino same_ti_tc(const char *ti, const char *tc, bool * embedded)
22843468e90cSJohn Marino {
22853468e90cSJohn Marino     bool same = TRUE;
22863468e90cSJohn Marino     double ti_delay = 0.0;
22873468e90cSJohn Marino     double tc_delay = 0.0;
22883468e90cSJohn Marino     const char *ti_last;
22893468e90cSJohn Marino 
22903468e90cSJohn Marino     *embedded = FALSE;
22913468e90cSJohn Marino     ti_last = parse_ti_delay(ti, &ti_delay);
22923468e90cSJohn Marino     tc = parse_tc_delay(tc, &tc_delay);
22933468e90cSJohn Marino 
22943468e90cSJohn Marino     while ((ti < ti_last) && *tc) {
22953468e90cSJohn Marino 	if (*ti == '\\' && ispunct(UChar(ti[1]))) {
22963468e90cSJohn Marino 	    ++ti;
22973468e90cSJohn Marino 	    if ((*ti == '^') && !strncmp(tc, "\\136", 4)) {
22983468e90cSJohn Marino 		ti += 1;
22993468e90cSJohn Marino 		tc += 4;
23003468e90cSJohn Marino 		continue;
23013468e90cSJohn Marino 	    }
23023468e90cSJohn Marino 	} else if (ti[0] == '$' && ti[1] == '<') {
23033468e90cSJohn Marino 	    double no_delay;
23043468e90cSJohn Marino 	    const char *ss = parse_ti_delay(ti, &no_delay);
23053468e90cSJohn Marino 	    if (ss != ti) {
23063468e90cSJohn Marino 		*embedded = TRUE;
23073468e90cSJohn Marino 		ti = ss;
23083468e90cSJohn Marino 		continue;
23093468e90cSJohn Marino 	    }
23103468e90cSJohn Marino 	}
23113468e90cSJohn Marino 	if (*tc == '\\' && ispunct(UChar(tc[1]))) {
23123468e90cSJohn Marino 	    ++tc;
23133468e90cSJohn Marino 	}
23143468e90cSJohn Marino 	if (*ti++ != *tc++) {
23153468e90cSJohn Marino 	    same = FALSE;
23163468e90cSJohn Marino 	    break;
23173468e90cSJohn Marino 	}
23183468e90cSJohn Marino     }
23193468e90cSJohn Marino 
23203468e90cSJohn Marino     if (*embedded) {
23213468e90cSJohn Marino 	if (same) {
23223468e90cSJohn Marino 	    same = FALSE;
23233468e90cSJohn Marino 	} else {
23243468e90cSJohn Marino 	    *embedded = FALSE;	/* report only one problem */
23253468e90cSJohn Marino 	}
23263468e90cSJohn Marino     }
23273468e90cSJohn Marino 
23283468e90cSJohn Marino     return same;
23293468e90cSJohn Marino }
23303468e90cSJohn Marino 
23313468e90cSJohn Marino /*
23323468e90cSJohn Marino  * Check terminfo to termcap translation.
23333468e90cSJohn Marino  */
23343468e90cSJohn Marino static void
check_infotocap(TERMTYPE2 * tp,int i,const char * value)2335*32bb5217SDaniel Fojt check_infotocap(TERMTYPE2 *tp, int i, const char *value)
23363468e90cSJohn Marino {
23373468e90cSJohn Marino     const char *name = ExtStrname(tp, i, strnames);
2338*32bb5217SDaniel Fojt     int params = ((i < (int) SIZEOF(parametrized))
23393468e90cSJohn Marino 		  ? parametrized[i]
23403468e90cSJohn Marino 		  : ((*value == 'k')
23413468e90cSJohn Marino 		     ? 0
23423468e90cSJohn Marino 		     : has_params(value)));
23433468e90cSJohn Marino     int to_char = 0;
23443468e90cSJohn Marino     char *ti_value;
23453468e90cSJohn Marino     char *tc_value;
23463468e90cSJohn Marino     bool embedded;
23473468e90cSJohn Marino 
2348*32bb5217SDaniel Fojt     assert(SIZEOF(parametrized) == STRCOUNT);
23493468e90cSJohn Marino     if ((ti_value = _nc_tic_expand(value, TRUE, to_char)) == ABSENT_STRING) {
23503468e90cSJohn Marino 	_nc_warning("tic-expansion of %s failed", name);
23513468e90cSJohn Marino     } else if ((tc_value = _nc_infotocap(name, ti_value, params)) == ABSENT_STRING) {
23523468e90cSJohn Marino 	_nc_warning("tic-conversion of %s failed", name);
23533468e90cSJohn Marino     } else if (params > 0) {
23543468e90cSJohn Marino 	int limit = 5;
23553468e90cSJohn Marino 	int count;
23563468e90cSJohn Marino 	bool first = TRUE;
23573468e90cSJohn Marino 
23583468e90cSJohn Marino 	if (!strcmp(name, "setf")
23593468e90cSJohn Marino 	    || !strcmp(name, "setb")
23603468e90cSJohn Marino 	    || !strcmp(name, "setaf")
23613468e90cSJohn Marino 	    || !strcmp(name, "setab")) {
2362*32bb5217SDaniel Fojt 	    if ((limit = max_colors) > 16)
2363*32bb5217SDaniel Fojt 		limit = 16;
23643468e90cSJohn Marino 	}
23653468e90cSJohn Marino 	for (count = 0; count < limit; ++count) {
23663468e90cSJohn Marino 	    char *ti_check = check_1_infotocap(name, ti_value, count);
23673468e90cSJohn Marino 	    char *tc_check = check_1_infotocap(name, tc_value, count);
23683468e90cSJohn Marino 
23693468e90cSJohn Marino 	    if (strcmp(ti_check, tc_check)) {
23703468e90cSJohn Marino 		if (first) {
23713468e90cSJohn Marino 		    fprintf(stderr, "check_infotocap(%s)\n", name);
23723468e90cSJohn Marino 		    fprintf(stderr, "...ti '%s'\n", ti_value);
23733468e90cSJohn Marino 		    fprintf(stderr, "...tc '%s'\n", tc_value);
23743468e90cSJohn Marino 		    first = FALSE;
23753468e90cSJohn Marino 		}
23763468e90cSJohn Marino 		_nc_warning("tparm-conversion of %s(%d) differs between\n\tterminfo %s\n\ttermcap  %s",
23773468e90cSJohn Marino 			    name, count, ti_check, tc_check);
23783468e90cSJohn Marino 	    }
2379*32bb5217SDaniel Fojt 	    free(ti_check);
2380*32bb5217SDaniel Fojt 	    free(tc_check);
23813468e90cSJohn Marino 	}
23823468e90cSJohn Marino     } else if (params == 0 && !same_ti_tc(ti_value, tc_value, &embedded)) {
23833468e90cSJohn Marino 	if (embedded) {
23843468e90cSJohn Marino 	    _nc_warning("termcap equivalent of %s cannot use embedded delay", name);
23853468e90cSJohn Marino 	} else {
23863468e90cSJohn Marino 	    _nc_warning("tic-conversion of %s changed value\n\tfrom %s\n\tto   %s",
23873468e90cSJohn Marino 			name, ti_value, tc_value);
23883468e90cSJohn Marino 	}
23893468e90cSJohn Marino     }
23903468e90cSJohn Marino }
23913468e90cSJohn Marino 
23923468e90cSJohn Marino static char *
skip_delay(char * s)23935f4613f2SJohn Marino skip_delay(char *s)
23945f4613f2SJohn Marino {
23955f4613f2SJohn Marino     while (*s == '/' || isdigit(UChar(*s)))
23965f4613f2SJohn Marino 	++s;
23975f4613f2SJohn Marino     return s;
23985f4613f2SJohn Marino }
23995f4613f2SJohn Marino 
24005f4613f2SJohn Marino /*
24015f4613f2SJohn Marino  * Skip a delay altogether, e.g., when comparing a simple string to sgr,
24025f4613f2SJohn Marino  * the latter may have a worst-case delay on the end.
24035f4613f2SJohn Marino  */
24045f4613f2SJohn Marino static char *
ignore_delays(char * s)24055f4613f2SJohn Marino ignore_delays(char *s)
24065f4613f2SJohn Marino {
24075f4613f2SJohn Marino     int delaying = 0;
24085f4613f2SJohn Marino 
24095f4613f2SJohn Marino     do {
24105f4613f2SJohn Marino 	switch (*s) {
24115f4613f2SJohn Marino 	case '$':
24125f4613f2SJohn Marino 	    if (delaying == 0)
24135f4613f2SJohn Marino 		delaying = 1;
24145f4613f2SJohn Marino 	    break;
24155f4613f2SJohn Marino 	case '<':
24165f4613f2SJohn Marino 	    if (delaying == 1)
24175f4613f2SJohn Marino 		delaying = 2;
24185f4613f2SJohn Marino 	    break;
24195f4613f2SJohn Marino 	case '\0':
24205f4613f2SJohn Marino 	    delaying = 0;
24215f4613f2SJohn Marino 	    break;
24225f4613f2SJohn Marino 	default:
24235f4613f2SJohn Marino 	    if (delaying) {
24245f4613f2SJohn Marino 		s = skip_delay(s);
24255f4613f2SJohn Marino 		if (*s == '>')
24265f4613f2SJohn Marino 		    ++s;
24275f4613f2SJohn Marino 		delaying = 0;
24285f4613f2SJohn Marino 	    }
24295f4613f2SJohn Marino 	    break;
24305f4613f2SJohn Marino 	}
24315f4613f2SJohn Marino 	if (delaying)
24325f4613f2SJohn Marino 	    ++s;
24335f4613f2SJohn Marino     } while (delaying);
24345f4613f2SJohn Marino     return s;
24355f4613f2SJohn Marino }
24365f4613f2SJohn Marino 
24373468e90cSJohn Marino #define DATA(name) { #name }
24383468e90cSJohn Marino static const char sgr_names[][11] =
24393468e90cSJohn Marino {
24403468e90cSJohn Marino     DATA(none),
24413468e90cSJohn Marino     DATA(standout),
24423468e90cSJohn Marino     DATA(underline),
24433468e90cSJohn Marino     DATA(reverse),
24443468e90cSJohn Marino     DATA(blink),
24453468e90cSJohn Marino     DATA(dim),
24463468e90cSJohn Marino     DATA(bold),
24473468e90cSJohn Marino     DATA(invis),
24483468e90cSJohn Marino     DATA(protect),
24493468e90cSJohn Marino     DATA(altcharset),
24503468e90cSJohn Marino     ""
24513468e90cSJohn Marino };
24523468e90cSJohn Marino #undef DATA
24533468e90cSJohn Marino 
24545f4613f2SJohn Marino /*
24555f4613f2SJohn Marino  * An sgr string may contain several settings other than the one we're
24565f4613f2SJohn Marino  * interested in, essentially sgr0 + rmacs + whatever.  As long as the
24575f4613f2SJohn Marino  * "whatever" is contained in the sgr string, that is close enough for our
24585f4613f2SJohn Marino  * sanity check.
24595f4613f2SJohn Marino  */
24605f4613f2SJohn Marino static bool
similar_sgr(int num,char * a,char * b)24615f4613f2SJohn Marino similar_sgr(int num, char *a, char *b)
24625f4613f2SJohn Marino {
24635f4613f2SJohn Marino     char *base_a = a;
24645f4613f2SJohn Marino     char *base_b = b;
24655f4613f2SJohn Marino     int delaying = 0;
24665f4613f2SJohn Marino 
24675f4613f2SJohn Marino     while (*b != 0) {
24685f4613f2SJohn Marino 	while (*a != *b) {
24695f4613f2SJohn Marino 	    if (*a == 0) {
24703468e90cSJohn Marino 		if (num < 0) {
24713468e90cSJohn Marino 		    ;
24723468e90cSJohn Marino 		} else if (b[0] == '$'
24735f4613f2SJohn Marino 			   && b[1] == '<') {
2474*32bb5217SDaniel Fojt 		    _nc_warning("did not find delay %s", _nc_visbuf(b));
24755f4613f2SJohn Marino 		} else {
24765f4613f2SJohn Marino 		    _nc_warning("checking sgr(%s) %s\n\tcompare to %s\n\tunmatched %s",
24773468e90cSJohn Marino 				sgr_names[num], _nc_visbuf2(1, base_a),
24785f4613f2SJohn Marino 				_nc_visbuf2(2, base_b),
24795f4613f2SJohn Marino 				_nc_visbuf2(3, b));
24805f4613f2SJohn Marino 		}
24815f4613f2SJohn Marino 		return FALSE;
24825f4613f2SJohn Marino 	    } else if (delaying) {
24835f4613f2SJohn Marino 		a = skip_delay(a);
24845f4613f2SJohn Marino 		b = skip_delay(b);
24855f4613f2SJohn Marino 	    } else if ((*b == '0' || (*b == ';')) && *a == 'm') {
24865f4613f2SJohn Marino 		b++;
24875f4613f2SJohn Marino 	    } else {
24885f4613f2SJohn Marino 		a++;
24895f4613f2SJohn Marino 	    }
24905f4613f2SJohn Marino 	}
24915f4613f2SJohn Marino 	switch (*a) {
24925f4613f2SJohn Marino 	case '$':
24935f4613f2SJohn Marino 	    if (delaying == 0)
24945f4613f2SJohn Marino 		delaying = 1;
24955f4613f2SJohn Marino 	    break;
24965f4613f2SJohn Marino 	case '<':
24975f4613f2SJohn Marino 	    if (delaying == 1)
24985f4613f2SJohn Marino 		delaying = 2;
24995f4613f2SJohn Marino 	    break;
25005f4613f2SJohn Marino 	default:
25015f4613f2SJohn Marino 	    delaying = 0;
25025f4613f2SJohn Marino 	    break;
25035f4613f2SJohn Marino 	}
25045f4613f2SJohn Marino 	a++;
25055f4613f2SJohn Marino 	b++;
25065f4613f2SJohn Marino     }
25075f4613f2SJohn Marino     /* ignore delays on the end of the string */
25085f4613f2SJohn Marino     a = ignore_delays(a);
25095f4613f2SJohn Marino     return ((num != 0) || (*a == 0));
25105f4613f2SJohn Marino }
25115f4613f2SJohn Marino 
25125f4613f2SJohn Marino static char *
check_sgr(TERMTYPE2 * tp,char * zero,int num,char * cap,const char * name)2513*32bb5217SDaniel Fojt check_sgr(TERMTYPE2 *tp, char *zero, int num, char *cap, const char *name)
25145f4613f2SJohn Marino {
25155f4613f2SJohn Marino     char *test;
25165f4613f2SJohn Marino 
25175f4613f2SJohn Marino     _nc_tparm_err = 0;
25185f4613f2SJohn Marino     test = TPARM_9(set_attributes,
25195f4613f2SJohn Marino 		   num == 1,
25205f4613f2SJohn Marino 		   num == 2,
25215f4613f2SJohn Marino 		   num == 3,
25225f4613f2SJohn Marino 		   num == 4,
25235f4613f2SJohn Marino 		   num == 5,
25245f4613f2SJohn Marino 		   num == 6,
25255f4613f2SJohn Marino 		   num == 7,
25265f4613f2SJohn Marino 		   num == 8,
25275f4613f2SJohn Marino 		   num == 9);
25285f4613f2SJohn Marino     if (test != 0) {
25295f4613f2SJohn Marino 	if (PRESENT(cap)) {
25305f4613f2SJohn Marino 	    if (!similar_sgr(num, test, cap)) {
25315f4613f2SJohn Marino 		_nc_warning("%s differs from sgr(%d)\n\t%s=%s\n\tsgr(%d)=%s",
25325f4613f2SJohn Marino 			    name, num,
25335f4613f2SJohn Marino 			    name, _nc_visbuf2(1, cap),
25345f4613f2SJohn Marino 			    num, _nc_visbuf2(2, test));
25355f4613f2SJohn Marino 	    }
25365f4613f2SJohn Marino 	} else if (_nc_capcmp(test, zero)) {
25375f4613f2SJohn Marino 	    _nc_warning("sgr(%d) present, but not %s", num, name);
25385f4613f2SJohn Marino 	}
25395f4613f2SJohn Marino     } else if (PRESENT(cap)) {
25405f4613f2SJohn Marino 	_nc_warning("sgr(%d) missing, but %s present", num, name);
25415f4613f2SJohn Marino     }
25425f4613f2SJohn Marino     if (_nc_tparm_err)
25435f4613f2SJohn Marino 	_nc_warning("stack error in sgr(%d) string", num);
25445f4613f2SJohn Marino     return test;
25455f4613f2SJohn Marino }
25465f4613f2SJohn Marino 
25475f4613f2SJohn Marino #define CHECK_SGR(num,name) check_sgr(tp, zero, num, name, #name)
25485f4613f2SJohn Marino 
25495f4613f2SJohn Marino #ifdef TRACE
25505f4613f2SJohn Marino /*
25515f4613f2SJohn Marino  * If tic is compiled with TRACE, we'll be able to see the output from the
25525f4613f2SJohn Marino  * DEBUG() macro.  But since it doesn't use traceon(), it always goes to
25535f4613f2SJohn Marino  * the standard error.  Use this function to make it simpler to follow the
25545f4613f2SJohn Marino  * resulting debug traces.
25555f4613f2SJohn Marino  */
25565f4613f2SJohn Marino static void
show_where(unsigned level)25575f4613f2SJohn Marino show_where(unsigned level)
25585f4613f2SJohn Marino {
25595f4613f2SJohn Marino     if (_nc_tracing >= DEBUG_LEVEL(level)) {
25603468e90cSJohn Marino 	char my_name[MAX_NAME_SIZE];
25615f4613f2SJohn Marino 	_nc_get_type(my_name);
25625f4613f2SJohn Marino 	_tracef("\"%s\", line %d, '%s'",
25635f4613f2SJohn Marino 		_nc_get_source(),
25645f4613f2SJohn Marino 		_nc_curr_line, my_name);
25655f4613f2SJohn Marino     }
25665f4613f2SJohn Marino }
25675f4613f2SJohn Marino 
25685f4613f2SJohn Marino #else
25695f4613f2SJohn Marino #define show_where(level)	/* nothing */
25705f4613f2SJohn Marino #endif
25715f4613f2SJohn Marino 
25723468e90cSJohn Marino typedef struct {
25733468e90cSJohn Marino     int keycode;
25743468e90cSJohn Marino     const char *name;
25753468e90cSJohn Marino     const char *value;
25763468e90cSJohn Marino } NAME_VALUE;
25773468e90cSJohn Marino 
25783468e90cSJohn Marino static NAME_VALUE *
get_fkey_list(TERMTYPE2 * tp)2579*32bb5217SDaniel Fojt get_fkey_list(TERMTYPE2 *tp)
25803468e90cSJohn Marino {
25813468e90cSJohn Marino     NAME_VALUE *result = typeMalloc(NAME_VALUE, NUM_STRINGS(tp) + 1);
25823468e90cSJohn Marino     const struct tinfo_fkeys *all_fkeys = _nc_tinfo_fkeys;
25833468e90cSJohn Marino     int used = 0;
25843468e90cSJohn Marino     unsigned j;
25853468e90cSJohn Marino 
25863468e90cSJohn Marino     if (result == 0)
25873468e90cSJohn Marino 	failed("get_fkey_list");
25883468e90cSJohn Marino 
25893468e90cSJohn Marino     for (j = 0; all_fkeys[j].code; j++) {
25903468e90cSJohn Marino 	char *a = tp->Strings[all_fkeys[j].offset];
25913468e90cSJohn Marino 	if (VALID_STRING(a)) {
25923468e90cSJohn Marino 	    result[used].keycode = (int) all_fkeys[j].code;
25933468e90cSJohn Marino 	    result[used].name = strnames[all_fkeys[j].offset];
25943468e90cSJohn Marino 	    result[used].value = a;
25953468e90cSJohn Marino 	    ++used;
25963468e90cSJohn Marino 	}
25973468e90cSJohn Marino     }
25983468e90cSJohn Marino #if NCURSES_XNAMES
25993468e90cSJohn Marino     for (j = STRCOUNT; j < NUM_STRINGS(tp); ++j) {
26003468e90cSJohn Marino 	const char *name = ExtStrname(tp, (int) j, strnames);
26013468e90cSJohn Marino 	if (*name == 'k') {
26023468e90cSJohn Marino 	    result[used].keycode = -1;
26033468e90cSJohn Marino 	    result[used].name = name;
26043468e90cSJohn Marino 	    result[used].value = tp->Strings[j];
26053468e90cSJohn Marino 	    ++used;
26063468e90cSJohn Marino 	}
26073468e90cSJohn Marino     }
26083468e90cSJohn Marino #endif
26093468e90cSJohn Marino     result[used].keycode = 0;
26103468e90cSJohn Marino     return result;
26113468e90cSJohn Marino }
26123468e90cSJohn Marino 
26133468e90cSJohn Marino static void
show_fkey_name(NAME_VALUE * data)26143468e90cSJohn Marino show_fkey_name(NAME_VALUE * data)
26153468e90cSJohn Marino {
26163468e90cSJohn Marino     if (data->keycode > 0) {
26173468e90cSJohn Marino 	fprintf(stderr, " %s", keyname(data->keycode));
26183468e90cSJohn Marino 	fprintf(stderr, " (capability \"%s\")", data->name);
26193468e90cSJohn Marino     } else {
26203468e90cSJohn Marino 	fprintf(stderr, " capability \"%s\"", data->name);
26213468e90cSJohn Marino     }
26223468e90cSJohn Marino }
26233468e90cSJohn Marino 
26243468e90cSJohn Marino /*
26253468e90cSJohn Marino  * A terminal entry may contain more than one keycode assigned to a given
26263468e90cSJohn Marino  * string (e.g., KEY_END and KEY_LL).  But curses will only return one (the
26273468e90cSJohn Marino  * last one assigned).
26285f4613f2SJohn Marino  */
26295f4613f2SJohn Marino static void
check_conflict(TERMTYPE2 * tp)2630*32bb5217SDaniel Fojt check_conflict(TERMTYPE2 *tp)
26315f4613f2SJohn Marino {
26325f4613f2SJohn Marino     bool conflict = FALSE;
26335f4613f2SJohn Marino     unsigned j, k;
26345f4613f2SJohn Marino 
26355f4613f2SJohn Marino     if (!(_nc_syntax == SYN_TERMCAP && capdump)) {
26363468e90cSJohn Marino 	char *check = calloc((size_t) (NUM_STRINGS(tp) + 1), sizeof(char));
26373468e90cSJohn Marino 	NAME_VALUE *given = get_fkey_list(tp);
26383468e90cSJohn Marino 
26393468e90cSJohn Marino 	if (check == 0)
2640*32bb5217SDaniel Fojt 	    failed("check_conflict");
26413468e90cSJohn Marino 
26423468e90cSJohn Marino 	for (j = 0; given[j].keycode; ++j) {
26433468e90cSJohn Marino 	    const char *a = given[j].value;
26445f4613f2SJohn Marino 	    bool first = TRUE;
26453468e90cSJohn Marino 
2646*32bb5217SDaniel Fojt 	    if (!VALID_STRING(a))
2647*32bb5217SDaniel Fojt 		continue;
2648*32bb5217SDaniel Fojt 
26493468e90cSJohn Marino 	    for (k = j + 1; given[k].keycode; k++) {
26503468e90cSJohn Marino 		const char *b = given[k].value;
2651*32bb5217SDaniel Fojt 
2652*32bb5217SDaniel Fojt 		if (!VALID_STRING(b))
2653*32bb5217SDaniel Fojt 		    continue;
26543468e90cSJohn Marino 		if (check[k])
26555f4613f2SJohn Marino 		    continue;
2656*32bb5217SDaniel Fojt 
26575f4613f2SJohn Marino 		if (!_nc_capcmp(a, b)) {
26583468e90cSJohn Marino 		    check[j] = 1;
26593468e90cSJohn Marino 		    check[k] = 1;
26605f4613f2SJohn Marino 		    if (first) {
26615f4613f2SJohn Marino 			if (!conflict) {
2662*32bb5217SDaniel Fojt 			    _nc_warning("conflicting key definitions (using the last)");
26635f4613f2SJohn Marino 			    conflict = TRUE;
26645f4613f2SJohn Marino 			}
26653468e90cSJohn Marino 			fprintf(stderr, "...");
26663468e90cSJohn Marino 			show_fkey_name(given + j);
26673468e90cSJohn Marino 			fprintf(stderr, " is the same as");
26683468e90cSJohn Marino 			show_fkey_name(given + k);
26695f4613f2SJohn Marino 			first = FALSE;
26705f4613f2SJohn Marino 		    } else {
26713468e90cSJohn Marino 			fprintf(stderr, ", ");
26723468e90cSJohn Marino 			show_fkey_name(given + k);
26735f4613f2SJohn Marino 		    }
26745f4613f2SJohn Marino 		}
26755f4613f2SJohn Marino 	    }
26765f4613f2SJohn Marino 	    if (!first)
26775f4613f2SJohn Marino 		fprintf(stderr, "\n");
26785f4613f2SJohn Marino 	}
2679*32bb5217SDaniel Fojt #if NCURSES_XNAMES
2680*32bb5217SDaniel Fojt 	if (using_extensions) {
2681*32bb5217SDaniel Fojt 	    /* *INDENT-OFF* */
2682*32bb5217SDaniel Fojt 	    static struct {
2683*32bb5217SDaniel Fojt 		const char *xcurses;
2684*32bb5217SDaniel Fojt 		const char *shifted;
2685*32bb5217SDaniel Fojt 	    } table[] = {
2686*32bb5217SDaniel Fojt 		{ "kDC",  NULL },
2687*32bb5217SDaniel Fojt 		{ "kDN",  "kind" },
2688*32bb5217SDaniel Fojt 		{ "kEND", NULL },
2689*32bb5217SDaniel Fojt 		{ "kHOM", NULL },
2690*32bb5217SDaniel Fojt 		{ "kLFT", NULL },
2691*32bb5217SDaniel Fojt 		{ "kNXT", NULL },
2692*32bb5217SDaniel Fojt 		{ "kPRV", NULL },
2693*32bb5217SDaniel Fojt 		{ "kRIT", NULL },
2694*32bb5217SDaniel Fojt 		{ "kUP",  "kri" },
2695*32bb5217SDaniel Fojt 		{ NULL,   NULL },
2696*32bb5217SDaniel Fojt 	    };
2697*32bb5217SDaniel Fojt 	    /* *INDENT-ON* */
2698*32bb5217SDaniel Fojt 
2699*32bb5217SDaniel Fojt 	    /*
2700*32bb5217SDaniel Fojt 	     * SVr4 curses defines the "xcurses" names listed above except for
2701*32bb5217SDaniel Fojt 	     * the special cases in the "shifted" column.  When using these
2702*32bb5217SDaniel Fojt 	     * names for xterm's extensions, that was confusing, and resulted
2703*32bb5217SDaniel Fojt 	     * in adding extended capabilities with "2" (shift) suffix.  This
2704*32bb5217SDaniel Fojt 	     * check warns about unnecessary use of extensions for this quirk.
2705*32bb5217SDaniel Fojt 	     */
2706*32bb5217SDaniel Fojt 	    for (j = 0; given[j].keycode; ++j) {
2707*32bb5217SDaniel Fojt 		const char *find = given[j].name;
2708*32bb5217SDaniel Fojt 		int value;
2709*32bb5217SDaniel Fojt 		char ch;
2710*32bb5217SDaniel Fojt 
2711*32bb5217SDaniel Fojt 		if (!VALID_STRING(given[j].value))
2712*32bb5217SDaniel Fojt 		    continue;
2713*32bb5217SDaniel Fojt 
2714*32bb5217SDaniel Fojt 		for (k = 0; table[k].xcurses; ++k) {
2715*32bb5217SDaniel Fojt 		    const char *test = table[k].xcurses;
2716*32bb5217SDaniel Fojt 		    size_t size = strlen(test);
2717*32bb5217SDaniel Fojt 
2718*32bb5217SDaniel Fojt 		    if (!strncmp(find, test, size) && strcmp(find, test)) {
2719*32bb5217SDaniel Fojt 			switch (sscanf(find + size, "%d%c", &value, &ch)) {
2720*32bb5217SDaniel Fojt 			case 1:
2721*32bb5217SDaniel Fojt 			    if (value == 2) {
2722*32bb5217SDaniel Fojt 				_nc_warning("expected '%s' rather than '%s'",
2723*32bb5217SDaniel Fojt 					    (table[k].shifted
2724*32bb5217SDaniel Fojt 					     ? table[k].shifted
2725*32bb5217SDaniel Fojt 					     : test), find);
2726*32bb5217SDaniel Fojt 			    } else if (value < 2 || value > 15) {
2727*32bb5217SDaniel Fojt 				_nc_warning("expected numeric 2..15 '%s'", find);
2728*32bb5217SDaniel Fojt 			    }
2729*32bb5217SDaniel Fojt 			    break;
2730*32bb5217SDaniel Fojt 			default:
2731*32bb5217SDaniel Fojt 			    _nc_warning("expected numeric suffix for '%s'", find);
2732*32bb5217SDaniel Fojt 			    break;
2733*32bb5217SDaniel Fojt 			}
2734*32bb5217SDaniel Fojt 			break;
2735*32bb5217SDaniel Fojt 		    }
2736*32bb5217SDaniel Fojt 		}
2737*32bb5217SDaniel Fojt 	    }
2738*32bb5217SDaniel Fojt 	}
2739*32bb5217SDaniel Fojt #endif
27403468e90cSJohn Marino 	free(given);
27413468e90cSJohn Marino 	free(check);
27423468e90cSJohn Marino     }
27435f4613f2SJohn Marino }
27445f4613f2SJohn Marino 
27453468e90cSJohn Marino /*
27463468e90cSJohn Marino  * Exiting a video mode should not duplicate sgr0
27473468e90cSJohn Marino  */
27483468e90cSJohn Marino static void
check_exit_attribute(const char * name,char * test,char * trimmed,char * untrimmed)27493468e90cSJohn Marino check_exit_attribute(const char *name, char *test, char *trimmed, char *untrimmed)
27503468e90cSJohn Marino {
2751*32bb5217SDaniel Fojt     if (VALID_STRING(test) && (trimmed != 0)) {
27523468e90cSJohn Marino 	if (similar_sgr(-1, trimmed, test) ||
27533468e90cSJohn Marino 	    similar_sgr(-1, untrimmed, test)) {
27543468e90cSJohn Marino 	    _nc_warning("%s matches exit_attribute_mode", name);
27553468e90cSJohn Marino 	}
27563468e90cSJohn Marino     }
27573468e90cSJohn Marino }
27583468e90cSJohn Marino 
27593468e90cSJohn Marino /*
27603468e90cSJohn Marino  * Returns true if the string looks like a standard SGR string.
27613468e90cSJohn Marino  */
27623468e90cSJohn Marino static bool
is_sgr_string(char * value)27633468e90cSJohn Marino is_sgr_string(char *value)
27643468e90cSJohn Marino {
27653468e90cSJohn Marino     bool result = FALSE;
27663468e90cSJohn Marino 
27673468e90cSJohn Marino     if (VALID_STRING(value)) {
2768*32bb5217SDaniel Fojt 	int skip = csi_length(value);
2769*32bb5217SDaniel Fojt 
2770*32bb5217SDaniel Fojt 	if (skip) {
27713468e90cSJohn Marino 	    int ch;
2772*32bb5217SDaniel Fojt 
2773*32bb5217SDaniel Fojt 	    result = TRUE;
2774*32bb5217SDaniel Fojt 	    value += skip;
27753468e90cSJohn Marino 	    while ((ch = UChar(*value++)) != '\0') {
27763468e90cSJohn Marino 		if (isdigit(ch) || ch == ';') {
27773468e90cSJohn Marino 		    ;
27783468e90cSJohn Marino 		} else if (ch == 'm' && *value == '\0') {
27793468e90cSJohn Marino 		    ;
27803468e90cSJohn Marino 		} else {
27813468e90cSJohn Marino 		    result = FALSE;
27823468e90cSJohn Marino 		    break;
27833468e90cSJohn Marino 		}
27843468e90cSJohn Marino 	    }
27853468e90cSJohn Marino 	}
27863468e90cSJohn Marino     }
27873468e90cSJohn Marino     return result;
27883468e90cSJohn Marino }
27893468e90cSJohn Marino 
27903468e90cSJohn Marino /*
27913468e90cSJohn Marino  * Check if the given capability contains a given SGR attribute.
27923468e90cSJohn Marino  */
27933468e90cSJohn Marino static void
check_sgr_param(TERMTYPE2 * tp,int code,const char * name,char * value)2794*32bb5217SDaniel Fojt check_sgr_param(TERMTYPE2 *tp, int code, const char *name, char *value)
27953468e90cSJohn Marino {
27963468e90cSJohn Marino     if (VALID_STRING(value)) {
27973468e90cSJohn Marino 	int ncv = ((code != 0) ? (1 << (code - 1)) : 0);
27983468e90cSJohn Marino 	char *test = tgoto(value, 0, 0);
27993468e90cSJohn Marino 	if (is_sgr_string(test)) {
28003468e90cSJohn Marino 	    int param = 0;
28013468e90cSJohn Marino 	    int count = 0;
28023468e90cSJohn Marino 	    int skips = 0;
28033468e90cSJohn Marino 	    int color = (value == set_a_foreground ||
28043468e90cSJohn Marino 			 value == set_a_background ||
28053468e90cSJohn Marino 			 value == set_foreground ||
28063468e90cSJohn Marino 			 value == set_background);
28073468e90cSJohn Marino 	    while (*test != 0) {
28083468e90cSJohn Marino 		if (isdigit(UChar(*test))) {
28093468e90cSJohn Marino 		    param = 10 * param + (*test - '0');
28103468e90cSJohn Marino 		    ++count;
28113468e90cSJohn Marino 		} else {
28123468e90cSJohn Marino 		    if (count) {
28133468e90cSJohn Marino 			/*
28143468e90cSJohn Marino 			 * Avoid unnecessary warning for xterm 256color codes.
28153468e90cSJohn Marino 			 */
28163468e90cSJohn Marino 			if (color && (param == 38 || param == 48))
28173468e90cSJohn Marino 			    skips = 3;
28183468e90cSJohn Marino 			if ((skips-- <= 0) && (param == code))
28193468e90cSJohn Marino 			    break;
28203468e90cSJohn Marino 		    }
28213468e90cSJohn Marino 		    count = 0;
28223468e90cSJohn Marino 		    param = 0;
28233468e90cSJohn Marino 		}
28243468e90cSJohn Marino 		++test;
28253468e90cSJohn Marino 	    }
28263468e90cSJohn Marino 	    if (count != 0 && param == code) {
28273468e90cSJohn Marino 		if (code == 0 ||
28283468e90cSJohn Marino 		    no_color_video < 0 ||
28293468e90cSJohn Marino 		    !(no_color_video & ncv)) {
28303468e90cSJohn Marino 		    _nc_warning("\"%s\" SGR-attribute used in %s",
28313468e90cSJohn Marino 				sgr_names[code],
28323468e90cSJohn Marino 				name);
28333468e90cSJohn Marino 		}
28343468e90cSJohn Marino 	    }
28353468e90cSJohn Marino 	}
28363468e90cSJohn Marino     }
28373468e90cSJohn Marino }
28383468e90cSJohn Marino 
2839*32bb5217SDaniel Fojt #if NCURSES_XNAMES
2840*32bb5217SDaniel Fojt static int
standard_type(const char * name)2841*32bb5217SDaniel Fojt standard_type(const char *name)
2842*32bb5217SDaniel Fojt {
2843*32bb5217SDaniel Fojt     int result = -1;
2844*32bb5217SDaniel Fojt     const struct name_table_entry *np;
2845*32bb5217SDaniel Fojt 
2846*32bb5217SDaniel Fojt     if ((np = _nc_find_entry(name, _nc_get_hash_table(0))) != 0) {
2847*32bb5217SDaniel Fojt 	result = np->nte_type;
2848*32bb5217SDaniel Fojt     }
2849*32bb5217SDaniel Fojt     return result;
2850*32bb5217SDaniel Fojt }
2851*32bb5217SDaniel Fojt 
2852*32bb5217SDaniel Fojt static const char *
name_of_type(int type)2853*32bb5217SDaniel Fojt name_of_type(int type)
2854*32bb5217SDaniel Fojt {
2855*32bb5217SDaniel Fojt     const char *result = "unknown";
2856*32bb5217SDaniel Fojt     switch (type) {
2857*32bb5217SDaniel Fojt     case BOOLEAN:
2858*32bb5217SDaniel Fojt 	result = "boolean";
2859*32bb5217SDaniel Fojt 	break;
2860*32bb5217SDaniel Fojt     case NUMBER:
2861*32bb5217SDaniel Fojt 	result = "number";
2862*32bb5217SDaniel Fojt 	break;
2863*32bb5217SDaniel Fojt     case STRING:
2864*32bb5217SDaniel Fojt 	result = "string";
2865*32bb5217SDaniel Fojt 	break;
2866*32bb5217SDaniel Fojt     }
2867*32bb5217SDaniel Fojt     return result;
2868*32bb5217SDaniel Fojt }
2869*32bb5217SDaniel Fojt 
2870*32bb5217SDaniel Fojt static void
check_user_capability_type(const char * name,int actual)2871*32bb5217SDaniel Fojt check_user_capability_type(const char *name, int actual)
2872*32bb5217SDaniel Fojt {
2873*32bb5217SDaniel Fojt     if (lookup_user_capability(name) == 0) {
2874*32bb5217SDaniel Fojt 	int expected = standard_type(name);
2875*32bb5217SDaniel Fojt 	if (expected >= 0) {
2876*32bb5217SDaniel Fojt 	    _nc_warning("expected %s to be %s, but actually %s",
2877*32bb5217SDaniel Fojt 			name,
2878*32bb5217SDaniel Fojt 			name_of_type(actual),
2879*32bb5217SDaniel Fojt 			name_of_type(expected)
2880*32bb5217SDaniel Fojt 		);
2881*32bb5217SDaniel Fojt 	} else if (*name != 'k') {
2882*32bb5217SDaniel Fojt 	    _nc_warning("undocumented %s capability %s",
2883*32bb5217SDaniel Fojt 			name_of_type(actual),
2884*32bb5217SDaniel Fojt 			name);
2885*32bb5217SDaniel Fojt 	}
2886*32bb5217SDaniel Fojt     }
2887*32bb5217SDaniel Fojt }
2888*32bb5217SDaniel Fojt #endif
2889*32bb5217SDaniel Fojt 
28903468e90cSJohn Marino /* other sanity-checks (things that we don't want in the normal
28913468e90cSJohn Marino  * logic that reads a terminfo entry)
28923468e90cSJohn Marino  */
28933468e90cSJohn Marino static void
check_termtype(TERMTYPE2 * tp,bool literal)2894*32bb5217SDaniel Fojt check_termtype(TERMTYPE2 *tp, bool literal)
28953468e90cSJohn Marino {
28963468e90cSJohn Marino     unsigned j;
28973468e90cSJohn Marino 
28983468e90cSJohn Marino     check_conflict(tp);
28993468e90cSJohn Marino 
29003468e90cSJohn Marino     for_each_string(j, tp) {
29015f4613f2SJohn Marino 	char *a = tp->Strings[j];
29023468e90cSJohn Marino 	if (VALID_STRING(a)) {
2903*32bb5217SDaniel Fojt 	    const char *name = ExtStrname(tp, (int) j, strnames);
2904*32bb5217SDaniel Fojt 	    /*
2905*32bb5217SDaniel Fojt 	     * If we expect parameters, or if there might be parameters,
2906*32bb5217SDaniel Fojt 	     * check for consistent number of parameters.
2907*32bb5217SDaniel Fojt 	     */
2908*32bb5217SDaniel Fojt 	    if (j >= SIZEOF(parametrized) ||
2909*32bb5217SDaniel Fojt 		is_user_capability(name) >= 0 ||
2910*32bb5217SDaniel Fojt 		parametrized[j] > 0) {
2911*32bb5217SDaniel Fojt 		check_params(tp, name, a, (j >= STRCOUNT));
2912*32bb5217SDaniel Fojt 	    }
2913*32bb5217SDaniel Fojt 	    check_delays(tp, ExtStrname(tp, (int) j, strnames), a);
29143468e90cSJohn Marino 	    if (capdump) {
29153468e90cSJohn Marino 		check_infotocap(tp, (int) j, a);
29163468e90cSJohn Marino 	    }
29173468e90cSJohn Marino 	}
29185f4613f2SJohn Marino     }
2919*32bb5217SDaniel Fojt #if NCURSES_XNAMES
2920*32bb5217SDaniel Fojt     /* in extended mode, verify that each extension is expected type */
2921*32bb5217SDaniel Fojt     for_each_ext_boolean(j, tp) {
2922*32bb5217SDaniel Fojt 	check_user_capability_type(ExtBoolname(tp, (int) j, strnames), BOOLEAN);
2923*32bb5217SDaniel Fojt     }
2924*32bb5217SDaniel Fojt     for_each_ext_number(j, tp) {
2925*32bb5217SDaniel Fojt 	check_user_capability_type(ExtNumname(tp, (int) j, strnames), NUMBER);
2926*32bb5217SDaniel Fojt     }
2927*32bb5217SDaniel Fojt     for_each_ext_string(j, tp) {
2928*32bb5217SDaniel Fojt 	check_user_capability_type(ExtStrname(tp, (int) j, strnames), STRING);
2929*32bb5217SDaniel Fojt     }
2930*32bb5217SDaniel Fojt #endif /* NCURSES_XNAMES */
29315f4613f2SJohn Marino 
29325f4613f2SJohn Marino     check_acs(tp);
29335f4613f2SJohn Marino     check_colors(tp);
29345f4613f2SJohn Marino     check_cursor(tp);
29355f4613f2SJohn Marino     check_keypad(tp);
29365f4613f2SJohn Marino     check_printer(tp);
29373468e90cSJohn Marino     check_screen(tp);
29385f4613f2SJohn Marino 
29395f4613f2SJohn Marino     /*
2940*32bb5217SDaniel Fojt      * These are probably both or none.
2941*32bb5217SDaniel Fojt      */
2942*32bb5217SDaniel Fojt     PAIRED(parm_index, parm_rindex);
2943*32bb5217SDaniel Fojt     PAIRED(parm_ich, parm_dch);
2944*32bb5217SDaniel Fojt 
2945*32bb5217SDaniel Fojt     /*
29465f4613f2SJohn Marino      * These may be mismatched because the terminal description relies on
29475f4613f2SJohn Marino      * restoring the cursor visibility by resetting it.
29485f4613f2SJohn Marino      */
29495f4613f2SJohn Marino     ANDMISSING(cursor_invisible, cursor_normal);
29505f4613f2SJohn Marino     ANDMISSING(cursor_visible, cursor_normal);
29515f4613f2SJohn Marino 
29525f4613f2SJohn Marino     if (PRESENT(cursor_visible) && PRESENT(cursor_normal)
29535f4613f2SJohn Marino 	&& !_nc_capcmp(cursor_visible, cursor_normal))
29545f4613f2SJohn Marino 	_nc_warning("cursor_visible is same as cursor_normal");
29555f4613f2SJohn Marino 
29565f4613f2SJohn Marino     /*
29575f4613f2SJohn Marino      * From XSI & O'Reilly, we gather that sc/rc are required if csr is
29585f4613f2SJohn Marino      * given, because the cursor position after the scrolling operation is
29595f4613f2SJohn Marino      * performed is undefined.
29605f4613f2SJohn Marino      */
29615f4613f2SJohn Marino     ANDMISSING(change_scroll_region, save_cursor);
29625f4613f2SJohn Marino     ANDMISSING(change_scroll_region, restore_cursor);
29635f4613f2SJohn Marino 
29645f4613f2SJohn Marino     /*
29655f4613f2SJohn Marino      * If we can clear tabs, we should be able to initialize them.
29665f4613f2SJohn Marino      */
29675f4613f2SJohn Marino     ANDMISSING(clear_all_tabs, set_tab);
29685f4613f2SJohn Marino 
29695f4613f2SJohn Marino     if (PRESENT(set_attributes)) {
29705f4613f2SJohn Marino 	char *zero = 0;
29715f4613f2SJohn Marino 
29725f4613f2SJohn Marino 	_nc_tparm_err = 0;
29735f4613f2SJohn Marino 	if (PRESENT(exit_attribute_mode)) {
29745f4613f2SJohn Marino 	    zero = strdup(CHECK_SGR(0, exit_attribute_mode));
29755f4613f2SJohn Marino 	} else {
29765f4613f2SJohn Marino 	    zero = strdup(TPARM_9(set_attributes, 0, 0, 0, 0, 0, 0, 0, 0, 0));
29775f4613f2SJohn Marino 	}
29785f4613f2SJohn Marino 	if (_nc_tparm_err)
29795f4613f2SJohn Marino 	    _nc_warning("stack error in sgr(0) string");
29805f4613f2SJohn Marino 
29815f4613f2SJohn Marino 	if (zero != 0) {
29825f4613f2SJohn Marino 	    CHECK_SGR(1, enter_standout_mode);
29835f4613f2SJohn Marino 	    CHECK_SGR(2, enter_underline_mode);
29845f4613f2SJohn Marino 	    CHECK_SGR(3, enter_reverse_mode);
29855f4613f2SJohn Marino 	    CHECK_SGR(4, enter_blink_mode);
29865f4613f2SJohn Marino 	    CHECK_SGR(5, enter_dim_mode);
29875f4613f2SJohn Marino 	    CHECK_SGR(6, enter_bold_mode);
29885f4613f2SJohn Marino 	    CHECK_SGR(7, enter_secure_mode);
29895f4613f2SJohn Marino 	    CHECK_SGR(8, enter_protected_mode);
29905f4613f2SJohn Marino 	    CHECK_SGR(9, enter_alt_charset_mode);
29915f4613f2SJohn Marino 	    free(zero);
29925f4613f2SJohn Marino 	} else {
29935f4613f2SJohn Marino 	    _nc_warning("sgr(0) did not return a value");
29945f4613f2SJohn Marino 	}
29955f4613f2SJohn Marino     } else if (PRESENT(exit_attribute_mode) &&
29965f4613f2SJohn Marino 	       set_attributes != CANCELLED_STRING) {
29975f4613f2SJohn Marino 	if (_nc_syntax == SYN_TERMINFO)
29985f4613f2SJohn Marino 	    _nc_warning("missing sgr string");
29995f4613f2SJohn Marino     }
30003468e90cSJohn Marino #define CHECK_SGR0(name) check_exit_attribute(#name, name, check_sgr0, exit_attribute_mode)
30015f4613f2SJohn Marino     if (PRESENT(exit_attribute_mode)) {
30025f4613f2SJohn Marino 	char *check_sgr0 = _nc_trim_sgr0(tp);
30035f4613f2SJohn Marino 
30045f4613f2SJohn Marino 	if (check_sgr0 == 0 || *check_sgr0 == '\0') {
30055f4613f2SJohn Marino 	    _nc_warning("trimmed sgr0 is empty");
30065f4613f2SJohn Marino 	} else {
30075f4613f2SJohn Marino 	    show_where(2);
30085f4613f2SJohn Marino 	    if (check_sgr0 != exit_attribute_mode) {
30095f4613f2SJohn Marino 		DEBUG(2,
30105f4613f2SJohn Marino 		      ("will trim sgr0\n\toriginal sgr0=%s\n\ttrimmed  sgr0=%s",
30115f4613f2SJohn Marino 		       _nc_visbuf2(1, exit_attribute_mode),
30125f4613f2SJohn Marino 		       _nc_visbuf2(2, check_sgr0)));
30135f4613f2SJohn Marino 	    } else {
30145f4613f2SJohn Marino 		DEBUG(2,
30155f4613f2SJohn Marino 		      ("will not trim sgr0\n\toriginal sgr0=%s",
30165f4613f2SJohn Marino 		       _nc_visbuf(exit_attribute_mode)));
30175f4613f2SJohn Marino 	    }
30185f4613f2SJohn Marino 	}
3019*32bb5217SDaniel Fojt #if defined(exit_italics_mode)
30203468e90cSJohn Marino 	CHECK_SGR0(exit_italics_mode);
3021*32bb5217SDaniel Fojt #endif
30223468e90cSJohn Marino 	CHECK_SGR0(exit_standout_mode);
30233468e90cSJohn Marino 	CHECK_SGR0(exit_underline_mode);
30243468e90cSJohn Marino 	if (check_sgr0 != exit_attribute_mode) {
30253468e90cSJohn Marino 	    free(check_sgr0);
30263468e90cSJohn Marino 	}
30273468e90cSJohn Marino     }
30283468e90cSJohn Marino #define CHECK_SGR_PARAM(code, name) check_sgr_param(tp, (int)code, #name, name)
30293468e90cSJohn Marino     for (j = 0; *sgr_names[j] != '\0'; ++j) {
30303468e90cSJohn Marino 	CHECK_SGR_PARAM(j, set_a_foreground);
30313468e90cSJohn Marino 	CHECK_SGR_PARAM(j, set_a_background);
30323468e90cSJohn Marino 	CHECK_SGR_PARAM(j, set_foreground);
30333468e90cSJohn Marino 	CHECK_SGR_PARAM(j, set_background);
30345f4613f2SJohn Marino     }
30355f4613f2SJohn Marino #ifdef TRACE
30365f4613f2SJohn Marino     show_where(2);
30375f4613f2SJohn Marino     if (!auto_right_margin) {
30385f4613f2SJohn Marino 	DEBUG(2,
30395f4613f2SJohn Marino 	      ("can write to lower-right directly"));
30405f4613f2SJohn Marino     } else if (PRESENT(enter_am_mode) && PRESENT(exit_am_mode)) {
30415f4613f2SJohn Marino 	DEBUG(2,
30425f4613f2SJohn Marino 	      ("can write to lower-right by suppressing automargin"));
30435f4613f2SJohn Marino     } else if ((PRESENT(enter_insert_mode) && PRESENT(exit_insert_mode))
30445f4613f2SJohn Marino 	       || PRESENT(insert_character) || PRESENT(parm_ich)) {
30455f4613f2SJohn Marino 	DEBUG(2,
30465f4613f2SJohn Marino 	      ("can write to lower-right by using inserts"));
30475f4613f2SJohn Marino     } else {
30485f4613f2SJohn Marino 	DEBUG(2,
30495f4613f2SJohn Marino 	      ("cannot write to lower-right"));
30505f4613f2SJohn Marino     }
30515f4613f2SJohn Marino #endif
30525f4613f2SJohn Marino 
30535f4613f2SJohn Marino     /*
30545f4613f2SJohn Marino      * Some standard applications (e.g., vi) and some non-curses
30555f4613f2SJohn Marino      * applications (e.g., jove) get confused if we have both ich1 and
30565f4613f2SJohn Marino      * smir/rmir.  Let's be nice and warn about that, too, even though
30575f4613f2SJohn Marino      * ncurses handles it.
30585f4613f2SJohn Marino      */
30595f4613f2SJohn Marino     if ((PRESENT(enter_insert_mode) || PRESENT(exit_insert_mode))
3060*32bb5217SDaniel Fojt 	&& PRESENT(insert_character)) {
30615f4613f2SJohn Marino 	_nc_warning("non-curses applications may be confused by ich1 with smir/rmir");
30625f4613f2SJohn Marino     }
30635f4613f2SJohn Marino 
30645f4613f2SJohn Marino     /*
30655f4613f2SJohn Marino      * Finally, do the non-verbose checks
30665f4613f2SJohn Marino      */
30675f4613f2SJohn Marino     if (save_check_termtype != 0)
30685f4613f2SJohn Marino 	save_check_termtype(tp, literal);
30695f4613f2SJohn Marino }
3070