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 31 #pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.13 */ 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 if ((ibool == NULL) || (num == NULL) || (str == NULL) || 193 (use && (used == NULL))) 194 badmalloc(); 195 196 /* Fill in the names and initialize the structures. */ 197 nullseen = FALSE; 198 for (i = 0; i < numbools; i++) { 199 ibool[i].infoname = boolnames[i]; 200 ibool[i].capname = boolcodes[i]; 201 /* This is necessary until fnames.c is */ 202 /* incorporated into standard curses. */ 203 if (nullseen || (boolfnames[i] == NULL)) { 204 ibool[i].fullname = "unknown_boolean"; 205 nullseen = TRUE; 206 } else 207 ibool[i].fullname = boolfnames[i]; 208 ibool[i].changed = FALSE; 209 ibool[i].seenagain = FALSE; 210 } 211 nullseen = 0; 212 for (i = 0; i < numnums; i++) { 213 num[i].infoname = numnames[i]; 214 num[i].capname = numcodes[i]; 215 if (nullseen || (numfnames[i] == NULL)) { 216 ibool[i].fullname = "unknown_number"; 217 nullseen = TRUE; 218 } else 219 num[i].fullname = numfnames[i]; 220 num[i].changed = FALSE; 221 num[i].seenagain = FALSE; 222 } 223 nullseen = 0; 224 for (i = 0; i < numstrs; i++) { 225 str[i].infoname = strnames[i]; 226 str[i].capname = strcodes[i]; 227 if (nullseen || (strfnames[i] == NULL)) { 228 str[i].fullname = "unknown_string"; 229 nullseen = TRUE; 230 } else 231 str[i].fullname = strfnames[i]; 232 str[i].changed = FALSE; 233 str[i].seenagain = FALSE; 234 } 235 } 236 237 /* 238 Routines to be passed to qsort(3) for comparison of the structures. 239 */ 240 int 241 boolcompare(const void *x, const void *y) 242 { 243 struct boolstruct *a; 244 struct boolstruct *b; 245 246 a = (struct boolstruct *)x; 247 b = (struct boolstruct *)y; 248 249 switch ((int) sortorder) { 250 case (int) by_terminfo: 251 return (strcmp(a->infoname, b->infoname)); 252 case (int) by_cap: 253 return (strcmp(a->capname, b->capname)); 254 case (int) by_longnames: 255 return (strcmp(a->fullname, b->fullname)); 256 default: 257 return (0); 258 } 259 } 260 261 int 262 numcompare(const void *x, const void *y) 263 { 264 struct numstruct *a; 265 struct numstruct *b; 266 267 a = (struct numstruct *)x; 268 b = (struct numstruct *)y; 269 switch ((int) sortorder) { 270 case (int) by_terminfo: 271 return (strcmp(a->infoname, b->infoname)); 272 case (int) by_cap: 273 return (strcmp(a->capname, b->capname)); 274 case (int) by_longnames: 275 return (strcmp(a->fullname, b->fullname)); 276 default: 277 return (0); 278 } 279 } 280 281 int 282 strcompare(const void *x, const void *y) 283 { 284 struct strstruct *a; 285 struct strstruct *b; 286 287 a = (struct strstruct *)x; 288 b = (struct strstruct *)y; 289 290 switch ((int) sortorder) { 291 case (int) by_terminfo: 292 return (strcmp(a->infoname, b->infoname)); 293 case (int) by_cap: 294 return (strcmp(a->capname, b->capname)); 295 case (int) by_longnames: 296 return (strcmp(a->fullname, b->fullname)); 297 default: 298 return (0); 299 } 300 } 301 302 /* 303 Sort the entries by their terminfo name. 304 */ 305 static void 306 sortnames() 307 { 308 if (sortorder != by_database) { 309 qsort((char *) ibool, (unsigned) numbools, 310 sizeof (struct boolstruct), boolcompare); 311 qsort((char *) num, (unsigned) numnums, 312 sizeof (struct numstruct), numcompare); 313 qsort((char *) str, (unsigned) numstrs, 314 sizeof (struct strstruct), strcompare); 315 } 316 return; 317 } 318 319 /* 320 Print out a string, or "NULL" if it's not defined. 321 */ 322 void 323 PR(FILE *stream, char *string) 324 { 325 if (string == NULL) 326 (void) fprintf(stream, "NULL"); 327 else 328 tpr(stream, string); 329 } 330 331 /* 332 Output the 'ko' termcap string. This is a list of all of the input 333 keys that input the same thing as the corresponding output strings. 334 */ 335 int kncounter; 336 char kobuffer[512]; 337 338 char 339 *addko(char *output, char *input, char *koptr) 340 { 341 char *inptr, *outptr, padbuffer[512]; 342 inptr = tgetstr(input, (char **)0); 343 if (inptr == NULL) 344 return (koptr); 345 outptr = tgetstr(output, (char **)0); 346 if (outptr == NULL) 347 return (koptr); 348 outptr = rmpadding(outptr, padbuffer, (int *) 0); 349 if (strcmp(inptr, outptr) == 0) { 350 *koptr++ = *output++; 351 *koptr++ = *output++; 352 *koptr++ = ','; 353 kncounter++; 354 } 355 return (koptr); 356 } 357 358 void 359 setupknko() 360 { 361 char *koptr; 362 363 kncounter = 0; 364 koptr = kobuffer; 365 366 koptr = addko("bs", "kb", koptr); /* key_backspace */ 367 koptr = addko("bt", "kB", koptr); /* key_btab */ 368 koptr = addko("cl", "kC", koptr); /* key_clear */ 369 koptr = addko("le", "kl", koptr); /* key_left */ 370 koptr = addko("do", "kd", koptr); /* key_down */ 371 koptr = addko("nd", "kr", koptr); /* key_right */ 372 koptr = addko("up", "ku", koptr); /* key_up */ 373 koptr = addko("dc", "kD", koptr); /* key_dc */ 374 koptr = addko("dl", "kL", koptr); /* key_dl */ 375 koptr = addko("cd", "kS", koptr); /* key_eos */ 376 koptr = addko("ce", "kE", koptr); /* key_eol */ 377 koptr = addko("ho", "kh", koptr); /* key_home */ 378 koptr = addko("st", "kT", koptr); /* key_stab */ 379 koptr = addko("ic", "kI", koptr); /* key_ic */ 380 koptr = addko("im", "kI", koptr); /* key_ic */ 381 koptr = addko("al", "kA", koptr); /* key_il */ 382 koptr = addko("sf", "kF", koptr); /* key_sf */ 383 koptr = addko("ll", "kH", koptr); /* key_ll */ 384 koptr = addko("sr", "kR", koptr); /* key_sr */ 385 koptr = addko("ei", "kM", koptr); /* key_eic */ 386 koptr = addko("ct", "ka", koptr); /* key_catab */ 387 388 /* get rid of comma */ 389 if (koptr != kobuffer) 390 *(--koptr) = '\0'; 391 } 392 393 void 394 pr_kn() 395 { 396 if (kncounter > 0) 397 pr_number((char *)0, "kn", (char *)0, kncounter); 398 } 399 400 void 401 pr_ko() 402 { 403 if (kncounter > 0) 404 pr_string((char *)0, "ko", (char *)0, kobuffer); 405 } 406 407 void 408 pr_bcaps() 409 { 410 char *retptr; 411 char padbuffer[512]; 412 413 if (verbose) 414 (void) fprintf(trace, "looking at 'bs'\n"); 415 retptr = cconvert(rmpadding(cursor_left, padbuffer, (int *) 0)); 416 if (strcmp("\\b", retptr) == 0) 417 pr_boolean((char *)0, "bs", (char *)0, 1); 418 419 if (verbose) 420 (void) fprintf(trace, "looking at 'pt'\n"); 421 retptr = cconvert(rmpadding(tab, padbuffer, (int *) 0)); 422 if (strcmp("\\t", retptr) == 0) 423 pr_boolean((char *)0, "pt", (char *)0, 1); 424 425 if (verbose) 426 (void) fprintf(trace, "looking at 'nc'\n"); 427 retptr = cconvert(rmpadding(carriage_return, padbuffer, (int *) 0)); 428 if (strcmp("\\r", retptr) != 0) 429 pr_boolean((char *)0, "nc", (char *)0, 1); 430 431 if (verbose) 432 (void) fprintf(trace, "looking at 'ns'\n"); 433 if (scroll_forward == NULL) 434 pr_boolean((char *)0, "ns", (char *)0, 1); 435 436 /* Ignore "xr": Return acts like ce \r \n (Delta Data) */ 437 } 438 439 void 440 pr_ncaps() 441 { 442 char padbuffer[512]; 443 int padding; 444 445 if (verbose) 446 (void) fprintf(trace, "looking at 'ug'\n"); 447 /* Duplicate sg for ug: Number of blank chars left by us or ue */ 448 if (magic_cookie_glitch > -1) 449 pr_number((char *)0, "ug", (char *)0, magic_cookie_glitch); 450 451 if (verbose) 452 (void) fprintf(trace, "looking at 'dB'\n"); 453 /* Number of millisec of bs delay needed */ 454 (void) rmpadding(cursor_left, padbuffer, &padding); 455 if (padding > 0) 456 pr_number((char *)0, "dB", (char *)0, padding); 457 458 if (verbose) 459 (void) fprintf(trace, "looking at 'dC'\n"); 460 /* Number of millisec of cr delay needed */ 461 (void) rmpadding(carriage_return, padbuffer, &padding); 462 if (padding > 0) 463 pr_number((char *)0, "dC", (char *)0, padding); 464 465 if (verbose) 466 (void) fprintf(trace, "looking at 'dF'\n"); 467 /* Number of millisec of ff delay needed */ 468 (void) rmpadding(form_feed, padbuffer, &padding); 469 if (padding > 0) 470 pr_number((char *)0, "dF", (char *)0, padding); 471 472 if (verbose) 473 (void) fprintf(trace, "looking at 'dN'\n"); 474 /* Number of millisec of nl delay needed */ 475 (void) rmpadding(cursor_down, padbuffer, &padding); 476 if (padding > 0) 477 pr_number((char *)0, "dN", (char *)0, padding); 478 479 if (verbose) 480 (void) fprintf(trace, "looking at 'dT'\n"); 481 /* Number of millisec of tab delay needed */ 482 (void) rmpadding(tab, padbuffer, &padding); 483 if (padding > 0) 484 pr_number((char *)0, "dT", (char *)0, padding); 485 486 /* Handle "kn": Number of "other" keys */ 487 setupknko(); 488 pr_kn(); 489 } 490 491 void 492 pr_scaps() 493 { 494 char *retptr; 495 char padbuffer[512]; 496 497 /* Backspace if not "^H" */ 498 if (verbose) 499 (void) fprintf(trace, "looking at 'bc'\n"); 500 retptr = cconvert(rmpadding(cursor_left, padbuffer, (int *) 0)); 501 if (strcmp("\\b", retptr) != 0) 502 pr_string((char *)0, "bc", (char *)0, cursor_left); 503 504 /* Newline character (default "\n") */ 505 if (verbose) 506 (void) fprintf(trace, "looking at 'nl'\n"); 507 retptr = cconvert(rmpadding(cursor_down, padbuffer, (int *) 0)); 508 if (strcmp("\\n", retptr) != 0) 509 pr_string((char *)0, "nl", (char *)0, cursor_down); 510 511 /* Handle "ko" here: Termcap entries for other non-function keys */ 512 pr_ko(); 513 514 /* Ignore "ma": Arrow key map, used by vi version 2 only */ 515 } 516 517 /* 518 Set up the first terminal and save the values from it. 519 */ 520 void 521 initfirstterm(char *term) 522 { 523 register int i; 524 525 if (verbose) 526 (void) fprintf(trace, "setting up terminal type '%s'.\n", 527 term); 528 529 (void) setupterm(term, devnull, (int *) 0); 530 531 /* Save the name for later use. */ 532 if (use) { 533 register unsigned int length; 534 savettytype = _savettytype; 535 if ((length = strlen(ttytype)) >= TTYLEN) { 536 savettytype = malloc(length); 537 if (savettytype == NULL) { 538 (void) fprintf(stderr, "%s: malloc is out " 539 "of space\n", progname); 540 (void) strncpy(_savettytype, ttytype, 541 TTYLEN-1); 542 _savettytype[TTYLEN] = '\0'; 543 savettytype = _savettytype; 544 } 545 } else 546 (void) strcpy(_savettytype, ttytype); 547 } 548 549 if (printing != pr_none) { 550 pr_heading(term, ttytype); 551 pr_bheading(); 552 } 553 554 /* Save the values for the first terminal. */ 555 for (i = 0; i < numbools; i++) { 556 if ((ibool[i].val = tgetflag(ibool[i].capname)) && 557 printing != pr_none) 558 pr_boolean(ibool[i].infoname, ibool[i].capname, 559 ibool[i].fullname, 1); 560 if (verbose) 561 (void) fprintf(trace, "%s=%d.\n", ibool[i].infoname, 562 ibool[i].val); 563 } 564 565 if (printing != pr_none) { 566 if (printing == pr_cap) 567 pr_bcaps(); 568 pr_bfooting(); 569 pr_nheading(); 570 } 571 572 for (i = 0; i < numnums; i++) { 573 if (((num[i].val = tgetnum(num[i].capname)) > -1) && 574 printing != pr_none) 575 pr_number(num[i].infoname, num[i].capname, 576 num[i].fullname, num[i].val); 577 if (verbose) 578 (void) fprintf(trace, "%s=%d.\n", num[i].infoname, 579 num[i].val); 580 } 581 582 if (printing != pr_none) { 583 if (printing == pr_cap) 584 pr_ncaps(); 585 pr_nfooting(); 586 pr_sheading(); 587 } 588 589 for (i = 0; i < numstrs; i++) { 590 str[i].val = tgetstr(str[i].capname, (char **)0); 591 if ((str[i].val != NULL) && printing != pr_none) 592 pr_string(str[i].infoname, str[i].capname, 593 str[i].fullname, str[i].val); 594 if (verbose) { 595 (void) fprintf(trace, "%s='", str[i].infoname); 596 PR(trace, str[i].val); 597 (void) fprintf(trace, "'.\n"); 598 } 599 } 600 601 if (printing == pr_cap) 602 pr_scaps(); 603 604 if (printing != pr_none) 605 pr_sfooting(); 606 } 607 608 /* 609 Set up the n'th terminal. 610 */ 611 static void 612 check_nth_terminal(char *nterm, int n) 613 { 614 register char boolval; 615 register short numval; 616 register char *strval; 617 register int i; 618 619 if (use) 620 used[n] = FALSE; 621 622 if (verbose) 623 (void) fprintf(trace, "adding in terminal type '%s'.\n", 624 nterm); 625 626 (void) setupterm(nterm, devnull, (int *) 0); 627 628 if (printing != pr_none) { 629 pr_heading(nterm, ttytype); 630 pr_bheading(); 631 } 632 633 if (diff || common || neither) { 634 if (Aflag && Bflag) 635 (void) printf("comparing %s (TERMINFO=%s) to %s " 636 "(TERMINFO=%s).\n", 637 firstterm, term1info, nterm, term2info); 638 else if (Aflag) 639 (void) printf("comparing %s (TERMINFO=%s) to %s.\n", 640 firstterm, term1info, nterm); 641 else if (Bflag) 642 (void) printf("comparing %s to %s (TERMINFO=%s).\n", 643 firstterm, nterm, term2info); 644 else 645 (void) printf("comparing %s to %s.\n", 646 firstterm, nterm); 647 (void) printf(" comparing booleans.\n"); 648 } 649 650 /* save away the values for the nth terminal */ 651 for (i = 0; i < numbools; i++) { 652 boolval = tgetflag(ibool[i].capname); 653 if (use) { 654 if (ibool[i].seenagain) { 655 /* 656 ** We do not have to worry about this impossible case 657 ** since booleans can have only two values: true and 658 ** false. 659 ** if (boolval && (boolval != ibool[i].secondval)) 660 ** { 661 ** (void) fprintf(trace, "use= order dependency" 662 ** "found:\n"); 663 ** (void) fprintf(trace, " %s: %s has %d, %s has" 664 ** " %d.\n", 665 ** ibool[i].capname, ibool[i].secondname, 666 ** ibool[i].secondval, nterm, boolval); 667 ** } 668 */ 669 } else { 670 if (boolval == TRUE) { 671 ibool[i].seenagain = TRUE; 672 ibool[i].secondval = boolval; 673 ibool[i].secondname = nterm; 674 if (ibool[i].val != boolval) 675 ibool[i].changed = TRUE; 676 else 677 used[n] = TRUE; 678 } 679 } 680 } 681 if (boolval) { 682 if (printing != pr_none) 683 pr_boolean(ibool[i].infoname, ibool[i].capname, 684 ibool[i].fullname, 1); 685 if (common && (ibool[i].val == boolval)) 686 (void) printf("\t%s= T.\n", ibool[i].infoname); 687 } else if (neither && !ibool[i].val) 688 (void) printf("\t!%s.\n", ibool[i].infoname); 689 if (diff && (ibool[i].val != boolval)) 690 (void) printf("\t%s: %c:%c.\n", ibool[i].infoname, 691 ibool[i].val?'T':'F', boolval?'T':'F'); 692 if (verbose) 693 (void) fprintf(trace, "%s: %d:%d, changed=%d, " 694 "seen=%d.\n", ibool[i].infoname, ibool[i].val, 695 boolval, ibool[i].changed, ibool[i].seenagain); 696 } 697 698 if (printing != pr_none) { 699 if (printing == pr_cap) 700 pr_bcaps(); 701 pr_bfooting(); 702 pr_nheading(); 703 } 704 705 if (diff || common || neither) 706 (void) printf(" comparing numbers.\n"); 707 708 for (i = 0; i < numnums; i++) { 709 numval = tgetnum(num[i].capname); 710 if (use) { 711 if (num[i].seenagain) { 712 if ((numval > -1) && 713 (numval != num[i].secondval)) { 714 (void) fprintf(stderr, 715 "%s: use = order dependency " 716 "found:\n", progname); 717 (void) fprintf(stderr, " %s: %s " 718 "has %d, %s has %d.\n", 719 num[i].capname, num[i].secondname, 720 num[i].secondval, nterm, numval); 721 } 722 } else { 723 if (numval > -1) { 724 num[i].seenagain = TRUE; 725 num[i].secondval = numval; 726 num[i].secondname = nterm; 727 if ((numval > -1) && 728 (num[i].val != numval)) 729 num[i].changed = TRUE; 730 else 731 used[n] = TRUE; 732 } 733 } 734 } 735 if (numval > -1) { 736 if (printing != pr_none) 737 pr_number(num[i].infoname, num[i].capname, 738 num[i].fullname, numval); 739 if (common && (num[i].val == numval)) 740 (void) printf("\t%s= %d.\n", num[i].infoname, 741 numval); 742 } else if (neither && (num[i].val == -1)) 743 (void) printf("\t!%s.\n", num[i].infoname); 744 if (diff && (num[i].val != numval)) 745 (void) printf("\t%s: %d:%d.\n", 746 num[i].infoname, num[i].val, numval); 747 if (verbose) 748 (void) fprintf(trace, "%s: %d:%d, " 749 "changed = %d, seen = %d.\n", 750 num[i].infoname, num[i].val, numval, 751 num[i].changed, num[i].seenagain); 752 } 753 754 if (printing != pr_none) { 755 if (printing == pr_cap) 756 pr_ncaps(); 757 pr_nfooting(); 758 pr_sheading(); 759 } 760 761 if (diff || common || neither) 762 (void) printf(" comparing strings.\n"); 763 764 for (i = 0; i < numstrs; i++) { 765 strval = tgetstr(str[i].capname, (char **)0); 766 if (use) { 767 if (str[i].seenagain && (strval != NULL)) { 768 if (!EQUAL(strval, str[i].secondval)) { 769 (void) fprintf(stderr, 770 "use= order dependency" 771 " found:\n"); 772 (void) fprintf(stderr, 773 " %s: %s has '", 774 str[i].capname, str[i].secondname); 775 PR(stderr, str[i].secondval); 776 (void) fprintf(stderr, 777 "', %s has '", nterm); 778 PR(stderr, strval); 779 (void) fprintf(stderr, "'.\n"); 780 } 781 } else { 782 if (strval != NULL) { 783 str[i].seenagain = TRUE; 784 str[i].secondval = strval; 785 str[i].secondname = nterm; 786 if (!EQUAL(str[i].val, strval)) 787 str[i].changed = TRUE; 788 else 789 used[n] = TRUE; 790 } 791 } 792 } 793 if (strval != NULL) { 794 if (printing != pr_none) 795 pr_string(str[i].infoname, str[i].capname, 796 str[i].fullname, strval); 797 if (common && EQUAL(str[i].val, strval)) { 798 (void) printf("\t%s= '", str[i].infoname); 799 PR(stdout, strval); 800 (void) printf("'.\n"); 801 } 802 } else if (neither && (str[i].val == NULL)) 803 (void) printf("\t!%s.\n", str[i].infoname); 804 if (diff && !EQUAL(str[i].val, strval)) { 805 (void) printf("\t%s: '", str[i].infoname); 806 PR(stdout, str[i].val); 807 (void) printf("','"); 808 PR(stdout, strval); 809 (void) printf("'.\n"); 810 } 811 if (verbose) { 812 (void) fprintf(trace, "%s: '", str[i].infoname); 813 PR(trace, str[i].val); 814 (void) fprintf(trace, "':'"); 815 PR(trace, strval); 816 (void) fprintf(trace, "',changed=%d,seen=%d.\n", 817 str[i].changed, str[i].seenagain); 818 } 819 } 820 821 if (printing == pr_cap) 822 pr_scaps(); 823 824 if (printing != pr_none) 825 pr_sfooting(); 826 827 return; 828 } 829 830 /* 831 A capability gets an at-sign if it no longer exists, but 832 one of the relative entries contains a value for it. 833 It gets printed if the original value is not seen in ANY 834 of the relative entries, or if the FIRST relative entry that has 835 the capability gives a DIFFERENT value for the capability. 836 */ 837 void 838 dorelative(int firstoptind, int argc, char **argv) 839 { 840 register int i; 841 842 /* turn off printing of termcap and long names */ 843 pr_init(pr_terminfo); 844 845 /* print out the entry name */ 846 pr_heading((char *)0, savettytype); 847 848 pr_bheading(); 849 850 /* Print out all bools that are different. */ 851 for (i = 0; i < numbools; i++) 852 if (!ibool[i].val && ibool[i].changed) 853 pr_boolean(ibool[i].infoname, (char *)0, 854 (char *)0, -1); 855 else if (ibool[i].val && (ibool[i].changed || 856 !ibool[i].seenagain)) 857 pr_boolean(ibool[i].infoname, (char *)0, (char *)0, 1); 858 859 pr_bfooting(); 860 pr_nheading(); 861 862 /* Print out all nums that are different. */ 863 for (i = 0; i < numnums; i++) 864 if (num[i].val < 0 && num[i].changed) 865 pr_number(num[i].infoname, (char *)0, (char *)0, -1); 866 else if (num[i].val >= 0 && (num[i].changed || 867 !num[i].seenagain)) 868 pr_number(num[i].infoname, (char *)0, 869 (char *)0, num[i].val); 870 871 pr_nfooting(); 872 pr_sheading(); 873 874 /* Print out all strs that are different. */ 875 for (i = 0; i < numstrs; i++) 876 if (str[i].val == NULL && str[i].changed) 877 pr_string(str[i].infoname, (char *)0, (char *)0, 878 (char *)0); 879 else if ((str[i].val != NULL) && 880 (str[i].changed || !str[i].seenagain)) 881 pr_string(str[i].infoname, (char *)0, (char *)0, str[i].val); 882 883 pr_sfooting(); 884 885 /* Finish it up. */ 886 for (i = firstoptind; i < argc; i++) 887 if (used[i - firstoptind]) 888 (void) printf("\tuse=%s,\n", argv[i]); 889 else 890 (void) fprintf(stderr, 891 "%s: 'use=%s' did not add anything to the " 892 "description.\n", progname, argv[i]); 893 } 894 895 void 896 local_setenv(char *termNinfo) 897 { 898 extern char **environ; 899 static char *newenviron[2] = { 0, 0 }; 900 static unsigned int termsize = BUFSIZ; 901 static char _terminfo[BUFSIZ]; 902 static char *terminfo = &_terminfo[0]; 903 register int termlen; 904 905 if (termNinfo && *termNinfo) { 906 if (verbose) 907 (void) fprintf(trace, "setting TERMINFO=%s.\n", 908 termNinfo); 909 termlen = strlen(termNinfo); 910 if (termlen + 10 > termsize) { 911 termsize = termlen + 20; 912 terminfo = (char *) malloc(termsize * sizeof (char)); 913 } 914 if (terminfo == (char *) NULL) 915 badmalloc(); 916 (void) sprintf(terminfo, "TERMINFO=%s", termNinfo); 917 newenviron[0] = terminfo; 918 } else 919 newenviron[0] = (char *) 0; 920 environ = newenviron; 921 } 922 923 int 924 main(int argc, char **argv) 925 { 926 int i, c, firstoptind; 927 char *tempargv[2]; 928 char *term = getenv("TERM"); 929 930 term1info = term2info = getenv("TERMINFO"); 931 progname = argv[0]; 932 933 /* parse options */ 934 while ((c = getopt(argc, argv, "ducnILCvV1rw:s:A:B:")) != EOF) 935 switch (c) { 936 case 'v': verbose++; 937 break; 938 case '1': pr_onecolumn(1); 939 break; 940 case 'w': pr_width(atoi(optarg)); 941 break; 942 case 'd': diff++; 943 break; 944 case 'c': common++; 945 break; 946 case 'n': neither++; 947 break; 948 case 'u': use++; 949 break; 950 case 'L': pr_init(printing = pr_longnames); 951 break; 952 case 'I': pr_init(printing = pr_terminfo); 953 break; 954 case 'C': pr_init(printing = pr_cap); 955 break; 956 case 'A': term1info = optarg; Aflag++; 957 break; 958 case 'B': term2info = optarg; Bflag++; 959 break; 960 case 'r': pr_caprestrict(0); 961 break; 962 case 's': 963 if (strcmp(optarg, "d") == 0) 964 sortorder = by_database; 965 else if (strcmp(optarg, "i") == 0) 966 sortorder = by_terminfo; 967 else if (strcmp(optarg, "l") == 0) 968 sortorder = by_longnames; 969 else if (strcmp(optarg, "c") == 0) 970 sortorder = by_cap; 971 else 972 goto usage; 973 break; 974 case 'V': 975 (void) printf("%s: version %s\n", progname, 976 "@(#)curses:screen/infocmp.c 1.13"); 977 exit(0); 978 case '?': 979 usage: 980 (void) fprintf(stderr, 981 "usage: %s [-ducn] [-ILC] [-1Vv] " 982 "[-s d|i|l|c] [-A directory] " 983 "[-B directory] term-names ...\n", 984 progname); 985 (void) fprintf(stderr, "\t-d\tprint " 986 "differences (the default for >1 " 987 "term-name)\n"); 988 (void) fprintf(stderr, "\t-u\tproduce " 989 "relative description\n"); 990 (void) fprintf(stderr, "\t-c\tprint common " 991 "entries\n"); 992 (void) fprintf(stderr, "\t-n\tprint entries " 993 "in neither\n"); 994 (void) fprintf(stderr, "\t-I\tprint terminfo " 995 "entries (the default for 1 term-name)\n"); 996 (void) fprintf(stderr, "\t-C\tprint termcap " 997 "entries\n"); 998 (void) fprintf(stderr, "\t-L\tprint long C " 999 "variable names\n"); 1000 (void) fprintf(stderr, "\t-1\tsingle column " 1001 "output\n"); 1002 (void) fprintf(stderr, "\t-V\tprint program " 1003 "version\n"); 1004 (void) fprintf(stderr, "\t-v\tverbose " 1005 "debugging output\n"); 1006 (void) fprintf(stderr, "\t-s\tchange sort " 1007 "order\n"); 1008 (void) fprintf(stderr, "\t-A\tset $TERMINFO " 1009 "for first term-name\n"); 1010 (void) fprintf(stderr, "\t-B\tset $TERMINFO " 1011 "for other term-names\n"); 1012 exit(-1); 1013 } 1014 1015 argc -= optind; 1016 argv += optind; 1017 optind = 0; 1018 1019 /* Default to $TERM for -n, -I, -C and -L options. */ 1020 /* This is done by faking argv[][], argc and optind. */ 1021 if (neither && (argc == 0 || argc == 1)) { 1022 if (argc == 0) 1023 tempargv[0] = term; 1024 else 1025 tempargv[0] = argv[optind]; 1026 tempargv[1] = term; 1027 argc = 2; 1028 argv = tempargv; 1029 optind = 0; 1030 } else if ((printing != pr_none) && (argc == 0)) { 1031 tempargv[0] = term; 1032 argc = 1; 1033 argv = tempargv; 1034 optind = 0; 1035 } 1036 1037 /* Check for enough names. */ 1038 if ((use || diff || common) && (argc <= 1)) { 1039 (void) fprintf(stderr, 1040 "%s: must have at least two terminal names for a " 1041 "comparison to be done.\n", progname); 1042 goto usage; 1043 } 1044 1045 /* Set the default of diff -d or print -I */ 1046 if (!use && (printing == pr_none) && !common && !neither) { 1047 if (argc == 0 || argc == 1) { 1048 if (argc == 0) { 1049 tempargv[0] = term; 1050 argc = 1; 1051 argv = tempargv; 1052 optind = 0; 1053 } 1054 pr_init(printing = pr_terminfo); 1055 } else 1056 diff++; 1057 } 1058 1059 /* Set the default sorting order. */ 1060 if (sortorder == none) 1061 switch ((int) printing) { 1062 case (int) pr_cap: 1063 sortorder = by_cap; break; 1064 case (int) pr_longnames: 1065 sortorder = by_longnames; break; 1066 case (int) pr_terminfo: 1067 case (int) pr_none: 1068 sortorder = by_terminfo; break; 1069 } 1070 1071 firstterm = argv[optind++]; 1072 firstoptind = optind; 1073 1074 allocvariables(argc, firstoptind); 1075 sortnames(); 1076 1077 devnull = open("/dev/null", O_RDWR); 1078 local_setenv(term1info); 1079 initfirstterm(firstterm); 1080 local_setenv(term2info); 1081 for (i = 0; optind < argc; optind++, i++) 1082 check_nth_terminal(argv[optind], i); 1083 1084 if (use) 1085 dorelative(firstoptind, argc, argv); 1086 1087 return (0); 1088 } 1089