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