1 /**************************************************************************** 2 * Copyright (c) 1998,1999 Free Software Foundation, Inc. * 3 * * 4 * Permission is hereby granted, free of charge, to any person obtaining a * 5 * copy of this software and associated documentation files (the * 6 * "Software"), to deal in the Software without restriction, including * 7 * without limitation the rights to use, copy, modify, merge, publish, * 8 * distribute, distribute with modifications, sublicense, and/or sell * 9 * copies of the Software, and to permit persons to whom the Software is * 10 * furnished to do so, subject to the following conditions: * 11 * * 12 * The above copyright notice and this permission notice shall be included * 13 * in all copies or substantial portions of the Software. * 14 * * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 18 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 21 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 22 * * 23 * Except as contained in this notice, the name(s) of the above copyright * 24 * holders shall not be used in advertising or otherwise to promote the * 25 * sale, use or other dealings in this Software without prior written * 26 * authorization. * 27 ****************************************************************************/ 28 29 /**************************************************************************** 30 * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 * 31 * and: Eric S. Raymond <esr@snark.thyrsus.com> * 32 ****************************************************************************/ 33 34 #define __INTERNAL_CAPS_VISIBLE 35 #include <progs.priv.h> 36 37 #include "dump_entry.h" 38 #include "termsort.c" /* this C file is generated */ 39 #include <parametrized.h> /* so is this */ 40 41 MODULE_ID("$Id: dump_entry.c,v 1.37 1999/03/14 12:29:30 tom Exp $") 42 43 #define INDENT 8 44 45 #define DISCARD(string) string = ABSENT_STRING 46 47 static int tversion; /* terminfo version */ 48 static int outform; /* output format to use */ 49 static int sortmode; /* sort mode to use */ 50 static int width = 60; /* max line width for listings */ 51 static int column; /* current column, limited by 'width' */ 52 static int oldcol; /* last value of column before wrap */ 53 static int tracelevel; /* level of debug output */ 54 static bool pretty; /* true if we format if-then-else strings */ 55 56 static char *outbuf; /* the output-buffer */ 57 static size_t out_used; /* ...its current length */ 58 static size_t out_size; /* ...and its allocated length */ 59 60 /* indirection pointers for implementing sort and display modes */ 61 static const int *bool_indirect, *num_indirect, *str_indirect; 62 static NCURSES_CONST char * const *bool_names; 63 static NCURSES_CONST char * const *num_names; 64 static NCURSES_CONST char * const *str_names; 65 66 static const char *separator, *trailer; 67 68 /* cover various ports and variants of terminfo */ 69 #define V_ALLCAPS 0 /* all capabilities (SVr4, XSI, ncurses) */ 70 #define V_SVR1 1 /* SVR1, Ultrix */ 71 #define V_HPUX 2 /* HP/UX */ 72 #define V_AIX 3 /* AIX */ 73 #define V_BSD 4 /* BSD */ 74 75 #define OBSOLETE(n) (n[0] == 'O' && n[1] == 'T') 76 77 #if NCURSES_XNAMES 78 #define BoolIndirect(j) ((j >= BOOLCOUNT) ? (j) : ((sortmode == S_NOSORT) ? j : bool_indirect[j])) 79 #define NumIndirect(j) ((j >= NUMCOUNT) ? (j) : ((sortmode == S_NOSORT) ? j : num_indirect[j])) 80 #define StrIndirect(j) ((j >= STRCOUNT) ? (j) : ((sortmode == S_NOSORT) ? j : str_indirect[j])) 81 #else 82 #define BoolIndirect(j) ((sortmode == S_NOSORT) ? (j) : bool_indirect[j]) 83 #define NumIndirect(j) ((sortmode == S_NOSORT) ? (j) : num_indirect[j]) 84 #define StrIndirect(j) ((sortmode == S_NOSORT) ? (j) : str_indirect[j]) 85 #endif 86 87 #if NO_LEAKS 88 void _nc_leaks_dump_entry(void) 89 { 90 if (outbuf != 0) { 91 free(outbuf); 92 outbuf = 0; 93 } 94 } 95 #endif 96 97 NCURSES_CONST char *nametrans(const char *name) 98 /* translate a capability name from termcap to terminfo */ 99 { 100 const struct name_table_entry *np; 101 102 if ((np = _nc_find_entry(name, _nc_get_hash_table(0))) != 0) 103 switch(np->nte_type) 104 { 105 case BOOLEAN: 106 if (bool_from_termcap[np->nte_index]) 107 return(boolcodes[np->nte_index]); 108 break; 109 110 case NUMBER: 111 if (num_from_termcap[np->nte_index]) 112 return(numcodes[np->nte_index]); 113 break; 114 115 case STRING: 116 if (str_from_termcap[np->nte_index]) 117 return(strcodes[np->nte_index]); 118 break; 119 } 120 121 return(0); 122 } 123 124 void dump_init(const char *version, int mode, int sort, int twidth, int traceval, bool formatted) 125 /* set up for entry display */ 126 { 127 width = twidth; 128 pretty = formatted; 129 tracelevel = traceval; 130 131 /* versions */ 132 if (version == 0) 133 tversion = V_ALLCAPS; 134 else if (!strcmp(version, "SVr1") || !strcmp(version, "SVR1") 135 || !strcmp(version, "Ultrix")) 136 tversion = V_SVR1; 137 else if (!strcmp(version, "HP")) 138 tversion = V_HPUX; 139 else if (!strcmp(version, "AIX")) 140 tversion = V_AIX; 141 else if (!strcmp(version, "BSD")) 142 tversion = V_BSD; 143 else 144 tversion = V_ALLCAPS; 145 146 /* implement display modes */ 147 switch (outform = mode) 148 { 149 case F_LITERAL: 150 case F_TERMINFO: 151 bool_names = boolnames; 152 num_names = numnames; 153 str_names = strnames; 154 separator = twidth ? ", " : ","; 155 trailer = "\n\t"; 156 break; 157 158 case F_VARIABLE: 159 bool_names = boolfnames; 160 num_names = numfnames; 161 str_names = strfnames; 162 separator = twidth ? ", " : ","; 163 trailer = "\n\t"; 164 break; 165 166 case F_TERMCAP: 167 case F_TCONVERR: 168 bool_names = boolcodes; 169 num_names = numcodes; 170 str_names = strcodes; 171 separator = ":"; 172 trailer = "\\\n\t:"; 173 break; 174 } 175 176 /* implement sort modes */ 177 switch(sortmode = sort) 178 { 179 case S_NOSORT: 180 if (traceval) 181 (void) fprintf(stderr, 182 "%s: sorting by term structure order\n", _nc_progname); 183 break; 184 185 case S_TERMINFO: 186 if (traceval) 187 (void) fprintf(stderr, 188 "%s: sorting by terminfo name order\n", _nc_progname); 189 bool_indirect = bool_terminfo_sort; 190 num_indirect = num_terminfo_sort; 191 str_indirect = str_terminfo_sort; 192 break; 193 194 case S_VARIABLE: 195 if (traceval) 196 (void) fprintf(stderr, 197 "%s: sorting by C variable order\n", _nc_progname); 198 bool_indirect = bool_variable_sort; 199 num_indirect = num_variable_sort; 200 str_indirect = str_variable_sort; 201 break; 202 203 case S_TERMCAP: 204 if (traceval) 205 (void) fprintf(stderr, 206 "%s: sorting by termcap name order\n", _nc_progname); 207 bool_indirect = bool_termcap_sort; 208 num_indirect = num_termcap_sort; 209 str_indirect = str_termcap_sort; 210 break; 211 } 212 213 if (traceval) 214 (void) fprintf(stderr, 215 "%s: width = %d, tversion = %d, outform = %d\n", 216 _nc_progname, width, tversion, outform); 217 } 218 219 static TERMTYPE *cur_type; 220 221 static int dump_predicate(int type, int idx) 222 /* predicate function to use for ordinary decompilation */ 223 { 224 switch(type) { 225 case BOOLEAN: 226 return (cur_type->Booleans[idx] == FALSE) 227 ? FAIL : cur_type->Booleans[idx]; 228 229 case NUMBER: 230 return (cur_type->Numbers[idx] == ABSENT_NUMERIC) 231 ? FAIL : cur_type->Numbers[idx]; 232 233 case STRING: 234 return (cur_type->Strings[idx] != ABSENT_STRING) 235 ? (int)TRUE : FAIL; 236 } 237 238 return(FALSE); /* pacify compiler */ 239 } 240 241 static void set_obsolete_termcaps(TERMTYPE *tp); 242 static void repair_acsc(TERMTYPE *tp); 243 244 /* is this the index of a function key string? */ 245 #define FNKEY(i) (((i)<= 65 && (i)>= 75) || ((i)<= 216 && (i)>= 268)) 246 247 static bool version_filter(int type, int idx) 248 /* filter out capabilities we may want to suppress */ 249 { 250 switch (tversion) 251 { 252 case V_ALLCAPS: /* SVr4, XSI Curses */ 253 return(TRUE); 254 255 case V_SVR1: /* System V Release 1, Ultrix */ 256 switch (type) 257 { 258 case BOOLEAN: 259 /* below and including xon_xoff */ 260 return ((idx <= 20) ? TRUE : FALSE); 261 case NUMBER: 262 /* below and including width_status_line */ 263 return ((idx <= 7) ? TRUE : FALSE); 264 case STRING: 265 /* below and including prtr_non */ 266 return ((idx <= 144) ? TRUE : FALSE); 267 } 268 break; 269 270 case V_HPUX: /* Hewlett-Packard */ 271 switch (type) 272 { 273 case BOOLEAN: 274 /* below and including xon_xoff */ 275 return ((idx <= 20) ? TRUE : FALSE); 276 case NUMBER: 277 /* below and including label_width */ 278 return ((idx <= 10) ? TRUE : FALSE); 279 case STRING: 280 if (idx <= 144) /* below and including prtr_non */ 281 return(TRUE); 282 else if (FNKEY(idx)) /* function keys */ 283 return(TRUE); 284 else if (idx==147||idx==156||idx==157) /* plab_norm,label_on,label_off */ 285 return(TRUE); 286 else 287 return(FALSE); 288 } 289 break; 290 291 case V_AIX: /* AIX */ 292 switch (type) 293 { 294 case BOOLEAN: 295 /* below and including xon_xoff */ 296 return ((idx <= 20) ? TRUE : FALSE); 297 case NUMBER: 298 /* below and including width_status_line */ 299 return ((idx <= 7) ? TRUE : FALSE); 300 case STRING: 301 if (idx <= 144) /* below and including prtr_non */ 302 return(TRUE); 303 else if (FNKEY(idx)) /* function keys */ 304 return(TRUE); 305 else 306 return(FALSE); 307 } 308 break; 309 310 case V_BSD: /* BSD */ 311 switch (type) 312 { 313 case BOOLEAN: 314 return bool_from_termcap[idx]; 315 case NUMBER: 316 return num_from_termcap[idx]; 317 case STRING: 318 return str_from_termcap[idx]; 319 } 320 break; 321 } 322 323 return(FALSE); /* pacify the compiler */ 324 } 325 326 static 327 void append_output (const char *src) 328 { 329 if (src == 0) { 330 out_used = 0; 331 append_output(""); 332 } else { 333 size_t need = strlen(src); 334 size_t want = need + out_used + 1; 335 if (want > out_size) { 336 out_size += want; /* be generous */ 337 if (outbuf == 0) 338 outbuf = malloc(out_size); 339 else 340 outbuf = realloc(outbuf, out_size); 341 } 342 (void)strcpy(outbuf + out_used, src); 343 out_used += need; 344 } 345 } 346 347 static 348 void force_wrap(void) 349 { 350 oldcol = column; 351 append_output(trailer); 352 column = INDENT; 353 } 354 355 static 356 void wrap_concat(const char *src) 357 { 358 int need = strlen(src); 359 int want = strlen(separator) + need; 360 361 if (column > INDENT 362 && column + want > width) { 363 force_wrap(); 364 } 365 append_output(src); 366 append_output(separator); 367 column += need; 368 } 369 370 #define IGNORE_SEP_TRAIL(first,last,sep_trail) \ 371 if ((size_t)(last - first) > sizeof(sep_trail)-1 \ 372 && !strncmp(first, sep_trail, sizeof(sep_trail)-1)) \ 373 first += sizeof(sep_trail)-2 374 375 /* Returns the nominal length of the buffer assuming it is termcap format, 376 * i.e., the continuation sequence is treated as a single character ":". 377 * 378 * There are several implementations of termcap which read the text into a 379 * fixed-size buffer. Generally they strip the newlines from the text, but may 380 * not do it until after the buffer is read. Also, "tc=" resolution may be 381 * expanded in the same buffer. This function is useful for measuring the size 382 * of the best fixed-buffer implementation; the worst case may be much worse. 383 */ 384 #ifdef TEST_TERMCAP_LENGTH 385 static int termcap_length(const char *src) 386 { 387 static const char pattern[] = ":\\\n\t:"; 388 389 int len = 0; 390 const char *const t = src + strlen(src); 391 392 while (*src != '\0') { 393 IGNORE_SEP_TRAIL(src, t, pattern); 394 src++; 395 len++; 396 } 397 return len; 398 } 399 #else 400 #define termcap_length(src) strlen(src) 401 #endif 402 403 static char * fmt_complex(char *dst, char *src, int level) 404 { 405 int percent = 0; 406 int n; 407 408 dst += strlen(dst); 409 while (*src != '\0') { 410 switch (*src) { 411 case '\\': 412 percent = 0; 413 *dst++ = *src++; 414 break; 415 case '%': 416 percent = 1; 417 break; 418 case '?': /* "if" */ 419 case 't': /* "then" */ 420 case 'e': /* "else" */ 421 if (percent) { 422 percent = 0; 423 dst[-1] = '\n'; 424 for (n = 0; n <= level; n++) 425 *dst++ = '\t'; 426 *dst++ = '%'; 427 *dst++ = *src; 428 *dst = '\0'; 429 if (*src++ == '?') { 430 src = fmt_complex(dst, src, level+1); 431 dst += strlen(dst); 432 } else if (level == 1) { 433 _nc_warning("%%%c without %%?", *src); 434 } 435 continue; 436 } 437 break; 438 case ';': /* "endif" */ 439 if (percent) { 440 percent = 0; 441 if (level > 1) { 442 dst[-1] = '\n'; 443 for (n = 0; n < level; n++) 444 *dst++ = '\t'; 445 *dst++ = '%'; 446 *dst++ = *src++; 447 *dst = '\0'; 448 return src; 449 } 450 _nc_warning("%%; without %%?"); 451 } 452 break; 453 default: 454 percent = 0; 455 break; 456 } 457 *dst++ = *src++; 458 } 459 *dst = '\0'; 460 return src; 461 } 462 463 int fmt_entry(TERMTYPE *tterm, 464 int (*pred)(int type, int idx), 465 bool suppress_untranslatable, 466 bool infodump, 467 int numbers) 468 { 469 int i, j; 470 char buffer[MAX_TERMINFO_LENGTH]; 471 NCURSES_CONST char *name; 472 int predval, len; 473 int num_bools = 0; 474 int num_values = 0; 475 int num_strings = 0; 476 bool outcount = 0; 477 478 #define WRAP_CONCAT \ 479 wrap_concat(buffer); \ 480 outcount = TRUE 481 482 len = 12; /* terminfo file-header */ 483 484 if (pred == 0) { 485 cur_type = tterm; 486 pred = dump_predicate; 487 } 488 489 append_output(0); 490 append_output(tterm->term_names); 491 append_output(separator); 492 column = out_used; 493 force_wrap(); 494 495 for_each_boolean(j,tterm) { 496 i = BoolIndirect(j); 497 name = ExtBoolname(tterm,i,bool_names); 498 499 if (!version_filter(BOOLEAN, i)) 500 continue; 501 else if ((outform == F_LITERAL || outform == F_TERMINFO || outform == F_VARIABLE) 502 && (OBSOLETE(name) && outform != F_LITERAL)) 503 continue; 504 505 predval = pred(BOOLEAN, i); 506 if (predval != FAIL) { 507 (void) strcpy(buffer, name); 508 if (predval <= 0) 509 (void) strcat(buffer, "@"); 510 else if (i + 1 > num_bools) 511 num_bools = i + 1; 512 WRAP_CONCAT; 513 } 514 } 515 516 if (column != INDENT) 517 force_wrap(); 518 519 for_each_number(j,tterm) { 520 i = NumIndirect(j); 521 name = ExtNumname(tterm,i,num_names); 522 523 if (!version_filter(NUMBER, i)) 524 continue; 525 else if ((outform == F_LITERAL || outform == F_TERMINFO || outform == F_VARIABLE) 526 && (OBSOLETE(name) && outform != F_LITERAL)) 527 continue; 528 529 predval = pred(NUMBER, i); 530 if (predval != FAIL) { 531 if (tterm->Numbers[i] < 0) { 532 sprintf(buffer, "%s@", name); 533 } else { 534 sprintf(buffer, "%s#%d", name, tterm->Numbers[i]); 535 if (i + 1 > num_values) 536 num_values = i + 1; 537 } 538 WRAP_CONCAT; 539 } 540 } 541 542 if (column != INDENT) 543 force_wrap(); 544 545 len += num_bools 546 + num_values * 2 547 + strlen(tterm->term_names) + 1; 548 if (len & 1) 549 len++; 550 551 repair_acsc(tterm); 552 for_each_string(j, tterm) { 553 i = StrIndirect(j); 554 name = ExtStrname(tterm,i,str_names); 555 556 if (!version_filter(STRING, i)) 557 continue; 558 else if ((outform == F_LITERAL || outform == F_TERMINFO || outform == F_VARIABLE) 559 && (OBSOLETE(name) && outform != F_LITERAL)) 560 continue; 561 562 /* 563 * Some older versions of vi want rmir/smir to be defined 564 * for ich/ich1 to work. If they're not defined, force 565 * them to be output as defined and empty. 566 */ 567 if (outform==F_TERMCAP) 568 { 569 #undef CUR 570 #define CUR tterm-> 571 if (insert_character || parm_ich) 572 { 573 if (&tterm->Strings[i] == &enter_insert_mode 574 && enter_insert_mode == ABSENT_STRING) 575 { 576 (void) strcpy(buffer, "im="); 577 goto catenate; 578 } 579 580 if (&tterm->Strings[i] == &exit_insert_mode 581 && exit_insert_mode == ABSENT_STRING) 582 { 583 (void) strcpy(buffer, "ei="); 584 goto catenate; 585 } 586 } 587 588 if (init_3string != 0 589 && termcap_reset != 0 590 && !strcmp(init_3string, termcap_reset)) 591 DISCARD(init_3string); 592 593 if (reset_2string != 0 594 && termcap_reset != 0 595 && !strcmp(reset_2string, termcap_reset)) 596 DISCARD(reset_2string); 597 } 598 599 predval = pred(STRING, i); 600 buffer[0] = '\0'; 601 if (predval != FAIL) { 602 if (tterm->Strings[i] != ABSENT_STRING 603 && i + 1 > num_strings) 604 num_strings = i + 1; 605 if (!VALID_STRING(tterm->Strings[i])) 606 sprintf(buffer, "%s@", name); 607 else if (outform == F_TERMCAP || outform == F_TCONVERR) 608 { 609 char *srccap = _nc_tic_expand(tterm->Strings[i], FALSE, numbers); 610 char *cv = _nc_infotocap(name, srccap, parametrized[i]); 611 612 if (cv == 0) 613 { 614 if (outform == F_TCONVERR) 615 sprintf(buffer, "%s=!!! %s WILL NOT CONVERT !!!", name, srccap); 616 else if (suppress_untranslatable) 617 continue; 618 else 619 sprintf(buffer, "..%s=%s", name, srccap); 620 } 621 else 622 sprintf(buffer, "%s=%s", name, cv); 623 len += strlen(tterm->Strings[i]) + 1; 624 } 625 else 626 { 627 char *src = _nc_tic_expand(tterm->Strings[i], outform==F_TERMINFO, numbers); 628 sprintf(buffer, "%s=", name); 629 if (pretty && outform==F_TERMINFO) 630 fmt_complex(buffer + strlen(buffer), src, 1); 631 else 632 strcat(buffer, src); 633 len += strlen(tterm->Strings[i]) + 1; 634 } 635 636 catenate: 637 WRAP_CONCAT; 638 } 639 } 640 len += num_strings * 2; 641 642 /* 643 * This piece of code should be an effective inverse of the functions 644 * postprocess_terminfo and postprocess_terminfo in parse_entry.c. 645 * Much more work should be done on this to support dumping termcaps. 646 */ 647 if (tversion == V_HPUX) 648 { 649 if (memory_lock) 650 { 651 (void) sprintf(buffer, "meml=%s", memory_lock); 652 WRAP_CONCAT; 653 } 654 if (memory_unlock) 655 { 656 (void) sprintf(buffer, "memu=%s", memory_unlock); 657 WRAP_CONCAT; 658 } 659 } 660 else if (tversion == V_AIX) 661 { 662 if (VALID_STRING(acs_chars)) 663 { 664 bool box_ok = TRUE; 665 const char *acstrans = "lqkxjmwuvtn"; 666 const char *cp; 667 char *tp, *sp, boxchars[11]; 668 669 tp = boxchars; 670 for (cp = acstrans; *cp; cp++) 671 { 672 sp = strchr(acs_chars, *cp); 673 if (sp) 674 *tp++ = sp[1]; 675 else 676 { 677 box_ok = FALSE; 678 break; 679 } 680 } 681 tp[0] = '\0'; 682 683 if (box_ok) 684 { 685 (void) strcpy(buffer, "box1="); 686 (void) strcat(buffer, _nc_tic_expand(boxchars, outform==F_TERMINFO, numbers)); 687 WRAP_CONCAT; 688 } 689 } 690 } 691 692 /* 693 * kludge: trim off trailer to avoid an extra blank line 694 * in infocmp -u output when there are no string differences 695 */ 696 if (outcount) 697 { 698 j = out_used; 699 if (j >= 2 700 && outbuf[j-1] == '\t' 701 && outbuf[j-2] == '\n') { 702 out_used -= 2; 703 } else if (j >= 4 704 && outbuf[j-1] == ':' 705 && outbuf[j-2] == '\t' 706 && outbuf[j-3] == '\n' 707 && outbuf[j-4] == '\\') { 708 out_used -= 4; 709 } 710 outbuf[out_used] = '\0'; 711 column = oldcol; 712 } 713 714 #if 0 715 fprintf(stderr, "num_bools = %d\n", num_bools); 716 fprintf(stderr, "num_values = %d\n", num_values); 717 fprintf(stderr, "num_strings = %d\n", num_strings); 718 fprintf(stderr, "term_names=%s, len=%d, strlen(outbuf)=%d, outbuf=%s\n", 719 tterm->term_names, len, out_used, outbuf); 720 #endif 721 /* 722 * Here's where we use infodump to trigger a more stringent length check 723 * for termcap-translation purposes. 724 * Return the length of the raw entry, without tc= expansions, 725 * It gives an idea of which entries are deadly to even *scan past*, 726 * as opposed to *use*. 727 */ 728 return(infodump ? len : termcap_length(outbuf)); 729 } 730 731 int dump_entry(TERMTYPE *tterm, bool limited, int numbers, int (*pred)(int type, int idx)) 732 /* dump a single entry */ 733 { 734 int len, critlen; 735 const char *legend; 736 bool infodump; 737 738 if (outform==F_TERMCAP || outform==F_TCONVERR) 739 { 740 critlen = MAX_TERMCAP_LENGTH; 741 legend = "older termcap"; 742 infodump = FALSE; 743 set_obsolete_termcaps(tterm); 744 } 745 else 746 { 747 critlen = MAX_TERMINFO_LENGTH; 748 legend = "terminfo"; 749 infodump = TRUE; 750 } 751 752 if (((len = fmt_entry(tterm, pred, FALSE, infodump, numbers)) > critlen) && limited) 753 { 754 (void) printf("# (untranslatable capabilities removed to fit entry within %d bytes)\n", 755 critlen); 756 if ((len = fmt_entry(tterm, pred, TRUE, infodump, numbers)) > critlen) 757 { 758 /* 759 * We pick on sgr because it's a nice long string capability that 760 * is really just an optimization hack. 761 */ 762 char *oldsgr = set_attributes; 763 set_attributes = ABSENT_STRING; 764 (void) printf("# (sgr removed to fit entry within %d bytes)\n", 765 critlen); 766 if ((len = fmt_entry(tterm, pred, TRUE, infodump, numbers)) > critlen) 767 { 768 int oldversion = tversion; 769 770 tversion = V_BSD; 771 (void) printf("# (terminfo-only capabilities suppressed to fit entry within %d bytes)\n", 772 critlen); 773 774 if ((len = fmt_entry(tterm, pred, TRUE, infodump, numbers)) > critlen) 775 { 776 (void) fprintf(stderr, 777 "warning: %s entry is %d bytes long\n", 778 _nc_first_name(tterm->term_names), 779 len); 780 (void) printf( 781 "# WARNING: this entry, %d bytes long, may core-dump %s libraries!\n", 782 len, legend); 783 } 784 tversion = oldversion; 785 } 786 set_attributes = oldsgr; 787 } 788 } 789 790 (void) fputs(outbuf, stdout); 791 return len; 792 } 793 794 int dump_uses(const char *name, bool infodump) 795 /* dump "use=" clauses in the appropriate format */ 796 { 797 char buffer[MAX_TERMINFO_LENGTH]; 798 799 append_output(0); 800 (void)sprintf(buffer, "%s%s", infodump ? "use=" : "tc=", name); 801 wrap_concat(buffer); 802 (void) fputs(outbuf, stdout); 803 return out_used; 804 } 805 806 void compare_entry(void (*hook)(int t, int i, const char *name), TERMTYPE *tp GCC_UNUSED) 807 /* compare two entries */ 808 { 809 int i, j; 810 NCURSES_CONST char * name; 811 812 (void) fputs(" comparing booleans.\n", stdout); 813 for_each_boolean(j,tp) 814 { 815 i = BoolIndirect(j); 816 name = ExtBoolname(tp,i,bool_names); 817 818 if ((outform == F_LITERAL || outform == F_TERMINFO || outform == F_VARIABLE) 819 && (OBSOLETE(name) && outform != F_LITERAL)) 820 continue; 821 822 (*hook)(BOOLEAN, i, name); 823 } 824 825 (void) fputs(" comparing numbers.\n", stdout); 826 for_each_number(j,tp) 827 { 828 i = NumIndirect(j); 829 name = ExtNumname(tp,i,num_names); 830 831 if ((outform==F_LITERAL || outform==F_TERMINFO || outform==F_VARIABLE) 832 && (OBSOLETE(name) && outform != F_LITERAL)) 833 continue; 834 835 (*hook)(NUMBER, i, name); 836 } 837 838 (void) fputs(" comparing strings.\n", stdout); 839 for_each_string(j,tp) 840 { 841 i = StrIndirect(j); 842 name = ExtStrname(tp,i,str_names); 843 844 if ((outform==F_LITERAL || outform==F_TERMINFO || outform==F_VARIABLE) 845 && (OBSOLETE(name) && outform != F_LITERAL)) 846 continue; 847 848 (*hook)(STRING, i, name); 849 } 850 } 851 852 #define NOTSET(s) ((s) == 0) 853 854 /* 855 * This bit of legerdemain turns all the terminfo variable names into 856 * references to locations in the arrays Booleans, Numbers, and Strings --- 857 * precisely what's needed. 858 */ 859 #undef CUR 860 #define CUR tp-> 861 862 static void set_obsolete_termcaps(TERMTYPE *tp) 863 { 864 #include "capdefaults.c" 865 } 866 867 /* 868 * Convert an alternate-character-set string to canonical form: sorted and 869 * unique. 870 */ 871 static void repair_acsc(TERMTYPE *tp) 872 { 873 if (VALID_STRING(acs_chars)) { 874 size_t n, m; 875 char mapped[256]; 876 char extra = 0; 877 unsigned source; 878 unsigned target; 879 bool fix_needed = FALSE; 880 881 for (n = 0, source = 0; acs_chars[n] != 0; n++) { 882 target = acs_chars[n]; 883 if (source >= target) { 884 fix_needed = TRUE; 885 break; 886 } 887 source = target; 888 if (acs_chars[n+1]) 889 n++; 890 } 891 if (fix_needed) { 892 memset(mapped, 0, sizeof(mapped)); 893 for (n = 0; acs_chars[n] != 0; n++) { 894 source = acs_chars[n]; 895 if ((target = (unsigned char)acs_chars[n+1]) != 0) { 896 mapped[source] = target; 897 n++; 898 } else { 899 extra = source; 900 } 901 } 902 for (n = m = 0; n < sizeof(mapped); n++) { 903 if (mapped[n]) { 904 acs_chars[m++] = n; 905 acs_chars[m++] = mapped[n]; 906 } 907 } 908 if (extra) 909 acs_chars[m++] = extra; /* garbage in, garbage out */ 910 acs_chars[m] = 0; 911 } 912 } 913 } 914