xref: /freebsd/contrib/ncurses/progs/tic.c (revision 7a69bbfb278952228c9aa1eca241e65fcdef425e)
10e3d5408SPeter Wemm /****************************************************************************
27a69bbfbSPeter Wemm  * Copyright (c) 1998,1999,2000,2001 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 
477a69bbfbSPeter Wemm MODULE_ID("$Id: tic.c,v 1.90 2001/04/15 00:21:31 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;
557a69bbfbSPeter Wemm static int tparm_errs;
560e3d5408SPeter Wemm 
570e3d5408SPeter Wemm static void (*save_check_termtype) (TERMTYPE *);
580e3d5408SPeter Wemm static void check_termtype(TERMTYPE * tt);
590e3d5408SPeter Wemm 
6018259542SPeter Wemm static const char usage_string[] = "[-V] [-v[n]] [-e names] [-CILNRTcfrswx1] source-file\n";
610e3d5408SPeter Wemm 
6215589c42SPeter Wemm static void
6315589c42SPeter Wemm cleanup(void)
640e3d5408SPeter Wemm {
650e3d5408SPeter Wemm     if (tmp_fp != 0)
660e3d5408SPeter Wemm 	fclose(tmp_fp);
670e3d5408SPeter Wemm     if (to_remove != 0) {
680e3d5408SPeter Wemm #if HAVE_REMOVE
690e3d5408SPeter Wemm 	remove(to_remove);
700e3d5408SPeter Wemm #else
710e3d5408SPeter Wemm 	unlink(to_remove);
720e3d5408SPeter Wemm #endif
730e3d5408SPeter Wemm     }
740e3d5408SPeter Wemm }
750e3d5408SPeter Wemm 
7615589c42SPeter Wemm static void
7715589c42SPeter Wemm failed(const char *msg)
780e3d5408SPeter Wemm {
790e3d5408SPeter Wemm     perror(msg);
800e3d5408SPeter Wemm     cleanup();
810e3d5408SPeter Wemm     exit(EXIT_FAILURE);
820e3d5408SPeter Wemm }
830e3d5408SPeter Wemm 
8415589c42SPeter Wemm static void
8515589c42SPeter Wemm usage(void)
860e3d5408SPeter Wemm {
8715589c42SPeter Wemm     static const char *const tbl[] =
8815589c42SPeter Wemm     {
890e3d5408SPeter Wemm 	"Options:",
900e3d5408SPeter Wemm 	"  -1         format translation output one capability per line",
910e3d5408SPeter Wemm 	"  -C         translate entries to termcap source form",
920e3d5408SPeter Wemm 	"  -I         translate entries to terminfo source form",
930e3d5408SPeter Wemm 	"  -L         translate entries to full terminfo source form",
940e3d5408SPeter Wemm 	"  -N         disable smart defaults for source translation",
950e3d5408SPeter Wemm 	"  -R         restrict translation to given terminfo/termcap version",
960e3d5408SPeter Wemm 	"  -T         remove size-restrictions on compiled description",
9718259542SPeter Wemm 	"  -V         print version",
9815589c42SPeter Wemm #if NCURSES_XNAMES
9915589c42SPeter Wemm 	"  -a         retain commented-out capabilities (sets -x also)",
10015589c42SPeter Wemm #endif
1010e3d5408SPeter Wemm 	"  -c         check only, validate input without compiling or translating",
1020e3d5408SPeter Wemm 	"  -f         format complex strings for readability",
1030e3d5408SPeter Wemm 	"  -G         format %{number} to %'char'",
1040e3d5408SPeter Wemm 	"  -g         format %'char' to %{number}",
1050e3d5408SPeter Wemm 	"  -e<names>  translate/compile only entries named by comma-separated list",
1060e3d5408SPeter Wemm 	"  -o<dir>    set output directory for compiled entry writes",
1070e3d5408SPeter Wemm 	"  -r         force resolution of all use entries in source translation",
1080e3d5408SPeter Wemm 	"  -s         print summary statistics",
1090e3d5408SPeter Wemm 	"  -v[n]      set verbosity level",
1100e3d5408SPeter Wemm 	"  -w[n]      set format width for translation output",
1110e3d5408SPeter Wemm #if NCURSES_XNAMES
1120e3d5408SPeter Wemm 	"  -x         treat unknown capabilities as user-defined",
1130e3d5408SPeter Wemm #endif
1140e3d5408SPeter Wemm 	"",
1150e3d5408SPeter Wemm 	"Parameters:",
1160e3d5408SPeter Wemm 	"  <file>     file to translate or compile"
1170e3d5408SPeter Wemm     };
1180e3d5408SPeter Wemm     size_t j;
1190e3d5408SPeter Wemm 
12015589c42SPeter Wemm     fprintf(stderr, "Usage: %s %s\n", _nc_progname, usage_string);
12118259542SPeter Wemm     for (j = 0; j < SIZEOF(tbl); j++) {
12215589c42SPeter Wemm 	fputs(tbl[j], stderr);
12315589c42SPeter Wemm 	putc('\n', stderr);
12415589c42SPeter Wemm     }
1250e3d5408SPeter Wemm     exit(EXIT_FAILURE);
1260e3d5408SPeter Wemm }
1270e3d5408SPeter Wemm 
1280e3d5408SPeter Wemm #define L_BRACE '{'
1290e3d5408SPeter Wemm #define R_BRACE '}'
1300e3d5408SPeter Wemm #define S_QUOTE '\'';
1310e3d5408SPeter Wemm 
13215589c42SPeter Wemm static void
13315589c42SPeter Wemm write_it(ENTRY * ep)
1340e3d5408SPeter Wemm {
1350e3d5408SPeter Wemm     unsigned n;
1360e3d5408SPeter Wemm     int ch;
1370e3d5408SPeter Wemm     char *s, *d, *t;
1380e3d5408SPeter Wemm     char result[MAX_ENTRY_SIZE];
1390e3d5408SPeter Wemm 
1400e3d5408SPeter Wemm     /*
1410e3d5408SPeter Wemm      * Look for strings that contain %{number}, convert them to %'char',
1420e3d5408SPeter Wemm      * which is shorter and runs a little faster.
1430e3d5408SPeter Wemm      */
1440e3d5408SPeter Wemm     for (n = 0; n < STRCOUNT; n++) {
1450e3d5408SPeter Wemm 	s = ep->tterm.Strings[n];
1460e3d5408SPeter Wemm 	if (VALID_STRING(s)
1470e3d5408SPeter Wemm 	    && strchr(s, L_BRACE) != 0) {
1480e3d5408SPeter Wemm 	    d = result;
1490e3d5408SPeter Wemm 	    t = s;
1500e3d5408SPeter Wemm 	    while ((ch = *t++) != 0) {
1510e3d5408SPeter Wemm 		*d++ = ch;
1520e3d5408SPeter Wemm 		if (ch == '\\') {
1530e3d5408SPeter Wemm 		    *d++ = *t++;
1540e3d5408SPeter Wemm 		} else if ((ch == '%')
1550e3d5408SPeter Wemm 			   && (*t == L_BRACE)) {
1560e3d5408SPeter Wemm 		    char *v = 0;
1570e3d5408SPeter Wemm 		    long value = strtol(t + 1, &v, 0);
1580e3d5408SPeter Wemm 		    if (v != 0
1590e3d5408SPeter Wemm 			&& *v == R_BRACE
1600e3d5408SPeter Wemm 			&& value > 0
1610e3d5408SPeter Wemm 			&& value != '\\'	/* FIXME */
1620e3d5408SPeter Wemm 			&& value < 127
1630e3d5408SPeter Wemm 			&& isprint((int) value)) {
1640e3d5408SPeter Wemm 			*d++ = S_QUOTE;
1650e3d5408SPeter Wemm 			*d++ = (int) value;
1660e3d5408SPeter Wemm 			*d++ = S_QUOTE;
1670e3d5408SPeter Wemm 			t = (v + 1);
1680e3d5408SPeter Wemm 		    }
1690e3d5408SPeter Wemm 		}
1700e3d5408SPeter Wemm 	    }
1710e3d5408SPeter Wemm 	    *d = 0;
1720e3d5408SPeter Wemm 	    if (strlen(result) < strlen(s))
1730e3d5408SPeter Wemm 		strcpy(s, result);
1740e3d5408SPeter Wemm 	}
1750e3d5408SPeter Wemm     }
1760e3d5408SPeter Wemm 
1770e3d5408SPeter Wemm     _nc_set_type(_nc_first_name(ep->tterm.term_names));
1780e3d5408SPeter Wemm     _nc_curr_line = ep->startline;
1790e3d5408SPeter Wemm     _nc_write_entry(&ep->tterm);
1800e3d5408SPeter Wemm }
1810e3d5408SPeter Wemm 
18215589c42SPeter Wemm static bool
18315589c42SPeter Wemm immedhook(ENTRY * ep GCC_UNUSED)
1840e3d5408SPeter Wemm /* write out entries with no use capabilities immediately to save storage */
1850e3d5408SPeter Wemm {
18618259542SPeter Wemm #if !HAVE_BIG_CORE
1870e3d5408SPeter Wemm     /*
1880e3d5408SPeter Wemm      * This is strictly a core-economy kluge.  The really clean way to handle
1890e3d5408SPeter Wemm      * compilation is to slurp the whole file into core and then do all the
1900e3d5408SPeter Wemm      * name-collision checks and entry writes in one swell foop.  But the
1910e3d5408SPeter Wemm      * terminfo master file is large enough that some core-poor systems swap
1920e3d5408SPeter Wemm      * like crazy when you compile it this way...there have been reports of
1930e3d5408SPeter Wemm      * this process taking *three hours*, rather than the twenty seconds or
1940e3d5408SPeter Wemm      * less typical on my development box.
1950e3d5408SPeter Wemm      *
1960e3d5408SPeter Wemm      * So.  This hook *immediately* writes out the referenced entry if it
1970e3d5408SPeter Wemm      * has no use capabilities.  The compiler main loop refrains from
1980e3d5408SPeter Wemm      * adding the entry to the in-core list when this hook fires.  If some
1990e3d5408SPeter Wemm      * other entry later needs to reference an entry that got written
2000e3d5408SPeter Wemm      * immediately, that's OK; the resolution code will fetch it off disk
2010e3d5408SPeter Wemm      * when it can't find it in core.
2020e3d5408SPeter Wemm      *
2030e3d5408SPeter Wemm      * Name collisions will still be detected, just not as cleanly.  The
2040e3d5408SPeter Wemm      * write_entry() code complains before overwriting an entry that
2050e3d5408SPeter Wemm      * postdates the time of tic's first call to write_entry().  Thus
2060e3d5408SPeter Wemm      * it will complain about overwriting entries newly made during the
2070e3d5408SPeter Wemm      * tic run, but not about overwriting ones that predate it.
2080e3d5408SPeter Wemm      *
2090e3d5408SPeter Wemm      * The reason this is a hook, and not in line with the rest of the
2100e3d5408SPeter Wemm      * compiler code, is that the support for termcap fallback cannot assume
2110e3d5408SPeter Wemm      * it has anywhere to spool out these entries!
2120e3d5408SPeter Wemm      *
2130e3d5408SPeter Wemm      * The _nc_set_type() call here requires a compensating one in
2140e3d5408SPeter Wemm      * _nc_parse_entry().
2150e3d5408SPeter Wemm      *
2160e3d5408SPeter Wemm      * If you define HAVE_BIG_CORE, you'll disable this kluge.  This will
2170e3d5408SPeter Wemm      * make tic a bit faster (because the resolution code won't have to do
2180e3d5408SPeter Wemm      * disk I/O nearly as often).
2190e3d5408SPeter Wemm      */
22015589c42SPeter Wemm     if (ep->nuses == 0) {
2210e3d5408SPeter Wemm 	int oldline = _nc_curr_line;
2220e3d5408SPeter Wemm 
2230e3d5408SPeter Wemm 	write_it(ep);
2240e3d5408SPeter Wemm 	_nc_curr_line = oldline;
2250e3d5408SPeter Wemm 	free(ep->tterm.str_table);
2260e3d5408SPeter Wemm 	return (TRUE);
2270e3d5408SPeter Wemm     }
2280e3d5408SPeter Wemm #endif /* HAVE_BIG_CORE */
2290e3d5408SPeter Wemm     return (FALSE);
2300e3d5408SPeter Wemm }
2310e3d5408SPeter Wemm 
23215589c42SPeter Wemm static void
23315589c42SPeter Wemm put_translate(int c)
2340e3d5408SPeter Wemm /* emit a comment char, translating terminfo names to termcap names */
2350e3d5408SPeter Wemm {
2360e3d5408SPeter Wemm     static bool in_name = FALSE;
23715589c42SPeter Wemm     static size_t have, used;
23815589c42SPeter Wemm     static char *namebuf, *suffix;
2390e3d5408SPeter Wemm 
24015589c42SPeter Wemm     if (in_name) {
24115589c42SPeter Wemm 	if (used + 1 >= have) {
24215589c42SPeter Wemm 	    have += 132;
24315589c42SPeter Wemm 	    namebuf = typeRealloc(char, have, namebuf);
24415589c42SPeter Wemm 	    suffix = typeRealloc(char, have, suffix);
2450e3d5408SPeter Wemm 	}
24615589c42SPeter Wemm 	if (c == '\n' || c == '@') {
24715589c42SPeter Wemm 	    namebuf[used++] = '\0';
2480e3d5408SPeter Wemm 	    (void) putchar('<');
2490e3d5408SPeter Wemm 	    (void) fputs(namebuf, stdout);
2500e3d5408SPeter Wemm 	    putchar(c);
2510e3d5408SPeter Wemm 	    in_name = FALSE;
25215589c42SPeter Wemm 	} else if (c != '>') {
25315589c42SPeter Wemm 	    namebuf[used++] = c;
25415589c42SPeter Wemm 	} else {		/* ah! candidate name! */
2550e3d5408SPeter Wemm 	    char *up;
2560e3d5408SPeter Wemm 	    NCURSES_CONST char *tp;
2570e3d5408SPeter Wemm 
25815589c42SPeter Wemm 	    namebuf[used++] = '\0';
2590e3d5408SPeter Wemm 	    in_name = FALSE;
2600e3d5408SPeter Wemm 
2610e3d5408SPeter Wemm 	    suffix[0] = '\0';
2620e3d5408SPeter Wemm 	    if ((up = strchr(namebuf, '#')) != 0
2630e3d5408SPeter Wemm 		|| (up = strchr(namebuf, '=')) != 0
26415589c42SPeter Wemm 		|| ((up = strchr(namebuf, '@')) != 0 && up[1] == '>')) {
2650e3d5408SPeter Wemm 		(void) strcpy(suffix, up);
2660e3d5408SPeter Wemm 		*up = '\0';
2670e3d5408SPeter Wemm 	    }
2680e3d5408SPeter Wemm 
26915589c42SPeter Wemm 	    if ((tp = nametrans(namebuf)) != 0) {
2700e3d5408SPeter Wemm 		(void) putchar(':');
2710e3d5408SPeter Wemm 		(void) fputs(tp, stdout);
2720e3d5408SPeter Wemm 		(void) fputs(suffix, stdout);
2730e3d5408SPeter Wemm 		(void) putchar(':');
27415589c42SPeter Wemm 	    } else {
2750e3d5408SPeter Wemm 		/* couldn't find a translation, just dump the name */
2760e3d5408SPeter Wemm 		(void) putchar('<');
2770e3d5408SPeter Wemm 		(void) fputs(namebuf, stdout);
2780e3d5408SPeter Wemm 		(void) fputs(suffix, stdout);
2790e3d5408SPeter Wemm 		(void) putchar('>');
2800e3d5408SPeter Wemm 	    }
28115589c42SPeter Wemm 	}
28215589c42SPeter Wemm     } else {
28315589c42SPeter Wemm 	used = 0;
28415589c42SPeter Wemm 	if (c == '<') {
28515589c42SPeter Wemm 	    in_name = TRUE;
28615589c42SPeter Wemm 	} else {
28715589c42SPeter Wemm 	    putchar(c);
28815589c42SPeter Wemm 	}
2890e3d5408SPeter Wemm     }
2900e3d5408SPeter Wemm }
2910e3d5408SPeter Wemm 
2920e3d5408SPeter Wemm /* Returns a string, stripped of leading/trailing whitespace */
29315589c42SPeter Wemm static char *
29415589c42SPeter Wemm stripped(char *src)
2950e3d5408SPeter Wemm {
2967a69bbfbSPeter Wemm     while (isspace(CharOf(*src)))
2970e3d5408SPeter Wemm 	src++;
2980e3d5408SPeter Wemm     if (*src != '\0') {
2990e3d5408SPeter Wemm 	char *dst = strcpy(malloc(strlen(src) + 1), src);
3000e3d5408SPeter Wemm 	size_t len = strlen(dst);
3017a69bbfbSPeter Wemm 	while (--len != 0 && isspace(CharOf(dst[len])))
3020e3d5408SPeter Wemm 	    dst[len] = '\0';
3030e3d5408SPeter Wemm 	return dst;
3040e3d5408SPeter Wemm     }
3050e3d5408SPeter Wemm     return 0;
3060e3d5408SPeter Wemm }
3070e3d5408SPeter Wemm 
30818259542SPeter Wemm static FILE *
30918259542SPeter Wemm open_input(const char *filename)
31018259542SPeter Wemm {
31118259542SPeter Wemm     FILE *fp = fopen(filename, "r");
31218259542SPeter Wemm     struct stat sb;
31318259542SPeter Wemm 
31418259542SPeter Wemm     if (fp == 0) {
31518259542SPeter Wemm 	fprintf(stderr, "%s: Can't open %s\n", _nc_progname, filename);
31618259542SPeter Wemm 	exit(EXIT_FAILURE);
31718259542SPeter Wemm     }
31818259542SPeter Wemm     if (fstat(fileno(fp), &sb) < 0
31918259542SPeter Wemm 	|| (sb.st_mode & S_IFMT) != S_IFREG) {
32018259542SPeter Wemm 	fprintf(stderr, "%s: %s is not a file\n", _nc_progname, filename);
32118259542SPeter Wemm 	exit(EXIT_FAILURE);
32218259542SPeter Wemm     }
32318259542SPeter Wemm     return fp;
32418259542SPeter Wemm }
32518259542SPeter Wemm 
3260e3d5408SPeter Wemm /* Parse the "-e" option-value into a list of names */
32715589c42SPeter Wemm static const char **
32815589c42SPeter Wemm make_namelist(char *src)
3290e3d5408SPeter Wemm {
3300e3d5408SPeter Wemm     const char **dst = 0;
3310e3d5408SPeter Wemm 
3320e3d5408SPeter Wemm     char *s, *base;
3330e3d5408SPeter Wemm     unsigned pass, n, nn;
3340e3d5408SPeter Wemm     char buffer[BUFSIZ];
3350e3d5408SPeter Wemm 
3360e3d5408SPeter Wemm     if (src == 0) {
3370e3d5408SPeter Wemm 	/* EMPTY */ ;
3380e3d5408SPeter Wemm     } else if (strchr(src, '/') != 0) {		/* a filename */
33918259542SPeter Wemm 	FILE *fp = open_input(src);
3400e3d5408SPeter Wemm 
3410e3d5408SPeter Wemm 	for (pass = 1; pass <= 2; pass++) {
3420e3d5408SPeter Wemm 	    nn = 0;
3430e3d5408SPeter Wemm 	    while (fgets(buffer, sizeof(buffer), fp) != 0) {
3440e3d5408SPeter Wemm 		if ((s = stripped(buffer)) != 0) {
3450e3d5408SPeter Wemm 		    if (dst != 0)
3460e3d5408SPeter Wemm 			dst[nn] = s;
3470e3d5408SPeter Wemm 		    nn++;
3480e3d5408SPeter Wemm 		}
3490e3d5408SPeter Wemm 	    }
3500e3d5408SPeter Wemm 	    if (pass == 1) {
35115589c42SPeter Wemm 		dst = typeCalloc(const char *, nn + 1);
3520e3d5408SPeter Wemm 		rewind(fp);
3530e3d5408SPeter Wemm 	    }
3540e3d5408SPeter Wemm 	}
3550e3d5408SPeter Wemm 	fclose(fp);
3560e3d5408SPeter Wemm     } else {			/* literal list of names */
3570e3d5408SPeter Wemm 	for (pass = 1; pass <= 2; pass++) {
3580e3d5408SPeter Wemm 	    for (n = nn = 0, base = src;; n++) {
3590e3d5408SPeter Wemm 		int mark = src[n];
3600e3d5408SPeter Wemm 		if (mark == ',' || mark == '\0') {
3610e3d5408SPeter Wemm 		    if (pass == 1) {
3620e3d5408SPeter Wemm 			nn++;
3630e3d5408SPeter Wemm 		    } else {
3640e3d5408SPeter Wemm 			src[n] = '\0';
3650e3d5408SPeter Wemm 			if ((s = stripped(base)) != 0)
3660e3d5408SPeter Wemm 			    dst[nn++] = s;
3670e3d5408SPeter Wemm 			base = &src[n + 1];
3680e3d5408SPeter Wemm 		    }
3690e3d5408SPeter Wemm 		}
3700e3d5408SPeter Wemm 		if (mark == '\0')
3710e3d5408SPeter Wemm 		    break;
3720e3d5408SPeter Wemm 	    }
3730e3d5408SPeter Wemm 	    if (pass == 1)
37415589c42SPeter Wemm 		dst = typeCalloc(const char *, nn + 1);
3750e3d5408SPeter Wemm 	}
3760e3d5408SPeter Wemm     }
3770e3d5408SPeter Wemm     if (showsummary) {
3780e3d5408SPeter Wemm 	fprintf(log_fp, "Entries that will be compiled:\n");
3790e3d5408SPeter Wemm 	for (n = 0; dst[n] != 0; n++)
3800e3d5408SPeter Wemm 	    fprintf(log_fp, "%d:%s\n", n + 1, dst[n]);
3810e3d5408SPeter Wemm     }
3820e3d5408SPeter Wemm     return dst;
3830e3d5408SPeter Wemm }
3840e3d5408SPeter Wemm 
38515589c42SPeter Wemm static bool
38615589c42SPeter Wemm matches(const char **needle, const char *haystack)
3870e3d5408SPeter Wemm /* does entry in needle list match |-separated field in haystack? */
3880e3d5408SPeter Wemm {
3890e3d5408SPeter Wemm     bool code = FALSE;
3900e3d5408SPeter Wemm     size_t n;
3910e3d5408SPeter Wemm 
39215589c42SPeter Wemm     if (needle != 0) {
39315589c42SPeter Wemm 	for (n = 0; needle[n] != 0; n++) {
39415589c42SPeter Wemm 	    if (_nc_name_match(haystack, needle[n], "|")) {
3950e3d5408SPeter Wemm 		code = TRUE;
3960e3d5408SPeter Wemm 		break;
3970e3d5408SPeter Wemm 	    }
3980e3d5408SPeter Wemm 	}
39915589c42SPeter Wemm     } else
4000e3d5408SPeter Wemm 	code = TRUE;
4010e3d5408SPeter Wemm     return (code);
4020e3d5408SPeter Wemm }
4030e3d5408SPeter Wemm 
40415589c42SPeter Wemm static FILE *
40515589c42SPeter Wemm open_tempfile(char *name)
40615589c42SPeter Wemm {
40715589c42SPeter Wemm     FILE *result = 0;
40815589c42SPeter Wemm #if HAVE_MKSTEMP
40915589c42SPeter Wemm     int fd = mkstemp(name);
41015589c42SPeter Wemm     if (fd >= 0)
41115589c42SPeter Wemm 	result = fdopen(fd, "w");
41215589c42SPeter Wemm #else
41315589c42SPeter Wemm     if (tmpnam(name) != 0)
41415589c42SPeter Wemm 	result = fopen(name, "w");
41515589c42SPeter Wemm #endif
41615589c42SPeter Wemm     return result;
41715589c42SPeter Wemm }
41815589c42SPeter Wemm 
41915589c42SPeter Wemm int
42015589c42SPeter Wemm main(int argc, char *argv[])
4210e3d5408SPeter Wemm {
4220e3d5408SPeter Wemm     char my_tmpname[PATH_MAX];
4230e3d5408SPeter Wemm     int v_opt = -1, debug_level;
4240e3d5408SPeter Wemm     int smart_defaults = TRUE;
4250e3d5408SPeter Wemm     char *termcap;
4260e3d5408SPeter Wemm     ENTRY *qp;
4270e3d5408SPeter Wemm 
4280e3d5408SPeter Wemm     int this_opt, last_opt = '?';
4290e3d5408SPeter Wemm 
4300e3d5408SPeter Wemm     int outform = F_TERMINFO;	/* output format */
4310e3d5408SPeter Wemm     int sortmode = S_TERMINFO;	/* sort_mode */
4320e3d5408SPeter Wemm 
4330e3d5408SPeter Wemm     int width = 60;
4340e3d5408SPeter Wemm     bool formatted = FALSE;	/* reformat complex strings? */
4350e3d5408SPeter Wemm     int numbers = 0;		/* format "%'char'" to/from "%{number}" */
4360e3d5408SPeter Wemm     bool infodump = FALSE;	/* running as captoinfo? */
4370e3d5408SPeter Wemm     bool capdump = FALSE;	/* running as infotocap? */
4380e3d5408SPeter Wemm     bool forceresolve = FALSE;	/* force resolution */
4390e3d5408SPeter Wemm     bool limited = TRUE;
4400e3d5408SPeter Wemm     char *tversion = (char *) NULL;
4410e3d5408SPeter Wemm     const char *source_file = "terminfo";
4420e3d5408SPeter Wemm     const char **namelst = 0;
4430e3d5408SPeter Wemm     char *outdir = (char *) NULL;
4440e3d5408SPeter Wemm     bool check_only = FALSE;
4450e3d5408SPeter Wemm 
4460e3d5408SPeter Wemm     log_fp = stderr;
4470e3d5408SPeter Wemm 
44818259542SPeter Wemm     _nc_progname = _nc_basename(argv[0]);
4490e3d5408SPeter Wemm 
45018259542SPeter Wemm     if ((infodump = (strcmp(_nc_progname, PROG_CAPTOINFO) == 0)) != FALSE) {
45115589c42SPeter Wemm 	outform = F_TERMINFO;
45215589c42SPeter Wemm 	sortmode = S_TERMINFO;
45315589c42SPeter Wemm     }
45418259542SPeter Wemm     if ((capdump = (strcmp(_nc_progname, PROG_INFOTOCAP) == 0)) != FALSE) {
45515589c42SPeter Wemm 	outform = F_TERMCAP;
45615589c42SPeter Wemm 	sortmode = S_TERMCAP;
45715589c42SPeter Wemm     }
4580e3d5408SPeter Wemm #if NCURSES_XNAMES
4590e3d5408SPeter Wemm     use_extended_names(FALSE);
4600e3d5408SPeter Wemm #endif
4610e3d5408SPeter Wemm 
4620e3d5408SPeter Wemm     /*
4630e3d5408SPeter Wemm      * Processing arguments is a little complicated, since someone made a
4640e3d5408SPeter Wemm      * design decision to allow the numeric values for -w, -v options to
4650e3d5408SPeter Wemm      * be optional.
4660e3d5408SPeter Wemm      */
46715589c42SPeter Wemm     while ((this_opt = getopt(argc, argv,
46815589c42SPeter Wemm 			      "0123456789CILNR:TVace:fGgo:rsvwx")) != EOF) {
4690e3d5408SPeter Wemm 	if (isdigit(this_opt)) {
4700e3d5408SPeter Wemm 	    switch (last_opt) {
4710e3d5408SPeter Wemm 	    case 'v':
4720e3d5408SPeter Wemm 		v_opt = (v_opt * 10) + (this_opt - '0');
4730e3d5408SPeter Wemm 		break;
4740e3d5408SPeter Wemm 	    case 'w':
4750e3d5408SPeter Wemm 		width = (width * 10) + (this_opt - '0');
4760e3d5408SPeter Wemm 		break;
4770e3d5408SPeter Wemm 	    default:
4780e3d5408SPeter Wemm 		if (this_opt != '1')
4790e3d5408SPeter Wemm 		    usage();
4800e3d5408SPeter Wemm 		last_opt = this_opt;
4810e3d5408SPeter Wemm 		width = 0;
4820e3d5408SPeter Wemm 	    }
4830e3d5408SPeter Wemm 	    continue;
4840e3d5408SPeter Wemm 	}
4850e3d5408SPeter Wemm 	switch (this_opt) {
4860e3d5408SPeter Wemm 	case 'C':
4870e3d5408SPeter Wemm 	    capdump = TRUE;
4880e3d5408SPeter Wemm 	    outform = F_TERMCAP;
4890e3d5408SPeter Wemm 	    sortmode = S_TERMCAP;
4900e3d5408SPeter Wemm 	    break;
4910e3d5408SPeter Wemm 	case 'I':
4920e3d5408SPeter Wemm 	    infodump = TRUE;
4930e3d5408SPeter Wemm 	    outform = F_TERMINFO;
4940e3d5408SPeter Wemm 	    sortmode = S_TERMINFO;
4950e3d5408SPeter Wemm 	    break;
4960e3d5408SPeter Wemm 	case 'L':
4970e3d5408SPeter Wemm 	    infodump = TRUE;
4980e3d5408SPeter Wemm 	    outform = F_VARIABLE;
4990e3d5408SPeter Wemm 	    sortmode = S_VARIABLE;
5000e3d5408SPeter Wemm 	    break;
5010e3d5408SPeter Wemm 	case 'N':
5020e3d5408SPeter Wemm 	    smart_defaults = FALSE;
5030e3d5408SPeter Wemm 	    break;
5040e3d5408SPeter Wemm 	case 'R':
5050e3d5408SPeter Wemm 	    tversion = optarg;
5060e3d5408SPeter Wemm 	    break;
5070e3d5408SPeter Wemm 	case 'T':
5080e3d5408SPeter Wemm 	    limited = FALSE;
5090e3d5408SPeter Wemm 	    break;
5100e3d5408SPeter Wemm 	case 'V':
51118259542SPeter Wemm 	    puts(curses_version());
5120e3d5408SPeter Wemm 	    return EXIT_SUCCESS;
5130e3d5408SPeter Wemm 	case 'c':
5140e3d5408SPeter Wemm 	    check_only = TRUE;
5150e3d5408SPeter Wemm 	    break;
5160e3d5408SPeter Wemm 	case 'e':
5170e3d5408SPeter Wemm 	    namelst = make_namelist(optarg);
5180e3d5408SPeter Wemm 	    break;
5190e3d5408SPeter Wemm 	case 'f':
5200e3d5408SPeter Wemm 	    formatted = TRUE;
5210e3d5408SPeter Wemm 	    break;
5220e3d5408SPeter Wemm 	case 'G':
5230e3d5408SPeter Wemm 	    numbers = 1;
5240e3d5408SPeter Wemm 	    break;
5250e3d5408SPeter Wemm 	case 'g':
5260e3d5408SPeter Wemm 	    numbers = -1;
5270e3d5408SPeter Wemm 	    break;
5280e3d5408SPeter Wemm 	case 'o':
5290e3d5408SPeter Wemm 	    outdir = optarg;
5300e3d5408SPeter Wemm 	    break;
5310e3d5408SPeter Wemm 	case 'r':
5320e3d5408SPeter Wemm 	    forceresolve = TRUE;
5330e3d5408SPeter Wemm 	    break;
5340e3d5408SPeter Wemm 	case 's':
5350e3d5408SPeter Wemm 	    showsummary = TRUE;
5360e3d5408SPeter Wemm 	    break;
5370e3d5408SPeter Wemm 	case 'v':
5380e3d5408SPeter Wemm 	    v_opt = 0;
5390e3d5408SPeter Wemm 	    break;
5400e3d5408SPeter Wemm 	case 'w':
5410e3d5408SPeter Wemm 	    width = 0;
5420e3d5408SPeter Wemm 	    break;
5430e3d5408SPeter Wemm #if NCURSES_XNAMES
54415589c42SPeter Wemm 	case 'a':
54515589c42SPeter Wemm 	    _nc_disable_period = TRUE;
54615589c42SPeter Wemm 	    /* FALLTHRU */
5470e3d5408SPeter Wemm 	case 'x':
5480e3d5408SPeter Wemm 	    use_extended_names(TRUE);
5490e3d5408SPeter Wemm 	    break;
5500e3d5408SPeter Wemm #endif
5510e3d5408SPeter Wemm 	default:
5520e3d5408SPeter Wemm 	    usage();
5530e3d5408SPeter Wemm 	}
5540e3d5408SPeter Wemm 	last_opt = this_opt;
5550e3d5408SPeter Wemm     }
5560e3d5408SPeter Wemm 
5570e3d5408SPeter Wemm     debug_level = (v_opt > 0) ? v_opt : (v_opt == 0);
55815589c42SPeter Wemm     set_trace_level(debug_level);
5590e3d5408SPeter Wemm 
56015589c42SPeter Wemm     if (_nc_tracing) {
5610e3d5408SPeter Wemm 	save_check_termtype = _nc_check_termtype;
5620e3d5408SPeter Wemm 	_nc_check_termtype = check_termtype;
5630e3d5408SPeter Wemm     }
56418259542SPeter Wemm #if !HAVE_BIG_CORE
5650e3d5408SPeter Wemm     /*
5660e3d5408SPeter Wemm      * Aaargh! immedhook seriously hoses us!
5670e3d5408SPeter Wemm      *
5680e3d5408SPeter Wemm      * One problem with immedhook is it means we can't do -e.  Problem
5690e3d5408SPeter Wemm      * is that we can't guarantee that for each terminal listed, all the
5700e3d5408SPeter Wemm      * terminals it depends on will have been kept in core for reference
5710e3d5408SPeter Wemm      * resolution -- in fact it's certain the primitive types at the end
5720e3d5408SPeter Wemm      * of reference chains *won't* be in core unless they were explicitly
5730e3d5408SPeter Wemm      * in the select list themselves.
5740e3d5408SPeter Wemm      */
57515589c42SPeter Wemm     if (namelst && (!infodump && !capdump)) {
5760e3d5408SPeter Wemm 	(void) fprintf(stderr,
5770e3d5408SPeter Wemm 		       "Sorry, -e can't be used without -I or -C\n");
5780e3d5408SPeter Wemm 	cleanup();
5790e3d5408SPeter Wemm 	return EXIT_FAILURE;
5800e3d5408SPeter Wemm     }
5810e3d5408SPeter Wemm #endif /* HAVE_BIG_CORE */
5820e3d5408SPeter Wemm 
5830e3d5408SPeter Wemm     if (optind < argc) {
5840e3d5408SPeter Wemm 	source_file = argv[optind++];
5850e3d5408SPeter Wemm 	if (optind < argc) {
5860e3d5408SPeter Wemm 	    fprintf(stderr,
5870e3d5408SPeter Wemm 		    "%s: Too many file names.  Usage:\n\t%s %s",
5880e3d5408SPeter Wemm 		    _nc_progname,
5890e3d5408SPeter Wemm 		    _nc_progname,
5900e3d5408SPeter Wemm 		    usage_string);
5910e3d5408SPeter Wemm 	    return EXIT_FAILURE;
5920e3d5408SPeter Wemm 	}
5930e3d5408SPeter Wemm     } else {
5940e3d5408SPeter Wemm 	if (infodump == TRUE) {
5950e3d5408SPeter Wemm 	    /* captoinfo's no-argument case */
5960e3d5408SPeter Wemm 	    source_file = "/etc/termcap";
5970e3d5408SPeter Wemm 	    if ((termcap = getenv("TERMCAP")) != 0
5980e3d5408SPeter Wemm 		&& (namelst = make_namelist(getenv("TERM"))) != 0) {
5990e3d5408SPeter Wemm 		if (access(termcap, F_OK) == 0) {
6000e3d5408SPeter Wemm 		    /* file exists */
6010e3d5408SPeter Wemm 		    source_file = termcap;
60218259542SPeter Wemm 		} else if ((tmp_fp = open_tempfile(strcpy(my_tmpname,
60318259542SPeter Wemm 							  "/tmp/XXXXXX")))
60418259542SPeter Wemm 			   != 0) {
60515589c42SPeter Wemm 		    source_file = my_tmpname;
6060e3d5408SPeter Wemm 		    fprintf(tmp_fp, "%s\n", termcap);
6070e3d5408SPeter Wemm 		    fclose(tmp_fp);
60818259542SPeter Wemm 		    tmp_fp = open_input(source_file);
6090e3d5408SPeter Wemm 		    to_remove = source_file;
6100e3d5408SPeter Wemm 		} else {
6110e3d5408SPeter Wemm 		    failed("tmpnam");
6120e3d5408SPeter Wemm 		}
6130e3d5408SPeter Wemm 	    }
6140e3d5408SPeter Wemm 	} else {
6150e3d5408SPeter Wemm 	    /* tic */
6160e3d5408SPeter Wemm 	    fprintf(stderr,
6170e3d5408SPeter Wemm 		    "%s: File name needed.  Usage:\n\t%s %s",
6180e3d5408SPeter Wemm 		    _nc_progname,
6190e3d5408SPeter Wemm 		    _nc_progname,
6200e3d5408SPeter Wemm 		    usage_string);
6210e3d5408SPeter Wemm 	    cleanup();
6220e3d5408SPeter Wemm 	    return EXIT_FAILURE;
6230e3d5408SPeter Wemm 	}
6240e3d5408SPeter Wemm     }
6250e3d5408SPeter Wemm 
62618259542SPeter Wemm     if (tmp_fp == 0)
62718259542SPeter Wemm 	tmp_fp = open_input(source_file);
6280e3d5408SPeter Wemm 
6290e3d5408SPeter Wemm     if (infodump)
6300e3d5408SPeter Wemm 	dump_init(tversion,
6310e3d5408SPeter Wemm 		  smart_defaults
6320e3d5408SPeter Wemm 		  ? outform
6330e3d5408SPeter Wemm 		  : F_LITERAL,
6340e3d5408SPeter Wemm 		  sortmode, width, debug_level, formatted);
6350e3d5408SPeter Wemm     else if (capdump)
6360e3d5408SPeter Wemm 	dump_init(tversion,
6370e3d5408SPeter Wemm 		  outform,
6380e3d5408SPeter Wemm 		  sortmode, width, debug_level, FALSE);
6390e3d5408SPeter Wemm 
6400e3d5408SPeter Wemm     /* parse entries out of the source file */
6410e3d5408SPeter Wemm     _nc_set_source(source_file);
64218259542SPeter Wemm #if !HAVE_BIG_CORE
6430e3d5408SPeter Wemm     if (!(check_only || infodump || capdump))
6440e3d5408SPeter Wemm 	_nc_set_writedir(outdir);
6450e3d5408SPeter Wemm #endif /* HAVE_BIG_CORE */
6460e3d5408SPeter Wemm     _nc_read_entry_source(tmp_fp, (char *) NULL,
6470e3d5408SPeter Wemm 			  !smart_defaults, FALSE,
6480e3d5408SPeter Wemm 			  (check_only || infodump || capdump) ? NULLHOOK : immedhook);
6490e3d5408SPeter Wemm 
6500e3d5408SPeter Wemm     /* do use resolution */
6510e3d5408SPeter Wemm     if (check_only || (!infodump && !capdump) || forceresolve) {
65215589c42SPeter Wemm 	if (!_nc_resolve_uses(TRUE) && !check_only) {
6530e3d5408SPeter Wemm 	    cleanup();
6540e3d5408SPeter Wemm 	    return EXIT_FAILURE;
6550e3d5408SPeter Wemm 	}
6560e3d5408SPeter Wemm     }
6570e3d5408SPeter Wemm 
6580e3d5408SPeter Wemm     /* length check */
65915589c42SPeter Wemm     if (check_only && (capdump || infodump)) {
66015589c42SPeter Wemm 	for_entry_list(qp) {
66115589c42SPeter Wemm 	    if (matches(namelst, qp->tterm.term_names)) {
6620e3d5408SPeter Wemm 		int len = fmt_entry(&qp->tterm, NULL, TRUE, infodump, numbers);
6630e3d5408SPeter Wemm 
6640e3d5408SPeter Wemm 		if (len > (infodump ? MAX_TERMINFO_LENGTH : MAX_TERMCAP_LENGTH))
6650e3d5408SPeter Wemm 		    (void) fprintf(stderr,
6660e3d5408SPeter Wemm 				   "warning: resolved %s entry is %d bytes long\n",
6670e3d5408SPeter Wemm 				   _nc_first_name(qp->tterm.term_names),
6680e3d5408SPeter Wemm 				   len);
6690e3d5408SPeter Wemm 	    }
6700e3d5408SPeter Wemm 	}
6710e3d5408SPeter Wemm     }
6720e3d5408SPeter Wemm 
6730e3d5408SPeter Wemm     /* write or dump all entries */
67415589c42SPeter Wemm     if (!check_only) {
67515589c42SPeter Wemm 	if (!infodump && !capdump) {
6760e3d5408SPeter Wemm 	    _nc_set_writedir(outdir);
67715589c42SPeter Wemm 	    for_entry_list(qp) {
6780e3d5408SPeter Wemm 		if (matches(namelst, qp->tterm.term_names))
6790e3d5408SPeter Wemm 		    write_it(qp);
6800e3d5408SPeter Wemm 	    }
68115589c42SPeter Wemm 	} else {
6820e3d5408SPeter Wemm 	    /* this is in case infotocap() generates warnings */
6830e3d5408SPeter Wemm 	    _nc_curr_col = _nc_curr_line = -1;
6840e3d5408SPeter Wemm 
68515589c42SPeter Wemm 	    for_entry_list(qp) {
68615589c42SPeter Wemm 		if (matches(namelst, qp->tterm.term_names)) {
6870e3d5408SPeter Wemm 		    int j = qp->cend - qp->cstart;
6880e3d5408SPeter Wemm 		    int len = 0;
6890e3d5408SPeter Wemm 
6900e3d5408SPeter Wemm 		    /* this is in case infotocap() generates warnings */
6910e3d5408SPeter Wemm 		    _nc_set_type(_nc_first_name(qp->tterm.term_names));
6920e3d5408SPeter Wemm 
6930e3d5408SPeter Wemm 		    (void) fseek(tmp_fp, qp->cstart, SEEK_SET);
69415589c42SPeter Wemm 		    while (j--) {
6950e3d5408SPeter Wemm 			if (infodump)
6960e3d5408SPeter Wemm 			    (void) putchar(fgetc(tmp_fp));
6970e3d5408SPeter Wemm 			else
6980e3d5408SPeter Wemm 			    put_translate(fgetc(tmp_fp));
69915589c42SPeter Wemm 		    }
7000e3d5408SPeter Wemm 
7010e3d5408SPeter Wemm 		    len = dump_entry(&qp->tterm, limited, numbers, NULL);
7020e3d5408SPeter Wemm 		    for (j = 0; j < qp->nuses; j++)
70315589c42SPeter Wemm 			len += dump_uses(qp->uses[j].name, !capdump);
7040e3d5408SPeter Wemm 		    (void) putchar('\n');
7050e3d5408SPeter Wemm 		    if (debug_level != 0 && !limited)
7060e3d5408SPeter Wemm 			printf("# length=%d\n", len);
7070e3d5408SPeter Wemm 		}
70815589c42SPeter Wemm 	    }
7097a69bbfbSPeter Wemm 	    if (!namelst && _nc_tail) {
7100e3d5408SPeter Wemm 		int c, oldc = '\0';
7110e3d5408SPeter Wemm 		bool in_comment = FALSE;
7120e3d5408SPeter Wemm 		bool trailing_comment = FALSE;
7130e3d5408SPeter Wemm 
7140e3d5408SPeter Wemm 		(void) fseek(tmp_fp, _nc_tail->cend, SEEK_SET);
71515589c42SPeter Wemm 		while ((c = fgetc(tmp_fp)) != EOF) {
7160e3d5408SPeter Wemm 		    if (oldc == '\n') {
7170e3d5408SPeter Wemm 			if (c == '#') {
7180e3d5408SPeter Wemm 			    trailing_comment = TRUE;
7190e3d5408SPeter Wemm 			    in_comment = TRUE;
7200e3d5408SPeter Wemm 			} else {
7210e3d5408SPeter Wemm 			    in_comment = FALSE;
7220e3d5408SPeter Wemm 			}
7230e3d5408SPeter Wemm 		    }
7240e3d5408SPeter Wemm 		    if (trailing_comment
7250e3d5408SPeter Wemm 			&& (in_comment || (oldc == '\n' && c == '\n')))
7260e3d5408SPeter Wemm 			putchar(c);
7270e3d5408SPeter Wemm 		    oldc = c;
7280e3d5408SPeter Wemm 		}
7290e3d5408SPeter Wemm 	    }
7300e3d5408SPeter Wemm 	}
7310e3d5408SPeter Wemm     }
7320e3d5408SPeter Wemm 
7330e3d5408SPeter Wemm     /* Show the directory into which entries were written, and the total
7340e3d5408SPeter Wemm      * number of entries
7350e3d5408SPeter Wemm      */
7360e3d5408SPeter Wemm     if (showsummary
7370e3d5408SPeter Wemm 	&& (!(check_only || infodump || capdump))) {
7380e3d5408SPeter Wemm 	int total = _nc_tic_written();
7390e3d5408SPeter Wemm 	if (total != 0)
7400e3d5408SPeter Wemm 	    fprintf(log_fp, "%d entries written to %s\n",
7410e3d5408SPeter Wemm 		    total,
7420e3d5408SPeter Wemm 		    _nc_tic_dir((char *) 0));
7430e3d5408SPeter Wemm 	else
7440e3d5408SPeter Wemm 	    fprintf(log_fp, "No entries written\n");
7450e3d5408SPeter Wemm     }
7460e3d5408SPeter Wemm     cleanup();
7470e3d5408SPeter Wemm     return (EXIT_SUCCESS);
7480e3d5408SPeter Wemm }
7490e3d5408SPeter Wemm 
7500e3d5408SPeter Wemm /*
7510e3d5408SPeter Wemm  * This bit of legerdemain turns all the terminfo variable names into
7520e3d5408SPeter Wemm  * references to locations in the arrays Booleans, Numbers, and Strings ---
7530e3d5408SPeter Wemm  * precisely what's needed (see comp_parse.c).
7540e3d5408SPeter Wemm  */
7550e3d5408SPeter Wemm 
7560e3d5408SPeter Wemm TERMINAL *cur_term;		/* tweak to avoid linking lib_cur_term.c */
7570e3d5408SPeter Wemm 
7580e3d5408SPeter Wemm #undef CUR
7590e3d5408SPeter Wemm #define CUR tp->
7600e3d5408SPeter Wemm 
76115589c42SPeter Wemm /*
76218259542SPeter Wemm  * Returns the expected number of parameters for the given capability.
76318259542SPeter Wemm  */
76418259542SPeter Wemm static int
7657a69bbfbSPeter Wemm expected_params(const char *name)
76618259542SPeter Wemm {
76718259542SPeter Wemm     /* *INDENT-OFF* */
76818259542SPeter Wemm     static const struct {
76918259542SPeter Wemm 	const char *name;
77018259542SPeter Wemm 	int count;
77118259542SPeter Wemm     } table[] = {
7727a69bbfbSPeter Wemm 	{ "S0",			1 },	/* 'screen' extension */
77318259542SPeter Wemm 	{ "birep",		2 },
77418259542SPeter Wemm 	{ "chr",		1 },
77518259542SPeter Wemm 	{ "colornm",		1 },
77618259542SPeter Wemm 	{ "cpi",		1 },
7777a69bbfbSPeter Wemm 	{ "csnm",		1 },
77818259542SPeter Wemm 	{ "csr",		2 },
77918259542SPeter Wemm 	{ "cub",		1 },
78018259542SPeter Wemm 	{ "cud",		1 },
78118259542SPeter Wemm 	{ "cuf",		1 },
78218259542SPeter Wemm 	{ "cup",		2 },
78318259542SPeter Wemm 	{ "cuu",		1 },
7847a69bbfbSPeter Wemm 	{ "cvr",		1 },
78518259542SPeter Wemm 	{ "cwin",		5 },
78618259542SPeter Wemm 	{ "dch",		1 },
7877a69bbfbSPeter Wemm 	{ "defc",		3 },
78818259542SPeter Wemm 	{ "dial",		1 },
78918259542SPeter Wemm 	{ "dispc",		1 },
79018259542SPeter Wemm 	{ "dl",			1 },
79118259542SPeter Wemm 	{ "ech",		1 },
79218259542SPeter Wemm 	{ "getm",		1 },
79318259542SPeter Wemm 	{ "hpa",		1 },
79418259542SPeter Wemm 	{ "ich",		1 },
79518259542SPeter Wemm 	{ "il",			1 },
79618259542SPeter Wemm 	{ "indn",		1 },
79718259542SPeter Wemm 	{ "initc",		4 },
79818259542SPeter Wemm 	{ "initp",		7 },
79918259542SPeter Wemm 	{ "lpi",		1 },
80018259542SPeter Wemm 	{ "mc5p",		1 },
80118259542SPeter Wemm 	{ "mrcup",		2 },
80218259542SPeter Wemm 	{ "mvpa",		1 },
80318259542SPeter Wemm 	{ "pfkey",		2 },
80418259542SPeter Wemm 	{ "pfloc",		2 },
80518259542SPeter Wemm 	{ "pfx",		2 },
80618259542SPeter Wemm 	{ "pfxl",		3 },
80718259542SPeter Wemm 	{ "pln",		2 },
80818259542SPeter Wemm 	{ "qdial",		1 },
8097a69bbfbSPeter Wemm 	{ "rcsd",		1 },
81018259542SPeter Wemm 	{ "rep",		2 },
81118259542SPeter Wemm 	{ "rin",		1 },
81218259542SPeter Wemm 	{ "sclk",		3 },
81318259542SPeter Wemm 	{ "scp",		1 },
81418259542SPeter Wemm 	{ "scs",		1 },
8157a69bbfbSPeter Wemm 	{ "scsd",		2 },
81618259542SPeter Wemm 	{ "setab",		1 },
81718259542SPeter Wemm 	{ "setaf",		1 },
81818259542SPeter Wemm 	{ "setb",		1 },
81918259542SPeter Wemm 	{ "setcolor",		1 },
82018259542SPeter Wemm 	{ "setf",		1 },
82118259542SPeter Wemm 	{ "sgr",		9 },
82218259542SPeter Wemm 	{ "sgr1",		6 },
82318259542SPeter Wemm 	{ "slength",		1 },
82418259542SPeter Wemm 	{ "slines",		1 },
82518259542SPeter Wemm 	{ "smgbp",		2 },
82618259542SPeter Wemm 	{ "smglp",		2 },
82718259542SPeter Wemm 	{ "smglr",		2 },
82818259542SPeter Wemm 	{ "smgrp",		1 },
82918259542SPeter Wemm 	{ "smgtb",		2 },
8307a69bbfbSPeter Wemm 	{ "smgtp",		1 },
83118259542SPeter Wemm 	{ "tsl",		1 },
83218259542SPeter Wemm 	{ "u6",			-1 },
83318259542SPeter Wemm 	{ "vpa",		1 },
83418259542SPeter Wemm 	{ "wind",		4 },
83518259542SPeter Wemm 	{ "wingo",		1 },
83618259542SPeter Wemm     };
83718259542SPeter Wemm     /* *INDENT-ON* */
83818259542SPeter Wemm 
83918259542SPeter Wemm     unsigned n;
84018259542SPeter Wemm     int result = 0;		/* function-keys, etc., use none */
84118259542SPeter Wemm 
84218259542SPeter Wemm     for (n = 0; n < SIZEOF(table); n++) {
84318259542SPeter Wemm 	if (!strcmp(name, table[n].name)) {
84418259542SPeter Wemm 	    result = table[n].count;
84518259542SPeter Wemm 	    break;
84618259542SPeter Wemm 	}
84718259542SPeter Wemm     }
84818259542SPeter Wemm 
84918259542SPeter Wemm     return result;
85018259542SPeter Wemm }
85118259542SPeter Wemm 
85218259542SPeter Wemm /*
85318259542SPeter Wemm  * Make a quick sanity check for the parameters which are used in the given
85418259542SPeter Wemm  * strings.  If there are no "%p" tokens, then there should be no other "%"
85518259542SPeter Wemm  * markers.
85618259542SPeter Wemm  */
85718259542SPeter Wemm static void
8587a69bbfbSPeter Wemm check_params(TERMTYPE * tp, const char *name, char *value)
85918259542SPeter Wemm {
86018259542SPeter Wemm     int expected = expected_params(name);
86118259542SPeter Wemm     int actual = 0;
86218259542SPeter Wemm     int n;
86318259542SPeter Wemm     bool params[10];
86418259542SPeter Wemm     char *s = value;
86518259542SPeter Wemm 
86618259542SPeter Wemm     for (n = 0; n < 10; n++)
86718259542SPeter Wemm 	params[n] = FALSE;
86818259542SPeter Wemm 
86918259542SPeter Wemm     while (*s != 0) {
87018259542SPeter Wemm 	if (*s == '%') {
87118259542SPeter Wemm 	    if (*++s == '\0') {
87218259542SPeter Wemm 		_nc_warning("expected character after %% in %s", name);
87318259542SPeter Wemm 		break;
87418259542SPeter Wemm 	    } else if (*s == 'p') {
87518259542SPeter Wemm 		if (*++s == '\0' || !isdigit((int) *s)) {
87618259542SPeter Wemm 		    _nc_warning("expected digit after %%p in %s", name);
87718259542SPeter Wemm 		    return;
87818259542SPeter Wemm 		} else {
87918259542SPeter Wemm 		    n = (*s - '0');
88018259542SPeter Wemm 		    if (n > actual)
88118259542SPeter Wemm 			actual = n;
88218259542SPeter Wemm 		    params[n] = TRUE;
88318259542SPeter Wemm 		}
88418259542SPeter Wemm 	    }
88518259542SPeter Wemm 	}
88618259542SPeter Wemm 	s++;
88718259542SPeter Wemm     }
88818259542SPeter Wemm 
88918259542SPeter Wemm     if (params[0]) {
89018259542SPeter Wemm 	_nc_warning("%s refers to parameter 0 (%%p0), which is not allowed", name);
89118259542SPeter Wemm     }
89218259542SPeter Wemm     if (value == set_attributes || expected < 0) {
89318259542SPeter Wemm 	;
89418259542SPeter Wemm     } else if (expected != actual) {
89518259542SPeter Wemm 	_nc_warning("%s uses %d parameters, expected %d", name,
89618259542SPeter Wemm 		    actual, expected);
89718259542SPeter Wemm 	for (n = 1; n < actual; n++) {
89818259542SPeter Wemm 	    if (!params[n])
89918259542SPeter Wemm 		_nc_warning("%s omits parameter %d", name, n);
90018259542SPeter Wemm 	}
90118259542SPeter Wemm     }
90218259542SPeter Wemm }
90318259542SPeter Wemm 
90418259542SPeter Wemm /*
90515589c42SPeter Wemm  * An sgr string may contain several settings other than the one we're
90615589c42SPeter Wemm  * interested in, essentially sgr0 + rmacs + whatever.  As long as the
90715589c42SPeter Wemm  * "whatever" is contained in the sgr string, that is close enough for our
90815589c42SPeter Wemm  * sanity check.
90915589c42SPeter Wemm  */
91015589c42SPeter Wemm static bool
91115589c42SPeter Wemm similar_sgr(char *a, char *b)
91215589c42SPeter Wemm {
91315589c42SPeter Wemm     while (*b != 0) {
91415589c42SPeter Wemm 	while (*a != *b) {
9157a69bbfbSPeter Wemm 	    if (*a == 0) {
9167a69bbfbSPeter Wemm 		if (b[0] == '$'
9177a69bbfbSPeter Wemm 		    && b[1] == '<') {
9187a69bbfbSPeter Wemm 		    _nc_warning("Did not find delay %s", _nc_visbuf(b));
9197a69bbfbSPeter Wemm 		} else {
9207a69bbfbSPeter Wemm 		    _nc_warning("Unmatched portion %s", _nc_visbuf(b));
9217a69bbfbSPeter Wemm 		}
92215589c42SPeter Wemm 		return FALSE;
9237a69bbfbSPeter Wemm 	    }
92415589c42SPeter Wemm 	    a++;
92515589c42SPeter Wemm 	}
92615589c42SPeter Wemm 	a++;
92715589c42SPeter Wemm 	b++;
92815589c42SPeter Wemm     }
92915589c42SPeter Wemm     return TRUE;
93015589c42SPeter Wemm }
93115589c42SPeter Wemm 
93215589c42SPeter Wemm static void
93315589c42SPeter Wemm check_sgr(TERMTYPE * tp, char *zero, int num, char *cap, const char *name)
93415589c42SPeter Wemm {
93515589c42SPeter Wemm     char *test = tparm(set_attributes,
93615589c42SPeter Wemm 		       num == 1,
93715589c42SPeter Wemm 		       num == 2,
93815589c42SPeter Wemm 		       num == 3,
93915589c42SPeter Wemm 		       num == 4,
94015589c42SPeter Wemm 		       num == 5,
94115589c42SPeter Wemm 		       num == 6,
94215589c42SPeter Wemm 		       num == 7,
94315589c42SPeter Wemm 		       num == 8,
94415589c42SPeter Wemm 		       num == 9);
9457a69bbfbSPeter Wemm     tparm_errs += _nc_tparm_err;
94615589c42SPeter Wemm     if (test != 0) {
94715589c42SPeter Wemm 	if (PRESENT(cap)) {
94815589c42SPeter Wemm 	    if (!similar_sgr(test, cap)) {
94915589c42SPeter Wemm 		_nc_warning("%s differs from sgr(%d): %s", name, num,
95015589c42SPeter Wemm 			    _nc_visbuf(test));
95115589c42SPeter Wemm 	    }
95215589c42SPeter Wemm 	} else if (strcmp(test, zero)) {
95315589c42SPeter Wemm 	    _nc_warning("sgr(%d) present, but not %s", num, name);
95415589c42SPeter Wemm 	}
95515589c42SPeter Wemm     } else if (PRESENT(cap)) {
95615589c42SPeter Wemm 	_nc_warning("sgr(%d) missing, but %s present", num, name);
95715589c42SPeter Wemm     }
95815589c42SPeter Wemm }
95915589c42SPeter Wemm 
96015589c42SPeter Wemm #define CHECK_SGR(num,name) check_sgr(tp, zero, num, name, #name)
96115589c42SPeter Wemm 
9620e3d5408SPeter Wemm /* other sanity-checks (things that we don't want in the normal
9630e3d5408SPeter Wemm  * logic that reads a terminfo entry)
9640e3d5408SPeter Wemm  */
96515589c42SPeter Wemm static void
96615589c42SPeter Wemm check_termtype(TERMTYPE * tp)
9670e3d5408SPeter Wemm {
9680e3d5408SPeter Wemm     bool conflict = FALSE;
9690e3d5408SPeter Wemm     unsigned j, k;
9700e3d5408SPeter Wemm     char fkeys[STRCOUNT];
9710e3d5408SPeter Wemm 
9720e3d5408SPeter Wemm     /*
9730e3d5408SPeter Wemm      * A terminal entry may contain more than one keycode assigned to
9740e3d5408SPeter Wemm      * a given string (e.g., KEY_END and KEY_LL).  But curses will only
9750e3d5408SPeter Wemm      * return one (the last one assigned).
9760e3d5408SPeter Wemm      */
9770e3d5408SPeter Wemm     memset(fkeys, 0, sizeof(fkeys));
9780e3d5408SPeter Wemm     for (j = 0; _nc_tinfo_fkeys[j].code; j++) {
9790e3d5408SPeter Wemm 	char *a = tp->Strings[_nc_tinfo_fkeys[j].offset];
9800e3d5408SPeter Wemm 	bool first = TRUE;
9810e3d5408SPeter Wemm 	if (!VALID_STRING(a))
9820e3d5408SPeter Wemm 	    continue;
9830e3d5408SPeter Wemm 	for (k = j + 1; _nc_tinfo_fkeys[k].code; k++) {
9840e3d5408SPeter Wemm 	    char *b = tp->Strings[_nc_tinfo_fkeys[k].offset];
9850e3d5408SPeter Wemm 	    if (!VALID_STRING(b)
9860e3d5408SPeter Wemm 		|| fkeys[k])
9870e3d5408SPeter Wemm 		continue;
9880e3d5408SPeter Wemm 	    if (!strcmp(a, b)) {
9890e3d5408SPeter Wemm 		fkeys[j] = 1;
9900e3d5408SPeter Wemm 		fkeys[k] = 1;
9910e3d5408SPeter Wemm 		if (first) {
9920e3d5408SPeter Wemm 		    if (!conflict) {
9930e3d5408SPeter Wemm 			_nc_warning("Conflicting key definitions (using the last)");
9940e3d5408SPeter Wemm 			conflict = TRUE;
9950e3d5408SPeter Wemm 		    }
9960e3d5408SPeter Wemm 		    fprintf(stderr, "... %s is the same as %s",
9970e3d5408SPeter Wemm 			    keyname(_nc_tinfo_fkeys[j].code),
9980e3d5408SPeter Wemm 			    keyname(_nc_tinfo_fkeys[k].code));
9990e3d5408SPeter Wemm 		    first = FALSE;
10000e3d5408SPeter Wemm 		} else {
10010e3d5408SPeter Wemm 		    fprintf(stderr, ", %s",
10020e3d5408SPeter Wemm 			    keyname(_nc_tinfo_fkeys[k].code));
10030e3d5408SPeter Wemm 		}
10040e3d5408SPeter Wemm 	    }
10050e3d5408SPeter Wemm 	}
10060e3d5408SPeter Wemm 	if (!first)
10070e3d5408SPeter Wemm 	    fprintf(stderr, "\n");
10080e3d5408SPeter Wemm     }
10090e3d5408SPeter Wemm 
101018259542SPeter Wemm     for (j = 0; j < NUM_STRINGS(tp); j++) {
101118259542SPeter Wemm 	char *a = tp->Strings[j];
101218259542SPeter Wemm 	if (VALID_STRING(a))
101318259542SPeter Wemm 	    check_params(tp, ExtStrname(tp, j, strnames), a);
101418259542SPeter Wemm     }
101518259542SPeter Wemm 
10160e3d5408SPeter Wemm     /*
10170e3d5408SPeter Wemm      * Quick check for color.  We could also check if the ANSI versus
10180e3d5408SPeter Wemm      * non-ANSI strings are misused.
10190e3d5408SPeter Wemm      */
10200e3d5408SPeter Wemm     if ((max_colors > 0) != (max_pairs > 0)
10210e3d5408SPeter Wemm 	|| (max_colors > max_pairs))
10220e3d5408SPeter Wemm 	_nc_warning("inconsistent values for max_colors and max_pairs");
10230e3d5408SPeter Wemm 
102415589c42SPeter Wemm     PAIRED(set_foreground, set_background);
102515589c42SPeter Wemm     PAIRED(set_a_foreground, set_a_background);
10260e3d5408SPeter Wemm 
10270e3d5408SPeter Wemm     /*
10280e3d5408SPeter Wemm      * These may be mismatched because the terminal description relies on
10290e3d5408SPeter Wemm      * restoring the cursor visibility by resetting it.
10300e3d5408SPeter Wemm      */
103115589c42SPeter Wemm     ANDMISSING(cursor_invisible, cursor_normal);
103215589c42SPeter Wemm     ANDMISSING(cursor_visible, cursor_normal);
103315589c42SPeter Wemm 
103415589c42SPeter Wemm     if (PRESENT(cursor_visible) && PRESENT(cursor_normal)
103515589c42SPeter Wemm 	&& !strcmp(cursor_visible, cursor_normal))
103615589c42SPeter Wemm 	_nc_warning("cursor_visible is same as cursor_normal");
10370e3d5408SPeter Wemm 
10380e3d5408SPeter Wemm     /*
10390e3d5408SPeter Wemm      * From XSI & O'Reilly, we gather that sc/rc are required if csr is
10400e3d5408SPeter Wemm      * given, because the cursor position after the scrolling operation is
10410e3d5408SPeter Wemm      * performed is undefined.
10420e3d5408SPeter Wemm      */
104315589c42SPeter Wemm     ANDMISSING(change_scroll_region, save_cursor);
104415589c42SPeter Wemm     ANDMISSING(change_scroll_region, restore_cursor);
104515589c42SPeter Wemm 
10467a69bbfbSPeter Wemm     tparm_errs = 0;
104715589c42SPeter Wemm     if (PRESENT(set_attributes)) {
104815589c42SPeter Wemm 	char *zero = tparm(set_attributes, 0, 0, 0, 0, 0, 0, 0, 0, 0);
104915589c42SPeter Wemm 
105015589c42SPeter Wemm 	zero = strdup(zero);
105115589c42SPeter Wemm 	CHECK_SGR(1, enter_standout_mode);
105215589c42SPeter Wemm 	CHECK_SGR(2, enter_underline_mode);
105315589c42SPeter Wemm 	CHECK_SGR(3, enter_reverse_mode);
105415589c42SPeter Wemm 	CHECK_SGR(4, enter_blink_mode);
105515589c42SPeter Wemm 	CHECK_SGR(5, enter_dim_mode);
105615589c42SPeter Wemm 	CHECK_SGR(6, enter_bold_mode);
105715589c42SPeter Wemm 	CHECK_SGR(7, enter_secure_mode);
105815589c42SPeter Wemm 	CHECK_SGR(8, enter_protected_mode);
105915589c42SPeter Wemm 	CHECK_SGR(9, enter_alt_charset_mode);
106015589c42SPeter Wemm 	free(zero);
10617a69bbfbSPeter Wemm 	if (tparm_errs)
10627a69bbfbSPeter Wemm 	    _nc_warning("stack error in sgr string");
106315589c42SPeter Wemm     }
10640e3d5408SPeter Wemm 
10650e3d5408SPeter Wemm     /*
10660e3d5408SPeter Wemm      * Some standard applications (e.g., vi) and some non-curses
10670e3d5408SPeter Wemm      * applications (e.g., jove) get confused if we have both ich/ich1 and
10680e3d5408SPeter Wemm      * smir/rmir.  Let's be nice and warn about that, too, even though
10690e3d5408SPeter Wemm      * ncurses handles it.
10700e3d5408SPeter Wemm      */
10710e3d5408SPeter Wemm     if ((PRESENT(enter_insert_mode) || PRESENT(exit_insert_mode))
10720e3d5408SPeter Wemm 	&& (PRESENT(insert_character) || PRESENT(parm_ich))) {
10730e3d5408SPeter Wemm 	_nc_warning("non-curses applications may be confused by ich/ich1 with smir/rmir");
10740e3d5408SPeter Wemm     }
10750e3d5408SPeter Wemm 
10760e3d5408SPeter Wemm     /*
10770e3d5408SPeter Wemm      * Finally, do the non-verbose checks
10780e3d5408SPeter Wemm      */
10790e3d5408SPeter Wemm     if (save_check_termtype != 0)
10800e3d5408SPeter Wemm 	save_check_termtype(tp);
10810e3d5408SPeter Wemm }
1082