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