1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* Copyright (c) 1988 AT&T */ 23 /* All Rights Reserved */ 24 25 26 /* 27 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 28 * Use is subject to license terms. 29 * 30 * Copyright (c) 2019, Joyent, Inc. 31 */ 32 33 /* 34 NAME 35 infocmp - compare terminfo descriptions, or dump a terminfo 36 description 37 38 AUTHOR 39 Tony Hansen, February 23, 1984. 40 */ 41 42 #include "curses.h" 43 #include "term.h" 44 #include "print.h" 45 #include <fcntl.h> 46 #include <stdlib.h> 47 48 /* externs from libcurses */ 49 extern char *boolnames[]; 50 extern char *boolcodes[]; 51 extern char *boolfnames[]; 52 extern char *numnames[]; 53 extern char *numcodes[]; 54 extern char *numfnames[]; 55 extern char *strnames[]; 56 extern char *strcodes[]; 57 extern char *strfnames[]; 58 extern char ttytype[]; 59 extern int tgetflag(); 60 extern int tgetnum(); 61 extern char *tgetstr(); 62 63 /* externs from libc */ 64 extern void exit(); 65 extern void qsort(); 66 extern char *getenv(); 67 extern int getopt(); 68 extern int optind; 69 extern char *optarg; 70 extern char *strncpy(), *strcpy(); 71 extern int strcmp(), strlen(); 72 73 /* data structures for this program */ 74 75 struct boolstruct { 76 char *infoname; /* the terminfo capability name */ 77 char *capname; /* the termcap capability name */ 78 char *fullname; /* the long C variable name */ 79 char *secondname; /* the use= terminal w/ this value */ 80 char val; /* the value */ 81 char secondval; /* the value in the use= terminal */ 82 char changed; /* a use= terminal changed the value */ 83 char seenagain; /* a use= terminal had this entry */ 84 }; 85 86 struct numstruct { 87 char *infoname; /* ditto from above */ 88 char *capname; 89 char *fullname; 90 char *secondname; 91 short val; 92 short secondval; 93 char changed; 94 char seenagain; 95 }; 96 97 struct strstruct { 98 char *infoname; /* ditto from above */ 99 char *capname; 100 char *fullname; 101 char *secondname; 102 char *val; 103 char *secondval; 104 char changed; 105 char seenagain; 106 }; 107 108 /* globals for this file */ 109 char *progname; /* argv[0], the name of the program */ 110 static struct boolstruct *ibool; /* array of char information */ 111 static struct numstruct *num; /* array of number information */ 112 static struct strstruct *str; /* array of string information */ 113 static char *used; /* usage statistics */ 114 static int numbools; /* how many booleans there are */ 115 static int numnums; /* how many numbers there are */ 116 static int numstrs; /* how many strings there are */ 117 #define TTYLEN 255 118 static char *firstterm; /* the name of the first terminal */ 119 static char *savettytype; /* the synonyms of the first terminal */ 120 static char _savettytype[TTYLEN+1]; /* the place to save those names */ 121 static int devnull; /* open("/dev/null") for setupterm */ 122 #define trace stderr /* send trace messages to stderr */ 123 124 /* options */ 125 static int verbose = 0; /* debugging printing level */ 126 static int diff = 0; /* produce diff listing, the default */ 127 static int common = 0; /* produce common listing */ 128 static int neither = 0; /* list caps in neither entry */ 129 static int use = 0; /* produce use= comparison listing */ 130 static enum printtypes printing /* doing any of above printing at all */ 131 = pr_none; 132 enum { none, by_database, by_terminfo, by_longnames, by_cap } 133 sortorder = none; /* sort the fields for printing */ 134 static char *term1info, *term2info; /* $TERMINFO settings */ 135 static int Aflag = 0, Bflag = 0; /* $TERMINFO was set with -A/-B */ 136 137 #define EQUAL(s1, s2) (((s1 == NULL) && (s2 == NULL)) || \ 138 ((s1 != NULL) && (s2 != NULL) && \ 139 (strcmp(s1, s2) == 0))) 140 141 static void sortnames(); 142 int numcompare(const void *, const void *); 143 int boolcompare(const void *, const void *); 144 int strcompare(const void *, const void *); 145 static void check_nth_terminal(char *, int); 146 147 void 148 badmalloc() 149 { 150 (void) fprintf(stderr, "%s: malloc is out of space!\n", progname); 151 exit(-1); 152 } 153 154 /* 155 Allocate and initialize the global data structures and variables. 156 */ 157 void 158 allocvariables(int argc, int firstoptind) 159 { 160 register int i, nullseen; 161 162 /* find out how many names we are dealing with */ 163 for (numbools = 0; boolnames[numbools]; numbools++) 164 ; 165 for (numnums = 0; numnames[numnums]; numnums++) 166 ; 167 for (numstrs = 0; strnames[numstrs]; numstrs++) 168 ; 169 170 if (verbose) { 171 (void) fprintf(trace, "There are %d boolean capabilities.\n", 172 numbools); 173 (void) fprintf(trace, "There are %d numeric capabilities.\n", 174 numnums); 175 (void) fprintf(trace, "There are %d string capabilities.\n", 176 numstrs); 177 } 178 179 /* Allocate storage for the names and their values */ 180 ibool = (struct boolstruct *) malloc((unsigned) numbools * 181 sizeof (struct boolstruct)); 182 num = (struct numstruct *) malloc((unsigned) numnums * 183 sizeof (struct numstruct)); 184 str = (struct strstruct *) malloc((unsigned) numstrs * 185 sizeof (struct strstruct)); 186 187 /* Allocate array to keep track of which names have been used. */ 188 if (use) { 189 used = (char *) malloc((unsigned) (argc - firstoptind) * 190 sizeof (char)); 191 } 192 193 if ((ibool == NULL) || (num == NULL) || (str == NULL) || 194 (use && (used == NULL))) 195 badmalloc(); 196 197 /* Fill in the names and initialize the structures. */ 198 nullseen = FALSE; 199 for (i = 0; i < numbools; i++) { 200 ibool[i].infoname = boolnames[i]; 201 ibool[i].capname = boolcodes[i]; 202 /* This is necessary until fnames.c is */ 203 /* incorporated into standard curses. */ 204 if (nullseen || (boolfnames[i] == NULL)) { 205 ibool[i].fullname = "unknown_boolean"; 206 nullseen = TRUE; 207 } else { 208 ibool[i].fullname = boolfnames[i]; 209 } 210 ibool[i].changed = FALSE; 211 ibool[i].seenagain = FALSE; 212 } 213 nullseen = 0; 214 for (i = 0; i < numnums; i++) { 215 num[i].infoname = numnames[i]; 216 num[i].capname = numcodes[i]; 217 if (nullseen || (numfnames[i] == NULL)) { 218 ibool[i].fullname = "unknown_number"; 219 nullseen = TRUE; 220 } else { 221 num[i].fullname = numfnames[i]; 222 } 223 num[i].changed = FALSE; 224 num[i].seenagain = FALSE; 225 } 226 nullseen = 0; 227 for (i = 0; i < numstrs; i++) { 228 str[i].infoname = strnames[i]; 229 str[i].capname = strcodes[i]; 230 if (nullseen || (strfnames[i] == NULL)) { 231 str[i].fullname = "unknown_string"; 232 nullseen = TRUE; 233 } else { 234 str[i].fullname = strfnames[i]; 235 } 236 str[i].changed = FALSE; 237 str[i].seenagain = FALSE; 238 } 239 } 240 241 /* 242 Routines to be passed to qsort(3) for comparison of the structures. 243 */ 244 int 245 boolcompare(const void *x, const void *y) 246 { 247 struct boolstruct *a; 248 struct boolstruct *b; 249 250 a = (struct boolstruct *)x; 251 b = (struct boolstruct *)y; 252 253 switch ((int) sortorder) { 254 case (int) by_terminfo: 255 return (strcmp(a->infoname, b->infoname)); 256 case (int) by_cap: 257 return (strcmp(a->capname, b->capname)); 258 case (int) by_longnames: 259 return (strcmp(a->fullname, b->fullname)); 260 default: 261 return (0); 262 } 263 } 264 265 int 266 numcompare(const void *x, const void *y) 267 { 268 struct numstruct *a; 269 struct numstruct *b; 270 271 a = (struct numstruct *)x; 272 b = (struct numstruct *)y; 273 switch ((int) sortorder) { 274 case (int) by_terminfo: 275 return (strcmp(a->infoname, b->infoname)); 276 case (int) by_cap: 277 return (strcmp(a->capname, b->capname)); 278 case (int) by_longnames: 279 return (strcmp(a->fullname, b->fullname)); 280 default: 281 return (0); 282 } 283 } 284 285 int 286 strcompare(const void *x, const void *y) 287 { 288 struct strstruct *a; 289 struct strstruct *b; 290 291 a = (struct strstruct *)x; 292 b = (struct strstruct *)y; 293 294 switch ((int) sortorder) { 295 case (int) by_terminfo: 296 return (strcmp(a->infoname, b->infoname)); 297 case (int) by_cap: 298 return (strcmp(a->capname, b->capname)); 299 case (int) by_longnames: 300 return (strcmp(a->fullname, b->fullname)); 301 default: 302 return (0); 303 } 304 } 305 306 /* 307 Sort the entries by their terminfo name. 308 */ 309 static void 310 sortnames() 311 { 312 if (sortorder != by_database) { 313 qsort((char *) ibool, (unsigned) numbools, 314 sizeof (struct boolstruct), boolcompare); 315 qsort((char *) num, (unsigned) numnums, 316 sizeof (struct numstruct), numcompare); 317 qsort((char *) str, (unsigned) numstrs, 318 sizeof (struct strstruct), strcompare); 319 } 320 return; 321 } 322 323 /* 324 Print out a string, or "NULL" if it's not defined. 325 */ 326 void 327 PR(FILE *stream, char *string) 328 { 329 if (string == NULL) 330 (void) fprintf(stream, "NULL"); 331 else 332 tpr(stream, string); 333 } 334 335 /* 336 Output the 'ko' termcap string. This is a list of all of the input 337 keys that input the same thing as the corresponding output strings. 338 */ 339 int kncounter; 340 char kobuffer[512]; 341 342 char 343 *addko(char *output, char *input, char *koptr) 344 { 345 char *inptr, *outptr, padbuffer[512]; 346 inptr = tgetstr(input, (char **)0); 347 if (inptr == NULL) 348 return (koptr); 349 outptr = tgetstr(output, (char **)0); 350 if (outptr == NULL) 351 return (koptr); 352 outptr = rmpadding(outptr, padbuffer, (int *) 0); 353 if (strcmp(inptr, outptr) == 0) { 354 *koptr++ = *output++; 355 *koptr++ = *output++; 356 *koptr++ = ','; 357 kncounter++; 358 } 359 return (koptr); 360 } 361 362 void 363 setupknko() 364 { 365 char *koptr; 366 367 kncounter = 0; 368 koptr = kobuffer; 369 370 koptr = addko("bs", "kb", koptr); /* key_backspace */ 371 koptr = addko("bt", "kB", koptr); /* key_btab */ 372 koptr = addko("cl", "kC", koptr); /* key_clear */ 373 koptr = addko("le", "kl", koptr); /* key_left */ 374 koptr = addko("do", "kd", koptr); /* key_down */ 375 koptr = addko("nd", "kr", koptr); /* key_right */ 376 koptr = addko("up", "ku", koptr); /* key_up */ 377 koptr = addko("dc", "kD", koptr); /* key_dc */ 378 koptr = addko("dl", "kL", koptr); /* key_dl */ 379 koptr = addko("cd", "kS", koptr); /* key_eos */ 380 koptr = addko("ce", "kE", koptr); /* key_eol */ 381 koptr = addko("ho", "kh", koptr); /* key_home */ 382 koptr = addko("st", "kT", koptr); /* key_stab */ 383 koptr = addko("ic", "kI", koptr); /* key_ic */ 384 koptr = addko("im", "kI", koptr); /* key_ic */ 385 koptr = addko("al", "kA", koptr); /* key_il */ 386 koptr = addko("sf", "kF", koptr); /* key_sf */ 387 koptr = addko("ll", "kH", koptr); /* key_ll */ 388 koptr = addko("sr", "kR", koptr); /* key_sr */ 389 koptr = addko("ei", "kM", koptr); /* key_eic */ 390 koptr = addko("ct", "ka", koptr); /* key_catab */ 391 392 /* get rid of comma */ 393 if (koptr != kobuffer) 394 *(--koptr) = '\0'; 395 } 396 397 void 398 pr_kn() 399 { 400 if (kncounter > 0) 401 pr_number((char *)0, "kn", (char *)0, kncounter); 402 } 403 404 void 405 pr_ko() 406 { 407 if (kncounter > 0) 408 pr_string((char *)0, "ko", (char *)0, kobuffer); 409 } 410 411 void 412 pr_bcaps() 413 { 414 char *retptr; 415 char padbuffer[512]; 416 417 if (verbose) 418 (void) fprintf(trace, "looking at 'bs'\n"); 419 retptr = cconvert(rmpadding(cursor_left, padbuffer, (int *) 0)); 420 if (strcmp("\\b", retptr) == 0) 421 pr_boolean((char *)0, "bs", (char *)0, 1); 422 423 if (verbose) 424 (void) fprintf(trace, "looking at 'pt'\n"); 425 retptr = cconvert(rmpadding(tab, padbuffer, (int *) 0)); 426 if (strcmp("\\t", retptr) == 0) 427 pr_boolean((char *)0, "pt", (char *)0, 1); 428 429 if (verbose) 430 (void) fprintf(trace, "looking at 'nc'\n"); 431 retptr = cconvert(rmpadding(carriage_return, padbuffer, (int *) 0)); 432 if (strcmp("\\r", retptr) != 0) 433 pr_boolean((char *)0, "nc", (char *)0, 1); 434 435 if (verbose) 436 (void) fprintf(trace, "looking at 'ns'\n"); 437 if (scroll_forward == NULL) 438 pr_boolean((char *)0, "ns", (char *)0, 1); 439 440 /* Ignore "xr": Return acts like ce \r \n (Delta Data) */ 441 } 442 443 void 444 pr_ncaps() 445 { 446 char padbuffer[512]; 447 int padding; 448 449 if (verbose) 450 (void) fprintf(trace, "looking at 'ug'\n"); 451 /* Duplicate sg for ug: Number of blank chars left by us or ue */ 452 if (magic_cookie_glitch > -1) 453 pr_number((char *)0, "ug", (char *)0, magic_cookie_glitch); 454 455 if (verbose) 456 (void) fprintf(trace, "looking at 'dB'\n"); 457 /* Number of millisec of bs delay needed */ 458 (void) rmpadding(cursor_left, padbuffer, &padding); 459 if (padding > 0) 460 pr_number((char *)0, "dB", (char *)0, padding); 461 462 if (verbose) 463 (void) fprintf(trace, "looking at 'dC'\n"); 464 /* Number of millisec of cr delay needed */ 465 (void) rmpadding(carriage_return, padbuffer, &padding); 466 if (padding > 0) 467 pr_number((char *)0, "dC", (char *)0, padding); 468 469 if (verbose) 470 (void) fprintf(trace, "looking at 'dF'\n"); 471 /* Number of millisec of ff delay needed */ 472 (void) rmpadding(form_feed, padbuffer, &padding); 473 if (padding > 0) 474 pr_number((char *)0, "dF", (char *)0, padding); 475 476 if (verbose) 477 (void) fprintf(trace, "looking at 'dN'\n"); 478 /* Number of millisec of nl delay needed */ 479 (void) rmpadding(cursor_down, padbuffer, &padding); 480 if (padding > 0) 481 pr_number((char *)0, "dN", (char *)0, padding); 482 483 if (verbose) 484 (void) fprintf(trace, "looking at 'dT'\n"); 485 /* Number of millisec of tab delay needed */ 486 (void) rmpadding(tab, padbuffer, &padding); 487 if (padding > 0) 488 pr_number((char *)0, "dT", (char *)0, padding); 489 490 /* Handle "kn": Number of "other" keys */ 491 setupknko(); 492 pr_kn(); 493 } 494 495 void 496 pr_scaps() 497 { 498 char *retptr; 499 char padbuffer[512]; 500 501 /* Backspace if not "^H" */ 502 if (verbose) 503 (void) fprintf(trace, "looking at 'bc'\n"); 504 retptr = cconvert(rmpadding(cursor_left, padbuffer, (int *) 0)); 505 if (strcmp("\\b", retptr) != 0) 506 pr_string((char *)0, "bc", (char *)0, cursor_left); 507 508 /* Newline character (default "\n") */ 509 if (verbose) 510 (void) fprintf(trace, "looking at 'nl'\n"); 511 retptr = cconvert(rmpadding(cursor_down, padbuffer, (int *) 0)); 512 if (strcmp("\\n", retptr) != 0) 513 pr_string((char *)0, "nl", (char *)0, cursor_down); 514 515 /* Handle "ko" here: Termcap entries for other non-function keys */ 516 pr_ko(); 517 518 /* Ignore "ma": Arrow key map, used by vi version 2 only */ 519 } 520 521 /* 522 Set up the first terminal and save the values from it. 523 */ 524 void 525 initfirstterm(char *term) 526 { 527 register int i; 528 529 if (verbose) { 530 (void) fprintf(trace, "setting up terminal type '%s'.\n", 531 term); 532 } 533 534 (void) setupterm(term, devnull, (int *) 0); 535 536 /* Save the name for later use. */ 537 if (use) { 538 register unsigned int length; 539 savettytype = _savettytype; 540 if ((length = strlen(ttytype)) >= TTYLEN) { 541 savettytype = malloc(length); 542 if (savettytype == NULL) { 543 (void) fprintf(stderr, "%s: malloc is out " 544 "of space\n", progname); 545 (void) strncpy(_savettytype, ttytype, 546 TTYLEN-1); 547 _savettytype[TTYLEN] = '\0'; 548 savettytype = _savettytype; 549 } 550 } else { 551 (void) strcpy(_savettytype, ttytype); 552 } 553 } 554 555 if (printing != pr_none) { 556 pr_heading(term, ttytype); 557 pr_bheading(); 558 } 559 560 /* Save the values for the first terminal. */ 561 for (i = 0; i < numbools; i++) { 562 if ((ibool[i].val = tgetflag(ibool[i].capname)) && 563 printing != pr_none) { 564 pr_boolean(ibool[i].infoname, ibool[i].capname, 565 ibool[i].fullname, 1); 566 } 567 568 if (verbose) { 569 (void) fprintf(trace, "%s=%d.\n", ibool[i].infoname, 570 ibool[i].val); 571 } 572 } 573 574 if (printing != pr_none) { 575 if (printing == pr_cap) 576 pr_bcaps(); 577 pr_bfooting(); 578 pr_nheading(); 579 } 580 581 for (i = 0; i < numnums; i++) { 582 if (((num[i].val = tgetnum(num[i].capname)) > -1) && 583 printing != pr_none) { 584 pr_number(num[i].infoname, num[i].capname, 585 num[i].fullname, num[i].val); 586 } 587 588 if (verbose) { 589 (void) fprintf(trace, "%s=%d.\n", num[i].infoname, 590 num[i].val); 591 } 592 } 593 594 if (printing != pr_none) { 595 if (printing == pr_cap) 596 pr_ncaps(); 597 pr_nfooting(); 598 pr_sheading(); 599 } 600 601 for (i = 0; i < numstrs; i++) { 602 str[i].val = tgetstr(str[i].capname, (char **)0); 603 if ((str[i].val != NULL) && printing != pr_none) { 604 pr_string(str[i].infoname, str[i].capname, 605 str[i].fullname, str[i].val); 606 } 607 608 if (verbose) { 609 (void) fprintf(trace, "%s='", str[i].infoname); 610 PR(trace, str[i].val); 611 (void) fprintf(trace, "'.\n"); 612 } 613 } 614 615 if (printing == pr_cap) 616 pr_scaps(); 617 618 if (printing != pr_none) 619 pr_sfooting(); 620 } 621 622 /* 623 Set up the n'th terminal. 624 */ 625 static void 626 check_nth_terminal(char *nterm, int n) 627 { 628 register char boolval; 629 register short numval; 630 register char *strval; 631 register int i; 632 633 if (use) 634 used[n] = FALSE; 635 636 if (verbose) { 637 (void) fprintf(trace, "adding in terminal type '%s'.\n", 638 nterm); 639 } 640 641 (void) setupterm(nterm, devnull, (int *) 0); 642 643 if (printing != pr_none) { 644 pr_heading(nterm, ttytype); 645 pr_bheading(); 646 } 647 648 if (diff || common || neither) { 649 if (Aflag && Bflag) 650 (void) printf("comparing %s (TERMINFO=%s) to %s " 651 "(TERMINFO=%s).\n", 652 firstterm, term1info, nterm, term2info); 653 else if (Aflag) 654 (void) printf("comparing %s (TERMINFO=%s) to %s.\n", 655 firstterm, term1info, nterm); 656 else if (Bflag) 657 (void) printf("comparing %s to %s (TERMINFO=%s).\n", 658 firstterm, nterm, term2info); 659 else 660 (void) printf("comparing %s to %s.\n", 661 firstterm, nterm); 662 (void) printf(" comparing booleans.\n"); 663 } 664 665 /* save away the values for the nth terminal */ 666 for (i = 0; i < numbools; i++) { 667 boolval = tgetflag(ibool[i].capname); 668 if (use) { 669 if (ibool[i].seenagain) { 670 /* 671 ** We do not have to worry about this impossible case 672 ** since booleans can have only two values: true and 673 ** false. 674 ** if (boolval && (boolval != ibool[i].secondval)) 675 ** { 676 ** (void) fprintf(trace, "use= order dependency" 677 ** "found:\n"); 678 ** (void) fprintf(trace, " %s: %s has %d, %s has" 679 ** " %d.\n", 680 ** ibool[i].capname, ibool[i].secondname, 681 ** ibool[i].secondval, nterm, boolval); 682 ** } 683 */ 684 } else { 685 if (boolval == TRUE) { 686 ibool[i].seenagain = TRUE; 687 ibool[i].secondval = boolval; 688 ibool[i].secondname = nterm; 689 if (ibool[i].val != boolval) 690 ibool[i].changed = TRUE; 691 else 692 used[n] = TRUE; 693 } 694 } 695 } 696 if (boolval) { 697 if (printing != pr_none) { 698 pr_boolean(ibool[i].infoname, ibool[i].capname, 699 ibool[i].fullname, 1); 700 } 701 702 if (common && (ibool[i].val == boolval)) 703 (void) printf("\t%s= T.\n", ibool[i].infoname); 704 } else if (neither && !ibool[i].val) { 705 (void) printf("\t!%s.\n", ibool[i].infoname); 706 } 707 if (diff && (ibool[i].val != boolval)) 708 (void) printf("\t%s: %c:%c.\n", ibool[i].infoname, 709 ibool[i].val?'T':'F', boolval?'T':'F'); 710 if (verbose) { 711 (void) fprintf(trace, "%s: %d:%d, changed=%d, " 712 "seen=%d.\n", ibool[i].infoname, ibool[i].val, 713 boolval, ibool[i].changed, ibool[i].seenagain); 714 } 715 } 716 717 if (printing != pr_none) { 718 if (printing == pr_cap) 719 pr_bcaps(); 720 pr_bfooting(); 721 pr_nheading(); 722 } 723 724 if (diff || common || neither) 725 (void) printf(" comparing numbers.\n"); 726 727 for (i = 0; i < numnums; i++) { 728 numval = tgetnum(num[i].capname); 729 if (use) { 730 if (num[i].seenagain) { 731 if ((numval > -1) && 732 (numval != num[i].secondval)) { 733 (void) fprintf(stderr, 734 "%s: use = order dependency " 735 "found:\n", progname); 736 (void) fprintf(stderr, " %s: %s " 737 "has %d, %s has %d.\n", 738 num[i].capname, num[i].secondname, 739 num[i].secondval, nterm, numval); 740 } 741 } else { 742 if (numval > -1) { 743 num[i].seenagain = TRUE; 744 num[i].secondval = numval; 745 num[i].secondname = nterm; 746 if ((numval > -1) && 747 (num[i].val != numval)) 748 num[i].changed = TRUE; 749 else 750 used[n] = TRUE; 751 } 752 } 753 } 754 if (numval > -1) { 755 if (printing != pr_none) { 756 pr_number(num[i].infoname, num[i].capname, 757 num[i].fullname, numval); 758 } 759 760 if (common && (num[i].val == numval)) { 761 (void) printf("\t%s= %d.\n", num[i].infoname, 762 numval); 763 } 764 765 } else if (neither && (num[i].val == -1)) { 766 (void) printf("\t!%s.\n", num[i].infoname); 767 } 768 769 if (diff && (num[i].val != numval)) { 770 (void) printf("\t%s: %d:%d.\n", 771 num[i].infoname, num[i].val, numval); 772 } 773 774 if (verbose) { 775 (void) fprintf(trace, "%s: %d:%d, " 776 "changed = %d, seen = %d.\n", 777 num[i].infoname, num[i].val, numval, 778 num[i].changed, num[i].seenagain); 779 } 780 } 781 782 if (printing != pr_none) { 783 if (printing == pr_cap) 784 pr_ncaps(); 785 pr_nfooting(); 786 pr_sheading(); 787 } 788 789 if (diff || common || neither) 790 (void) printf(" comparing strings.\n"); 791 792 for (i = 0; i < numstrs; i++) { 793 strval = tgetstr(str[i].capname, (char **)0); 794 if (use) { 795 if (str[i].seenagain && (strval != NULL)) { 796 if (!EQUAL(strval, str[i].secondval)) { 797 (void) fprintf(stderr, 798 "use= order dependency" 799 " found:\n"); 800 (void) fprintf(stderr, 801 " %s: %s has '", 802 str[i].capname, str[i].secondname); 803 PR(stderr, str[i].secondval); 804 (void) fprintf(stderr, 805 "', %s has '", nterm); 806 PR(stderr, strval); 807 (void) fprintf(stderr, "'.\n"); 808 } 809 } else { 810 if (strval != NULL) { 811 str[i].seenagain = TRUE; 812 str[i].secondval = strval; 813 str[i].secondname = nterm; 814 if (!EQUAL(str[i].val, strval)) 815 str[i].changed = TRUE; 816 else 817 used[n] = TRUE; 818 } 819 } 820 } 821 if (strval != NULL) { 822 if (printing != pr_none) { 823 pr_string(str[i].infoname, str[i].capname, 824 str[i].fullname, strval); 825 } 826 827 if (common && EQUAL(str[i].val, strval)) { 828 (void) printf("\t%s= '", str[i].infoname); 829 PR(stdout, strval); 830 (void) printf("'.\n"); 831 } 832 } else if (neither && (str[i].val == NULL)) 833 (void) printf("\t!%s.\n", str[i].infoname); 834 if (diff && !EQUAL(str[i].val, strval)) { 835 (void) printf("\t%s: '", str[i].infoname); 836 PR(stdout, str[i].val); 837 (void) printf("','"); 838 PR(stdout, strval); 839 (void) printf("'.\n"); 840 } 841 if (verbose) { 842 (void) fprintf(trace, "%s: '", str[i].infoname); 843 PR(trace, str[i].val); 844 (void) fprintf(trace, "':'"); 845 PR(trace, strval); 846 (void) fprintf(trace, "',changed=%d,seen=%d.\n", 847 str[i].changed, str[i].seenagain); 848 } 849 } 850 851 if (printing == pr_cap) 852 pr_scaps(); 853 854 if (printing != pr_none) 855 pr_sfooting(); 856 857 return; 858 } 859 860 /* 861 A capability gets an at-sign if it no longer exists, but 862 one of the relative entries contains a value for it. 863 It gets printed if the original value is not seen in ANY 864 of the relative entries, or if the FIRST relative entry that has 865 the capability gives a DIFFERENT value for the capability. 866 */ 867 void 868 dorelative(int firstoptind, int argc, char **argv) 869 { 870 register int i; 871 872 /* turn off printing of termcap and long names */ 873 pr_init(pr_terminfo); 874 875 /* print out the entry name */ 876 pr_heading((char *)0, savettytype); 877 878 pr_bheading(); 879 880 /* Print out all bools that are different. */ 881 for (i = 0; i < numbools; i++) { 882 if (!ibool[i].val && ibool[i].changed) { 883 pr_boolean(ibool[i].infoname, (char *)0, 884 (char *)0, -1); 885 } else if (ibool[i].val && (ibool[i].changed || 886 !ibool[i].seenagain)) { 887 pr_boolean(ibool[i].infoname, (char *)0, (char *)0, 1); 888 } 889 } 890 891 pr_bfooting(); 892 pr_nheading(); 893 894 /* Print out all nums that are different. */ 895 for (i = 0; i < numnums; i++) { 896 if (num[i].val < 0 && num[i].changed) { 897 pr_number(num[i].infoname, (char *)0, (char *)0, -1); 898 } else if (num[i].val >= 0 && (num[i].changed || 899 !num[i].seenagain)) { 900 pr_number(num[i].infoname, (char *)0, 901 (char *)0, num[i].val); 902 } 903 } 904 905 pr_nfooting(); 906 pr_sheading(); 907 908 /* Print out all strs that are different. */ 909 for (i = 0; i < numstrs; i++) { 910 if (str[i].val == NULL && str[i].changed) { 911 pr_string(str[i].infoname, (char *)0, (char *)0, 912 (char *)0); 913 } else if ((str[i].val != NULL) && 914 (str[i].changed || !str[i].seenagain)) { 915 pr_string(str[i].infoname, 916 (char *)0, (char *)0, str[i].val); 917 } 918 } 919 920 pr_sfooting(); 921 922 /* Finish it up. */ 923 for (i = firstoptind; i < argc; i++) { 924 if (used[i - firstoptind]) { 925 (void) printf("\tuse=%s,\n", argv[i]); 926 } else { 927 (void) fprintf(stderr, 928 "%s: 'use=%s' did not add anything to the " 929 "description.\n", progname, argv[i]); 930 } 931 } 932 } 933 934 void 935 local_setenv(char *termNinfo) 936 { 937 extern char **environ; 938 static char *newenviron[2] = { 0, 0 }; 939 static unsigned int termsize = BUFSIZ; 940 static char _terminfo[BUFSIZ]; 941 static char *terminfo = &_terminfo[0]; 942 register int termlen; 943 944 if (termNinfo && *termNinfo) { 945 if (verbose) { 946 (void) fprintf(trace, "setting TERMINFO=%s.\n", 947 termNinfo); 948 } 949 950 termlen = strlen(termNinfo); 951 if (termlen + 10 > termsize) { 952 termsize = termlen + 20; 953 terminfo = (char *) malloc(termsize * sizeof (char)); 954 } 955 if (terminfo == (char *) NULL) 956 badmalloc(); 957 (void) sprintf(terminfo, "TERMINFO=%s", termNinfo); 958 newenviron[0] = terminfo; 959 } else 960 newenviron[0] = (char *) 0; 961 environ = newenviron; 962 } 963 964 int 965 main(int argc, char **argv) 966 { 967 int i, c, firstoptind; 968 char *tempargv[2]; 969 char *term = getenv("TERM"); 970 971 term1info = term2info = getenv("TERMINFO"); 972 progname = argv[0]; 973 974 /* parse options */ 975 while ((c = getopt(argc, argv, "ducnILCvV1rw:s:A:B:")) != EOF) 976 switch (c) { 977 case 'v': verbose++; 978 break; 979 case '1': pr_onecolumn(1); 980 break; 981 case 'w': pr_width(atoi(optarg)); 982 break; 983 case 'd': diff++; 984 break; 985 case 'c': common++; 986 break; 987 case 'n': neither++; 988 break; 989 case 'u': use++; 990 break; 991 case 'L': pr_init(printing = pr_longnames); 992 break; 993 case 'I': pr_init(printing = pr_terminfo); 994 break; 995 case 'C': pr_init(printing = pr_cap); 996 break; 997 case 'A': term1info = optarg; Aflag++; 998 break; 999 case 'B': term2info = optarg; Bflag++; 1000 break; 1001 case 'r': pr_caprestrict(0); 1002 break; 1003 case 's': 1004 if (strcmp(optarg, "d") == 0) 1005 sortorder = by_database; 1006 else if (strcmp(optarg, "i") == 0) 1007 sortorder = by_terminfo; 1008 else if (strcmp(optarg, "l") == 0) 1009 sortorder = by_longnames; 1010 else if (strcmp(optarg, "c") == 0) 1011 sortorder = by_cap; 1012 else 1013 goto usage; 1014 break; 1015 case 'V': 1016 (void) printf("%s: version %s\n", progname, 1017 "@(#)curses:screen/infocmp.c 1.13"); 1018 exit(0); 1019 case '?': 1020 usage: 1021 (void) fprintf(stderr, 1022 "usage: %s [-ducn] [-ILC] [-1Vv] " 1023 "[-s d|i|l|c] [-A directory] " 1024 "[-B directory] term-names ...\n", 1025 progname); 1026 (void) fprintf(stderr, "\t-d\tprint " 1027 "differences (the default for >1 " 1028 "term-name)\n"); 1029 (void) fprintf(stderr, "\t-u\tproduce " 1030 "relative description\n"); 1031 (void) fprintf(stderr, "\t-c\tprint common " 1032 "entries\n"); 1033 (void) fprintf(stderr, "\t-n\tprint entries " 1034 "in neither\n"); 1035 (void) fprintf(stderr, "\t-I\tprint terminfo " 1036 "entries (the default for 1 term-name)\n"); 1037 (void) fprintf(stderr, "\t-C\tprint termcap " 1038 "entries\n"); 1039 (void) fprintf(stderr, "\t-L\tprint long C " 1040 "variable names\n"); 1041 (void) fprintf(stderr, "\t-1\tsingle column " 1042 "output\n"); 1043 (void) fprintf(stderr, "\t-V\tprint program " 1044 "version\n"); 1045 (void) fprintf(stderr, "\t-v\tverbose " 1046 "debugging output\n"); 1047 (void) fprintf(stderr, "\t-s\tchange sort " 1048 "order\n"); 1049 (void) fprintf(stderr, "\t-A\tset $TERMINFO " 1050 "for first term-name\n"); 1051 (void) fprintf(stderr, "\t-B\tset $TERMINFO " 1052 "for other term-names\n"); 1053 exit(-1); 1054 } 1055 1056 argc -= optind; 1057 argv += optind; 1058 optind = 0; 1059 1060 /* Default to $TERM for -n, -I, -C and -L options. */ 1061 /* This is done by faking argv[][], argc and optind. */ 1062 if (neither && (argc == 0 || argc == 1)) { 1063 if (argc == 0) 1064 tempargv[0] = term; 1065 else 1066 tempargv[0] = argv[optind]; 1067 tempargv[1] = term; 1068 argc = 2; 1069 argv = tempargv; 1070 optind = 0; 1071 } else if ((printing != pr_none) && (argc == 0)) { 1072 tempargv[0] = term; 1073 argc = 1; 1074 argv = tempargv; 1075 optind = 0; 1076 } 1077 1078 /* Check for enough names. */ 1079 if ((use || diff || common) && (argc <= 1)) { 1080 (void) fprintf(stderr, 1081 "%s: must have at least two terminal names for a " 1082 "comparison to be done.\n", progname); 1083 goto usage; 1084 } 1085 1086 /* Set the default of diff -d or print -I */ 1087 if (!use && (printing == pr_none) && !common && !neither) { 1088 if (argc == 0 || argc == 1) { 1089 if (argc == 0) { 1090 tempargv[0] = term; 1091 argc = 1; 1092 argv = tempargv; 1093 optind = 0; 1094 } 1095 pr_init(printing = pr_terminfo); 1096 } else { 1097 diff++; 1098 } 1099 } 1100 1101 /* Set the default sorting order. */ 1102 if (sortorder == none) { 1103 switch ((int) printing) { 1104 case (int) pr_cap: 1105 sortorder = by_cap; break; 1106 case (int) pr_longnames: 1107 sortorder = by_longnames; break; 1108 case (int) pr_terminfo: 1109 case (int) pr_none: 1110 sortorder = by_terminfo; break; 1111 } 1112 } 1113 1114 firstterm = argv[optind++]; 1115 firstoptind = optind; 1116 1117 allocvariables(argc, firstoptind); 1118 sortnames(); 1119 1120 devnull = open("/dev/null", O_RDWR); 1121 local_setenv(term1info); 1122 initfirstterm(firstterm); 1123 local_setenv(term2info); 1124 for (i = 0; optind < argc; optind++, i++) 1125 check_nth_terminal(argv[optind], i); 1126 1127 if (use) 1128 dorelative(firstoptind, argc, argv); 1129 1130 return (0); 1131 } 1132