1 /**************************************************************************** 2 * Copyright (c) 1998-2011,2012 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 * and: Thomas E. Dickey 1996-on * 33 ****************************************************************************/ 34 35 /* 36 * parse_entry.c -- compile one terminfo or termcap entry 37 * 38 * Get an exact in-core representation of an entry. Don't 39 * try to resolve use or tc capabilities, that is someone 40 * else's job. Depends on the lexical analyzer to get tokens 41 * from the input stream. 42 */ 43 44 #define __INTERNAL_CAPS_VISIBLE 45 #include <curses.priv.h> 46 47 #include <ctype.h> 48 #include <tic.h> 49 50 MODULE_ID("$Id: parse_entry.c,v 1.80 2015/04/04 14:18:38 tom Exp $") 51 52 #ifdef LINT 53 static short const parametrized[] = 54 {0}; 55 #else 56 #include <parametrized.h> 57 #endif 58 59 static void postprocess_termcap(TERMTYPE *, bool); 60 static void postprocess_terminfo(TERMTYPE *); 61 static struct name_table_entry const *lookup_fullname(const char *name); 62 63 #if NCURSES_XNAMES 64 65 static struct name_table_entry const * 66 _nc_extend_names(ENTRY * entryp, char *name, int token_type) 67 { 68 static struct name_table_entry temp; 69 TERMTYPE *tp = &(entryp->tterm); 70 unsigned offset = 0; 71 unsigned actual; 72 unsigned tindex; 73 unsigned first, last, n; 74 bool found; 75 76 switch (token_type) { 77 case BOOLEAN: 78 first = 0; 79 last = tp->ext_Booleans; 80 offset = tp->ext_Booleans; 81 tindex = tp->num_Booleans; 82 break; 83 case NUMBER: 84 first = tp->ext_Booleans; 85 last = tp->ext_Numbers + first; 86 offset = (unsigned) (tp->ext_Booleans + tp->ext_Numbers); 87 tindex = tp->num_Numbers; 88 break; 89 case STRING: 90 first = (unsigned) (tp->ext_Booleans + tp->ext_Numbers); 91 last = tp->ext_Strings + first; 92 offset = (unsigned) (tp->ext_Booleans + tp->ext_Numbers + tp->ext_Strings); 93 tindex = tp->num_Strings; 94 break; 95 case CANCEL: 96 actual = NUM_EXT_NAMES(tp); 97 for (n = 0; n < actual; n++) { 98 if (!strcmp(name, tp->ext_Names[n])) { 99 if (n > (unsigned) (tp->ext_Booleans + tp->ext_Numbers)) { 100 token_type = STRING; 101 } else if (n > tp->ext_Booleans) { 102 token_type = NUMBER; 103 } else { 104 token_type = BOOLEAN; 105 } 106 return _nc_extend_names(entryp, name, token_type); 107 } 108 } 109 /* Well, we are given a cancel for a name that we don't recognize */ 110 return _nc_extend_names(entryp, name, STRING); 111 default: 112 return 0; 113 } 114 115 /* Adjust the 'offset' (insertion-point) to keep the lists of extended 116 * names sorted. 117 */ 118 for (n = first, found = FALSE; n < last; n++) { 119 int cmp = strcmp(tp->ext_Names[n], name); 120 if (cmp == 0) 121 found = TRUE; 122 if (cmp >= 0) { 123 offset = n; 124 tindex = n - first; 125 switch (token_type) { 126 case BOOLEAN: 127 tindex += BOOLCOUNT; 128 break; 129 case NUMBER: 130 tindex += NUMCOUNT; 131 break; 132 case STRING: 133 tindex += STRCOUNT; 134 break; 135 } 136 break; 137 } 138 } 139 140 #define for_each_value(max) \ 141 for (last = (unsigned) (max - 1); last > tindex; last--) 142 143 if (!found) { 144 switch (token_type) { 145 case BOOLEAN: 146 tp->ext_Booleans++; 147 tp->num_Booleans++; 148 TYPE_REALLOC(NCURSES_SBOOL, tp->num_Booleans, tp->Booleans); 149 for_each_value(tp->num_Booleans) 150 tp->Booleans[last] = tp->Booleans[last - 1]; 151 break; 152 case NUMBER: 153 tp->ext_Numbers++; 154 tp->num_Numbers++; 155 TYPE_REALLOC(short, tp->num_Numbers, tp->Numbers); 156 for_each_value(tp->num_Numbers) 157 tp->Numbers[last] = tp->Numbers[last - 1]; 158 break; 159 case STRING: 160 tp->ext_Strings++; 161 tp->num_Strings++; 162 TYPE_REALLOC(char *, tp->num_Strings, tp->Strings); 163 for_each_value(tp->num_Strings) 164 tp->Strings[last] = tp->Strings[last - 1]; 165 break; 166 } 167 actual = NUM_EXT_NAMES(tp); 168 TYPE_REALLOC(char *, actual, tp->ext_Names); 169 while (--actual > offset) 170 tp->ext_Names[actual] = tp->ext_Names[actual - 1]; 171 tp->ext_Names[offset] = _nc_save_str(name); 172 } 173 174 temp.nte_name = tp->ext_Names[offset]; 175 temp.nte_type = token_type; 176 temp.nte_index = (short) tindex; 177 temp.nte_link = -1; 178 179 return &temp; 180 } 181 #endif /* NCURSES_XNAMES */ 182 183 /* 184 * int 185 * _nc_parse_entry(entry, literal, silent) 186 * 187 * Compile one entry. Doesn't try to resolve use or tc capabilities. 188 * 189 * found-forward-use = FALSE 190 * re-initialise internal arrays 191 * get_token(); 192 * if the token was not a name in column 1, complain and die 193 * save names in entry's string table 194 * while (get_token() is not EOF and not NAMES) 195 * check for existence and type-correctness 196 * enter cap into structure 197 * if STRING 198 * save string in entry's string table 199 * push back token 200 */ 201 202 #define BAD_TC_USAGE if (!bad_tc_usage) \ 203 { bad_tc_usage = TRUE; \ 204 _nc_warning("Legacy termcap allows only a trailing tc= clause"); } 205 206 #define MAX_NUMBER 0x7fff /* positive shorts only */ 207 208 NCURSES_EXPORT(int) 209 _nc_parse_entry(struct entry *entryp, int literal, bool silent) 210 { 211 int token_type; 212 struct name_table_entry const *entry_ptr; 213 char *ptr, *base; 214 bool bad_tc_usage = FALSE; 215 216 token_type = _nc_get_token(silent); 217 218 if (token_type == EOF) 219 return (EOF); 220 if (token_type != NAMES) 221 _nc_err_abort("Entry does not start with terminal names in column one"); 222 223 _nc_init_entry(&entryp->tterm); 224 225 entryp->cstart = _nc_comment_start; 226 entryp->cend = _nc_comment_end; 227 entryp->startline = _nc_start_line; 228 DEBUG(2, ("Comment range is %ld to %ld", entryp->cstart, entryp->cend)); 229 230 /* 231 * Strip off the 2-character termcap name, if present. Originally termcap 232 * used that as an indexing aid. We can retain 2-character terminfo names, 233 * but note that they would be lost if we translate to/from termcap. This 234 * feature is supposedly obsolete since "newer" BSD implementations do not 235 * use it; however our reference for this feature is SunOS 4.x, which 236 * implemented it. Note that the resulting terminal type was never the 237 * 2-character name, but was instead the first alias after that. 238 */ 239 ptr = _nc_curr_token.tk_name; 240 if (_nc_syntax == SYN_TERMCAP 241 #if NCURSES_XNAMES 242 && !_nc_user_definable 243 #endif 244 ) { 245 if (ptr[2] == '|') { 246 ptr += 3; 247 _nc_curr_token.tk_name[2] = '\0'; 248 } 249 } 250 251 entryp->tterm.str_table = entryp->tterm.term_names = _nc_save_str(ptr); 252 253 if (entryp->tterm.str_table == 0) 254 return (ERR); 255 256 DEBUG(1, ("Starting '%s'", ptr)); 257 258 /* 259 * We do this because the one-token lookahead in the parse loop 260 * results in the terminal type getting prematurely set to correspond 261 * to that of the next entry. 262 */ 263 _nc_set_type(_nc_first_name(entryp->tterm.term_names)); 264 265 /* check for overly-long names and aliases */ 266 for (base = entryp->tterm.term_names; (ptr = strchr(base, '|')) != 0; 267 base = ptr + 1) { 268 if (ptr - base > MAX_ALIAS) { 269 _nc_warning("%s `%.*s' may be too long", 270 (base == entryp->tterm.term_names) 271 ? "primary name" 272 : "alias", 273 (int) (ptr - base), base); 274 } 275 } 276 277 entryp->nuses = 0; 278 279 for (token_type = _nc_get_token(silent); 280 token_type != EOF && token_type != NAMES; 281 token_type = _nc_get_token(silent)) { 282 bool is_use = (strcmp(_nc_curr_token.tk_name, "use") == 0); 283 bool is_tc = !is_use && (strcmp(_nc_curr_token.tk_name, "tc") == 0); 284 if (is_use || is_tc) { 285 entryp->uses[entryp->nuses].name = _nc_save_str(_nc_curr_token.tk_valstring); 286 entryp->uses[entryp->nuses].line = _nc_curr_line; 287 entryp->nuses++; 288 if (entryp->nuses > 1 && is_tc) { 289 BAD_TC_USAGE 290 } 291 } else { 292 /* normal token lookup */ 293 entry_ptr = _nc_find_entry(_nc_curr_token.tk_name, 294 _nc_get_hash_table(_nc_syntax)); 295 296 /* 297 * Our kluge to handle aliasing. The reason it's done 298 * this ugly way, with a linear search, is so the hashing 299 * machinery doesn't have to be made really complicated 300 * (also we get better warnings this way). No point in 301 * making this case fast, aliased caps aren't common now 302 * and will get rarer. 303 */ 304 if (entry_ptr == NOTFOUND) { 305 const struct alias *ap; 306 307 if (_nc_syntax == SYN_TERMCAP) { 308 if (entryp->nuses != 0) { 309 BAD_TC_USAGE 310 } 311 for (ap = _nc_get_alias_table(TRUE); ap->from; ap++) 312 if (strcmp(ap->from, _nc_curr_token.tk_name) == 0) { 313 if (ap->to == (char *) 0) { 314 _nc_warning("%s (%s termcap extension) ignored", 315 ap->from, ap->source); 316 goto nexttok; 317 } 318 319 entry_ptr = _nc_find_entry(ap->to, 320 _nc_get_hash_table(TRUE)); 321 if (entry_ptr && !silent) 322 _nc_warning("%s (%s termcap extension) aliased to %s", 323 ap->from, ap->source, ap->to); 324 break; 325 } 326 } else { /* if (_nc_syntax == SYN_TERMINFO) */ 327 for (ap = _nc_get_alias_table(FALSE); ap->from; ap++) 328 if (strcmp(ap->from, _nc_curr_token.tk_name) == 0) { 329 if (ap->to == (char *) 0) { 330 _nc_warning("%s (%s terminfo extension) ignored", 331 ap->from, ap->source); 332 goto nexttok; 333 } 334 335 entry_ptr = _nc_find_entry(ap->to, 336 _nc_get_hash_table(FALSE)); 337 if (entry_ptr && !silent) 338 _nc_warning("%s (%s terminfo extension) aliased to %s", 339 ap->from, ap->source, ap->to); 340 break; 341 } 342 343 if (entry_ptr == NOTFOUND) { 344 entry_ptr = lookup_fullname(_nc_curr_token.tk_name); 345 } 346 } 347 } 348 #if NCURSES_XNAMES 349 /* 350 * If we have extended-names active, we will automatically 351 * define a name based on its context. 352 */ 353 if (entry_ptr == NOTFOUND 354 && _nc_user_definable 355 && (entry_ptr = _nc_extend_names(entryp, 356 _nc_curr_token.tk_name, 357 token_type)) != 0) { 358 if (_nc_tracing >= DEBUG_LEVEL(1)) 359 _nc_warning("extended capability '%s'", _nc_curr_token.tk_name); 360 } 361 #endif /* NCURSES_XNAMES */ 362 363 /* can't find this cap name, not even as an alias */ 364 if (entry_ptr == NOTFOUND) { 365 if (!silent) 366 _nc_warning("unknown capability '%s'", 367 _nc_curr_token.tk_name); 368 continue; 369 } 370 371 /* deal with bad type/value combinations. */ 372 if (token_type != CANCEL && entry_ptr->nte_type != token_type) { 373 /* 374 * Nasty special cases here handle situations in which type 375 * information can resolve name clashes. Normal lookup 376 * finds the last instance in the capability table of a 377 * given name, regardless of type. find_type_entry looks 378 * for a first matching instance with given type. So as 379 * long as all ambiguous names occur in pairs of distinct 380 * type, this will do the job. 381 */ 382 383 if (token_type == NUMBER 384 && !strcmp("ma", _nc_curr_token.tk_name)) { 385 /* tell max_attributes from arrow_key_map */ 386 entry_ptr = _nc_find_type_entry("ma", NUMBER, 387 _nc_syntax != 0); 388 assert(entry_ptr != 0); 389 390 } else if (token_type == STRING 391 && !strcmp("MT", _nc_curr_token.tk_name)) { 392 /* map terminfo's string MT to MT */ 393 entry_ptr = _nc_find_type_entry("MT", STRING, 394 _nc_syntax != 0); 395 assert(entry_ptr != 0); 396 397 } else if (token_type == BOOLEAN 398 && entry_ptr->nte_type == STRING) { 399 /* treat strings without following "=" as empty strings */ 400 token_type = STRING; 401 } else { 402 /* we couldn't recover; skip this token */ 403 if (!silent) { 404 const char *type_name; 405 switch (entry_ptr->nte_type) { 406 case BOOLEAN: 407 type_name = "boolean"; 408 break; 409 case STRING: 410 type_name = "string"; 411 break; 412 case NUMBER: 413 type_name = "numeric"; 414 break; 415 default: 416 type_name = "unknown"; 417 break; 418 } 419 _nc_warning("wrong type used for %s capability '%s'", 420 type_name, _nc_curr_token.tk_name); 421 } 422 continue; 423 } 424 } 425 426 /* now we know that the type/value combination is OK */ 427 switch (token_type) { 428 case CANCEL: 429 switch (entry_ptr->nte_type) { 430 case BOOLEAN: 431 entryp->tterm.Booleans[entry_ptr->nte_index] = CANCELLED_BOOLEAN; 432 break; 433 434 case NUMBER: 435 entryp->tterm.Numbers[entry_ptr->nte_index] = CANCELLED_NUMERIC; 436 break; 437 438 case STRING: 439 entryp->tterm.Strings[entry_ptr->nte_index] = CANCELLED_STRING; 440 break; 441 } 442 break; 443 444 case BOOLEAN: 445 entryp->tterm.Booleans[entry_ptr->nte_index] = TRUE; 446 break; 447 448 case NUMBER: 449 if (_nc_curr_token.tk_valnumber > MAX_NUMBER) { 450 entryp->tterm.Numbers[entry_ptr->nte_index] = MAX_NUMBER; 451 } else { 452 entryp->tterm.Numbers[entry_ptr->nte_index] = 453 (short) _nc_curr_token.tk_valnumber; 454 } 455 break; 456 457 case STRING: 458 ptr = _nc_curr_token.tk_valstring; 459 if (_nc_syntax == SYN_TERMCAP) 460 ptr = _nc_captoinfo(_nc_curr_token.tk_name, 461 ptr, 462 parametrized[entry_ptr->nte_index]); 463 entryp->tterm.Strings[entry_ptr->nte_index] = _nc_save_str(ptr); 464 break; 465 466 default: 467 if (!silent) 468 _nc_warning("unknown token type"); 469 _nc_panic_mode((char) ((_nc_syntax == SYN_TERMCAP) ? ':' : ',')); 470 continue; 471 } 472 } /* end else cur_token.name != "use" */ 473 nexttok: 474 continue; /* cannot have a label w/o statement */ 475 } /* endwhile (not EOF and not NAMES) */ 476 477 _nc_push_token(token_type); 478 _nc_set_type(_nc_first_name(entryp->tterm.term_names)); 479 480 /* 481 * Try to deduce as much as possible from extension capabilities 482 * (this includes obsolete BSD capabilities). Sigh...it would be more 483 * space-efficient to call this after use resolution, but it has 484 * to be done before entry allocation is wrapped up. 485 */ 486 if (!literal) { 487 if (_nc_syntax == SYN_TERMCAP) { 488 bool has_base_entry = FALSE; 489 unsigned i; 490 491 /* 492 * Don't insert defaults if this is a `+' entry meant only 493 * for inclusion in other entries (not sure termcap ever 494 * had these, actually). 495 */ 496 if (strchr(entryp->tterm.term_names, '+')) 497 has_base_entry = TRUE; 498 else 499 /* 500 * Otherwise, look for a base entry that will already 501 * have picked up defaults via translation. 502 */ 503 for (i = 0; i < entryp->nuses; i++) 504 if (!strchr((char *) entryp->uses[i].name, '+')) 505 has_base_entry = TRUE; 506 507 postprocess_termcap(&entryp->tterm, has_base_entry); 508 } else 509 postprocess_terminfo(&entryp->tterm); 510 } 511 _nc_wrap_entry(entryp, FALSE); 512 513 return (OK); 514 } 515 516 NCURSES_EXPORT(int) 517 _nc_capcmp(const char *s, const char *t) 518 /* compare two string capabilities, stripping out padding */ 519 { 520 if (!VALID_STRING(s) && !VALID_STRING(t)) 521 return (0); 522 else if (!VALID_STRING(s) || !VALID_STRING(t)) 523 return (1); 524 525 for (;;) { 526 if (s[0] == '$' && s[1] == '<') { 527 for (s += 2;; s++) 528 if (!(isdigit(UChar(*s)) 529 || *s == '.' 530 || *s == '*' 531 || *s == '/' 532 || *s == '>')) 533 break; 534 } 535 536 if (t[0] == '$' && t[1] == '<') { 537 for (t += 2;; t++) 538 if (!(isdigit(UChar(*t)) 539 || *t == '.' 540 || *t == '*' 541 || *t == '/' 542 || *t == '>')) 543 break; 544 } 545 546 /* we've now pushed s and t past any padding they were pointing at */ 547 548 if (*s == '\0' && *t == '\0') 549 return (0); 550 551 if (*s != *t) 552 return (*t - *s); 553 554 /* else *s == *t but one is not NUL, so continue */ 555 s++, t++; 556 } 557 } 558 559 static void 560 append_acs0(string_desc * dst, int code, int src) 561 { 562 if (src != 0) { 563 char temp[3]; 564 temp[0] = (char) code; 565 temp[1] = (char) src; 566 temp[2] = 0; 567 _nc_safe_strcat(dst, temp); 568 } 569 } 570 571 static void 572 append_acs(string_desc * dst, int code, char *src) 573 { 574 if (src != 0 && strlen(src) == 1) { 575 append_acs0(dst, code, *src); 576 } 577 } 578 579 /* 580 * The ko capability, if present, consists of a comma-separated capability 581 * list. For each capability, we may assume there is a keycap that sends the 582 * string which is the value of that capability. 583 */ 584 #define DATA(from, to) { { from }, { to } } 585 typedef struct { 586 const char from[3]; 587 const char to[6]; 588 } assoc; 589 static assoc const ko_xlate[] = 590 { 591 DATA("al", "kil1"), /* insert line key -> KEY_IL */ 592 DATA("bt", "kcbt"), /* back tab -> KEY_BTAB */ 593 DATA("cd", "ked"), /* clear-to-eos key -> KEY_EOL */ 594 DATA("ce", "kel"), /* clear-to-eol key -> KEY_EOS */ 595 DATA("cl", "kclr"), /* clear key -> KEY_CLEAR */ 596 DATA("ct", "tbc"), /* clear all tabs -> KEY_CATAB */ 597 DATA("dc", "kdch1"), /* delete char -> KEY_DC */ 598 DATA("dl", "kdl1"), /* delete line -> KEY_DL */ 599 DATA("do", "kcud1"), /* down key -> KEY_DOWN */ 600 DATA("ei", "krmir"), /* exit insert key -> KEY_EIC */ 601 DATA("ho", "khome"), /* home key -> KEY_HOME */ 602 DATA("ic", "kich1"), /* insert char key -> KEY_IC */ 603 DATA("im", "kIC"), /* insert-mode key -> KEY_SIC */ 604 DATA("le", "kcub1"), /* le key -> KEY_LEFT */ 605 DATA("nd", "kcuf1"), /* nd key -> KEY_RIGHT */ 606 DATA("nl", "kent"), /* new line key -> KEY_ENTER */ 607 DATA("st", "khts"), /* set-tab key -> KEY_STAB */ 608 DATA("ta", ""), 609 DATA("up", "kcuu1"), /* up-arrow key -> KEY_UP */ 610 }; 611 612 /* 613 * This routine fills in string caps that either had defaults under 614 * termcap or can be manufactured from obsolete termcap capabilities. 615 * It was lifted from Ross Ridge's mytinfo package. 616 */ 617 618 static const char C_CR[] = "\r"; 619 static const char C_LF[] = "\n"; 620 static const char C_BS[] = "\b"; 621 static const char C_HT[] = "\t"; 622 623 /* 624 * Note that WANTED and PRESENT are not simple inverses! If a capability 625 * has been explicitly cancelled, it's not considered WANTED. 626 */ 627 #define WANTED(s) ((s) == ABSENT_STRING) 628 #define PRESENT(s) (((s) != ABSENT_STRING) && ((s) != CANCELLED_STRING)) 629 630 /* 631 * This bit of legerdemain turns all the terminfo variable names into 632 * references to locations in the arrays Booleans, Numbers, and Strings --- 633 * precisely what's needed. 634 */ 635 636 #undef CUR 637 #define CUR tp-> 638 639 static void 640 postprocess_termcap(TERMTYPE *tp, bool has_base) 641 { 642 char buf[MAX_LINE * 2 + 2]; 643 string_desc result; 644 645 /* 646 * TERMCAP DEFAULTS AND OBSOLETE-CAPABILITY TRANSLATIONS 647 * 648 * This first part of the code is the functional inverse of the 649 * fragment in capdefaults.c. 650 * ---------------------------------------------------------------------- 651 */ 652 653 /* if there was a tc entry, assume we picked up defaults via that */ 654 if (!has_base) { 655 if (WANTED(init_3string) && termcap_init2) 656 init_3string = _nc_save_str(termcap_init2); 657 658 if (WANTED(reset_2string) && termcap_reset) 659 reset_2string = _nc_save_str(termcap_reset); 660 661 if (WANTED(carriage_return)) { 662 if (carriage_return_delay > 0) { 663 _nc_SPRINTF(buf, _nc_SLIMIT(sizeof(buf)) 664 "%s$<%d>", C_CR, carriage_return_delay); 665 carriage_return = _nc_save_str(buf); 666 } else 667 carriage_return = _nc_save_str(C_CR); 668 } 669 if (WANTED(cursor_left)) { 670 if (backspace_delay > 0) { 671 _nc_SPRINTF(buf, _nc_SLIMIT(sizeof(buf)) 672 "%s$<%d>", C_BS, backspace_delay); 673 cursor_left = _nc_save_str(buf); 674 } else if (backspaces_with_bs == 1) 675 cursor_left = _nc_save_str(C_BS); 676 else if (PRESENT(backspace_if_not_bs)) 677 cursor_left = backspace_if_not_bs; 678 } 679 /* vi doesn't use "do", but it does seem to use nl (or '\n') instead */ 680 if (WANTED(cursor_down)) { 681 if (PRESENT(linefeed_if_not_lf)) 682 cursor_down = linefeed_if_not_lf; 683 else if (linefeed_is_newline != 1) { 684 if (new_line_delay > 0) { 685 _nc_SPRINTF(buf, _nc_SLIMIT(sizeof(buf)) 686 "%s$<%d>", C_LF, new_line_delay); 687 cursor_down = _nc_save_str(buf); 688 } else 689 cursor_down = _nc_save_str(C_LF); 690 } 691 } 692 if (WANTED(scroll_forward) && crt_no_scrolling != 1) { 693 if (PRESENT(linefeed_if_not_lf)) 694 cursor_down = linefeed_if_not_lf; 695 else if (linefeed_is_newline != 1) { 696 if (new_line_delay > 0) { 697 _nc_SPRINTF(buf, _nc_SLIMIT(sizeof(buf)) 698 "%s$<%d>", C_LF, new_line_delay); 699 scroll_forward = _nc_save_str(buf); 700 } else 701 scroll_forward = _nc_save_str(C_LF); 702 } 703 } 704 if (WANTED(newline)) { 705 if (linefeed_is_newline == 1) { 706 if (new_line_delay > 0) { 707 _nc_SPRINTF(buf, _nc_SLIMIT(sizeof(buf)) 708 "%s$<%d>", C_LF, new_line_delay); 709 newline = _nc_save_str(buf); 710 } else 711 newline = _nc_save_str(C_LF); 712 } else if (PRESENT(carriage_return) && PRESENT(scroll_forward)) { 713 _nc_str_init(&result, buf, sizeof(buf)); 714 if (_nc_safe_strcat(&result, carriage_return) 715 && _nc_safe_strcat(&result, scroll_forward)) 716 newline = _nc_save_str(buf); 717 } else if (PRESENT(carriage_return) && PRESENT(cursor_down)) { 718 _nc_str_init(&result, buf, sizeof(buf)); 719 if (_nc_safe_strcat(&result, carriage_return) 720 && _nc_safe_strcat(&result, cursor_down)) 721 newline = _nc_save_str(buf); 722 } 723 } 724 } 725 726 /* 727 * Inverse of capdefaults.c code ends here. 728 * ---------------------------------------------------------------------- 729 * 730 * TERMCAP-TO TERMINFO MAPPINGS FOR SOURCE TRANSLATION 731 * 732 * These translations will *not* be inverted by tgetent(). 733 */ 734 735 if (!has_base) { 736 /* 737 * We wait until now to decide if we've got a working cr because even 738 * one that doesn't work can be used for newline. Unfortunately the 739 * space allocated for it is wasted. 740 */ 741 if (return_does_clr_eol == 1 || no_correctly_working_cr == 1) 742 carriage_return = ABSENT_STRING; 743 744 /* 745 * Supposedly most termcap entries have ta now and '\t' is no longer a 746 * default, but it doesn't seem to be true... 747 */ 748 if (WANTED(tab)) { 749 if (horizontal_tab_delay > 0) { 750 _nc_SPRINTF(buf, _nc_SLIMIT(sizeof(buf)) 751 "%s$<%d>", C_HT, horizontal_tab_delay); 752 tab = _nc_save_str(buf); 753 } else 754 tab = _nc_save_str(C_HT); 755 } 756 if (init_tabs == ABSENT_NUMERIC && has_hardware_tabs == TRUE) 757 init_tabs = 8; 758 759 /* 760 * Assume we can beep with ^G unless we're given bl@. 761 */ 762 if (WANTED(bell)) 763 bell = _nc_save_str("\007"); 764 } 765 766 /* 767 * Translate the old termcap :pt: capability to it#8 + ht=\t 768 */ 769 if (has_hardware_tabs == TRUE) { 770 if (init_tabs != 8 && init_tabs != ABSENT_NUMERIC) 771 _nc_warning("hardware tabs with a width other than 8: %d", init_tabs); 772 else { 773 if (tab && _nc_capcmp(tab, C_HT)) 774 _nc_warning("hardware tabs with a non-^I tab string %s", 775 _nc_visbuf(tab)); 776 else { 777 if (WANTED(tab)) 778 tab = _nc_save_str(C_HT); 779 init_tabs = 8; 780 } 781 } 782 } 783 /* 784 * Now translate the ko capability, if there is one. This 785 * isn't from mytinfo... 786 */ 787 if (PRESENT(other_non_function_keys)) { 788 char *base; 789 char *bp, *cp, *dp; 790 struct name_table_entry const *from_ptr; 791 struct name_table_entry const *to_ptr; 792 char buf2[MAX_TERMINFO_LENGTH]; 793 bool foundim; 794 795 /* we're going to use this for a special case later */ 796 dp = strchr(other_non_function_keys, 'i'); 797 foundim = (dp != 0) && (dp[1] == 'm'); 798 799 /* look at each comma-separated capability in the ko string... */ 800 for (base = other_non_function_keys; 801 (cp = strchr(base, ',')) != 0; 802 base = cp + 1) { 803 size_t len = (unsigned) (cp - base); 804 size_t n; 805 assoc const *ap = 0; 806 807 for (n = 0; n < SIZEOF(ko_xlate); ++n) { 808 if (len == strlen(ko_xlate[n].from) 809 && strncmp(ko_xlate[n].from, base, len) == 0) { 810 ap = ko_xlate + n; 811 break; 812 } 813 } 814 if (ap == 0) { 815 _nc_warning("unknown capability `%.*s' in ko string", 816 (int) len, base); 817 continue; 818 } else if (ap->to[0] == '\0') /* ignore it */ 819 continue; 820 821 /* now we know we found a match in ko_table, so... */ 822 823 from_ptr = _nc_find_entry(ap->from, _nc_get_hash_table(TRUE)); 824 to_ptr = _nc_find_entry(ap->to, _nc_get_hash_table(FALSE)); 825 826 if (!from_ptr || !to_ptr) /* should never happen! */ 827 _nc_err_abort("ko translation table is invalid, I give up"); 828 829 if (WANTED(tp->Strings[from_ptr->nte_index])) { 830 _nc_warning("no value for ko capability %s", ap->from); 831 continue; 832 } 833 834 if (tp->Strings[to_ptr->nte_index]) { 835 /* There's no point in warning about it if it's the same 836 * string; that's just an inefficiency. 837 */ 838 if (strcmp( 839 tp->Strings[from_ptr->nte_index], 840 tp->Strings[to_ptr->nte_index]) != 0) 841 _nc_warning("%s (%s) already has an explicit value %s, ignoring ko", 842 ap->to, ap->from, 843 _nc_visbuf(tp->Strings[to_ptr->nte_index])); 844 continue; 845 } 846 847 /* 848 * The magic moment -- copy the mapped key string over, 849 * stripping out padding. 850 */ 851 for (dp = buf2, bp = tp->Strings[from_ptr->nte_index]; *bp; bp++) { 852 if (bp[0] == '$' && bp[1] == '<') { 853 while (*bp && *bp != '>') { 854 ++bp; 855 } 856 } else 857 *dp++ = *bp; 858 } 859 *dp = '\0'; 860 861 tp->Strings[to_ptr->nte_index] = _nc_save_str(buf2); 862 } 863 864 /* 865 * Note: ko=im and ko=ic both want to grab the `Insert' 866 * keycap. There's a kich1 but no ksmir, so the ic capability 867 * got mapped to kich1 and im to kIC to avoid a collision. 868 * If the description has im but not ic, hack kIC back to kich1. 869 */ 870 if (foundim && WANTED(key_ic) && key_sic) { 871 key_ic = key_sic; 872 key_sic = ABSENT_STRING; 873 } 874 } 875 876 if (!has_base) { 877 if (!hard_copy) { 878 if (WANTED(key_backspace)) 879 key_backspace = _nc_save_str(C_BS); 880 if (WANTED(key_left)) 881 key_left = _nc_save_str(C_BS); 882 if (WANTED(key_down)) 883 key_down = _nc_save_str(C_LF); 884 } 885 } 886 887 /* 888 * Translate XENIX forms characters. 889 */ 890 if (PRESENT(acs_ulcorner) || 891 PRESENT(acs_llcorner) || 892 PRESENT(acs_urcorner) || 893 PRESENT(acs_lrcorner) || 894 PRESENT(acs_ltee) || 895 PRESENT(acs_rtee) || 896 PRESENT(acs_btee) || 897 PRESENT(acs_ttee) || 898 PRESENT(acs_hline) || 899 PRESENT(acs_vline) || 900 PRESENT(acs_plus)) { 901 char buf2[MAX_TERMCAP_LENGTH]; 902 903 _nc_str_init(&result, buf2, sizeof(buf2)); 904 _nc_safe_strcat(&result, acs_chars); 905 906 append_acs(&result, 'j', acs_lrcorner); 907 append_acs(&result, 'k', acs_urcorner); 908 append_acs(&result, 'l', acs_ulcorner); 909 append_acs(&result, 'm', acs_llcorner); 910 append_acs(&result, 'n', acs_plus); 911 append_acs(&result, 'q', acs_hline); 912 append_acs(&result, 't', acs_ltee); 913 append_acs(&result, 'u', acs_rtee); 914 append_acs(&result, 'v', acs_btee); 915 append_acs(&result, 'w', acs_ttee); 916 append_acs(&result, 'x', acs_vline); 917 918 if (buf2[0]) { 919 acs_chars = _nc_save_str(buf2); 920 _nc_warning("acsc string synthesized from XENIX capabilities"); 921 } 922 } else if (acs_chars == 0 923 && enter_alt_charset_mode != 0 924 && exit_alt_charset_mode != 0) { 925 acs_chars = _nc_save_str(VT_ACSC); 926 } 927 } 928 929 static void 930 postprocess_terminfo(TERMTYPE *tp) 931 { 932 /* 933 * TERMINFO-TO-TERMINFO MAPPINGS FOR SOURCE TRANSLATION 934 * ---------------------------------------------------------------------- 935 */ 936 937 /* 938 * Translate AIX forms characters. 939 */ 940 if (PRESENT(box_chars_1)) { 941 char buf2[MAX_TERMCAP_LENGTH]; 942 string_desc result; 943 944 _nc_str_init(&result, buf2, sizeof(buf2)); 945 _nc_safe_strcat(&result, acs_chars); 946 947 append_acs0(&result, 'l', box_chars_1[0]); /* ACS_ULCORNER */ 948 append_acs0(&result, 'q', box_chars_1[1]); /* ACS_HLINE */ 949 append_acs0(&result, 'k', box_chars_1[2]); /* ACS_URCORNER */ 950 append_acs0(&result, 'x', box_chars_1[3]); /* ACS_VLINE */ 951 append_acs0(&result, 'j', box_chars_1[4]); /* ACS_LRCORNER */ 952 append_acs0(&result, 'm', box_chars_1[5]); /* ACS_LLCORNER */ 953 append_acs0(&result, 'w', box_chars_1[6]); /* ACS_TTEE */ 954 append_acs0(&result, 'u', box_chars_1[7]); /* ACS_RTEE */ 955 append_acs0(&result, 'v', box_chars_1[8]); /* ACS_BTEE */ 956 append_acs0(&result, 't', box_chars_1[9]); /* ACS_LTEE */ 957 append_acs0(&result, 'n', box_chars_1[10]); /* ACS_PLUS */ 958 959 if (buf2[0]) { 960 acs_chars = _nc_save_str(buf2); 961 _nc_warning("acsc string synthesized from AIX capabilities"); 962 box_chars_1 = ABSENT_STRING; 963 } 964 } 965 /* 966 * ---------------------------------------------------------------------- 967 */ 968 } 969 970 /* 971 * Do a linear search through the terminfo tables to find a given full-name. 972 * We don't expect to do this often, so there's no hashing function. 973 * 974 * In effect, this scans through the 3 lists of full-names, and looks them 975 * up in _nc_info_table, which is organized so that the nte_index fields are 976 * sorted, but the nte_type fields are not necessarily grouped together. 977 */ 978 static struct name_table_entry const * 979 lookup_fullname(const char *find) 980 { 981 int state = -1; 982 983 for (;;) { 984 int count = 0; 985 NCURSES_CONST char *const *names; 986 987 switch (++state) { 988 case BOOLEAN: 989 names = boolfnames; 990 break; 991 case STRING: 992 names = strfnames; 993 break; 994 case NUMBER: 995 names = numfnames; 996 break; 997 default: 998 return NOTFOUND; 999 } 1000 1001 for (count = 0; names[count] != 0; count++) { 1002 if (!strcmp(names[count], find)) { 1003 struct name_table_entry const *entry_ptr = _nc_get_table(FALSE); 1004 while (entry_ptr->nte_type != state 1005 || entry_ptr->nte_index != count) 1006 entry_ptr++; 1007 return entry_ptr; 1008 } 1009 } 1010 } 1011 } 1012 1013 /* parse_entry.c ends here */ 1014