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