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