tic.c revision 98503
150276Speter/****************************************************************************
298503Speter * Copyright (c) 1998-2001,2002 Free Software Foundation, Inc.              *
350276Speter *                                                                          *
450276Speter * Permission is hereby granted, free of charge, to any person obtaining a  *
550276Speter * copy of this software and associated documentation files (the            *
650276Speter * "Software"), to deal in the Software without restriction, including      *
750276Speter * without limitation the rights to use, copy, modify, merge, publish,      *
850276Speter * distribute, distribute with modifications, sublicense, and/or sell       *
950276Speter * copies of the Software, and to permit persons to whom the Software is    *
1050276Speter * furnished to do so, subject to the following conditions:                 *
1150276Speter *                                                                          *
1250276Speter * The above copyright notice and this permission notice shall be included  *
1350276Speter * in all copies or substantial portions of the Software.                   *
1450276Speter *                                                                          *
1550276Speter * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
1650276Speter * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
1750276Speter * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
1850276Speter * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
1950276Speter * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
2050276Speter * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
2150276Speter * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
2250276Speter *                                                                          *
2350276Speter * Except as contained in this notice, the name(s) of the above copyright   *
2450276Speter * holders shall not be used in advertising or otherwise to promote the     *
2550276Speter * sale, use or other dealings in this Software without prior written       *
2650276Speter * authorization.                                                           *
2750276Speter ****************************************************************************/
2850276Speter
2950276Speter/****************************************************************************
3050276Speter *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
3150276Speter *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
3298503Speter *     and: Thomas E. Dickey 1996 on                                        *
3350276Speter ****************************************************************************/
3450276Speter
3550276Speter/*
3650276Speter *	tic.c --- Main program for terminfo compiler
3750276Speter *			by Eric S. Raymond
3850276Speter *
3950276Speter */
4050276Speter
4150276Speter#include <progs.priv.h>
4266963Speter#include <sys/stat.h>
4350276Speter
4450276Speter#include <dump_entry.h>
4550276Speter#include <term_entry.h>
4666963Speter#include <transform.h>
4750276Speter
4898503SpeterMODULE_ID("$Id: tic.c,v 1.96 2002/06/01 20:42:53 tom Exp $")
4950276Speter
5050276Speterconst char *_nc_progname = "tic";
5150276Speter
5262449Speterstatic FILE *log_fp;
5362449Speterstatic FILE *tmp_fp;
5462449Speterstatic bool showsummary = FALSE;
5562449Speterstatic const char *to_remove;
5676726Speterstatic int tparm_errs;
5750276Speter
5862449Speterstatic void (*save_check_termtype) (TERMTYPE *);
5962449Speterstatic void check_termtype(TERMTYPE * tt);
6050276Speter
6166963Speterstatic const char usage_string[] = "[-V] [-v[n]] [-e names] [-CILNRTcfrswx1] source-file\n";
6250276Speter
6362449Speterstatic void
6462449Spetercleanup(void)
6550276Speter{
6662449Speter    if (tmp_fp != 0)
6762449Speter	fclose(tmp_fp);
6862449Speter    if (to_remove != 0) {
6950276Speter#if HAVE_REMOVE
7062449Speter	remove(to_remove);
7150276Speter#else
7262449Speter	unlink(to_remove);
7350276Speter#endif
7462449Speter    }
7550276Speter}
7650276Speter
7762449Speterstatic void
7862449Speterfailed(const char *msg)
7950276Speter{
8062449Speter    perror(msg);
8162449Speter    cleanup();
8262449Speter    exit(EXIT_FAILURE);
8350276Speter}
8450276Speter
8562449Speterstatic void
8662449Speterusage(void)
8750276Speter{
8862449Speter    static const char *const tbl[] =
8962449Speter    {
9050276Speter	"Options:",
9150276Speter	"  -1         format translation output one capability per line",
9250276Speter	"  -C         translate entries to termcap source form",
9350276Speter	"  -I         translate entries to terminfo source form",
9450276Speter	"  -L         translate entries to full terminfo source form",
9550276Speter	"  -N         disable smart defaults for source translation",
9650276Speter	"  -R         restrict translation to given terminfo/termcap version",
9750276Speter	"  -T         remove size-restrictions on compiled description",
9866963Speter	"  -V         print version",
9962449Speter#if NCURSES_XNAMES
10062449Speter	"  -a         retain commented-out capabilities (sets -x also)",
10162449Speter#endif
10250276Speter	"  -c         check only, validate input without compiling or translating",
10350276Speter	"  -f         format complex strings for readability",
10450276Speter	"  -G         format %{number} to %'char'",
10550276Speter	"  -g         format %'char' to %{number}",
10650276Speter	"  -e<names>  translate/compile only entries named by comma-separated list",
10750276Speter	"  -o<dir>    set output directory for compiled entry writes",
10850276Speter	"  -r         force resolution of all use entries in source translation",
10950276Speter	"  -s         print summary statistics",
11050276Speter	"  -v[n]      set verbosity level",
11150276Speter	"  -w[n]      set format width for translation output",
11250276Speter#if NCURSES_XNAMES
11350276Speter	"  -x         treat unknown capabilities as user-defined",
11450276Speter#endif
11550276Speter	"",
11650276Speter	"Parameters:",
11750276Speter	"  <file>     file to translate or compile"
11862449Speter    };
11962449Speter    size_t j;
12050276Speter
12162449Speter    fprintf(stderr, "Usage: %s %s\n", _nc_progname, usage_string);
12266963Speter    for (j = 0; j < SIZEOF(tbl); j++) {
12362449Speter	fputs(tbl[j], stderr);
12462449Speter	putc('\n', stderr);
12562449Speter    }
12662449Speter    exit(EXIT_FAILURE);
12750276Speter}
12850276Speter
12950276Speter#define L_BRACE '{'
13050276Speter#define R_BRACE '}'
13150276Speter#define S_QUOTE '\'';
13250276Speter
13362449Speterstatic void
13462449Speterwrite_it(ENTRY * ep)
13550276Speter{
13662449Speter    unsigned n;
13762449Speter    int ch;
13862449Speter    char *s, *d, *t;
13962449Speter    char result[MAX_ENTRY_SIZE];
14050276Speter
14162449Speter    /*
14262449Speter     * Look for strings that contain %{number}, convert them to %'char',
14362449Speter     * which is shorter and runs a little faster.
14462449Speter     */
14562449Speter    for (n = 0; n < STRCOUNT; n++) {
14662449Speter	s = ep->tterm.Strings[n];
14762449Speter	if (VALID_STRING(s)
14862449Speter	    && strchr(s, L_BRACE) != 0) {
14962449Speter	    d = result;
15062449Speter	    t = s;
15162449Speter	    while ((ch = *t++) != 0) {
15262449Speter		*d++ = ch;
15362449Speter		if (ch == '\\') {
15462449Speter		    *d++ = *t++;
15562449Speter		} else if ((ch == '%')
15666963Speter			   && (*t == L_BRACE)) {
15762449Speter		    char *v = 0;
15862449Speter		    long value = strtol(t + 1, &v, 0);
15962449Speter		    if (v != 0
16062449Speter			&& *v == R_BRACE
16162449Speter			&& value > 0
16262449Speter			&& value != '\\'	/* FIXME */
16362449Speter			&& value < 127
16462449Speter			&& isprint((int) value)) {
16562449Speter			*d++ = S_QUOTE;
16662449Speter			*d++ = (int) value;
16762449Speter			*d++ = S_QUOTE;
16862449Speter			t = (v + 1);
16962449Speter		    }
17050276Speter		}
17162449Speter	    }
17262449Speter	    *d = 0;
17362449Speter	    if (strlen(result) < strlen(s))
17462449Speter		strcpy(s, result);
17550276Speter	}
17662449Speter    }
17750276Speter
17862449Speter    _nc_set_type(_nc_first_name(ep->tterm.term_names));
17962449Speter    _nc_curr_line = ep->startline;
18062449Speter    _nc_write_entry(&ep->tterm);
18150276Speter}
18250276Speter
18362449Speterstatic bool
18462449Speterimmedhook(ENTRY * ep GCC_UNUSED)
18550276Speter/* write out entries with no use capabilities immediately to save storage */
18650276Speter{
18766963Speter#if !HAVE_BIG_CORE
18850276Speter    /*
18950276Speter     * This is strictly a core-economy kluge.  The really clean way to handle
19050276Speter     * compilation is to slurp the whole file into core and then do all the
19150276Speter     * name-collision checks and entry writes in one swell foop.  But the
19250276Speter     * terminfo master file is large enough that some core-poor systems swap
19350276Speter     * like crazy when you compile it this way...there have been reports of
19450276Speter     * this process taking *three hours*, rather than the twenty seconds or
19550276Speter     * less typical on my development box.
19650276Speter     *
19750276Speter     * So.  This hook *immediately* writes out the referenced entry if it
19850276Speter     * has no use capabilities.  The compiler main loop refrains from
19950276Speter     * adding the entry to the in-core list when this hook fires.  If some
20050276Speter     * other entry later needs to reference an entry that got written
20150276Speter     * immediately, that's OK; the resolution code will fetch it off disk
20250276Speter     * when it can't find it in core.
20350276Speter     *
20450276Speter     * Name collisions will still be detected, just not as cleanly.  The
20550276Speter     * write_entry() code complains before overwriting an entry that
20650276Speter     * postdates the time of tic's first call to write_entry().  Thus
20750276Speter     * it will complain about overwriting entries newly made during the
20850276Speter     * tic run, but not about overwriting ones that predate it.
20950276Speter     *
21050276Speter     * The reason this is a hook, and not in line with the rest of the
21150276Speter     * compiler code, is that the support for termcap fallback cannot assume
21250276Speter     * it has anywhere to spool out these entries!
21350276Speter     *
21450276Speter     * The _nc_set_type() call here requires a compensating one in
21550276Speter     * _nc_parse_entry().
21650276Speter     *
21750276Speter     * If you define HAVE_BIG_CORE, you'll disable this kluge.  This will
21850276Speter     * make tic a bit faster (because the resolution code won't have to do
21950276Speter     * disk I/O nearly as often).
22050276Speter     */
22162449Speter    if (ep->nuses == 0) {
22262449Speter	int oldline = _nc_curr_line;
22350276Speter
22450276Speter	write_it(ep);
22550276Speter	_nc_curr_line = oldline;
22650276Speter	free(ep->tterm.str_table);
22762449Speter	return (TRUE);
22850276Speter    }
22950276Speter#endif /* HAVE_BIG_CORE */
23062449Speter    return (FALSE);
23150276Speter}
23250276Speter
23362449Speterstatic void
23462449Speterput_translate(int c)
23550276Speter/* emit a comment char, translating terminfo names to termcap names */
23650276Speter{
23750276Speter    static bool in_name = FALSE;
23862449Speter    static size_t have, used;
23962449Speter    static char *namebuf, *suffix;
24050276Speter
24162449Speter    if (in_name) {
24262449Speter	if (used + 1 >= have) {
24362449Speter	    have += 132;
24462449Speter	    namebuf = typeRealloc(char, have, namebuf);
24562449Speter	    suffix = typeRealloc(char, have, suffix);
24650276Speter	}
24762449Speter	if (c == '\n' || c == '@') {
24862449Speter	    namebuf[used++] = '\0';
24962449Speter	    (void) putchar('<');
25062449Speter	    (void) fputs(namebuf, stdout);
25150276Speter	    putchar(c);
25262449Speter	    in_name = FALSE;
25362449Speter	} else if (c != '>') {
25462449Speter	    namebuf[used++] = c;
25562449Speter	} else {		/* ah! candidate name! */
25662449Speter	    char *up;
25762449Speter	    NCURSES_CONST char *tp;
25850276Speter
25962449Speter	    namebuf[used++] = '\0';
26062449Speter	    in_name = FALSE;
26150276Speter
26262449Speter	    suffix[0] = '\0';
26362449Speter	    if ((up = strchr(namebuf, '#')) != 0
26462449Speter		|| (up = strchr(namebuf, '=')) != 0
26562449Speter		|| ((up = strchr(namebuf, '@')) != 0 && up[1] == '>')) {
26662449Speter		(void) strcpy(suffix, up);
26762449Speter		*up = '\0';
26862449Speter	    }
26950276Speter
27062449Speter	    if ((tp = nametrans(namebuf)) != 0) {
27162449Speter		(void) putchar(':');
27262449Speter		(void) fputs(tp, stdout);
27362449Speter		(void) fputs(suffix, stdout);
27462449Speter		(void) putchar(':');
27562449Speter	    } else {
27662449Speter		/* couldn't find a translation, just dump the name */
27762449Speter		(void) putchar('<');
27862449Speter		(void) fputs(namebuf, stdout);
27962449Speter		(void) fputs(suffix, stdout);
28062449Speter		(void) putchar('>');
28162449Speter	    }
28250276Speter	}
28362449Speter    } else {
28462449Speter	used = 0;
28562449Speter	if (c == '<') {
28662449Speter	    in_name = TRUE;
28762449Speter	} else {
28862449Speter	    putchar(c);
28950276Speter	}
29050276Speter    }
29150276Speter}
29250276Speter
29350276Speter/* Returns a string, stripped of leading/trailing whitespace */
29462449Speterstatic char *
29562449Speterstripped(char *src)
29650276Speter{
29797049Speter    while (isspace(UChar(*src)))
29862449Speter	src++;
29962449Speter    if (*src != '\0') {
30062449Speter	char *dst = strcpy(malloc(strlen(src) + 1), src);
30162449Speter	size_t len = strlen(dst);
30297049Speter	while (--len != 0 && isspace(UChar(dst[len])))
30362449Speter	    dst[len] = '\0';
30462449Speter	return dst;
30562449Speter    }
30662449Speter    return 0;
30750276Speter}
30850276Speter
30966963Speterstatic FILE *
31066963Speteropen_input(const char *filename)
31166963Speter{
31266963Speter    FILE *fp = fopen(filename, "r");
31366963Speter    struct stat sb;
31466963Speter
31566963Speter    if (fp == 0) {
31666963Speter	fprintf(stderr, "%s: Can't open %s\n", _nc_progname, filename);
31766963Speter	exit(EXIT_FAILURE);
31866963Speter    }
31966963Speter    if (fstat(fileno(fp), &sb) < 0
32066963Speter	|| (sb.st_mode & S_IFMT) != S_IFREG) {
32166963Speter	fprintf(stderr, "%s: %s is not a file\n", _nc_progname, filename);
32266963Speter	exit(EXIT_FAILURE);
32366963Speter    }
32466963Speter    return fp;
32566963Speter}
32666963Speter
32750276Speter/* Parse the "-e" option-value into a list of names */
32862449Speterstatic const char **
32962449Spetermake_namelist(char *src)
33050276Speter{
33162449Speter    const char **dst = 0;
33250276Speter
33362449Speter    char *s, *base;
33462449Speter    unsigned pass, n, nn;
33562449Speter    char buffer[BUFSIZ];
33650276Speter
33762449Speter    if (src == 0) {
33862449Speter	/* EMPTY */ ;
33962449Speter    } else if (strchr(src, '/') != 0) {		/* a filename */
34066963Speter	FILE *fp = open_input(src);
34150276Speter
34262449Speter	for (pass = 1; pass <= 2; pass++) {
34362449Speter	    nn = 0;
34462449Speter	    while (fgets(buffer, sizeof(buffer), fp) != 0) {
34562449Speter		if ((s = stripped(buffer)) != 0) {
34662449Speter		    if (dst != 0)
34762449Speter			dst[nn] = s;
34862449Speter		    nn++;
34950276Speter		}
35062449Speter	    }
35162449Speter	    if (pass == 1) {
35262449Speter		dst = typeCalloc(const char *, nn + 1);
35362449Speter		rewind(fp);
35462449Speter	    }
35562449Speter	}
35662449Speter	fclose(fp);
35762449Speter    } else {			/* literal list of names */
35862449Speter	for (pass = 1; pass <= 2; pass++) {
35962449Speter	    for (n = nn = 0, base = src;; n++) {
36062449Speter		int mark = src[n];
36162449Speter		if (mark == ',' || mark == '\0') {
36262449Speter		    if (pass == 1) {
36362449Speter			nn++;
36462449Speter		    } else {
36562449Speter			src[n] = '\0';
36662449Speter			if ((s = stripped(base)) != 0)
36762449Speter			    dst[nn++] = s;
36862449Speter			base = &src[n + 1];
36962449Speter		    }
37050276Speter		}
37162449Speter		if (mark == '\0')
37262449Speter		    break;
37362449Speter	    }
37462449Speter	    if (pass == 1)
37562449Speter		dst = typeCalloc(const char *, nn + 1);
37650276Speter	}
37762449Speter    }
37862449Speter    if (showsummary) {
37962449Speter	fprintf(log_fp, "Entries that will be compiled:\n");
38062449Speter	for (n = 0; dst[n] != 0; n++)
38162449Speter	    fprintf(log_fp, "%d:%s\n", n + 1, dst[n]);
38262449Speter    }
38362449Speter    return dst;
38450276Speter}
38550276Speter
38662449Speterstatic bool
38762449Spetermatches(const char **needle, const char *haystack)
38850276Speter/* does entry in needle list match |-separated field in haystack? */
38950276Speter{
39062449Speter    bool code = FALSE;
39162449Speter    size_t n;
39250276Speter
39362449Speter    if (needle != 0) {
39462449Speter	for (n = 0; needle[n] != 0; n++) {
39562449Speter	    if (_nc_name_match(haystack, needle[n], "|")) {
39662449Speter		code = TRUE;
39762449Speter		break;
39862449Speter	    }
39950276Speter	}
40062449Speter    } else
40162449Speter	code = TRUE;
40262449Speter    return (code);
40350276Speter}
40450276Speter
40562449Speterstatic FILE *
40662449Speteropen_tempfile(char *name)
40750276Speter{
40862449Speter    FILE *result = 0;
40962449Speter#if HAVE_MKSTEMP
41062449Speter    int fd = mkstemp(name);
41162449Speter    if (fd >= 0)
41262449Speter	result = fdopen(fd, "w");
41362449Speter#else
41462449Speter    if (tmpnam(name) != 0)
41562449Speter	result = fopen(name, "w");
41662449Speter#endif
41762449Speter    return result;
41862449Speter}
41950276Speter
42062449Speterint
42162449Spetermain(int argc, char *argv[])
42262449Speter{
42362449Speter    char my_tmpname[PATH_MAX];
42462449Speter    int v_opt = -1, debug_level;
42562449Speter    int smart_defaults = TRUE;
42662449Speter    char *termcap;
42762449Speter    ENTRY *qp;
42850276Speter
42962449Speter    int this_opt, last_opt = '?';
43050276Speter
43162449Speter    int outform = F_TERMINFO;	/* output format */
43262449Speter    int sortmode = S_TERMINFO;	/* sort_mode */
43350276Speter
43462449Speter    int width = 60;
43562449Speter    bool formatted = FALSE;	/* reformat complex strings? */
43662449Speter    int numbers = 0;		/* format "%'char'" to/from "%{number}" */
43762449Speter    bool infodump = FALSE;	/* running as captoinfo? */
43862449Speter    bool capdump = FALSE;	/* running as infotocap? */
43962449Speter    bool forceresolve = FALSE;	/* force resolution */
44062449Speter    bool limited = TRUE;
44162449Speter    char *tversion = (char *) NULL;
44262449Speter    const char *source_file = "terminfo";
44362449Speter    const char **namelst = 0;
44462449Speter    char *outdir = (char *) NULL;
44562449Speter    bool check_only = FALSE;
44650276Speter
44762449Speter    log_fp = stderr;
44850276Speter
44997049Speter    _nc_progname = _nc_rootname(argv[0]);
45062449Speter
45166963Speter    if ((infodump = (strcmp(_nc_progname, PROG_CAPTOINFO) == 0)) != FALSE) {
45262449Speter	outform = F_TERMINFO;
45362449Speter	sortmode = S_TERMINFO;
45462449Speter    }
45566963Speter    if ((capdump = (strcmp(_nc_progname, PROG_INFOTOCAP) == 0)) != FALSE) {
45662449Speter	outform = F_TERMCAP;
45762449Speter	sortmode = S_TERMCAP;
45862449Speter    }
45950276Speter#if NCURSES_XNAMES
46062449Speter    use_extended_names(FALSE);
46150276Speter#endif
46250276Speter
46362449Speter    /*
46462449Speter     * Processing arguments is a little complicated, since someone made a
46562449Speter     * design decision to allow the numeric values for -w, -v options to
46662449Speter     * be optional.
46762449Speter     */
46862449Speter    while ((this_opt = getopt(argc, argv,
46966963Speter			      "0123456789CILNR:TVace:fGgo:rsvwx")) != EOF) {
47062449Speter	if (isdigit(this_opt)) {
47162449Speter	    switch (last_opt) {
47262449Speter	    case 'v':
47362449Speter		v_opt = (v_opt * 10) + (this_opt - '0');
47462449Speter		break;
47562449Speter	    case 'w':
47662449Speter		width = (width * 10) + (this_opt - '0');
47762449Speter		break;
47862449Speter	    default:
47962449Speter		if (this_opt != '1')
48062449Speter		    usage();
48162449Speter		last_opt = this_opt;
48262449Speter		width = 0;
48362449Speter	    }
48462449Speter	    continue;
48562449Speter	}
48662449Speter	switch (this_opt) {
48762449Speter	case 'C':
48862449Speter	    capdump = TRUE;
48962449Speter	    outform = F_TERMCAP;
49062449Speter	    sortmode = S_TERMCAP;
49162449Speter	    break;
49262449Speter	case 'I':
49362449Speter	    infodump = TRUE;
49462449Speter	    outform = F_TERMINFO;
49562449Speter	    sortmode = S_TERMINFO;
49662449Speter	    break;
49762449Speter	case 'L':
49862449Speter	    infodump = TRUE;
49962449Speter	    outform = F_VARIABLE;
50062449Speter	    sortmode = S_VARIABLE;
50162449Speter	    break;
50262449Speter	case 'N':
50362449Speter	    smart_defaults = FALSE;
50462449Speter	    break;
50562449Speter	case 'R':
50662449Speter	    tversion = optarg;
50762449Speter	    break;
50862449Speter	case 'T':
50962449Speter	    limited = FALSE;
51062449Speter	    break;
51162449Speter	case 'V':
51266963Speter	    puts(curses_version());
51362449Speter	    return EXIT_SUCCESS;
51462449Speter	case 'c':
51562449Speter	    check_only = TRUE;
51662449Speter	    break;
51762449Speter	case 'e':
51862449Speter	    namelst = make_namelist(optarg);
51962449Speter	    break;
52062449Speter	case 'f':
52162449Speter	    formatted = TRUE;
52262449Speter	    break;
52362449Speter	case 'G':
52462449Speter	    numbers = 1;
52562449Speter	    break;
52662449Speter	case 'g':
52762449Speter	    numbers = -1;
52862449Speter	    break;
52962449Speter	case 'o':
53062449Speter	    outdir = optarg;
53162449Speter	    break;
53262449Speter	case 'r':
53362449Speter	    forceresolve = TRUE;
53462449Speter	    break;
53562449Speter	case 's':
53662449Speter	    showsummary = TRUE;
53762449Speter	    break;
53862449Speter	case 'v':
53962449Speter	    v_opt = 0;
54062449Speter	    break;
54162449Speter	case 'w':
54262449Speter	    width = 0;
54362449Speter	    break;
54450276Speter#if NCURSES_XNAMES
54562449Speter	case 'a':
54662449Speter	    _nc_disable_period = TRUE;
54762449Speter	    /* FALLTHRU */
54862449Speter	case 'x':
54962449Speter	    use_extended_names(TRUE);
55062449Speter	    break;
55150276Speter#endif
55262449Speter	default:
55362449Speter	    usage();
55450276Speter	}
55562449Speter	last_opt = this_opt;
55662449Speter    }
55750276Speter
55862449Speter    debug_level = (v_opt > 0) ? v_opt : (v_opt == 0);
55962449Speter    set_trace_level(debug_level);
56050276Speter
56162449Speter    if (_nc_tracing) {
56262449Speter	save_check_termtype = _nc_check_termtype;
56362449Speter	_nc_check_termtype = check_termtype;
56462449Speter    }
56566963Speter#if !HAVE_BIG_CORE
56662449Speter    /*
56762449Speter     * Aaargh! immedhook seriously hoses us!
56862449Speter     *
56962449Speter     * One problem with immedhook is it means we can't do -e.  Problem
57062449Speter     * is that we can't guarantee that for each terminal listed, all the
57162449Speter     * terminals it depends on will have been kept in core for reference
57262449Speter     * resolution -- in fact it's certain the primitive types at the end
57362449Speter     * of reference chains *won't* be in core unless they were explicitly
57462449Speter     * in the select list themselves.
57562449Speter     */
57662449Speter    if (namelst && (!infodump && !capdump)) {
57762449Speter	(void) fprintf(stderr,
57866963Speter		       "Sorry, -e can't be used without -I or -C\n");
57962449Speter	cleanup();
58062449Speter	return EXIT_FAILURE;
58162449Speter    }
58250276Speter#endif /* HAVE_BIG_CORE */
58350276Speter
58462449Speter    if (optind < argc) {
58562449Speter	source_file = argv[optind++];
58650276Speter	if (optind < argc) {
58762449Speter	    fprintf(stderr,
58866963Speter		    "%s: Too many file names.  Usage:\n\t%s %s",
58966963Speter		    _nc_progname,
59066963Speter		    _nc_progname,
59166963Speter		    usage_string);
59262449Speter	    return EXIT_FAILURE;
59362449Speter	}
59462449Speter    } else {
59562449Speter	if (infodump == TRUE) {
59662449Speter	    /* captoinfo's no-argument case */
59762449Speter	    source_file = "/etc/termcap";
59862449Speter	    if ((termcap = getenv("TERMCAP")) != 0
59962449Speter		&& (namelst = make_namelist(getenv("TERM"))) != 0) {
60062449Speter		if (access(termcap, F_OK) == 0) {
60162449Speter		    /* file exists */
60262449Speter		    source_file = termcap;
60366963Speter		} else if ((tmp_fp = open_tempfile(strcpy(my_tmpname,
60466963Speter							  "/tmp/XXXXXX")))
60566963Speter			   != 0) {
60662449Speter		    source_file = my_tmpname;
60762449Speter		    fprintf(tmp_fp, "%s\n", termcap);
60862449Speter		    fclose(tmp_fp);
60966963Speter		    tmp_fp = open_input(source_file);
61062449Speter		    to_remove = source_file;
61162449Speter		} else {
61262449Speter		    failed("tmpnam");
61350276Speter		}
61462449Speter	    }
61550276Speter	} else {
61662449Speter	    /* tic */
61762449Speter	    fprintf(stderr,
61866963Speter		    "%s: File name needed.  Usage:\n\t%s %s",
61966963Speter		    _nc_progname,
62066963Speter		    _nc_progname,
62166963Speter		    usage_string);
62262449Speter	    cleanup();
62362449Speter	    return EXIT_FAILURE;
62450276Speter	}
62562449Speter    }
62650276Speter
62766963Speter    if (tmp_fp == 0)
62866963Speter	tmp_fp = open_input(source_file);
62950276Speter
63062449Speter    if (infodump)
63162449Speter	dump_init(tversion,
63266963Speter		  smart_defaults
63366963Speter		  ? outform
63466963Speter		  : F_LITERAL,
63566963Speter		  sortmode, width, debug_level, formatted);
63662449Speter    else if (capdump)
63762449Speter	dump_init(tversion,
63866963Speter		  outform,
63966963Speter		  sortmode, width, debug_level, FALSE);
64050276Speter
64162449Speter    /* parse entries out of the source file */
64262449Speter    _nc_set_source(source_file);
64366963Speter#if !HAVE_BIG_CORE
64462449Speter    if (!(check_only || infodump || capdump))
64562449Speter	_nc_set_writedir(outdir);
64650276Speter#endif /* HAVE_BIG_CORE */
64762449Speter    _nc_read_entry_source(tmp_fp, (char *) NULL,
64866963Speter			  !smart_defaults, FALSE,
64966963Speter			  (check_only || infodump || capdump) ? NULLHOOK : immedhook);
65050276Speter
65162449Speter    /* do use resolution */
65262449Speter    if (check_only || (!infodump && !capdump) || forceresolve) {
65362449Speter	if (!_nc_resolve_uses(TRUE) && !check_only) {
65462449Speter	    cleanup();
65562449Speter	    return EXIT_FAILURE;
65650276Speter	}
65762449Speter    }
65850276Speter
65962449Speter    /* length check */
66062449Speter    if (check_only && (capdump || infodump)) {
66162449Speter	for_entry_list(qp) {
66262449Speter	    if (matches(namelst, qp->tterm.term_names)) {
66362449Speter		int len = fmt_entry(&qp->tterm, NULL, TRUE, infodump, numbers);
66450276Speter
66562449Speter		if (len > (infodump ? MAX_TERMINFO_LENGTH : MAX_TERMCAP_LENGTH))
66662449Speter		    (void) fprintf(stderr,
66766963Speter				   "warning: resolved %s entry is %d bytes long\n",
66866963Speter				   _nc_first_name(qp->tterm.term_names),
66966963Speter				   len);
67050276Speter	    }
67150276Speter	}
67262449Speter    }
67350276Speter
67462449Speter    /* write or dump all entries */
67562449Speter    if (!check_only) {
67662449Speter	if (!infodump && !capdump) {
67762449Speter	    _nc_set_writedir(outdir);
67862449Speter	    for_entry_list(qp) {
67962449Speter		if (matches(namelst, qp->tterm.term_names))
68062449Speter		    write_it(qp);
68150276Speter	    }
68262449Speter	} else {
68362449Speter	    /* this is in case infotocap() generates warnings */
68462449Speter	    _nc_curr_col = _nc_curr_line = -1;
68550276Speter
68662449Speter	    for_entry_list(qp) {
68762449Speter		if (matches(namelst, qp->tterm.term_names)) {
68862449Speter		    int j = qp->cend - qp->cstart;
68962449Speter		    int len = 0;
69050276Speter
69162449Speter		    /* this is in case infotocap() generates warnings */
69262449Speter		    _nc_set_type(_nc_first_name(qp->tterm.term_names));
69350276Speter
69462449Speter		    (void) fseek(tmp_fp, qp->cstart, SEEK_SET);
69562449Speter		    while (j--) {
69662449Speter			if (infodump)
69762449Speter			    (void) putchar(fgetc(tmp_fp));
69862449Speter			else
69962449Speter			    put_translate(fgetc(tmp_fp));
70050276Speter		    }
70150276Speter
70262449Speter		    len = dump_entry(&qp->tterm, limited, numbers, NULL);
70362449Speter		    for (j = 0; j < qp->nuses; j++)
70462449Speter			len += dump_uses(qp->uses[j].name, !capdump);
70562449Speter		    (void) putchar('\n');
70662449Speter		    if (debug_level != 0 && !limited)
70762449Speter			printf("# length=%d\n", len);
70862449Speter		}
70962449Speter	    }
71076726Speter	    if (!namelst && _nc_tail) {
71162449Speter		int c, oldc = '\0';
71262449Speter		bool in_comment = FALSE;
71362449Speter		bool trailing_comment = FALSE;
71462449Speter
71562449Speter		(void) fseek(tmp_fp, _nc_tail->cend, SEEK_SET);
71662449Speter		while ((c = fgetc(tmp_fp)) != EOF) {
71762449Speter		    if (oldc == '\n') {
71862449Speter			if (c == '#') {
71962449Speter			    trailing_comment = TRUE;
72062449Speter			    in_comment = TRUE;
72162449Speter			} else {
72262449Speter			    in_comment = FALSE;
72350276Speter			}
72450276Speter		    }
72562449Speter		    if (trailing_comment
72662449Speter			&& (in_comment || (oldc == '\n' && c == '\n')))
72762449Speter			putchar(c);
72862449Speter		    oldc = c;
72950276Speter		}
73050276Speter	    }
73150276Speter	}
73262449Speter    }
73350276Speter
73462449Speter    /* Show the directory into which entries were written, and the total
73562449Speter     * number of entries
73662449Speter     */
73762449Speter    if (showsummary
73862449Speter	&& (!(check_only || infodump || capdump))) {
73962449Speter	int total = _nc_tic_written();
74062449Speter	if (total != 0)
74162449Speter	    fprintf(log_fp, "%d entries written to %s\n",
74266963Speter		    total,
74366963Speter		    _nc_tic_dir((char *) 0));
74462449Speter	else
74562449Speter	    fprintf(log_fp, "No entries written\n");
74662449Speter    }
74762449Speter    cleanup();
74862449Speter    return (EXIT_SUCCESS);
74950276Speter}
75050276Speter
75150276Speter/*
75250276Speter * This bit of legerdemain turns all the terminfo variable names into
75350276Speter * references to locations in the arrays Booleans, Numbers, and Strings ---
75450276Speter * precisely what's needed (see comp_parse.c).
75550276Speter */
75650276Speter
75762449SpeterTERMINAL *cur_term;		/* tweak to avoid linking lib_cur_term.c */
75850276Speter
75950276Speter#undef CUR
76050276Speter#define CUR tp->
76150276Speter
76262449Speter/*
76366963Speter * Returns the expected number of parameters for the given capability.
76466963Speter */
76566963Speterstatic int
76676726Speterexpected_params(const char *name)
76766963Speter{
76866963Speter    /* *INDENT-OFF* */
76966963Speter    static const struct {
77066963Speter	const char *name;
77166963Speter	int count;
77266963Speter    } table[] = {
77376726Speter	{ "S0",			1 },	/* 'screen' extension */
77466963Speter	{ "birep",		2 },
77566963Speter	{ "chr",		1 },
77666963Speter	{ "colornm",		1 },
77766963Speter	{ "cpi",		1 },
77876726Speter	{ "csnm",		1 },
77966963Speter	{ "csr",		2 },
78066963Speter	{ "cub",		1 },
78166963Speter	{ "cud",		1 },
78266963Speter	{ "cuf",		1 },
78366963Speter	{ "cup",		2 },
78476726Speter	{ "cuu",		1 },
78566963Speter	{ "cvr",		1 },
78666963Speter	{ "cwin",		5 },
78766963Speter	{ "dch",		1 },
78876726Speter	{ "defc",		3 },
78966963Speter	{ "dial",		1 },
79066963Speter	{ "dispc",		1 },
79166963Speter	{ "dl",			1 },
79266963Speter	{ "ech",		1 },
79366963Speter	{ "getm",		1 },
79466963Speter	{ "hpa",		1 },
79566963Speter	{ "ich",		1 },
79666963Speter	{ "il",			1 },
79766963Speter	{ "indn",		1 },
79866963Speter	{ "initc",		4 },
79966963Speter	{ "initp",		7 },
80066963Speter	{ "lpi",		1 },
80166963Speter	{ "mc5p",		1 },
80266963Speter	{ "mrcup",		2 },
80366963Speter	{ "mvpa",		1 },
80466963Speter	{ "pfkey",		2 },
80566963Speter	{ "pfloc",		2 },
80666963Speter	{ "pfx",		2 },
80766963Speter	{ "pfxl",		3 },
80866963Speter	{ "pln",		2 },
80966963Speter	{ "qdial",		1 },
81076726Speter	{ "rcsd",		1 },
81166963Speter	{ "rep",		2 },
81266963Speter	{ "rin",		1 },
81366963Speter	{ "sclk",		3 },
81466963Speter	{ "scp",		1 },
81566963Speter	{ "scs",		1 },
81676726Speter	{ "scsd",		2 },
81766963Speter	{ "setab",		1 },
81866963Speter	{ "setaf",		1 },
81966963Speter	{ "setb",		1 },
82066963Speter	{ "setcolor",		1 },
82166963Speter	{ "setf",		1 },
82266963Speter	{ "sgr",		9 },
82366963Speter	{ "sgr1",		6 },
82466963Speter	{ "slength",		1 },
82566963Speter	{ "slines",		1 },
82698503Speter	{ "smgbp",		1 },	/* 2 if smgtp is not given */
82798503Speter	{ "smglp",		1 },
82866963Speter	{ "smglr",		2 },
82966963Speter	{ "smgrp",		1 },
83066963Speter	{ "smgtb",		2 },
83176726Speter	{ "smgtp",		1 },
83266963Speter	{ "tsl",		1 },
83366963Speter	{ "u6",			-1 },
83466963Speter	{ "vpa",		1 },
83566963Speter	{ "wind",		4 },
83666963Speter	{ "wingo",		1 },
83766963Speter    };
83866963Speter    /* *INDENT-ON* */
83966963Speter
84066963Speter    unsigned n;
84166963Speter    int result = 0;		/* function-keys, etc., use none */
84266963Speter
84366963Speter    for (n = 0; n < SIZEOF(table); n++) {
84466963Speter	if (!strcmp(name, table[n].name)) {
84566963Speter	    result = table[n].count;
84666963Speter	    break;
84766963Speter	}
84866963Speter    }
84966963Speter
85066963Speter    return result;
85166963Speter}
85266963Speter
85366963Speter/*
85466963Speter * Make a quick sanity check for the parameters which are used in the given
85566963Speter * strings.  If there are no "%p" tokens, then there should be no other "%"
85666963Speter * markers.
85766963Speter */
85866963Speterstatic void
85976726Spetercheck_params(TERMTYPE * tp, const char *name, char *value)
86066963Speter{
86166963Speter    int expected = expected_params(name);
86266963Speter    int actual = 0;
86366963Speter    int n;
86466963Speter    bool params[10];
86566963Speter    char *s = value;
86666963Speter
86798503Speter    if (!strcmp(name, "smgbp")
86898503Speter	&& set_top_margin_parm == 0)
86998503Speter	expected = 2;
87098503Speter
87166963Speter    for (n = 0; n < 10; n++)
87266963Speter	params[n] = FALSE;
87366963Speter
87466963Speter    while (*s != 0) {
87566963Speter	if (*s == '%') {
87666963Speter	    if (*++s == '\0') {
87766963Speter		_nc_warning("expected character after %% in %s", name);
87866963Speter		break;
87966963Speter	    } else if (*s == 'p') {
88066963Speter		if (*++s == '\0' || !isdigit((int) *s)) {
88166963Speter		    _nc_warning("expected digit after %%p in %s", name);
88266963Speter		    return;
88366963Speter		} else {
88466963Speter		    n = (*s - '0');
88566963Speter		    if (n > actual)
88666963Speter			actual = n;
88766963Speter		    params[n] = TRUE;
88866963Speter		}
88966963Speter	    }
89066963Speter	}
89166963Speter	s++;
89266963Speter    }
89366963Speter
89466963Speter    if (params[0]) {
89566963Speter	_nc_warning("%s refers to parameter 0 (%%p0), which is not allowed", name);
89666963Speter    }
89766963Speter    if (value == set_attributes || expected < 0) {
89866963Speter	;
89966963Speter    } else if (expected != actual) {
90066963Speter	_nc_warning("%s uses %d parameters, expected %d", name,
90166963Speter		    actual, expected);
90266963Speter	for (n = 1; n < actual; n++) {
90366963Speter	    if (!params[n])
90466963Speter		_nc_warning("%s omits parameter %d", name, n);
90566963Speter	}
90666963Speter    }
90766963Speter}
90866963Speter
90998503Speterstatic char *
91098503Speterskip_delay(char *s)
91198503Speter{
91298503Speter    while (*s == '/' || isdigit(UChar(*s)))
91398503Speter	++s;
91498503Speter    return s;
91598503Speter}
91698503Speter
91766963Speter/*
91862449Speter * An sgr string may contain several settings other than the one we're
91962449Speter * interested in, essentially sgr0 + rmacs + whatever.  As long as the
92062449Speter * "whatever" is contained in the sgr string, that is close enough for our
92162449Speter * sanity check.
92262449Speter */
92362449Speterstatic bool
92498503Spetersimilar_sgr(int num, char *a, char *b)
92562449Speter{
92698503Speter    static const char *names[] =
92798503Speter    {
92898503Speter	"none"
92998503Speter	,"standout"
93098503Speter	,"underline"
93198503Speter	,"reverse"
93298503Speter	,"blink"
93398503Speter	,"dim"
93498503Speter	,"bold"
93598503Speter	,"invis"
93698503Speter	,"protect"
93798503Speter	,"altcharset"
93898503Speter    };
93998503Speter    char *base_a = a;
94098503Speter    char *base_b = b;
94198503Speter    int delaying = 0;
94298503Speter
94362449Speter    while (*b != 0) {
94462449Speter	while (*a != *b) {
94576726Speter	    if (*a == 0) {
94676726Speter		if (b[0] == '$'
94776726Speter		    && b[1] == '<') {
94876726Speter		    _nc_warning("Did not find delay %s", _nc_visbuf(b));
94976726Speter		} else {
95098503Speter		    _nc_warning("checking sgr(%s) %s\n\tcompare to %s\n\tunmatched %s",
95198503Speter				names[num], _nc_visbuf2(1, base_a),
95298503Speter				_nc_visbuf2(2, base_b),
95398503Speter				_nc_visbuf2(3, b));
95476726Speter		}
95562449Speter		return FALSE;
95698503Speter	    } else if (delaying) {
95798503Speter		a = skip_delay(a);
95898503Speter		b = skip_delay(b);
95998503Speter	    } else {
96098503Speter		a++;
96176726Speter	    }
96262449Speter	}
96398503Speter	switch (*a) {
96498503Speter	case '$':
96598503Speter	    if (delaying == 0)
96698503Speter		delaying = 1;
96798503Speter	    break;
96898503Speter	case '<':
96998503Speter	    if (delaying == 1)
97098503Speter		delaying = 2;
97198503Speter	    break;
97298503Speter	default:
97398503Speter	    delaying = 0;
97498503Speter	    break;
97598503Speter	}
97662449Speter	a++;
97762449Speter	b++;
97862449Speter    }
97962449Speter    return TRUE;
98062449Speter}
98162449Speter
98262449Speterstatic void
98362449Spetercheck_sgr(TERMTYPE * tp, char *zero, int num, char *cap, const char *name)
98462449Speter{
98562449Speter    char *test = tparm(set_attributes,
98666963Speter		       num == 1,
98766963Speter		       num == 2,
98866963Speter		       num == 3,
98966963Speter		       num == 4,
99066963Speter		       num == 5,
99166963Speter		       num == 6,
99266963Speter		       num == 7,
99366963Speter		       num == 8,
99466963Speter		       num == 9);
99576726Speter    tparm_errs += _nc_tparm_err;
99662449Speter    if (test != 0) {
99762449Speter	if (PRESENT(cap)) {
99898503Speter	    if (!similar_sgr(num, test, cap)) {
99998503Speter		_nc_warning("%s differs from sgr(%d)\n\t%s=%s\n\tsgr(%d)=%s",
100098503Speter			    name, num,
100198503Speter			    name, _nc_visbuf2(1, cap),
100298503Speter			    num, _nc_visbuf2(2, test));
100362449Speter	    }
100462449Speter	} else if (strcmp(test, zero)) {
100562449Speter	    _nc_warning("sgr(%d) present, but not %s", num, name);
100662449Speter	}
100762449Speter    } else if (PRESENT(cap)) {
100862449Speter	_nc_warning("sgr(%d) missing, but %s present", num, name);
100962449Speter    }
101062449Speter}
101162449Speter
101262449Speter#define CHECK_SGR(num,name) check_sgr(tp, zero, num, name, #name)
101362449Speter
101450276Speter/* other sanity-checks (things that we don't want in the normal
101550276Speter * logic that reads a terminfo entry)
101650276Speter */
101762449Speterstatic void
101862449Spetercheck_termtype(TERMTYPE * tp)
101950276Speter{
102062449Speter    bool conflict = FALSE;
102162449Speter    unsigned j, k;
102262449Speter    char fkeys[STRCOUNT];
102350276Speter
102462449Speter    /*
102562449Speter     * A terminal entry may contain more than one keycode assigned to
102662449Speter     * a given string (e.g., KEY_END and KEY_LL).  But curses will only
102762449Speter     * return one (the last one assigned).
102862449Speter     */
102962449Speter    memset(fkeys, 0, sizeof(fkeys));
103062449Speter    for (j = 0; _nc_tinfo_fkeys[j].code; j++) {
103162449Speter	char *a = tp->Strings[_nc_tinfo_fkeys[j].offset];
103262449Speter	bool first = TRUE;
103362449Speter	if (!VALID_STRING(a))
103462449Speter	    continue;
103562449Speter	for (k = j + 1; _nc_tinfo_fkeys[k].code; k++) {
103662449Speter	    char *b = tp->Strings[_nc_tinfo_fkeys[k].offset];
103762449Speter	    if (!VALID_STRING(b)
103862449Speter		|| fkeys[k])
103950276Speter		continue;
104062449Speter	    if (!strcmp(a, b)) {
104162449Speter		fkeys[j] = 1;
104262449Speter		fkeys[k] = 1;
104362449Speter		if (first) {
104462449Speter		    if (!conflict) {
104562449Speter			_nc_warning("Conflicting key definitions (using the last)");
104662449Speter			conflict = TRUE;
104750276Speter		    }
104862449Speter		    fprintf(stderr, "... %s is the same as %s",
104966963Speter			    keyname(_nc_tinfo_fkeys[j].code),
105066963Speter			    keyname(_nc_tinfo_fkeys[k].code));
105162449Speter		    first = FALSE;
105262449Speter		} else {
105362449Speter		    fprintf(stderr, ", %s",
105466963Speter			    keyname(_nc_tinfo_fkeys[k].code));
105550276Speter		}
105650276Speter	    }
105750276Speter	}
105862449Speter	if (!first)
105962449Speter	    fprintf(stderr, "\n");
106062449Speter    }
106150276Speter
106266963Speter    for (j = 0; j < NUM_STRINGS(tp); j++) {
106366963Speter	char *a = tp->Strings[j];
106466963Speter	if (VALID_STRING(a))
106566963Speter	    check_params(tp, ExtStrname(tp, j, strnames), a);
106666963Speter    }
106766963Speter
106862449Speter    /*
106962449Speter     * Quick check for color.  We could also check if the ANSI versus
107062449Speter     * non-ANSI strings are misused.
107162449Speter     */
107262449Speter    if ((max_colors > 0) != (max_pairs > 0)
107398503Speter	|| ((max_colors > max_pairs) && (initialize_pair == 0)))
107498503Speter	_nc_warning("inconsistent values for max_colors (%d) and max_pairs (%d)",
107598503Speter		    max_colors, max_pairs);
107650276Speter
107762449Speter    PAIRED(set_foreground, set_background);
107862449Speter    PAIRED(set_a_foreground, set_a_background);
107950276Speter
108062449Speter    /*
108162449Speter     * These may be mismatched because the terminal description relies on
108262449Speter     * restoring the cursor visibility by resetting it.
108362449Speter     */
108462449Speter    ANDMISSING(cursor_invisible, cursor_normal);
108562449Speter    ANDMISSING(cursor_visible, cursor_normal);
108650276Speter
108762449Speter    if (PRESENT(cursor_visible) && PRESENT(cursor_normal)
108862449Speter	&& !strcmp(cursor_visible, cursor_normal))
108962449Speter	_nc_warning("cursor_visible is same as cursor_normal");
109050276Speter
109162449Speter    /*
109262449Speter     * From XSI & O'Reilly, we gather that sc/rc are required if csr is
109362449Speter     * given, because the cursor position after the scrolling operation is
109462449Speter     * performed is undefined.
109562449Speter     */
109662449Speter    ANDMISSING(change_scroll_region, save_cursor);
109762449Speter    ANDMISSING(change_scroll_region, restore_cursor);
109850276Speter
109976726Speter    tparm_errs = 0;
110062449Speter    if (PRESENT(set_attributes)) {
110162449Speter	char *zero = tparm(set_attributes, 0, 0, 0, 0, 0, 0, 0, 0, 0);
110262449Speter
110362449Speter	zero = strdup(zero);
110462449Speter	CHECK_SGR(1, enter_standout_mode);
110562449Speter	CHECK_SGR(2, enter_underline_mode);
110662449Speter	CHECK_SGR(3, enter_reverse_mode);
110762449Speter	CHECK_SGR(4, enter_blink_mode);
110862449Speter	CHECK_SGR(5, enter_dim_mode);
110962449Speter	CHECK_SGR(6, enter_bold_mode);
111062449Speter	CHECK_SGR(7, enter_secure_mode);
111162449Speter	CHECK_SGR(8, enter_protected_mode);
111262449Speter	CHECK_SGR(9, enter_alt_charset_mode);
111362449Speter	free(zero);
111476726Speter	if (tparm_errs)
111576726Speter	    _nc_warning("stack error in sgr string");
111662449Speter    }
111762449Speter
111862449Speter    /*
111962449Speter     * Some standard applications (e.g., vi) and some non-curses
112062449Speter     * applications (e.g., jove) get confused if we have both ich/ich1 and
112162449Speter     * smir/rmir.  Let's be nice and warn about that, too, even though
112262449Speter     * ncurses handles it.
112362449Speter     */
112462449Speter    if ((PRESENT(enter_insert_mode) || PRESENT(exit_insert_mode))
112562449Speter	&& (PRESENT(insert_character) || PRESENT(parm_ich))) {
112662449Speter	_nc_warning("non-curses applications may be confused by ich/ich1 with smir/rmir");
112762449Speter    }
112862449Speter
112962449Speter    /*
113062449Speter     * Finally, do the non-verbose checks
113162449Speter     */
113262449Speter    if (save_check_termtype != 0)
113362449Speter	save_check_termtype(tp);
113450276Speter}
1135