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