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