xref: /freebsd-src/contrib/ncurses/progs/infocmp.c (revision 18259542b2f8fa7e3f76f4bb0dd37995dfd424aa)
10e3d5408SPeter Wemm /****************************************************************************
215589c42SPeter Wemm  * Copyright (c) 1998,1999,2000 Free Software Foundation, Inc.              *
30e3d5408SPeter Wemm  *                                                                          *
40e3d5408SPeter Wemm  * Permission is hereby granted, free of charge, to any person obtaining a  *
50e3d5408SPeter Wemm  * copy of this software and associated documentation files (the            *
60e3d5408SPeter Wemm  * "Software"), to deal in the Software without restriction, including      *
70e3d5408SPeter Wemm  * without limitation the rights to use, copy, modify, merge, publish,      *
80e3d5408SPeter Wemm  * distribute, distribute with modifications, sublicense, and/or sell       *
90e3d5408SPeter Wemm  * copies of the Software, and to permit persons to whom the Software is    *
100e3d5408SPeter Wemm  * furnished to do so, subject to the following conditions:                 *
110e3d5408SPeter Wemm  *                                                                          *
120e3d5408SPeter Wemm  * The above copyright notice and this permission notice shall be included  *
130e3d5408SPeter Wemm  * in all copies or substantial portions of the Software.                   *
140e3d5408SPeter Wemm  *                                                                          *
150e3d5408SPeter Wemm  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
160e3d5408SPeter Wemm  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
170e3d5408SPeter Wemm  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
180e3d5408SPeter Wemm  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
190e3d5408SPeter Wemm  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
200e3d5408SPeter Wemm  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
210e3d5408SPeter Wemm  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
220e3d5408SPeter Wemm  *                                                                          *
230e3d5408SPeter Wemm  * Except as contained in this notice, the name(s) of the above copyright   *
240e3d5408SPeter Wemm  * holders shall not be used in advertising or otherwise to promote the     *
250e3d5408SPeter Wemm  * sale, use or other dealings in this Software without prior written       *
260e3d5408SPeter Wemm  * authorization.                                                           *
270e3d5408SPeter Wemm  ****************************************************************************/
280e3d5408SPeter Wemm 
290e3d5408SPeter Wemm /****************************************************************************
300e3d5408SPeter Wemm  *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
310e3d5408SPeter Wemm  *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
320e3d5408SPeter Wemm  ****************************************************************************/
330e3d5408SPeter Wemm 
340e3d5408SPeter Wemm /*
350e3d5408SPeter Wemm  *	infocmp.c -- decompile an entry, or compare two entries
360e3d5408SPeter Wemm  *		written by Eric S. Raymond
370e3d5408SPeter Wemm  */
380e3d5408SPeter Wemm 
390e3d5408SPeter Wemm #include <progs.priv.h>
400e3d5408SPeter Wemm 
410e3d5408SPeter Wemm #include <term_entry.h>
420e3d5408SPeter Wemm #include <dump_entry.h>
430e3d5408SPeter Wemm 
44*18259542SPeter Wemm MODULE_ID("$Id: infocmp.c,v 1.57 2000/10/01 01:26:25 tom Exp $")
450e3d5408SPeter Wemm 
460e3d5408SPeter Wemm #define L_CURL "{"
470e3d5408SPeter Wemm #define R_CURL "}"
480e3d5408SPeter Wemm 
490e3d5408SPeter Wemm #define MAXTERMS	32	/* max # terminal arguments we can handle */
5015589c42SPeter Wemm #define MAX_STRING	1024	/* maximum formatted string */
510e3d5408SPeter Wemm 
520e3d5408SPeter Wemm const char *_nc_progname = "infocmp";
530e3d5408SPeter Wemm 
540e3d5408SPeter Wemm typedef char path[PATH_MAX];
550e3d5408SPeter Wemm 
560e3d5408SPeter Wemm /***************************************************************************
570e3d5408SPeter Wemm  *
580e3d5408SPeter Wemm  * The following control variables, together with the contents of the
590e3d5408SPeter Wemm  * terminfo entries, completely determine the actions of the program.
600e3d5408SPeter Wemm  *
610e3d5408SPeter Wemm  ***************************************************************************/
620e3d5408SPeter Wemm 
630e3d5408SPeter Wemm static char *tname[MAXTERMS];	/* terminal type names */
6415589c42SPeter Wemm static ENTRY entries[MAXTERMS];	/* terminfo entries */
650e3d5408SPeter Wemm static int termcount;		/* count of terminal entries */
660e3d5408SPeter Wemm 
6715589c42SPeter Wemm static bool limited = TRUE;	/* "-r" option is not set */
6815589c42SPeter Wemm static bool quiet = FALSE;
6915589c42SPeter Wemm static const char *bool_sep = ":";
7015589c42SPeter Wemm static const char *s_absent = "NULL";
7115589c42SPeter Wemm static const char *s_cancel = "NULL";
720e3d5408SPeter Wemm static const char *tversion;	/* terminfo version selected */
730e3d5408SPeter Wemm static int itrace;		/* trace flag for debugging */
740e3d5408SPeter Wemm static int mwidth = 60;
7515589c42SPeter Wemm static int numbers = 0;		/* format "%'char'" to/from "%{number}" */
7615589c42SPeter Wemm static int outform = F_TERMINFO;	/* output format */
7715589c42SPeter Wemm static int sortmode;		/* sort_mode */
780e3d5408SPeter Wemm 
790e3d5408SPeter Wemm /* main comparison mode */
800e3d5408SPeter Wemm static int compare;
810e3d5408SPeter Wemm #define C_DEFAULT	0	/* don't force comparison mode */
820e3d5408SPeter Wemm #define C_DIFFERENCE	1	/* list differences between two terminals */
830e3d5408SPeter Wemm #define C_COMMON	2	/* list common capabilities */
840e3d5408SPeter Wemm #define C_NAND		3	/* list capabilities in neither terminal */
850e3d5408SPeter Wemm #define C_USEALL	4	/* generate relative use-form entry */
860e3d5408SPeter Wemm static bool ignorepads;		/* ignore pad prefixes when diffing */
870e3d5408SPeter Wemm 
880e3d5408SPeter Wemm #if NO_LEAKS
890e3d5408SPeter Wemm #undef ExitProgram
9015589c42SPeter Wemm static void
9115589c42SPeter Wemm ExitProgram(int code) GCC_NORETURN;
9215589c42SPeter Wemm /* prototype is to get gcc to accept the noreturn attribute */
9315589c42SPeter Wemm      static void
9415589c42SPeter Wemm        ExitProgram(int code)
950e3d5408SPeter Wemm {
960e3d5408SPeter Wemm     while (termcount-- > 0)
9715589c42SPeter Wemm 	_nc_free_termtype(&entries[termcount].tterm);
980e3d5408SPeter Wemm     _nc_leaks_dump_entry();
990e3d5408SPeter Wemm     _nc_free_and_exit(code);
1000e3d5408SPeter Wemm }
1010e3d5408SPeter Wemm #endif
1020e3d5408SPeter Wemm 
10315589c42SPeter Wemm static char *
10415589c42SPeter Wemm canonical_name(char *ptr, char *buf)
1050e3d5408SPeter Wemm /* extract the terminal type's primary name */
1060e3d5408SPeter Wemm {
1070e3d5408SPeter Wemm     char *bp;
1080e3d5408SPeter Wemm 
1090e3d5408SPeter Wemm     (void) strcpy(buf, ptr);
11015589c42SPeter Wemm     if ((bp = strchr(buf, '|')) != 0)
1110e3d5408SPeter Wemm 	*bp = '\0';
1120e3d5408SPeter Wemm 
1130e3d5408SPeter Wemm     return (buf);
1140e3d5408SPeter Wemm }
1150e3d5408SPeter Wemm 
1160e3d5408SPeter Wemm /***************************************************************************
1170e3d5408SPeter Wemm  *
1180e3d5408SPeter Wemm  * Predicates for dump function
1190e3d5408SPeter Wemm  *
1200e3d5408SPeter Wemm  ***************************************************************************/
1210e3d5408SPeter Wemm 
12215589c42SPeter Wemm static int
12315589c42SPeter Wemm capcmp(int idx, const char *s, const char *t)
1240e3d5408SPeter Wemm /* capability comparison function */
1250e3d5408SPeter Wemm {
1260e3d5408SPeter Wemm     if (!VALID_STRING(s) && !VALID_STRING(t))
12715589c42SPeter Wemm 	return (s != t);
1280e3d5408SPeter Wemm     else if (!VALID_STRING(s) || !VALID_STRING(t))
1290e3d5408SPeter Wemm 	return (1);
1300e3d5408SPeter Wemm 
13115589c42SPeter Wemm     if ((idx == acs_chars_index) || !ignorepads)
1320e3d5408SPeter Wemm 	return (strcmp(s, t));
13315589c42SPeter Wemm     else
13415589c42SPeter Wemm 	return (_nc_capcmp(s, t));
1350e3d5408SPeter Wemm }
1360e3d5408SPeter Wemm 
13715589c42SPeter Wemm static int
13815589c42SPeter Wemm use_predicate(int type, int idx)
1390e3d5408SPeter Wemm /* predicate function to use for use decompilation */
1400e3d5408SPeter Wemm {
14115589c42SPeter Wemm     ENTRY *ep;
1420e3d5408SPeter Wemm 
14315589c42SPeter Wemm     switch (type) {
14415589c42SPeter Wemm     case BOOLEAN:
1450e3d5408SPeter Wemm 	{
1460e3d5408SPeter Wemm 	    int is_set = FALSE;
1470e3d5408SPeter Wemm 
1480e3d5408SPeter Wemm 	    /*
1490e3d5408SPeter Wemm 	     * This assumes that multiple use entries are supposed
1500e3d5408SPeter Wemm 	     * to contribute the logical or of their boolean capabilities.
1510e3d5408SPeter Wemm 	     * This is true if we take the semantics of multiple uses to
1520e3d5408SPeter Wemm 	     * be 'each capability gets the first non-default value found
1530e3d5408SPeter Wemm 	     * in the sequence of use entries'.
15415589c42SPeter Wemm 	     *
15515589c42SPeter Wemm 	     * Note that cancelled or absent booleans are stored as FALSE,
15615589c42SPeter Wemm 	     * unlike numbers and strings, whose cancelled/absent state is
15715589c42SPeter Wemm 	     * recorded in the terminfo database.
1580e3d5408SPeter Wemm 	     */
15915589c42SPeter Wemm 	    for (ep = &entries[1]; ep < entries + termcount; ep++)
16015589c42SPeter Wemm 		if (ep->tterm.Booleans[idx] == TRUE) {
16115589c42SPeter Wemm 		    is_set = entries[0].tterm.Booleans[idx];
1620e3d5408SPeter Wemm 		    break;
1630e3d5408SPeter Wemm 		}
16415589c42SPeter Wemm 	    if (is_set != entries[0].tterm.Booleans[idx])
1650e3d5408SPeter Wemm 		return (!is_set);
1660e3d5408SPeter Wemm 	    else
1670e3d5408SPeter Wemm 		return (FAIL);
1680e3d5408SPeter Wemm 	}
1690e3d5408SPeter Wemm 
17015589c42SPeter Wemm     case NUMBER:
17115589c42SPeter Wemm 	{
1720e3d5408SPeter Wemm 	    int value = ABSENT_NUMERIC;
1730e3d5408SPeter Wemm 
1740e3d5408SPeter Wemm 	    /*
1750e3d5408SPeter Wemm 	     * We take the semantics of multiple uses to be 'each
1760e3d5408SPeter Wemm 	     * capability gets the first non-default value found
1770e3d5408SPeter Wemm 	     * in the sequence of use entries'.
1780e3d5408SPeter Wemm 	     */
17915589c42SPeter Wemm 	    for (ep = &entries[1]; ep < entries + termcount; ep++)
18015589c42SPeter Wemm 		if (VALID_NUMERIC(ep->tterm.Numbers[idx])) {
18115589c42SPeter Wemm 		    value = ep->tterm.Numbers[idx];
1820e3d5408SPeter Wemm 		    break;
1830e3d5408SPeter Wemm 		}
1840e3d5408SPeter Wemm 
18515589c42SPeter Wemm 	    if (value != entries[0].tterm.Numbers[idx])
1860e3d5408SPeter Wemm 		return (value != ABSENT_NUMERIC);
1870e3d5408SPeter Wemm 	    else
1880e3d5408SPeter Wemm 		return (FAIL);
1890e3d5408SPeter Wemm 	}
1900e3d5408SPeter Wemm 
19115589c42SPeter Wemm     case STRING:
19215589c42SPeter Wemm 	{
1930e3d5408SPeter Wemm 	    char *termstr, *usestr = ABSENT_STRING;
1940e3d5408SPeter Wemm 
19515589c42SPeter Wemm 	    termstr = entries[0].tterm.Strings[idx];
1960e3d5408SPeter Wemm 
1970e3d5408SPeter Wemm 	    /*
1980e3d5408SPeter Wemm 	     * We take the semantics of multiple uses to be 'each
1990e3d5408SPeter Wemm 	     * capability gets the first non-default value found
2000e3d5408SPeter Wemm 	     * in the sequence of use entries'.
2010e3d5408SPeter Wemm 	     */
20215589c42SPeter Wemm 	    for (ep = &entries[1]; ep < entries + termcount; ep++)
20315589c42SPeter Wemm 		if (ep->tterm.Strings[idx]) {
20415589c42SPeter Wemm 		    usestr = ep->tterm.Strings[idx];
2050e3d5408SPeter Wemm 		    break;
2060e3d5408SPeter Wemm 		}
2070e3d5408SPeter Wemm 
2080e3d5408SPeter Wemm 	    if (usestr == ABSENT_STRING && termstr == ABSENT_STRING)
2090e3d5408SPeter Wemm 		return (FAIL);
21015589c42SPeter Wemm 	    else if (!usestr || !termstr || capcmp(idx, usestr, termstr))
2110e3d5408SPeter Wemm 		return (TRUE);
2120e3d5408SPeter Wemm 	    else
2130e3d5408SPeter Wemm 		return (FAIL);
2140e3d5408SPeter Wemm 	}
2150e3d5408SPeter Wemm     }
2160e3d5408SPeter Wemm 
2170e3d5408SPeter Wemm     return (FALSE);		/* pacify compiler */
2180e3d5408SPeter Wemm }
2190e3d5408SPeter Wemm 
22015589c42SPeter Wemm static bool
22115589c42SPeter Wemm useeq(ENTRY * e1, ENTRY * e2)
22215589c42SPeter Wemm /* are the use references in two entries equivalent? */
22315589c42SPeter Wemm {
22415589c42SPeter Wemm     int i, j;
22515589c42SPeter Wemm 
22615589c42SPeter Wemm     if (e1->nuses != e2->nuses)
22715589c42SPeter Wemm 	return (FALSE);
22815589c42SPeter Wemm 
22915589c42SPeter Wemm     /* Ugh...this is quadratic again */
23015589c42SPeter Wemm     for (i = 0; i < e1->nuses; i++) {
23115589c42SPeter Wemm 	bool foundmatch = FALSE;
23215589c42SPeter Wemm 
23315589c42SPeter Wemm 	/* search second entry for given use reference */
23415589c42SPeter Wemm 	for (j = 0; j < e2->nuses; j++)
23515589c42SPeter Wemm 	    if (!strcmp(e1->uses[i].name, e2->uses[j].name)) {
23615589c42SPeter Wemm 		foundmatch = TRUE;
23715589c42SPeter Wemm 		break;
23815589c42SPeter Wemm 	    }
23915589c42SPeter Wemm 
24015589c42SPeter Wemm 	if (!foundmatch)
24115589c42SPeter Wemm 	    return (FALSE);
24215589c42SPeter Wemm     }
24315589c42SPeter Wemm 
24415589c42SPeter Wemm     return (TRUE);
24515589c42SPeter Wemm }
24615589c42SPeter Wemm 
24715589c42SPeter Wemm static bool
24815589c42SPeter Wemm entryeq(TERMTYPE * t1, TERMTYPE * t2)
24915589c42SPeter Wemm /* are two entries equivalent? */
2500e3d5408SPeter Wemm {
2510e3d5408SPeter Wemm     int i;
2520e3d5408SPeter Wemm 
2530e3d5408SPeter Wemm     for (i = 0; i < NUM_BOOLEANS(t1); i++)
2540e3d5408SPeter Wemm 	if (t1->Booleans[i] != t2->Booleans[i])
2550e3d5408SPeter Wemm 	    return (FALSE);
2560e3d5408SPeter Wemm 
2570e3d5408SPeter Wemm     for (i = 0; i < NUM_NUMBERS(t1); i++)
2580e3d5408SPeter Wemm 	if (t1->Numbers[i] != t2->Numbers[i])
2590e3d5408SPeter Wemm 	    return (FALSE);
2600e3d5408SPeter Wemm 
2610e3d5408SPeter Wemm     for (i = 0; i < NUM_STRINGS(t1); i++)
26215589c42SPeter Wemm 	if (capcmp(i, t1->Strings[i], t2->Strings[i]))
2630e3d5408SPeter Wemm 	    return (FALSE);
2640e3d5408SPeter Wemm 
2650e3d5408SPeter Wemm     return (TRUE);
2660e3d5408SPeter Wemm }
2670e3d5408SPeter Wemm 
2680e3d5408SPeter Wemm #define TIC_EXPAND(result) _nc_tic_expand(result, outform==F_TERMINFO, numbers)
2690e3d5408SPeter Wemm 
27015589c42SPeter Wemm static void
27115589c42SPeter Wemm print_uses(ENTRY * ep, FILE * fp)
27215589c42SPeter Wemm /* print an entry's use references */
27315589c42SPeter Wemm {
27415589c42SPeter Wemm     int i;
27515589c42SPeter Wemm 
27615589c42SPeter Wemm     if (!ep->nuses)
27715589c42SPeter Wemm 	fputs("NULL", fp);
27815589c42SPeter Wemm     else
27915589c42SPeter Wemm 	for (i = 0; i < ep->nuses; i++) {
28015589c42SPeter Wemm 	    fputs(ep->uses[i].name, fp);
28115589c42SPeter Wemm 	    if (i < ep->nuses - 1)
28215589c42SPeter Wemm 		fputs(" ", fp);
28315589c42SPeter Wemm 	}
28415589c42SPeter Wemm }
28515589c42SPeter Wemm 
28615589c42SPeter Wemm static const char *
28715589c42SPeter Wemm dump_boolean(int val)
28815589c42SPeter Wemm /* display the value of a boolean capability */
28915589c42SPeter Wemm {
29015589c42SPeter Wemm     switch (val) {
29115589c42SPeter Wemm     case ABSENT_BOOLEAN:
29215589c42SPeter Wemm 	return (s_absent);
29315589c42SPeter Wemm     case CANCELLED_BOOLEAN:
29415589c42SPeter Wemm 	return (s_cancel);
29515589c42SPeter Wemm     case FALSE:
29615589c42SPeter Wemm 	return ("F");
29715589c42SPeter Wemm     case TRUE:
29815589c42SPeter Wemm 	return ("T");
29915589c42SPeter Wemm     default:
30015589c42SPeter Wemm 	return ("?");
30115589c42SPeter Wemm     }
30215589c42SPeter Wemm }
30315589c42SPeter Wemm 
30415589c42SPeter Wemm static void
30515589c42SPeter Wemm dump_numeric(int val, char *buf)
30615589c42SPeter Wemm /* display the value of a boolean capability */
30715589c42SPeter Wemm {
30815589c42SPeter Wemm     switch (val) {
30915589c42SPeter Wemm     case ABSENT_NUMERIC:
31015589c42SPeter Wemm 	strcpy(buf, s_absent);
31115589c42SPeter Wemm 	break;
31215589c42SPeter Wemm     case CANCELLED_NUMERIC:
31315589c42SPeter Wemm 	strcpy(buf, s_cancel);
31415589c42SPeter Wemm 	break;
31515589c42SPeter Wemm     default:
31615589c42SPeter Wemm 	sprintf(buf, "%d", val);
31715589c42SPeter Wemm 	break;
31815589c42SPeter Wemm     }
31915589c42SPeter Wemm }
32015589c42SPeter Wemm 
32115589c42SPeter Wemm static void
32215589c42SPeter Wemm dump_string(char *val, char *buf)
32315589c42SPeter Wemm /* display the value of a string capability */
32415589c42SPeter Wemm {
32515589c42SPeter Wemm     if (val == ABSENT_STRING)
32615589c42SPeter Wemm 	strcpy(buf, s_absent);
32715589c42SPeter Wemm     else if (val == CANCELLED_STRING)
32815589c42SPeter Wemm 	strcpy(buf, s_cancel);
32915589c42SPeter Wemm     else {
33015589c42SPeter Wemm 	sprintf(buf, "'%.*s'", MAX_STRING - 3, TIC_EXPAND(val));
33115589c42SPeter Wemm     }
33215589c42SPeter Wemm }
33315589c42SPeter Wemm 
33415589c42SPeter Wemm static void
33515589c42SPeter Wemm compare_predicate(int type, int idx, const char *name)
3360e3d5408SPeter Wemm /* predicate function to use for entry difference reports */
3370e3d5408SPeter Wemm {
33815589c42SPeter Wemm     register ENTRY *e1 = &entries[0];
33915589c42SPeter Wemm     register ENTRY *e2 = &entries[1];
34015589c42SPeter Wemm     char buf1[MAX_STRING], buf2[MAX_STRING];
34115589c42SPeter Wemm     int b1, b2;
34215589c42SPeter Wemm     int n1, n2;
3430e3d5408SPeter Wemm     char *s1, *s2;
3440e3d5408SPeter Wemm 
34515589c42SPeter Wemm     switch (type) {
34615589c42SPeter Wemm     case CMP_BOOLEAN:
34715589c42SPeter Wemm 	b1 = e1->tterm.Booleans[idx];
34815589c42SPeter Wemm 	b2 = e2->tterm.Booleans[idx];
34915589c42SPeter Wemm 	switch (compare) {
3500e3d5408SPeter Wemm 	case C_DIFFERENCE:
35115589c42SPeter Wemm 	    if (!(b1 == ABSENT_BOOLEAN && b2 == ABSENT_BOOLEAN) && b1 != b2)
35215589c42SPeter Wemm 		(void) printf("\t%s: %s%s%s.\n",
3530e3d5408SPeter Wemm 			      name,
35415589c42SPeter Wemm 			      dump_boolean(b1),
35515589c42SPeter Wemm 			      bool_sep,
35615589c42SPeter Wemm 			      dump_boolean(b2));
3570e3d5408SPeter Wemm 	    break;
3580e3d5408SPeter Wemm 
3590e3d5408SPeter Wemm 	case C_COMMON:
36015589c42SPeter Wemm 	    if (b1 == b2 && b1 != ABSENT_BOOLEAN)
36115589c42SPeter Wemm 		(void) printf("\t%s= %s.\n", name, dump_boolean(b1));
3620e3d5408SPeter Wemm 	    break;
3630e3d5408SPeter Wemm 
3640e3d5408SPeter Wemm 	case C_NAND:
36515589c42SPeter Wemm 	    if (b1 == ABSENT_BOOLEAN && b2 == ABSENT_BOOLEAN)
3660e3d5408SPeter Wemm 		(void) printf("\t!%s.\n", name);
3670e3d5408SPeter Wemm 	    break;
3680e3d5408SPeter Wemm 	}
3690e3d5408SPeter Wemm 	break;
3700e3d5408SPeter Wemm 
37115589c42SPeter Wemm     case CMP_NUMBER:
37215589c42SPeter Wemm 	n1 = e1->tterm.Numbers[idx];
37315589c42SPeter Wemm 	n2 = e2->tterm.Numbers[idx];
37415589c42SPeter Wemm 	dump_numeric(n1, buf1);
37515589c42SPeter Wemm 	dump_numeric(n2, buf2);
37615589c42SPeter Wemm 	switch (compare) {
3770e3d5408SPeter Wemm 	case C_DIFFERENCE:
37815589c42SPeter Wemm 	    if (!((n1 == ABSENT_NUMERIC && n2 == ABSENT_NUMERIC)) && n1 != n2)
37915589c42SPeter Wemm 		(void) printf("\t%s: %s, %s.\n", name, buf1, buf2);
3800e3d5408SPeter Wemm 	    break;
3810e3d5408SPeter Wemm 
3820e3d5408SPeter Wemm 	case C_COMMON:
38315589c42SPeter Wemm 	    if (n1 != ABSENT_NUMERIC && n2 != ABSENT_NUMERIC && n1 == n2)
38415589c42SPeter Wemm 		(void) printf("\t%s= %s.\n", name, buf1);
3850e3d5408SPeter Wemm 	    break;
3860e3d5408SPeter Wemm 
3870e3d5408SPeter Wemm 	case C_NAND:
38815589c42SPeter Wemm 	    if (n1 == ABSENT_NUMERIC && n2 == ABSENT_NUMERIC)
3890e3d5408SPeter Wemm 		(void) printf("\t!%s.\n", name);
3900e3d5408SPeter Wemm 	    break;
3910e3d5408SPeter Wemm 	}
3920e3d5408SPeter Wemm 	break;
3930e3d5408SPeter Wemm 
39415589c42SPeter Wemm     case CMP_STRING:
39515589c42SPeter Wemm 	s1 = e1->tterm.Strings[idx];
39615589c42SPeter Wemm 	s2 = e2->tterm.Strings[idx];
39715589c42SPeter Wemm 	switch (compare) {
3980e3d5408SPeter Wemm 	case C_DIFFERENCE:
39915589c42SPeter Wemm 	    if (capcmp(idx, s1, s2)) {
40015589c42SPeter Wemm 		dump_string(s1, buf1);
40115589c42SPeter Wemm 		dump_string(s2, buf2);
4020e3d5408SPeter Wemm 		if (strcmp(buf1, buf2))
40315589c42SPeter Wemm 		    (void) printf("\t%s: %s, %s.\n", name, buf1, buf2);
4040e3d5408SPeter Wemm 	    }
4050e3d5408SPeter Wemm 	    break;
4060e3d5408SPeter Wemm 
4070e3d5408SPeter Wemm 	case C_COMMON:
40815589c42SPeter Wemm 	    if (s1 && s2 && !capcmp(idx, s1, s2))
4090e3d5408SPeter Wemm 		(void) printf("\t%s= '%s'.\n", name, TIC_EXPAND(s1));
4100e3d5408SPeter Wemm 	    break;
4110e3d5408SPeter Wemm 
4120e3d5408SPeter Wemm 	case C_NAND:
4130e3d5408SPeter Wemm 	    if (!s1 && !s2)
4140e3d5408SPeter Wemm 		(void) printf("\t!%s.\n", name);
4150e3d5408SPeter Wemm 	    break;
4160e3d5408SPeter Wemm 	}
4170e3d5408SPeter Wemm 	break;
4180e3d5408SPeter Wemm 
41915589c42SPeter Wemm     case CMP_USE:
42015589c42SPeter Wemm 	/* unlike the other modes, this compares *all* use entries */
42115589c42SPeter Wemm 	switch (compare) {
42215589c42SPeter Wemm 	case C_DIFFERENCE:
42315589c42SPeter Wemm 	    if (!useeq(e1, e2)) {
42415589c42SPeter Wemm 		(void) fputs("\tuse: ", stdout);
42515589c42SPeter Wemm 		print_uses(e1, stdout);
42615589c42SPeter Wemm 		fputs(", ", stdout);
42715589c42SPeter Wemm 		print_uses(e2, stdout);
42815589c42SPeter Wemm 		fputs(".\n", stdout);
42915589c42SPeter Wemm 	    }
43015589c42SPeter Wemm 	    break;
43115589c42SPeter Wemm 
43215589c42SPeter Wemm 	case C_COMMON:
43315589c42SPeter Wemm 	    if (e1->nuses && e2->nuses && useeq(e1, e2)) {
43415589c42SPeter Wemm 		(void) fputs("\tuse: ", stdout);
43515589c42SPeter Wemm 		print_uses(e1, stdout);
43615589c42SPeter Wemm 		fputs(".\n", stdout);
43715589c42SPeter Wemm 	    }
43815589c42SPeter Wemm 	    break;
43915589c42SPeter Wemm 
44015589c42SPeter Wemm 	case C_NAND:
44115589c42SPeter Wemm 	    if (!e1->nuses && !e2->nuses)
44215589c42SPeter Wemm 		(void) printf("\t!use.\n");
44315589c42SPeter Wemm 	    break;
44415589c42SPeter Wemm 	}
44515589c42SPeter Wemm     }
4460e3d5408SPeter Wemm }
4470e3d5408SPeter Wemm 
4480e3d5408SPeter Wemm /***************************************************************************
4490e3d5408SPeter Wemm  *
4500e3d5408SPeter Wemm  * Init string analysis
4510e3d5408SPeter Wemm  *
4520e3d5408SPeter Wemm  ***************************************************************************/
4530e3d5408SPeter Wemm 
45415589c42SPeter Wemm typedef struct {
45515589c42SPeter Wemm     const char *from;
45615589c42SPeter Wemm     const char *to;
45715589c42SPeter Wemm } assoc;
4580e3d5408SPeter Wemm 
4590e3d5408SPeter Wemm static const assoc std_caps[] =
4600e3d5408SPeter Wemm {
4610e3d5408SPeter Wemm     /* these are specified by X.364 and iBCS2 */
4620e3d5408SPeter Wemm     {"\033c", "RIS"},		/* full reset */
4630e3d5408SPeter Wemm     {"\0337", "SC"},		/* save cursor */
4640e3d5408SPeter Wemm     {"\0338", "RC"},		/* restore cursor */
4650e3d5408SPeter Wemm     {"\033[r", "RSR"},		/* not an X.364 mnemonic */
4660e3d5408SPeter Wemm     {"\033[m", "SGR0"},		/* not an X.364 mnemonic */
4670e3d5408SPeter Wemm     {"\033[2J", "ED2"},		/* clear page */
4680e3d5408SPeter Wemm 
4690e3d5408SPeter Wemm     /* this group is specified by ISO 2022 */
4700e3d5408SPeter Wemm     {"\033(0", "ISO DEC G0"},	/* enable DEC graphics for G0 */
4710e3d5408SPeter Wemm     {"\033(A", "ISO UK G0"},	/* enable UK chars for G0 */
4720e3d5408SPeter Wemm     {"\033(B", "ISO US G0"},	/* enable US chars for G0 */
4730e3d5408SPeter Wemm     {"\033)0", "ISO DEC G1"},	/* enable DEC graphics for G1 */
4740e3d5408SPeter Wemm     {"\033)A", "ISO UK G1"},	/* enable UK chars for G1 */
4750e3d5408SPeter Wemm     {"\033)B", "ISO US G1"},	/* enable US chars for G1 */
4760e3d5408SPeter Wemm 
4770e3d5408SPeter Wemm     /* these are DEC private modes widely supported by emulators */
4780e3d5408SPeter Wemm     {"\033=", "DECPAM"},	/* application keypad mode */
4790e3d5408SPeter Wemm     {"\033>", "DECPNM"},	/* normal keypad mode */
4800e3d5408SPeter Wemm     {"\033<", "DECANSI"},	/* enter ANSI mode */
4810e3d5408SPeter Wemm 
4820e3d5408SPeter Wemm     {(char *) 0, (char *) 0}
4830e3d5408SPeter Wemm };
4840e3d5408SPeter Wemm 
4850e3d5408SPeter Wemm static const assoc private_modes[] =
4860e3d5408SPeter Wemm /* DEC \E[ ... [hl] modes recognized by many emulators */
4870e3d5408SPeter Wemm {
4880e3d5408SPeter Wemm     {"1", "CKM"},		/* application cursor keys */
4890e3d5408SPeter Wemm     {"2", "ANM"},		/* set VT52 mode */
4900e3d5408SPeter Wemm     {"3", "COLM"},		/* 132-column mode */
4910e3d5408SPeter Wemm     {"4", "SCLM"},		/* smooth scroll */
4920e3d5408SPeter Wemm     {"5", "SCNM"},		/* reverse video mode */
4930e3d5408SPeter Wemm     {"6", "OM"},		/* origin mode */
4940e3d5408SPeter Wemm     {"7", "AWM"},		/* wraparound mode */
4950e3d5408SPeter Wemm     {"8", "ARM"},		/* auto-repeat mode */
4960e3d5408SPeter Wemm     {(char *) 0, (char *) 0}
4970e3d5408SPeter Wemm };
4980e3d5408SPeter Wemm 
4990e3d5408SPeter Wemm static const assoc ecma_highlights[] =
5000e3d5408SPeter Wemm /* recognize ECMA attribute sequences */
5010e3d5408SPeter Wemm {
5020e3d5408SPeter Wemm     {"0", "NORMAL"},		/* normal */
5030e3d5408SPeter Wemm     {"1", "+BOLD"},		/* bold on */
5040e3d5408SPeter Wemm     {"2", "+DIM"},		/* dim on */
5050e3d5408SPeter Wemm     {"3", "+ITALIC"},		/* italic on */
5060e3d5408SPeter Wemm     {"4", "+UNDERLINE"},	/* underline on */
5070e3d5408SPeter Wemm     {"5", "+BLINK"},		/* blink on */
5080e3d5408SPeter Wemm     {"6", "+FASTBLINK"},	/* fastblink on */
5090e3d5408SPeter Wemm     {"7", "+REVERSE"},		/* reverse on */
5100e3d5408SPeter Wemm     {"8", "+INVISIBLE"},	/* invisible on */
5110e3d5408SPeter Wemm     {"9", "+DELETED"},		/* deleted on */
5120e3d5408SPeter Wemm     {"10", "MAIN-FONT"},	/* select primary font */
5130e3d5408SPeter Wemm     {"11", "ALT-FONT-1"},	/* select alternate font 1 */
5140e3d5408SPeter Wemm     {"12", "ALT-FONT-2"},	/* select alternate font 2 */
5150e3d5408SPeter Wemm     {"13", "ALT-FONT-3"},	/* select alternate font 3 */
5160e3d5408SPeter Wemm     {"14", "ALT-FONT-4"},	/* select alternate font 4 */
5170e3d5408SPeter Wemm     {"15", "ALT-FONT-5"},	/* select alternate font 5 */
5180e3d5408SPeter Wemm     {"16", "ALT-FONT-6"},	/* select alternate font 6 */
5190e3d5408SPeter Wemm     {"17", "ALT-FONT-7"},	/* select alternate font 7 */
5200e3d5408SPeter Wemm     {"18", "ALT-FONT-1"},	/* select alternate font 1 */
5210e3d5408SPeter Wemm     {"19", "ALT-FONT-1"},	/* select alternate font 1 */
5220e3d5408SPeter Wemm     {"20", "FRAKTUR"},		/* Fraktur font */
5230e3d5408SPeter Wemm     {"21", "DOUBLEUNDER"},	/* double underline */
5240e3d5408SPeter Wemm     {"22", "-DIM"},		/* dim off */
5250e3d5408SPeter Wemm     {"23", "-ITALIC"},		/* italic off */
5260e3d5408SPeter Wemm     {"24", "-UNDERLINE"},	/* underline off */
5270e3d5408SPeter Wemm     {"25", "-BLINK"},		/* blink off */
5280e3d5408SPeter Wemm     {"26", "-FASTBLINK"},	/* fastblink off */
5290e3d5408SPeter Wemm     {"27", "-REVERSE"},		/* reverse off */
5300e3d5408SPeter Wemm     {"28", "-INVISIBLE"},	/* invisible off */
5310e3d5408SPeter Wemm     {"29", "-DELETED"},		/* deleted off */
5320e3d5408SPeter Wemm     {(char *) 0, (char *) 0}
5330e3d5408SPeter Wemm };
5340e3d5408SPeter Wemm 
53515589c42SPeter Wemm static void
53615589c42SPeter Wemm analyze_string(const char *name, const char *cap, TERMTYPE * tp)
5370e3d5408SPeter Wemm {
5380e3d5408SPeter Wemm     char buf[MAX_TERMINFO_LENGTH];
5390e3d5408SPeter Wemm     char buf2[MAX_TERMINFO_LENGTH];
5400e3d5408SPeter Wemm     const char *sp, *ep;
5410e3d5408SPeter Wemm     const assoc *ap;
5420e3d5408SPeter Wemm 
5430e3d5408SPeter Wemm     if (cap == ABSENT_STRING || cap == CANCELLED_STRING)
5440e3d5408SPeter Wemm 	return;
5450e3d5408SPeter Wemm     (void) printf("%s: ", name);
5460e3d5408SPeter Wemm 
5470e3d5408SPeter Wemm     buf[0] = '\0';
54815589c42SPeter Wemm     for (sp = cap; *sp; sp++) {
5490e3d5408SPeter Wemm 	int i;
5500e3d5408SPeter Wemm 	size_t len = 0;
5510e3d5408SPeter Wemm 	const char *expansion = 0;
5520e3d5408SPeter Wemm 
5530e3d5408SPeter Wemm 	/* first, check other capabilities in this entry */
55415589c42SPeter Wemm 	for (i = 0; i < STRCOUNT; i++) {
5550e3d5408SPeter Wemm 	    char *cp = tp->Strings[i];
5560e3d5408SPeter Wemm 
5570e3d5408SPeter Wemm 	    /* don't use soft-key capabilities */
5580e3d5408SPeter Wemm 	    if (strnames[i][0] == 'k' && strnames[i][0] == 'f')
5590e3d5408SPeter Wemm 		continue;
5600e3d5408SPeter Wemm 
56115589c42SPeter Wemm 	    if (cp != ABSENT_STRING && cp != CANCELLED_STRING && cp[0] && cp
56215589c42SPeter Wemm 		!= cap) {
5630e3d5408SPeter Wemm 		len = strlen(cp);
5640e3d5408SPeter Wemm 		(void) strncpy(buf2, sp, len);
5650e3d5408SPeter Wemm 		buf2[len] = '\0';
5660e3d5408SPeter Wemm 
5670e3d5408SPeter Wemm 		if (_nc_capcmp(cp, buf2))
5680e3d5408SPeter Wemm 		    continue;
5690e3d5408SPeter Wemm 
5700e3d5408SPeter Wemm #define ISRS(s)	(!strncmp((s), "is", 2) || !strncmp((s), "rs", 2))
5710e3d5408SPeter Wemm 		/*
5720e3d5408SPeter Wemm 		 * Theoretically we just passed the test for translation
5730e3d5408SPeter Wemm 		 * (equality once the padding is stripped).  However, there
5740e3d5408SPeter Wemm 		 * are a few more hoops that need to be jumped so that
5750e3d5408SPeter Wemm 		 * identical pairs of initialization and reset strings
5760e3d5408SPeter Wemm 		 * don't just refer to each other.
5770e3d5408SPeter Wemm 		 */
5780e3d5408SPeter Wemm 		if (ISRS(name) || ISRS(strnames[i]))
5790e3d5408SPeter Wemm 		    if (cap < cp)
5800e3d5408SPeter Wemm 			continue;
5810e3d5408SPeter Wemm #undef ISRS
5820e3d5408SPeter Wemm 
5830e3d5408SPeter Wemm 		expansion = strnames[i];
5840e3d5408SPeter Wemm 		break;
5850e3d5408SPeter Wemm 	    }
5860e3d5408SPeter Wemm 	}
5870e3d5408SPeter Wemm 
5880e3d5408SPeter Wemm 	/* now check the standard capabilities */
5890e3d5408SPeter Wemm 	if (!expansion)
59015589c42SPeter Wemm 	    for (ap = std_caps; ap->from; ap++) {
5910e3d5408SPeter Wemm 		len = strlen(ap->from);
5920e3d5408SPeter Wemm 
59315589c42SPeter Wemm 		if (strncmp(ap->from, sp, len) == 0) {
5940e3d5408SPeter Wemm 		    expansion = ap->to;
5950e3d5408SPeter Wemm 		    break;
5960e3d5408SPeter Wemm 		}
5970e3d5408SPeter Wemm 	    }
5980e3d5408SPeter Wemm 
5990e3d5408SPeter Wemm 	/* now check for private-mode sequences */
6000e3d5408SPeter Wemm 	if (!expansion
6010e3d5408SPeter Wemm 	    && sp[0] == '\033' && sp[1] == '[' && sp[2] == '?'
6020e3d5408SPeter Wemm 	    && (len = strspn(sp + 3, "0123456789;"))
60315589c42SPeter Wemm 	    && ((sp[3 + len] == 'h') || (sp[3 + len] == 'l'))) {
6040e3d5408SPeter Wemm 	    char buf3[MAX_TERMINFO_LENGTH];
6050e3d5408SPeter Wemm 
6060e3d5408SPeter Wemm 	    (void) strcpy(buf2, (sp[3 + len] == 'h') ? "DEC+" : "DEC-");
6070e3d5408SPeter Wemm 	    (void) strncpy(buf3, sp + 3, len);
6080e3d5408SPeter Wemm 	    len += 4;
6090e3d5408SPeter Wemm 	    buf3[len] = '\0';
6100e3d5408SPeter Wemm 
6110e3d5408SPeter Wemm 	    ep = strtok(buf3, ";");
6120e3d5408SPeter Wemm 	    do {
6130e3d5408SPeter Wemm 		bool found = FALSE;
6140e3d5408SPeter Wemm 
61515589c42SPeter Wemm 		for (ap = private_modes; ap->from; ap++) {
6160e3d5408SPeter Wemm 		    size_t tlen = strlen(ap->from);
6170e3d5408SPeter Wemm 
61815589c42SPeter Wemm 		    if (strncmp(ap->from, ep, tlen) == 0) {
6190e3d5408SPeter Wemm 			(void) strcat(buf2, ap->to);
6200e3d5408SPeter Wemm 			found = TRUE;
6210e3d5408SPeter Wemm 			break;
6220e3d5408SPeter Wemm 		    }
6230e3d5408SPeter Wemm 		}
6240e3d5408SPeter Wemm 
6250e3d5408SPeter Wemm 		if (!found)
6260e3d5408SPeter Wemm 		    (void) strcat(buf2, ep);
6270e3d5408SPeter Wemm 		(void) strcat(buf2, ";");
6280e3d5408SPeter Wemm 	    } while
62915589c42SPeter Wemm 		((ep = strtok((char *) 0, ";")));
6300e3d5408SPeter Wemm 	    buf2[strlen(buf2) - 1] = '\0';
6310e3d5408SPeter Wemm 	    expansion = buf2;
6320e3d5408SPeter Wemm 	}
6330e3d5408SPeter Wemm 
6340e3d5408SPeter Wemm 	/* now check for ECMA highlight sequences */
6350e3d5408SPeter Wemm 	if (!expansion
6360e3d5408SPeter Wemm 	    && sp[0] == '\033' && sp[1] == '['
6370e3d5408SPeter Wemm 	    && (len = strspn(sp + 2, "0123456789;"))
63815589c42SPeter Wemm 	    && sp[2 + len] == 'm') {
6390e3d5408SPeter Wemm 	    char buf3[MAX_TERMINFO_LENGTH];
6400e3d5408SPeter Wemm 
6410e3d5408SPeter Wemm 	    (void) strcpy(buf2, "SGR:");
6420e3d5408SPeter Wemm 	    (void) strncpy(buf3, sp + 2, len);
6430e3d5408SPeter Wemm 	    len += 3;
6440e3d5408SPeter Wemm 	    buf3[len] = '\0';
6450e3d5408SPeter Wemm 
6460e3d5408SPeter Wemm 	    ep = strtok(buf3, ";");
6470e3d5408SPeter Wemm 	    do {
6480e3d5408SPeter Wemm 		bool found = FALSE;
6490e3d5408SPeter Wemm 
65015589c42SPeter Wemm 		for (ap = ecma_highlights; ap->from; ap++) {
6510e3d5408SPeter Wemm 		    size_t tlen = strlen(ap->from);
6520e3d5408SPeter Wemm 
65315589c42SPeter Wemm 		    if (strncmp(ap->from, ep, tlen) == 0) {
6540e3d5408SPeter Wemm 			(void) strcat(buf2, ap->to);
6550e3d5408SPeter Wemm 			found = TRUE;
6560e3d5408SPeter Wemm 			break;
6570e3d5408SPeter Wemm 		    }
6580e3d5408SPeter Wemm 		}
6590e3d5408SPeter Wemm 
6600e3d5408SPeter Wemm 		if (!found)
6610e3d5408SPeter Wemm 		    (void) strcat(buf2, ep);
6620e3d5408SPeter Wemm 		(void) strcat(buf2, ";");
6630e3d5408SPeter Wemm 	    } while
66415589c42SPeter Wemm 		((ep = strtok((char *) 0, ";")));
6650e3d5408SPeter Wemm 
6660e3d5408SPeter Wemm 	    buf2[strlen(buf2) - 1] = '\0';
6670e3d5408SPeter Wemm 	    expansion = buf2;
6680e3d5408SPeter Wemm 	}
6690e3d5408SPeter Wemm 	/* now check for scroll region reset */
67015589c42SPeter Wemm 	if (!expansion) {
6710e3d5408SPeter Wemm 	    (void) sprintf(buf2, "\033[1;%dr", tp->Numbers[2]);
6720e3d5408SPeter Wemm 	    len = strlen(buf2);
6730e3d5408SPeter Wemm 	    if (strncmp(buf2, sp, len) == 0)
6740e3d5408SPeter Wemm 		expansion = "RSR";
6750e3d5408SPeter Wemm 	}
6760e3d5408SPeter Wemm 
6770e3d5408SPeter Wemm 	/* now check for home-down */
67815589c42SPeter Wemm 	if (!expansion) {
6790e3d5408SPeter Wemm 	    (void) sprintf(buf2, "\033[%d;1H", tp->Numbers[2]);
6800e3d5408SPeter Wemm 	    len = strlen(buf2);
6810e3d5408SPeter Wemm 	    if (strncmp(buf2, sp, len) == 0)
6820e3d5408SPeter Wemm 		expansion = "LL";
6830e3d5408SPeter Wemm 	}
6840e3d5408SPeter Wemm 
6850e3d5408SPeter Wemm 	/* now look at the expansion we got, if any */
68615589c42SPeter Wemm 	if (expansion) {
6870e3d5408SPeter Wemm 	    (void) sprintf(buf + strlen(buf), "{%s}", expansion);
6880e3d5408SPeter Wemm 	    sp += len - 1;
6890e3d5408SPeter Wemm 	    continue;
69015589c42SPeter Wemm 	} else {
6910e3d5408SPeter Wemm 	    /* couldn't match anything */
6920e3d5408SPeter Wemm 	    buf2[0] = *sp;
6930e3d5408SPeter Wemm 	    buf2[1] = '\0';
6940e3d5408SPeter Wemm 	    (void) strcat(buf, TIC_EXPAND(buf2));
6950e3d5408SPeter Wemm 	}
6960e3d5408SPeter Wemm     }
6970e3d5408SPeter Wemm     (void) printf("%s\n", buf);
6980e3d5408SPeter Wemm }
6990e3d5408SPeter Wemm 
7000e3d5408SPeter Wemm /***************************************************************************
7010e3d5408SPeter Wemm  *
7020e3d5408SPeter Wemm  * File comparison
7030e3d5408SPeter Wemm  *
7040e3d5408SPeter Wemm  ***************************************************************************/
7050e3d5408SPeter Wemm 
70615589c42SPeter Wemm static void
70715589c42SPeter Wemm file_comparison(int argc, char *argv[])
7080e3d5408SPeter Wemm {
7090e3d5408SPeter Wemm #define MAXCOMPARE	2
7100e3d5408SPeter Wemm     /* someday we may allow comparisons on more files */
7110e3d5408SPeter Wemm     int filecount = 0;
7120e3d5408SPeter Wemm     ENTRY *heads[MAXCOMPARE];
7130e3d5408SPeter Wemm     ENTRY *tails[MAXCOMPARE];
7140e3d5408SPeter Wemm     ENTRY *qp, *rp;
7150e3d5408SPeter Wemm     int i, n;
7160e3d5408SPeter Wemm 
71715589c42SPeter Wemm     dump_init((char *) 0, F_LITERAL, S_TERMINFO, 0, itrace, FALSE);
7180e3d5408SPeter Wemm 
71915589c42SPeter Wemm     for (n = 0; n < argc && n < MAXCOMPARE; n++) {
72015589c42SPeter Wemm 	if (freopen(argv[n], "r", stdin) == 0)
7210e3d5408SPeter Wemm 	    _nc_err_abort("Can't open %s", argv[n]);
7220e3d5408SPeter Wemm 
72315589c42SPeter Wemm 	_nc_head = _nc_tail = 0;
7240e3d5408SPeter Wemm 
7250e3d5408SPeter Wemm 	/* parse entries out of the source file */
7260e3d5408SPeter Wemm 	_nc_set_source(argv[n]);
7270e3d5408SPeter Wemm 	_nc_read_entry_source(stdin, NULL, TRUE, FALSE, NULLHOOK);
7280e3d5408SPeter Wemm 
7290e3d5408SPeter Wemm 	if (itrace)
7300e3d5408SPeter Wemm 	    (void) fprintf(stderr, "Resolving file %d...\n", n - 0);
7310e3d5408SPeter Wemm 
73215589c42SPeter Wemm 	/* maybe do use resolution */
73315589c42SPeter Wemm 	if (!_nc_resolve_uses(!limited)) {
7340e3d5408SPeter Wemm 	    (void) fprintf(stderr,
7350e3d5408SPeter Wemm 			   "There are unresolved use entries in %s:\n",
7360e3d5408SPeter Wemm 			   argv[n]);
73715589c42SPeter Wemm 	    for_entry_list(qp) {
73815589c42SPeter Wemm 		if (qp->nuses) {
7390e3d5408SPeter Wemm 		    (void) fputs(qp->tterm.term_names, stderr);
7400e3d5408SPeter Wemm 		    (void) fputc('\n', stderr);
7410e3d5408SPeter Wemm 		}
74215589c42SPeter Wemm 	    }
7430e3d5408SPeter Wemm 	    exit(EXIT_FAILURE);
7440e3d5408SPeter Wemm 	}
7450e3d5408SPeter Wemm 
7460e3d5408SPeter Wemm 	heads[filecount] = _nc_head;
7470e3d5408SPeter Wemm 	tails[filecount] = _nc_tail;
7480e3d5408SPeter Wemm 	filecount++;
7490e3d5408SPeter Wemm     }
7500e3d5408SPeter Wemm 
7510e3d5408SPeter Wemm     /* OK, all entries are in core.  Ready to do the comparison */
7520e3d5408SPeter Wemm     if (itrace)
7530e3d5408SPeter Wemm 	(void) fprintf(stderr, "Entries are now in core...\n");
7540e3d5408SPeter Wemm 
75515589c42SPeter Wemm     /* The entry-matching loop. Sigh, this is intrinsically quadratic. */
75615589c42SPeter Wemm     for (qp = heads[0]; qp; qp = qp->next) {
7570e3d5408SPeter Wemm 	for (rp = heads[1]; rp; rp = rp->next)
75815589c42SPeter Wemm 	    if (_nc_entry_match(qp->tterm.term_names, rp->tterm.term_names)) {
75915589c42SPeter Wemm 		if (qp->ncrosslinks < MAX_CROSSLINKS)
76015589c42SPeter Wemm 		    qp->crosslinks[qp->ncrosslinks] = rp;
76115589c42SPeter Wemm 		qp->ncrosslinks++;
7620e3d5408SPeter Wemm 
76315589c42SPeter Wemm 		if (rp->ncrosslinks < MAX_CROSSLINKS)
76415589c42SPeter Wemm 		    rp->crosslinks[rp->ncrosslinks] = qp;
76515589c42SPeter Wemm 		rp->ncrosslinks++;
7660e3d5408SPeter Wemm 	    }
7670e3d5408SPeter Wemm     }
7680e3d5408SPeter Wemm 
7690e3d5408SPeter Wemm     /* now we have two circular lists with crosslinks */
7700e3d5408SPeter Wemm     if (itrace)
7710e3d5408SPeter Wemm 	(void) fprintf(stderr, "Name matches are done...\n");
7720e3d5408SPeter Wemm 
77315589c42SPeter Wemm     for (qp = heads[0]; qp; qp = qp->next) {
77415589c42SPeter Wemm 	if (qp->ncrosslinks > 1) {
7750e3d5408SPeter Wemm 	    (void) fprintf(stderr,
7760e3d5408SPeter Wemm 			   "%s in file 1 (%s) has %d matches in file 2 (%s):\n",
7770e3d5408SPeter Wemm 			   _nc_first_name(qp->tterm.term_names),
7780e3d5408SPeter Wemm 			   argv[0],
77915589c42SPeter Wemm 			   qp->ncrosslinks,
7800e3d5408SPeter Wemm 			   argv[1]);
78115589c42SPeter Wemm 	    for (i = 0; i < qp->ncrosslinks; i++)
7820e3d5408SPeter Wemm 		(void) fprintf(stderr,
7830e3d5408SPeter Wemm 			       "\t%s\n",
78415589c42SPeter Wemm 			       _nc_first_name((qp->crosslinks[i])->tterm.term_names));
7850e3d5408SPeter Wemm 	}
78615589c42SPeter Wemm     }
78715589c42SPeter Wemm 
78815589c42SPeter Wemm     for (rp = heads[1]; rp; rp = rp->next) {
78915589c42SPeter Wemm 	if (rp->ncrosslinks > 1) {
7900e3d5408SPeter Wemm 	    (void) fprintf(stderr,
7910e3d5408SPeter Wemm 			   "%s in file 2 (%s) has %d matches in file 1 (%s):\n",
7920e3d5408SPeter Wemm 			   _nc_first_name(rp->tterm.term_names),
7930e3d5408SPeter Wemm 			   argv[1],
79415589c42SPeter Wemm 			   rp->ncrosslinks,
7950e3d5408SPeter Wemm 			   argv[0]);
79615589c42SPeter Wemm 	    for (i = 0; i < rp->ncrosslinks; i++)
7970e3d5408SPeter Wemm 		(void) fprintf(stderr,
7980e3d5408SPeter Wemm 			       "\t%s\n",
79915589c42SPeter Wemm 			       _nc_first_name((rp->crosslinks[i])->tterm.term_names));
80015589c42SPeter Wemm 	}
8010e3d5408SPeter Wemm     }
8020e3d5408SPeter Wemm 
8030e3d5408SPeter Wemm     (void) printf("In file 1 (%s) only:\n", argv[0]);
8040e3d5408SPeter Wemm     for (qp = heads[0]; qp; qp = qp->next)
80515589c42SPeter Wemm 	if (qp->ncrosslinks == 0)
8060e3d5408SPeter Wemm 	    (void) printf("\t%s\n",
8070e3d5408SPeter Wemm 			  _nc_first_name(qp->tterm.term_names));
8080e3d5408SPeter Wemm 
8090e3d5408SPeter Wemm     (void) printf("In file 2 (%s) only:\n", argv[1]);
8100e3d5408SPeter Wemm     for (rp = heads[1]; rp; rp = rp->next)
81115589c42SPeter Wemm 	if (rp->ncrosslinks == 0)
8120e3d5408SPeter Wemm 	    (void) printf("\t%s\n",
8130e3d5408SPeter Wemm 			  _nc_first_name(rp->tterm.term_names));
8140e3d5408SPeter Wemm 
8150e3d5408SPeter Wemm     (void) printf("The following entries are equivalent:\n");
81615589c42SPeter Wemm     for (qp = heads[0]; qp; qp = qp->next) {
81715589c42SPeter Wemm 	rp = qp->crosslinks[0];
8180e3d5408SPeter Wemm 
81915589c42SPeter Wemm 	if (qp->ncrosslinks == 1) {
82015589c42SPeter Wemm 	    rp = qp->crosslinks[0];
82115589c42SPeter Wemm 
82215589c42SPeter Wemm 	    repair_acsc(&qp->tterm);
82315589c42SPeter Wemm 	    repair_acsc(&rp->tterm);
82415589c42SPeter Wemm #if NCURSES_XNAMES
82515589c42SPeter Wemm 	    _nc_align_termtype(&qp->tterm, &rp->tterm);
82615589c42SPeter Wemm #endif
82715589c42SPeter Wemm 	    if (entryeq(&qp->tterm, &rp->tterm) && useeq(qp, rp)) {
8280e3d5408SPeter Wemm 		char name1[NAMESIZE], name2[NAMESIZE];
8290e3d5408SPeter Wemm 
8300e3d5408SPeter Wemm 		(void) canonical_name(qp->tterm.term_names, name1);
8310e3d5408SPeter Wemm 		(void) canonical_name(rp->tterm.term_names, name2);
8320e3d5408SPeter Wemm 
8330e3d5408SPeter Wemm 		(void) printf("%s = %s\n", name1, name2);
8340e3d5408SPeter Wemm 	    }
8350e3d5408SPeter Wemm 	}
83615589c42SPeter Wemm     }
8370e3d5408SPeter Wemm 
8380e3d5408SPeter Wemm     (void) printf("Differing entries:\n");
8390e3d5408SPeter Wemm     termcount = 2;
84015589c42SPeter Wemm     for (qp = heads[0]; qp; qp = qp->next) {
8410e3d5408SPeter Wemm 
84215589c42SPeter Wemm 	if (qp->ncrosslinks == 1) {
84315589c42SPeter Wemm 	    rp = qp->crosslinks[0];
8440e3d5408SPeter Wemm #if NCURSES_XNAMES
84515589c42SPeter Wemm 	    /* sorry - we have to do this on each pass */
8460e3d5408SPeter Wemm 	    _nc_align_termtype(&qp->tterm, &rp->tterm);
8470e3d5408SPeter Wemm #endif
84815589c42SPeter Wemm 	    if (!(entryeq(&qp->tterm, &rp->tterm) && useeq(qp, rp))) {
8490e3d5408SPeter Wemm 		char name1[NAMESIZE], name2[NAMESIZE];
8500e3d5408SPeter Wemm 
85115589c42SPeter Wemm 		entries[0] = *qp;
85215589c42SPeter Wemm 		entries[1] = *rp;
8530e3d5408SPeter Wemm 
8540e3d5408SPeter Wemm 		(void) canonical_name(qp->tterm.term_names, name1);
8550e3d5408SPeter Wemm 		(void) canonical_name(rp->tterm.term_names, name2);
8560e3d5408SPeter Wemm 
85715589c42SPeter Wemm 		switch (compare) {
8580e3d5408SPeter Wemm 		case C_DIFFERENCE:
8590e3d5408SPeter Wemm 		    if (itrace)
86015589c42SPeter Wemm 			(void) fprintf(stderr,
86115589c42SPeter Wemm 				       "infocmp: dumping differences\n");
8620e3d5408SPeter Wemm 		    (void) printf("comparing %s to %s.\n", name1, name2);
86315589c42SPeter Wemm 		    compare_entry(compare_predicate, &entries->tterm, quiet);
8640e3d5408SPeter Wemm 		    break;
8650e3d5408SPeter Wemm 
8660e3d5408SPeter Wemm 		case C_COMMON:
8670e3d5408SPeter Wemm 		    if (itrace)
8680e3d5408SPeter Wemm 			(void) fprintf(stderr,
8690e3d5408SPeter Wemm 				       "infocmp: dumping common capabilities\n");
8700e3d5408SPeter Wemm 		    (void) printf("comparing %s to %s.\n", name1, name2);
87115589c42SPeter Wemm 		    compare_entry(compare_predicate, &entries->tterm, quiet);
8720e3d5408SPeter Wemm 		    break;
8730e3d5408SPeter Wemm 
8740e3d5408SPeter Wemm 		case C_NAND:
8750e3d5408SPeter Wemm 		    if (itrace)
8760e3d5408SPeter Wemm 			(void) fprintf(stderr,
8770e3d5408SPeter Wemm 				       "infocmp: dumping differences\n");
8780e3d5408SPeter Wemm 		    (void) printf("comparing %s to %s.\n", name1, name2);
87915589c42SPeter Wemm 		    compare_entry(compare_predicate, &entries->tterm, quiet);
8800e3d5408SPeter Wemm 		    break;
8810e3d5408SPeter Wemm 
8820e3d5408SPeter Wemm 		}
8830e3d5408SPeter Wemm 	    }
8840e3d5408SPeter Wemm 	}
8850e3d5408SPeter Wemm     }
88615589c42SPeter Wemm }
8870e3d5408SPeter Wemm 
88815589c42SPeter Wemm static void
88915589c42SPeter Wemm usage(void)
8900e3d5408SPeter Wemm {
89115589c42SPeter Wemm     static const char *tbl[] =
89215589c42SPeter Wemm     {
8930e3d5408SPeter Wemm 	"Usage: infocmp [options] [-A directory] [-B directory] [termname...]"
8940e3d5408SPeter Wemm 	,""
8950e3d5408SPeter Wemm 	,"Options:"
8960e3d5408SPeter Wemm 	,"  -1    print single-column"
8970e3d5408SPeter Wemm 	,"  -C    use termcap-names"
8980e3d5408SPeter Wemm 	,"  -F    compare terminfo-files"
8990e3d5408SPeter Wemm 	,"  -I    use terminfo-names"
9000e3d5408SPeter Wemm 	,"  -L    use long names"
9010e3d5408SPeter Wemm 	,"  -R subset (see manpage)"
9020e3d5408SPeter Wemm 	,"  -T    eliminate size limits (test)"
9030e3d5408SPeter Wemm 	,"  -V    print version"
90415589c42SPeter Wemm #if NCURSES_XNAMES
90515589c42SPeter Wemm 	,"  -a    with -F, list commented-out caps"
90615589c42SPeter Wemm #endif
9070e3d5408SPeter Wemm 	,"  -c    list common capabilities"
9080e3d5408SPeter Wemm 	,"  -d    list different capabilities"
9090e3d5408SPeter Wemm 	,"  -e    format output for C initializer"
9100e3d5408SPeter Wemm 	,"  -E    format output as C tables"
9110e3d5408SPeter Wemm 	,"  -f    with -1, format complex strings"
9120e3d5408SPeter Wemm 	,"  -G    format %{number} to %'char'"
9130e3d5408SPeter Wemm 	,"  -g    format %'char' to %{number}"
9140e3d5408SPeter Wemm 	,"  -i    analyze initialization/reset"
9150e3d5408SPeter Wemm 	,"  -l    output terminfo names"
9160e3d5408SPeter Wemm 	,"  -n    list capabilities in neither"
9170e3d5408SPeter Wemm 	,"  -p    ignore padding specifiers"
91815589c42SPeter Wemm 	,"  -q    brief listing, removes headers"
9190e3d5408SPeter Wemm 	,"  -r    with -C, output in termcap form"
92015589c42SPeter Wemm 	,"  -r    with -F, resolve use-references"
9210e3d5408SPeter Wemm 	,"  -s [d|i|l|c] sort fields"
9220e3d5408SPeter Wemm 	,"  -u    produce source with 'use='"
9230e3d5408SPeter Wemm 	,"  -v number  (verbose)"
9240e3d5408SPeter Wemm 	,"  -w number  (width)"
9250e3d5408SPeter Wemm     };
9260e3d5408SPeter Wemm     const size_t first = 3;
927*18259542SPeter Wemm     const size_t last = SIZEOF(tbl);
9280e3d5408SPeter Wemm     const size_t left = (last - first + 1) / 2 + first;
9290e3d5408SPeter Wemm     size_t n;
9300e3d5408SPeter Wemm 
9310e3d5408SPeter Wemm     for (n = 0; n < left; n++) {
9320e3d5408SPeter Wemm 	size_t m = (n < first) ? last : n + left - first;
9330e3d5408SPeter Wemm 	if (m < last)
9340e3d5408SPeter Wemm 	    fprintf(stderr, "%-40.40s%s\n", tbl[n], tbl[m]);
9350e3d5408SPeter Wemm 	else
9360e3d5408SPeter Wemm 	    fprintf(stderr, "%s\n", tbl[n]);
9370e3d5408SPeter Wemm     }
9380e3d5408SPeter Wemm     exit(EXIT_FAILURE);
9390e3d5408SPeter Wemm }
9400e3d5408SPeter Wemm 
94115589c42SPeter Wemm static char *
94215589c42SPeter Wemm name_initializer(const char *type)
9430e3d5408SPeter Wemm {
9440e3d5408SPeter Wemm     static char *initializer;
9450e3d5408SPeter Wemm     char *s;
9460e3d5408SPeter Wemm 
9470e3d5408SPeter Wemm     if (initializer == 0)
94815589c42SPeter Wemm 	initializer = (char *) malloc(strlen(entries->tterm.term_names) + 20);
9490e3d5408SPeter Wemm 
95015589c42SPeter Wemm     (void) sprintf(initializer, "%s_data_%s", type, entries->tterm.term_names);
95115589c42SPeter Wemm     for (s = initializer; *s != 0 && *s != '|'; s++) {
9520e3d5408SPeter Wemm 	if (!isalnum(*s))
9530e3d5408SPeter Wemm 	    *s = '_';
9540e3d5408SPeter Wemm     }
9550e3d5408SPeter Wemm     *s = 0;
9560e3d5408SPeter Wemm     return initializer;
9570e3d5408SPeter Wemm }
9580e3d5408SPeter Wemm 
9590e3d5408SPeter Wemm /* dump C initializers for the terminal type */
96015589c42SPeter Wemm static void
96115589c42SPeter Wemm dump_initializers(TERMTYPE * term)
9620e3d5408SPeter Wemm {
9630e3d5408SPeter Wemm     int n;
9640e3d5408SPeter Wemm     const char *str = 0;
9650e3d5408SPeter Wemm     int size;
9660e3d5408SPeter Wemm 
96715589c42SPeter Wemm     (void) printf("static char %s[] = %s\n", name_initializer("bool"), L_CURL);
9680e3d5408SPeter Wemm 
96915589c42SPeter Wemm     for_each_boolean(n, term) {
97015589c42SPeter Wemm 	switch ((int) (term->Booleans[n])) {
9710e3d5408SPeter Wemm 	case TRUE:
9720e3d5408SPeter Wemm 	    str = "TRUE";
9730e3d5408SPeter Wemm 	    break;
9740e3d5408SPeter Wemm 
9750e3d5408SPeter Wemm 	case FALSE:
9760e3d5408SPeter Wemm 	    str = "FALSE";
9770e3d5408SPeter Wemm 	    break;
9780e3d5408SPeter Wemm 
9790e3d5408SPeter Wemm 	case ABSENT_BOOLEAN:
9800e3d5408SPeter Wemm 	    str = "ABSENT_BOOLEAN";
9810e3d5408SPeter Wemm 	    break;
9820e3d5408SPeter Wemm 
9830e3d5408SPeter Wemm 	case CANCELLED_BOOLEAN:
9840e3d5408SPeter Wemm 	    str = "CANCELLED_BOOLEAN";
9850e3d5408SPeter Wemm 	    break;
9860e3d5408SPeter Wemm 	}
9870e3d5408SPeter Wemm 	(void) printf("\t/* %3d: %-8s */\t%s,\n",
9880e3d5408SPeter Wemm 		      n, ExtBoolname(term, n, boolnames), str);
9890e3d5408SPeter Wemm     }
9900e3d5408SPeter Wemm     (void) printf("%s;\n", R_CURL);
9910e3d5408SPeter Wemm 
9920e3d5408SPeter Wemm     (void) printf("static short %s[] = %s\n", name_initializer("number"), L_CURL);
9930e3d5408SPeter Wemm 
99415589c42SPeter Wemm     for_each_number(n, term) {
9950e3d5408SPeter Wemm 	char buf[BUFSIZ];
99615589c42SPeter Wemm 	switch (term->Numbers[n]) {
9970e3d5408SPeter Wemm 	case ABSENT_NUMERIC:
9980e3d5408SPeter Wemm 	    str = "ABSENT_NUMERIC";
9990e3d5408SPeter Wemm 	    break;
10000e3d5408SPeter Wemm 	case CANCELLED_NUMERIC:
10010e3d5408SPeter Wemm 	    str = "CANCELLED_NUMERIC";
10020e3d5408SPeter Wemm 	    break;
10030e3d5408SPeter Wemm 	default:
10040e3d5408SPeter Wemm 	    sprintf(buf, "%d", term->Numbers[n]);
10050e3d5408SPeter Wemm 	    str = buf;
10060e3d5408SPeter Wemm 	    break;
10070e3d5408SPeter Wemm 	}
1008*18259542SPeter Wemm 	(void) printf("\t/* %3d: %-8s */\t%s,\n", n,
1009*18259542SPeter Wemm 		      ExtNumname(term, n, numnames), str);
10100e3d5408SPeter Wemm     }
10110e3d5408SPeter Wemm     (void) printf("%s;\n", R_CURL);
10120e3d5408SPeter Wemm 
10130e3d5408SPeter Wemm     size = sizeof(TERMTYPE)
10140e3d5408SPeter Wemm 	+ (NUM_BOOLEANS(term) * sizeof(term->Booleans[0]))
10150e3d5408SPeter Wemm 	+ (NUM_NUMBERS(term) * sizeof(term->Numbers[0]));
10160e3d5408SPeter Wemm 
10170e3d5408SPeter Wemm     (void) printf("static char * %s[] = %s\n", name_initializer("string"), L_CURL);
10180e3d5408SPeter Wemm 
101915589c42SPeter Wemm     for_each_string(n, term) {
102015589c42SPeter Wemm 	char buf[MAX_STRING], *sp, *tp;
10210e3d5408SPeter Wemm 
10220e3d5408SPeter Wemm 	if (term->Strings[n] == ABSENT_STRING)
10230e3d5408SPeter Wemm 	    str = "ABSENT_STRING";
10240e3d5408SPeter Wemm 	else if (term->Strings[n] == CANCELLED_STRING)
10250e3d5408SPeter Wemm 	    str = "CANCELLED_STRING";
102615589c42SPeter Wemm 	else {
10270e3d5408SPeter Wemm 	    tp = buf;
10280e3d5408SPeter Wemm 	    *tp++ = '"';
102915589c42SPeter Wemm 	    for (sp = term->Strings[n];
103015589c42SPeter Wemm 		 *sp != 0 && (tp - buf) < MAX_STRING - 6;
103115589c42SPeter Wemm 		 sp++) {
10320e3d5408SPeter Wemm 		if (isascii(*sp) && isprint(*sp) && *sp != '\\' && *sp != '"')
10330e3d5408SPeter Wemm 		    *tp++ = *sp;
103415589c42SPeter Wemm 		else {
10350e3d5408SPeter Wemm 		    (void) sprintf(tp, "\\%03o", *sp & 0xff);
10360e3d5408SPeter Wemm 		    tp += 4;
10370e3d5408SPeter Wemm 		}
10380e3d5408SPeter Wemm 	    }
10390e3d5408SPeter Wemm 	    *tp++ = '"';
10400e3d5408SPeter Wemm 	    *tp = '\0';
10410e3d5408SPeter Wemm 	    size += (strlen(term->Strings[n]) + 1);
10420e3d5408SPeter Wemm 	    str = buf;
10430e3d5408SPeter Wemm 	}
10440e3d5408SPeter Wemm #if NCURSES_XNAMES
104515589c42SPeter Wemm 	if (n == STRCOUNT) {
10460e3d5408SPeter Wemm 	    (void) printf("%s;\n", R_CURL);
10470e3d5408SPeter Wemm 
104815589c42SPeter Wemm 	    (void) printf("static char * %s[] = %s\n",
104915589c42SPeter Wemm 			  name_initializer("string_ext"), L_CURL);
10500e3d5408SPeter Wemm 	}
10510e3d5408SPeter Wemm #endif
1052*18259542SPeter Wemm 	(void) printf("\t/* %3d: %-8s */\t%s,\n", n,
1053*18259542SPeter Wemm 		      ExtStrname(term, n, strnames), str);
10540e3d5408SPeter Wemm     }
10550e3d5408SPeter Wemm     (void) printf("%s;\n", R_CURL);
10560e3d5408SPeter Wemm }
10570e3d5408SPeter Wemm 
10580e3d5408SPeter Wemm /* dump C initializers for the terminal type */
105915589c42SPeter Wemm static void
106015589c42SPeter Wemm dump_termtype(TERMTYPE * term)
10610e3d5408SPeter Wemm {
10620e3d5408SPeter Wemm     (void) printf("\t%s\n\t\t\"%s\",\n", L_CURL, term->term_names);
10630e3d5408SPeter Wemm     (void) printf("\t\t(char *)0,\t/* pointer to string table */\n");
10640e3d5408SPeter Wemm 
10650e3d5408SPeter Wemm     (void) printf("\t\t%s,\n", name_initializer("bool"));
10660e3d5408SPeter Wemm     (void) printf("\t\t%s,\n", name_initializer("number"));
10670e3d5408SPeter Wemm 
10680e3d5408SPeter Wemm     (void) printf("\t\t%s,\n", name_initializer("string"));
10690e3d5408SPeter Wemm 
10700e3d5408SPeter Wemm #if NCURSES_XNAMES
10710e3d5408SPeter Wemm     (void) printf("#if NCURSES_XNAMES\n");
10720e3d5408SPeter Wemm     (void) printf("\t\t(char *)0,\t/* pointer to extended string table */\n");
10730e3d5408SPeter Wemm     (void) printf("\t\t%s,\t/* ...corresponding names */\n",
10740e3d5408SPeter Wemm 		  (NUM_STRINGS(term) != STRCOUNT)
10750e3d5408SPeter Wemm 		  ? name_initializer("string_ext")
10760e3d5408SPeter Wemm 		  : "(char **)0");
10770e3d5408SPeter Wemm 
10780e3d5408SPeter Wemm     (void) printf("\t\t%d,\t\t/* count total Booleans */\n", NUM_BOOLEANS(term));
10790e3d5408SPeter Wemm     (void) printf("\t\t%d,\t\t/* count total Numbers */\n", NUM_NUMBERS(term));
10800e3d5408SPeter Wemm     (void) printf("\t\t%d,\t\t/* count total Strings */\n", NUM_STRINGS(term));
10810e3d5408SPeter Wemm 
108215589c42SPeter Wemm     (void) printf("\t\t%d,\t\t/* count extensions to Booleans */\n",
108315589c42SPeter Wemm 		  NUM_BOOLEANS(term) - BOOLCOUNT);
108415589c42SPeter Wemm     (void) printf("\t\t%d,\t\t/* count extensions to Numbers */\n",
108515589c42SPeter Wemm 		  NUM_NUMBERS(term) - NUMCOUNT);
108615589c42SPeter Wemm     (void) printf("\t\t%d,\t\t/* count extensions to Strings */\n",
108715589c42SPeter Wemm 		  NUM_STRINGS(term) - STRCOUNT);
10880e3d5408SPeter Wemm 
10890e3d5408SPeter Wemm     (void) printf("#endif /* NCURSES_XNAMES */\n");
10900e3d5408SPeter Wemm #endif /* NCURSES_XNAMES */
10910e3d5408SPeter Wemm     (void) printf("\t%s\n", R_CURL);
10920e3d5408SPeter Wemm }
10930e3d5408SPeter Wemm 
1094*18259542SPeter Wemm static int
1095*18259542SPeter Wemm optarg_to_number(void)
1096*18259542SPeter Wemm {
1097*18259542SPeter Wemm     char *temp = 0;
1098*18259542SPeter Wemm     long value = strtol(optarg, &temp, 0);
1099*18259542SPeter Wemm 
1100*18259542SPeter Wemm     if (temp == 0 || temp == optarg || *temp != 0) {
1101*18259542SPeter Wemm 	fprintf(stderr, "Expected a number, not \"%s\"\n", optarg);
1102*18259542SPeter Wemm 	exit(EXIT_FAILURE);
1103*18259542SPeter Wemm     }
1104*18259542SPeter Wemm     return (int) value;
1105*18259542SPeter Wemm }
1106*18259542SPeter Wemm 
11070e3d5408SPeter Wemm /***************************************************************************
11080e3d5408SPeter Wemm  *
11090e3d5408SPeter Wemm  * Main sequence
11100e3d5408SPeter Wemm  *
11110e3d5408SPeter Wemm  ***************************************************************************/
11120e3d5408SPeter Wemm 
111315589c42SPeter Wemm int
111415589c42SPeter Wemm main(int argc, char *argv[])
11150e3d5408SPeter Wemm {
11160e3d5408SPeter Wemm     char *terminal, *firstdir, *restdir;
11170e3d5408SPeter Wemm     /* Avoid "local data >32k" error with mwcc */
11180e3d5408SPeter Wemm     /* Also avoid overflowing smaller stacks on systems like AmigaOS */
111915589c42SPeter Wemm     path *tfile = (path *) malloc(sizeof(path) * MAXTERMS);
11200e3d5408SPeter Wemm     int c, i, len;
11210e3d5408SPeter Wemm     bool formatted = FALSE;
11220e3d5408SPeter Wemm     bool filecompare = FALSE;
11230e3d5408SPeter Wemm     int initdump = 0;
11240e3d5408SPeter Wemm     bool init_analyze = FALSE;
11250e3d5408SPeter Wemm 
112615589c42SPeter Wemm     if ((terminal = getenv("TERM")) == 0) {
11270e3d5408SPeter Wemm 	(void) fprintf(stderr,
11280e3d5408SPeter Wemm 		       "infocmp: environment variable TERM not set\n");
11290e3d5408SPeter Wemm 	return EXIT_FAILURE;
11300e3d5408SPeter Wemm     }
11310e3d5408SPeter Wemm 
11320e3d5408SPeter Wemm     /* where is the terminfo database location going to default to? */
11330e3d5408SPeter Wemm     restdir = firstdir = 0;
11340e3d5408SPeter Wemm 
113515589c42SPeter Wemm     while ((c = getopt(argc, argv, "adeEcCfFGgIinlLpqrR:s:uv:Vw:A:B:1T")) != EOF)
113615589c42SPeter Wemm 	switch (c) {
113715589c42SPeter Wemm #if NCURSES_XNAMES
113815589c42SPeter Wemm 	case 'a':
113915589c42SPeter Wemm 	    _nc_disable_period = TRUE;
114015589c42SPeter Wemm 	    use_extended_names(TRUE);
114115589c42SPeter Wemm 	    break;
114215589c42SPeter Wemm #endif
11430e3d5408SPeter Wemm 	case 'd':
11440e3d5408SPeter Wemm 	    compare = C_DIFFERENCE;
11450e3d5408SPeter Wemm 	    break;
11460e3d5408SPeter Wemm 
11470e3d5408SPeter Wemm 	case 'e':
11480e3d5408SPeter Wemm 	    initdump |= 1;
11490e3d5408SPeter Wemm 	    break;
11500e3d5408SPeter Wemm 
11510e3d5408SPeter Wemm 	case 'E':
11520e3d5408SPeter Wemm 	    initdump |= 2;
11530e3d5408SPeter Wemm 	    break;
11540e3d5408SPeter Wemm 
11550e3d5408SPeter Wemm 	case 'c':
11560e3d5408SPeter Wemm 	    compare = C_COMMON;
11570e3d5408SPeter Wemm 	    break;
11580e3d5408SPeter Wemm 
11590e3d5408SPeter Wemm 	case 'C':
11600e3d5408SPeter Wemm 	    outform = F_TERMCAP;
11610e3d5408SPeter Wemm 	    tversion = "BSD";
11620e3d5408SPeter Wemm 	    if (sortmode == S_DEFAULT)
11630e3d5408SPeter Wemm 		sortmode = S_TERMCAP;
11640e3d5408SPeter Wemm 	    break;
11650e3d5408SPeter Wemm 
11660e3d5408SPeter Wemm 	case 'f':
11670e3d5408SPeter Wemm 	    formatted = TRUE;
11680e3d5408SPeter Wemm 	    break;
11690e3d5408SPeter Wemm 
11700e3d5408SPeter Wemm 	case 'G':
11710e3d5408SPeter Wemm 	    numbers = 1;
11720e3d5408SPeter Wemm 	    break;
11730e3d5408SPeter Wemm 
11740e3d5408SPeter Wemm 	case 'g':
11750e3d5408SPeter Wemm 	    numbers = -1;
11760e3d5408SPeter Wemm 	    break;
11770e3d5408SPeter Wemm 
11780e3d5408SPeter Wemm 	case 'F':
11790e3d5408SPeter Wemm 	    filecompare = TRUE;
11800e3d5408SPeter Wemm 	    break;
11810e3d5408SPeter Wemm 
11820e3d5408SPeter Wemm 	case 'I':
11830e3d5408SPeter Wemm 	    outform = F_TERMINFO;
11840e3d5408SPeter Wemm 	    if (sortmode == S_DEFAULT)
11850e3d5408SPeter Wemm 		sortmode = S_VARIABLE;
11860e3d5408SPeter Wemm 	    tversion = 0;
11870e3d5408SPeter Wemm 	    break;
11880e3d5408SPeter Wemm 
11890e3d5408SPeter Wemm 	case 'i':
11900e3d5408SPeter Wemm 	    init_analyze = TRUE;
11910e3d5408SPeter Wemm 	    break;
11920e3d5408SPeter Wemm 
11930e3d5408SPeter Wemm 	case 'l':
11940e3d5408SPeter Wemm 	    outform = F_TERMINFO;
11950e3d5408SPeter Wemm 	    break;
11960e3d5408SPeter Wemm 
11970e3d5408SPeter Wemm 	case 'L':
11980e3d5408SPeter Wemm 	    outform = F_VARIABLE;
11990e3d5408SPeter Wemm 	    if (sortmode == S_DEFAULT)
12000e3d5408SPeter Wemm 		sortmode = S_VARIABLE;
12010e3d5408SPeter Wemm 	    break;
12020e3d5408SPeter Wemm 
12030e3d5408SPeter Wemm 	case 'n':
12040e3d5408SPeter Wemm 	    compare = C_NAND;
12050e3d5408SPeter Wemm 	    break;
12060e3d5408SPeter Wemm 
12070e3d5408SPeter Wemm 	case 'p':
12080e3d5408SPeter Wemm 	    ignorepads = TRUE;
12090e3d5408SPeter Wemm 	    break;
12100e3d5408SPeter Wemm 
121115589c42SPeter Wemm 	case 'q':
121215589c42SPeter Wemm 	    quiet = TRUE;
121315589c42SPeter Wemm 	    s_absent = "-";
121415589c42SPeter Wemm 	    s_cancel = "@";
121515589c42SPeter Wemm 	    bool_sep = ", ";
121615589c42SPeter Wemm 	    break;
121715589c42SPeter Wemm 
12180e3d5408SPeter Wemm 	case 'r':
12190e3d5408SPeter Wemm 	    tversion = 0;
12200e3d5408SPeter Wemm 	    limited = FALSE;
12210e3d5408SPeter Wemm 	    break;
12220e3d5408SPeter Wemm 
12230e3d5408SPeter Wemm 	case 'R':
12240e3d5408SPeter Wemm 	    tversion = optarg;
12250e3d5408SPeter Wemm 	    break;
12260e3d5408SPeter Wemm 
12270e3d5408SPeter Wemm 	case 's':
12280e3d5408SPeter Wemm 	    if (*optarg == 'd')
12290e3d5408SPeter Wemm 		sortmode = S_NOSORT;
12300e3d5408SPeter Wemm 	    else if (*optarg == 'i')
12310e3d5408SPeter Wemm 		sortmode = S_TERMINFO;
12320e3d5408SPeter Wemm 	    else if (*optarg == 'l')
12330e3d5408SPeter Wemm 		sortmode = S_VARIABLE;
12340e3d5408SPeter Wemm 	    else if (*optarg == 'c')
12350e3d5408SPeter Wemm 		sortmode = S_TERMCAP;
123615589c42SPeter Wemm 	    else {
12370e3d5408SPeter Wemm 		(void) fprintf(stderr,
12380e3d5408SPeter Wemm 			       "infocmp: unknown sort mode\n");
12390e3d5408SPeter Wemm 		return EXIT_FAILURE;
12400e3d5408SPeter Wemm 	    }
12410e3d5408SPeter Wemm 	    break;
12420e3d5408SPeter Wemm 
12430e3d5408SPeter Wemm 	case 'u':
12440e3d5408SPeter Wemm 	    compare = C_USEALL;
12450e3d5408SPeter Wemm 	    break;
12460e3d5408SPeter Wemm 
12470e3d5408SPeter Wemm 	case 'v':
1248*18259542SPeter Wemm 	    itrace = optarg_to_number();
124915589c42SPeter Wemm 	    set_trace_level(itrace);
12500e3d5408SPeter Wemm 	    break;
12510e3d5408SPeter Wemm 
12520e3d5408SPeter Wemm 	case 'V':
1253*18259542SPeter Wemm 	    puts(curses_version());
12540e3d5408SPeter Wemm 	    ExitProgram(EXIT_SUCCESS);
12550e3d5408SPeter Wemm 
12560e3d5408SPeter Wemm 	case 'w':
1257*18259542SPeter Wemm 	    mwidth = optarg_to_number();
12580e3d5408SPeter Wemm 	    break;
12590e3d5408SPeter Wemm 
12600e3d5408SPeter Wemm 	case 'A':
12610e3d5408SPeter Wemm 	    firstdir = optarg;
12620e3d5408SPeter Wemm 	    break;
12630e3d5408SPeter Wemm 
12640e3d5408SPeter Wemm 	case 'B':
12650e3d5408SPeter Wemm 	    restdir = optarg;
12660e3d5408SPeter Wemm 	    break;
12670e3d5408SPeter Wemm 
12680e3d5408SPeter Wemm 	case '1':
12690e3d5408SPeter Wemm 	    mwidth = 0;
12700e3d5408SPeter Wemm 	    break;
12710e3d5408SPeter Wemm 
12720e3d5408SPeter Wemm 	case 'T':
12730e3d5408SPeter Wemm 	    limited = FALSE;
12740e3d5408SPeter Wemm 	    break;
12750e3d5408SPeter Wemm 	default:
12760e3d5408SPeter Wemm 	    usage();
12770e3d5408SPeter Wemm 	}
12780e3d5408SPeter Wemm 
12790e3d5408SPeter Wemm     /* by default, sort by terminfo name */
12800e3d5408SPeter Wemm     if (sortmode == S_DEFAULT)
12810e3d5408SPeter Wemm 	sortmode = S_TERMINFO;
12820e3d5408SPeter Wemm 
12830e3d5408SPeter Wemm     /* set up for display */
12840e3d5408SPeter Wemm     dump_init(tversion, outform, sortmode, mwidth, itrace, formatted);
12850e3d5408SPeter Wemm 
12860e3d5408SPeter Wemm     /* make sure we have at least one terminal name to work with */
12870e3d5408SPeter Wemm     if (optind >= argc)
12880e3d5408SPeter Wemm 	argv[argc++] = terminal;
12890e3d5408SPeter Wemm 
12900e3d5408SPeter Wemm     /* if user is after a comparison, make sure we have two entries */
12910e3d5408SPeter Wemm     if (compare != C_DEFAULT && optind >= argc - 1)
12920e3d5408SPeter Wemm 	argv[argc++] = terminal;
12930e3d5408SPeter Wemm 
12940e3d5408SPeter Wemm     /* exactly two terminal names with no options means do -d */
12950e3d5408SPeter Wemm     if (argc - optind == 2 && compare == C_DEFAULT)
12960e3d5408SPeter Wemm 	compare = C_DIFFERENCE;
12970e3d5408SPeter Wemm 
129815589c42SPeter Wemm     if (!filecompare) {
12990e3d5408SPeter Wemm 	/* grab the entries */
13000e3d5408SPeter Wemm 	termcount = 0;
130115589c42SPeter Wemm 	for (; optind < argc; optind++) {
130215589c42SPeter Wemm 	    if (termcount >= MAXTERMS) {
13030e3d5408SPeter Wemm 		(void) fprintf(stderr,
13040e3d5408SPeter Wemm 			       "infocmp: too many terminal type arguments\n");
13050e3d5408SPeter Wemm 		return EXIT_FAILURE;
130615589c42SPeter Wemm 	    } else {
13070e3d5408SPeter Wemm 		const char *directory = termcount ? restdir : firstdir;
13080e3d5408SPeter Wemm 		int status;
13090e3d5408SPeter Wemm 
13100e3d5408SPeter Wemm 		tname[termcount] = argv[optind];
13110e3d5408SPeter Wemm 
131215589c42SPeter Wemm 		if (directory) {
13130e3d5408SPeter Wemm 		    (void) sprintf(tfile[termcount], "%s/%c/%s",
13140e3d5408SPeter Wemm 				   directory,
13150e3d5408SPeter Wemm 				   *argv[optind], argv[optind]);
13160e3d5408SPeter Wemm 		    if (itrace)
13170e3d5408SPeter Wemm 			(void) fprintf(stderr,
13180e3d5408SPeter Wemm 				       "infocmp: reading entry %s from file %s\n",
13190e3d5408SPeter Wemm 				       argv[optind], tfile[termcount]);
13200e3d5408SPeter Wemm 
13210e3d5408SPeter Wemm 		    status = _nc_read_file_entry(tfile[termcount],
132215589c42SPeter Wemm 						 &entries[termcount].tterm);
132315589c42SPeter Wemm 		} else {
13240e3d5408SPeter Wemm 		    if (itrace)
13250e3d5408SPeter Wemm 			(void) fprintf(stderr,
13260e3d5408SPeter Wemm 				       "infocmp: reading entry %s from system directories %s\n",
13270e3d5408SPeter Wemm 				       argv[optind], tname[termcount]);
13280e3d5408SPeter Wemm 
13290e3d5408SPeter Wemm 		    status = _nc_read_entry(tname[termcount],
13300e3d5408SPeter Wemm 					    tfile[termcount],
133115589c42SPeter Wemm 					    &entries[termcount].tterm);
13320e3d5408SPeter Wemm 		    directory = TERMINFO;	/* for error message */
13330e3d5408SPeter Wemm 		}
13340e3d5408SPeter Wemm 
133515589c42SPeter Wemm 		if (status <= 0) {
13360e3d5408SPeter Wemm 		    (void) fprintf(stderr,
13370e3d5408SPeter Wemm 				   "infocmp: couldn't open terminfo file %s.\n",
13380e3d5408SPeter Wemm 				   tfile[termcount]);
13390e3d5408SPeter Wemm 		    return EXIT_FAILURE;
13400e3d5408SPeter Wemm 		}
134115589c42SPeter Wemm 		repair_acsc(&entries[termcount].tterm);
13420e3d5408SPeter Wemm 		termcount++;
13430e3d5408SPeter Wemm 	    }
13440e3d5408SPeter Wemm 	}
13450e3d5408SPeter Wemm 
13460e3d5408SPeter Wemm #if NCURSES_XNAMES
13470e3d5408SPeter Wemm 	if (termcount > 1)
134815589c42SPeter Wemm 	    _nc_align_termtype(&entries[0].tterm, &entries[1].tterm);
13490e3d5408SPeter Wemm #endif
13500e3d5408SPeter Wemm 
13510e3d5408SPeter Wemm 	/* dump as C initializer for the terminal type */
135215589c42SPeter Wemm 	if (initdump) {
13530e3d5408SPeter Wemm 	    if (initdump & 1)
135415589c42SPeter Wemm 		dump_termtype(&entries[0].tterm);
13550e3d5408SPeter Wemm 	    if (initdump & 2)
135615589c42SPeter Wemm 		dump_initializers(&entries[0].tterm);
13570e3d5408SPeter Wemm 	    ExitProgram(EXIT_SUCCESS);
13580e3d5408SPeter Wemm 	}
13590e3d5408SPeter Wemm 
13600e3d5408SPeter Wemm 	/* analyze the init strings */
136115589c42SPeter Wemm 	if (init_analyze) {
13620e3d5408SPeter Wemm #undef CUR
136315589c42SPeter Wemm #define CUR	entries[0].tterm.
136415589c42SPeter Wemm 	    analyze_string("is1", init_1string, &entries[0].tterm);
136515589c42SPeter Wemm 	    analyze_string("is2", init_2string, &entries[0].tterm);
136615589c42SPeter Wemm 	    analyze_string("is3", init_3string, &entries[0].tterm);
136715589c42SPeter Wemm 	    analyze_string("rs1", reset_1string, &entries[0].tterm);
136815589c42SPeter Wemm 	    analyze_string("rs2", reset_2string, &entries[0].tterm);
136915589c42SPeter Wemm 	    analyze_string("rs3", reset_3string, &entries[0].tterm);
137015589c42SPeter Wemm 	    analyze_string("smcup", enter_ca_mode, &entries[0].tterm);
137115589c42SPeter Wemm 	    analyze_string("rmcup", exit_ca_mode, &entries[0].tterm);
13720e3d5408SPeter Wemm #undef CUR
13730e3d5408SPeter Wemm 	    ExitProgram(EXIT_SUCCESS);
13740e3d5408SPeter Wemm 	}
13750e3d5408SPeter Wemm 
13760e3d5408SPeter Wemm 	/*
13770e3d5408SPeter Wemm 	 * Here's where the real work gets done
13780e3d5408SPeter Wemm 	 */
137915589c42SPeter Wemm 	switch (compare) {
13800e3d5408SPeter Wemm 	case C_DEFAULT:
13810e3d5408SPeter Wemm 	    if (itrace)
13820e3d5408SPeter Wemm 		(void) fprintf(stderr,
13830e3d5408SPeter Wemm 			       "infocmp: about to dump %s\n",
13840e3d5408SPeter Wemm 			       tname[0]);
13850e3d5408SPeter Wemm 	    (void) printf("#\tReconstructed via infocmp from file: %s\n",
13860e3d5408SPeter Wemm 			  tfile[0]);
138715589c42SPeter Wemm 	    len = dump_entry(&entries[0].tterm, limited, numbers, NULL);
13880e3d5408SPeter Wemm 	    putchar('\n');
13890e3d5408SPeter Wemm 	    if (itrace)
13900e3d5408SPeter Wemm 		(void) fprintf(stderr, "infocmp: length %d\n", len);
13910e3d5408SPeter Wemm 	    break;
13920e3d5408SPeter Wemm 
13930e3d5408SPeter Wemm 	case C_DIFFERENCE:
13940e3d5408SPeter Wemm 	    if (itrace)
13950e3d5408SPeter Wemm 		(void) fprintf(stderr, "infocmp: dumping differences\n");
13960e3d5408SPeter Wemm 	    (void) printf("comparing %s to %s.\n", tname[0], tname[1]);
139715589c42SPeter Wemm 	    compare_entry(compare_predicate, &entries->tterm, quiet);
13980e3d5408SPeter Wemm 	    break;
13990e3d5408SPeter Wemm 
14000e3d5408SPeter Wemm 	case C_COMMON:
14010e3d5408SPeter Wemm 	    if (itrace)
14020e3d5408SPeter Wemm 		(void) fprintf(stderr,
14030e3d5408SPeter Wemm 			       "infocmp: dumping common capabilities\n");
14040e3d5408SPeter Wemm 	    (void) printf("comparing %s to %s.\n", tname[0], tname[1]);
140515589c42SPeter Wemm 	    compare_entry(compare_predicate, &entries->tterm, quiet);
14060e3d5408SPeter Wemm 	    break;
14070e3d5408SPeter Wemm 
14080e3d5408SPeter Wemm 	case C_NAND:
14090e3d5408SPeter Wemm 	    if (itrace)
14100e3d5408SPeter Wemm 		(void) fprintf(stderr,
14110e3d5408SPeter Wemm 			       "infocmp: dumping differences\n");
14120e3d5408SPeter Wemm 	    (void) printf("comparing %s to %s.\n", tname[0], tname[1]);
141315589c42SPeter Wemm 	    compare_entry(compare_predicate, &entries->tterm, quiet);
14140e3d5408SPeter Wemm 	    break;
14150e3d5408SPeter Wemm 
14160e3d5408SPeter Wemm 	case C_USEALL:
14170e3d5408SPeter Wemm 	    if (itrace)
14180e3d5408SPeter Wemm 		(void) fprintf(stderr, "infocmp: dumping use entry\n");
141915589c42SPeter Wemm 	    len = dump_entry(&entries[0].tterm, limited, numbers, use_predicate);
14200e3d5408SPeter Wemm 	    for (i = 1; i < termcount; i++)
142115589c42SPeter Wemm 		len += dump_uses(tname[i], !(outform == F_TERMCAP || outform
142215589c42SPeter Wemm 					     == F_TCONVERR));
14230e3d5408SPeter Wemm 	    putchar('\n');
14240e3d5408SPeter Wemm 	    if (itrace)
14250e3d5408SPeter Wemm 		(void) fprintf(stderr, "infocmp: length %d\n", len);
14260e3d5408SPeter Wemm 	    break;
14270e3d5408SPeter Wemm 	}
142815589c42SPeter Wemm     } else if (compare == C_USEALL)
14290e3d5408SPeter Wemm 	(void) fprintf(stderr, "Sorry, -u doesn't work with -F\n");
14300e3d5408SPeter Wemm     else if (compare == C_DEFAULT)
14310e3d5408SPeter Wemm 	(void) fprintf(stderr, "Use `tic -[CI] <file>' for this.\n");
14320e3d5408SPeter Wemm     else if (argc - optind != 2)
14330e3d5408SPeter Wemm 	(void) fprintf(stderr,
14340e3d5408SPeter Wemm 		       "File comparison needs exactly two file arguments.\n");
14350e3d5408SPeter Wemm     else
14360e3d5408SPeter Wemm 	file_comparison(argc - optind, argv + optind);
14370e3d5408SPeter Wemm 
14380e3d5408SPeter Wemm     ExitProgram(EXIT_SUCCESS);
14390e3d5408SPeter Wemm }
14400e3d5408SPeter Wemm 
14410e3d5408SPeter Wemm /* infocmp.c ends here */
1442