Remove building with NOCRYPTO option
[minix3.git] / usr.bin / infocmp / infocmp.c
blobf3b04fc7899d8a911d90117a54e0267c13691492
1 /* $NetBSD: infocmp.c,v 1.8 2013/10/01 09:01:49 roy Exp $ */
3 /*
4 * Copyright (c) 2009, 2010 The NetBSD Foundation, Inc.
6 * This code is derived from software contributed to The NetBSD Foundation
7 * by Roy Marples.
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.
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.
30 #include <sys/cdefs.h>
31 __RCSID("$NetBSD: infocmp.c,v 1.8 2013/10/01 09:01:49 roy Exp $");
33 #include <sys/ioctl.h>
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>
44 #define SW 8
46 typedef struct tient {
47 char type;
48 const char *id;
49 signed char flag;
50 short num;
51 const char *str;
52 } TIENT;
54 static size_t cols;
55 static int aflag, cflag, nflag, qflag, xflag;
57 static size_t
58 outstr(FILE *f, const char *str)
60 unsigned char ch;
61 size_t r, l;
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)))
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;
103 goto prnt;
106 if (f != NULL)
107 fputc('\\', f);
108 r++;
109 prnt:
110 if (f != NULL)
111 fputc(ch, f);
112 r++;
114 return r;
117 static int
118 ent_compare(const void *a, const void *b)
120 const TIENT *ta, *tb;
122 ta = (const TIENT *)a;
123 tb = (const TIENT *)b;
124 return strcmp(ta->id, tb->id);
127 static void
128 setdb(char *db)
130 size_t len;
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);
141 static void
142 print_ent(const TIENT *ents, size_t nents)
144 size_t col, i, l;
145 char nbuf[64];
147 if (nents == 0)
148 return;
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");
185 if (col != SW) {
186 if (col + l > cols) {
187 printf("\n\t");
188 col = SW;
189 } else
190 col += printf(" ");
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;
214 printf("\n");
217 static size_t
218 load_ents(TIENT *ents, TERMINAL *t, char type)
220 size_t i, n, max;
221 TERMUSERDEF *ud;
223 switch (type) {
224 case 'f':
225 max = TIFLAGMAX;
226 break;
227 case 'n':
228 max = TINUMMAX;
229 break;
230 default:
231 max = TISTRMAX;
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))
241 ents[n].id = _ti_flagid(i);
242 ents[n].type = 'f';
243 ents[n++].flag = t->flags[i];
245 break;
246 case 'n':
247 if (VALID_NUMERIC(t->nums[i]) ||
248 (aflag && t->nums[i] == CANCELLED_NUMERIC))
250 ents[n].id = _ti_numid(i);
251 ents[n].type = 'n';
252 ents[n++].num = t->nums[i];
254 break;
255 default:
256 if (VALID_STRING(t->strs[i]) ||
257 (aflag && t->strs[i] == CANCELLED_STRING))
259 ents[n].id = _ti_strid(i);
260 ents[n].type = 's';
261 ents[n++].str = t->strs[i];
263 break;
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;
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;
297 qsort(ents, n, sizeof(TIENT), ent_compare);
298 return n;
301 static void
302 cprint_ent(TIENT *ent)
305 if (ent == NULL) {
306 if (qflag == 0)
307 printf("NULL");
308 else
309 printf("-");
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;
348 static void
349 compare_ents(TIENT *ents1, size_t n1, TIENT *ents2, size_t n2)
351 size_t i1, i2;
352 TIENT *e1, *e2, ee;
353 int c;
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;
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;
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;
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");
410 continue;
412 if (VALID_STRING(e1->str) &&
413 VALID_STRING(e2->str) &&
414 strcmp(e1->str, e2->str) == 0)
415 continue;
416 break;
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");
429 static TERMINAL *
430 load_term(const char *name)
432 TERMINAL *t;
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)
442 return t;
444 if (_ti_database == NULL)
445 errx(1, "no terminal definition found in internal database");
446 else
447 errx(1, "no terminal definition found in %s.db", _ti_database);
450 static void
451 show_missing(TERMINAL *t1, TERMINAL *t2, char type)
453 ssize_t i, max;
454 const char *id;
456 switch (type) {
457 case 'f':
458 max = TIFLAGMAX;
459 break;
460 case 'n':
461 max = TINUMMAX;
462 break;
463 default:
464 max = TISTRMAX;
467 for (i = 0; i <= max; i++) {
468 switch (type) {
469 case 'f':
470 if (t1->flags[i] != ABSENT_BOOLEAN ||
471 t2->flags[i] != ABSENT_BOOLEAN)
472 continue;
473 id = _ti_flagid(i);
474 break;
475 case 'n':
476 if (t1->nums[i] != ABSENT_NUMERIC ||
477 t2->nums[i] != ABSENT_NUMERIC)
478 continue;
479 id = _ti_numid(i);
480 break;
481 default:
482 if (t1->strs[i] != ABSENT_STRING ||
483 t2->strs[i] != ABSENT_STRING)
484 continue;
485 id = _ti_strid(i);
486 break;
488 printf("\t!%s.\n", id);
492 static TERMUSERDEF *
493 find_userdef(TERMINAL *term, const char *id)
495 size_t i;
497 for (i = 0; i < term->_nuserdefs; i++)
498 if (strcmp(term->_userdefs[i].id, id) == 0)
499 return &term->_userdefs[i];
500 return NULL;
503 static void
504 use_terms(TERMINAL *term, size_t nuse, char **uterms)
506 TERMINAL **terms;
507 TERMUSERDEF *ud, *tud;
508 size_t i, j, agree, absent, data;
510 terms = malloc(sizeof(**terms) * nuse);
511 if (terms == NULL)
512 err(1, "malloc");
513 for (i = 0; i < nuse; i++) {
514 if (strcmp(term->name, *uterms) == 0)
515 errx(1, "cannot use same terminal");
516 for (j = 0; j < i; j++)
517 if (strcmp(terms[j]->name, *uterms) == 0)
518 errx(1, "cannot use same terminal");
519 terms[i] = load_term(*uterms++);
522 for (i = 0; i < TIFLAGMAX + 1; i++) {
523 agree = absent = data = 0;
524 for (j = 0; j < nuse; j++) {
525 if (terms[j]->flags[i] == ABSENT_BOOLEAN ||
526 terms[j]->flags[i] == CANCELLED_BOOLEAN)
527 absent++;
528 else {
529 data++;
530 if (term->flags[i] == terms[j]->flags[i])
531 agree++;
534 if (data == 0)
535 continue;
536 if (agree > 0 && agree + absent == nuse)
537 term->flags[i] = ABSENT_BOOLEAN;
538 else if (term->flags[i] == ABSENT_BOOLEAN)
539 term->flags[i] = CANCELLED_BOOLEAN;
542 for (i = 0; i < TINUMMAX + 1; i++) {
543 agree = absent = data = 0;
544 for (j = 0; j < nuse; j++) {
545 if (terms[j]->nums[i] == ABSENT_NUMERIC ||
546 terms[j]->nums[i] == CANCELLED_NUMERIC)
547 absent++;
548 else {
549 data++;
550 if (term->nums[i] == terms[j]->nums[i])
551 agree++;
554 if (data == 0)
555 continue;
556 if (agree > 0 && agree + absent == nuse)
557 term->nums[i] = ABSENT_NUMERIC;
558 else if (term->nums[i] == ABSENT_NUMERIC)
559 term->nums[i] = CANCELLED_NUMERIC;
562 for (i = 0; i < TISTRMAX + 1; i++) {
563 agree = absent = data = 0;
564 for (j = 0; j < nuse; j++) {
565 if (terms[j]->strs[i] == ABSENT_STRING ||
566 terms[j]->strs[i] == CANCELLED_STRING)
567 absent++;
568 else {
569 data++;
570 if (VALID_STRING(term->strs[i]) &&
571 strcmp(term->strs[i],
572 terms[j]->strs[i]) == 0)
573 agree++;
576 if (data == 0)
577 continue;
578 if (agree > 0 && agree + absent == nuse)
579 term->strs[i] = ABSENT_STRING;
580 else if (term->strs[i] == ABSENT_STRING)
581 term->strs[i] = CANCELLED_STRING;
584 /* User defined caps are more tricky.
585 First we set any to absent that agree. */
586 for (i = 0; i < term->_nuserdefs; i++) {
587 agree = absent = data = 0;
588 ud = &term->_userdefs[i];
589 for (j = 0; j < nuse; j++) {
590 tud = find_userdef(terms[j], ud->id);
591 if (tud == NULL)
592 absent++;
593 else {
594 data++;
595 switch (ud->type) {
596 case 'f':
597 if (tud->type == 'f' &&
598 tud->flag == ud->flag)
599 agree++;
600 break;
601 case 'n':
602 if (tud->type == 'n' &&
603 tud->num == ud->num)
604 agree++;
605 break;
606 case 's':
607 if (tud->type == 's' &&
608 VALID_STRING(tud->str) &&
609 VALID_STRING(ud->str) &&
610 strcmp(ud->str, tud->str) == 0)
611 agree++;
612 break;
616 if (data == 0)
617 continue;
618 if (agree > 0 && agree + absent == nuse) {
619 ud->flag = ABSENT_BOOLEAN;
620 ud->num = ABSENT_NUMERIC;
621 ud->str = ABSENT_STRING;
625 /* Now add any that we don't have as cancelled */
626 for (i = 0; i < nuse; i++) {
627 for (j = 0; j < terms[i]->_nuserdefs; j++) {
628 ud = find_userdef(term, terms[i]->_userdefs[j].id);
629 if (ud != NULL)
630 continue; /* We have handled this */
631 term->_userdefs = realloc(term->_userdefs,
632 sizeof(*term->_userdefs) * (term->_nuserdefs + 1));
633 if (term->_userdefs == NULL)
634 err(1, "malloc");
635 tud = &term->_userdefs[term->_nuserdefs++];
636 tud->id = terms[i]->_userdefs[j].id;
637 tud->type = terms[i]->_userdefs[j].flag;
638 tud->flag = CANCELLED_BOOLEAN;
639 tud->num = CANCELLED_NUMERIC;
640 tud->str = CANCELLED_STRING;
646 main(int argc, char **argv)
648 char *term, *Barg;
649 int ch, uflag;
650 TERMINAL *t, *t2;
651 size_t n, n2;
652 struct winsize ws;
653 TIENT ents[TISTRMAX + 1], ents2[TISTRMAX + 1];
655 cols = 80; /* default */
656 term = getenv("COLUMNS");
657 if (term != NULL)
658 cols = strtoul(term, NULL, 10);
659 else if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == 0)
660 cols = ws.ws_col;
662 uflag = xflag = 0;
663 Barg = NULL;
664 while ((ch = getopt(argc, argv, "1A:B:acnquw:x")) != -1)
665 switch (ch) {
666 case '1':
667 cols = 1;
668 break;
669 case 'A':
670 setdb(optarg);
671 break;
672 case 'B':
673 Barg = optarg;
674 break;
675 case 'a':
676 aflag = 1;
677 break;
678 case 'c':
679 cflag = 1;
680 break;
681 case 'n':
682 nflag = 1;
683 break;
684 case 'q':
685 qflag = 1;
686 break;
687 case 'u':
688 uflag = 1;
689 aflag = 1;
690 break;
691 case 'w':
692 cols = strtoul(optarg, NULL, 10);
693 break;
694 case 'x':
695 xflag = 1;
696 break;
697 case '?':
698 default:
699 fprintf(stderr,
700 "usage: %s [-1acnqux] [-A database] [-B database] "
701 "[-w cols] [term]\n",
702 getprogname());
703 return EXIT_FAILURE;
705 cols--;
707 if (optind + 1 < argc)
708 aflag = 1;
710 if (optind < argc)
711 term = argv[optind++];
712 else
713 term = NULL;
714 t = load_term(term);
716 if (uflag != 0)
717 use_terms(t, argc - optind, argv + optind);
719 if ((optind + 1 != argc && nflag == 0) || uflag != 0) {
720 if (uflag == 0) {
721 printf("# Reconstructed from ");
722 if (_ti_database == NULL)
723 printf("internal database\n");
724 else
725 printf("%s%s\n", _ti_database,
726 *_ti_database == '/' ? ".cdb" : "");
728 printf("%s", t->name);
729 if (t->_alias != NULL && *t->_alias != '\0')
730 printf("|%s", t->_alias);
731 if (t->desc != NULL && *t->desc != '\0')
732 printf("|%s", t->desc);
733 printf(",\n");
735 n = load_ents(ents, t, 'f');
736 print_ent(ents, n);
737 n = load_ents(ents, t, 'n');
738 print_ent(ents, n);
739 n = load_ents(ents, t, 's');
740 print_ent(ents, n);
742 if (uflag != 0) {
743 printf("\t");
744 n = SW;
745 for (; optind < argc; optind++) {
746 n2 = 5 + strlen(argv[optind]);
747 if (n != SW) {
748 if (n + n2 > cols) {
749 printf("\n\t");
750 n = SW;
751 } else
752 n += printf(" ");
754 n += printf("use=%s,", argv[optind]);
756 printf("\n");
758 return EXIT_SUCCESS;
761 if (Barg == NULL)
762 unsetenv("TERMINFO");
763 else
764 setdb(Barg);
765 t2 = load_term(argv[optind++]);
766 printf("comparing %s to %s.\n", t->name, t2->name);
767 if (qflag == 0)
768 printf(" comparing booleans.\n");
769 if (nflag == 0) {
770 n = load_ents(ents, t, 'f');
771 n2 = load_ents(ents2, t2, 'f');
772 compare_ents(ents, n, ents2, n2);
773 } else
774 show_missing(t, t2, 'f');
775 if (qflag == 0)
776 printf(" comparing numbers.\n");
777 if (nflag == 0) {
778 n = load_ents(ents, t, 'n');
779 n2 = load_ents(ents2, t2, 'n');
780 compare_ents(ents, n, ents2, n2);
781 } else
782 show_missing(t, t2, 'n');
783 if (qflag == 0)
784 printf(" comparing strings.\n");
785 if (nflag == 0) {
786 n = load_ents(ents, t, 's');
787 n2 = load_ents(ents2, t2, 's');
788 compare_ents(ents, n, ents2, n2);
789 } else
790 show_missing(t, t2, 's');
791 return EXIT_SUCCESS;