1*fe2a18efSroy /* $NetBSD: infocmp.c,v 1.17 2020/03/31 12:44:15 roy Exp $ */
24ca00e00Sroy
34ca00e00Sroy /*
4c33983b9Sroy * Copyright (c) 2009, 2010, 2020 The NetBSD Foundation, Inc.
54ca00e00Sroy *
64ca00e00Sroy * This code is derived from software contributed to The NetBSD Foundation
74ca00e00Sroy * by Roy Marples.
84ca00e00Sroy *
94ca00e00Sroy * Redistribution and use in source and binary forms, with or without
104ca00e00Sroy * modification, are permitted provided that the following conditions
114ca00e00Sroy * are met:
124ca00e00Sroy * 1. Redistributions of source code must retain the above copyright
134ca00e00Sroy * notice, this list of conditions and the following disclaimer.
144ca00e00Sroy * 2. Redistributions in binary form must reproduce the above copyright
154ca00e00Sroy * notice, this list of conditions and the following disclaimer in the
164ca00e00Sroy * documentation and/or other materials provided with the distribution.
174ca00e00Sroy *
184ca00e00Sroy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
194ca00e00Sroy * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
204ca00e00Sroy * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
214ca00e00Sroy * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
224ca00e00Sroy * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
234ca00e00Sroy * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
244ca00e00Sroy * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
254ca00e00Sroy * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
264ca00e00Sroy * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
274ca00e00Sroy * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
284ca00e00Sroy */
294ca00e00Sroy
304ca00e00Sroy #include <sys/cdefs.h>
31*fe2a18efSroy __RCSID("$NetBSD: infocmp.c,v 1.17 2020/03/31 12:44:15 roy Exp $");
324ca00e00Sroy
334ca00e00Sroy #include <sys/ioctl.h>
344ca00e00Sroy
354ca00e00Sroy #include <ctype.h>
364ca00e00Sroy #include <err.h>
374ca00e00Sroy #include <stdio.h>
384ca00e00Sroy #include <stdlib.h>
394ca00e00Sroy #include <string.h>
404ca00e00Sroy #include <term_private.h>
414ca00e00Sroy #include <term.h>
424ca00e00Sroy #include <unistd.h>
430fca9bd2Schristos #include <util.h>
444ca00e00Sroy
454ca00e00Sroy #define SW 8
464ca00e00Sroy
474ca00e00Sroy typedef struct tient {
484ca00e00Sroy char type;
494ca00e00Sroy const char *id;
50461cb40bSroy signed char flag;
51c33983b9Sroy int num;
524ca00e00Sroy const char *str;
534ca00e00Sroy } TIENT;
544ca00e00Sroy
554ca00e00Sroy static size_t cols;
565f630912Sroy static int aflag, cflag, nflag, qflag, xflag;
574ca00e00Sroy
584ca00e00Sroy static size_t
outstr(FILE * f,const char * str)594ca00e00Sroy outstr(FILE *f, const char *str)
604ca00e00Sroy {
614ca00e00Sroy unsigned char ch;
624ca00e00Sroy size_t r, l;
634ca00e00Sroy
644ca00e00Sroy r = 0;
654ca00e00Sroy l = strlen(str);
664ca00e00Sroy while ((ch = (unsigned char)(*str++)) != '\0') {
674ca00e00Sroy switch (ch) {
684ca00e00Sroy case 128:
694ca00e00Sroy ch = '0';
704ca00e00Sroy break;
714ca00e00Sroy case '\033':
724ca00e00Sroy ch = 'E';
734ca00e00Sroy break;
744ca00e00Sroy case '\014':
754ca00e00Sroy ch = 'f';
764ca00e00Sroy break;
774ca00e00Sroy case '^': /* FALLTHROUGH */
784ca00e00Sroy case ',': /* escape these */
794ca00e00Sroy break;
804ca00e00Sroy case ' ':
814ca00e00Sroy ch = 's';
824ca00e00Sroy break;
834ca00e00Sroy default:
844ca00e00Sroy if (ch == '\177') {
854ca00e00Sroy if (f != NULL)
864ca00e00Sroy fputc('^', f);
874ca00e00Sroy ch = '?';
884ca00e00Sroy r++;
894ca00e00Sroy } else if (iscntrl(ch) &&
904ca00e00Sroy ch < 128 &&
914ca00e00Sroy ch != '\\' &&
924ca00e00Sroy (l < 4 || isdigit((unsigned char)*str)))
934ca00e00Sroy {
944ca00e00Sroy if (f != NULL)
954ca00e00Sroy fputc('^', f);
964ca00e00Sroy ch += '@';
974ca00e00Sroy r++;
984ca00e00Sroy } else if (!isprint(ch)) {
994ca00e00Sroy if (f != NULL)
1004ca00e00Sroy fprintf(f, "\\%03o", ch);
1014ca00e00Sroy r += 4;
1024ca00e00Sroy continue;
1034ca00e00Sroy }
1044ca00e00Sroy goto prnt;
1054ca00e00Sroy }
1064ca00e00Sroy
1074ca00e00Sroy if (f != NULL)
1084ca00e00Sroy fputc('\\', f);
1094ca00e00Sroy r++;
1104ca00e00Sroy prnt:
1114ca00e00Sroy if (f != NULL)
1124ca00e00Sroy fputc(ch, f);
1134ca00e00Sroy r++;
1144ca00e00Sroy }
1154ca00e00Sroy return r;
1164ca00e00Sroy }
1174ca00e00Sroy
1184ca00e00Sroy static int
ent_compare(const void * a,const void * b)1194ca00e00Sroy ent_compare(const void *a, const void *b)
1204ca00e00Sroy {
1214ca00e00Sroy const TIENT *ta, *tb;
1224ca00e00Sroy
1234ca00e00Sroy ta = (const TIENT *)a;
1244ca00e00Sroy tb = (const TIENT *)b;
1254ca00e00Sroy return strcmp(ta->id, tb->id);
1264ca00e00Sroy }
1274ca00e00Sroy
1284ca00e00Sroy static void
setdb(char * db)1294ca00e00Sroy setdb(char *db)
1304ca00e00Sroy {
1312f3310bfSchristos static const char *ext[] = { ".cdb", ".db" };
1324ca00e00Sroy
1332f3310bfSchristos for (size_t i = 0; i < __arraycount(ext); i++) {
1342f3310bfSchristos char *ptr = strstr(db, ext[i]);
1352f3310bfSchristos if (ptr == NULL || ptr[strlen(ext[i])] != '\0')
1362f3310bfSchristos continue;
1372f3310bfSchristos *ptr = '\0';
1382f3310bfSchristos break;
1392f3310bfSchristos }
1404ca00e00Sroy setenv("TERMINFO", db, 1);
1414ca00e00Sroy }
1424ca00e00Sroy
1434ca00e00Sroy static void
print_ent(const TIENT * ents,size_t nents)1444ca00e00Sroy print_ent(const TIENT *ents, size_t nents)
1454ca00e00Sroy {
1464ca00e00Sroy size_t col, i, l;
1474ca00e00Sroy char nbuf[64];
1484ca00e00Sroy
1494ca00e00Sroy if (nents == 0)
1504ca00e00Sroy return;
1514ca00e00Sroy
1524ca00e00Sroy col = SW;
1534ca00e00Sroy printf("\t");
1544ca00e00Sroy for (i = 0; i < nents; i++) {
1554ca00e00Sroy if (*ents[i].id == '.' && aflag == 0)
1564ca00e00Sroy continue;
1574ca00e00Sroy switch (ents[i].type) {
1584ca00e00Sroy case 'f':
1594ca00e00Sroy if (ents[i].flag == ABSENT_BOOLEAN)
1604ca00e00Sroy continue;
1614ca00e00Sroy l = strlen(ents[i].id) + 2;
1624ca00e00Sroy if (ents[i].flag == CANCELLED_BOOLEAN)
1634ca00e00Sroy l++;
1644ca00e00Sroy break;
1654ca00e00Sroy case 'n':
1664ca00e00Sroy if (ents[i].num == ABSENT_NUMERIC)
1674ca00e00Sroy continue;
1684ca00e00Sroy if (VALID_NUMERIC(ents[i].num))
1694ca00e00Sroy l = snprintf(nbuf, sizeof(nbuf), "%s#%d,",
1704ca00e00Sroy ents[i].id, ents[i].num);
1714ca00e00Sroy else
1724ca00e00Sroy l = snprintf(nbuf, sizeof(nbuf), "%s@,",
1734ca00e00Sroy ents[i].id);
1744ca00e00Sroy break;
1754ca00e00Sroy case 's':
1764ca00e00Sroy if (ents[i].str == ABSENT_STRING)
1774ca00e00Sroy continue;
1784ca00e00Sroy if (VALID_STRING(ents[i].str))
1794ca00e00Sroy l = strlen(ents[i].id) +
1804ca00e00Sroy outstr(NULL, ents[i].str) + 7;
1814ca00e00Sroy else
1824ca00e00Sroy l = strlen(ents[i].id) + 3;
1834ca00e00Sroy break;
1844ca00e00Sroy default:
1850fca9bd2Schristos errx(EXIT_FAILURE, "invalid type");
1864ca00e00Sroy }
1874ca00e00Sroy if (col != SW) {
1884ca00e00Sroy if (col + l > cols) {
1894ca00e00Sroy printf("\n\t");
1904ca00e00Sroy col = SW;
1914ca00e00Sroy } else
1924ca00e00Sroy col += printf(" ");
1934ca00e00Sroy }
1944ca00e00Sroy switch (ents[i].type) {
1954ca00e00Sroy case 'f':
1964ca00e00Sroy col += printf("%s", ents[i].id);
1974ca00e00Sroy if (ents[i].flag == ABSENT_BOOLEAN ||
1984ca00e00Sroy ents[i].flag == CANCELLED_BOOLEAN)
1994ca00e00Sroy col += printf("@");
2004ca00e00Sroy col += printf(",");
2014ca00e00Sroy break;
2024ca00e00Sroy case 'n':
2034ca00e00Sroy col += printf("%s", nbuf);
2044ca00e00Sroy break;
2054ca00e00Sroy case 's':
2064ca00e00Sroy col += printf("%s", ents[i].id);
2074ca00e00Sroy if (VALID_STRING(ents[i].str)) {
2084ca00e00Sroy col += printf("=");
2094ca00e00Sroy col += outstr(stdout, ents[i].str);
2104ca00e00Sroy } else
2114ca00e00Sroy col += printf("@");
2124ca00e00Sroy col += printf(",");
2134ca00e00Sroy break;
2144ca00e00Sroy }
2154ca00e00Sroy }
2164ca00e00Sroy printf("\n");
2174ca00e00Sroy }
2184ca00e00Sroy
2194ca00e00Sroy static size_t
load_ents(TIENT * ents,TERMINAL * t,char type)2204ca00e00Sroy load_ents(TIENT *ents, TERMINAL *t, char type)
2214ca00e00Sroy {
2224ca00e00Sroy size_t i, n, max;
2234ca00e00Sroy TERMUSERDEF *ud;
2244ca00e00Sroy
2254ca00e00Sroy switch (type) {
2264ca00e00Sroy case 'f':
2274ca00e00Sroy max = TIFLAGMAX;
2284ca00e00Sroy break;
2294ca00e00Sroy case 'n':
2304ca00e00Sroy max = TINUMMAX;
2314ca00e00Sroy break;
2324ca00e00Sroy default:
2334ca00e00Sroy max = TISTRMAX;
2344ca00e00Sroy }
2354ca00e00Sroy
2364ca00e00Sroy n = 0;
2374ca00e00Sroy for (i = 0; i <= max; i++) {
2384ca00e00Sroy switch (type) {
2394ca00e00Sroy case 'f':
2404ca00e00Sroy if (t->flags[i] == 1 ||
2415f630912Sroy (aflag && t->flags[i] == CANCELLED_BOOLEAN))
2424ca00e00Sroy {
2434ca00e00Sroy ents[n].id = _ti_flagid(i);
2444ca00e00Sroy ents[n].type = 'f';
2454ca00e00Sroy ents[n++].flag = t->flags[i];
2464ca00e00Sroy }
2474ca00e00Sroy break;
2484ca00e00Sroy case 'n':
2494ca00e00Sroy if (VALID_NUMERIC(t->nums[i]) ||
2505f630912Sroy (aflag && t->nums[i] == CANCELLED_NUMERIC))
2514ca00e00Sroy {
2524ca00e00Sroy ents[n].id = _ti_numid(i);
2534ca00e00Sroy ents[n].type = 'n';
2544ca00e00Sroy ents[n++].num = t->nums[i];
2554ca00e00Sroy }
2564ca00e00Sroy break;
2574ca00e00Sroy default:
2584ca00e00Sroy if (VALID_STRING(t->strs[i]) ||
2595f630912Sroy (aflag && t->strs[i] == CANCELLED_STRING))
2604ca00e00Sroy {
2614ca00e00Sroy ents[n].id = _ti_strid(i);
2624ca00e00Sroy ents[n].type = 's';
2634ca00e00Sroy ents[n++].str = t->strs[i];
2644ca00e00Sroy }
2654ca00e00Sroy break;
2664ca00e00Sroy }
2674ca00e00Sroy }
2684ca00e00Sroy
2694ca00e00Sroy if (xflag != 0 && t->_nuserdefs != 0) {
2704ca00e00Sroy for (i = 0; i < t->_nuserdefs; i++) {
2714ca00e00Sroy ud = &t->_userdefs[i];
2724ca00e00Sroy if (ud->type == type) {
2734ca00e00Sroy switch (type) {
2744ca00e00Sroy case 'f':
2755f630912Sroy if (!aflag &&
2764ca00e00Sroy !VALID_BOOLEAN(ud->flag))
2774ca00e00Sroy continue;
2784ca00e00Sroy break;
2794ca00e00Sroy case 'n':
2805f630912Sroy if (!aflag &&
2814ca00e00Sroy !VALID_NUMERIC(ud->num))
2824ca00e00Sroy continue;
2834ca00e00Sroy break;
2844ca00e00Sroy case 's':
2855f630912Sroy if (!aflag &&
2864ca00e00Sroy !VALID_STRING(ud->str))
2874ca00e00Sroy continue;
2884ca00e00Sroy break;
2894ca00e00Sroy }
2904ca00e00Sroy ents[n].id = ud->id;
2914ca00e00Sroy ents[n].type = ud->type;
2924ca00e00Sroy ents[n].flag = ud->flag;
2934ca00e00Sroy ents[n].num = ud->num;
2944ca00e00Sroy ents[n++].str = ud->str;
2954ca00e00Sroy }
2964ca00e00Sroy }
2974ca00e00Sroy }
2984ca00e00Sroy
2994ca00e00Sroy qsort(ents, n, sizeof(TIENT), ent_compare);
3004ca00e00Sroy return n;
3014ca00e00Sroy }
3024ca00e00Sroy
3034ca00e00Sroy static void
cprint_ent(TIENT * ent)3044ca00e00Sroy cprint_ent(TIENT *ent)
3054ca00e00Sroy {
3064ca00e00Sroy
3074ca00e00Sroy if (ent == NULL) {
3084ca00e00Sroy if (qflag == 0)
3094ca00e00Sroy printf("NULL");
3104ca00e00Sroy else
3114ca00e00Sroy printf("-");
3124ca00e00Sroy }
3134ca00e00Sroy
3144ca00e00Sroy switch (ent->type) {
3154ca00e00Sroy case 'f':
3164ca00e00Sroy if (VALID_BOOLEAN(ent->flag))
3174ca00e00Sroy printf(ent->flag == 1 ? "T" : "F");
3184ca00e00Sroy else if (qflag == 0)
3194ca00e00Sroy printf("F");
3204ca00e00Sroy else if (ent->flag == CANCELLED_BOOLEAN)
3214ca00e00Sroy printf("@");
3224ca00e00Sroy else
3234ca00e00Sroy printf("-");
3244ca00e00Sroy break;
3254ca00e00Sroy case 'n':
3264ca00e00Sroy if (VALID_NUMERIC(ent->num))
3274ca00e00Sroy printf("%d", ent->num);
3284ca00e00Sroy else if (qflag == 0)
3294ca00e00Sroy printf("NULL");
3304ca00e00Sroy else if (ent->num == CANCELLED_NUMERIC)
3314ca00e00Sroy printf("@");
3324ca00e00Sroy else
3334ca00e00Sroy printf("-");
3344ca00e00Sroy break;
3354ca00e00Sroy case 's':
3364ca00e00Sroy if (VALID_STRING(ent->str)) {
3374ca00e00Sroy printf("'");
3384ca00e00Sroy outstr(stdout, ent->str);
3394ca00e00Sroy printf("'");
3404ca00e00Sroy } else if (qflag == 0)
3414ca00e00Sroy printf("NULL");
3424ca00e00Sroy else if (ent->str == CANCELLED_STRING)
3434ca00e00Sroy printf("@");
3444ca00e00Sroy else
3454ca00e00Sroy printf("-");
3464ca00e00Sroy break;
3474ca00e00Sroy }
3484ca00e00Sroy }
3494ca00e00Sroy
3504ca00e00Sroy static void
compare_ents(TIENT * ents1,size_t n1,TIENT * ents2,size_t n2)3514ca00e00Sroy compare_ents(TIENT *ents1, size_t n1, TIENT *ents2, size_t n2)
3524ca00e00Sroy {
3534ca00e00Sroy size_t i1, i2;
3544ca00e00Sroy TIENT *e1, *e2, ee;
3554ca00e00Sroy int c;
3564ca00e00Sroy
3574ca00e00Sroy i1 = i2 = 0;
3584ca00e00Sroy ee.type = 'f';
3594ca00e00Sroy ee.flag = ABSENT_BOOLEAN;
3604ca00e00Sroy ee.num = ABSENT_NUMERIC;
3614ca00e00Sroy ee.str = ABSENT_STRING;
3624ca00e00Sroy while (i1 != n1 || i2 != n2) {
3634ca00e00Sroy if (i1 == n1)
3644ca00e00Sroy c = 1;
3654ca00e00Sroy else if (i2 == n2)
3664ca00e00Sroy c = -1;
3674ca00e00Sroy else
3684ca00e00Sroy c = strcmp(ents1[i1].id, ents2[i2].id);
3694ca00e00Sroy if (c == 0) {
3704ca00e00Sroy e1 = &ents1[i1++];
3714ca00e00Sroy e2 = &ents2[i2++];
3724ca00e00Sroy } else if (c < 0) {
3734ca00e00Sroy e1 = &ents1[i1++];
3744ca00e00Sroy e2 = ⅇ
3754ca00e00Sroy ee.id = e1->id;
3764ca00e00Sroy ee.type = e1->type;
3774ca00e00Sroy } else {
3784ca00e00Sroy e1 = ⅇ
3794ca00e00Sroy e2 = &ents2[i2++];
3804ca00e00Sroy ee.id = e2->id;
3814ca00e00Sroy ee.type = e2->type;
3824ca00e00Sroy }
3834ca00e00Sroy switch (e1->type) {
3844ca00e00Sroy case 'f':
3854ca00e00Sroy if (cflag != 0) {
3864ca00e00Sroy if (e1->flag == e2->flag)
3874ca00e00Sroy printf("\t%s\n", ents1[i1].id);
3884ca00e00Sroy continue;
3894ca00e00Sroy }
3904ca00e00Sroy if (e1->flag == e2->flag)
3914ca00e00Sroy continue;
3924ca00e00Sroy break;
3934ca00e00Sroy case 'n':
3944ca00e00Sroy if (cflag != 0) {
3954ca00e00Sroy if (e1->num == e2->num)
3964ca00e00Sroy printf("\t%s#%d\n",
3974ca00e00Sroy ents1[i1].id, ents1[i1].num);
3984ca00e00Sroy continue;
3994ca00e00Sroy }
4004ca00e00Sroy if (e1->num == e2->num)
4014ca00e00Sroy continue;
4024ca00e00Sroy break;
4034ca00e00Sroy case 's':
4044ca00e00Sroy if (cflag != 0) {
4054ca00e00Sroy if (VALID_STRING(e1->str) &&
4064ca00e00Sroy VALID_STRING(e2->str) &&
4074ca00e00Sroy strcmp(e1->str, e2->str) == 0) {
4084ca00e00Sroy printf("\t%s=", ents1[i1].id);
4094ca00e00Sroy outstr(stdout, ents1[i1].str);
4104ca00e00Sroy printf("\n");
4114ca00e00Sroy }
4124ca00e00Sroy continue;
4134ca00e00Sroy }
4144ca00e00Sroy if (VALID_STRING(e1->str) &&
4154ca00e00Sroy VALID_STRING(e2->str) &&
4164ca00e00Sroy strcmp(e1->str, e2->str) == 0)
4174ca00e00Sroy continue;
4184ca00e00Sroy break;
4194ca00e00Sroy }
4204ca00e00Sroy printf("\t%s: ", e1->id);
4214ca00e00Sroy cprint_ent(e1);
4224ca00e00Sroy if (e1->type == 'f')
4234ca00e00Sroy printf(":");
4244ca00e00Sroy else
4254ca00e00Sroy printf(", ");
4264ca00e00Sroy cprint_ent(e2);
4274ca00e00Sroy printf(".\n");
4284ca00e00Sroy }
4294ca00e00Sroy }
4304ca00e00Sroy
4314ca00e00Sroy static TERMINAL *
load_term(const char * name)4324ca00e00Sroy load_term(const char *name)
4334ca00e00Sroy {
4344ca00e00Sroy TERMINAL *t;
4354ca00e00Sroy
4360fca9bd2Schristos t = ecalloc(1, sizeof(*t));
4374ca00e00Sroy if (name == NULL)
4384ca00e00Sroy name = getenv("TERM");
4394ca00e00Sroy if (name == NULL)
4404ca00e00Sroy name = "dumb";
4415176b197Sroy if (_ti_getterm(t, name, 1) == 1)
4424ca00e00Sroy return t;
4435176b197Sroy
4445176b197Sroy if (_ti_database == NULL)
445c33983b9Sroy errx(EXIT_FAILURE,
446c33983b9Sroy "no terminal definition found in internal database");
4475176b197Sroy else
448c33983b9Sroy errx(EXIT_FAILURE,
449c33983b9Sroy "no terminal definition found in %s.db", _ti_database);
4504ca00e00Sroy }
4514ca00e00Sroy
4524ca00e00Sroy static void
show_missing(TERMINAL * t1,TERMINAL * t2,char type)4534ca00e00Sroy show_missing(TERMINAL *t1, TERMINAL *t2, char type)
4544ca00e00Sroy {
4554ca00e00Sroy ssize_t i, max;
4564ca00e00Sroy const char *id;
4574ca00e00Sroy
4584ca00e00Sroy switch (type) {
4594ca00e00Sroy case 'f':
4604ca00e00Sroy max = TIFLAGMAX;
4614ca00e00Sroy break;
4624ca00e00Sroy case 'n':
4634ca00e00Sroy max = TINUMMAX;
4644ca00e00Sroy break;
4654ca00e00Sroy default:
4664ca00e00Sroy max = TISTRMAX;
4674ca00e00Sroy }
4684ca00e00Sroy
4694ca00e00Sroy for (i = 0; i <= max; i++) {
4704ca00e00Sroy switch (type) {
4714ca00e00Sroy case 'f':
4724ca00e00Sroy if (t1->flags[i] != ABSENT_BOOLEAN ||
4734ca00e00Sroy t2->flags[i] != ABSENT_BOOLEAN)
4744ca00e00Sroy continue;
4754ca00e00Sroy id = _ti_flagid(i);
4764ca00e00Sroy break;
4774ca00e00Sroy case 'n':
4784ca00e00Sroy if (t1->nums[i] != ABSENT_NUMERIC ||
4794ca00e00Sroy t2->nums[i] != ABSENT_NUMERIC)
4804ca00e00Sroy continue;
4814ca00e00Sroy id = _ti_numid(i);
4824ca00e00Sroy break;
4834ca00e00Sroy default:
4844ca00e00Sroy if (t1->strs[i] != ABSENT_STRING ||
4854ca00e00Sroy t2->strs[i] != ABSENT_STRING)
4864ca00e00Sroy continue;
4874ca00e00Sroy id = _ti_strid(i);
4884ca00e00Sroy break;
4894ca00e00Sroy }
4904ca00e00Sroy printf("\t!%s.\n", id);
4914ca00e00Sroy }
4924ca00e00Sroy }
4934ca00e00Sroy
4944ca00e00Sroy static TERMUSERDEF *
find_userdef(TERMINAL * term,const char * id)4954ca00e00Sroy find_userdef(TERMINAL *term, const char *id)
4964ca00e00Sroy {
4974ca00e00Sroy size_t i;
4984ca00e00Sroy
4994ca00e00Sroy for (i = 0; i < term->_nuserdefs; i++)
5004ca00e00Sroy if (strcmp(term->_userdefs[i].id, id) == 0)
5014ca00e00Sroy return &term->_userdefs[i];
5024ca00e00Sroy return NULL;
5034ca00e00Sroy }
5044ca00e00Sroy
5054ca00e00Sroy static void
use_terms(TERMINAL * term,size_t nuse,char ** uterms)5064ca00e00Sroy use_terms(TERMINAL *term, size_t nuse, char **uterms)
5074ca00e00Sroy {
5084ca00e00Sroy TERMINAL **terms;
5094ca00e00Sroy TERMUSERDEF *ud, *tud;
5104ca00e00Sroy size_t i, j, agree, absent, data;
5114ca00e00Sroy
51243ed6275Schristos terms = ecalloc(nuse, sizeof(*terms));
5134ca00e00Sroy for (i = 0; i < nuse; i++) {
5144ca00e00Sroy if (strcmp(term->name, *uterms) == 0)
5150fca9bd2Schristos errx(EXIT_FAILURE, "cannot use same terminal");
5164ca00e00Sroy for (j = 0; j < i; j++)
5174ca00e00Sroy if (strcmp(terms[j]->name, *uterms) == 0)
5180fca9bd2Schristos errx(EXIT_FAILURE, "cannot use same terminal");
5194ca00e00Sroy terms[i] = load_term(*uterms++);
5204ca00e00Sroy }
5214ca00e00Sroy
5224ca00e00Sroy for (i = 0; i < TIFLAGMAX + 1; i++) {
5234ca00e00Sroy agree = absent = data = 0;
5244ca00e00Sroy for (j = 0; j < nuse; j++) {
5254ca00e00Sroy if (terms[j]->flags[i] == ABSENT_BOOLEAN ||
5264ca00e00Sroy terms[j]->flags[i] == CANCELLED_BOOLEAN)
5274ca00e00Sroy absent++;
5284ca00e00Sroy else {
5294ca00e00Sroy data++;
5304ca00e00Sroy if (term->flags[i] == terms[j]->flags[i])
5314ca00e00Sroy agree++;
5324ca00e00Sroy }
5334ca00e00Sroy }
5344ca00e00Sroy if (data == 0)
5354ca00e00Sroy continue;
5364ca00e00Sroy if (agree > 0 && agree + absent == nuse)
5374ca00e00Sroy term->flags[i] = ABSENT_BOOLEAN;
5384ca00e00Sroy else if (term->flags[i] == ABSENT_BOOLEAN)
5394ca00e00Sroy term->flags[i] = CANCELLED_BOOLEAN;
5404ca00e00Sroy }
5414ca00e00Sroy
5424ca00e00Sroy for (i = 0; i < TINUMMAX + 1; i++) {
5434ca00e00Sroy agree = absent = data = 0;
5444ca00e00Sroy for (j = 0; j < nuse; j++) {
5454ca00e00Sroy if (terms[j]->nums[i] == ABSENT_NUMERIC ||
5464ca00e00Sroy terms[j]->nums[i] == CANCELLED_NUMERIC)
5474ca00e00Sroy absent++;
5484ca00e00Sroy else {
5494ca00e00Sroy data++;
5504ca00e00Sroy if (term->nums[i] == terms[j]->nums[i])
5514ca00e00Sroy agree++;
5524ca00e00Sroy }
5534ca00e00Sroy }
5544ca00e00Sroy if (data == 0)
5554ca00e00Sroy continue;
5564ca00e00Sroy if (agree > 0 && agree + absent == nuse)
5574ca00e00Sroy term->nums[i] = ABSENT_NUMERIC;
5584ca00e00Sroy else if (term->nums[i] == ABSENT_NUMERIC)
5594ca00e00Sroy term->nums[i] = CANCELLED_NUMERIC;
5604ca00e00Sroy }
5614ca00e00Sroy
5624ca00e00Sroy for (i = 0; i < TISTRMAX + 1; i++) {
5634ca00e00Sroy agree = absent = data = 0;
5644ca00e00Sroy for (j = 0; j < nuse; j++) {
5654ca00e00Sroy if (terms[j]->strs[i] == ABSENT_STRING ||
5664ca00e00Sroy terms[j]->strs[i] == CANCELLED_STRING)
5674ca00e00Sroy absent++;
5684ca00e00Sroy else {
5694ca00e00Sroy data++;
5704ca00e00Sroy if (VALID_STRING(term->strs[i]) &&
5714ca00e00Sroy strcmp(term->strs[i],
5724ca00e00Sroy terms[j]->strs[i]) == 0)
5734ca00e00Sroy agree++;
5744ca00e00Sroy }
5754ca00e00Sroy }
5764ca00e00Sroy if (data == 0)
5774ca00e00Sroy continue;
5784ca00e00Sroy if (agree > 0 && agree + absent == nuse)
5794ca00e00Sroy term->strs[i] = ABSENT_STRING;
5804ca00e00Sroy else if (term->strs[i] == ABSENT_STRING)
5814ca00e00Sroy term->strs[i] = CANCELLED_STRING;
5824ca00e00Sroy }
5834ca00e00Sroy
5844ca00e00Sroy /* User defined caps are more tricky.
5854ca00e00Sroy First we set any to absent that agree. */
5864ca00e00Sroy for (i = 0; i < term->_nuserdefs; i++) {
5874ca00e00Sroy agree = absent = data = 0;
5884ca00e00Sroy ud = &term->_userdefs[i];
5894ca00e00Sroy for (j = 0; j < nuse; j++) {
5904ca00e00Sroy tud = find_userdef(terms[j], ud->id);
5914ca00e00Sroy if (tud == NULL)
5924ca00e00Sroy absent++;
5934ca00e00Sroy else {
5944ca00e00Sroy data++;
5954ca00e00Sroy switch (ud->type) {
5964ca00e00Sroy case 'f':
5974ca00e00Sroy if (tud->type == 'f' &&
5984ca00e00Sroy tud->flag == ud->flag)
5994ca00e00Sroy agree++;
6004ca00e00Sroy break;
6014ca00e00Sroy case 'n':
6024ca00e00Sroy if (tud->type == 'n' &&
6034ca00e00Sroy tud->num == ud->num)
6044ca00e00Sroy agree++;
6054ca00e00Sroy break;
6064ca00e00Sroy case 's':
6074ca00e00Sroy if (tud->type == 's' &&
6084ca00e00Sroy VALID_STRING(tud->str) &&
6094ca00e00Sroy VALID_STRING(ud->str) &&
6104ca00e00Sroy strcmp(ud->str, tud->str) == 0)
6114ca00e00Sroy agree++;
6124ca00e00Sroy break;
6134ca00e00Sroy }
6144ca00e00Sroy }
6154ca00e00Sroy }
6164ca00e00Sroy if (data == 0)
6174ca00e00Sroy continue;
6184ca00e00Sroy if (agree > 0 && agree + absent == nuse) {
6194ca00e00Sroy ud->flag = ABSENT_BOOLEAN;
6204ca00e00Sroy ud->num = ABSENT_NUMERIC;
6214ca00e00Sroy ud->str = ABSENT_STRING;
6224ca00e00Sroy }
6234ca00e00Sroy }
6244ca00e00Sroy
6254ca00e00Sroy /* Now add any that we don't have as cancelled */
6264ca00e00Sroy for (i = 0; i < nuse; i++) {
6274ca00e00Sroy for (j = 0; j < terms[i]->_nuserdefs; j++) {
6284ca00e00Sroy ud = find_userdef(term, terms[i]->_userdefs[j].id);
6294ca00e00Sroy if (ud != NULL)
6304ca00e00Sroy continue; /* We have handled this */
6310fca9bd2Schristos term->_userdefs = erealloc(term->_userdefs,
6324ca00e00Sroy sizeof(*term->_userdefs) * (term->_nuserdefs + 1));
6334ca00e00Sroy tud = &term->_userdefs[term->_nuserdefs++];
6344ca00e00Sroy tud->id = terms[i]->_userdefs[j].id;
6354ca00e00Sroy tud->type = terms[i]->_userdefs[j].flag;
6364ca00e00Sroy tud->flag = CANCELLED_BOOLEAN;
6374ca00e00Sroy tud->num = CANCELLED_NUMERIC;
6384ca00e00Sroy tud->str = CANCELLED_STRING;
6394ca00e00Sroy }
6404ca00e00Sroy }
6414ca00e00Sroy }
6424ca00e00Sroy
6434ca00e00Sroy int
main(int argc,char ** argv)6444ca00e00Sroy main(int argc, char **argv)
6454ca00e00Sroy {
6464ca00e00Sroy char *term, *Barg;
6474ca00e00Sroy int ch, uflag;
6484ca00e00Sroy TERMINAL *t, *t2;
6494ca00e00Sroy size_t n, n2;
6504ca00e00Sroy struct winsize ws;
6514ca00e00Sroy TIENT ents[TISTRMAX + 1], ents2[TISTRMAX + 1];
6524ca00e00Sroy
6534ca00e00Sroy cols = 80; /* default */
6544ca00e00Sroy term = getenv("COLUMNS");
6554ca00e00Sroy if (term != NULL)
6564ca00e00Sroy cols = strtoul(term, NULL, 10);
6574ca00e00Sroy else if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == 0)
6584ca00e00Sroy cols = ws.ws_col;
6594ca00e00Sroy
6604ca00e00Sroy uflag = xflag = 0;
6614ca00e00Sroy Barg = NULL;
6624ca00e00Sroy while ((ch = getopt(argc, argv, "1A:B:acnquw:x")) != -1)
6634ca00e00Sroy switch (ch) {
6644ca00e00Sroy case '1':
6654ca00e00Sroy cols = 1;
6664ca00e00Sroy break;
6674ca00e00Sroy case 'A':
6684ca00e00Sroy setdb(optarg);
6694ca00e00Sroy break;
6704ca00e00Sroy case 'B':
6714ca00e00Sroy Barg = optarg;
6724ca00e00Sroy break;
6734ca00e00Sroy case 'a':
6745f630912Sroy aflag = 1;
6754ca00e00Sroy break;
6764ca00e00Sroy case 'c':
6775f630912Sroy cflag = 1;
6784ca00e00Sroy break;
6794ca00e00Sroy case 'n':
6805f630912Sroy nflag = 1;
6814ca00e00Sroy break;
6824ca00e00Sroy case 'q':
6835f630912Sroy qflag = 1;
6844ca00e00Sroy break;
6854ca00e00Sroy case 'u':
6865f630912Sroy uflag = 1;
6875f630912Sroy aflag = 1;
6884ca00e00Sroy break;
6894ca00e00Sroy case 'w':
6904ca00e00Sroy cols = strtoul(optarg, NULL, 10);
6914ca00e00Sroy break;
6924ca00e00Sroy case 'x':
6935f630912Sroy xflag = 1;
6944ca00e00Sroy break;
6954ca00e00Sroy case '?':
6964ca00e00Sroy default:
6974ca00e00Sroy fprintf(stderr,
6984ca00e00Sroy "usage: %s [-1acnqux] [-A database] [-B database] "
6994ca00e00Sroy "[-w cols] [term]\n",
7004ca00e00Sroy getprogname());
7014ca00e00Sroy return EXIT_FAILURE;
7024ca00e00Sroy }
7034ca00e00Sroy cols--;
7044ca00e00Sroy
7054ca00e00Sroy if (optind + 1 < argc)
7065f630912Sroy aflag = 1;
7074ca00e00Sroy
7084ca00e00Sroy if (optind < argc)
7094ca00e00Sroy term = argv[optind++];
7104ca00e00Sroy else
7114ca00e00Sroy term = NULL;
7124ca00e00Sroy t = load_term(term);
7134ca00e00Sroy
7144ca00e00Sroy if (uflag != 0)
7154ca00e00Sroy use_terms(t, argc - optind, argv + optind);
7164ca00e00Sroy
7174ca00e00Sroy if ((optind + 1 != argc && nflag == 0) || uflag != 0) {
718f5e0f030Sroy if (uflag == 0)
719f5e0f030Sroy printf("# Reconstructed from %s\n",
720f5e0f030Sroy _ti_database == NULL ?
721f5e0f030Sroy "internal database" : _ti_database);
722a46bbbf6Sroy /* Strip internal versioning */
723a46bbbf6Sroy term = strchr(t->name, TERMINFO_VDELIM);
724a46bbbf6Sroy if (term != NULL)
725a46bbbf6Sroy *term = '\0';
7264ca00e00Sroy printf("%s", t->name);
727*fe2a18efSroy if (t->_alias != NULL) {
728*fe2a18efSroy char *alias, *aliascpy, *delim;
729*fe2a18efSroy
730cd83b487Sroy alias = aliascpy = estrdup(t->_alias);
731cd83b487Sroy while (alias != NULL && *alias != '\0') {
732cd83b487Sroy putchar('|');
733cd83b487Sroy delim = strchr(alias, TERMINFO_VDELIM);
734cd83b487Sroy if (delim != NULL)
735cd83b487Sroy *delim++ = '\0';
736cd83b487Sroy printf("%s", alias);
737cd83b487Sroy if (delim != NULL) {
738cd83b487Sroy while (*delim != '\0' && *delim != '|')
739cd83b487Sroy delim++;
740cd83b487Sroy if (*delim == '\0')
741cd83b487Sroy alias = NULL;
742cd83b487Sroy else
743cd83b487Sroy alias = delim + 1;
744cd83b487Sroy } else
745cd83b487Sroy alias = NULL;
746cd83b487Sroy }
747cd83b487Sroy free(aliascpy);
748*fe2a18efSroy }
7494ca00e00Sroy if (t->desc != NULL && *t->desc != '\0')
7504ca00e00Sroy printf("|%s", t->desc);
7514ca00e00Sroy printf(",\n");
7524ca00e00Sroy
7534ca00e00Sroy n = load_ents(ents, t, 'f');
7544ca00e00Sroy print_ent(ents, n);
7554ca00e00Sroy n = load_ents(ents, t, 'n');
7564ca00e00Sroy print_ent(ents, n);
7574ca00e00Sroy n = load_ents(ents, t, 's');
7584ca00e00Sroy print_ent(ents, n);
7594ca00e00Sroy
7604ca00e00Sroy if (uflag != 0) {
7614ca00e00Sroy printf("\t");
7624ca00e00Sroy n = SW;
7634ca00e00Sroy for (; optind < argc; optind++) {
7644ca00e00Sroy n2 = 5 + strlen(argv[optind]);
7654ca00e00Sroy if (n != SW) {
7664ca00e00Sroy if (n + n2 > cols) {
7674ca00e00Sroy printf("\n\t");
7684ca00e00Sroy n = SW;
7694ca00e00Sroy } else
7704ca00e00Sroy n += printf(" ");
7714ca00e00Sroy }
7724ca00e00Sroy n += printf("use=%s,", argv[optind]);
7734ca00e00Sroy }
7744ca00e00Sroy printf("\n");
7754ca00e00Sroy }
7764ca00e00Sroy return EXIT_SUCCESS;
7774ca00e00Sroy }
7784ca00e00Sroy
7794ca00e00Sroy if (Barg == NULL)
7804ca00e00Sroy unsetenv("TERMINFO");
7814ca00e00Sroy else
7824ca00e00Sroy setdb(Barg);
7834ca00e00Sroy t2 = load_term(argv[optind++]);
7844ca00e00Sroy printf("comparing %s to %s.\n", t->name, t2->name);
7854ca00e00Sroy if (qflag == 0)
7864ca00e00Sroy printf(" comparing booleans.\n");
7874ca00e00Sroy if (nflag == 0) {
7884ca00e00Sroy n = load_ents(ents, t, 'f');
7894ca00e00Sroy n2 = load_ents(ents2, t2, 'f');
7904ca00e00Sroy compare_ents(ents, n, ents2, n2);
7914ca00e00Sroy } else
7924ca00e00Sroy show_missing(t, t2, 'f');
7934ca00e00Sroy if (qflag == 0)
7944ca00e00Sroy printf(" comparing numbers.\n");
7954ca00e00Sroy if (nflag == 0) {
7964ca00e00Sroy n = load_ents(ents, t, 'n');
7974ca00e00Sroy n2 = load_ents(ents2, t2, 'n');
7984ca00e00Sroy compare_ents(ents, n, ents2, n2);
7994ca00e00Sroy } else
8004ca00e00Sroy show_missing(t, t2, 'n');
8014ca00e00Sroy if (qflag == 0)
8024ca00e00Sroy printf(" comparing strings.\n");
8034ca00e00Sroy if (nflag == 0) {
8044ca00e00Sroy n = load_ents(ents, t, 's');
8054ca00e00Sroy n2 = load_ents(ents2, t2, 's');
8064ca00e00Sroy compare_ents(ents, n, ents2, n2);
8074ca00e00Sroy } else
8084ca00e00Sroy show_missing(t, t2, 's');
8094ca00e00Sroy return EXIT_SUCCESS;
8104ca00e00Sroy }
811