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