Home | History | Annotate | Line # | Download | only in infocmp
infocmp.c revision 1.10
      1 /* $NetBSD: infocmp.c,v 1.10 2016/03/09 20:02:33 christos Exp $ */
      2 
      3 /*
      4  * Copyright (c) 2009, 2010 The NetBSD Foundation, Inc.
      5  *
      6  * This code is derived from software contributed to The NetBSD Foundation
      7  * by Roy Marples.
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted provided that the following conditions
     11  * are met:
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  * 2. Redistributions in binary form must reproduce the above copyright
     15  *    notice, this list of conditions and the following disclaimer in the
     16  *    documentation and/or other materials provided with the distribution.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28  */
     29 
     30 #include <sys/cdefs.h>
     31 __RCSID("$NetBSD: infocmp.c,v 1.10 2016/03/09 20:02:33 christos Exp $");
     32 
     33 #include <sys/ioctl.h>
     34 
     35 #include <ctype.h>
     36 #include <err.h>
     37 #include <stdio.h>
     38 #include <stdlib.h>
     39 #include <string.h>
     40 #include <term_private.h>
     41 #include <term.h>
     42 #include <unistd.h>
     43 #include <util.h>
     44 
     45 #define SW 8
     46 
     47 typedef struct tient {
     48 	char type;
     49 	const char *id;
     50 	signed char flag;
     51 	short num;
     52 	const char *str;
     53 } TIENT;
     54 
     55 static size_t cols;
     56 static int aflag, cflag, nflag, qflag, xflag;
     57 
     58 static size_t
     59 outstr(FILE *f, const char *str)
     60 {
     61 	unsigned char ch;
     62 	size_t r, l;
     63 
     64 	r = 0;
     65 	l = strlen(str);
     66 	while ((ch = (unsigned char)(*str++)) != '\0') {
     67 		switch (ch) {
     68 		case 128:
     69 			ch = '0';
     70 			break;
     71 		case '\033':
     72 			ch = 'E';
     73 			break;
     74 		case '\014':
     75 			ch = 'f';
     76 			break;
     77 		case '^': /* FALLTHROUGH */
     78 		case ',': /* escape these */
     79 			break;
     80 		case ' ':
     81 			ch = 's';
     82 			break;
     83 		default:
     84 			if (ch == '\177') {
     85 				if (f != NULL)
     86 					fputc('^', f);
     87 				ch = '?';
     88 				r++;
     89 			} else if (iscntrl(ch) &&
     90 			    ch < 128 &&
     91 			    ch != '\\' &&
     92 			    (l < 4 || isdigit((unsigned char)*str)))
     93 			{
     94 				if (f != NULL)
     95 					fputc('^', f);
     96 				ch += '@';
     97 				r++;
     98 			} else if (!isprint(ch)) {
     99 				if (f != NULL)
    100 					fprintf(f, "\\%03o", ch);
    101 				r += 4;
    102 				continue;
    103 			}
    104 			goto prnt;
    105 		}
    106 
    107 		if (f != NULL)
    108 			fputc('\\', f);
    109 		r++;
    110 prnt:
    111 		if (f != NULL)
    112 			fputc(ch, f);
    113 		r++;
    114 	}
    115 	return r;
    116 }
    117 
    118 static int
    119 ent_compare(const void *a, const void *b)
    120 {
    121 	const TIENT *ta, *tb;
    122 
    123 	ta = (const TIENT *)a;
    124 	tb = (const TIENT *)b;
    125 	return strcmp(ta->id, tb->id);
    126 }
    127 
    128 static void
    129 setdb(char *db)
    130 {
    131 	size_t len;
    132 
    133 	len = strlen(db);
    134 	if (len > 3 &&
    135 	    db[len - 3] == '.' &&
    136 	    db[len - 2] == 'd' &&
    137 	    db[len - 1] == 'b')
    138 		db[len - 3] = '\0';
    139 	setenv("TERMINFO", db, 1);
    140 }
    141 
    142 static void
    143 print_ent(const TIENT *ents, size_t nents)
    144 {
    145 	size_t col, i, l;
    146 	char nbuf[64];
    147 
    148 	if (nents == 0)
    149 		return;
    150 
    151 	col = SW;
    152 	printf("\t");
    153 	for (i = 0; i < nents; i++) {
    154 		if (*ents[i].id == '.' && aflag == 0)
    155 			continue;
    156 		switch (ents[i].type) {
    157 		case 'f':
    158 			if (ents[i].flag == ABSENT_BOOLEAN)
    159 				continue;
    160 			l = strlen(ents[i].id) + 2;
    161 			if (ents[i].flag == CANCELLED_BOOLEAN)
    162 				l++;
    163 			break;
    164 		case 'n':
    165 			if (ents[i].num == ABSENT_NUMERIC)
    166 				continue;
    167 			if (VALID_NUMERIC(ents[i].num))
    168 				l = snprintf(nbuf, sizeof(nbuf), "%s#%d,",
    169 				    ents[i].id, ents[i].num);
    170 			else
    171 				l = snprintf(nbuf, sizeof(nbuf), "%s@,",
    172 				    ents[i].id);
    173 			break;
    174 		case 's':
    175 			if (ents[i].str == ABSENT_STRING)
    176 				continue;
    177 			if (VALID_STRING(ents[i].str))
    178 				l = strlen(ents[i].id) +
    179 				    outstr(NULL, ents[i].str) + 7;
    180 			else
    181 				l = strlen(ents[i].id) + 3;
    182 			break;
    183 		default:
    184 			errx(EXIT_FAILURE, "invalid type");
    185 		}
    186 		if (col != SW) {
    187 			if (col + l > cols) {
    188 				printf("\n\t");
    189 				col = SW;
    190 			} else
    191 				col += printf(" ");
    192 		}
    193 		switch (ents[i].type) {
    194 		case 'f':
    195 			col += printf("%s", ents[i].id);
    196 			if (ents[i].flag == ABSENT_BOOLEAN ||
    197 			    ents[i].flag == CANCELLED_BOOLEAN)
    198 				col += printf("@");
    199 			col += printf(",");
    200 			break;
    201 		case 'n':
    202 			col += printf("%s", nbuf);
    203 			break;
    204 		case 's':
    205 			col += printf("%s", ents[i].id);
    206 			if (VALID_STRING(ents[i].str)) {
    207 				col += printf("=");
    208 				col += outstr(stdout, ents[i].str);
    209 			} else
    210 				col += printf("@");
    211 			col += printf(",");
    212 			break;
    213 		}
    214 	}
    215 	printf("\n");
    216 }
    217 
    218 static size_t
    219 load_ents(TIENT *ents, TERMINAL *t, char type)
    220 {
    221 	size_t i, n, max;
    222 	TERMUSERDEF *ud;
    223 
    224 	switch (type) {
    225 	case 'f':
    226 		max = TIFLAGMAX;
    227 		break;
    228 	case 'n':
    229 		max = TINUMMAX;
    230 		break;
    231 	default:
    232 		max = TISTRMAX;
    233 	}
    234 
    235 	n = 0;
    236 	for (i = 0; i <= max; i++) {
    237 		switch (type) {
    238 		case 'f':
    239 			if (t->flags[i] == 1 ||
    240 			    (aflag && t->flags[i] == CANCELLED_BOOLEAN))
    241 			{
    242 				ents[n].id = _ti_flagid(i);
    243 				ents[n].type = 'f';
    244 				ents[n++].flag = t->flags[i];
    245 			}
    246 			break;
    247 		case 'n':
    248 			if (VALID_NUMERIC(t->nums[i]) ||
    249 			    (aflag && t->nums[i] == CANCELLED_NUMERIC))
    250 			{
    251 				ents[n].id = _ti_numid(i);
    252 				ents[n].type = 'n';
    253 				ents[n++].num = t->nums[i];
    254 			}
    255 			break;
    256 		default:
    257 			if (VALID_STRING(t->strs[i]) ||
    258 			    (aflag && t->strs[i] == CANCELLED_STRING))
    259 			{
    260 				ents[n].id = _ti_strid(i);
    261 				ents[n].type = 's';
    262 				ents[n++].str = t->strs[i];
    263 			}
    264 			break;
    265 		}
    266 	}
    267 
    268 	if (xflag != 0 && t->_nuserdefs != 0) {
    269 		for (i = 0; i < t->_nuserdefs; i++) {
    270 			ud = &t->_userdefs[i];
    271 			if (ud->type == type) {
    272 				switch (type) {
    273 				case 'f':
    274 					if (!aflag &&
    275 					    !VALID_BOOLEAN(ud->flag))
    276 						continue;
    277 					break;
    278 				case 'n':
    279 					if (!aflag &&
    280 					    !VALID_NUMERIC(ud->num))
    281 						continue;
    282 					break;
    283 				case 's':
    284 					if (!aflag &&
    285 					    !VALID_STRING(ud->str))
    286 						continue;
    287 					break;
    288 				}
    289 				ents[n].id = ud->id;
    290 				ents[n].type = ud->type;
    291 				ents[n].flag = ud->flag;
    292 				ents[n].num = ud->num;
    293 				ents[n++].str = ud->str;
    294 			}
    295 		}
    296 	}
    297 
    298 	qsort(ents, n, sizeof(TIENT), ent_compare);
    299 	return n;
    300 }
    301 
    302 static void
    303 cprint_ent(TIENT *ent)
    304 {
    305 
    306 	if (ent == NULL) {
    307 		if (qflag == 0)
    308 			printf("NULL");
    309 		else
    310 			printf("-");
    311 	}
    312 
    313 	switch (ent->type) {
    314 	case 'f':
    315 		if (VALID_BOOLEAN(ent->flag))
    316 			printf(ent->flag == 1 ? "T" : "F");
    317 		else if (qflag == 0)
    318 			printf("F");
    319 		else if (ent->flag == CANCELLED_BOOLEAN)
    320 			printf("@");
    321 		else
    322 			printf("-");
    323 		break;
    324 	case 'n':
    325 		if (VALID_NUMERIC(ent->num))
    326 			printf("%d", ent->num);
    327 		else if (qflag == 0)
    328 			printf("NULL");
    329 		else if (ent->num == CANCELLED_NUMERIC)
    330 			printf("@");
    331 		else
    332 			printf("-");
    333 		break;
    334 	case 's':
    335 		if (VALID_STRING(ent->str)) {
    336 			printf("'");
    337 			outstr(stdout, ent->str);
    338 			printf("'");
    339 		} else if (qflag == 0)
    340 			printf("NULL");
    341 		else if (ent->str == CANCELLED_STRING)
    342 			printf("@");
    343 		else
    344 			printf("-");
    345 		break;
    346 	}
    347 }
    348 
    349 static void
    350 compare_ents(TIENT *ents1, size_t n1, TIENT *ents2, size_t n2)
    351 {
    352 	size_t i1, i2;
    353 	TIENT *e1, *e2, ee;
    354 	int c;
    355 
    356 	i1 = i2 = 0;
    357 	ee.type = 'f';
    358 	ee.flag = ABSENT_BOOLEAN;
    359 	ee.num = ABSENT_NUMERIC;
    360 	ee.str = ABSENT_STRING;
    361 	while (i1 != n1 || i2 != n2) {
    362 		if (i1 == n1)
    363 			c = 1;
    364 		else if (i2 == n2)
    365 			c = -1;
    366 		else
    367 			c = strcmp(ents1[i1].id, ents2[i2].id);
    368 		if (c == 0) {
    369 			e1 = &ents1[i1++];
    370 			e2 = &ents2[i2++];
    371 		} else if (c < 0) {
    372 			e1 = &ents1[i1++];
    373 			e2 = &ee;
    374 			ee.id = e1->id;
    375 			ee.type = e1->type;
    376 		} else {
    377 			e1 = &ee;
    378 			e2 = &ents2[i2++];
    379 			ee.id = e2->id;
    380 			ee.type = e2->type;
    381 		}
    382 		switch (e1->type) {
    383 		case 'f':
    384 			if (cflag != 0) {
    385 				if (e1->flag == e2->flag)
    386 					printf("\t%s\n", ents1[i1].id);
    387 				continue;
    388 			}
    389 			if (e1->flag == e2->flag)
    390 				continue;
    391 			break;
    392 		case 'n':
    393 			if (cflag != 0) {
    394 				if (e1->num == e2->num)
    395 					printf("\t%s#%d\n",
    396 					    ents1[i1].id, ents1[i1].num);
    397 				continue;
    398 			}
    399 			if (e1->num == e2->num)
    400 				continue;
    401 			break;
    402 		case 's':
    403 			if (cflag != 0) {
    404 				if (VALID_STRING(e1->str) &&
    405 				    VALID_STRING(e2->str) &&
    406 				    strcmp(e1->str, e2->str) == 0) {
    407 					printf("\t%s=", ents1[i1].id);
    408 					outstr(stdout, ents1[i1].str);
    409 					printf("\n");
    410 				}
    411 				continue;
    412 			}
    413 			if (VALID_STRING(e1->str) &&
    414 			    VALID_STRING(e2->str) &&
    415 			    strcmp(e1->str, e2->str) == 0)
    416 				continue;
    417 			break;
    418 		}
    419 		printf("\t%s: ", e1->id);
    420 		cprint_ent(e1);
    421 		if (e1->type == 'f')
    422 			printf(":");
    423 		else
    424 			printf(", ");
    425 		cprint_ent(e2);
    426 		printf(".\n");
    427 	}
    428 }
    429 
    430 static TERMINAL *
    431 load_term(const char *name)
    432 {
    433 	TERMINAL *t;
    434 
    435 	t = ecalloc(1, sizeof(*t));
    436 	if (name == NULL)
    437 		name = getenv("TERM");
    438 	if (name == NULL)
    439 		name = "dumb";
    440 	if (_ti_getterm(t, name, 1) == 1)
    441 		return t;
    442 
    443 	if (_ti_database == NULL)
    444 		errx(EXIT_FAILURE, "no terminal definition found in internal database");
    445 	else
    446 		errx(EXIT_FAILURE, "no terminal definition found in %s.db", _ti_database);
    447 }
    448 
    449 static void
    450 show_missing(TERMINAL *t1, TERMINAL *t2, char type)
    451 {
    452 	ssize_t i, max;
    453 	const char *id;
    454 
    455 	switch (type) {
    456 	case 'f':
    457 		max = TIFLAGMAX;
    458 		break;
    459 	case 'n':
    460 		max = TINUMMAX;
    461 		break;
    462 	default:
    463 		max = TISTRMAX;
    464 	}
    465 
    466 	for (i = 0; i <= max; i++) {
    467 		switch (type) {
    468 		case 'f':
    469 			if (t1->flags[i] != ABSENT_BOOLEAN ||
    470 			    t2->flags[i] != ABSENT_BOOLEAN)
    471 				continue;
    472 			id = _ti_flagid(i);
    473 			break;
    474 		case 'n':
    475 			if (t1->nums[i] != ABSENT_NUMERIC ||
    476 			    t2->nums[i] != ABSENT_NUMERIC)
    477 				continue;
    478 			id = _ti_numid(i);
    479 			break;
    480 		default:
    481 			if (t1->strs[i] != ABSENT_STRING ||
    482 			    t2->strs[i] != ABSENT_STRING)
    483 				continue;
    484 			id = _ti_strid(i);
    485 			break;
    486 		}
    487 		printf("\t!%s.\n", id);
    488 	}
    489 }
    490 
    491 static TERMUSERDEF *
    492 find_userdef(TERMINAL *term, const char *id)
    493 {
    494 	size_t i;
    495 
    496 	for (i = 0; i < term->_nuserdefs; i++)
    497 		if (strcmp(term->_userdefs[i].id, id) == 0)
    498 			return &term->_userdefs[i];
    499 	return NULL;
    500 }
    501 
    502 static void
    503 use_terms(TERMINAL *term, size_t nuse, char **uterms)
    504 {
    505 	TERMINAL **terms;
    506 	TERMUSERDEF *ud, *tud;
    507 	size_t i, j, agree, absent, data;
    508 
    509 	terms = ecalloc(nuse, sizeof(**terms));
    510 	for (i = 0; i < nuse; i++) {
    511 		if (strcmp(term->name, *uterms) == 0)
    512 			errx(EXIT_FAILURE, "cannot use same terminal");
    513 		for (j = 0; j < i; j++)
    514 			if (strcmp(terms[j]->name, *uterms) == 0)
    515 				errx(EXIT_FAILURE, "cannot use same terminal");
    516 		terms[i] = load_term(*uterms++);
    517 	}
    518 
    519 	for (i = 0; i < TIFLAGMAX + 1; i++) {
    520 		agree = absent = data = 0;
    521 		for (j = 0; j < nuse; j++) {
    522 			if (terms[j]->flags[i] == ABSENT_BOOLEAN ||
    523 			    terms[j]->flags[i] == CANCELLED_BOOLEAN)
    524 				absent++;
    525 			else {
    526 				data++;
    527 				if (term->flags[i] == terms[j]->flags[i])
    528 					agree++;
    529 			}
    530 		}
    531 		if (data == 0)
    532 			continue;
    533 		if (agree > 0 && agree + absent == nuse)
    534 			term->flags[i] = ABSENT_BOOLEAN;
    535 		else if (term->flags[i] == ABSENT_BOOLEAN)
    536 			term->flags[i] = CANCELLED_BOOLEAN;
    537 	}
    538 
    539 	for (i = 0; i < TINUMMAX + 1; i++) {
    540 		agree = absent = data = 0;
    541 		for (j = 0; j < nuse; j++) {
    542 			if (terms[j]->nums[i] == ABSENT_NUMERIC ||
    543 			    terms[j]->nums[i] == CANCELLED_NUMERIC)
    544 				absent++;
    545 			else {
    546 				data++;
    547 				if (term->nums[i] == terms[j]->nums[i])
    548 					agree++;
    549 			}
    550 		}
    551 		if (data == 0)
    552 			continue;
    553 		if (agree > 0 && agree + absent == nuse)
    554 			term->nums[i] = ABSENT_NUMERIC;
    555 		else if (term->nums[i] == ABSENT_NUMERIC)
    556 			term->nums[i] = CANCELLED_NUMERIC;
    557 	}
    558 
    559 	for (i = 0; i < TISTRMAX + 1; i++) {
    560 		agree = absent = data = 0;
    561 		for (j = 0; j < nuse; j++) {
    562 			if (terms[j]->strs[i] == ABSENT_STRING ||
    563 			    terms[j]->strs[i] == CANCELLED_STRING)
    564 				absent++;
    565 			else {
    566 				data++;
    567 				if (VALID_STRING(term->strs[i]) &&
    568 				    strcmp(term->strs[i],
    569 					terms[j]->strs[i]) == 0)
    570 					agree++;
    571 			}
    572 		}
    573 		if (data == 0)
    574 			continue;
    575 		if (agree > 0 && agree + absent == nuse)
    576 			term->strs[i] = ABSENT_STRING;
    577 		else if (term->strs[i] == ABSENT_STRING)
    578 			term->strs[i] = CANCELLED_STRING;
    579 	}
    580 
    581 	/* User defined caps are more tricky.
    582 	   First we set any to absent that agree. */
    583 	for (i = 0; i < term->_nuserdefs; i++) {
    584 		agree = absent = data = 0;
    585 		ud = &term->_userdefs[i];
    586 		for (j = 0; j < nuse; j++) {
    587 			tud = find_userdef(terms[j], ud->id);
    588 			if (tud == NULL)
    589 				absent++;
    590 			else {
    591 				data++;
    592 				switch (ud->type) {
    593 				case 'f':
    594 					if (tud->type == 'f' &&
    595 					    tud->flag == ud->flag)
    596 						agree++;
    597 					break;
    598 				case 'n':
    599 					if (tud->type == 'n' &&
    600 					    tud->num == ud->num)
    601 						agree++;
    602 					break;
    603 				case 's':
    604 					if (tud->type == 's' &&
    605 					    VALID_STRING(tud->str) &&
    606 					    VALID_STRING(ud->str) &&
    607 					    strcmp(ud->str, tud->str) == 0)
    608 						agree++;
    609 					break;
    610 				}
    611 			}
    612 		}
    613 		if (data == 0)
    614 			continue;
    615 		if (agree > 0 && agree + absent == nuse) {
    616 			ud->flag = ABSENT_BOOLEAN;
    617 			ud->num = ABSENT_NUMERIC;
    618 			ud->str = ABSENT_STRING;
    619 		}
    620 	}
    621 
    622 	/* Now add any that we don't have as cancelled */
    623 	for (i = 0; i < nuse; i++) {
    624 		for (j = 0; j < terms[i]->_nuserdefs; j++) {
    625 			ud = find_userdef(term, terms[i]->_userdefs[j].id);
    626 			if (ud != NULL)
    627 				continue; /* We have handled this */
    628 			term->_userdefs = erealloc(term->_userdefs,
    629 			    sizeof(*term->_userdefs) * (term->_nuserdefs + 1));
    630 			tud = &term->_userdefs[term->_nuserdefs++];
    631 			tud->id = terms[i]->_userdefs[j].id;
    632 			tud->type = terms[i]->_userdefs[j].flag;
    633 			tud->flag = CANCELLED_BOOLEAN;
    634 			tud->num = CANCELLED_NUMERIC;
    635 			tud->str = CANCELLED_STRING;
    636 		}
    637 	}
    638 }
    639 
    640 int
    641 main(int argc, char **argv)
    642 {
    643 	char *term, *Barg;
    644 	int ch, uflag;
    645 	TERMINAL *t, *t2;
    646 	size_t n, n2;
    647 	struct winsize ws;
    648 	TIENT ents[TISTRMAX + 1], ents2[TISTRMAX + 1];
    649 
    650 	cols = 80; /* default */
    651 	term = getenv("COLUMNS");
    652 	if (term != NULL)
    653 		cols = strtoul(term, NULL, 10);
    654 	else if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == 0)
    655 		cols = ws.ws_col;
    656 
    657 	uflag = xflag = 0;
    658 	Barg = NULL;
    659 	while ((ch = getopt(argc, argv, "1A:B:acnquw:x")) != -1)
    660 		switch (ch) {
    661 		case '1':
    662 			cols = 1;
    663 			break;
    664 		case 'A':
    665 			setdb(optarg);
    666 			break;
    667 		case 'B':
    668 			Barg = optarg;
    669 			break;
    670 		case 'a':
    671 			aflag = 1;
    672 			break;
    673 		case 'c':
    674 			cflag = 1;
    675 			break;
    676 		case 'n':
    677 			nflag = 1;
    678 			break;
    679 		case 'q':
    680 			qflag = 1;
    681 			break;
    682 		case 'u':
    683 			uflag = 1;
    684 			aflag = 1;
    685 			break;
    686 		case 'w':
    687 			cols = strtoul(optarg, NULL, 10);
    688 			break;
    689 		case 'x':
    690 			xflag = 1;
    691 			break;
    692 		case '?':
    693 		default:
    694 			fprintf(stderr,
    695 			    "usage: %s [-1acnqux] [-A database] [-B database] "
    696 			    "[-w cols] [term]\n",
    697 			    getprogname());
    698 			return EXIT_FAILURE;
    699 		}
    700 	cols--;
    701 
    702 	if (optind + 1 < argc)
    703 		aflag = 1;
    704 
    705 	if (optind < argc)
    706 		term = argv[optind++];
    707 	else
    708 		term = NULL;
    709 	t = load_term(term);
    710 
    711 	if (uflag != 0)
    712 		use_terms(t, argc - optind, argv + optind);
    713 
    714 	if ((optind + 1 != argc && nflag == 0) || uflag != 0) {
    715 		if (uflag == 0) {
    716 			printf("# Reconstructed from ");
    717 			if (_ti_database == NULL)
    718 				printf("internal database\n");
    719 			else
    720 				printf("%s%s\n", _ti_database,
    721 				    *_ti_database == '/' ? ".cdb" : "");
    722 		}
    723 		printf("%s", t->name);
    724 		if (t->_alias != NULL && *t->_alias != '\0')
    725 			printf("|%s", t->_alias);
    726 		if (t->desc != NULL && *t->desc != '\0')
    727 			printf("|%s", t->desc);
    728 		printf(",\n");
    729 
    730 		n = load_ents(ents, t, 'f');
    731 		print_ent(ents, n);
    732 		n = load_ents(ents, t, 'n');
    733 		print_ent(ents, n);
    734 		n = load_ents(ents, t, 's');
    735 		print_ent(ents, n);
    736 
    737 		if (uflag != 0) {
    738 			printf("\t");
    739 			n = SW;
    740 			for (; optind < argc; optind++) {
    741 				n2 = 5 + strlen(argv[optind]);
    742 				if (n != SW) {
    743 					if (n + n2 > cols) {
    744 						printf("\n\t");
    745 						n = SW;
    746 					} else
    747 						n += printf(" ");
    748 				}
    749 				n += printf("use=%s,", argv[optind]);
    750 			}
    751 			printf("\n");
    752 		}
    753 		return EXIT_SUCCESS;
    754 	}
    755 
    756 	if (Barg == NULL)
    757 		unsetenv("TERMINFO");
    758 	else
    759 		setdb(Barg);
    760 	t2 = load_term(argv[optind++]);
    761 	printf("comparing %s to %s.\n", t->name, t2->name);
    762 	if (qflag == 0)
    763 		printf("    comparing booleans.\n");
    764 	if (nflag == 0) {
    765 		n = load_ents(ents, t, 'f');
    766 		n2 = load_ents(ents2, t2, 'f');
    767 		compare_ents(ents, n, ents2, n2);
    768 	} else
    769 		show_missing(t, t2, 'f');
    770 	if (qflag == 0)
    771 		printf("    comparing numbers.\n");
    772 	if (nflag == 0) {
    773 		n = load_ents(ents, t, 'n');
    774 		n2 = load_ents(ents2, t2, 'n');
    775 		compare_ents(ents, n, ents2, n2);
    776 	} else
    777 		show_missing(t, t2, 'n');
    778 	if (qflag == 0)
    779 		printf("    comparing strings.\n");
    780 	if (nflag == 0) {
    781 		n = load_ents(ents, t, 's');
    782 		n2 = load_ents(ents2, t2, 's');
    783 		compare_ents(ents, n, ents2, n2);
    784 	} else
    785 		show_missing(t, t2, 's');
    786 	return EXIT_SUCCESS;
    787 }
    788