diff options
Diffstat (limited to 'contrib/ncurses/ncurses/tinfo/parse_entry.c')
-rw-r--r-- | contrib/ncurses/ncurses/tinfo/parse_entry.c | 1047 |
1 files changed, 1047 insertions, 0 deletions
diff --git a/contrib/ncurses/ncurses/tinfo/parse_entry.c b/contrib/ncurses/ncurses/tinfo/parse_entry.c new file mode 100644 index 000000000000..07f3868e0b44 --- /dev/null +++ b/contrib/ncurses/ncurses/tinfo/parse_entry.c @@ -0,0 +1,1047 @@ +/**************************************************************************** + * Copyright (c) 1999 Free Software Foundation, Inc. * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the * + * "Software"), to deal in the Software without restriction, including * + * without limitation the rights to use, copy, modify, merge, publish, * + * distribute, distribute with modifications, sublicense, and/or sell * + * copies of the Software, and to permit persons to whom the Software is * + * furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included * + * in all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * + * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + * * + * Except as contained in this notice, the name(s) of the above copyright * + * holders shall not be used in advertising or otherwise to promote the * + * sale, use or other dealings in this Software without prior written * + * authorization. * + ****************************************************************************/ + +/**************************************************************************** + * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 * + * and: Eric S. Raymond <esr@snark.thyrsus.com> * + ****************************************************************************/ + + +/* + * parse_entry.c -- compile one terminfo or termcap entry + * + * Get an exact in-core representation of an entry. Don't + * try to resolve use or tc capabilities, that is someone + * else's job. Depends on the lexical analyzer to get tokens + * from the input stream. + */ + +#include <curses.priv.h> + +#include <ctype.h> +#include <tic.h> +#define __INTERNAL_CAPS_VISIBLE +#include <term_entry.h> + +MODULE_ID("$Id: parse_entry.c,v 1.39 1999/03/01 02:28:51 tom Exp $") + +#ifdef LINT +static short const parametrized[] = { 0 }; +#else +#include <parametrized.h> +#endif + +struct token _nc_curr_token; + +static void postprocess_termcap(TERMTYPE *, bool); +static void postprocess_terminfo(TERMTYPE *); +static struct name_table_entry const * lookup_fullname(const char *name); + +#if NCURSES_XNAMES + +static struct name_table_entry const * +_nc_extend_names(ENTRY *entryp, char *name, int token_type) +{ + static struct name_table_entry temp; + TERMTYPE *tp = &(entryp->tterm); + unsigned offset = 0; + unsigned actual; + unsigned tindex; + unsigned first, last, n; + bool found; + + switch (token_type) { + case BOOLEAN: + first = 0; + last = tp->ext_Booleans; + offset = tp->ext_Booleans; + tindex = tp->num_Booleans; + break; + case NUMBER: + first = tp->ext_Booleans; + last = tp->ext_Numbers + first; + offset = tp->ext_Booleans + tp->ext_Numbers; + tindex = tp->num_Numbers; + break; + case STRING: + first = tp->ext_Booleans + tp->ext_Numbers; + last = tp->ext_Strings + first; + offset = tp->ext_Booleans + tp->ext_Numbers + tp->ext_Strings; + tindex = tp->num_Strings; + break; + case CANCEL: + actual = NUM_EXT_NAMES(tp); + for (n = 0; n < actual; n++) { + if (!strcmp(name, tp->ext_Names[n])) { + if (n > (unsigned)(tp->ext_Booleans + tp->ext_Numbers)) { + token_type = STRING; + } else if (n > tp->ext_Booleans) { + token_type = NUMBER; + } else { + token_type = BOOLEAN; + } + return _nc_extend_names(entryp, name, token_type); + } + } + /* Well, we are given a cancel for a name that we don't recognize */ + return _nc_extend_names(entryp, name, STRING); + default: + return 0; + } + + /* Adjust the 'offset' (insertion-point) to keep the lists of extended + * names sorted. + */ + for (n = first, found = FALSE; n < last; n++) { + int cmp = strcmp(tp->ext_Names[n], name); + if (cmp == 0) + found = TRUE; + if (cmp >= 0) { + offset = n; + tindex = n - first; + switch (token_type) { + case BOOLEAN: tindex += BOOLCOUNT; break; + case NUMBER: tindex += NUMCOUNT; break; + case STRING: tindex += STRCOUNT; break; + } + break; + } + } + if (!found) { + switch (token_type) { + case BOOLEAN: + tp->ext_Booleans += 1; + tp->num_Booleans += 1; + tp->Booleans = typeRealloc(char, tp->num_Booleans, tp->Booleans); + for (last = tp->num_Booleans-1; last > tindex; last--) + tp->Booleans[last] = tp->Booleans[last-1]; + break; + case NUMBER: + tp->ext_Numbers += 1; + tp->num_Numbers += 1; + tp->Numbers = typeRealloc(short, tp->num_Numbers, tp->Numbers); + for (last = tp->num_Numbers-1; last > tindex; last--) + tp->Numbers[last] = tp->Numbers[last-1]; + break; + case STRING: + tp->ext_Strings += 1; + tp->num_Strings += 1; + tp->Strings = typeRealloc(char *, tp->num_Strings, tp->Strings); + for (last = tp->num_Strings-1; last > tindex; last--) + tp->Strings[last] = tp->Strings[last-1]; + break; + } + actual = NUM_EXT_NAMES(tp); + tp->ext_Names = typeRealloc(char *, actual, tp->ext_Names); + while (--actual > offset) + tp->ext_Names[actual] = tp->ext_Names[actual-1]; + tp->ext_Names[offset] = _nc_save_str(name); + } + + temp.nte_name = tp->ext_Names[offset]; + temp.nte_type = token_type; + temp.nte_index = tindex; + temp.nte_link = -1; + + return &temp; +} +#endif /* NCURSES_XNAMES */ + +/* + * int + * _nc_parse_entry(entry, literal, silent) + * + * Compile one entry. Doesn't try to resolve use or tc capabilities. + * + * found-forward-use = FALSE + * re-initialise internal arrays + * get_token(); + * if the token was not a name in column 1, complain and die + * save names in entry's string table + * while (get_token() is not EOF and not NAMES) + * check for existance and type-correctness + * enter cap into structure + * if STRING + * save string in entry's string table + * push back token + */ + +int _nc_parse_entry(struct entry *entryp, int literal, bool silent) +{ + int token_type; + struct name_table_entry const *entry_ptr; + char *ptr, namecpy[MAX_NAME_SIZE+1]; + + token_type = _nc_get_token(); + + if (token_type == EOF) + return(EOF); + if (token_type != NAMES) + _nc_err_abort("Entry does not start with terminal names in column one"); + + _nc_init_entry(&entryp->tterm); + + entryp->cstart = _nc_comment_start; + entryp->cend = _nc_comment_end; + entryp->startline = _nc_start_line; + DEBUG(2, ("Comment range is %ld to %ld", entryp->cstart, entryp->cend)); + + /* junk the 2-character termcap name, if present */ + ptr = _nc_curr_token.tk_name; + if (ptr[2] == '|') + { + ptr = _nc_curr_token.tk_name + 3; + _nc_curr_token.tk_name[2] = '\0'; + } + + entryp->tterm.str_table = entryp->tterm.term_names = _nc_save_str(ptr); + + DEBUG(1, ("Starting '%s'", ptr)); + + /* + * We do this because the one-token lookahead in the parse loop + * results in the terminal type getting prematurely set to correspond + * to that of the next entry. + */ + _nc_set_type(_nc_first_name(entryp->tterm.term_names)); + + /* check for overly-long names and aliases */ + (void) strncpy(namecpy, entryp->tterm.term_names, MAX_NAME_SIZE); + namecpy[MAX_NAME_SIZE] = '\0'; + if ((ptr = strrchr(namecpy, '|')) != (char *)0) + *ptr = '\0'; + ptr = strtok(namecpy, "|"); + if (strlen(ptr) > MAX_ALIAS) + _nc_warning("primary name may be too long"); + while ((ptr = strtok((char *)0, "|")) != (char *)0) + if (strlen(ptr) > MAX_ALIAS) + _nc_warning("alias `%s' may be too long", ptr); + + entryp->nuses = 0; + + for (token_type = _nc_get_token(); + token_type != EOF && token_type != NAMES; + token_type = _nc_get_token()) + { + if (strcmp(_nc_curr_token.tk_name, "use") == 0 + || strcmp(_nc_curr_token.tk_name, "tc") == 0) { + entryp->uses[entryp->nuses].parent = (void *)_nc_save_str(_nc_curr_token.tk_valstring); + entryp->uses[entryp->nuses].line = _nc_curr_line; + entryp->nuses++; + } else { + /* normal token lookup */ + entry_ptr = _nc_find_entry(_nc_curr_token.tk_name, + _nc_syntax ? _nc_cap_hash_table : _nc_info_hash_table); + + /* + * Our kluge to handle aliasing. The reason it's done + * this ugly way, with a linear search, is so the hashing + * machinery doesn't have to be made really complicated + * (also we get better warnings this way). No point in + * making this case fast, aliased caps aren't common now + * and will get rarer. + */ + if (entry_ptr == NOTFOUND) + { + const struct alias *ap; + + if (_nc_syntax == SYN_TERMCAP) + { + for (ap = _nc_capalias_table; ap->from; ap++) + if (strcmp(ap->from, _nc_curr_token.tk_name) == 0) + { + if (ap->to == (char *)0) + { + _nc_warning("%s (%s termcap extension) ignored", + ap->from, ap->source); + goto nexttok; + } + + entry_ptr = _nc_find_entry(ap->to, _nc_cap_hash_table); + if (entry_ptr && !silent) + _nc_warning("%s (%s termcap extension) aliased to %s", ap->from, ap->source, ap->to); + break; + } + } + else /* if (_nc_syntax == SYN_TERMINFO) */ + { + for (ap = _nc_infoalias_table; ap->from; ap++) + if (strcmp(ap->from, _nc_curr_token.tk_name) == 0) + { + if (ap->to == (char *)0) + { + _nc_warning("%s (%s terminfo extension) ignored", + ap->from, ap->source); + goto nexttok; + } + + entry_ptr = _nc_find_entry(ap->to, _nc_info_hash_table); + if (entry_ptr && !silent) + _nc_warning("%s (%s terminfo extension) aliased to %s", ap->from, ap->source, ap->to); + break; + } + + if (entry_ptr == NOTFOUND) { + entry_ptr = lookup_fullname(_nc_curr_token.tk_name); + } + } + } + +#if NCURSES_XNAMES + /* + * If we have extended-names active, we will automatically + * define a name based on its context. + */ + if (entry_ptr == NOTFOUND + && _nc_user_definable + && (entry_ptr = _nc_extend_names(entryp, _nc_curr_token.tk_name, token_type)) != 0) { + _nc_warning("extended capability '%s'", _nc_curr_token.tk_name); + } +#endif /* NCURSES_XNAMES */ + + /* can't find this cap name, not even as an alias */ + if (entry_ptr == NOTFOUND) { + if (!silent) + _nc_warning("unknown capability '%s'", + _nc_curr_token.tk_name); + continue; + } + + /* deal with bad type/value combinations. */ + if (token_type != CANCEL && entry_ptr->nte_type != token_type) + { + /* + * Nasty special cases here handle situations in which type + * information can resolve name clashes. Normal lookup + * finds the last instance in the capability table of a + * given name, regardless of type. find_type_entry looks + * for a first matching instance with given type. So as + * long as all ambiguous names occur in pairs of distinct + * type, this will do the job. + */ + + /* tell max_attributes from arrow_key_map */ + if (token_type == NUMBER && !strcmp("ma", _nc_curr_token.tk_name)) + entry_ptr = _nc_find_type_entry("ma", NUMBER, + _nc_get_table(_nc_syntax != 0)); + + /* map terminfo's string MT to MT */ + else if (token_type==STRING &&!strcmp("MT",_nc_curr_token.tk_name)) + entry_ptr = _nc_find_type_entry("MT", STRING, + _nc_get_table(_nc_syntax != 0)); + + /* treat strings without following "=" as empty strings */ + else if (token_type==BOOLEAN && entry_ptr->nte_type==STRING) + token_type = STRING; + /* we couldn't recover; skip this token */ + else + { + if (!silent) + { + const char *type_name; + switch (entry_ptr->nte_type) + { + case BOOLEAN: + type_name = "boolean"; + break; + case STRING: + type_name = "string"; + break; + case NUMBER: + type_name = "numeric"; + break; + default: + type_name = "unknown"; + break; + } + _nc_warning("wrong type used for %s capability '%s'", + type_name, _nc_curr_token.tk_name); + } + continue; + } + } + + /* now we know that the type/value combination is OK */ + switch (token_type) { + case CANCEL: + switch (entry_ptr->nte_type) { + case BOOLEAN: + entryp->tterm.Booleans[entry_ptr->nte_index] = CANCELLED_BOOLEAN; + break; + + case NUMBER: + entryp->tterm.Numbers[entry_ptr->nte_index] = CANCELLED_NUMERIC; + break; + + case STRING: + entryp->tterm.Strings[entry_ptr->nte_index] = CANCELLED_STRING; + break; + } + break; + + case BOOLEAN: + entryp->tterm.Booleans[entry_ptr->nte_index] = TRUE; + break; + + case NUMBER: + entryp->tterm.Numbers[entry_ptr->nte_index] = + _nc_curr_token.tk_valnumber; + break; + + case STRING: + ptr = _nc_curr_token.tk_valstring; + if (_nc_syntax==SYN_TERMCAP) + ptr = _nc_captoinfo(_nc_curr_token.tk_name, + ptr, + parametrized[entry_ptr->nte_index]); + entryp->tterm.Strings[entry_ptr->nte_index] = _nc_save_str(ptr); + break; + + default: + if (!silent) + _nc_warning("unknown token type"); + _nc_panic_mode((_nc_syntax==SYN_TERMCAP) ? ':' : ','); + continue; + } + } /* end else cur_token.name != "use" */ + nexttok: + continue; /* cannot have a label w/o statement */ + } /* endwhile (not EOF and not NAMES) */ + + _nc_push_token(token_type); + _nc_set_type(_nc_first_name(entryp->tterm.term_names)); + + /* + * Try to deduce as much as possible from extension capabilities + * (this includes obsolete BSD capabilities). Sigh...it would be more + * space-efficient to call this after use resolution, but it has + * to be done before entry allocation is wrapped up. + */ + if (!literal) { + if (_nc_syntax == SYN_TERMCAP) + { + bool has_base_entry = FALSE; + int i; + + /* + * Don't insert defaults if this is a `+' entry meant only + * for inclusion in other entries (not sure termcap ever + * had these, actually). + */ + if (strchr(entryp->tterm.term_names, '+')) + has_base_entry = TRUE; + else + /* + * Otherwise, look for a base entry that will already + * have picked up defaults via translation. + */ + for (i = 0; i < entryp->nuses; i++) + if (!strchr((char *)entryp->uses[i].parent, '+')) + has_base_entry = TRUE; + + postprocess_termcap(&entryp->tterm, has_base_entry); + } + else + postprocess_terminfo(&entryp->tterm); + } + _nc_wrap_entry(entryp); + + return(OK); +} + +int _nc_capcmp(const char *s, const char *t) +/* compare two string capabilities, stripping out padding */ +{ + if (!s && !t) + return(0); + else if (!s || !t) + return(1); + + for (;;) + { + if (s[0] == '$' && s[1] == '<') + { + for (s += 2; ; s++) + if (!(isdigit(*s) || *s=='.' || *s=='*' || *s=='/' || *s=='>')) + break; + } + + if (t[0] == '$' && t[1] == '<') + { + for (t += 2; ; t++) + if (!(isdigit(*t) || *t=='.' || *t=='*' || *t=='/' || *t=='>')) + break; + } + + /* we've now pushed s and t past any padding they were pointing at */ + + if (*s == '\0' && *t == '\0') + return(0); + + if (*s != *t) + return(*t - *s); + + /* else *s == *t but one is not NUL, so continue */ + s++, t++; + } +} + +/* + * The ko capability, if present, consists of a comma-separated capability + * list. For each capability, we may assume there is a keycap that sends the + * string which is the value of that capability. + */ +typedef struct {const char *from; const char *to;} assoc; +static assoc const ko_xlate[] = +{ + {"al", "kil1"}, /* insert line key -> KEY_IL */ + {"bt", "kcbt"}, /* back tab -> KEY_BTAB */ + {"cd", "ked"}, /* clear-to-eos key -> KEY_EOL */ + {"ce", "kel"}, /* clear-to-eol key -> KEY_EOS */ + {"cl", "kclr"}, /* clear key -> KEY_CLEAR */ + {"ct", "tbc"}, /* clear all tabs -> KEY_CATAB */ + {"dc", "kdch1"}, /* delete char -> KEY_DC */ + {"dl", "kdl1"}, /* delete line -> KEY_DL */ + {"do", "kcud1"}, /* down key -> KEY_DOWN */ + {"ei", "krmir"}, /* exit insert key -> KEY_EIC */ + {"ho", "khome"}, /* home key -> KEY_HOME */ + {"ic", "kich1"}, /* insert char key -> KEY_IC */ + {"im", "kIC"}, /* insert-mode key -> KEY_SIC */ + {"le", "kcub1"}, /* le key -> KEY_LEFT */ + {"nd", "kcuf1"}, /* nd key -> KEY_RIGHT */ + {"nl", "kent"}, /* new line key -> KEY_ENTER */ + {"st", "khts"}, /* set-tab key -> KEY_STAB */ + {"ta", CANCELLED_STRING}, + {"up", "kcuu1"}, /* up-arrow key -> KEY_UP */ + {(char *)0, (char *)0}, +}; + +/* + * This routine fills in string caps that either had defaults under + * termcap or can be manufactured from obsolete termcap capabilities. + * It was lifted from Ross Ridge's mytinfo package. + */ + +static const char C_CR[] = "\r"; +static const char C_LF[] = "\n"; +static const char C_BS[] = "\b"; +static const char C_HT[] = "\t"; + +/* + * Note that WANTED and PRESENT are not simple inverses! If a capability + * has been explicitly cancelled, it's not considered WANTED. + */ +#define WANTED(s) ((s) == ABSENT_STRING) +#define PRESENT(s) (((s) != ABSENT_STRING) && ((s) != CANCELLED_STRING)) + +/* + * This bit of legerdemain turns all the terminfo variable names into + * references to locations in the arrays Booleans, Numbers, and Strings --- + * precisely what's needed. + */ + +#undef CUR +#define CUR tp-> + +static +void postprocess_termcap(TERMTYPE *tp, bool has_base) +{ + char buf[MAX_LINE * 2 + 2]; + + /* + * TERMCAP DEFAULTS AND OBSOLETE-CAPABILITY TRANSLATIONS + * + * This first part of the code is the functional inverse of the + * fragment in capdefaults.c. + * ---------------------------------------------------------------------- + */ + + /* if there was a tc entry, assume we picked up defaults via that */ + if (!has_base) + { + if (WANTED(init_3string) && termcap_init2) + init_3string = _nc_save_str(termcap_init2); + + if (WANTED(reset_2string) && termcap_reset) + reset_2string = _nc_save_str(termcap_reset); + + if (WANTED(carriage_return)) { + if (carriage_return_delay > 0) { + sprintf(buf, "%s$<%d>", C_CR, carriage_return_delay); + carriage_return = _nc_save_str(buf); + } else + carriage_return = _nc_save_str(C_CR); + } + if (WANTED(cursor_left)) { + if (backspace_delay > 0) { + sprintf(buf, "%s$<%d>", C_BS, backspace_delay); + cursor_left = _nc_save_str(buf); + } else if (backspaces_with_bs == 1) + cursor_left = _nc_save_str(C_BS); + else if (PRESENT(backspace_if_not_bs)) + cursor_left = backspace_if_not_bs; + } + /* vi doesn't use "do", but it does seems to use nl (or '\n') instead */ + if (WANTED(cursor_down)) { + if (PRESENT(linefeed_if_not_lf)) + cursor_down = linefeed_if_not_lf; + else if (linefeed_is_newline != 1) { + if (new_line_delay > 0) { + sprintf(buf, "%s$<%d>", C_LF, new_line_delay); + cursor_down = _nc_save_str(buf); + } else + cursor_down = _nc_save_str(C_LF); + } + } + if (WANTED(scroll_forward) && crt_no_scrolling != 1) { + if (PRESENT(linefeed_if_not_lf)) + cursor_down = linefeed_if_not_lf; + else if (linefeed_is_newline != 1) { + if (new_line_delay > 0) { + sprintf(buf, "%s$<%d>", C_LF, new_line_delay); + scroll_forward = _nc_save_str(buf); + } else + scroll_forward = _nc_save_str(C_LF); + } + } + if (WANTED(newline)) { + if (linefeed_is_newline == 1) { + if (new_line_delay > 0) { + sprintf(buf, "%s$<%d>", C_LF, new_line_delay); + newline = _nc_save_str(buf); + } else + newline = _nc_save_str(C_LF); + } else if (PRESENT(carriage_return) && PRESENT(scroll_forward)) { + strncpy(buf, carriage_return, MAX_LINE-2); + buf[MAX_LINE-1] = '\0'; + strncat(buf, scroll_forward, MAX_LINE-strlen(buf)-1); + buf[MAX_LINE] = '\0'; + newline = _nc_save_str(buf); + } else if (PRESENT(carriage_return) && PRESENT(cursor_down)) { + strncpy(buf, carriage_return, MAX_LINE-2); + buf[MAX_LINE-1] = '\0'; + strncat(buf, cursor_down, MAX_LINE-strlen(buf)-1); + buf[MAX_LINE] = '\0'; + newline = _nc_save_str(buf); + } + } + } + + /* + * Inverse of capdefaults.c code ends here. + * ---------------------------------------------------------------------- + * + * TERMCAP-TO TERMINFO MAPPINGS FOR SOURCE TRANSLATION + * + * These translations will *not* be inverted by tgetent(). + */ + + if (!has_base) + { + /* + * We wait until now to decide if we've got a working cr because even + * one that doesn't work can be used for newline. Unfortunately the + * space allocated for it is wasted. + */ + if (return_does_clr_eol == 1 || no_correctly_working_cr == 1) + carriage_return = ABSENT_STRING; + + /* + * Supposedly most termcap entries have ta now and '\t' is no longer a + * default, but it doesn't seem to be true... + */ + if (WANTED(tab)) { + if (horizontal_tab_delay > 0) { + sprintf(buf, "%s$<%d>", C_HT, horizontal_tab_delay); + tab = _nc_save_str(buf); + } else + tab = _nc_save_str(C_HT); + } + if (init_tabs == ABSENT_NUMERIC && has_hardware_tabs == TRUE) + init_tabs = 8; + + /* + * Assume we can beep with ^G unless we're given bl@. + */ + if (WANTED(bell)) + bell = _nc_save_str("\007"); + } + + /* + * Translate the old termcap :pt: capability to it#8 + ht=\t + */ + if (has_hardware_tabs == TRUE) { + if (init_tabs != 8 && init_tabs != ABSENT_NUMERIC) + _nc_warning("hardware tabs with a width other than 8: %d", init_tabs); + else + { + if (tab && _nc_capcmp(tab, C_HT)) + _nc_warning("hardware tabs with a non-^I tab string %s", + _nc_visbuf(tab)); + else + { + if (WANTED(tab)) + tab = _nc_save_str(C_HT); + init_tabs = 8; + } + } + } + /* + * Now translate the ko capability, if there is one. This + * isn't from mytinfo... + */ + if (PRESENT(other_non_function_keys)) + { + char *dp, *cp = strtok(other_non_function_keys, ","); + struct name_table_entry const *from_ptr; + struct name_table_entry const *to_ptr; + assoc const *ap; + char buf2[MAX_TERMINFO_LENGTH]; + bool foundim; + + /* we're going to use this for a special case later */ + dp = strchr(other_non_function_keys, 'i'); + foundim = dp && dp[1] == 'm'; + + /* look at each comma-separated capability in the ko string... */ + do { + for (ap = ko_xlate; ap->from; ap++) + if (strcmp(ap->from, cp) == 0) + break; + if (!ap->to) + { + _nc_warning("unknown capability `%s' in ko string", cp); + continue; + } + else if (ap->to == CANCELLED_STRING) /* ignore it */ + continue; + + /* now we know we found a match in ko_table, so... */ + + from_ptr = _nc_find_entry(ap->from, _nc_cap_hash_table); + to_ptr = _nc_find_entry(ap->to, _nc_info_hash_table); + + if (!from_ptr || !to_ptr) /* should never happen! */ + _nc_err_abort("ko translation table is invalid, I give up"); + + if (WANTED(tp->Strings[from_ptr->nte_index])) + { + _nc_warning("no value for ko capability %s", ap->from); + continue; + } + + if (tp->Strings[to_ptr->nte_index]) + { + /* There's no point in warning about it if it's the same + * string; that's just an inefficiency. + */ + if (strcmp( + tp->Strings[from_ptr->nte_index], + tp->Strings[to_ptr->nte_index]) != 0) + _nc_warning("%s (%s) already has an explicit value %s, ignoring ko", + ap->to, ap->from, + _nc_visbuf(tp->Strings[to_ptr->nte_index]) ); + continue; + } + + /* + * The magic moment -- copy the mapped key string over, + * stripping out padding. + */ + dp = buf2; + for (cp = tp->Strings[from_ptr->nte_index]; *cp; cp++) + { + if (cp[0] == '$' && cp[1] == '<') + { + while (*cp && *cp != '>') + if (!*cp) + break; + else + ++cp; + } + else + *dp++ = *cp; + } + *dp++ = '\0'; + + tp->Strings[to_ptr->nte_index] = _nc_save_str(buf2); + } while + ((cp = strtok((char *)0, ",")) != 0); + + /* + * Note: ko=im and ko=ic both want to grab the `Insert' + * keycap. There's a kich1 but no ksmir, so the ic capability + * got mapped to kich1 and im to kIC to avoid a collision. + * If the description has im but not ic, hack kIC back to kich1. + */ + if (foundim && WANTED(key_ic) && key_sic) + { + key_ic = key_sic; + key_sic = ABSENT_STRING; + } + } + + if (!hard_copy) + { + if (WANTED(key_backspace)) + key_backspace = _nc_save_str(C_BS); + if (WANTED(key_left)) + key_left = _nc_save_str(C_BS); + if (WANTED(key_down)) + key_down = _nc_save_str(C_LF); + } + + /* + * Translate XENIX forms characters. + */ + if (PRESENT(acs_ulcorner) || + PRESENT(acs_llcorner) || + PRESENT(acs_urcorner) || + PRESENT(acs_lrcorner) || + PRESENT(acs_ltee) || + PRESENT(acs_rtee) || + PRESENT(acs_btee) || + PRESENT(acs_ttee) || + PRESENT(acs_hline) || + PRESENT(acs_vline) || + PRESENT(acs_plus)) + { + char buf2[MAX_TERMCAP_LENGTH], *bp = buf2; + + if (acs_chars) + { + (void)strcpy(bp, acs_chars); + bp += strlen(bp); + } + + if (acs_ulcorner && acs_ulcorner[1] == '\0') + { + *bp++ = 'l'; + *bp++ = *acs_ulcorner; + } + if (acs_llcorner && acs_llcorner[1] == '\0') + { + *bp++ = 'm'; + *bp++ = *acs_llcorner; + } + if (acs_urcorner && acs_urcorner[1] == '\0') + { + *bp++ = 'k'; + *bp++ = *acs_urcorner; + } + if (acs_lrcorner && acs_lrcorner[1] == '\0') + { + *bp++ = 'j'; + *bp++ = *acs_lrcorner; + } + if (acs_ltee && acs_ltee[1] == '\0') + { + *bp++ = 't'; + *bp++ = *acs_ltee; + } + if (acs_rtee && acs_rtee[1] == '\0') + { + *bp++ = 'u'; + *bp++ = *acs_rtee; + } + if (acs_btee && acs_btee[1] == '\0') + { + *bp++ = 'v'; + *bp++ = *acs_btee; + } + if (acs_ttee && acs_ttee[1] == '\0') + { + *bp++ = 'w'; + *bp++ = *acs_ttee; + } + if (acs_hline && acs_hline[1] == '\0') + { + *bp++ = 'q'; + *bp++ = *acs_hline; + } + if (acs_vline && acs_vline[1] == '\0') + { + *bp++ = 'x'; + *bp++ = *acs_vline; + } + if (acs_plus) + { + *bp++ = 'n'; + strcpy(bp, acs_plus); + bp = buf2 + strlen(buf2); + } + + if (bp != buf2) + { + *bp++ = '\0'; + acs_chars = _nc_save_str(buf2); + _nc_warning("acsc string synthesized from XENIX capabilities"); + } + } + else if (acs_chars == 0 + && enter_alt_charset_mode != 0 + && exit_alt_charset_mode != 0) + { + acs_chars = _nc_save_str("``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~"); + } +} + +static +void postprocess_terminfo(TERMTYPE *tp) +{ + /* + * TERMINFO-TO-TERMINFO MAPPINGS FOR SOURCE TRANSLATION + * ---------------------------------------------------------------------- + */ + + /* + * Translate AIX forms characters. + */ + if (PRESENT(box_chars_1)) + { + char buf2[MAX_TERMCAP_LENGTH], *bp = buf2; + + if (acs_chars) + { + (void)strcpy(bp, acs_chars); + bp += strlen(bp); + } + + if (box_chars_1[0]) /* ACS_ULCORNER */ + { + *bp++ = 'l'; + *bp++ = box_chars_1[0]; + } + if (box_chars_1[1]) /* ACS_HLINE */ + { + *bp++ = 'q'; + *bp++ = box_chars_1[1]; + } + if (box_chars_1[2]) /* ACS_URCORNER */ + { + *bp++ = 'k'; + *bp++ = box_chars_1[2]; + } + if (box_chars_1[3]) /* ACS_VLINE */ + { + *bp++ = 'x'; + *bp++ = box_chars_1[3]; + } + if (box_chars_1[4]) /* ACS_LRCORNER */ + { + *bp++ = 'j'; + *bp++ = box_chars_1[4]; + } + if (box_chars_1[5]) /* ACS_LLCORNER */ + { + *bp++ = 'm'; + *bp++ = box_chars_1[5]; + } + if (box_chars_1[6]) /* ACS_TTEE */ + { + *bp++ = 'w'; + *bp++ = box_chars_1[6]; + } + if (box_chars_1[7]) /* ACS_RTEE */ + { + *bp++ = 'u'; + *bp++ = box_chars_1[7]; + } + if (box_chars_1[8]) /* ACS_BTEE */ + { + *bp++ = 'v'; + *bp++ = box_chars_1[8]; + } + if (box_chars_1[9]) /* ACS_LTEE */ + { + *bp++ = 't'; + *bp++ = box_chars_1[9]; + } + if (box_chars_1[10]) /* ACS_PLUS */ + { + *bp++ = 'n'; + *bp++ = box_chars_1[10]; + } + + if (bp != buf2) + { + *bp++ = '\0'; + acs_chars = _nc_save_str(buf2); + _nc_warning("acsc string synthesized from AIX capabilities"); + box_chars_1 = ABSENT_STRING; + } + } + /* + * ---------------------------------------------------------------------- + */ +} + +/* + * Do a linear search through the terminfo tables to find a given full-name. + * We don't expect to do this often, so there's no hashing function. + * + * In effect, this scans through the 3 lists of full-names, and looks them + * up in _nc_info_table, which is organized so that the nte_index fields are + * sorted, but the nte_type fields are not necessarily grouped together. + */ +static +struct name_table_entry const * lookup_fullname(const char *find) +{ + int state = -1; + + for (;;) { + int count = 0; + NCURSES_CONST char *const *names; + + switch (++state) { + case BOOLEAN: + names = boolfnames; + break; + case STRING: + names = strfnames; + break; + case NUMBER: + names = numfnames; + break; + default: + return NOTFOUND; + } + + for (count = 0; names[count] != 0; count++) { + if (!strcmp(names[count], find)) { + struct name_table_entry const *entry_ptr = _nc_get_table(FALSE); + while (entry_ptr->nte_type != state + || entry_ptr->nte_index != count) + entry_ptr++; + return entry_ptr; + } + } + } +} + +/* parse_entry.c ends here */ |