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