xref: /freebsd/contrib/ncurses/progs/tic.c (revision 15589c42fa2774d2f8ee650f4f31eb8d3a861316)
10e3d5408SPeter Wemm /****************************************************************************
215589c42SPeter Wemm  * Copyright (c) 1998,1999,2000 Free Software Foundation, Inc.              *
30e3d5408SPeter Wemm  *                                                                          *
40e3d5408SPeter Wemm  * Permission is hereby granted, free of charge, to any person obtaining a  *
50e3d5408SPeter Wemm  * copy of this software and associated documentation files (the            *
60e3d5408SPeter Wemm  * "Software"), to deal in the Software without restriction, including      *
70e3d5408SPeter Wemm  * without limitation the rights to use, copy, modify, merge, publish,      *
80e3d5408SPeter Wemm  * distribute, distribute with modifications, sublicense, and/or sell       *
90e3d5408SPeter Wemm  * copies of the Software, and to permit persons to whom the Software is    *
100e3d5408SPeter Wemm  * furnished to do so, subject to the following conditions:                 *
110e3d5408SPeter Wemm  *                                                                          *
120e3d5408SPeter Wemm  * The above copyright notice and this permission notice shall be included  *
130e3d5408SPeter Wemm  * in all copies or substantial portions of the Software.                   *
140e3d5408SPeter Wemm  *                                                                          *
150e3d5408SPeter Wemm  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
160e3d5408SPeter Wemm  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
170e3d5408SPeter Wemm  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
180e3d5408SPeter Wemm  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
190e3d5408SPeter Wemm  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
200e3d5408SPeter Wemm  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
210e3d5408SPeter Wemm  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
220e3d5408SPeter Wemm  *                                                                          *
230e3d5408SPeter Wemm  * Except as contained in this notice, the name(s) of the above copyright   *
240e3d5408SPeter Wemm  * holders shall not be used in advertising or otherwise to promote the     *
250e3d5408SPeter Wemm  * sale, use or other dealings in this Software without prior written       *
260e3d5408SPeter Wemm  * authorization.                                                           *
270e3d5408SPeter Wemm  ****************************************************************************/
280e3d5408SPeter Wemm 
290e3d5408SPeter Wemm /****************************************************************************
300e3d5408SPeter Wemm  *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
310e3d5408SPeter Wemm  *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
320e3d5408SPeter Wemm  ****************************************************************************/
330e3d5408SPeter Wemm 
340e3d5408SPeter Wemm /*
350e3d5408SPeter Wemm  *	tic.c --- Main program for terminfo compiler
360e3d5408SPeter Wemm  *			by Eric S. Raymond
370e3d5408SPeter Wemm  *
380e3d5408SPeter Wemm  */
390e3d5408SPeter Wemm 
400e3d5408SPeter Wemm #include <progs.priv.h>
410e3d5408SPeter Wemm 
420e3d5408SPeter Wemm #include <dump_entry.h>
430e3d5408SPeter Wemm #include <term_entry.h>
440e3d5408SPeter Wemm 
4515589c42SPeter Wemm MODULE_ID("$Id: tic.c,v 1.69 2000/04/08 23:53:49 tom Exp $")
460e3d5408SPeter Wemm 
470e3d5408SPeter Wemm const char *_nc_progname = "tic";
480e3d5408SPeter Wemm 
490e3d5408SPeter Wemm static FILE *log_fp;
500e3d5408SPeter Wemm static FILE *tmp_fp;
510e3d5408SPeter Wemm static bool showsummary = FALSE;
520e3d5408SPeter Wemm static const char *to_remove;
530e3d5408SPeter Wemm 
540e3d5408SPeter Wemm static void (*save_check_termtype) (TERMTYPE *);
550e3d5408SPeter Wemm static void check_termtype(TERMTYPE * tt);
560e3d5408SPeter Wemm 
570e3d5408SPeter Wemm static const char usage_string[] = "[-h] [-v[n]] [-e names] [-CILNRTcfrswx1] source-file\n";
580e3d5408SPeter Wemm 
5915589c42SPeter Wemm static void
6015589c42SPeter Wemm cleanup(void)
610e3d5408SPeter Wemm {
620e3d5408SPeter Wemm     if (tmp_fp != 0)
630e3d5408SPeter Wemm 	fclose(tmp_fp);
640e3d5408SPeter Wemm     if (to_remove != 0) {
650e3d5408SPeter Wemm #if HAVE_REMOVE
660e3d5408SPeter Wemm 	remove(to_remove);
670e3d5408SPeter Wemm #else
680e3d5408SPeter Wemm 	unlink(to_remove);
690e3d5408SPeter Wemm #endif
700e3d5408SPeter Wemm     }
710e3d5408SPeter Wemm }
720e3d5408SPeter Wemm 
7315589c42SPeter Wemm static void
7415589c42SPeter Wemm failed(const char *msg)
750e3d5408SPeter Wemm {
760e3d5408SPeter Wemm     perror(msg);
770e3d5408SPeter Wemm     cleanup();
780e3d5408SPeter Wemm     exit(EXIT_FAILURE);
790e3d5408SPeter Wemm }
800e3d5408SPeter Wemm 
8115589c42SPeter Wemm static void
8215589c42SPeter Wemm usage(void)
830e3d5408SPeter Wemm {
8415589c42SPeter Wemm     static const char *const tbl[] =
8515589c42SPeter Wemm     {
860e3d5408SPeter Wemm 	"Options:",
870e3d5408SPeter Wemm 	"  -1         format translation output one capability per line",
880e3d5408SPeter Wemm 	"  -C         translate entries to termcap source form",
890e3d5408SPeter Wemm 	"  -I         translate entries to terminfo source form",
900e3d5408SPeter Wemm 	"  -L         translate entries to full terminfo source form",
910e3d5408SPeter Wemm 	"  -N         disable smart defaults for source translation",
920e3d5408SPeter Wemm 	"  -R         restrict translation to given terminfo/termcap version",
930e3d5408SPeter Wemm 	"  -T         remove size-restrictions on compiled description",
9415589c42SPeter Wemm #if NCURSES_XNAMES
9515589c42SPeter Wemm 	"  -a         retain commented-out capabilities (sets -x also)",
9615589c42SPeter Wemm #endif
970e3d5408SPeter Wemm 	"  -c         check only, validate input without compiling or translating",
980e3d5408SPeter Wemm 	"  -f         format complex strings for readability",
990e3d5408SPeter Wemm 	"  -G         format %{number} to %'char'",
1000e3d5408SPeter Wemm 	"  -g         format %'char' to %{number}",
1010e3d5408SPeter Wemm 	"  -e<names>  translate/compile only entries named by comma-separated list",
1020e3d5408SPeter Wemm 	"  -o<dir>    set output directory for compiled entry writes",
1030e3d5408SPeter Wemm 	"  -r         force resolution of all use entries in source translation",
1040e3d5408SPeter Wemm 	"  -s         print summary statistics",
1050e3d5408SPeter Wemm 	"  -v[n]      set verbosity level",
1060e3d5408SPeter Wemm 	"  -w[n]      set format width for translation output",
1070e3d5408SPeter Wemm #if NCURSES_XNAMES
1080e3d5408SPeter Wemm 	"  -x         treat unknown capabilities as user-defined",
1090e3d5408SPeter Wemm #endif
1100e3d5408SPeter Wemm 	"",
1110e3d5408SPeter Wemm 	"Parameters:",
1120e3d5408SPeter Wemm 	"  <file>     file to translate or compile"
1130e3d5408SPeter Wemm     };
1140e3d5408SPeter Wemm     size_t j;
1150e3d5408SPeter Wemm 
11615589c42SPeter Wemm     fprintf(stderr, "Usage: %s %s\n", _nc_progname, usage_string);
11715589c42SPeter Wemm     for (j = 0; j < sizeof(tbl) / sizeof(tbl[0]); j++) {
11815589c42SPeter Wemm 	fputs(tbl[j], stderr);
11915589c42SPeter Wemm 	putc('\n', stderr);
12015589c42SPeter Wemm     }
1210e3d5408SPeter Wemm     exit(EXIT_FAILURE);
1220e3d5408SPeter Wemm }
1230e3d5408SPeter Wemm 
1240e3d5408SPeter Wemm #define L_BRACE '{'
1250e3d5408SPeter Wemm #define R_BRACE '}'
1260e3d5408SPeter Wemm #define S_QUOTE '\'';
1270e3d5408SPeter Wemm 
12815589c42SPeter Wemm static void
12915589c42SPeter Wemm write_it(ENTRY * ep)
1300e3d5408SPeter Wemm {
1310e3d5408SPeter Wemm     unsigned n;
1320e3d5408SPeter Wemm     int ch;
1330e3d5408SPeter Wemm     char *s, *d, *t;
1340e3d5408SPeter Wemm     char result[MAX_ENTRY_SIZE];
1350e3d5408SPeter Wemm 
1360e3d5408SPeter Wemm     /*
1370e3d5408SPeter Wemm      * Look for strings that contain %{number}, convert them to %'char',
1380e3d5408SPeter Wemm      * which is shorter and runs a little faster.
1390e3d5408SPeter Wemm      */
1400e3d5408SPeter Wemm     for (n = 0; n < STRCOUNT; n++) {
1410e3d5408SPeter Wemm 	s = ep->tterm.Strings[n];
1420e3d5408SPeter Wemm 	if (VALID_STRING(s)
1430e3d5408SPeter Wemm 	    && strchr(s, L_BRACE) != 0) {
1440e3d5408SPeter Wemm 	    d = result;
1450e3d5408SPeter Wemm 	    t = s;
1460e3d5408SPeter Wemm 	    while ((ch = *t++) != 0) {
1470e3d5408SPeter Wemm 		*d++ = ch;
1480e3d5408SPeter Wemm 		if (ch == '\\') {
1490e3d5408SPeter Wemm 		    *d++ = *t++;
1500e3d5408SPeter Wemm 		} else if ((ch == '%')
1510e3d5408SPeter Wemm 		    && (*t == L_BRACE)) {
1520e3d5408SPeter Wemm 		    char *v = 0;
1530e3d5408SPeter Wemm 		    long value = strtol(t + 1, &v, 0);
1540e3d5408SPeter Wemm 		    if (v != 0
1550e3d5408SPeter Wemm 			&& *v == R_BRACE
1560e3d5408SPeter Wemm 			&& value > 0
1570e3d5408SPeter Wemm 			&& value != '\\'	/* FIXME */
1580e3d5408SPeter Wemm 			&& value < 127
1590e3d5408SPeter Wemm 			&& isprint((int) value)) {
1600e3d5408SPeter Wemm 			*d++ = S_QUOTE;
1610e3d5408SPeter Wemm 			*d++ = (int) value;
1620e3d5408SPeter Wemm 			*d++ = S_QUOTE;
1630e3d5408SPeter Wemm 			t = (v + 1);
1640e3d5408SPeter Wemm 		    }
1650e3d5408SPeter Wemm 		}
1660e3d5408SPeter Wemm 	    }
1670e3d5408SPeter Wemm 	    *d = 0;
1680e3d5408SPeter Wemm 	    if (strlen(result) < strlen(s))
1690e3d5408SPeter Wemm 		strcpy(s, result);
1700e3d5408SPeter Wemm 	}
1710e3d5408SPeter Wemm     }
1720e3d5408SPeter Wemm 
1730e3d5408SPeter Wemm     _nc_set_type(_nc_first_name(ep->tterm.term_names));
1740e3d5408SPeter Wemm     _nc_curr_line = ep->startline;
1750e3d5408SPeter Wemm     _nc_write_entry(&ep->tterm);
1760e3d5408SPeter Wemm }
1770e3d5408SPeter Wemm 
17815589c42SPeter Wemm static bool
17915589c42SPeter Wemm immedhook(ENTRY * ep GCC_UNUSED)
1800e3d5408SPeter Wemm /* write out entries with no use capabilities immediately to save storage */
1810e3d5408SPeter Wemm {
1820e3d5408SPeter Wemm #ifndef HAVE_BIG_CORE
1830e3d5408SPeter Wemm     /*
1840e3d5408SPeter Wemm      * This is strictly a core-economy kluge.  The really clean way to handle
1850e3d5408SPeter Wemm      * compilation is to slurp the whole file into core and then do all the
1860e3d5408SPeter Wemm      * name-collision checks and entry writes in one swell foop.  But the
1870e3d5408SPeter Wemm      * terminfo master file is large enough that some core-poor systems swap
1880e3d5408SPeter Wemm      * like crazy when you compile it this way...there have been reports of
1890e3d5408SPeter Wemm      * this process taking *three hours*, rather than the twenty seconds or
1900e3d5408SPeter Wemm      * less typical on my development box.
1910e3d5408SPeter Wemm      *
1920e3d5408SPeter Wemm      * So.  This hook *immediately* writes out the referenced entry if it
1930e3d5408SPeter Wemm      * has no use capabilities.  The compiler main loop refrains from
1940e3d5408SPeter Wemm      * adding the entry to the in-core list when this hook fires.  If some
1950e3d5408SPeter Wemm      * other entry later needs to reference an entry that got written
1960e3d5408SPeter Wemm      * immediately, that's OK; the resolution code will fetch it off disk
1970e3d5408SPeter Wemm      * when it can't find it in core.
1980e3d5408SPeter Wemm      *
1990e3d5408SPeter Wemm      * Name collisions will still be detected, just not as cleanly.  The
2000e3d5408SPeter Wemm      * write_entry() code complains before overwriting an entry that
2010e3d5408SPeter Wemm      * postdates the time of tic's first call to write_entry().  Thus
2020e3d5408SPeter Wemm      * it will complain about overwriting entries newly made during the
2030e3d5408SPeter Wemm      * tic run, but not about overwriting ones that predate it.
2040e3d5408SPeter Wemm      *
2050e3d5408SPeter Wemm      * The reason this is a hook, and not in line with the rest of the
2060e3d5408SPeter Wemm      * compiler code, is that the support for termcap fallback cannot assume
2070e3d5408SPeter Wemm      * it has anywhere to spool out these entries!
2080e3d5408SPeter Wemm      *
2090e3d5408SPeter Wemm      * The _nc_set_type() call here requires a compensating one in
2100e3d5408SPeter Wemm      * _nc_parse_entry().
2110e3d5408SPeter Wemm      *
2120e3d5408SPeter Wemm      * If you define HAVE_BIG_CORE, you'll disable this kluge.  This will
2130e3d5408SPeter Wemm      * make tic a bit faster (because the resolution code won't have to do
2140e3d5408SPeter Wemm      * disk I/O nearly as often).
2150e3d5408SPeter Wemm      */
21615589c42SPeter Wemm     if (ep->nuses == 0) {
2170e3d5408SPeter Wemm 	int oldline = _nc_curr_line;
2180e3d5408SPeter Wemm 
2190e3d5408SPeter Wemm 	write_it(ep);
2200e3d5408SPeter Wemm 	_nc_curr_line = oldline;
2210e3d5408SPeter Wemm 	free(ep->tterm.str_table);
2220e3d5408SPeter Wemm 	return (TRUE);
2230e3d5408SPeter Wemm     }
2240e3d5408SPeter Wemm #endif /* HAVE_BIG_CORE */
2250e3d5408SPeter Wemm     return (FALSE);
2260e3d5408SPeter Wemm }
2270e3d5408SPeter Wemm 
22815589c42SPeter Wemm static void
22915589c42SPeter Wemm put_translate(int c)
2300e3d5408SPeter Wemm /* emit a comment char, translating terminfo names to termcap names */
2310e3d5408SPeter Wemm {
2320e3d5408SPeter Wemm     static bool in_name = FALSE;
23315589c42SPeter Wemm     static size_t have, used;
23415589c42SPeter Wemm     static char *namebuf, *suffix;
2350e3d5408SPeter Wemm 
23615589c42SPeter Wemm     if (in_name) {
23715589c42SPeter Wemm 	if (used + 1 >= have) {
23815589c42SPeter Wemm 	    have += 132;
23915589c42SPeter Wemm 	    namebuf = typeRealloc(char, have, namebuf);
24015589c42SPeter Wemm 	    suffix = typeRealloc(char, have, suffix);
2410e3d5408SPeter Wemm 	}
24215589c42SPeter Wemm 	if (c == '\n' || c == '@') {
24315589c42SPeter Wemm 	    namebuf[used++] = '\0';
2440e3d5408SPeter Wemm 	    (void) putchar('<');
2450e3d5408SPeter Wemm 	    (void) fputs(namebuf, stdout);
2460e3d5408SPeter Wemm 	    putchar(c);
2470e3d5408SPeter Wemm 	    in_name = FALSE;
24815589c42SPeter Wemm 	} else if (c != '>') {
24915589c42SPeter Wemm 	    namebuf[used++] = c;
25015589c42SPeter Wemm 	} else {		/* ah! candidate name! */
2510e3d5408SPeter Wemm 	    char *up;
2520e3d5408SPeter Wemm 	    NCURSES_CONST char *tp;
2530e3d5408SPeter Wemm 
25415589c42SPeter Wemm 	    namebuf[used++] = '\0';
2550e3d5408SPeter Wemm 	    in_name = FALSE;
2560e3d5408SPeter Wemm 
2570e3d5408SPeter Wemm 	    suffix[0] = '\0';
2580e3d5408SPeter Wemm 	    if ((up = strchr(namebuf, '#')) != 0
2590e3d5408SPeter Wemm 		|| (up = strchr(namebuf, '=')) != 0
26015589c42SPeter Wemm 		|| ((up = strchr(namebuf, '@')) != 0 && up[1] == '>')) {
2610e3d5408SPeter Wemm 		(void) strcpy(suffix, up);
2620e3d5408SPeter Wemm 		*up = '\0';
2630e3d5408SPeter Wemm 	    }
2640e3d5408SPeter Wemm 
26515589c42SPeter Wemm 	    if ((tp = nametrans(namebuf)) != 0) {
2660e3d5408SPeter Wemm 		(void) putchar(':');
2670e3d5408SPeter Wemm 		(void) fputs(tp, stdout);
2680e3d5408SPeter Wemm 		(void) fputs(suffix, stdout);
2690e3d5408SPeter Wemm 		(void) putchar(':');
27015589c42SPeter Wemm 	    } else {
2710e3d5408SPeter Wemm 		/* couldn't find a translation, just dump the name */
2720e3d5408SPeter Wemm 		(void) putchar('<');
2730e3d5408SPeter Wemm 		(void) fputs(namebuf, stdout);
2740e3d5408SPeter Wemm 		(void) fputs(suffix, stdout);
2750e3d5408SPeter Wemm 		(void) putchar('>');
2760e3d5408SPeter Wemm 	    }
27715589c42SPeter Wemm 	}
27815589c42SPeter Wemm     } else {
27915589c42SPeter Wemm 	used = 0;
28015589c42SPeter Wemm 	if (c == '<') {
28115589c42SPeter Wemm 	    in_name = TRUE;
28215589c42SPeter Wemm 	} else {
28315589c42SPeter Wemm 	    putchar(c);
28415589c42SPeter Wemm 	}
2850e3d5408SPeter Wemm     }
2860e3d5408SPeter Wemm }
2870e3d5408SPeter Wemm 
2880e3d5408SPeter Wemm /* Returns a string, stripped of leading/trailing whitespace */
28915589c42SPeter Wemm static char *
29015589c42SPeter Wemm stripped(char *src)
2910e3d5408SPeter Wemm {
2920e3d5408SPeter Wemm     while (isspace(*src))
2930e3d5408SPeter Wemm 	src++;
2940e3d5408SPeter Wemm     if (*src != '\0') {
2950e3d5408SPeter Wemm 	char *dst = strcpy(malloc(strlen(src) + 1), src);
2960e3d5408SPeter Wemm 	size_t len = strlen(dst);
2970e3d5408SPeter Wemm 	while (--len != 0 && isspace(dst[len]))
2980e3d5408SPeter Wemm 	    dst[len] = '\0';
2990e3d5408SPeter Wemm 	return dst;
3000e3d5408SPeter Wemm     }
3010e3d5408SPeter Wemm     return 0;
3020e3d5408SPeter Wemm }
3030e3d5408SPeter Wemm 
3040e3d5408SPeter Wemm /* Parse the "-e" option-value into a list of names */
30515589c42SPeter Wemm static const char **
30615589c42SPeter Wemm make_namelist(char *src)
3070e3d5408SPeter Wemm {
3080e3d5408SPeter Wemm     const char **dst = 0;
3090e3d5408SPeter Wemm 
3100e3d5408SPeter Wemm     char *s, *base;
3110e3d5408SPeter Wemm     unsigned pass, n, nn;
3120e3d5408SPeter Wemm     char buffer[BUFSIZ];
3130e3d5408SPeter Wemm 
3140e3d5408SPeter Wemm     if (src == 0) {
3150e3d5408SPeter Wemm 	/* EMPTY */ ;
3160e3d5408SPeter Wemm     } else if (strchr(src, '/') != 0) {		/* a filename */
3170e3d5408SPeter Wemm 	FILE *fp = fopen(src, "r");
3180e3d5408SPeter Wemm 	if (fp == 0)
3190e3d5408SPeter Wemm 	    failed(src);
3200e3d5408SPeter Wemm 
3210e3d5408SPeter Wemm 	for (pass = 1; pass <= 2; pass++) {
3220e3d5408SPeter Wemm 	    nn = 0;
3230e3d5408SPeter Wemm 	    while (fgets(buffer, sizeof(buffer), fp) != 0) {
3240e3d5408SPeter Wemm 		if ((s = stripped(buffer)) != 0) {
3250e3d5408SPeter Wemm 		    if (dst != 0)
3260e3d5408SPeter Wemm 			dst[nn] = s;
3270e3d5408SPeter Wemm 		    nn++;
3280e3d5408SPeter Wemm 		}
3290e3d5408SPeter Wemm 	    }
3300e3d5408SPeter Wemm 	    if (pass == 1) {
33115589c42SPeter Wemm 		dst = typeCalloc(const char *, nn + 1);
3320e3d5408SPeter Wemm 		rewind(fp);
3330e3d5408SPeter Wemm 	    }
3340e3d5408SPeter Wemm 	}
3350e3d5408SPeter Wemm 	fclose(fp);
3360e3d5408SPeter Wemm     } else {			/* literal list of names */
3370e3d5408SPeter Wemm 	for (pass = 1; pass <= 2; pass++) {
3380e3d5408SPeter Wemm 	    for (n = nn = 0, base = src;; n++) {
3390e3d5408SPeter Wemm 		int mark = src[n];
3400e3d5408SPeter Wemm 		if (mark == ',' || mark == '\0') {
3410e3d5408SPeter Wemm 		    if (pass == 1) {
3420e3d5408SPeter Wemm 			nn++;
3430e3d5408SPeter Wemm 		    } else {
3440e3d5408SPeter Wemm 			src[n] = '\0';
3450e3d5408SPeter Wemm 			if ((s = stripped(base)) != 0)
3460e3d5408SPeter Wemm 			    dst[nn++] = s;
3470e3d5408SPeter Wemm 			base = &src[n + 1];
3480e3d5408SPeter Wemm 		    }
3490e3d5408SPeter Wemm 		}
3500e3d5408SPeter Wemm 		if (mark == '\0')
3510e3d5408SPeter Wemm 		    break;
3520e3d5408SPeter Wemm 	    }
3530e3d5408SPeter Wemm 	    if (pass == 1)
35415589c42SPeter Wemm 		dst = typeCalloc(const char *, nn + 1);
3550e3d5408SPeter Wemm 	}
3560e3d5408SPeter Wemm     }
3570e3d5408SPeter Wemm     if (showsummary) {
3580e3d5408SPeter Wemm 	fprintf(log_fp, "Entries that will be compiled:\n");
3590e3d5408SPeter Wemm 	for (n = 0; dst[n] != 0; n++)
3600e3d5408SPeter Wemm 	    fprintf(log_fp, "%d:%s\n", n + 1, dst[n]);
3610e3d5408SPeter Wemm     }
3620e3d5408SPeter Wemm     return dst;
3630e3d5408SPeter Wemm }
3640e3d5408SPeter Wemm 
36515589c42SPeter Wemm static bool
36615589c42SPeter Wemm matches(const char **needle, const char *haystack)
3670e3d5408SPeter Wemm /* does entry in needle list match |-separated field in haystack? */
3680e3d5408SPeter Wemm {
3690e3d5408SPeter Wemm     bool code = FALSE;
3700e3d5408SPeter Wemm     size_t n;
3710e3d5408SPeter Wemm 
37215589c42SPeter Wemm     if (needle != 0) {
37315589c42SPeter Wemm 	for (n = 0; needle[n] != 0; n++) {
37415589c42SPeter Wemm 	    if (_nc_name_match(haystack, needle[n], "|")) {
3750e3d5408SPeter Wemm 		code = TRUE;
3760e3d5408SPeter Wemm 		break;
3770e3d5408SPeter Wemm 	    }
3780e3d5408SPeter Wemm 	}
37915589c42SPeter Wemm     } else
3800e3d5408SPeter Wemm 	code = TRUE;
3810e3d5408SPeter Wemm     return (code);
3820e3d5408SPeter Wemm }
3830e3d5408SPeter Wemm 
38415589c42SPeter Wemm static FILE *
38515589c42SPeter Wemm open_tempfile(char *name)
38615589c42SPeter Wemm {
38715589c42SPeter Wemm     FILE *result = 0;
38815589c42SPeter Wemm #if HAVE_MKSTEMP
38915589c42SPeter Wemm     int fd = mkstemp(name);
39015589c42SPeter Wemm     if (fd >= 0)
39115589c42SPeter Wemm 	result = fdopen(fd, "w");
39215589c42SPeter Wemm #else
39315589c42SPeter Wemm     if (tmpnam(name) != 0)
39415589c42SPeter Wemm 	result = fopen(name, "w");
39515589c42SPeter Wemm #endif
39615589c42SPeter Wemm     return result;
39715589c42SPeter Wemm }
39815589c42SPeter Wemm 
39915589c42SPeter Wemm int
40015589c42SPeter Wemm main(int argc, char *argv[])
4010e3d5408SPeter Wemm {
4020e3d5408SPeter Wemm     char my_tmpname[PATH_MAX];
4030e3d5408SPeter Wemm     int v_opt = -1, debug_level;
4040e3d5408SPeter Wemm     int smart_defaults = TRUE;
4050e3d5408SPeter Wemm     char *termcap;
4060e3d5408SPeter Wemm     ENTRY *qp;
4070e3d5408SPeter Wemm 
4080e3d5408SPeter Wemm     int this_opt, last_opt = '?';
4090e3d5408SPeter Wemm 
4100e3d5408SPeter Wemm     int outform = F_TERMINFO;	/* output format */
4110e3d5408SPeter Wemm     int sortmode = S_TERMINFO;	/* sort_mode */
4120e3d5408SPeter Wemm 
4130e3d5408SPeter Wemm     int width = 60;
4140e3d5408SPeter Wemm     bool formatted = FALSE;	/* reformat complex strings? */
4150e3d5408SPeter Wemm     int numbers = 0;		/* format "%'char'" to/from "%{number}" */
4160e3d5408SPeter Wemm     bool infodump = FALSE;	/* running as captoinfo? */
4170e3d5408SPeter Wemm     bool capdump = FALSE;	/* running as infotocap? */
4180e3d5408SPeter Wemm     bool forceresolve = FALSE;	/* force resolution */
4190e3d5408SPeter Wemm     bool limited = TRUE;
4200e3d5408SPeter Wemm     char *tversion = (char *) NULL;
4210e3d5408SPeter Wemm     const char *source_file = "terminfo";
4220e3d5408SPeter Wemm     const char **namelst = 0;
4230e3d5408SPeter Wemm     char *outdir = (char *) NULL;
4240e3d5408SPeter Wemm     bool check_only = FALSE;
4250e3d5408SPeter Wemm 
4260e3d5408SPeter Wemm     log_fp = stderr;
4270e3d5408SPeter Wemm 
4280e3d5408SPeter Wemm     if ((_nc_progname = strrchr(argv[0], '/')) == NULL)
4290e3d5408SPeter Wemm 	_nc_progname = argv[0];
4300e3d5408SPeter Wemm     else
4310e3d5408SPeter Wemm 	_nc_progname++;
4320e3d5408SPeter Wemm 
43315589c42SPeter Wemm     if ((infodump = (strcmp(_nc_progname, "captoinfo") == 0)) != FALSE) {
43415589c42SPeter Wemm 	outform = F_TERMINFO;
43515589c42SPeter Wemm 	sortmode = S_TERMINFO;
43615589c42SPeter Wemm     }
43715589c42SPeter Wemm     if ((capdump = (strcmp(_nc_progname, "infotocap") == 0)) != FALSE) {
43815589c42SPeter Wemm 	outform = F_TERMCAP;
43915589c42SPeter Wemm 	sortmode = S_TERMCAP;
44015589c42SPeter Wemm     }
4410e3d5408SPeter Wemm #if NCURSES_XNAMES
4420e3d5408SPeter Wemm     use_extended_names(FALSE);
4430e3d5408SPeter Wemm #endif
4440e3d5408SPeter Wemm 
4450e3d5408SPeter Wemm     /*
4460e3d5408SPeter Wemm      * Processing arguments is a little complicated, since someone made a
4470e3d5408SPeter Wemm      * design decision to allow the numeric values for -w, -v options to
4480e3d5408SPeter Wemm      * be optional.
4490e3d5408SPeter Wemm      */
45015589c42SPeter Wemm     while ((this_opt = getopt(argc, argv,
45115589c42SPeter Wemm 		"0123456789CILNR:TVace:fGgo:rsvwx")) != EOF) {
4520e3d5408SPeter Wemm 	if (isdigit(this_opt)) {
4530e3d5408SPeter Wemm 	    switch (last_opt) {
4540e3d5408SPeter Wemm 	    case 'v':
4550e3d5408SPeter Wemm 		v_opt = (v_opt * 10) + (this_opt - '0');
4560e3d5408SPeter Wemm 		break;
4570e3d5408SPeter Wemm 	    case 'w':
4580e3d5408SPeter Wemm 		width = (width * 10) + (this_opt - '0');
4590e3d5408SPeter Wemm 		break;
4600e3d5408SPeter Wemm 	    default:
4610e3d5408SPeter Wemm 		if (this_opt != '1')
4620e3d5408SPeter Wemm 		    usage();
4630e3d5408SPeter Wemm 		last_opt = this_opt;
4640e3d5408SPeter Wemm 		width = 0;
4650e3d5408SPeter Wemm 	    }
4660e3d5408SPeter Wemm 	    continue;
4670e3d5408SPeter Wemm 	}
4680e3d5408SPeter Wemm 	switch (this_opt) {
4690e3d5408SPeter Wemm 	case 'C':
4700e3d5408SPeter Wemm 	    capdump = TRUE;
4710e3d5408SPeter Wemm 	    outform = F_TERMCAP;
4720e3d5408SPeter Wemm 	    sortmode = S_TERMCAP;
4730e3d5408SPeter Wemm 	    break;
4740e3d5408SPeter Wemm 	case 'I':
4750e3d5408SPeter Wemm 	    infodump = TRUE;
4760e3d5408SPeter Wemm 	    outform = F_TERMINFO;
4770e3d5408SPeter Wemm 	    sortmode = S_TERMINFO;
4780e3d5408SPeter Wemm 	    break;
4790e3d5408SPeter Wemm 	case 'L':
4800e3d5408SPeter Wemm 	    infodump = TRUE;
4810e3d5408SPeter Wemm 	    outform = F_VARIABLE;
4820e3d5408SPeter Wemm 	    sortmode = S_VARIABLE;
4830e3d5408SPeter Wemm 	    break;
4840e3d5408SPeter Wemm 	case 'N':
4850e3d5408SPeter Wemm 	    smart_defaults = FALSE;
4860e3d5408SPeter Wemm 	    break;
4870e3d5408SPeter Wemm 	case 'R':
4880e3d5408SPeter Wemm 	    tversion = optarg;
4890e3d5408SPeter Wemm 	    break;
4900e3d5408SPeter Wemm 	case 'T':
4910e3d5408SPeter Wemm 	    limited = FALSE;
4920e3d5408SPeter Wemm 	    break;
4930e3d5408SPeter Wemm 	case 'V':
4940e3d5408SPeter Wemm 	    puts(NCURSES_VERSION);
4950e3d5408SPeter Wemm 	    return EXIT_SUCCESS;
4960e3d5408SPeter Wemm 	case 'c':
4970e3d5408SPeter Wemm 	    check_only = TRUE;
4980e3d5408SPeter Wemm 	    break;
4990e3d5408SPeter Wemm 	case 'e':
5000e3d5408SPeter Wemm 	    namelst = make_namelist(optarg);
5010e3d5408SPeter Wemm 	    break;
5020e3d5408SPeter Wemm 	case 'f':
5030e3d5408SPeter Wemm 	    formatted = TRUE;
5040e3d5408SPeter Wemm 	    break;
5050e3d5408SPeter Wemm 	case 'G':
5060e3d5408SPeter Wemm 	    numbers = 1;
5070e3d5408SPeter Wemm 	    break;
5080e3d5408SPeter Wemm 	case 'g':
5090e3d5408SPeter Wemm 	    numbers = -1;
5100e3d5408SPeter Wemm 	    break;
5110e3d5408SPeter Wemm 	case 'o':
5120e3d5408SPeter Wemm 	    outdir = optarg;
5130e3d5408SPeter Wemm 	    break;
5140e3d5408SPeter Wemm 	case 'r':
5150e3d5408SPeter Wemm 	    forceresolve = TRUE;
5160e3d5408SPeter Wemm 	    break;
5170e3d5408SPeter Wemm 	case 's':
5180e3d5408SPeter Wemm 	    showsummary = TRUE;
5190e3d5408SPeter Wemm 	    break;
5200e3d5408SPeter Wemm 	case 'v':
5210e3d5408SPeter Wemm 	    v_opt = 0;
5220e3d5408SPeter Wemm 	    break;
5230e3d5408SPeter Wemm 	case 'w':
5240e3d5408SPeter Wemm 	    width = 0;
5250e3d5408SPeter Wemm 	    break;
5260e3d5408SPeter Wemm #if NCURSES_XNAMES
52715589c42SPeter Wemm 	case 'a':
52815589c42SPeter Wemm 	    _nc_disable_period = TRUE;
52915589c42SPeter Wemm 	    /* FALLTHRU */
5300e3d5408SPeter Wemm 	case 'x':
5310e3d5408SPeter Wemm 	    use_extended_names(TRUE);
5320e3d5408SPeter Wemm 	    break;
5330e3d5408SPeter Wemm #endif
5340e3d5408SPeter Wemm 	default:
5350e3d5408SPeter Wemm 	    usage();
5360e3d5408SPeter Wemm 	}
5370e3d5408SPeter Wemm 	last_opt = this_opt;
5380e3d5408SPeter Wemm     }
5390e3d5408SPeter Wemm 
5400e3d5408SPeter Wemm     debug_level = (v_opt > 0) ? v_opt : (v_opt == 0);
54115589c42SPeter Wemm     set_trace_level(debug_level);
5420e3d5408SPeter Wemm 
54315589c42SPeter Wemm     if (_nc_tracing) {
5440e3d5408SPeter Wemm 	save_check_termtype = _nc_check_termtype;
5450e3d5408SPeter Wemm 	_nc_check_termtype = check_termtype;
5460e3d5408SPeter Wemm     }
5470e3d5408SPeter Wemm #ifndef HAVE_BIG_CORE
5480e3d5408SPeter Wemm     /*
5490e3d5408SPeter Wemm      * Aaargh! immedhook seriously hoses us!
5500e3d5408SPeter Wemm      *
5510e3d5408SPeter Wemm      * One problem with immedhook is it means we can't do -e.  Problem
5520e3d5408SPeter Wemm      * is that we can't guarantee that for each terminal listed, all the
5530e3d5408SPeter Wemm      * terminals it depends on will have been kept in core for reference
5540e3d5408SPeter Wemm      * resolution -- in fact it's certain the primitive types at the end
5550e3d5408SPeter Wemm      * of reference chains *won't* be in core unless they were explicitly
5560e3d5408SPeter Wemm      * in the select list themselves.
5570e3d5408SPeter Wemm      */
55815589c42SPeter Wemm     if (namelst && (!infodump && !capdump)) {
5590e3d5408SPeter Wemm 	(void) fprintf(stderr,
5600e3d5408SPeter Wemm 	    "Sorry, -e can't be used without -I or -C\n");
5610e3d5408SPeter Wemm 	cleanup();
5620e3d5408SPeter Wemm 	return EXIT_FAILURE;
5630e3d5408SPeter Wemm     }
5640e3d5408SPeter Wemm #endif /* HAVE_BIG_CORE */
5650e3d5408SPeter Wemm 
5660e3d5408SPeter Wemm     if (optind < argc) {
5670e3d5408SPeter Wemm 	source_file = argv[optind++];
5680e3d5408SPeter Wemm 	if (optind < argc) {
5690e3d5408SPeter Wemm 	    fprintf(stderr,
5700e3d5408SPeter Wemm 		"%s: Too many file names.  Usage:\n\t%s %s",
5710e3d5408SPeter Wemm 		_nc_progname,
5720e3d5408SPeter Wemm 		_nc_progname,
5730e3d5408SPeter Wemm 		usage_string);
5740e3d5408SPeter Wemm 	    return EXIT_FAILURE;
5750e3d5408SPeter Wemm 	}
5760e3d5408SPeter Wemm     } else {
5770e3d5408SPeter Wemm 	if (infodump == TRUE) {
5780e3d5408SPeter Wemm 	    /* captoinfo's no-argument case */
5790e3d5408SPeter Wemm 	    source_file = "/etc/termcap";
5800e3d5408SPeter Wemm 	    if ((termcap = getenv("TERMCAP")) != 0
5810e3d5408SPeter Wemm 		&& (namelst = make_namelist(getenv("TERM"))) != 0) {
5820e3d5408SPeter Wemm 		if (access(termcap, F_OK) == 0) {
5830e3d5408SPeter Wemm 		    /* file exists */
5840e3d5408SPeter Wemm 		    source_file = termcap;
58515589c42SPeter Wemm 		} else if ((tmp_fp = open_tempfile(my_tmpname)) != 0) {
58615589c42SPeter Wemm 		    source_file = my_tmpname;
5870e3d5408SPeter Wemm 		    fprintf(tmp_fp, "%s\n", termcap);
5880e3d5408SPeter Wemm 		    fclose(tmp_fp);
5890e3d5408SPeter Wemm 		    tmp_fp = fopen(source_file, "r");
5900e3d5408SPeter Wemm 		    to_remove = source_file;
5910e3d5408SPeter Wemm 		} else {
5920e3d5408SPeter Wemm 		    failed("tmpnam");
5930e3d5408SPeter Wemm 		}
5940e3d5408SPeter Wemm 	    }
5950e3d5408SPeter Wemm 	} else {
5960e3d5408SPeter Wemm 	    /* tic */
5970e3d5408SPeter Wemm 	    fprintf(stderr,
5980e3d5408SPeter Wemm 		"%s: File name needed.  Usage:\n\t%s %s",
5990e3d5408SPeter Wemm 		_nc_progname,
6000e3d5408SPeter Wemm 		_nc_progname,
6010e3d5408SPeter Wemm 		usage_string);
6020e3d5408SPeter Wemm 	    cleanup();
6030e3d5408SPeter Wemm 	    return EXIT_FAILURE;
6040e3d5408SPeter Wemm 	}
6050e3d5408SPeter Wemm     }
6060e3d5408SPeter Wemm 
6070e3d5408SPeter Wemm     if (tmp_fp == 0
6080e3d5408SPeter Wemm 	&& (tmp_fp = fopen(source_file, "r")) == 0) {
6090e3d5408SPeter Wemm 	fprintf(stderr, "%s: Can't open %s\n", _nc_progname, source_file);
6100e3d5408SPeter Wemm 	return EXIT_FAILURE;
6110e3d5408SPeter Wemm     }
6120e3d5408SPeter Wemm 
6130e3d5408SPeter Wemm     if (infodump)
6140e3d5408SPeter Wemm 	dump_init(tversion,
6150e3d5408SPeter Wemm 	    smart_defaults
6160e3d5408SPeter Wemm 	    ? outform
6170e3d5408SPeter Wemm 	    : F_LITERAL,
6180e3d5408SPeter Wemm 	    sortmode, width, debug_level, formatted);
6190e3d5408SPeter Wemm     else if (capdump)
6200e3d5408SPeter Wemm 	dump_init(tversion,
6210e3d5408SPeter Wemm 	    outform,
6220e3d5408SPeter Wemm 	    sortmode, width, debug_level, FALSE);
6230e3d5408SPeter Wemm 
6240e3d5408SPeter Wemm     /* parse entries out of the source file */
6250e3d5408SPeter Wemm     _nc_set_source(source_file);
6260e3d5408SPeter Wemm #ifndef HAVE_BIG_CORE
6270e3d5408SPeter Wemm     if (!(check_only || infodump || capdump))
6280e3d5408SPeter Wemm 	_nc_set_writedir(outdir);
6290e3d5408SPeter Wemm #endif /* HAVE_BIG_CORE */
6300e3d5408SPeter Wemm     _nc_read_entry_source(tmp_fp, (char *) NULL,
6310e3d5408SPeter Wemm 	!smart_defaults, FALSE,
6320e3d5408SPeter Wemm 	(check_only || infodump || capdump) ? NULLHOOK : immedhook);
6330e3d5408SPeter Wemm 
6340e3d5408SPeter Wemm     /* do use resolution */
6350e3d5408SPeter Wemm     if (check_only || (!infodump && !capdump) || forceresolve) {
63615589c42SPeter Wemm 	if (!_nc_resolve_uses(TRUE) && !check_only) {
6370e3d5408SPeter Wemm 	    cleanup();
6380e3d5408SPeter Wemm 	    return EXIT_FAILURE;
6390e3d5408SPeter Wemm 	}
6400e3d5408SPeter Wemm     }
6410e3d5408SPeter Wemm 
6420e3d5408SPeter Wemm     /* length check */
64315589c42SPeter Wemm     if (check_only && (capdump || infodump)) {
64415589c42SPeter Wemm 	for_entry_list(qp) {
64515589c42SPeter Wemm 	    if (matches(namelst, qp->tterm.term_names)) {
6460e3d5408SPeter Wemm 		int len = fmt_entry(&qp->tterm, NULL, TRUE, infodump, numbers);
6470e3d5408SPeter Wemm 
6480e3d5408SPeter Wemm 		if (len > (infodump ? MAX_TERMINFO_LENGTH : MAX_TERMCAP_LENGTH))
6490e3d5408SPeter Wemm 		    (void) fprintf(stderr,
6500e3d5408SPeter Wemm 			"warning: resolved %s entry is %d bytes long\n",
6510e3d5408SPeter Wemm 			_nc_first_name(qp->tterm.term_names),
6520e3d5408SPeter Wemm 			len);
6530e3d5408SPeter Wemm 	    }
6540e3d5408SPeter Wemm 	}
6550e3d5408SPeter Wemm     }
6560e3d5408SPeter Wemm 
6570e3d5408SPeter Wemm     /* write or dump all entries */
65815589c42SPeter Wemm     if (!check_only) {
65915589c42SPeter Wemm 	if (!infodump && !capdump) {
6600e3d5408SPeter Wemm 	    _nc_set_writedir(outdir);
66115589c42SPeter Wemm 	    for_entry_list(qp) {
6620e3d5408SPeter Wemm 		if (matches(namelst, qp->tterm.term_names))
6630e3d5408SPeter Wemm 		    write_it(qp);
6640e3d5408SPeter Wemm 	    }
66515589c42SPeter Wemm 	} else {
6660e3d5408SPeter Wemm 	    /* this is in case infotocap() generates warnings */
6670e3d5408SPeter Wemm 	    _nc_curr_col = _nc_curr_line = -1;
6680e3d5408SPeter Wemm 
66915589c42SPeter Wemm 	    for_entry_list(qp) {
67015589c42SPeter Wemm 		if (matches(namelst, qp->tterm.term_names)) {
6710e3d5408SPeter Wemm 		    int j = qp->cend - qp->cstart;
6720e3d5408SPeter Wemm 		    int len = 0;
6730e3d5408SPeter Wemm 
6740e3d5408SPeter Wemm 		    /* this is in case infotocap() generates warnings */
6750e3d5408SPeter Wemm 		    _nc_set_type(_nc_first_name(qp->tterm.term_names));
6760e3d5408SPeter Wemm 
6770e3d5408SPeter Wemm 		    (void) fseek(tmp_fp, qp->cstart, SEEK_SET);
67815589c42SPeter Wemm 		    while (j--) {
6790e3d5408SPeter Wemm 			if (infodump)
6800e3d5408SPeter Wemm 			    (void) putchar(fgetc(tmp_fp));
6810e3d5408SPeter Wemm 			else
6820e3d5408SPeter Wemm 			    put_translate(fgetc(tmp_fp));
68315589c42SPeter Wemm 		    }
6840e3d5408SPeter Wemm 
6850e3d5408SPeter Wemm 		    len = dump_entry(&qp->tterm, limited, numbers, NULL);
6860e3d5408SPeter Wemm 		    for (j = 0; j < qp->nuses; j++)
68715589c42SPeter Wemm 			len += dump_uses(qp->uses[j].name, !capdump);
6880e3d5408SPeter Wemm 		    (void) putchar('\n');
6890e3d5408SPeter Wemm 		    if (debug_level != 0 && !limited)
6900e3d5408SPeter Wemm 			printf("# length=%d\n", len);
6910e3d5408SPeter Wemm 		}
69215589c42SPeter Wemm 	    }
69315589c42SPeter Wemm 	    if (!namelst) {
6940e3d5408SPeter Wemm 		int c, oldc = '\0';
6950e3d5408SPeter Wemm 		bool in_comment = FALSE;
6960e3d5408SPeter Wemm 		bool trailing_comment = FALSE;
6970e3d5408SPeter Wemm 
6980e3d5408SPeter Wemm 		(void) fseek(tmp_fp, _nc_tail->cend, SEEK_SET);
69915589c42SPeter Wemm 		while ((c = fgetc(tmp_fp)) != EOF) {
7000e3d5408SPeter Wemm 		    if (oldc == '\n') {
7010e3d5408SPeter Wemm 			if (c == '#') {
7020e3d5408SPeter Wemm 			    trailing_comment = TRUE;
7030e3d5408SPeter Wemm 			    in_comment = TRUE;
7040e3d5408SPeter Wemm 			} else {
7050e3d5408SPeter Wemm 			    in_comment = FALSE;
7060e3d5408SPeter Wemm 			}
7070e3d5408SPeter Wemm 		    }
7080e3d5408SPeter Wemm 		    if (trailing_comment
7090e3d5408SPeter Wemm 			&& (in_comment || (oldc == '\n' && c == '\n')))
7100e3d5408SPeter Wemm 			putchar(c);
7110e3d5408SPeter Wemm 		    oldc = c;
7120e3d5408SPeter Wemm 		}
7130e3d5408SPeter Wemm 	    }
7140e3d5408SPeter Wemm 	}
7150e3d5408SPeter Wemm     }
7160e3d5408SPeter Wemm 
7170e3d5408SPeter Wemm     /* Show the directory into which entries were written, and the total
7180e3d5408SPeter Wemm      * number of entries
7190e3d5408SPeter Wemm      */
7200e3d5408SPeter Wemm     if (showsummary
7210e3d5408SPeter Wemm 	&& (!(check_only || infodump || capdump))) {
7220e3d5408SPeter Wemm 	int total = _nc_tic_written();
7230e3d5408SPeter Wemm 	if (total != 0)
7240e3d5408SPeter Wemm 	    fprintf(log_fp, "%d entries written to %s\n",
7250e3d5408SPeter Wemm 		total,
7260e3d5408SPeter Wemm 		_nc_tic_dir((char *) 0));
7270e3d5408SPeter Wemm 	else
7280e3d5408SPeter Wemm 	    fprintf(log_fp, "No entries written\n");
7290e3d5408SPeter Wemm     }
7300e3d5408SPeter Wemm     cleanup();
7310e3d5408SPeter Wemm     return (EXIT_SUCCESS);
7320e3d5408SPeter Wemm }
7330e3d5408SPeter Wemm 
7340e3d5408SPeter Wemm /*
7350e3d5408SPeter Wemm  * This bit of legerdemain turns all the terminfo variable names into
7360e3d5408SPeter Wemm  * references to locations in the arrays Booleans, Numbers, and Strings ---
7370e3d5408SPeter Wemm  * precisely what's needed (see comp_parse.c).
7380e3d5408SPeter Wemm  */
7390e3d5408SPeter Wemm 
7400e3d5408SPeter Wemm TERMINAL *cur_term;		/* tweak to avoid linking lib_cur_term.c */
7410e3d5408SPeter Wemm 
7420e3d5408SPeter Wemm #undef CUR
7430e3d5408SPeter Wemm #define CUR tp->
7440e3d5408SPeter Wemm 
74515589c42SPeter Wemm /*
74615589c42SPeter Wemm  * An sgr string may contain several settings other than the one we're
74715589c42SPeter Wemm  * interested in, essentially sgr0 + rmacs + whatever.  As long as the
74815589c42SPeter Wemm  * "whatever" is contained in the sgr string, that is close enough for our
74915589c42SPeter Wemm  * sanity check.
75015589c42SPeter Wemm  */
75115589c42SPeter Wemm static bool
75215589c42SPeter Wemm similar_sgr(char *a, char *b)
75315589c42SPeter Wemm {
75415589c42SPeter Wemm     while (*b != 0) {
75515589c42SPeter Wemm 	while (*a != *b) {
75615589c42SPeter Wemm 	    if (*a == 0)
75715589c42SPeter Wemm 		return FALSE;
75815589c42SPeter Wemm 	    a++;
75915589c42SPeter Wemm 	}
76015589c42SPeter Wemm 	a++;
76115589c42SPeter Wemm 	b++;
76215589c42SPeter Wemm     }
76315589c42SPeter Wemm     return TRUE;
76415589c42SPeter Wemm }
76515589c42SPeter Wemm 
76615589c42SPeter Wemm static void
76715589c42SPeter Wemm check_sgr(TERMTYPE * tp, char *zero, int num, char *cap, const char *name)
76815589c42SPeter Wemm {
76915589c42SPeter Wemm     char *test = tparm(set_attributes,
77015589c42SPeter Wemm 	num == 1,
77115589c42SPeter Wemm 	num == 2,
77215589c42SPeter Wemm 	num == 3,
77315589c42SPeter Wemm 	num == 4,
77415589c42SPeter Wemm 	num == 5,
77515589c42SPeter Wemm 	num == 6,
77615589c42SPeter Wemm 	num == 7,
77715589c42SPeter Wemm 	num == 8,
77815589c42SPeter Wemm 	num == 9);
77915589c42SPeter Wemm     if (test != 0) {
78015589c42SPeter Wemm 	if (PRESENT(cap)) {
78115589c42SPeter Wemm 	    if (!similar_sgr(test, cap)) {
78215589c42SPeter Wemm 		_nc_warning("%s differs from sgr(%d): %s", name, num,
78315589c42SPeter Wemm 		    _nc_visbuf(test));
78415589c42SPeter Wemm 	    }
78515589c42SPeter Wemm 	} else if (strcmp(test, zero)) {
78615589c42SPeter Wemm 	    _nc_warning("sgr(%d) present, but not %s", num, name);
78715589c42SPeter Wemm 	}
78815589c42SPeter Wemm     } else if (PRESENT(cap)) {
78915589c42SPeter Wemm 	_nc_warning("sgr(%d) missing, but %s present", num, name);
79015589c42SPeter Wemm     }
79115589c42SPeter Wemm }
79215589c42SPeter Wemm 
79315589c42SPeter Wemm #define CHECK_SGR(num,name) check_sgr(tp, zero, num, name, #name)
79415589c42SPeter Wemm 
7950e3d5408SPeter Wemm /* other sanity-checks (things that we don't want in the normal
7960e3d5408SPeter Wemm  * logic that reads a terminfo entry)
7970e3d5408SPeter Wemm  */
79815589c42SPeter Wemm static void
79915589c42SPeter Wemm check_termtype(TERMTYPE * tp)
8000e3d5408SPeter Wemm {
8010e3d5408SPeter Wemm     bool conflict = FALSE;
8020e3d5408SPeter Wemm     unsigned j, k;
8030e3d5408SPeter Wemm     char fkeys[STRCOUNT];
8040e3d5408SPeter Wemm 
8050e3d5408SPeter Wemm     /*
8060e3d5408SPeter Wemm      * A terminal entry may contain more than one keycode assigned to
8070e3d5408SPeter Wemm      * a given string (e.g., KEY_END and KEY_LL).  But curses will only
8080e3d5408SPeter Wemm      * return one (the last one assigned).
8090e3d5408SPeter Wemm      */
8100e3d5408SPeter Wemm     memset(fkeys, 0, sizeof(fkeys));
8110e3d5408SPeter Wemm     for (j = 0; _nc_tinfo_fkeys[j].code; j++) {
8120e3d5408SPeter Wemm 	char *a = tp->Strings[_nc_tinfo_fkeys[j].offset];
8130e3d5408SPeter Wemm 	bool first = TRUE;
8140e3d5408SPeter Wemm 	if (!VALID_STRING(a))
8150e3d5408SPeter Wemm 	    continue;
8160e3d5408SPeter Wemm 	for (k = j + 1; _nc_tinfo_fkeys[k].code; k++) {
8170e3d5408SPeter Wemm 	    char *b = tp->Strings[_nc_tinfo_fkeys[k].offset];
8180e3d5408SPeter Wemm 	    if (!VALID_STRING(b)
8190e3d5408SPeter Wemm 		|| fkeys[k])
8200e3d5408SPeter Wemm 		continue;
8210e3d5408SPeter Wemm 	    if (!strcmp(a, b)) {
8220e3d5408SPeter Wemm 		fkeys[j] = 1;
8230e3d5408SPeter Wemm 		fkeys[k] = 1;
8240e3d5408SPeter Wemm 		if (first) {
8250e3d5408SPeter Wemm 		    if (!conflict) {
8260e3d5408SPeter Wemm 			_nc_warning("Conflicting key definitions (using the last)");
8270e3d5408SPeter Wemm 			conflict = TRUE;
8280e3d5408SPeter Wemm 		    }
8290e3d5408SPeter Wemm 		    fprintf(stderr, "... %s is the same as %s",
8300e3d5408SPeter Wemm 			keyname(_nc_tinfo_fkeys[j].code),
8310e3d5408SPeter Wemm 			keyname(_nc_tinfo_fkeys[k].code));
8320e3d5408SPeter Wemm 		    first = FALSE;
8330e3d5408SPeter Wemm 		} else {
8340e3d5408SPeter Wemm 		    fprintf(stderr, ", %s",
8350e3d5408SPeter Wemm 			keyname(_nc_tinfo_fkeys[k].code));
8360e3d5408SPeter Wemm 		}
8370e3d5408SPeter Wemm 	    }
8380e3d5408SPeter Wemm 	}
8390e3d5408SPeter Wemm 	if (!first)
8400e3d5408SPeter Wemm 	    fprintf(stderr, "\n");
8410e3d5408SPeter Wemm     }
8420e3d5408SPeter Wemm 
8430e3d5408SPeter Wemm     /*
8440e3d5408SPeter Wemm      * Quick check for color.  We could also check if the ANSI versus
8450e3d5408SPeter Wemm      * non-ANSI strings are misused.
8460e3d5408SPeter Wemm      */
8470e3d5408SPeter Wemm     if ((max_colors > 0) != (max_pairs > 0)
8480e3d5408SPeter Wemm 	|| (max_colors > max_pairs))
8490e3d5408SPeter Wemm 	_nc_warning("inconsistent values for max_colors and max_pairs");
8500e3d5408SPeter Wemm 
85115589c42SPeter Wemm     PAIRED(set_foreground, set_background);
85215589c42SPeter Wemm     PAIRED(set_a_foreground, set_a_background);
8530e3d5408SPeter Wemm 
8540e3d5408SPeter Wemm     /*
8550e3d5408SPeter Wemm      * These may be mismatched because the terminal description relies on
8560e3d5408SPeter Wemm      * restoring the cursor visibility by resetting it.
8570e3d5408SPeter Wemm      */
85815589c42SPeter Wemm     ANDMISSING(cursor_invisible, cursor_normal);
85915589c42SPeter Wemm     ANDMISSING(cursor_visible, cursor_normal);
86015589c42SPeter Wemm 
86115589c42SPeter Wemm     if (PRESENT(cursor_visible) && PRESENT(cursor_normal)
86215589c42SPeter Wemm 	&& !strcmp(cursor_visible, cursor_normal))
86315589c42SPeter Wemm 	_nc_warning("cursor_visible is same as cursor_normal");
8640e3d5408SPeter Wemm 
8650e3d5408SPeter Wemm     /*
8660e3d5408SPeter Wemm      * From XSI & O'Reilly, we gather that sc/rc are required if csr is
8670e3d5408SPeter Wemm      * given, because the cursor position after the scrolling operation is
8680e3d5408SPeter Wemm      * performed is undefined.
8690e3d5408SPeter Wemm      */
87015589c42SPeter Wemm     ANDMISSING(change_scroll_region, save_cursor);
87115589c42SPeter Wemm     ANDMISSING(change_scroll_region, restore_cursor);
87215589c42SPeter Wemm 
87315589c42SPeter Wemm     if (PRESENT(set_attributes)) {
87415589c42SPeter Wemm 	char *zero = tparm(set_attributes, 0, 0, 0, 0, 0, 0, 0, 0, 0);
87515589c42SPeter Wemm 
87615589c42SPeter Wemm 	zero = strdup(zero);
87715589c42SPeter Wemm 	CHECK_SGR(1, enter_standout_mode);
87815589c42SPeter Wemm 	CHECK_SGR(2, enter_underline_mode);
87915589c42SPeter Wemm 	CHECK_SGR(3, enter_reverse_mode);
88015589c42SPeter Wemm 	CHECK_SGR(4, enter_blink_mode);
88115589c42SPeter Wemm 	CHECK_SGR(5, enter_dim_mode);
88215589c42SPeter Wemm 	CHECK_SGR(6, enter_bold_mode);
88315589c42SPeter Wemm 	CHECK_SGR(7, enter_secure_mode);
88415589c42SPeter Wemm 	CHECK_SGR(8, enter_protected_mode);
88515589c42SPeter Wemm 	CHECK_SGR(9, enter_alt_charset_mode);
88615589c42SPeter Wemm 	free(zero);
88715589c42SPeter Wemm     }
8880e3d5408SPeter Wemm 
8890e3d5408SPeter Wemm     /*
8900e3d5408SPeter Wemm      * Some standard applications (e.g., vi) and some non-curses
8910e3d5408SPeter Wemm      * applications (e.g., jove) get confused if we have both ich/ich1 and
8920e3d5408SPeter Wemm      * smir/rmir.  Let's be nice and warn about that, too, even though
8930e3d5408SPeter Wemm      * ncurses handles it.
8940e3d5408SPeter Wemm      */
8950e3d5408SPeter Wemm     if ((PRESENT(enter_insert_mode) || PRESENT(exit_insert_mode))
8960e3d5408SPeter Wemm 	&& (PRESENT(insert_character) || PRESENT(parm_ich))) {
8970e3d5408SPeter Wemm 	_nc_warning("non-curses applications may be confused by ich/ich1 with smir/rmir");
8980e3d5408SPeter Wemm     }
8990e3d5408SPeter Wemm 
9000e3d5408SPeter Wemm     /*
9010e3d5408SPeter Wemm      * Finally, do the non-verbose checks
9020e3d5408SPeter Wemm      */
9030e3d5408SPeter Wemm     if (save_check_termtype != 0)
9040e3d5408SPeter Wemm 	save_check_termtype(tp);
9050e3d5408SPeter Wemm }
906