150276Speter/****************************************************************************
2176187Srafan * Copyright (c) 1998-2007,2008 Free Software Foundation, Inc.              *
350276Speter *                                                                          *
450276Speter * Permission is hereby granted, free of charge, to any person obtaining a  *
550276Speter * copy of this software and associated documentation files (the            *
650276Speter * "Software"), to deal in the Software without restriction, including      *
750276Speter * without limitation the rights to use, copy, modify, merge, publish,      *
850276Speter * distribute, distribute with modifications, sublicense, and/or sell       *
950276Speter * copies of the Software, and to permit persons to whom the Software is    *
1050276Speter * furnished to do so, subject to the following conditions:                 *
1150276Speter *                                                                          *
1250276Speter * The above copyright notice and this permission notice shall be included  *
1350276Speter * in all copies or substantial portions of the Software.                   *
1450276Speter *                                                                          *
1550276Speter * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
1650276Speter * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
1750276Speter * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
1850276Speter * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
1950276Speter * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
2050276Speter * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
2150276Speter * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
2250276Speter *                                                                          *
2350276Speter * Except as contained in this notice, the name(s) of the above copyright   *
2450276Speter * holders shall not be used in advertising or otherwise to promote the     *
2550276Speter * sale, use or other dealings in this Software without prior written       *
2650276Speter * authorization.                                                           *
2750276Speter ****************************************************************************/
2850276Speter
2950276Speter/****************************************************************************
3050276Speter *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
3150276Speter *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
32166124Srafan *     and: Thomas E. Dickey                        1996-on                 *
3350276Speter ****************************************************************************/
3450276Speter
3550276Speter/*
3650276Speter *	infocmp.c -- decompile an entry, or compare two entries
3750276Speter *		written by Eric S. Raymond
38174993Srafan *		and Thomas E Dickey
3950276Speter */
4050276Speter
4150276Speter#include <progs.priv.h>
4250276Speter
4350276Speter#include <dump_entry.h>
4450276Speter
45184989SrafanMODULE_ID("$Id: infocmp.c,v 1.103 2008/08/16 22:04:56 tom Exp $")
4650276Speter
4750276Speter#define L_CURL "{"
4850276Speter#define R_CURL "}"
4950276Speter
5062449Speter#define MAX_STRING	1024	/* maximum formatted string */
5150276Speter
5250276Speterconst char *_nc_progname = "infocmp";
5350276Speter
5462449Spetertypedef char path[PATH_MAX];
5550276Speter
5650276Speter/***************************************************************************
5750276Speter *
5850276Speter * The following control variables, together with the contents of the
5950276Speter * terminfo entries, completely determine the actions of the program.
6050276Speter *
6150276Speter ***************************************************************************/
6250276Speter
63174993Srafanstatic ENTRY *entries;		/* terminfo entries */
6450276Speterstatic int termcount;		/* count of terminal entries */
6550276Speter
6662449Speterstatic bool limited = TRUE;	/* "-r" option is not set */
6762449Speterstatic bool quiet = FALSE;
68166124Srafanstatic bool literal = FALSE;
6962449Speterstatic const char *bool_sep = ":";
7062449Speterstatic const char *s_absent = "NULL";
7162449Speterstatic const char *s_cancel = "NULL";
7250276Speterstatic const char *tversion;	/* terminfo version selected */
7362449Speterstatic int itrace;		/* trace flag for debugging */
7462449Speterstatic int mwidth = 60;
7550276Speterstatic int numbers = 0;		/* format "%'char'" to/from "%{number}" */
7666963Speterstatic int outform = F_TERMINFO;	/* output format */
7750276Speterstatic int sortmode;		/* sort_mode */
7850276Speter
7950276Speter/* main comparison mode */
8050276Speterstatic int compare;
8150276Speter#define C_DEFAULT	0	/* don't force comparison mode */
8250276Speter#define C_DIFFERENCE	1	/* list differences between two terminals */
8350276Speter#define C_COMMON	2	/* list common capabilities */
8450276Speter#define C_NAND		3	/* list capabilities in neither terminal */
8550276Speter#define C_USEALL	4	/* generate relative use-form entry */
8650276Speterstatic bool ignorepads;		/* ignore pad prefixes when diffing */
8750276Speter
8850276Speter#if NO_LEAKS
8950276Speter#undef ExitProgram
90166124Srafanstatic void ExitProgram(int code) GCC_NORETURN;
91166124Srafan/* prototype is to get gcc to accept the noreturn attribute */
9262449Speterstatic void
93166124SrafanExitProgram(int code)
9450276Speter{
9562449Speter    while (termcount-- > 0)
9662449Speter	_nc_free_termtype(&entries[termcount].tterm);
9762449Speter    _nc_leaks_dump_entry();
98174993Srafan    free(entries);
99174993Srafan    _nc_free_tic(code);
10050276Speter}
10150276Speter#endif
10250276Speter
10362449Speterstatic char *
10462449Spetercanonical_name(char *ptr, char *buf)
10550276Speter/* extract the terminal type's primary name */
10650276Speter{
10762449Speter    char *bp;
10850276Speter
10950276Speter    (void) strcpy(buf, ptr);
11062449Speter    if ((bp = strchr(buf, '|')) != 0)
11150276Speter	*bp = '\0';
11250276Speter
11362449Speter    return (buf);
11450276Speter}
11550276Speter
11650276Speter/***************************************************************************
11750276Speter *
11850276Speter * Predicates for dump function
11950276Speter *
12050276Speter ***************************************************************************/
12150276Speter
12262449Speterstatic int
123166124Srafancapcmp(PredIdx idx, const char *s, const char *t)
12450276Speter/* capability comparison function */
12550276Speter{
12650276Speter    if (!VALID_STRING(s) && !VALID_STRING(t))
12762449Speter	return (s != t);
12850276Speter    else if (!VALID_STRING(s) || !VALID_STRING(t))
12962449Speter	return (1);
13050276Speter
13162449Speter    if ((idx == acs_chars_index) || !ignorepads)
13262449Speter	return (strcmp(s, t));
13350276Speter    else
13462449Speter	return (_nc_capcmp(s, t));
13550276Speter}
13650276Speter
13762449Speterstatic int
138166124Srafanuse_predicate(unsigned type, PredIdx idx)
13950276Speter/* predicate function to use for use decompilation */
14050276Speter{
14162449Speter    ENTRY *ep;
14250276Speter
14362449Speter    switch (type) {
14462449Speter    case BOOLEAN:
14550276Speter	{
14662449Speter	    int is_set = FALSE;
14750276Speter
14862449Speter	    /*
14962449Speter	     * This assumes that multiple use entries are supposed
15062449Speter	     * to contribute the logical or of their boolean capabilities.
15162449Speter	     * This is true if we take the semantics of multiple uses to
15262449Speter	     * be 'each capability gets the first non-default value found
15362449Speter	     * in the sequence of use entries'.
15462449Speter	     *
15562449Speter	     * Note that cancelled or absent booleans are stored as FALSE,
15662449Speter	     * unlike numbers and strings, whose cancelled/absent state is
15762449Speter	     * recorded in the terminfo database.
15862449Speter	     */
15962449Speter	    for (ep = &entries[1]; ep < entries + termcount; ep++)
16062449Speter		if (ep->tterm.Booleans[idx] == TRUE) {
16162449Speter		    is_set = entries[0].tterm.Booleans[idx];
16262449Speter		    break;
16350276Speter		}
16462449Speter	    if (is_set != entries[0].tterm.Booleans[idx])
16562449Speter		return (!is_set);
16662449Speter	    else
16762449Speter		return (FAIL);
16862449Speter	}
16950276Speter
17062449Speter    case NUMBER:
17162449Speter	{
17262449Speter	    int value = ABSENT_NUMERIC;
17350276Speter
17462449Speter	    /*
17562449Speter	     * We take the semantics of multiple uses to be 'each
17662449Speter	     * capability gets the first non-default value found
17762449Speter	     * in the sequence of use entries'.
17862449Speter	     */
17962449Speter	    for (ep = &entries[1]; ep < entries + termcount; ep++)
18062449Speter		if (VALID_NUMERIC(ep->tterm.Numbers[idx])) {
18162449Speter		    value = ep->tterm.Numbers[idx];
18262449Speter		    break;
18362449Speter		}
18450276Speter
18562449Speter	    if (value != entries[0].tterm.Numbers[idx])
18662449Speter		return (value != ABSENT_NUMERIC);
18762449Speter	    else
18862449Speter		return (FAIL);
18962449Speter	}
19062449Speter
19162449Speter    case STRING:
19262449Speter	{
19362449Speter	    char *termstr, *usestr = ABSENT_STRING;
19462449Speter
19562449Speter	    termstr = entries[0].tterm.Strings[idx];
19662449Speter
19762449Speter	    /*
19862449Speter	     * We take the semantics of multiple uses to be 'each
19962449Speter	     * capability gets the first non-default value found
20062449Speter	     * in the sequence of use entries'.
20162449Speter	     */
20262449Speter	    for (ep = &entries[1]; ep < entries + termcount; ep++)
20362449Speter		if (ep->tterm.Strings[idx]) {
20462449Speter		    usestr = ep->tterm.Strings[idx];
20562449Speter		    break;
20650276Speter		}
20750276Speter
20862449Speter	    if (usestr == ABSENT_STRING && termstr == ABSENT_STRING)
20962449Speter		return (FAIL);
21062449Speter	    else if (!usestr || !termstr || capcmp(idx, usestr, termstr))
21162449Speter		return (TRUE);
21262449Speter	    else
21362449Speter		return (FAIL);
21462449Speter	}
21562449Speter    }
21650276Speter
21762449Speter    return (FALSE);		/* pacify compiler */
21862449Speter}
21950276Speter
22062449Speterstatic bool
22162449Speteruseeq(ENTRY * e1, ENTRY * e2)
22262449Speter/* are the use references in two entries equivalent? */
22362449Speter{
224184989Srafan    unsigned i, j;
22550276Speter
22662449Speter    if (e1->nuses != e2->nuses)
22762449Speter	return (FALSE);
22862449Speter
22962449Speter    /* Ugh...this is quadratic again */
23062449Speter    for (i = 0; i < e1->nuses; i++) {
23162449Speter	bool foundmatch = FALSE;
23262449Speter
23362449Speter	/* search second entry for given use reference */
23462449Speter	for (j = 0; j < e2->nuses; j++)
23562449Speter	    if (!strcmp(e1->uses[i].name, e2->uses[j].name)) {
23662449Speter		foundmatch = TRUE;
23762449Speter		break;
23850276Speter	    }
23950276Speter
24062449Speter	if (!foundmatch)
24162449Speter	    return (FALSE);
24262449Speter    }
24362449Speter
24462449Speter    return (TRUE);
24550276Speter}
24650276Speter
24762449Speterstatic bool
248166124Srafanentryeq(TERMTYPE *t1, TERMTYPE *t2)
24962449Speter/* are two entries equivalent? */
25050276Speter{
251166124Srafan    unsigned i;
25250276Speter
25350276Speter    for (i = 0; i < NUM_BOOLEANS(t1); i++)
25450276Speter	if (t1->Booleans[i] != t2->Booleans[i])
25562449Speter	    return (FALSE);
25650276Speter
25750276Speter    for (i = 0; i < NUM_NUMBERS(t1); i++)
25850276Speter	if (t1->Numbers[i] != t2->Numbers[i])
25962449Speter	    return (FALSE);
26050276Speter
26150276Speter    for (i = 0; i < NUM_STRINGS(t1); i++)
262166124Srafan	if (capcmp((PredIdx) i, t1->Strings[i], t2->Strings[i]))
26362449Speter	    return (FALSE);
26450276Speter
26562449Speter    return (TRUE);
26650276Speter}
26750276Speter
26850276Speter#define TIC_EXPAND(result) _nc_tic_expand(result, outform==F_TERMINFO, numbers)
26950276Speter
27062449Speterstatic void
271166124Srafanprint_uses(ENTRY * ep, FILE *fp)
27262449Speter/* print an entry's use references */
27362449Speter{
274184989Srafan    unsigned i;
27562449Speter
27662449Speter    if (!ep->nuses)
27762449Speter	fputs("NULL", fp);
27862449Speter    else
27962449Speter	for (i = 0; i < ep->nuses; i++) {
28062449Speter	    fputs(ep->uses[i].name, fp);
28162449Speter	    if (i < ep->nuses - 1)
28262449Speter		fputs(" ", fp);
28362449Speter	}
28462449Speter}
28562449Speter
28662449Speterstatic const char *
28762449Speterdump_boolean(int val)
28862449Speter/* display the value of a boolean capability */
28962449Speter{
29062449Speter    switch (val) {
29162449Speter    case ABSENT_BOOLEAN:
29262449Speter	return (s_absent);
29362449Speter    case CANCELLED_BOOLEAN:
29462449Speter	return (s_cancel);
29562449Speter    case FALSE:
29662449Speter	return ("F");
29762449Speter    case TRUE:
29862449Speter	return ("T");
29962449Speter    default:
30062449Speter	return ("?");
30162449Speter    }
30262449Speter}
30362449Speter
30462449Speterstatic void
30562449Speterdump_numeric(int val, char *buf)
30662449Speter/* display the value of a boolean capability */
30762449Speter{
30862449Speter    switch (val) {
30962449Speter    case ABSENT_NUMERIC:
31062449Speter	strcpy(buf, s_absent);
31162449Speter	break;
31262449Speter    case CANCELLED_NUMERIC:
31362449Speter	strcpy(buf, s_cancel);
31462449Speter	break;
31562449Speter    default:
31662449Speter	sprintf(buf, "%d", val);
31762449Speter	break;
31862449Speter    }
31962449Speter}
32062449Speter
32162449Speterstatic void
32262449Speterdump_string(char *val, char *buf)
32362449Speter/* display the value of a string capability */
32462449Speter{
32562449Speter    if (val == ABSENT_STRING)
32662449Speter	strcpy(buf, s_absent);
32762449Speter    else if (val == CANCELLED_STRING)
32862449Speter	strcpy(buf, s_cancel);
32962449Speter    else {
33062449Speter	sprintf(buf, "'%.*s'", MAX_STRING - 3, TIC_EXPAND(val));
33162449Speter    }
33262449Speter}
33362449Speter
33462449Speterstatic void
335166124Srafancompare_predicate(PredType type, PredIdx idx, const char *name)
33650276Speter/* predicate function to use for entry difference reports */
33750276Speter{
33862449Speter    register ENTRY *e1 = &entries[0];
33962449Speter    register ENTRY *e2 = &entries[1];
34062449Speter    char buf1[MAX_STRING], buf2[MAX_STRING];
34162449Speter    int b1, b2;
34262449Speter    int n1, n2;
34362449Speter    char *s1, *s2;
34450276Speter
34562449Speter    switch (type) {
34662449Speter    case CMP_BOOLEAN:
34762449Speter	b1 = e1->tterm.Booleans[idx];
34862449Speter	b2 = e2->tterm.Booleans[idx];
34962449Speter	switch (compare) {
35062449Speter	case C_DIFFERENCE:
35162449Speter	    if (!(b1 == ABSENT_BOOLEAN && b2 == ABSENT_BOOLEAN) && b1 != b2)
35262449Speter		(void) printf("\t%s: %s%s%s.\n",
35366963Speter			      name,
35466963Speter			      dump_boolean(b1),
35566963Speter			      bool_sep,
35666963Speter			      dump_boolean(b2));
35762449Speter	    break;
35850276Speter
35962449Speter	case C_COMMON:
36062449Speter	    if (b1 == b2 && b1 != ABSENT_BOOLEAN)
36162449Speter		(void) printf("\t%s= %s.\n", name, dump_boolean(b1));
36262449Speter	    break;
36350276Speter
36462449Speter	case C_NAND:
36562449Speter	    if (b1 == ABSENT_BOOLEAN && b2 == ABSENT_BOOLEAN)
36662449Speter		(void) printf("\t!%s.\n", name);
36762449Speter	    break;
36862449Speter	}
36962449Speter	break;
37050276Speter
37162449Speter    case CMP_NUMBER:
37262449Speter	n1 = e1->tterm.Numbers[idx];
37362449Speter	n2 = e2->tterm.Numbers[idx];
37462449Speter	dump_numeric(n1, buf1);
37562449Speter	dump_numeric(n2, buf2);
37662449Speter	switch (compare) {
37762449Speter	case C_DIFFERENCE:
37862449Speter	    if (!((n1 == ABSENT_NUMERIC && n2 == ABSENT_NUMERIC)) && n1 != n2)
37962449Speter		(void) printf("\t%s: %s, %s.\n", name, buf1, buf2);
38062449Speter	    break;
38150276Speter
38262449Speter	case C_COMMON:
38362449Speter	    if (n1 != ABSENT_NUMERIC && n2 != ABSENT_NUMERIC && n1 == n2)
38462449Speter		(void) printf("\t%s= %s.\n", name, buf1);
38562449Speter	    break;
38650276Speter
38762449Speter	case C_NAND:
38862449Speter	    if (n1 == ABSENT_NUMERIC && n2 == ABSENT_NUMERIC)
38962449Speter		(void) printf("\t!%s.\n", name);
39062449Speter	    break;
39162449Speter	}
39250276Speter	break;
39350276Speter
39462449Speter    case CMP_STRING:
39562449Speter	s1 = e1->tterm.Strings[idx];
39662449Speter	s2 = e2->tterm.Strings[idx];
39762449Speter	switch (compare) {
39862449Speter	case C_DIFFERENCE:
39962449Speter	    if (capcmp(idx, s1, s2)) {
40062449Speter		dump_string(s1, buf1);
40162449Speter		dump_string(s2, buf2);
40262449Speter		if (strcmp(buf1, buf2))
40362449Speter		    (void) printf("\t%s: %s, %s.\n", name, buf1, buf2);
40462449Speter	    }
40562449Speter	    break;
40650276Speter
40762449Speter	case C_COMMON:
40862449Speter	    if (s1 && s2 && !capcmp(idx, s1, s2))
40962449Speter		(void) printf("\t%s= '%s'.\n", name, TIC_EXPAND(s1));
41062449Speter	    break;
41150276Speter
41262449Speter	case C_NAND:
41362449Speter	    if (!s1 && !s2)
41462449Speter		(void) printf("\t!%s.\n", name);
41562449Speter	    break;
41662449Speter	}
41762449Speter	break;
41850276Speter
41962449Speter    case CMP_USE:
42062449Speter	/* unlike the other modes, this compares *all* use entries */
42162449Speter	switch (compare) {
42262449Speter	case C_DIFFERENCE:
42362449Speter	    if (!useeq(e1, e2)) {
42462449Speter		(void) fputs("\tuse: ", stdout);
42562449Speter		print_uses(e1, stdout);
42662449Speter		fputs(", ", stdout);
42762449Speter		print_uses(e2, stdout);
42862449Speter		fputs(".\n", stdout);
42962449Speter	    }
43062449Speter	    break;
43150276Speter
43262449Speter	case C_COMMON:
43362449Speter	    if (e1->nuses && e2->nuses && useeq(e1, e2)) {
43462449Speter		(void) fputs("\tuse: ", stdout);
43562449Speter		print_uses(e1, stdout);
43662449Speter		fputs(".\n", stdout);
43762449Speter	    }
43862449Speter	    break;
43950276Speter
44062449Speter	case C_NAND:
44162449Speter	    if (!e1->nuses && !e2->nuses)
44262449Speter		(void) printf("\t!use.\n");
44362449Speter	    break;
44450276Speter	}
44562449Speter    }
44650276Speter}
44750276Speter
44850276Speter/***************************************************************************
44950276Speter *
45050276Speter * Init string analysis
45150276Speter *
45250276Speter ***************************************************************************/
45350276Speter
45462449Spetertypedef struct {
45562449Speter    const char *from;
45662449Speter    const char *to;
45762449Speter} assoc;
45850276Speter
45950276Speterstatic const assoc std_caps[] =
46050276Speter{
46150276Speter    /* these are specified by X.364 and iBCS2 */
46262449Speter    {"\033c", "RIS"},		/* full reset */
46362449Speter    {"\0337", "SC"},		/* save cursor */
46462449Speter    {"\0338", "RC"},		/* restore cursor */
46562449Speter    {"\033[r", "RSR"},		/* not an X.364 mnemonic */
46662449Speter    {"\033[m", "SGR0"},		/* not an X.364 mnemonic */
46762449Speter    {"\033[2J", "ED2"},		/* clear page */
46850276Speter
46950276Speter    /* this group is specified by ISO 2022 */
47062449Speter    {"\033(0", "ISO DEC G0"},	/* enable DEC graphics for G0 */
47162449Speter    {"\033(A", "ISO UK G0"},	/* enable UK chars for G0 */
47262449Speter    {"\033(B", "ISO US G0"},	/* enable US chars for G0 */
47362449Speter    {"\033)0", "ISO DEC G1"},	/* enable DEC graphics for G1 */
47462449Speter    {"\033)A", "ISO UK G1"},	/* enable UK chars for G1 */
47562449Speter    {"\033)B", "ISO US G1"},	/* enable US chars for G1 */
47650276Speter
477166124Srafan    /* these are DEC private controls widely supported by emulators */
47862449Speter    {"\033=", "DECPAM"},	/* application keypad mode */
47962449Speter    {"\033>", "DECPNM"},	/* normal keypad mode */
48062449Speter    {"\033<", "DECANSI"},	/* enter ANSI mode */
481166124Srafan    {"\033[!p", "DECSTR"},	/* soft reset */
482166124Srafan    {"\033 F", "S7C1T"},	/* 7-bit controls */
48350276Speter
48462449Speter    {(char *) 0, (char *) 0}
48550276Speter};
48650276Speter
487166124Srafanstatic const assoc std_modes[] =
488166124Srafan/* ECMA \E[ ... [hl] modes recognized by many emulators */
489166124Srafan{
490166124Srafan    {"2", "AM"},		/* keyboard action mode */
491166124Srafan    {"4", "IRM"},		/* insert/replace mode */
492166124Srafan    {"12", "SRM"},		/* send/receive mode */
493166124Srafan    {"20", "LNM"},		/* linefeed mode */
494166124Srafan    {(char *) 0, (char *) 0}
495166124Srafan};
496166124Srafan
49750276Speterstatic const assoc private_modes[] =
49850276Speter/* DEC \E[ ... [hl] modes recognized by many emulators */
49950276Speter{
50062449Speter    {"1", "CKM"},		/* application cursor keys */
50162449Speter    {"2", "ANM"},		/* set VT52 mode */
50262449Speter    {"3", "COLM"},		/* 132-column mode */
50362449Speter    {"4", "SCLM"},		/* smooth scroll */
50462449Speter    {"5", "SCNM"},		/* reverse video mode */
50562449Speter    {"6", "OM"},		/* origin mode */
50662449Speter    {"7", "AWM"},		/* wraparound mode */
50762449Speter    {"8", "ARM"},		/* auto-repeat mode */
50862449Speter    {(char *) 0, (char *) 0}
50950276Speter};
51050276Speter
51150276Speterstatic const assoc ecma_highlights[] =
51250276Speter/* recognize ECMA attribute sequences */
51350276Speter{
51462449Speter    {"0", "NORMAL"},		/* normal */
51562449Speter    {"1", "+BOLD"},		/* bold on */
51662449Speter    {"2", "+DIM"},		/* dim on */
51762449Speter    {"3", "+ITALIC"},		/* italic on */
51862449Speter    {"4", "+UNDERLINE"},	/* underline on */
51962449Speter    {"5", "+BLINK"},		/* blink on */
52062449Speter    {"6", "+FASTBLINK"},	/* fastblink on */
52162449Speter    {"7", "+REVERSE"},		/* reverse on */
52262449Speter    {"8", "+INVISIBLE"},	/* invisible on */
52362449Speter    {"9", "+DELETED"},		/* deleted on */
52462449Speter    {"10", "MAIN-FONT"},	/* select primary font */
52562449Speter    {"11", "ALT-FONT-1"},	/* select alternate font 1 */
52662449Speter    {"12", "ALT-FONT-2"},	/* select alternate font 2 */
52762449Speter    {"13", "ALT-FONT-3"},	/* select alternate font 3 */
52862449Speter    {"14", "ALT-FONT-4"},	/* select alternate font 4 */
52962449Speter    {"15", "ALT-FONT-5"},	/* select alternate font 5 */
53062449Speter    {"16", "ALT-FONT-6"},	/* select alternate font 6 */
53162449Speter    {"17", "ALT-FONT-7"},	/* select alternate font 7 */
53262449Speter    {"18", "ALT-FONT-1"},	/* select alternate font 1 */
53362449Speter    {"19", "ALT-FONT-1"},	/* select alternate font 1 */
53462449Speter    {"20", "FRAKTUR"},		/* Fraktur font */
53562449Speter    {"21", "DOUBLEUNDER"},	/* double underline */
53662449Speter    {"22", "-DIM"},		/* dim off */
53762449Speter    {"23", "-ITALIC"},		/* italic off */
53862449Speter    {"24", "-UNDERLINE"},	/* underline off */
53962449Speter    {"25", "-BLINK"},		/* blink off */
54062449Speter    {"26", "-FASTBLINK"},	/* fastblink off */
54162449Speter    {"27", "-REVERSE"},		/* reverse off */
54262449Speter    {"28", "-INVISIBLE"},	/* invisible off */
54362449Speter    {"29", "-DELETED"},		/* deleted off */
54462449Speter    {(char *) 0, (char *) 0}
54550276Speter};
54650276Speter
547166124Srafanstatic int
548166124Srafanskip_csi(const char *cap)
549166124Srafan{
550166124Srafan    int result = 0;
551166124Srafan    if (cap[0] == '\033' && cap[1] == '[')
552166124Srafan	result = 2;
553166124Srafan    else if (UChar(cap[0]) == 0233)
554166124Srafan	result = 1;
555166124Srafan    return result;
556166124Srafan}
557166124Srafan
558166124Srafanstatic bool
559166124Srafansame_param(const char *table, const char *param, unsigned length)
560166124Srafan{
561166124Srafan    bool result = FALSE;
562166124Srafan    if (strncmp(table, param, length) == 0) {
563166124Srafan	result = !isdigit(UChar(param[length]));
564166124Srafan    }
565166124Srafan    return result;
566166124Srafan}
567166124Srafan
568166124Srafanstatic char *
569166124Srafanlookup_params(const assoc * table, char *dst, char *src)
570166124Srafan{
571184989Srafan    char *result = 0;
572166124Srafan    const char *ep = strtok(src, ";");
573166124Srafan
574184989Srafan    if (ep != 0) {
575184989Srafan	const assoc *ap;
576166124Srafan
577184989Srafan	do {
578184989Srafan	    bool found = FALSE;
579166124Srafan
580184989Srafan	    for (ap = table; ap->from; ap++) {
581184989Srafan		size_t tlen = strlen(ap->from);
582184989Srafan
583184989Srafan		if (same_param(ap->from, ep, tlen)) {
584184989Srafan		    (void) strcat(dst, ap->to);
585184989Srafan		    found = TRUE;
586184989Srafan		    break;
587184989Srafan		}
588166124Srafan	    }
589166124Srafan
590184989Srafan	    if (!found)
591184989Srafan		(void) strcat(dst, ep);
592184989Srafan	    (void) strcat(dst, ";");
593184989Srafan	} while
594184989Srafan	    ((ep = strtok((char *) 0, ";")));
595166124Srafan
596184989Srafan	dst[strlen(dst) - 1] = '\0';
597166124Srafan
598184989Srafan	result = dst;
599184989Srafan    }
600184989Srafan    return result;
601166124Srafan}
602166124Srafan
60362449Speterstatic void
604166124Srafananalyze_string(const char *name, const char *cap, TERMTYPE *tp)
60550276Speter{
60662449Speter    char buf2[MAX_TERMINFO_LENGTH];
607166124Srafan    const char *sp;
60862449Speter    const assoc *ap;
609166124Srafan    int tp_lines = tp->Numbers[2];
61050276Speter
61150276Speter    if (cap == ABSENT_STRING || cap == CANCELLED_STRING)
61250276Speter	return;
61350276Speter    (void) printf("%s: ", name);
61450276Speter
61562449Speter    for (sp = cap; *sp; sp++) {
61662449Speter	int i;
617166124Srafan	int csi;
61862449Speter	size_t len = 0;
619166124Srafan	size_t next;
62050276Speter	const char *expansion = 0;
621166124Srafan	char buf3[MAX_TERMINFO_LENGTH];
62250276Speter
62350276Speter	/* first, check other capabilities in this entry */
62462449Speter	for (i = 0; i < STRCOUNT; i++) {
62562449Speter	    char *cp = tp->Strings[i];
62650276Speter
62750276Speter	    /* don't use soft-key capabilities */
62850276Speter	    if (strnames[i][0] == 'k' && strnames[i][0] == 'f')
62950276Speter		continue;
63050276Speter
63162449Speter	    if (cp != ABSENT_STRING && cp != CANCELLED_STRING && cp[0] && cp
63262449Speter		!= cap) {
63350276Speter		len = strlen(cp);
63450276Speter		(void) strncpy(buf2, sp, len);
63550276Speter		buf2[len] = '\0';
63650276Speter
63750276Speter		if (_nc_capcmp(cp, buf2))
63850276Speter		    continue;
63950276Speter
64050276Speter#define ISRS(s)	(!strncmp((s), "is", 2) || !strncmp((s), "rs", 2))
64150276Speter		/*
64250276Speter		 * Theoretically we just passed the test for translation
64350276Speter		 * (equality once the padding is stripped).  However, there
64450276Speter		 * are a few more hoops that need to be jumped so that
64550276Speter		 * identical pairs of initialization and reset strings
64650276Speter		 * don't just refer to each other.
64750276Speter		 */
64850276Speter		if (ISRS(name) || ISRS(strnames[i]))
64950276Speter		    if (cap < cp)
65050276Speter			continue;
65150276Speter#undef ISRS
65250276Speter
65350276Speter		expansion = strnames[i];
65450276Speter		break;
65550276Speter	    }
65650276Speter	}
65750276Speter
65850276Speter	/* now check the standard capabilities */
659166124Srafan	if (!expansion) {
660166124Srafan	    csi = skip_csi(sp);
66162449Speter	    for (ap = std_caps; ap->from; ap++) {
662184989Srafan		size_t adj = (size_t) (csi ? 2 : 0);
663166124Srafan
66450276Speter		len = strlen(ap->from);
665166124Srafan		if (csi && skip_csi(ap->from) != csi)
666166124Srafan		    continue;
667166124Srafan		if (len > adj
668166124Srafan		    && strncmp(ap->from + adj, sp + csi, len - adj) == 0) {
66950276Speter		    expansion = ap->to;
670166124Srafan		    len -= adj;
671184989Srafan		    len += (size_t) csi;
67250276Speter		    break;
67350276Speter		}
67450276Speter	    }
675166124Srafan	}
67650276Speter
677166124Srafan	/* now check for standard-mode sequences */
67850276Speter	if (!expansion
679166124Srafan	    && (csi = skip_csi(sp)) != 0
680166124Srafan	    && (len = strspn(sp + csi, "0123456789;"))
681184989Srafan	    && (len < sizeof(buf3))
682184989Srafan	    && (next = (size_t) csi + len)
683166124Srafan	    && ((sp[next] == 'h') || (sp[next] == 'l'))) {
68450276Speter
685166124Srafan	    (void) strcpy(buf2, (sp[next] == 'h') ? "ECMA+" : "ECMA-");
686166124Srafan	    (void) strncpy(buf3, sp + csi, len);
68750276Speter	    buf3[len] = '\0';
688184989Srafan	    len += (size_t) csi + 1;
68950276Speter
690166124Srafan	    expansion = lookup_params(std_modes, buf2, buf3);
691166124Srafan	}
69250276Speter
693166124Srafan	/* now check for private-mode sequences */
694166124Srafan	if (!expansion
695166124Srafan	    && (csi = skip_csi(sp)) != 0
696166124Srafan	    && sp[csi] == '?'
697166124Srafan	    && (len = strspn(sp + csi + 1, "0123456789;"))
698184989Srafan	    && (len < sizeof(buf3))
699184989Srafan	    && (next = (size_t) csi + 1 + len)
700166124Srafan	    && ((sp[next] == 'h') || (sp[next] == 'l'))) {
70150276Speter
702166124Srafan	    (void) strcpy(buf2, (sp[next] == 'h') ? "DEC+" : "DEC-");
703166124Srafan	    (void) strncpy(buf3, sp + csi + 1, len);
704166124Srafan	    buf3[len] = '\0';
705184989Srafan	    len += (size_t) csi + 2;
70650276Speter
707166124Srafan	    expansion = lookup_params(private_modes, buf2, buf3);
70850276Speter	}
70950276Speter
71050276Speter	/* now check for ECMA highlight sequences */
71150276Speter	if (!expansion
712166124Srafan	    && (csi = skip_csi(sp)) != 0
713166124Srafan	    && (len = strspn(sp + csi, "0123456789;")) != 0
714184989Srafan	    && (len < sizeof(buf3))
715184989Srafan	    && (next = (size_t) csi + len)
716166124Srafan	    && sp[next] == 'm') {
71750276Speter
71850276Speter	    (void) strcpy(buf2, "SGR:");
719166124Srafan	    (void) strncpy(buf3, sp + csi, len);
72050276Speter	    buf3[len] = '\0';
721184989Srafan	    len += (size_t) csi + 1;
72250276Speter
723166124Srafan	    expansion = lookup_params(ecma_highlights, buf2, buf3);
724166124Srafan	}
72550276Speter
726166124Srafan	if (!expansion
727166124Srafan	    && (csi = skip_csi(sp)) != 0
728166124Srafan	    && sp[csi] == 'm') {
729184989Srafan	    len = (size_t) csi + 1;
730166124Srafan	    (void) strcpy(buf2, "SGR:");
731166124Srafan	    strcat(buf2, ecma_highlights[0].to);
73250276Speter	    expansion = buf2;
73350276Speter	}
734166124Srafan
73550276Speter	/* now check for scroll region reset */
736166124Srafan	if (!expansion
737166124Srafan	    && (csi = skip_csi(sp)) != 0) {
738166124Srafan	    if (sp[csi] == 'r') {
73950276Speter		expansion = "RSR";
740166124Srafan		len = 1;
741166124Srafan	    } else {
742166124Srafan		(void) sprintf(buf2, "1;%dr", tp_lines);
743166124Srafan		len = strlen(buf2);
744166124Srafan		if (strncmp(buf2, sp + csi, len) == 0)
745166124Srafan		    expansion = "RSR";
746166124Srafan	    }
747184989Srafan	    len += (size_t) csi;
74850276Speter	}
74950276Speter
75050276Speter	/* now check for home-down */
751166124Srafan	if (!expansion
752166124Srafan	    && (csi = skip_csi(sp)) != 0) {
753166124Srafan	    (void) sprintf(buf2, "%d;1H", tp_lines);
75450276Speter	    len = strlen(buf2);
755166124Srafan	    if (strncmp(buf2, sp + csi, len) == 0) {
75662449Speter		expansion = "LL";
757166124Srafan	    } else {
758166124Srafan		(void) sprintf(buf2, "%dH", tp_lines);
759166124Srafan		len = strlen(buf2);
760166124Srafan		if (strncmp(buf2, sp + csi, len) == 0) {
761166124Srafan		    expansion = "LL";
762166124Srafan		}
763166124Srafan	    }
764184989Srafan	    len += (size_t) csi;
76550276Speter	}
76650276Speter
76750276Speter	/* now look at the expansion we got, if any */
76862449Speter	if (expansion) {
769184989Srafan	    printf("{%s}", expansion);
77050276Speter	    sp += len - 1;
77162449Speter	} else {
77250276Speter	    /* couldn't match anything */
77350276Speter	    buf2[0] = *sp;
77450276Speter	    buf2[1] = '\0';
775184989Srafan	    fputs(TIC_EXPAND(buf2), stdout);
77650276Speter	}
77750276Speter    }
778184989Srafan    putchar('\n');
77950276Speter}
78050276Speter
78150276Speter/***************************************************************************
78250276Speter *
78350276Speter * File comparison
78450276Speter *
78550276Speter ***************************************************************************/
78650276Speter
78762449Speterstatic void
78862449Speterfile_comparison(int argc, char *argv[])
78950276Speter{
79050276Speter#define MAXCOMPARE	2
79150276Speter    /* someday we may allow comparisons on more files */
79262449Speter    int filecount = 0;
79362449Speter    ENTRY *heads[MAXCOMPARE];
79462449Speter    ENTRY *qp, *rp;
79562449Speter    int i, n;
79650276Speter
797184989Srafan    memset(heads, 0, sizeof(heads));
79862449Speter    dump_init((char *) 0, F_LITERAL, S_TERMINFO, 0, itrace, FALSE);
79950276Speter
80062449Speter    for (n = 0; n < argc && n < MAXCOMPARE; n++) {
80162449Speter	if (freopen(argv[n], "r", stdin) == 0)
80250276Speter	    _nc_err_abort("Can't open %s", argv[n]);
80350276Speter
80462449Speter	_nc_head = _nc_tail = 0;
80550276Speter
80650276Speter	/* parse entries out of the source file */
80750276Speter	_nc_set_source(argv[n]);
808166124Srafan	_nc_read_entry_source(stdin, NULL, TRUE, literal, NULLHOOK);
80950276Speter
81050276Speter	if (itrace)
81162449Speter	    (void) fprintf(stderr, "Resolving file %d...\n", n - 0);
81250276Speter
81362449Speter	/* maybe do use resolution */
814166124Srafan	if (!_nc_resolve_uses2(!limited, literal)) {
81550276Speter	    (void) fprintf(stderr,
81666963Speter			   "There are unresolved use entries in %s:\n",
81766963Speter			   argv[n]);
81862449Speter	    for_entry_list(qp) {
81962449Speter		if (qp->nuses) {
82050276Speter		    (void) fputs(qp->tterm.term_names, stderr);
82150276Speter		    (void) fputc('\n', stderr);
82250276Speter		}
82362449Speter	    }
824166124Srafan	    ExitProgram(EXIT_FAILURE);
82550276Speter	}
82650276Speter
82750276Speter	heads[filecount] = _nc_head;
82850276Speter	filecount++;
82950276Speter    }
83050276Speter
83150276Speter    /* OK, all entries are in core.  Ready to do the comparison */
83250276Speter    if (itrace)
83350276Speter	(void) fprintf(stderr, "Entries are now in core...\n");
83450276Speter
83562449Speter    /* The entry-matching loop. Sigh, this is intrinsically quadratic. */
83662449Speter    for (qp = heads[0]; qp; qp = qp->next) {
83750276Speter	for (rp = heads[1]; rp; rp = rp->next)
83862449Speter	    if (_nc_entry_match(qp->tterm.term_names, rp->tterm.term_names)) {
83962449Speter		if (qp->ncrosslinks < MAX_CROSSLINKS)
84062449Speter		    qp->crosslinks[qp->ncrosslinks] = rp;
84162449Speter		qp->ncrosslinks++;
84250276Speter
84362449Speter		if (rp->ncrosslinks < MAX_CROSSLINKS)
84462449Speter		    rp->crosslinks[rp->ncrosslinks] = qp;
84562449Speter		rp->ncrosslinks++;
84650276Speter	    }
84750276Speter    }
84850276Speter
84950276Speter    /* now we have two circular lists with crosslinks */
85050276Speter    if (itrace)
85150276Speter	(void) fprintf(stderr, "Name matches are done...\n");
85250276Speter
85362449Speter    for (qp = heads[0]; qp; qp = qp->next) {
85462449Speter	if (qp->ncrosslinks > 1) {
85550276Speter	    (void) fprintf(stderr,
85666963Speter			   "%s in file 1 (%s) has %d matches in file 2 (%s):\n",
85766963Speter			   _nc_first_name(qp->tterm.term_names),
85866963Speter			   argv[0],
85966963Speter			   qp->ncrosslinks,
86066963Speter			   argv[1]);
86162449Speter	    for (i = 0; i < qp->ncrosslinks; i++)
86250276Speter		(void) fprintf(stderr,
86366963Speter			       "\t%s\n",
86466963Speter			       _nc_first_name((qp->crosslinks[i])->tterm.term_names));
86550276Speter	}
86662449Speter    }
86762449Speter
86862449Speter    for (rp = heads[1]; rp; rp = rp->next) {
86962449Speter	if (rp->ncrosslinks > 1) {
87050276Speter	    (void) fprintf(stderr,
87166963Speter			   "%s in file 2 (%s) has %d matches in file 1 (%s):\n",
87266963Speter			   _nc_first_name(rp->tterm.term_names),
87366963Speter			   argv[1],
87466963Speter			   rp->ncrosslinks,
87566963Speter			   argv[0]);
87662449Speter	    for (i = 0; i < rp->ncrosslinks; i++)
87750276Speter		(void) fprintf(stderr,
87866963Speter			       "\t%s\n",
87966963Speter			       _nc_first_name((rp->crosslinks[i])->tterm.term_names));
88050276Speter	}
88162449Speter    }
88250276Speter
88350276Speter    (void) printf("In file 1 (%s) only:\n", argv[0]);
88450276Speter    for (qp = heads[0]; qp; qp = qp->next)
88562449Speter	if (qp->ncrosslinks == 0)
88650276Speter	    (void) printf("\t%s\n",
88766963Speter			  _nc_first_name(qp->tterm.term_names));
88850276Speter
88950276Speter    (void) printf("In file 2 (%s) only:\n", argv[1]);
89050276Speter    for (rp = heads[1]; rp; rp = rp->next)
89162449Speter	if (rp->ncrosslinks == 0)
89250276Speter	    (void) printf("\t%s\n",
89366963Speter			  _nc_first_name(rp->tterm.term_names));
89450276Speter
89550276Speter    (void) printf("The following entries are equivalent:\n");
89662449Speter    for (qp = heads[0]; qp; qp = qp->next) {
89762449Speter	rp = qp->crosslinks[0];
89850276Speter
89962449Speter	if (qp->ncrosslinks == 1) {
90062449Speter	    rp = qp->crosslinks[0];
90150276Speter
90262449Speter	    repair_acsc(&qp->tterm);
90362449Speter	    repair_acsc(&rp->tterm);
90462449Speter#if NCURSES_XNAMES
90562449Speter	    _nc_align_termtype(&qp->tterm, &rp->tterm);
90662449Speter#endif
90762449Speter	    if (entryeq(&qp->tterm, &rp->tterm) && useeq(qp, rp)) {
90862449Speter		char name1[NAMESIZE], name2[NAMESIZE];
90950276Speter
91062449Speter		(void) canonical_name(qp->tterm.term_names, name1);
91162449Speter		(void) canonical_name(rp->tterm.term_names, name2);
91262449Speter
91362449Speter		(void) printf("%s = %s\n", name1, name2);
91462449Speter	    }
91550276Speter	}
91650276Speter    }
91750276Speter
91850276Speter    (void) printf("Differing entries:\n");
91950276Speter    termcount = 2;
92062449Speter    for (qp = heads[0]; qp; qp = qp->next) {
92150276Speter
92262449Speter	if (qp->ncrosslinks == 1) {
92362449Speter	    rp = qp->crosslinks[0];
92450276Speter#if NCURSES_XNAMES
92562449Speter	    /* sorry - we have to do this on each pass */
92650276Speter	    _nc_align_termtype(&qp->tterm, &rp->tterm);
92750276Speter#endif
92862449Speter	    if (!(entryeq(&qp->tterm, &rp->tterm) && useeq(qp, rp))) {
92962449Speter		char name1[NAMESIZE], name2[NAMESIZE];
93050276Speter
93162449Speter		entries[0] = *qp;
93262449Speter		entries[1] = *rp;
93350276Speter
93462449Speter		(void) canonical_name(qp->tterm.term_names, name1);
93562449Speter		(void) canonical_name(rp->tterm.term_names, name2);
93650276Speter
93762449Speter		switch (compare) {
93862449Speter		case C_DIFFERENCE:
93962449Speter		    if (itrace)
94062449Speter			(void) fprintf(stderr,
941174993Srafan				       "%s: dumping differences\n",
942174993Srafan				       _nc_progname);
94362449Speter		    (void) printf("comparing %s to %s.\n", name1, name2);
94462449Speter		    compare_entry(compare_predicate, &entries->tterm, quiet);
94562449Speter		    break;
94650276Speter
94762449Speter		case C_COMMON:
94862449Speter		    if (itrace)
94962449Speter			(void) fprintf(stderr,
950174993Srafan				       "%s: dumping common capabilities\n",
951174993Srafan				       _nc_progname);
95262449Speter		    (void) printf("comparing %s to %s.\n", name1, name2);
95362449Speter		    compare_entry(compare_predicate, &entries->tterm, quiet);
95462449Speter		    break;
95550276Speter
95662449Speter		case C_NAND:
95762449Speter		    if (itrace)
95862449Speter			(void) fprintf(stderr,
959174993Srafan				       "%s: dumping differences\n",
960174993Srafan				       _nc_progname);
96162449Speter		    (void) printf("comparing %s to %s.\n", name1, name2);
96262449Speter		    compare_entry(compare_predicate, &entries->tterm, quiet);
96362449Speter		    break;
96450276Speter
96562449Speter		}
96650276Speter	    }
96750276Speter	}
96850276Speter    }
96950276Speter}
97050276Speter
97162449Speterstatic void
97262449Speterusage(void)
97350276Speter{
97462449Speter    static const char *tbl[] =
97562449Speter    {
97662449Speter	"Usage: infocmp [options] [-A directory] [-B directory] [termname...]"
97762449Speter	,""
97862449Speter	,"Options:"
97962449Speter	,"  -1    print single-column"
98062449Speter	,"  -C    use termcap-names"
98162449Speter	,"  -F    compare terminfo-files"
98262449Speter	,"  -I    use terminfo-names"
98362449Speter	,"  -L    use long names"
98462449Speter	,"  -R subset (see manpage)"
98562449Speter	,"  -T    eliminate size limits (test)"
986166124Srafan	,"  -U    eliminate post-processing of entries"
98762449Speter	,"  -V    print version"
98862449Speter#if NCURSES_XNAMES
98962449Speter	,"  -a    with -F, list commented-out caps"
99062449Speter#endif
99162449Speter	,"  -c    list common capabilities"
99262449Speter	,"  -d    list different capabilities"
99362449Speter	,"  -e    format output for C initializer"
99462449Speter	,"  -E    format output as C tables"
99562449Speter	,"  -f    with -1, format complex strings"
99662449Speter	,"  -G    format %{number} to %'char'"
99762449Speter	,"  -g    format %'char' to %{number}"
99862449Speter	,"  -i    analyze initialization/reset"
99962449Speter	,"  -l    output terminfo names"
100062449Speter	,"  -n    list capabilities in neither"
100162449Speter	,"  -p    ignore padding specifiers"
100262449Speter	,"  -q    brief listing, removes headers"
100362449Speter	,"  -r    with -C, output in termcap form"
100462449Speter	,"  -r    with -F, resolve use-references"
100562449Speter	,"  -s [d|i|l|c] sort fields"
1006166124Srafan#if NCURSES_XNAMES
1007166124Srafan	,"  -t    suppress commented-out capabilities"
1008166124Srafan#endif
100962449Speter	,"  -u    produce source with 'use='"
101062449Speter	,"  -v number  (verbose)"
101162449Speter	,"  -w number  (width)"
1012166124Srafan#if NCURSES_XNAMES
1013166124Srafan	,"  -x    treat unknown capabilities as user-defined"
1014166124Srafan#endif
101562449Speter    };
101662449Speter    const size_t first = 3;
101766963Speter    const size_t last = SIZEOF(tbl);
101862449Speter    const size_t left = (last - first + 1) / 2 + first;
101962449Speter    size_t n;
102050276Speter
102162449Speter    for (n = 0; n < left; n++) {
102262449Speter	size_t m = (n < first) ? last : n + left - first;
102362449Speter	if (m < last)
102462449Speter	    fprintf(stderr, "%-40.40s%s\n", tbl[n], tbl[m]);
102562449Speter	else
102662449Speter	    fprintf(stderr, "%s\n", tbl[n]);
102762449Speter    }
1028166124Srafan    ExitProgram(EXIT_FAILURE);
102950276Speter}
103050276Speter
103162449Speterstatic char *
103297049Speterany_initializer(const char *fmt, const char *type)
103350276Speter{
103450276Speter    static char *initializer;
103550276Speter    char *s;
103650276Speter
103750276Speter    if (initializer == 0)
103897049Speter	initializer = (char *) malloc(strlen(entries->tterm.term_names) +
103997049Speter				      strlen(type) + strlen(fmt));
104050276Speter
104197049Speter    (void) strcpy(initializer, entries->tterm.term_names);
104262449Speter    for (s = initializer; *s != 0 && *s != '|'; s++) {
104397049Speter	if (!isalnum(UChar(*s)))
104450276Speter	    *s = '_';
104550276Speter    }
104650276Speter    *s = 0;
104797049Speter    (void) sprintf(s, fmt, type);
104850276Speter    return initializer;
104950276Speter}
105050276Speter
105197049Speterstatic char *
105297049Spetername_initializer(const char *type)
105397049Speter{
105497049Speter    return any_initializer("_%s_data", type);
105597049Speter}
105697049Speter
105797049Speterstatic char *
105897049Speterstring_variable(const char *type)
105997049Speter{
106097049Speter    return any_initializer("_s_%s", type);
106197049Speter}
106297049Speter
106350276Speter/* dump C initializers for the terminal type */
106462449Speterstatic void
1065166124Srafandump_initializers(TERMTYPE *term)
106650276Speter{
1067166124Srafan    unsigned n;
106850276Speter    const char *str = 0;
106950276Speter
107097049Speter    printf("\nstatic char %s[] = \"%s\";\n\n",
107197049Speter	   name_initializer("alias"), entries->tterm.term_names);
107297049Speter
107397049Speter    for_each_string(n, term) {
107497049Speter	char buf[MAX_STRING], *sp, *tp;
107597049Speter
107697049Speter	if (VALID_STRING(term->Strings[n])) {
107797049Speter	    tp = buf;
107897049Speter	    *tp++ = '"';
107997049Speter	    for (sp = term->Strings[n];
108097049Speter		 *sp != 0 && (tp - buf) < MAX_STRING - 6;
108197049Speter		 sp++) {
108297049Speter		if (isascii(UChar(*sp))
108397049Speter		    && isprint(UChar(*sp))
108497049Speter		    && *sp != '\\'
108597049Speter		    && *sp != '"')
108697049Speter		    *tp++ = *sp;
108797049Speter		else {
108897049Speter		    (void) sprintf(tp, "\\%03o", UChar(*sp));
108997049Speter		    tp += 4;
109097049Speter		}
109197049Speter	    }
109297049Speter	    *tp++ = '"';
109397049Speter	    *tp = '\0';
109497049Speter	    (void) printf("static char %-20s[] = %s;\n",
109597049Speter			  string_variable(ExtStrname(term, n, strnames)), buf);
109697049Speter	}
109797049Speter    }
109897049Speter    printf("\n");
109997049Speter
110062449Speter    (void) printf("static char %s[] = %s\n", name_initializer("bool"), L_CURL);
110150276Speter
110262449Speter    for_each_boolean(n, term) {
110362449Speter	switch ((int) (term->Booleans[n])) {
110450276Speter	case TRUE:
110550276Speter	    str = "TRUE";
110650276Speter	    break;
110750276Speter
110850276Speter	case FALSE:
110950276Speter	    str = "FALSE";
111050276Speter	    break;
111150276Speter
111250276Speter	case ABSENT_BOOLEAN:
111350276Speter	    str = "ABSENT_BOOLEAN";
111450276Speter	    break;
111550276Speter
111650276Speter	case CANCELLED_BOOLEAN:
111750276Speter	    str = "CANCELLED_BOOLEAN";
111850276Speter	    break;
111950276Speter	}
1120166124Srafan	(void) printf("\t/* %3u: %-8s */\t%s,\n",
112166963Speter		      n, ExtBoolname(term, n, boolnames), str);
112250276Speter    }
112350276Speter    (void) printf("%s;\n", R_CURL);
112450276Speter
112550276Speter    (void) printf("static short %s[] = %s\n", name_initializer("number"), L_CURL);
112650276Speter
112762449Speter    for_each_number(n, term) {
112862449Speter	char buf[BUFSIZ];
112962449Speter	switch (term->Numbers[n]) {
113050276Speter	case ABSENT_NUMERIC:
113150276Speter	    str = "ABSENT_NUMERIC";
113250276Speter	    break;
113350276Speter	case CANCELLED_NUMERIC:
113450276Speter	    str = "CANCELLED_NUMERIC";
113550276Speter	    break;
113650276Speter	default:
113750276Speter	    sprintf(buf, "%d", term->Numbers[n]);
113850276Speter	    str = buf;
113950276Speter	    break;
114050276Speter	}
1141166124Srafan	(void) printf("\t/* %3u: %-8s */\t%s,\n", n,
114266963Speter		      ExtNumname(term, n, numnames), str);
114350276Speter    }
114450276Speter    (void) printf("%s;\n", R_CURL);
114550276Speter
114650276Speter    (void) printf("static char * %s[] = %s\n", name_initializer("string"), L_CURL);
114750276Speter
114862449Speter    for_each_string(n, term) {
114950276Speter
115050276Speter	if (term->Strings[n] == ABSENT_STRING)
115150276Speter	    str = "ABSENT_STRING";
115250276Speter	else if (term->Strings[n] == CANCELLED_STRING)
115350276Speter	    str = "CANCELLED_STRING";
115462449Speter	else {
115597049Speter	    str = string_variable(ExtStrname(term, n, strnames));
115650276Speter	}
1157166124Srafan	(void) printf("\t/* %3u: %-8s */\t%s,\n", n,
115866963Speter		      ExtStrname(term, n, strnames), str);
115950276Speter    }
116050276Speter    (void) printf("%s;\n", R_CURL);
116197049Speter
116297049Speter#if NCURSES_XNAMES
116397049Speter    if ((NUM_BOOLEANS(term) != BOOLCOUNT)
116497049Speter	|| (NUM_NUMBERS(term) != NUMCOUNT)
116597049Speter	|| (NUM_STRINGS(term) != STRCOUNT)) {
116697049Speter	(void) printf("static char * %s[] = %s\n",
116797049Speter		      name_initializer("string_ext"), L_CURL);
116897049Speter	for (n = BOOLCOUNT; n < NUM_BOOLEANS(term); ++n) {
1169166124Srafan	    (void) printf("\t/* %3u: bool */\t\"%s\",\n",
117097049Speter			  n, ExtBoolname(term, n, boolnames));
117197049Speter	}
117297049Speter	for (n = NUMCOUNT; n < NUM_NUMBERS(term); ++n) {
1173166124Srafan	    (void) printf("\t/* %3u: num */\t\"%s\",\n",
117497049Speter			  n, ExtNumname(term, n, numnames));
117597049Speter	}
117697049Speter	for (n = STRCOUNT; n < NUM_STRINGS(term); ++n) {
1177166124Srafan	    (void) printf("\t/* %3u: str */\t\"%s\",\n",
117897049Speter			  n, ExtStrname(term, n, strnames));
117997049Speter	}
118097049Speter	(void) printf("%s;\n", R_CURL);
118197049Speter    }
118297049Speter#endif
118350276Speter}
118450276Speter
118550276Speter/* dump C initializers for the terminal type */
118662449Speterstatic void
1187166124Srafandump_termtype(TERMTYPE *term)
118850276Speter{
118997049Speter    (void) printf("\t%s\n\t\t%s,\n", L_CURL, name_initializer("alias"));
119050276Speter    (void) printf("\t\t(char *)0,\t/* pointer to string table */\n");
119150276Speter
119250276Speter    (void) printf("\t\t%s,\n", name_initializer("bool"));
119350276Speter    (void) printf("\t\t%s,\n", name_initializer("number"));
119450276Speter
119550276Speter    (void) printf("\t\t%s,\n", name_initializer("string"));
119650276Speter
119750276Speter#if NCURSES_XNAMES
119850276Speter    (void) printf("#if NCURSES_XNAMES\n");
119950276Speter    (void) printf("\t\t(char *)0,\t/* pointer to extended string table */\n");
120050276Speter    (void) printf("\t\t%s,\t/* ...corresponding names */\n",
120197049Speter		  ((NUM_BOOLEANS(term) != BOOLCOUNT)
120297049Speter		   || (NUM_NUMBERS(term) != NUMCOUNT)
120397049Speter		   || (NUM_STRINGS(term) != STRCOUNT))
120466963Speter		  ? name_initializer("string_ext")
120566963Speter		  : "(char **)0");
120650276Speter
120750276Speter    (void) printf("\t\t%d,\t\t/* count total Booleans */\n", NUM_BOOLEANS(term));
120862449Speter    (void) printf("\t\t%d,\t\t/* count total Numbers */\n", NUM_NUMBERS(term));
120962449Speter    (void) printf("\t\t%d,\t\t/* count total Strings */\n", NUM_STRINGS(term));
121050276Speter
121162449Speter    (void) printf("\t\t%d,\t\t/* count extensions to Booleans */\n",
121266963Speter		  NUM_BOOLEANS(term) - BOOLCOUNT);
121362449Speter    (void) printf("\t\t%d,\t\t/* count extensions to Numbers */\n",
121466963Speter		  NUM_NUMBERS(term) - NUMCOUNT);
121562449Speter    (void) printf("\t\t%d,\t\t/* count extensions to Strings */\n",
121666963Speter		  NUM_STRINGS(term) - STRCOUNT);
121750276Speter
121850276Speter    (void) printf("#endif /* NCURSES_XNAMES */\n");
1219176187Srafan#else
1220176187Srafan    (void) term;
122150276Speter#endif /* NCURSES_XNAMES */
122250276Speter    (void) printf("\t%s\n", R_CURL);
122350276Speter}
122450276Speter
122566963Speterstatic int
122666963Speteroptarg_to_number(void)
122766963Speter{
122866963Speter    char *temp = 0;
122966963Speter    long value = strtol(optarg, &temp, 0);
123066963Speter
123166963Speter    if (temp == 0 || temp == optarg || *temp != 0) {
123266963Speter	fprintf(stderr, "Expected a number, not \"%s\"\n", optarg);
1233166124Srafan	ExitProgram(EXIT_FAILURE);
123466963Speter    }
123566963Speter    return (int) value;
123666963Speter}
123766963Speter
1238166124Srafanstatic char *
1239166124Srafanterminal_env(void)
1240166124Srafan{
1241166124Srafan    char *terminal;
1242166124Srafan
1243166124Srafan    if ((terminal = getenv("TERM")) == 0) {
1244166124Srafan	(void) fprintf(stderr,
1245174993Srafan		       "%s: environment variable TERM not set\n",
1246174993Srafan		       _nc_progname);
1247166124Srafan	exit(EXIT_FAILURE);
1248166124Srafan    }
1249166124Srafan    return terminal;
1250166124Srafan}
1251166124Srafan
125250276Speter/***************************************************************************
125350276Speter *
125450276Speter * Main sequence
125550276Speter *
125650276Speter ***************************************************************************/
125750276Speter
125862449Speterint
125962449Spetermain(int argc, char *argv[])
126050276Speter{
126162449Speter    /* Avoid "local data >32k" error with mwcc */
126262449Speter    /* Also avoid overflowing smaller stacks on systems like AmigaOS */
1263174993Srafan    path *tfile = 0;
1264174993Srafan    char **tname = 0;
1265174993Srafan    int maxterms;
1266174993Srafan
1267174993Srafan    char **myargv;
1268174993Srafan
1269174993Srafan    char *firstdir, *restdir;
127062449Speter    int c, i, len;
127162449Speter    bool formatted = FALSE;
127262449Speter    bool filecompare = FALSE;
127362449Speter    int initdump = 0;
127462449Speter    bool init_analyze = FALSE;
1275166124Srafan    bool suppress_untranslatable = FALSE;
127650276Speter
127762449Speter    /* where is the terminfo database location going to default to? */
127862449Speter    restdir = firstdir = 0;
127950276Speter
1280166124Srafan#if NCURSES_XNAMES
1281166124Srafan    use_extended_names(FALSE);
1282166124Srafan#endif
1283166124Srafan
1284174993Srafan    _nc_progname = _nc_rootname(argv[0]);
1285174993Srafan
1286174993Srafan    /* make sure we have enough space to add two terminal entries */
1287184989Srafan    myargv = typeCalloc(char *, (size_t) (argc + 3));
1288184989Srafan    memcpy(myargv, argv, (sizeof(char *) * (size_t) argc));
1289174993Srafan    argv = myargv;
1290174993Srafan
1291166124Srafan    while ((c = getopt(argc,
1292166124Srafan		       argv,
1293174993Srafan		       "1A:aB:CcdEeFfGgIiLlnpqR:rs:TtUuVv:w:x")) != -1) {
129462449Speter	switch (c) {
1295166124Srafan	case '1':
1296166124Srafan	    mwidth = 0;
1297166124Srafan	    break;
1298166124Srafan
1299166124Srafan	case 'A':
1300166124Srafan	    firstdir = optarg;
1301166124Srafan	    break;
1302166124Srafan
130362449Speter#if NCURSES_XNAMES
130462449Speter	case 'a':
130562449Speter	    _nc_disable_period = TRUE;
130662449Speter	    use_extended_names(TRUE);
130762449Speter	    break;
130862449Speter#endif
1309166124Srafan	case 'B':
1310166124Srafan	    restdir = optarg;
1311166124Srafan	    break;
1312166124Srafan
1313166124Srafan	case 'C':
1314166124Srafan	    outform = F_TERMCAP;
1315166124Srafan	    tversion = "BSD";
1316166124Srafan	    if (sortmode == S_DEFAULT)
1317166124Srafan		sortmode = S_TERMCAP;
1318166124Srafan	    break;
1319166124Srafan
1320166124Srafan	case 'c':
1321166124Srafan	    compare = C_COMMON;
1322166124Srafan	    break;
1323166124Srafan
132462449Speter	case 'd':
132562449Speter	    compare = C_DIFFERENCE;
132662449Speter	    break;
132750276Speter
132862449Speter	case 'E':
132962449Speter	    initdump |= 2;
133062449Speter	    break;
133150276Speter
1332166124Srafan	case 'e':
1333166124Srafan	    initdump |= 1;
133462449Speter	    break;
133550276Speter
1336166124Srafan	case 'F':
1337166124Srafan	    filecompare = TRUE;
133862449Speter	    break;
133950276Speter
134062449Speter	case 'f':
134162449Speter	    formatted = TRUE;
134262449Speter	    break;
134350276Speter
134462449Speter	case 'G':
134562449Speter	    numbers = 1;
134662449Speter	    break;
134750276Speter
134862449Speter	case 'g':
134962449Speter	    numbers = -1;
135062449Speter	    break;
135150276Speter
135262449Speter	case 'I':
135362449Speter	    outform = F_TERMINFO;
135462449Speter	    if (sortmode == S_DEFAULT)
135562449Speter		sortmode = S_VARIABLE;
135662449Speter	    tversion = 0;
135762449Speter	    break;
135850276Speter
135962449Speter	case 'i':
136062449Speter	    init_analyze = TRUE;
136162449Speter	    break;
136250276Speter
136362449Speter	case 'L':
136462449Speter	    outform = F_VARIABLE;
136562449Speter	    if (sortmode == S_DEFAULT)
136662449Speter		sortmode = S_VARIABLE;
136762449Speter	    break;
136850276Speter
1369166124Srafan	case 'l':
1370166124Srafan	    outform = F_TERMINFO;
1371166124Srafan	    break;
1372166124Srafan
137362449Speter	case 'n':
137462449Speter	    compare = C_NAND;
137562449Speter	    break;
137650276Speter
137762449Speter	case 'p':
137862449Speter	    ignorepads = TRUE;
137962449Speter	    break;
138050276Speter
138162449Speter	case 'q':
138262449Speter	    quiet = TRUE;
138362449Speter	    s_absent = "-";
138462449Speter	    s_cancel = "@";
138562449Speter	    bool_sep = ", ";
138662449Speter	    break;
138750276Speter
1388166124Srafan	case 'R':
1389166124Srafan	    tversion = optarg;
1390166124Srafan	    break;
1391166124Srafan
139262449Speter	case 'r':
139362449Speter	    tversion = 0;
139462449Speter	    break;
139550276Speter
139662449Speter	case 's':
139762449Speter	    if (*optarg == 'd')
139862449Speter		sortmode = S_NOSORT;
139962449Speter	    else if (*optarg == 'i')
140062449Speter		sortmode = S_TERMINFO;
140162449Speter	    else if (*optarg == 'l')
140262449Speter		sortmode = S_VARIABLE;
140362449Speter	    else if (*optarg == 'c')
140462449Speter		sortmode = S_TERMCAP;
140562449Speter	    else {
140662449Speter		(void) fprintf(stderr,
1407174993Srafan			       "%s: unknown sort mode\n",
1408174993Srafan			       _nc_progname);
1409166124Srafan		ExitProgram(EXIT_FAILURE);
141062449Speter	    }
141162449Speter	    break;
141250276Speter
1413166124Srafan	case 'T':
1414166124Srafan	    limited = FALSE;
1415166124Srafan	    break;
1416166124Srafan
1417166124Srafan#if NCURSES_XNAMES
1418166124Srafan	case 't':
1419166124Srafan	    _nc_disable_period = FALSE;
1420166124Srafan	    suppress_untranslatable = TRUE;
1421166124Srafan	    break;
1422166124Srafan#endif
1423166124Srafan
1424166124Srafan	case 'U':
1425166124Srafan	    literal = TRUE;
1426166124Srafan	    break;
1427166124Srafan
142862449Speter	case 'u':
142962449Speter	    compare = C_USEALL;
143062449Speter	    break;
143150276Speter
1432166124Srafan	case 'V':
1433166124Srafan	    puts(curses_version());
1434166124Srafan	    ExitProgram(EXIT_SUCCESS);
1435166124Srafan
143662449Speter	case 'v':
143766963Speter	    itrace = optarg_to_number();
143862449Speter	    set_trace_level(itrace);
143962449Speter	    break;
144050276Speter
144162449Speter	case 'w':
144266963Speter	    mwidth = optarg_to_number();
144362449Speter	    break;
144450276Speter
1445166124Srafan#if NCURSES_XNAMES
1446166124Srafan	case 'x':
1447166124Srafan	    use_extended_names(TRUE);
144862449Speter	    break;
1449166124Srafan#endif
145050276Speter
145162449Speter	default:
145262449Speter	    usage();
145362449Speter	}
1454166124Srafan    }
145550276Speter
1456176187Srafan    maxterms = (argc + 2 - optind);
1457174993Srafan    tfile = typeMalloc(path, maxterms);
1458174993Srafan    tname = typeCalloc(char *, maxterms);
1459174993Srafan    entries = typeCalloc(ENTRY, maxterms);
1460174993Srafan
1461174993Srafan    if (tfile == 0
1462174993Srafan	|| tname == 0
1463174993Srafan	|| entries == 0) {
1464174993Srafan	fprintf(stderr, "%s: not enough memory\n", _nc_progname);
1465174993Srafan	ExitProgram(EXIT_FAILURE);
1466174993Srafan    }
1467174993Srafan
146862449Speter    /* by default, sort by terminfo name */
146962449Speter    if (sortmode == S_DEFAULT)
147062449Speter	sortmode = S_TERMINFO;
147150276Speter
147262449Speter    /* set up for display */
147362449Speter    dump_init(tversion, outform, sortmode, mwidth, itrace, formatted);
147450276Speter
147562449Speter    /* make sure we have at least one terminal name to work with */
147662449Speter    if (optind >= argc)
1477166124Srafan	argv[argc++] = terminal_env();
147850276Speter
147962449Speter    /* if user is after a comparison, make sure we have two entries */
148062449Speter    if (compare != C_DEFAULT && optind >= argc - 1)
1481166124Srafan	argv[argc++] = terminal_env();
148250276Speter
148362449Speter    /* exactly two terminal names with no options means do -d */
148462449Speter    if (argc - optind == 2 && compare == C_DEFAULT)
148562449Speter	compare = C_DIFFERENCE;
148650276Speter
148762449Speter    if (!filecompare) {
148862449Speter	/* grab the entries */
148962449Speter	termcount = 0;
149062449Speter	for (; optind < argc; optind++) {
1491174993Srafan	    const char *directory = termcount ? restdir : firstdir;
1492174993Srafan	    int status;
149350276Speter
1494174993Srafan	    tname[termcount] = argv[optind];
149550276Speter
1496174993Srafan	    if (directory) {
1497166124Srafan#if USE_DATABASE
1498174993Srafan#if MIXEDCASE_FILENAMES
1499174993Srafan#define LEAF_FMT "%c"
1500174993Srafan#else
1501174993Srafan#define LEAF_FMT "%02x"
1502174993Srafan#endif
1503174993Srafan		(void) sprintf(tfile[termcount], "%s/" LEAF_FMT "/%s",
1504174993Srafan			       directory,
1505174993Srafan			       UChar(*argv[optind]), argv[optind]);
1506174993Srafan		if (itrace)
1507174993Srafan		    (void) fprintf(stderr,
1508174993Srafan				   "%s: reading entry %s from file %s\n",
1509174993Srafan				   _nc_progname,
1510174993Srafan				   argv[optind], tfile[termcount]);
151150276Speter
1512174993Srafan		status = _nc_read_file_entry(tfile[termcount],
1513174993Srafan					     &entries[termcount].tterm);
1514166124Srafan#else
1515174993Srafan		(void) fprintf(stderr, "%s: terminfo files not supported\n",
1516174993Srafan			       _nc_progname);
1517174993Srafan		ExitProgram(EXIT_FAILURE);
1518166124Srafan#endif
1519174993Srafan	    } else {
1520174993Srafan		if (itrace)
1521174993Srafan		    (void) fprintf(stderr,
1522174993Srafan				   "%s: reading entry %s from database\n",
1523174993Srafan				   _nc_progname,
1524174993Srafan				   tname[termcount]);
152550276Speter
1526174993Srafan		status = _nc_read_entry(tname[termcount],
1527174993Srafan					tfile[termcount],
1528174993Srafan					&entries[termcount].tterm);
1529174993Srafan		directory = TERMINFO;	/* for error message */
1530174993Srafan	    }
153162449Speter
1532174993Srafan	    if (status <= 0) {
1533174993Srafan		(void) fprintf(stderr,
1534174993Srafan			       "%s: couldn't open terminfo file %s.\n",
1535174993Srafan			       _nc_progname,
1536174993Srafan			       tfile[termcount]);
1537174993Srafan		ExitProgram(EXIT_FAILURE);
153850276Speter	    }
1539174993Srafan	    repair_acsc(&entries[termcount].tterm);
1540174993Srafan	    termcount++;
154162449Speter	}
154250276Speter
154350276Speter#if NCURSES_XNAMES
154462449Speter	if (termcount > 1)
154562449Speter	    _nc_align_termtype(&entries[0].tterm, &entries[1].tterm);
154650276Speter#endif
154750276Speter
154862449Speter	/* dump as C initializer for the terminal type */
154962449Speter	if (initdump) {
155062449Speter	    if (initdump & 1)
155162449Speter		dump_termtype(&entries[0].tterm);
155262449Speter	    if (initdump & 2)
155362449Speter		dump_initializers(&entries[0].tterm);
155462449Speter	}
155550276Speter
155662449Speter	/* analyze the init strings */
1557166124Srafan	else if (init_analyze) {
155850276Speter#undef CUR
155962449Speter#define CUR	entries[0].tterm.
156062449Speter	    analyze_string("is1", init_1string, &entries[0].tterm);
156162449Speter	    analyze_string("is2", init_2string, &entries[0].tterm);
156262449Speter	    analyze_string("is3", init_3string, &entries[0].tterm);
156362449Speter	    analyze_string("rs1", reset_1string, &entries[0].tterm);
156462449Speter	    analyze_string("rs2", reset_2string, &entries[0].tterm);
156562449Speter	    analyze_string("rs3", reset_3string, &entries[0].tterm);
156662449Speter	    analyze_string("smcup", enter_ca_mode, &entries[0].tterm);
156762449Speter	    analyze_string("rmcup", exit_ca_mode, &entries[0].tterm);
156850276Speter#undef CUR
1569166124Srafan	} else {
157050276Speter
1571166124Srafan	    /*
1572166124Srafan	     * Here's where the real work gets done
1573166124Srafan	     */
1574166124Srafan	    switch (compare) {
1575166124Srafan	    case C_DEFAULT:
1576166124Srafan		if (itrace)
1577166124Srafan		    (void) fprintf(stderr,
1578174993Srafan				   "%s: about to dump %s\n",
1579174993Srafan				   _nc_progname,
1580166124Srafan				   tname[0]);
1581166124Srafan		(void) printf("#\tReconstructed via infocmp from file: %s\n",
1582166124Srafan			      tfile[0]);
1583166124Srafan		dump_entry(&entries[0].tterm,
1584166124Srafan			   suppress_untranslatable,
1585166124Srafan			   limited,
1586166124Srafan			   numbers,
1587166124Srafan			   NULL);
1588166124Srafan		len = show_entry();
1589166124Srafan		if (itrace)
1590174993Srafan		    (void) fprintf(stderr, "%s: length %d\n", _nc_progname, len);
1591166124Srafan		break;
159250276Speter
1593166124Srafan	    case C_DIFFERENCE:
1594166124Srafan		if (itrace)
1595174993Srafan		    (void) fprintf(stderr, "%s: dumping differences\n", _nc_progname);
1596166124Srafan		(void) printf("comparing %s to %s.\n", tname[0], tname[1]);
1597166124Srafan		compare_entry(compare_predicate, &entries->tterm, quiet);
1598166124Srafan		break;
159950276Speter
1600166124Srafan	    case C_COMMON:
1601166124Srafan		if (itrace)
1602166124Srafan		    (void) fprintf(stderr,
1603174993Srafan				   "%s: dumping common capabilities\n",
1604174993Srafan				   _nc_progname);
1605166124Srafan		(void) printf("comparing %s to %s.\n", tname[0], tname[1]);
1606166124Srafan		compare_entry(compare_predicate, &entries->tterm, quiet);
1607166124Srafan		break;
160850276Speter
1609166124Srafan	    case C_NAND:
1610166124Srafan		if (itrace)
1611166124Srafan		    (void) fprintf(stderr,
1612174993Srafan				   "%s: dumping differences\n",
1613174993Srafan				   _nc_progname);
1614166124Srafan		(void) printf("comparing %s to %s.\n", tname[0], tname[1]);
1615166124Srafan		compare_entry(compare_predicate, &entries->tterm, quiet);
1616166124Srafan		break;
161750276Speter
1618166124Srafan	    case C_USEALL:
1619166124Srafan		if (itrace)
1620174993Srafan		    (void) fprintf(stderr, "%s: dumping use entry\n", _nc_progname);
1621166124Srafan		dump_entry(&entries[0].tterm,
1622166124Srafan			   suppress_untranslatable,
1623166124Srafan			   limited,
1624166124Srafan			   numbers,
1625166124Srafan			   use_predicate);
1626166124Srafan		for (i = 1; i < termcount; i++)
1627166124Srafan		    dump_uses(tname[i], !(outform == F_TERMCAP
1628166124Srafan					  || outform == F_TCONVERR));
1629166124Srafan		len = show_entry();
1630166124Srafan		if (itrace)
1631174993Srafan		    (void) fprintf(stderr, "%s: length %d\n", _nc_progname, len);
1632166124Srafan		break;
1633166124Srafan	    }
163450276Speter	}
163562449Speter    } else if (compare == C_USEALL)
163662449Speter	(void) fprintf(stderr, "Sorry, -u doesn't work with -F\n");
163762449Speter    else if (compare == C_DEFAULT)
163862449Speter	(void) fprintf(stderr, "Use `tic -[CI] <file>' for this.\n");
163962449Speter    else if (argc - optind != 2)
164062449Speter	(void) fprintf(stderr,
164166963Speter		       "File comparison needs exactly two file arguments.\n");
164262449Speter    else
164362449Speter	file_comparison(argc - optind, argv + optind);
164450276Speter
1645174993Srafan#if NO_LEAKS
1646174993Srafan    free(myargv);
1647166124Srafan    free(tfile);
1648174993Srafan    free(tname);
1649174993Srafan#endif
165062449Speter    ExitProgram(EXIT_SUCCESS);
165150276Speter}
165250276Speter
165350276Speter/* infocmp.c ends here */
1654