xref: /freebsd/contrib/ncurses/progs/tic.c (revision 18259542b2f8fa7e3f76f4bb0dd37995dfd424aa)
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>
4118259542SPeter Wemm #include <sys/stat.h>
420e3d5408SPeter Wemm 
430e3d5408SPeter Wemm #include <dump_entry.h>
440e3d5408SPeter Wemm #include <term_entry.h>
4518259542SPeter Wemm #include <transform.h>
460e3d5408SPeter Wemm 
4718259542SPeter Wemm MODULE_ID("$Id: tic.c,v 1.82 2000/10/01 02:11:39 tom Exp $")
480e3d5408SPeter Wemm 
490e3d5408SPeter Wemm const char *_nc_progname = "tic";
500e3d5408SPeter Wemm 
510e3d5408SPeter Wemm static FILE *log_fp;
520e3d5408SPeter Wemm static FILE *tmp_fp;
530e3d5408SPeter Wemm static bool showsummary = FALSE;
540e3d5408SPeter Wemm static const char *to_remove;
550e3d5408SPeter Wemm 
560e3d5408SPeter Wemm static void (*save_check_termtype) (TERMTYPE *);
570e3d5408SPeter Wemm static void check_termtype(TERMTYPE * tt);
580e3d5408SPeter Wemm 
5918259542SPeter Wemm static const char usage_string[] = "[-V] [-v[n]] [-e names] [-CILNRTcfrswx1] source-file\n";
600e3d5408SPeter Wemm 
6115589c42SPeter Wemm static void
6215589c42SPeter Wemm cleanup(void)
630e3d5408SPeter Wemm {
640e3d5408SPeter Wemm     if (tmp_fp != 0)
650e3d5408SPeter Wemm 	fclose(tmp_fp);
660e3d5408SPeter Wemm     if (to_remove != 0) {
670e3d5408SPeter Wemm #if HAVE_REMOVE
680e3d5408SPeter Wemm 	remove(to_remove);
690e3d5408SPeter Wemm #else
700e3d5408SPeter Wemm 	unlink(to_remove);
710e3d5408SPeter Wemm #endif
720e3d5408SPeter Wemm     }
730e3d5408SPeter Wemm }
740e3d5408SPeter Wemm 
7515589c42SPeter Wemm static void
7615589c42SPeter Wemm failed(const char *msg)
770e3d5408SPeter Wemm {
780e3d5408SPeter Wemm     perror(msg);
790e3d5408SPeter Wemm     cleanup();
800e3d5408SPeter Wemm     exit(EXIT_FAILURE);
810e3d5408SPeter Wemm }
820e3d5408SPeter Wemm 
8315589c42SPeter Wemm static void
8415589c42SPeter Wemm usage(void)
850e3d5408SPeter Wemm {
8615589c42SPeter Wemm     static const char *const tbl[] =
8715589c42SPeter Wemm     {
880e3d5408SPeter Wemm 	"Options:",
890e3d5408SPeter Wemm 	"  -1         format translation output one capability per line",
900e3d5408SPeter Wemm 	"  -C         translate entries to termcap source form",
910e3d5408SPeter Wemm 	"  -I         translate entries to terminfo source form",
920e3d5408SPeter Wemm 	"  -L         translate entries to full terminfo source form",
930e3d5408SPeter Wemm 	"  -N         disable smart defaults for source translation",
940e3d5408SPeter Wemm 	"  -R         restrict translation to given terminfo/termcap version",
950e3d5408SPeter Wemm 	"  -T         remove size-restrictions on compiled description",
9618259542SPeter Wemm 	"  -V         print version",
9715589c42SPeter Wemm #if NCURSES_XNAMES
9815589c42SPeter Wemm 	"  -a         retain commented-out capabilities (sets -x also)",
9915589c42SPeter Wemm #endif
1000e3d5408SPeter Wemm 	"  -c         check only, validate input without compiling or translating",
1010e3d5408SPeter Wemm 	"  -f         format complex strings for readability",
1020e3d5408SPeter Wemm 	"  -G         format %{number} to %'char'",
1030e3d5408SPeter Wemm 	"  -g         format %'char' to %{number}",
1040e3d5408SPeter Wemm 	"  -e<names>  translate/compile only entries named by comma-separated list",
1050e3d5408SPeter Wemm 	"  -o<dir>    set output directory for compiled entry writes",
1060e3d5408SPeter Wemm 	"  -r         force resolution of all use entries in source translation",
1070e3d5408SPeter Wemm 	"  -s         print summary statistics",
1080e3d5408SPeter Wemm 	"  -v[n]      set verbosity level",
1090e3d5408SPeter Wemm 	"  -w[n]      set format width for translation output",
1100e3d5408SPeter Wemm #if NCURSES_XNAMES
1110e3d5408SPeter Wemm 	"  -x         treat unknown capabilities as user-defined",
1120e3d5408SPeter Wemm #endif
1130e3d5408SPeter Wemm 	"",
1140e3d5408SPeter Wemm 	"Parameters:",
1150e3d5408SPeter Wemm 	"  <file>     file to translate or compile"
1160e3d5408SPeter Wemm     };
1170e3d5408SPeter Wemm     size_t j;
1180e3d5408SPeter Wemm 
11915589c42SPeter Wemm     fprintf(stderr, "Usage: %s %s\n", _nc_progname, usage_string);
12018259542SPeter Wemm     for (j = 0; j < SIZEOF(tbl); j++) {
12115589c42SPeter Wemm 	fputs(tbl[j], stderr);
12215589c42SPeter Wemm 	putc('\n', stderr);
12315589c42SPeter Wemm     }
1240e3d5408SPeter Wemm     exit(EXIT_FAILURE);
1250e3d5408SPeter Wemm }
1260e3d5408SPeter Wemm 
1270e3d5408SPeter Wemm #define L_BRACE '{'
1280e3d5408SPeter Wemm #define R_BRACE '}'
1290e3d5408SPeter Wemm #define S_QUOTE '\'';
1300e3d5408SPeter Wemm 
13115589c42SPeter Wemm static void
13215589c42SPeter Wemm write_it(ENTRY * ep)
1330e3d5408SPeter Wemm {
1340e3d5408SPeter Wemm     unsigned n;
1350e3d5408SPeter Wemm     int ch;
1360e3d5408SPeter Wemm     char *s, *d, *t;
1370e3d5408SPeter Wemm     char result[MAX_ENTRY_SIZE];
1380e3d5408SPeter Wemm 
1390e3d5408SPeter Wemm     /*
1400e3d5408SPeter Wemm      * Look for strings that contain %{number}, convert them to %'char',
1410e3d5408SPeter Wemm      * which is shorter and runs a little faster.
1420e3d5408SPeter Wemm      */
1430e3d5408SPeter Wemm     for (n = 0; n < STRCOUNT; n++) {
1440e3d5408SPeter Wemm 	s = ep->tterm.Strings[n];
1450e3d5408SPeter Wemm 	if (VALID_STRING(s)
1460e3d5408SPeter Wemm 	    && strchr(s, L_BRACE) != 0) {
1470e3d5408SPeter Wemm 	    d = result;
1480e3d5408SPeter Wemm 	    t = s;
1490e3d5408SPeter Wemm 	    while ((ch = *t++) != 0) {
1500e3d5408SPeter Wemm 		*d++ = ch;
1510e3d5408SPeter Wemm 		if (ch == '\\') {
1520e3d5408SPeter Wemm 		    *d++ = *t++;
1530e3d5408SPeter Wemm 		} else if ((ch == '%')
1540e3d5408SPeter Wemm 			   && (*t == L_BRACE)) {
1550e3d5408SPeter Wemm 		    char *v = 0;
1560e3d5408SPeter Wemm 		    long value = strtol(t + 1, &v, 0);
1570e3d5408SPeter Wemm 		    if (v != 0
1580e3d5408SPeter Wemm 			&& *v == R_BRACE
1590e3d5408SPeter Wemm 			&& value > 0
1600e3d5408SPeter Wemm 			&& value != '\\'	/* FIXME */
1610e3d5408SPeter Wemm 			&& value < 127
1620e3d5408SPeter Wemm 			&& isprint((int) value)) {
1630e3d5408SPeter Wemm 			*d++ = S_QUOTE;
1640e3d5408SPeter Wemm 			*d++ = (int) value;
1650e3d5408SPeter Wemm 			*d++ = S_QUOTE;
1660e3d5408SPeter Wemm 			t = (v + 1);
1670e3d5408SPeter Wemm 		    }
1680e3d5408SPeter Wemm 		}
1690e3d5408SPeter Wemm 	    }
1700e3d5408SPeter Wemm 	    *d = 0;
1710e3d5408SPeter Wemm 	    if (strlen(result) < strlen(s))
1720e3d5408SPeter Wemm 		strcpy(s, result);
1730e3d5408SPeter Wemm 	}
1740e3d5408SPeter Wemm     }
1750e3d5408SPeter Wemm 
1760e3d5408SPeter Wemm     _nc_set_type(_nc_first_name(ep->tterm.term_names));
1770e3d5408SPeter Wemm     _nc_curr_line = ep->startline;
1780e3d5408SPeter Wemm     _nc_write_entry(&ep->tterm);
1790e3d5408SPeter Wemm }
1800e3d5408SPeter Wemm 
18115589c42SPeter Wemm static bool
18215589c42SPeter Wemm immedhook(ENTRY * ep GCC_UNUSED)
1830e3d5408SPeter Wemm /* write out entries with no use capabilities immediately to save storage */
1840e3d5408SPeter Wemm {
18518259542SPeter Wemm #if !HAVE_BIG_CORE
1860e3d5408SPeter Wemm     /*
1870e3d5408SPeter Wemm      * This is strictly a core-economy kluge.  The really clean way to handle
1880e3d5408SPeter Wemm      * compilation is to slurp the whole file into core and then do all the
1890e3d5408SPeter Wemm      * name-collision checks and entry writes in one swell foop.  But the
1900e3d5408SPeter Wemm      * terminfo master file is large enough that some core-poor systems swap
1910e3d5408SPeter Wemm      * like crazy when you compile it this way...there have been reports of
1920e3d5408SPeter Wemm      * this process taking *three hours*, rather than the twenty seconds or
1930e3d5408SPeter Wemm      * less typical on my development box.
1940e3d5408SPeter Wemm      *
1950e3d5408SPeter Wemm      * So.  This hook *immediately* writes out the referenced entry if it
1960e3d5408SPeter Wemm      * has no use capabilities.  The compiler main loop refrains from
1970e3d5408SPeter Wemm      * adding the entry to the in-core list when this hook fires.  If some
1980e3d5408SPeter Wemm      * other entry later needs to reference an entry that got written
1990e3d5408SPeter Wemm      * immediately, that's OK; the resolution code will fetch it off disk
2000e3d5408SPeter Wemm      * when it can't find it in core.
2010e3d5408SPeter Wemm      *
2020e3d5408SPeter Wemm      * Name collisions will still be detected, just not as cleanly.  The
2030e3d5408SPeter Wemm      * write_entry() code complains before overwriting an entry that
2040e3d5408SPeter Wemm      * postdates the time of tic's first call to write_entry().  Thus
2050e3d5408SPeter Wemm      * it will complain about overwriting entries newly made during the
2060e3d5408SPeter Wemm      * tic run, but not about overwriting ones that predate it.
2070e3d5408SPeter Wemm      *
2080e3d5408SPeter Wemm      * The reason this is a hook, and not in line with the rest of the
2090e3d5408SPeter Wemm      * compiler code, is that the support for termcap fallback cannot assume
2100e3d5408SPeter Wemm      * it has anywhere to spool out these entries!
2110e3d5408SPeter Wemm      *
2120e3d5408SPeter Wemm      * The _nc_set_type() call here requires a compensating one in
2130e3d5408SPeter Wemm      * _nc_parse_entry().
2140e3d5408SPeter Wemm      *
2150e3d5408SPeter Wemm      * If you define HAVE_BIG_CORE, you'll disable this kluge.  This will
2160e3d5408SPeter Wemm      * make tic a bit faster (because the resolution code won't have to do
2170e3d5408SPeter Wemm      * disk I/O nearly as often).
2180e3d5408SPeter Wemm      */
21915589c42SPeter Wemm     if (ep->nuses == 0) {
2200e3d5408SPeter Wemm 	int oldline = _nc_curr_line;
2210e3d5408SPeter Wemm 
2220e3d5408SPeter Wemm 	write_it(ep);
2230e3d5408SPeter Wemm 	_nc_curr_line = oldline;
2240e3d5408SPeter Wemm 	free(ep->tterm.str_table);
2250e3d5408SPeter Wemm 	return (TRUE);
2260e3d5408SPeter Wemm     }
2270e3d5408SPeter Wemm #endif /* HAVE_BIG_CORE */
2280e3d5408SPeter Wemm     return (FALSE);
2290e3d5408SPeter Wemm }
2300e3d5408SPeter Wemm 
23115589c42SPeter Wemm static void
23215589c42SPeter Wemm put_translate(int c)
2330e3d5408SPeter Wemm /* emit a comment char, translating terminfo names to termcap names */
2340e3d5408SPeter Wemm {
2350e3d5408SPeter Wemm     static bool in_name = FALSE;
23615589c42SPeter Wemm     static size_t have, used;
23715589c42SPeter Wemm     static char *namebuf, *suffix;
2380e3d5408SPeter Wemm 
23915589c42SPeter Wemm     if (in_name) {
24015589c42SPeter Wemm 	if (used + 1 >= have) {
24115589c42SPeter Wemm 	    have += 132;
24215589c42SPeter Wemm 	    namebuf = typeRealloc(char, have, namebuf);
24315589c42SPeter Wemm 	    suffix = typeRealloc(char, have, suffix);
2440e3d5408SPeter Wemm 	}
24515589c42SPeter Wemm 	if (c == '\n' || c == '@') {
24615589c42SPeter Wemm 	    namebuf[used++] = '\0';
2470e3d5408SPeter Wemm 	    (void) putchar('<');
2480e3d5408SPeter Wemm 	    (void) fputs(namebuf, stdout);
2490e3d5408SPeter Wemm 	    putchar(c);
2500e3d5408SPeter Wemm 	    in_name = FALSE;
25115589c42SPeter Wemm 	} else if (c != '>') {
25215589c42SPeter Wemm 	    namebuf[used++] = c;
25315589c42SPeter Wemm 	} else {		/* ah! candidate name! */
2540e3d5408SPeter Wemm 	    char *up;
2550e3d5408SPeter Wemm 	    NCURSES_CONST char *tp;
2560e3d5408SPeter Wemm 
25715589c42SPeter Wemm 	    namebuf[used++] = '\0';
2580e3d5408SPeter Wemm 	    in_name = FALSE;
2590e3d5408SPeter Wemm 
2600e3d5408SPeter Wemm 	    suffix[0] = '\0';
2610e3d5408SPeter Wemm 	    if ((up = strchr(namebuf, '#')) != 0
2620e3d5408SPeter Wemm 		|| (up = strchr(namebuf, '=')) != 0
26315589c42SPeter Wemm 		|| ((up = strchr(namebuf, '@')) != 0 && up[1] == '>')) {
2640e3d5408SPeter Wemm 		(void) strcpy(suffix, up);
2650e3d5408SPeter Wemm 		*up = '\0';
2660e3d5408SPeter Wemm 	    }
2670e3d5408SPeter Wemm 
26815589c42SPeter Wemm 	    if ((tp = nametrans(namebuf)) != 0) {
2690e3d5408SPeter Wemm 		(void) putchar(':');
2700e3d5408SPeter Wemm 		(void) fputs(tp, stdout);
2710e3d5408SPeter Wemm 		(void) fputs(suffix, stdout);
2720e3d5408SPeter Wemm 		(void) putchar(':');
27315589c42SPeter Wemm 	    } else {
2740e3d5408SPeter Wemm 		/* couldn't find a translation, just dump the name */
2750e3d5408SPeter Wemm 		(void) putchar('<');
2760e3d5408SPeter Wemm 		(void) fputs(namebuf, stdout);
2770e3d5408SPeter Wemm 		(void) fputs(suffix, stdout);
2780e3d5408SPeter Wemm 		(void) putchar('>');
2790e3d5408SPeter Wemm 	    }
28015589c42SPeter Wemm 	}
28115589c42SPeter Wemm     } else {
28215589c42SPeter Wemm 	used = 0;
28315589c42SPeter Wemm 	if (c == '<') {
28415589c42SPeter Wemm 	    in_name = TRUE;
28515589c42SPeter Wemm 	} else {
28615589c42SPeter Wemm 	    putchar(c);
28715589c42SPeter Wemm 	}
2880e3d5408SPeter Wemm     }
2890e3d5408SPeter Wemm }
2900e3d5408SPeter Wemm 
2910e3d5408SPeter Wemm /* Returns a string, stripped of leading/trailing whitespace */
29215589c42SPeter Wemm static char *
29315589c42SPeter Wemm stripped(char *src)
2940e3d5408SPeter Wemm {
2950e3d5408SPeter Wemm     while (isspace(*src))
2960e3d5408SPeter Wemm 	src++;
2970e3d5408SPeter Wemm     if (*src != '\0') {
2980e3d5408SPeter Wemm 	char *dst = strcpy(malloc(strlen(src) + 1), src);
2990e3d5408SPeter Wemm 	size_t len = strlen(dst);
3000e3d5408SPeter Wemm 	while (--len != 0 && isspace(dst[len]))
3010e3d5408SPeter Wemm 	    dst[len] = '\0';
3020e3d5408SPeter Wemm 	return dst;
3030e3d5408SPeter Wemm     }
3040e3d5408SPeter Wemm     return 0;
3050e3d5408SPeter Wemm }
3060e3d5408SPeter Wemm 
30718259542SPeter Wemm static FILE *
30818259542SPeter Wemm open_input(const char *filename)
30918259542SPeter Wemm {
31018259542SPeter Wemm     FILE *fp = fopen(filename, "r");
31118259542SPeter Wemm     struct stat sb;
31218259542SPeter Wemm 
31318259542SPeter Wemm     if (fp == 0) {
31418259542SPeter Wemm 	fprintf(stderr, "%s: Can't open %s\n", _nc_progname, filename);
31518259542SPeter Wemm 	exit(EXIT_FAILURE);
31618259542SPeter Wemm     }
31718259542SPeter Wemm     if (fstat(fileno(fp), &sb) < 0
31818259542SPeter Wemm 	|| (sb.st_mode & S_IFMT) != S_IFREG) {
31918259542SPeter Wemm 	fprintf(stderr, "%s: %s is not a file\n", _nc_progname, filename);
32018259542SPeter Wemm 	exit(EXIT_FAILURE);
32118259542SPeter Wemm     }
32218259542SPeter Wemm     return fp;
32318259542SPeter Wemm }
32418259542SPeter Wemm 
3250e3d5408SPeter Wemm /* Parse the "-e" option-value into a list of names */
32615589c42SPeter Wemm static const char **
32715589c42SPeter Wemm make_namelist(char *src)
3280e3d5408SPeter Wemm {
3290e3d5408SPeter Wemm     const char **dst = 0;
3300e3d5408SPeter Wemm 
3310e3d5408SPeter Wemm     char *s, *base;
3320e3d5408SPeter Wemm     unsigned pass, n, nn;
3330e3d5408SPeter Wemm     char buffer[BUFSIZ];
3340e3d5408SPeter Wemm 
3350e3d5408SPeter Wemm     if (src == 0) {
3360e3d5408SPeter Wemm 	/* EMPTY */ ;
3370e3d5408SPeter Wemm     } else if (strchr(src, '/') != 0) {		/* a filename */
33818259542SPeter Wemm 	FILE *fp = open_input(src);
3390e3d5408SPeter Wemm 
3400e3d5408SPeter Wemm 	for (pass = 1; pass <= 2; pass++) {
3410e3d5408SPeter Wemm 	    nn = 0;
3420e3d5408SPeter Wemm 	    while (fgets(buffer, sizeof(buffer), fp) != 0) {
3430e3d5408SPeter Wemm 		if ((s = stripped(buffer)) != 0) {
3440e3d5408SPeter Wemm 		    if (dst != 0)
3450e3d5408SPeter Wemm 			dst[nn] = s;
3460e3d5408SPeter Wemm 		    nn++;
3470e3d5408SPeter Wemm 		}
3480e3d5408SPeter Wemm 	    }
3490e3d5408SPeter Wemm 	    if (pass == 1) {
35015589c42SPeter Wemm 		dst = typeCalloc(const char *, nn + 1);
3510e3d5408SPeter Wemm 		rewind(fp);
3520e3d5408SPeter Wemm 	    }
3530e3d5408SPeter Wemm 	}
3540e3d5408SPeter Wemm 	fclose(fp);
3550e3d5408SPeter Wemm     } else {			/* literal list of names */
3560e3d5408SPeter Wemm 	for (pass = 1; pass <= 2; pass++) {
3570e3d5408SPeter Wemm 	    for (n = nn = 0, base = src;; n++) {
3580e3d5408SPeter Wemm 		int mark = src[n];
3590e3d5408SPeter Wemm 		if (mark == ',' || mark == '\0') {
3600e3d5408SPeter Wemm 		    if (pass == 1) {
3610e3d5408SPeter Wemm 			nn++;
3620e3d5408SPeter Wemm 		    } else {
3630e3d5408SPeter Wemm 			src[n] = '\0';
3640e3d5408SPeter Wemm 			if ((s = stripped(base)) != 0)
3650e3d5408SPeter Wemm 			    dst[nn++] = s;
3660e3d5408SPeter Wemm 			base = &src[n + 1];
3670e3d5408SPeter Wemm 		    }
3680e3d5408SPeter Wemm 		}
3690e3d5408SPeter Wemm 		if (mark == '\0')
3700e3d5408SPeter Wemm 		    break;
3710e3d5408SPeter Wemm 	    }
3720e3d5408SPeter Wemm 	    if (pass == 1)
37315589c42SPeter Wemm 		dst = typeCalloc(const char *, nn + 1);
3740e3d5408SPeter Wemm 	}
3750e3d5408SPeter Wemm     }
3760e3d5408SPeter Wemm     if (showsummary) {
3770e3d5408SPeter Wemm 	fprintf(log_fp, "Entries that will be compiled:\n");
3780e3d5408SPeter Wemm 	for (n = 0; dst[n] != 0; n++)
3790e3d5408SPeter Wemm 	    fprintf(log_fp, "%d:%s\n", n + 1, dst[n]);
3800e3d5408SPeter Wemm     }
3810e3d5408SPeter Wemm     return dst;
3820e3d5408SPeter Wemm }
3830e3d5408SPeter Wemm 
38415589c42SPeter Wemm static bool
38515589c42SPeter Wemm matches(const char **needle, const char *haystack)
3860e3d5408SPeter Wemm /* does entry in needle list match |-separated field in haystack? */
3870e3d5408SPeter Wemm {
3880e3d5408SPeter Wemm     bool code = FALSE;
3890e3d5408SPeter Wemm     size_t n;
3900e3d5408SPeter Wemm 
39115589c42SPeter Wemm     if (needle != 0) {
39215589c42SPeter Wemm 	for (n = 0; needle[n] != 0; n++) {
39315589c42SPeter Wemm 	    if (_nc_name_match(haystack, needle[n], "|")) {
3940e3d5408SPeter Wemm 		code = TRUE;
3950e3d5408SPeter Wemm 		break;
3960e3d5408SPeter Wemm 	    }
3970e3d5408SPeter Wemm 	}
39815589c42SPeter Wemm     } else
3990e3d5408SPeter Wemm 	code = TRUE;
4000e3d5408SPeter Wemm     return (code);
4010e3d5408SPeter Wemm }
4020e3d5408SPeter Wemm 
40315589c42SPeter Wemm static FILE *
40415589c42SPeter Wemm open_tempfile(char *name)
40515589c42SPeter Wemm {
40615589c42SPeter Wemm     FILE *result = 0;
40715589c42SPeter Wemm #if HAVE_MKSTEMP
40815589c42SPeter Wemm     int fd = mkstemp(name);
40915589c42SPeter Wemm     if (fd >= 0)
41015589c42SPeter Wemm 	result = fdopen(fd, "w");
41115589c42SPeter Wemm #else
41215589c42SPeter Wemm     if (tmpnam(name) != 0)
41315589c42SPeter Wemm 	result = fopen(name, "w");
41415589c42SPeter Wemm #endif
41515589c42SPeter Wemm     return result;
41615589c42SPeter Wemm }
41715589c42SPeter Wemm 
41815589c42SPeter Wemm int
41915589c42SPeter Wemm main(int argc, char *argv[])
4200e3d5408SPeter Wemm {
4210e3d5408SPeter Wemm     char my_tmpname[PATH_MAX];
4220e3d5408SPeter Wemm     int v_opt = -1, debug_level;
4230e3d5408SPeter Wemm     int smart_defaults = TRUE;
4240e3d5408SPeter Wemm     char *termcap;
4250e3d5408SPeter Wemm     ENTRY *qp;
4260e3d5408SPeter Wemm 
4270e3d5408SPeter Wemm     int this_opt, last_opt = '?';
4280e3d5408SPeter Wemm 
4290e3d5408SPeter Wemm     int outform = F_TERMINFO;	/* output format */
4300e3d5408SPeter Wemm     int sortmode = S_TERMINFO;	/* sort_mode */
4310e3d5408SPeter Wemm 
4320e3d5408SPeter Wemm     int width = 60;
4330e3d5408SPeter Wemm     bool formatted = FALSE;	/* reformat complex strings? */
4340e3d5408SPeter Wemm     int numbers = 0;		/* format "%'char'" to/from "%{number}" */
4350e3d5408SPeter Wemm     bool infodump = FALSE;	/* running as captoinfo? */
4360e3d5408SPeter Wemm     bool capdump = FALSE;	/* running as infotocap? */
4370e3d5408SPeter Wemm     bool forceresolve = FALSE;	/* force resolution */
4380e3d5408SPeter Wemm     bool limited = TRUE;
4390e3d5408SPeter Wemm     char *tversion = (char *) NULL;
4400e3d5408SPeter Wemm     const char *source_file = "terminfo";
4410e3d5408SPeter Wemm     const char **namelst = 0;
4420e3d5408SPeter Wemm     char *outdir = (char *) NULL;
4430e3d5408SPeter Wemm     bool check_only = FALSE;
4440e3d5408SPeter Wemm 
4450e3d5408SPeter Wemm     log_fp = stderr;
4460e3d5408SPeter Wemm 
44718259542SPeter Wemm     _nc_progname = _nc_basename(argv[0]);
4480e3d5408SPeter Wemm 
44918259542SPeter Wemm     if ((infodump = (strcmp(_nc_progname, PROG_CAPTOINFO) == 0)) != FALSE) {
45015589c42SPeter Wemm 	outform = F_TERMINFO;
45115589c42SPeter Wemm 	sortmode = S_TERMINFO;
45215589c42SPeter Wemm     }
45318259542SPeter Wemm     if ((capdump = (strcmp(_nc_progname, PROG_INFOTOCAP) == 0)) != FALSE) {
45415589c42SPeter Wemm 	outform = F_TERMCAP;
45515589c42SPeter Wemm 	sortmode = S_TERMCAP;
45615589c42SPeter Wemm     }
4570e3d5408SPeter Wemm #if NCURSES_XNAMES
4580e3d5408SPeter Wemm     use_extended_names(FALSE);
4590e3d5408SPeter Wemm #endif
4600e3d5408SPeter Wemm 
4610e3d5408SPeter Wemm     /*
4620e3d5408SPeter Wemm      * Processing arguments is a little complicated, since someone made a
4630e3d5408SPeter Wemm      * design decision to allow the numeric values for -w, -v options to
4640e3d5408SPeter Wemm      * be optional.
4650e3d5408SPeter Wemm      */
46615589c42SPeter Wemm     while ((this_opt = getopt(argc, argv,
46715589c42SPeter Wemm 			      "0123456789CILNR:TVace:fGgo:rsvwx")) != EOF) {
4680e3d5408SPeter Wemm 	if (isdigit(this_opt)) {
4690e3d5408SPeter Wemm 	    switch (last_opt) {
4700e3d5408SPeter Wemm 	    case 'v':
4710e3d5408SPeter Wemm 		v_opt = (v_opt * 10) + (this_opt - '0');
4720e3d5408SPeter Wemm 		break;
4730e3d5408SPeter Wemm 	    case 'w':
4740e3d5408SPeter Wemm 		width = (width * 10) + (this_opt - '0');
4750e3d5408SPeter Wemm 		break;
4760e3d5408SPeter Wemm 	    default:
4770e3d5408SPeter Wemm 		if (this_opt != '1')
4780e3d5408SPeter Wemm 		    usage();
4790e3d5408SPeter Wemm 		last_opt = this_opt;
4800e3d5408SPeter Wemm 		width = 0;
4810e3d5408SPeter Wemm 	    }
4820e3d5408SPeter Wemm 	    continue;
4830e3d5408SPeter Wemm 	}
4840e3d5408SPeter Wemm 	switch (this_opt) {
4850e3d5408SPeter Wemm 	case 'C':
4860e3d5408SPeter Wemm 	    capdump = TRUE;
4870e3d5408SPeter Wemm 	    outform = F_TERMCAP;
4880e3d5408SPeter Wemm 	    sortmode = S_TERMCAP;
4890e3d5408SPeter Wemm 	    break;
4900e3d5408SPeter Wemm 	case 'I':
4910e3d5408SPeter Wemm 	    infodump = TRUE;
4920e3d5408SPeter Wemm 	    outform = F_TERMINFO;
4930e3d5408SPeter Wemm 	    sortmode = S_TERMINFO;
4940e3d5408SPeter Wemm 	    break;
4950e3d5408SPeter Wemm 	case 'L':
4960e3d5408SPeter Wemm 	    infodump = TRUE;
4970e3d5408SPeter Wemm 	    outform = F_VARIABLE;
4980e3d5408SPeter Wemm 	    sortmode = S_VARIABLE;
4990e3d5408SPeter Wemm 	    break;
5000e3d5408SPeter Wemm 	case 'N':
5010e3d5408SPeter Wemm 	    smart_defaults = FALSE;
5020e3d5408SPeter Wemm 	    break;
5030e3d5408SPeter Wemm 	case 'R':
5040e3d5408SPeter Wemm 	    tversion = optarg;
5050e3d5408SPeter Wemm 	    break;
5060e3d5408SPeter Wemm 	case 'T':
5070e3d5408SPeter Wemm 	    limited = FALSE;
5080e3d5408SPeter Wemm 	    break;
5090e3d5408SPeter Wemm 	case 'V':
51018259542SPeter Wemm 	    puts(curses_version());
5110e3d5408SPeter Wemm 	    return EXIT_SUCCESS;
5120e3d5408SPeter Wemm 	case 'c':
5130e3d5408SPeter Wemm 	    check_only = TRUE;
5140e3d5408SPeter Wemm 	    break;
5150e3d5408SPeter Wemm 	case 'e':
5160e3d5408SPeter Wemm 	    namelst = make_namelist(optarg);
5170e3d5408SPeter Wemm 	    break;
5180e3d5408SPeter Wemm 	case 'f':
5190e3d5408SPeter Wemm 	    formatted = TRUE;
5200e3d5408SPeter Wemm 	    break;
5210e3d5408SPeter Wemm 	case 'G':
5220e3d5408SPeter Wemm 	    numbers = 1;
5230e3d5408SPeter Wemm 	    break;
5240e3d5408SPeter Wemm 	case 'g':
5250e3d5408SPeter Wemm 	    numbers = -1;
5260e3d5408SPeter Wemm 	    break;
5270e3d5408SPeter Wemm 	case 'o':
5280e3d5408SPeter Wemm 	    outdir = optarg;
5290e3d5408SPeter Wemm 	    break;
5300e3d5408SPeter Wemm 	case 'r':
5310e3d5408SPeter Wemm 	    forceresolve = TRUE;
5320e3d5408SPeter Wemm 	    break;
5330e3d5408SPeter Wemm 	case 's':
5340e3d5408SPeter Wemm 	    showsummary = TRUE;
5350e3d5408SPeter Wemm 	    break;
5360e3d5408SPeter Wemm 	case 'v':
5370e3d5408SPeter Wemm 	    v_opt = 0;
5380e3d5408SPeter Wemm 	    break;
5390e3d5408SPeter Wemm 	case 'w':
5400e3d5408SPeter Wemm 	    width = 0;
5410e3d5408SPeter Wemm 	    break;
5420e3d5408SPeter Wemm #if NCURSES_XNAMES
54315589c42SPeter Wemm 	case 'a':
54415589c42SPeter Wemm 	    _nc_disable_period = TRUE;
54515589c42SPeter Wemm 	    /* FALLTHRU */
5460e3d5408SPeter Wemm 	case 'x':
5470e3d5408SPeter Wemm 	    use_extended_names(TRUE);
5480e3d5408SPeter Wemm 	    break;
5490e3d5408SPeter Wemm #endif
5500e3d5408SPeter Wemm 	default:
5510e3d5408SPeter Wemm 	    usage();
5520e3d5408SPeter Wemm 	}
5530e3d5408SPeter Wemm 	last_opt = this_opt;
5540e3d5408SPeter Wemm     }
5550e3d5408SPeter Wemm 
5560e3d5408SPeter Wemm     debug_level = (v_opt > 0) ? v_opt : (v_opt == 0);
55715589c42SPeter Wemm     set_trace_level(debug_level);
5580e3d5408SPeter Wemm 
55915589c42SPeter Wemm     if (_nc_tracing) {
5600e3d5408SPeter Wemm 	save_check_termtype = _nc_check_termtype;
5610e3d5408SPeter Wemm 	_nc_check_termtype = check_termtype;
5620e3d5408SPeter Wemm     }
56318259542SPeter Wemm #if !HAVE_BIG_CORE
5640e3d5408SPeter Wemm     /*
5650e3d5408SPeter Wemm      * Aaargh! immedhook seriously hoses us!
5660e3d5408SPeter Wemm      *
5670e3d5408SPeter Wemm      * One problem with immedhook is it means we can't do -e.  Problem
5680e3d5408SPeter Wemm      * is that we can't guarantee that for each terminal listed, all the
5690e3d5408SPeter Wemm      * terminals it depends on will have been kept in core for reference
5700e3d5408SPeter Wemm      * resolution -- in fact it's certain the primitive types at the end
5710e3d5408SPeter Wemm      * of reference chains *won't* be in core unless they were explicitly
5720e3d5408SPeter Wemm      * in the select list themselves.
5730e3d5408SPeter Wemm      */
57415589c42SPeter Wemm     if (namelst && (!infodump && !capdump)) {
5750e3d5408SPeter Wemm 	(void) fprintf(stderr,
5760e3d5408SPeter Wemm 		       "Sorry, -e can't be used without -I or -C\n");
5770e3d5408SPeter Wemm 	cleanup();
5780e3d5408SPeter Wemm 	return EXIT_FAILURE;
5790e3d5408SPeter Wemm     }
5800e3d5408SPeter Wemm #endif /* HAVE_BIG_CORE */
5810e3d5408SPeter Wemm 
5820e3d5408SPeter Wemm     if (optind < argc) {
5830e3d5408SPeter Wemm 	source_file = argv[optind++];
5840e3d5408SPeter Wemm 	if (optind < argc) {
5850e3d5408SPeter Wemm 	    fprintf(stderr,
5860e3d5408SPeter Wemm 		    "%s: Too many file names.  Usage:\n\t%s %s",
5870e3d5408SPeter Wemm 		    _nc_progname,
5880e3d5408SPeter Wemm 		    _nc_progname,
5890e3d5408SPeter Wemm 		    usage_string);
5900e3d5408SPeter Wemm 	    return EXIT_FAILURE;
5910e3d5408SPeter Wemm 	}
5920e3d5408SPeter Wemm     } else {
5930e3d5408SPeter Wemm 	if (infodump == TRUE) {
5940e3d5408SPeter Wemm 	    /* captoinfo's no-argument case */
5950e3d5408SPeter Wemm 	    source_file = "/etc/termcap";
5960e3d5408SPeter Wemm 	    if ((termcap = getenv("TERMCAP")) != 0
5970e3d5408SPeter Wemm 		&& (namelst = make_namelist(getenv("TERM"))) != 0) {
5980e3d5408SPeter Wemm 		if (access(termcap, F_OK) == 0) {
5990e3d5408SPeter Wemm 		    /* file exists */
6000e3d5408SPeter Wemm 		    source_file = termcap;
60118259542SPeter Wemm 		} else if ((tmp_fp = open_tempfile(strcpy(my_tmpname,
60218259542SPeter Wemm 							  "/tmp/XXXXXX")))
60318259542SPeter Wemm 			   != 0) {
60415589c42SPeter Wemm 		    source_file = my_tmpname;
6050e3d5408SPeter Wemm 		    fprintf(tmp_fp, "%s\n", termcap);
6060e3d5408SPeter Wemm 		    fclose(tmp_fp);
60718259542SPeter Wemm 		    tmp_fp = open_input(source_file);
6080e3d5408SPeter Wemm 		    to_remove = source_file;
6090e3d5408SPeter Wemm 		} else {
6100e3d5408SPeter Wemm 		    failed("tmpnam");
6110e3d5408SPeter Wemm 		}
6120e3d5408SPeter Wemm 	    }
6130e3d5408SPeter Wemm 	} else {
6140e3d5408SPeter Wemm 	    /* tic */
6150e3d5408SPeter Wemm 	    fprintf(stderr,
6160e3d5408SPeter Wemm 		    "%s: File name needed.  Usage:\n\t%s %s",
6170e3d5408SPeter Wemm 		    _nc_progname,
6180e3d5408SPeter Wemm 		    _nc_progname,
6190e3d5408SPeter Wemm 		    usage_string);
6200e3d5408SPeter Wemm 	    cleanup();
6210e3d5408SPeter Wemm 	    return EXIT_FAILURE;
6220e3d5408SPeter Wemm 	}
6230e3d5408SPeter Wemm     }
6240e3d5408SPeter Wemm 
62518259542SPeter Wemm     if (tmp_fp == 0)
62618259542SPeter Wemm 	tmp_fp = open_input(source_file);
6270e3d5408SPeter Wemm 
6280e3d5408SPeter Wemm     if (infodump)
6290e3d5408SPeter Wemm 	dump_init(tversion,
6300e3d5408SPeter Wemm 		  smart_defaults
6310e3d5408SPeter Wemm 		  ? outform
6320e3d5408SPeter Wemm 		  : F_LITERAL,
6330e3d5408SPeter Wemm 		  sortmode, width, debug_level, formatted);
6340e3d5408SPeter Wemm     else if (capdump)
6350e3d5408SPeter Wemm 	dump_init(tversion,
6360e3d5408SPeter Wemm 		  outform,
6370e3d5408SPeter Wemm 		  sortmode, width, debug_level, FALSE);
6380e3d5408SPeter Wemm 
6390e3d5408SPeter Wemm     /* parse entries out of the source file */
6400e3d5408SPeter Wemm     _nc_set_source(source_file);
64118259542SPeter Wemm #if !HAVE_BIG_CORE
6420e3d5408SPeter Wemm     if (!(check_only || infodump || capdump))
6430e3d5408SPeter Wemm 	_nc_set_writedir(outdir);
6440e3d5408SPeter Wemm #endif /* HAVE_BIG_CORE */
6450e3d5408SPeter Wemm     _nc_read_entry_source(tmp_fp, (char *) NULL,
6460e3d5408SPeter Wemm 			  !smart_defaults, FALSE,
6470e3d5408SPeter Wemm 			  (check_only || infodump || capdump) ? NULLHOOK : immedhook);
6480e3d5408SPeter Wemm 
6490e3d5408SPeter Wemm     /* do use resolution */
6500e3d5408SPeter Wemm     if (check_only || (!infodump && !capdump) || forceresolve) {
65115589c42SPeter Wemm 	if (!_nc_resolve_uses(TRUE) && !check_only) {
6520e3d5408SPeter Wemm 	    cleanup();
6530e3d5408SPeter Wemm 	    return EXIT_FAILURE;
6540e3d5408SPeter Wemm 	}
6550e3d5408SPeter Wemm     }
6560e3d5408SPeter Wemm 
6570e3d5408SPeter Wemm     /* length check */
65815589c42SPeter Wemm     if (check_only && (capdump || infodump)) {
65915589c42SPeter Wemm 	for_entry_list(qp) {
66015589c42SPeter Wemm 	    if (matches(namelst, qp->tterm.term_names)) {
6610e3d5408SPeter Wemm 		int len = fmt_entry(&qp->tterm, NULL, TRUE, infodump, numbers);
6620e3d5408SPeter Wemm 
6630e3d5408SPeter Wemm 		if (len > (infodump ? MAX_TERMINFO_LENGTH : MAX_TERMCAP_LENGTH))
6640e3d5408SPeter Wemm 		    (void) fprintf(stderr,
6650e3d5408SPeter Wemm 				   "warning: resolved %s entry is %d bytes long\n",
6660e3d5408SPeter Wemm 				   _nc_first_name(qp->tterm.term_names),
6670e3d5408SPeter Wemm 				   len);
6680e3d5408SPeter Wemm 	    }
6690e3d5408SPeter Wemm 	}
6700e3d5408SPeter Wemm     }
6710e3d5408SPeter Wemm 
6720e3d5408SPeter Wemm     /* write or dump all entries */
67315589c42SPeter Wemm     if (!check_only) {
67415589c42SPeter Wemm 	if (!infodump && !capdump) {
6750e3d5408SPeter Wemm 	    _nc_set_writedir(outdir);
67615589c42SPeter Wemm 	    for_entry_list(qp) {
6770e3d5408SPeter Wemm 		if (matches(namelst, qp->tterm.term_names))
6780e3d5408SPeter Wemm 		    write_it(qp);
6790e3d5408SPeter Wemm 	    }
68015589c42SPeter Wemm 	} else {
6810e3d5408SPeter Wemm 	    /* this is in case infotocap() generates warnings */
6820e3d5408SPeter Wemm 	    _nc_curr_col = _nc_curr_line = -1;
6830e3d5408SPeter Wemm 
68415589c42SPeter Wemm 	    for_entry_list(qp) {
68515589c42SPeter Wemm 		if (matches(namelst, qp->tterm.term_names)) {
6860e3d5408SPeter Wemm 		    int j = qp->cend - qp->cstart;
6870e3d5408SPeter Wemm 		    int len = 0;
6880e3d5408SPeter Wemm 
6890e3d5408SPeter Wemm 		    /* this is in case infotocap() generates warnings */
6900e3d5408SPeter Wemm 		    _nc_set_type(_nc_first_name(qp->tterm.term_names));
6910e3d5408SPeter Wemm 
6920e3d5408SPeter Wemm 		    (void) fseek(tmp_fp, qp->cstart, SEEK_SET);
69315589c42SPeter Wemm 		    while (j--) {
6940e3d5408SPeter Wemm 			if (infodump)
6950e3d5408SPeter Wemm 			    (void) putchar(fgetc(tmp_fp));
6960e3d5408SPeter Wemm 			else
6970e3d5408SPeter Wemm 			    put_translate(fgetc(tmp_fp));
69815589c42SPeter Wemm 		    }
6990e3d5408SPeter Wemm 
7000e3d5408SPeter Wemm 		    len = dump_entry(&qp->tterm, limited, numbers, NULL);
7010e3d5408SPeter Wemm 		    for (j = 0; j < qp->nuses; j++)
70215589c42SPeter Wemm 			len += dump_uses(qp->uses[j].name, !capdump);
7030e3d5408SPeter Wemm 		    (void) putchar('\n');
7040e3d5408SPeter Wemm 		    if (debug_level != 0 && !limited)
7050e3d5408SPeter Wemm 			printf("# length=%d\n", len);
7060e3d5408SPeter Wemm 		}
70715589c42SPeter Wemm 	    }
70815589c42SPeter Wemm 	    if (!namelst) {
7090e3d5408SPeter Wemm 		int c, oldc = '\0';
7100e3d5408SPeter Wemm 		bool in_comment = FALSE;
7110e3d5408SPeter Wemm 		bool trailing_comment = FALSE;
7120e3d5408SPeter Wemm 
7130e3d5408SPeter Wemm 		(void) fseek(tmp_fp, _nc_tail->cend, SEEK_SET);
71415589c42SPeter Wemm 		while ((c = fgetc(tmp_fp)) != EOF) {
7150e3d5408SPeter Wemm 		    if (oldc == '\n') {
7160e3d5408SPeter Wemm 			if (c == '#') {
7170e3d5408SPeter Wemm 			    trailing_comment = TRUE;
7180e3d5408SPeter Wemm 			    in_comment = TRUE;
7190e3d5408SPeter Wemm 			} else {
7200e3d5408SPeter Wemm 			    in_comment = FALSE;
7210e3d5408SPeter Wemm 			}
7220e3d5408SPeter Wemm 		    }
7230e3d5408SPeter Wemm 		    if (trailing_comment
7240e3d5408SPeter Wemm 			&& (in_comment || (oldc == '\n' && c == '\n')))
7250e3d5408SPeter Wemm 			putchar(c);
7260e3d5408SPeter Wemm 		    oldc = c;
7270e3d5408SPeter Wemm 		}
7280e3d5408SPeter Wemm 	    }
7290e3d5408SPeter Wemm 	}
7300e3d5408SPeter Wemm     }
7310e3d5408SPeter Wemm 
7320e3d5408SPeter Wemm     /* Show the directory into which entries were written, and the total
7330e3d5408SPeter Wemm      * number of entries
7340e3d5408SPeter Wemm      */
7350e3d5408SPeter Wemm     if (showsummary
7360e3d5408SPeter Wemm 	&& (!(check_only || infodump || capdump))) {
7370e3d5408SPeter Wemm 	int total = _nc_tic_written();
7380e3d5408SPeter Wemm 	if (total != 0)
7390e3d5408SPeter Wemm 	    fprintf(log_fp, "%d entries written to %s\n",
7400e3d5408SPeter Wemm 		    total,
7410e3d5408SPeter Wemm 		    _nc_tic_dir((char *) 0));
7420e3d5408SPeter Wemm 	else
7430e3d5408SPeter Wemm 	    fprintf(log_fp, "No entries written\n");
7440e3d5408SPeter Wemm     }
7450e3d5408SPeter Wemm     cleanup();
7460e3d5408SPeter Wemm     return (EXIT_SUCCESS);
7470e3d5408SPeter Wemm }
7480e3d5408SPeter Wemm 
7490e3d5408SPeter Wemm /*
7500e3d5408SPeter Wemm  * This bit of legerdemain turns all the terminfo variable names into
7510e3d5408SPeter Wemm  * references to locations in the arrays Booleans, Numbers, and Strings ---
7520e3d5408SPeter Wemm  * precisely what's needed (see comp_parse.c).
7530e3d5408SPeter Wemm  */
7540e3d5408SPeter Wemm 
7550e3d5408SPeter Wemm TERMINAL *cur_term;		/* tweak to avoid linking lib_cur_term.c */
7560e3d5408SPeter Wemm 
7570e3d5408SPeter Wemm #undef CUR
7580e3d5408SPeter Wemm #define CUR tp->
7590e3d5408SPeter Wemm 
76015589c42SPeter Wemm /*
76118259542SPeter Wemm  * Returns the expected number of parameters for the given capability.
76218259542SPeter Wemm  */
76318259542SPeter Wemm static int
76418259542SPeter Wemm expected_params(char *name)
76518259542SPeter Wemm {
76618259542SPeter Wemm     /* *INDENT-OFF* */
76718259542SPeter Wemm     static const struct {
76818259542SPeter Wemm 	const char *name;
76918259542SPeter Wemm 	int count;
77018259542SPeter Wemm     } table[] = {
77118259542SPeter Wemm 	{ "birep",		2 },
77218259542SPeter Wemm 	{ "chr",		1 },
77318259542SPeter Wemm 	{ "colornm",		1 },
77418259542SPeter Wemm 	{ "cpi",		1 },
77518259542SPeter Wemm 	{ "csr",		2 },
77618259542SPeter Wemm 	{ "cub",		1 },
77718259542SPeter Wemm 	{ "cud",		1 },
77818259542SPeter Wemm 	{ "cuf",		1 },
77918259542SPeter Wemm 	{ "cup",		2 },
78018259542SPeter Wemm 	{ "cvr",		1 },
78118259542SPeter Wemm 	{ "cuu",		1 },
78218259542SPeter Wemm 	{ "cwin",		5 },
78318259542SPeter Wemm 	{ "dch",		1 },
78418259542SPeter Wemm 	{ "dclk",		2 },
78518259542SPeter Wemm 	{ "dial",		1 },
78618259542SPeter Wemm 	{ "dispc",		1 },
78718259542SPeter Wemm 	{ "dl",			1 },
78818259542SPeter Wemm 	{ "ech",		1 },
78918259542SPeter Wemm 	{ "getm",		1 },
79018259542SPeter Wemm 	{ "hpa",		1 },
79118259542SPeter Wemm 	{ "ich",		1 },
79218259542SPeter Wemm 	{ "il",			1 },
79318259542SPeter Wemm 	{ "indn",		1 },
79418259542SPeter Wemm 	{ "initc",		4 },
79518259542SPeter Wemm 	{ "initp",		7 },
79618259542SPeter Wemm 	{ "lpi",		1 },
79718259542SPeter Wemm 	{ "mc5p",		1 },
79818259542SPeter Wemm 	{ "mrcup",		2 },
79918259542SPeter Wemm 	{ "mvpa",		1 },
80018259542SPeter Wemm 	{ "pfkey",		2 },
80118259542SPeter Wemm 	{ "pfloc",		2 },
80218259542SPeter Wemm 	{ "pfx",		2 },
80318259542SPeter Wemm 	{ "pfxl",		3 },
80418259542SPeter Wemm 	{ "pln",		2 },
80518259542SPeter Wemm 	{ "qdial",		1 },
80618259542SPeter Wemm 	{ "rep",		2 },
80718259542SPeter Wemm 	{ "rin",		1 },
80818259542SPeter Wemm 	{ "sclk",		3 },
80918259542SPeter Wemm 	{ "scp",		1 },
81018259542SPeter Wemm 	{ "scs",		1 },
81118259542SPeter Wemm 	{ "setab",		1 },
81218259542SPeter Wemm 	{ "setaf",		1 },
81318259542SPeter Wemm 	{ "setb",		1 },
81418259542SPeter Wemm 	{ "setcolor",		1 },
81518259542SPeter Wemm 	{ "setf",		1 },
81618259542SPeter Wemm 	{ "sgr",		9 },
81718259542SPeter Wemm 	{ "sgr1",		6 },
81818259542SPeter Wemm 	{ "slength",		1 },
81918259542SPeter Wemm 	{ "slines",		1 },
82018259542SPeter Wemm 	{ "smgbp",		2 },
82118259542SPeter Wemm 	{ "smglp",		2 },
82218259542SPeter Wemm 	{ "smglr",		2 },
82318259542SPeter Wemm 	{ "smgrp",		1 },
82418259542SPeter Wemm 	{ "smgtb",		2 },
82518259542SPeter Wemm 	{ "smgtp",		2 },
82618259542SPeter Wemm 	{ "tsl",		1 },
82718259542SPeter Wemm 	{ "u6",			-1 },
82818259542SPeter Wemm 	{ "vpa",		1 },
82918259542SPeter Wemm 	{ "wind",		4 },
83018259542SPeter Wemm 	{ "wingo",		1 },
83118259542SPeter Wemm     };
83218259542SPeter Wemm     /* *INDENT-ON* */
83318259542SPeter Wemm 
83418259542SPeter Wemm     unsigned n;
83518259542SPeter Wemm     int result = 0;		/* function-keys, etc., use none */
83618259542SPeter Wemm 
83718259542SPeter Wemm     for (n = 0; n < SIZEOF(table); n++) {
83818259542SPeter Wemm 	if (!strcmp(name, table[n].name)) {
83918259542SPeter Wemm 	    result = table[n].count;
84018259542SPeter Wemm 	    break;
84118259542SPeter Wemm 	}
84218259542SPeter Wemm     }
84318259542SPeter Wemm 
84418259542SPeter Wemm     return result;
84518259542SPeter Wemm }
84618259542SPeter Wemm 
84718259542SPeter Wemm /*
84818259542SPeter Wemm  * Make a quick sanity check for the parameters which are used in the given
84918259542SPeter Wemm  * strings.  If there are no "%p" tokens, then there should be no other "%"
85018259542SPeter Wemm  * markers.
85118259542SPeter Wemm  */
85218259542SPeter Wemm static void
85318259542SPeter Wemm check_params(TERMTYPE * tp, char *name, char *value)
85418259542SPeter Wemm {
85518259542SPeter Wemm     int expected = expected_params(name);
85618259542SPeter Wemm     int actual = 0;
85718259542SPeter Wemm     int n;
85818259542SPeter Wemm     bool params[10];
85918259542SPeter Wemm     char *s = value;
86018259542SPeter Wemm 
86118259542SPeter Wemm     for (n = 0; n < 10; n++)
86218259542SPeter Wemm 	params[n] = FALSE;
86318259542SPeter Wemm 
86418259542SPeter Wemm     while (*s != 0) {
86518259542SPeter Wemm 	if (*s == '%') {
86618259542SPeter Wemm 	    if (*++s == '\0') {
86718259542SPeter Wemm 		_nc_warning("expected character after %% in %s", name);
86818259542SPeter Wemm 		break;
86918259542SPeter Wemm 	    } else if (*s == 'p') {
87018259542SPeter Wemm 		if (*++s == '\0' || !isdigit((int) *s)) {
87118259542SPeter Wemm 		    _nc_warning("expected digit after %%p in %s", name);
87218259542SPeter Wemm 		    return;
87318259542SPeter Wemm 		} else {
87418259542SPeter Wemm 		    n = (*s - '0');
87518259542SPeter Wemm 		    if (n > actual)
87618259542SPeter Wemm 			actual = n;
87718259542SPeter Wemm 		    params[n] = TRUE;
87818259542SPeter Wemm 		}
87918259542SPeter Wemm 	    }
88018259542SPeter Wemm 	}
88118259542SPeter Wemm 	s++;
88218259542SPeter Wemm     }
88318259542SPeter Wemm 
88418259542SPeter Wemm     if (params[0]) {
88518259542SPeter Wemm 	_nc_warning("%s refers to parameter 0 (%%p0), which is not allowed", name);
88618259542SPeter Wemm     }
88718259542SPeter Wemm     if (value == set_attributes || expected < 0) {
88818259542SPeter Wemm 	;
88918259542SPeter Wemm     } else if (expected != actual) {
89018259542SPeter Wemm 	_nc_warning("%s uses %d parameters, expected %d", name,
89118259542SPeter Wemm 		    actual, expected);
89218259542SPeter Wemm 	for (n = 1; n < actual; n++) {
89318259542SPeter Wemm 	    if (!params[n])
89418259542SPeter Wemm 		_nc_warning("%s omits parameter %d", name, n);
89518259542SPeter Wemm 	}
89618259542SPeter Wemm     }
89718259542SPeter Wemm }
89818259542SPeter Wemm 
89918259542SPeter Wemm /*
90015589c42SPeter Wemm  * An sgr string may contain several settings other than the one we're
90115589c42SPeter Wemm  * interested in, essentially sgr0 + rmacs + whatever.  As long as the
90215589c42SPeter Wemm  * "whatever" is contained in the sgr string, that is close enough for our
90315589c42SPeter Wemm  * sanity check.
90415589c42SPeter Wemm  */
90515589c42SPeter Wemm static bool
90615589c42SPeter Wemm similar_sgr(char *a, char *b)
90715589c42SPeter Wemm {
90815589c42SPeter Wemm     while (*b != 0) {
90915589c42SPeter Wemm 	while (*a != *b) {
91015589c42SPeter Wemm 	    if (*a == 0)
91115589c42SPeter Wemm 		return FALSE;
91215589c42SPeter Wemm 	    a++;
91315589c42SPeter Wemm 	}
91415589c42SPeter Wemm 	a++;
91515589c42SPeter Wemm 	b++;
91615589c42SPeter Wemm     }
91715589c42SPeter Wemm     return TRUE;
91815589c42SPeter Wemm }
91915589c42SPeter Wemm 
92015589c42SPeter Wemm static void
92115589c42SPeter Wemm check_sgr(TERMTYPE * tp, char *zero, int num, char *cap, const char *name)
92215589c42SPeter Wemm {
92315589c42SPeter Wemm     char *test = tparm(set_attributes,
92415589c42SPeter Wemm 		       num == 1,
92515589c42SPeter Wemm 		       num == 2,
92615589c42SPeter Wemm 		       num == 3,
92715589c42SPeter Wemm 		       num == 4,
92815589c42SPeter Wemm 		       num == 5,
92915589c42SPeter Wemm 		       num == 6,
93015589c42SPeter Wemm 		       num == 7,
93115589c42SPeter Wemm 		       num == 8,
93215589c42SPeter Wemm 		       num == 9);
93315589c42SPeter Wemm     if (test != 0) {
93415589c42SPeter Wemm 	if (PRESENT(cap)) {
93515589c42SPeter Wemm 	    if (!similar_sgr(test, cap)) {
93615589c42SPeter Wemm 		_nc_warning("%s differs from sgr(%d): %s", name, num,
93715589c42SPeter Wemm 			    _nc_visbuf(test));
93815589c42SPeter Wemm 	    }
93915589c42SPeter Wemm 	} else if (strcmp(test, zero)) {
94015589c42SPeter Wemm 	    _nc_warning("sgr(%d) present, but not %s", num, name);
94115589c42SPeter Wemm 	}
94215589c42SPeter Wemm     } else if (PRESENT(cap)) {
94315589c42SPeter Wemm 	_nc_warning("sgr(%d) missing, but %s present", num, name);
94415589c42SPeter Wemm     }
94515589c42SPeter Wemm }
94615589c42SPeter Wemm 
94715589c42SPeter Wemm #define CHECK_SGR(num,name) check_sgr(tp, zero, num, name, #name)
94815589c42SPeter Wemm 
9490e3d5408SPeter Wemm /* other sanity-checks (things that we don't want in the normal
9500e3d5408SPeter Wemm  * logic that reads a terminfo entry)
9510e3d5408SPeter Wemm  */
95215589c42SPeter Wemm static void
95315589c42SPeter Wemm check_termtype(TERMTYPE * tp)
9540e3d5408SPeter Wemm {
9550e3d5408SPeter Wemm     bool conflict = FALSE;
9560e3d5408SPeter Wemm     unsigned j, k;
9570e3d5408SPeter Wemm     char fkeys[STRCOUNT];
9580e3d5408SPeter Wemm 
9590e3d5408SPeter Wemm     /*
9600e3d5408SPeter Wemm      * A terminal entry may contain more than one keycode assigned to
9610e3d5408SPeter Wemm      * a given string (e.g., KEY_END and KEY_LL).  But curses will only
9620e3d5408SPeter Wemm      * return one (the last one assigned).
9630e3d5408SPeter Wemm      */
9640e3d5408SPeter Wemm     memset(fkeys, 0, sizeof(fkeys));
9650e3d5408SPeter Wemm     for (j = 0; _nc_tinfo_fkeys[j].code; j++) {
9660e3d5408SPeter Wemm 	char *a = tp->Strings[_nc_tinfo_fkeys[j].offset];
9670e3d5408SPeter Wemm 	bool first = TRUE;
9680e3d5408SPeter Wemm 	if (!VALID_STRING(a))
9690e3d5408SPeter Wemm 	    continue;
9700e3d5408SPeter Wemm 	for (k = j + 1; _nc_tinfo_fkeys[k].code; k++) {
9710e3d5408SPeter Wemm 	    char *b = tp->Strings[_nc_tinfo_fkeys[k].offset];
9720e3d5408SPeter Wemm 	    if (!VALID_STRING(b)
9730e3d5408SPeter Wemm 		|| fkeys[k])
9740e3d5408SPeter Wemm 		continue;
9750e3d5408SPeter Wemm 	    if (!strcmp(a, b)) {
9760e3d5408SPeter Wemm 		fkeys[j] = 1;
9770e3d5408SPeter Wemm 		fkeys[k] = 1;
9780e3d5408SPeter Wemm 		if (first) {
9790e3d5408SPeter Wemm 		    if (!conflict) {
9800e3d5408SPeter Wemm 			_nc_warning("Conflicting key definitions (using the last)");
9810e3d5408SPeter Wemm 			conflict = TRUE;
9820e3d5408SPeter Wemm 		    }
9830e3d5408SPeter Wemm 		    fprintf(stderr, "... %s is the same as %s",
9840e3d5408SPeter Wemm 			    keyname(_nc_tinfo_fkeys[j].code),
9850e3d5408SPeter Wemm 			    keyname(_nc_tinfo_fkeys[k].code));
9860e3d5408SPeter Wemm 		    first = FALSE;
9870e3d5408SPeter Wemm 		} else {
9880e3d5408SPeter Wemm 		    fprintf(stderr, ", %s",
9890e3d5408SPeter Wemm 			    keyname(_nc_tinfo_fkeys[k].code));
9900e3d5408SPeter Wemm 		}
9910e3d5408SPeter Wemm 	    }
9920e3d5408SPeter Wemm 	}
9930e3d5408SPeter Wemm 	if (!first)
9940e3d5408SPeter Wemm 	    fprintf(stderr, "\n");
9950e3d5408SPeter Wemm     }
9960e3d5408SPeter Wemm 
99718259542SPeter Wemm     for (j = 0; j < NUM_STRINGS(tp); j++) {
99818259542SPeter Wemm 	char *a = tp->Strings[j];
99918259542SPeter Wemm 	if (VALID_STRING(a))
100018259542SPeter Wemm 	    check_params(tp, ExtStrname(tp, j, strnames), a);
100118259542SPeter Wemm     }
100218259542SPeter Wemm 
10030e3d5408SPeter Wemm     /*
10040e3d5408SPeter Wemm      * Quick check for color.  We could also check if the ANSI versus
10050e3d5408SPeter Wemm      * non-ANSI strings are misused.
10060e3d5408SPeter Wemm      */
10070e3d5408SPeter Wemm     if ((max_colors > 0) != (max_pairs > 0)
10080e3d5408SPeter Wemm 	|| (max_colors > max_pairs))
10090e3d5408SPeter Wemm 	_nc_warning("inconsistent values for max_colors and max_pairs");
10100e3d5408SPeter Wemm 
101115589c42SPeter Wemm     PAIRED(set_foreground, set_background);
101215589c42SPeter Wemm     PAIRED(set_a_foreground, set_a_background);
10130e3d5408SPeter Wemm 
10140e3d5408SPeter Wemm     /*
10150e3d5408SPeter Wemm      * These may be mismatched because the terminal description relies on
10160e3d5408SPeter Wemm      * restoring the cursor visibility by resetting it.
10170e3d5408SPeter Wemm      */
101815589c42SPeter Wemm     ANDMISSING(cursor_invisible, cursor_normal);
101915589c42SPeter Wemm     ANDMISSING(cursor_visible, cursor_normal);
102015589c42SPeter Wemm 
102115589c42SPeter Wemm     if (PRESENT(cursor_visible) && PRESENT(cursor_normal)
102215589c42SPeter Wemm 	&& !strcmp(cursor_visible, cursor_normal))
102315589c42SPeter Wemm 	_nc_warning("cursor_visible is same as cursor_normal");
10240e3d5408SPeter Wemm 
10250e3d5408SPeter Wemm     /*
10260e3d5408SPeter Wemm      * From XSI & O'Reilly, we gather that sc/rc are required if csr is
10270e3d5408SPeter Wemm      * given, because the cursor position after the scrolling operation is
10280e3d5408SPeter Wemm      * performed is undefined.
10290e3d5408SPeter Wemm      */
103015589c42SPeter Wemm     ANDMISSING(change_scroll_region, save_cursor);
103115589c42SPeter Wemm     ANDMISSING(change_scroll_region, restore_cursor);
103215589c42SPeter Wemm 
103315589c42SPeter Wemm     if (PRESENT(set_attributes)) {
103415589c42SPeter Wemm 	char *zero = tparm(set_attributes, 0, 0, 0, 0, 0, 0, 0, 0, 0);
103515589c42SPeter Wemm 
103615589c42SPeter Wemm 	zero = strdup(zero);
103715589c42SPeter Wemm 	CHECK_SGR(1, enter_standout_mode);
103815589c42SPeter Wemm 	CHECK_SGR(2, enter_underline_mode);
103915589c42SPeter Wemm 	CHECK_SGR(3, enter_reverse_mode);
104015589c42SPeter Wemm 	CHECK_SGR(4, enter_blink_mode);
104115589c42SPeter Wemm 	CHECK_SGR(5, enter_dim_mode);
104215589c42SPeter Wemm 	CHECK_SGR(6, enter_bold_mode);
104315589c42SPeter Wemm 	CHECK_SGR(7, enter_secure_mode);
104415589c42SPeter Wemm 	CHECK_SGR(8, enter_protected_mode);
104515589c42SPeter Wemm 	CHECK_SGR(9, enter_alt_charset_mode);
104615589c42SPeter Wemm 	free(zero);
104715589c42SPeter Wemm     }
10480e3d5408SPeter Wemm 
10490e3d5408SPeter Wemm     /*
10500e3d5408SPeter Wemm      * Some standard applications (e.g., vi) and some non-curses
10510e3d5408SPeter Wemm      * applications (e.g., jove) get confused if we have both ich/ich1 and
10520e3d5408SPeter Wemm      * smir/rmir.  Let's be nice and warn about that, too, even though
10530e3d5408SPeter Wemm      * ncurses handles it.
10540e3d5408SPeter Wemm      */
10550e3d5408SPeter Wemm     if ((PRESENT(enter_insert_mode) || PRESENT(exit_insert_mode))
10560e3d5408SPeter Wemm 	&& (PRESENT(insert_character) || PRESENT(parm_ich))) {
10570e3d5408SPeter Wemm 	_nc_warning("non-curses applications may be confused by ich/ich1 with smir/rmir");
10580e3d5408SPeter Wemm     }
10590e3d5408SPeter Wemm 
10600e3d5408SPeter Wemm     /*
10610e3d5408SPeter Wemm      * Finally, do the non-verbose checks
10620e3d5408SPeter Wemm      */
10630e3d5408SPeter Wemm     if (save_check_termtype != 0)
10640e3d5408SPeter Wemm 	save_check_termtype(tp);
10650e3d5408SPeter Wemm }
1066