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