parse_entry.c revision 66963
150276Speter/**************************************************************************** 262449Speter * Copyright (c) 1998,1999,2000 Free Software Foundation, Inc. * 350276Speter * * 450276Speter * Permission is hereby granted, free of charge, to any person obtaining a * 550276Speter * copy of this software and associated documentation files (the * 650276Speter * "Software"), to deal in the Software without restriction, including * 750276Speter * without limitation the rights to use, copy, modify, merge, publish, * 850276Speter * distribute, distribute with modifications, sublicense, and/or sell * 950276Speter * copies of the Software, and to permit persons to whom the Software is * 1050276Speter * furnished to do so, subject to the following conditions: * 1150276Speter * * 1250276Speter * The above copyright notice and this permission notice shall be included * 1350276Speter * in all copies or substantial portions of the Software. * 1450276Speter * * 1550276Speter * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 1650276Speter * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 1750276Speter * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 1850276Speter * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 1950276Speter * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 2050276Speter * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 2150276Speter * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 2250276Speter * * 2350276Speter * Except as contained in this notice, the name(s) of the above copyright * 2450276Speter * holders shall not be used in advertising or otherwise to promote the * 2550276Speter * sale, use or other dealings in this Software without prior written * 2650276Speter * authorization. * 2750276Speter ****************************************************************************/ 2850276Speter 2950276Speter/**************************************************************************** 3050276Speter * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 * 3150276Speter * and: Eric S. Raymond <esr@snark.thyrsus.com> * 3250276Speter ****************************************************************************/ 3350276Speter 3450276Speter/* 3550276Speter * parse_entry.c -- compile one terminfo or termcap entry 3650276Speter * 3750276Speter * Get an exact in-core representation of an entry. Don't 3850276Speter * try to resolve use or tc capabilities, that is someone 3950276Speter * else's job. Depends on the lexical analyzer to get tokens 4050276Speter * from the input stream. 4150276Speter */ 4250276Speter 4350276Speter#include <curses.priv.h> 4450276Speter 4550276Speter#include <ctype.h> 4650276Speter#include <tic.h> 4750276Speter#define __INTERNAL_CAPS_VISIBLE 4850276Speter#include <term_entry.h> 4950276Speter 5066963SpeterMODULE_ID("$Id: parse_entry.c,v 1.48 2000/10/03 09:38:48 tom Exp $") 5150276Speter 5250276Speter#ifdef LINT 5362449Speterstatic short const parametrized[] = 5462449Speter{0}; 5550276Speter#else 5650276Speter#include <parametrized.h> 5750276Speter#endif 5850276Speter 5962449Speterstatic void postprocess_termcap(TERMTYPE *, bool); 6062449Speterstatic void postprocess_terminfo(TERMTYPE *); 6162449Speterstatic struct name_table_entry const *lookup_fullname(const char *name); 6250276Speter 6350276Speter#if NCURSES_XNAMES 6450276Speter 6562449Speterstatic struct name_table_entry const * 6662449Speter_nc_extend_names(ENTRY * entryp, char *name, int token_type) 6750276Speter{ 6850276Speter static struct name_table_entry temp; 6950276Speter TERMTYPE *tp = &(entryp->tterm); 7050276Speter unsigned offset = 0; 7150276Speter unsigned actual; 7250276Speter unsigned tindex; 7350276Speter unsigned first, last, n; 7450276Speter bool found; 7550276Speter 7650276Speter switch (token_type) { 7750276Speter case BOOLEAN: 7862449Speter first = 0; 7962449Speter last = tp->ext_Booleans; 8050276Speter offset = tp->ext_Booleans; 8150276Speter tindex = tp->num_Booleans; 8250276Speter break; 8350276Speter case NUMBER: 8462449Speter first = tp->ext_Booleans; 8562449Speter last = tp->ext_Numbers + first; 8650276Speter offset = tp->ext_Booleans + tp->ext_Numbers; 8750276Speter tindex = tp->num_Numbers; 8850276Speter break; 8950276Speter case STRING: 9062449Speter first = tp->ext_Booleans + tp->ext_Numbers; 9162449Speter last = tp->ext_Strings + first; 9250276Speter offset = tp->ext_Booleans + tp->ext_Numbers + tp->ext_Strings; 9350276Speter tindex = tp->num_Strings; 9450276Speter break; 9550276Speter case CANCEL: 9650276Speter actual = NUM_EXT_NAMES(tp); 9750276Speter for (n = 0; n < actual; n++) { 9850276Speter if (!strcmp(name, tp->ext_Names[n])) { 9962449Speter if (n > (unsigned) (tp->ext_Booleans + tp->ext_Numbers)) { 10050276Speter token_type = STRING; 10150276Speter } else if (n > tp->ext_Booleans) { 10250276Speter token_type = NUMBER; 10350276Speter } else { 10450276Speter token_type = BOOLEAN; 10550276Speter } 10650276Speter return _nc_extend_names(entryp, name, token_type); 10750276Speter } 10850276Speter } 10950276Speter /* Well, we are given a cancel for a name that we don't recognize */ 11050276Speter return _nc_extend_names(entryp, name, STRING); 11150276Speter default: 11250276Speter return 0; 11350276Speter } 11450276Speter 11550276Speter /* Adjust the 'offset' (insertion-point) to keep the lists of extended 11650276Speter * names sorted. 11750276Speter */ 11850276Speter for (n = first, found = FALSE; n < last; n++) { 11950276Speter int cmp = strcmp(tp->ext_Names[n], name); 12050276Speter if (cmp == 0) 12150276Speter found = TRUE; 12250276Speter if (cmp >= 0) { 12350276Speter offset = n; 12450276Speter tindex = n - first; 12550276Speter switch (token_type) { 12662449Speter case BOOLEAN: 12762449Speter tindex += BOOLCOUNT; 12862449Speter break; 12962449Speter case NUMBER: 13062449Speter tindex += NUMCOUNT; 13162449Speter break; 13262449Speter case STRING: 13362449Speter tindex += STRCOUNT; 13462449Speter break; 13550276Speter } 13650276Speter break; 13750276Speter } 13850276Speter } 13950276Speter if (!found) { 14050276Speter switch (token_type) { 14150276Speter case BOOLEAN: 14250276Speter tp->ext_Booleans += 1; 14350276Speter tp->num_Booleans += 1; 14450276Speter tp->Booleans = typeRealloc(char, tp->num_Booleans, tp->Booleans); 14562449Speter for (last = tp->num_Booleans - 1; last > tindex; last--) 14662449Speter tp->Booleans[last] = tp->Booleans[last - 1]; 14750276Speter break; 14850276Speter case NUMBER: 14950276Speter tp->ext_Numbers += 1; 15050276Speter tp->num_Numbers += 1; 15150276Speter tp->Numbers = typeRealloc(short, tp->num_Numbers, tp->Numbers); 15262449Speter for (last = tp->num_Numbers - 1; last > tindex; last--) 15362449Speter tp->Numbers[last] = tp->Numbers[last - 1]; 15450276Speter break; 15550276Speter case STRING: 15650276Speter tp->ext_Strings += 1; 15750276Speter tp->num_Strings += 1; 15850276Speter tp->Strings = typeRealloc(char *, tp->num_Strings, tp->Strings); 15962449Speter for (last = tp->num_Strings - 1; last > tindex; last--) 16062449Speter tp->Strings[last] = tp->Strings[last - 1]; 16150276Speter break; 16250276Speter } 16350276Speter actual = NUM_EXT_NAMES(tp); 16462449Speter tp->ext_Names = typeRealloc(char *, actual, tp->ext_Names); 16550276Speter while (--actual > offset) 16662449Speter tp->ext_Names[actual] = tp->ext_Names[actual - 1]; 16750276Speter tp->ext_Names[offset] = _nc_save_str(name); 16850276Speter } 16950276Speter 17062449Speter temp.nte_name = tp->ext_Names[offset]; 17162449Speter temp.nte_type = token_type; 17250276Speter temp.nte_index = tindex; 17362449Speter temp.nte_link = -1; 17450276Speter 17550276Speter return &temp; 17650276Speter} 17750276Speter#endif /* NCURSES_XNAMES */ 17850276Speter 17950276Speter/* 18050276Speter * int 18150276Speter * _nc_parse_entry(entry, literal, silent) 18250276Speter * 18350276Speter * Compile one entry. Doesn't try to resolve use or tc capabilities. 18450276Speter * 18550276Speter * found-forward-use = FALSE 18650276Speter * re-initialise internal arrays 18750276Speter * get_token(); 18850276Speter * if the token was not a name in column 1, complain and die 18950276Speter * save names in entry's string table 19050276Speter * while (get_token() is not EOF and not NAMES) 19150276Speter * check for existance and type-correctness 19250276Speter * enter cap into structure 19350276Speter * if STRING 19450276Speter * save string in entry's string table 19550276Speter * push back token 19650276Speter */ 19750276Speter 19862449Speterint 19962449Speter_nc_parse_entry(struct entry *entryp, int literal, bool silent) 20050276Speter{ 20162449Speter int token_type; 20262449Speter struct name_table_entry const *entry_ptr; 20366963Speter char *ptr, *base; 20450276Speter 20550276Speter token_type = _nc_get_token(); 20650276Speter 20750276Speter if (token_type == EOF) 20862449Speter return (EOF); 20950276Speter if (token_type != NAMES) 21050276Speter _nc_err_abort("Entry does not start with terminal names in column one"); 21150276Speter 21250276Speter _nc_init_entry(&entryp->tterm); 21350276Speter 21450276Speter entryp->cstart = _nc_comment_start; 21550276Speter entryp->cend = _nc_comment_end; 21650276Speter entryp->startline = _nc_start_line; 21750276Speter DEBUG(2, ("Comment range is %ld to %ld", entryp->cstart, entryp->cend)); 21850276Speter 21950276Speter /* junk the 2-character termcap name, if present */ 22050276Speter ptr = _nc_curr_token.tk_name; 22162449Speter if (ptr[2] == '|') { 22250276Speter ptr = _nc_curr_token.tk_name + 3; 22350276Speter _nc_curr_token.tk_name[2] = '\0'; 22450276Speter } 22550276Speter 22650276Speter entryp->tterm.str_table = entryp->tterm.term_names = _nc_save_str(ptr); 22750276Speter 22850276Speter DEBUG(1, ("Starting '%s'", ptr)); 22950276Speter 23050276Speter /* 23150276Speter * We do this because the one-token lookahead in the parse loop 23250276Speter * results in the terminal type getting prematurely set to correspond 23350276Speter * to that of the next entry. 23450276Speter */ 23550276Speter _nc_set_type(_nc_first_name(entryp->tterm.term_names)); 23650276Speter 23750276Speter /* check for overly-long names and aliases */ 23866963Speter for (base = entryp->tterm.term_names; (ptr = strchr(base, '|')) != 0; 23966963Speter base = ptr + 1) { 24066963Speter if (ptr - base > MAX_ALIAS) { 24166963Speter _nc_warning("%s `%.*s' may be too long", 24266963Speter (base == entryp->tterm.term_names) 24366963Speter ? "primary name" 24466963Speter : "alias", 24566963Speter ptr - base, base); 24666963Speter } 24766963Speter } 24850276Speter 24950276Speter entryp->nuses = 0; 25050276Speter 25150276Speter for (token_type = _nc_get_token(); 25266963Speter token_type != EOF && token_type != NAMES; 25366963Speter token_type = _nc_get_token()) { 25450276Speter if (strcmp(_nc_curr_token.tk_name, "use") == 0 25550276Speter || strcmp(_nc_curr_token.tk_name, "tc") == 0) { 25662449Speter entryp->uses[entryp->nuses].name = _nc_save_str(_nc_curr_token.tk_valstring); 25750276Speter entryp->uses[entryp->nuses].line = _nc_curr_line; 25850276Speter entryp->nuses++; 25950276Speter } else { 26050276Speter /* normal token lookup */ 26150276Speter entry_ptr = _nc_find_entry(_nc_curr_token.tk_name, 26266963Speter _nc_syntax ? _nc_cap_hash_table : _nc_info_hash_table); 26350276Speter 26450276Speter /* 26550276Speter * Our kluge to handle aliasing. The reason it's done 26650276Speter * this ugly way, with a linear search, is so the hashing 26750276Speter * machinery doesn't have to be made really complicated 26850276Speter * (also we get better warnings this way). No point in 26950276Speter * making this case fast, aliased caps aren't common now 27050276Speter * and will get rarer. 27150276Speter */ 27262449Speter if (entry_ptr == NOTFOUND) { 27362449Speter const struct alias *ap; 27450276Speter 27562449Speter if (_nc_syntax == SYN_TERMCAP) { 27650276Speter for (ap = _nc_capalias_table; ap->from; ap++) 27762449Speter if (strcmp(ap->from, _nc_curr_token.tk_name) == 0) { 27862449Speter if (ap->to == (char *) 0) { 27950276Speter _nc_warning("%s (%s termcap extension) ignored", 28066963Speter ap->from, ap->source); 28150276Speter goto nexttok; 28250276Speter } 28350276Speter 28450276Speter entry_ptr = _nc_find_entry(ap->to, _nc_cap_hash_table); 28550276Speter if (entry_ptr && !silent) 28662449Speter _nc_warning("%s (%s termcap extension) aliased to %s", 28766963Speter ap->from, ap->source, ap->to); 28850276Speter break; 28950276Speter } 29062449Speter } else { /* if (_nc_syntax == SYN_TERMINFO) */ 29150276Speter for (ap = _nc_infoalias_table; ap->from; ap++) 29262449Speter if (strcmp(ap->from, _nc_curr_token.tk_name) == 0) { 29362449Speter if (ap->to == (char *) 0) { 29450276Speter _nc_warning("%s (%s terminfo extension) ignored", 29566963Speter ap->from, ap->source); 29650276Speter goto nexttok; 29750276Speter } 29850276Speter 29950276Speter entry_ptr = _nc_find_entry(ap->to, _nc_info_hash_table); 30050276Speter if (entry_ptr && !silent) 30162449Speter _nc_warning("%s (%s terminfo extension) aliased to %s", 30266963Speter ap->from, ap->source, ap->to); 30350276Speter break; 30450276Speter } 30550276Speter 30650276Speter if (entry_ptr == NOTFOUND) { 30750276Speter entry_ptr = lookup_fullname(_nc_curr_token.tk_name); 30850276Speter } 30950276Speter } 31050276Speter } 31150276Speter#if NCURSES_XNAMES 31250276Speter /* 31350276Speter * If we have extended-names active, we will automatically 31450276Speter * define a name based on its context. 31550276Speter */ 31650276Speter if (entry_ptr == NOTFOUND 31762449Speter && _nc_user_definable 31862449Speter && (entry_ptr = _nc_extend_names(entryp, 31966963Speter _nc_curr_token.tk_name, 32066963Speter token_type)) != 0) { 32162449Speter if (_nc_tracing >= DEBUG_LEVEL(1)) 32262449Speter _nc_warning("extended capability '%s'", _nc_curr_token.tk_name); 32350276Speter } 32450276Speter#endif /* NCURSES_XNAMES */ 32550276Speter 32650276Speter /* can't find this cap name, not even as an alias */ 32750276Speter if (entry_ptr == NOTFOUND) { 32850276Speter if (!silent) 32950276Speter _nc_warning("unknown capability '%s'", 33066963Speter _nc_curr_token.tk_name); 33150276Speter continue; 33250276Speter } 33350276Speter 33450276Speter /* deal with bad type/value combinations. */ 33562449Speter if (token_type != CANCEL && entry_ptr->nte_type != token_type) { 33650276Speter /* 33750276Speter * Nasty special cases here handle situations in which type 33850276Speter * information can resolve name clashes. Normal lookup 33950276Speter * finds the last instance in the capability table of a 34050276Speter * given name, regardless of type. find_type_entry looks 34150276Speter * for a first matching instance with given type. So as 34250276Speter * long as all ambiguous names occur in pairs of distinct 34350276Speter * type, this will do the job. 34450276Speter */ 34550276Speter 34650276Speter /* tell max_attributes from arrow_key_map */ 34750276Speter if (token_type == NUMBER && !strcmp("ma", _nc_curr_token.tk_name)) 34850276Speter entry_ptr = _nc_find_type_entry("ma", NUMBER, 34966963Speter _nc_get_table(_nc_syntax 35066963Speter != 0)); 35150276Speter 35250276Speter /* map terminfo's string MT to MT */ 35362449Speter else if (token_type == STRING && !strcmp("MT", _nc_curr_token.tk_name)) 35450276Speter entry_ptr = _nc_find_type_entry("MT", STRING, 35566963Speter _nc_get_table(_nc_syntax 35666963Speter != 0)); 35750276Speter 35850276Speter /* treat strings without following "=" as empty strings */ 35962449Speter else if (token_type == BOOLEAN && entry_ptr->nte_type == STRING) 36050276Speter token_type = STRING; 36150276Speter /* we couldn't recover; skip this token */ 36262449Speter else { 36362449Speter if (!silent) { 36450276Speter const char *type_name; 36562449Speter switch (entry_ptr->nte_type) { 36650276Speter case BOOLEAN: 36762449Speter type_name = "boolean"; 36862449Speter break; 36950276Speter case STRING: 37062449Speter type_name = "string"; 37162449Speter break; 37250276Speter case NUMBER: 37362449Speter type_name = "numeric"; 37462449Speter break; 37550276Speter default: 37662449Speter type_name = "unknown"; 37762449Speter break; 37850276Speter } 37950276Speter _nc_warning("wrong type used for %s capability '%s'", 38066963Speter type_name, _nc_curr_token.tk_name); 38150276Speter } 38250276Speter continue; 38350276Speter } 38450276Speter } 38550276Speter 38650276Speter /* now we know that the type/value combination is OK */ 38750276Speter switch (token_type) { 38850276Speter case CANCEL: 38950276Speter switch (entry_ptr->nte_type) { 39050276Speter case BOOLEAN: 39150276Speter entryp->tterm.Booleans[entry_ptr->nte_index] = CANCELLED_BOOLEAN; 39250276Speter break; 39350276Speter 39450276Speter case NUMBER: 39550276Speter entryp->tterm.Numbers[entry_ptr->nte_index] = CANCELLED_NUMERIC; 39650276Speter break; 39750276Speter 39850276Speter case STRING: 39950276Speter entryp->tterm.Strings[entry_ptr->nte_index] = CANCELLED_STRING; 40050276Speter break; 40150276Speter } 40250276Speter break; 40350276Speter 40450276Speter case BOOLEAN: 40550276Speter entryp->tterm.Booleans[entry_ptr->nte_index] = TRUE; 40650276Speter break; 40750276Speter 40850276Speter case NUMBER: 40950276Speter entryp->tterm.Numbers[entry_ptr->nte_index] = 41050276Speter _nc_curr_token.tk_valnumber; 41150276Speter break; 41250276Speter 41350276Speter case STRING: 41450276Speter ptr = _nc_curr_token.tk_valstring; 41562449Speter if (_nc_syntax == SYN_TERMCAP) 41650276Speter ptr = _nc_captoinfo(_nc_curr_token.tk_name, 41766963Speter ptr, 41866963Speter parametrized[entry_ptr->nte_index]); 41950276Speter entryp->tterm.Strings[entry_ptr->nte_index] = _nc_save_str(ptr); 42050276Speter break; 42150276Speter 42250276Speter default: 42350276Speter if (!silent) 42450276Speter _nc_warning("unknown token type"); 42562449Speter _nc_panic_mode((_nc_syntax == SYN_TERMCAP) ? ':' : ','); 42650276Speter continue; 42750276Speter } 42862449Speter } /* end else cur_token.name != "use" */ 42962449Speter nexttok: 43062449Speter continue; /* cannot have a label w/o statement */ 43162449Speter } /* endwhile (not EOF and not NAMES) */ 43250276Speter 43350276Speter _nc_push_token(token_type); 43450276Speter _nc_set_type(_nc_first_name(entryp->tterm.term_names)); 43550276Speter 43650276Speter /* 43750276Speter * Try to deduce as much as possible from extension capabilities 43850276Speter * (this includes obsolete BSD capabilities). Sigh...it would be more 43950276Speter * space-efficient to call this after use resolution, but it has 44050276Speter * to be done before entry allocation is wrapped up. 44150276Speter */ 44250276Speter if (!literal) { 44362449Speter if (_nc_syntax == SYN_TERMCAP) { 44462449Speter bool has_base_entry = FALSE; 44562449Speter int i; 44650276Speter 44750276Speter /* 44850276Speter * Don't insert defaults if this is a `+' entry meant only 44950276Speter * for inclusion in other entries (not sure termcap ever 45050276Speter * had these, actually). 45150276Speter */ 45250276Speter if (strchr(entryp->tterm.term_names, '+')) 45350276Speter has_base_entry = TRUE; 45450276Speter else 45550276Speter /* 45650276Speter * Otherwise, look for a base entry that will already 45750276Speter * have picked up defaults via translation. 45850276Speter */ 45950276Speter for (i = 0; i < entryp->nuses; i++) 46062449Speter if (!strchr((char *) entryp->uses[i].name, '+')) 46150276Speter has_base_entry = TRUE; 46250276Speter 46350276Speter postprocess_termcap(&entryp->tterm, has_base_entry); 46462449Speter } else 46550276Speter postprocess_terminfo(&entryp->tterm); 46650276Speter } 46750276Speter _nc_wrap_entry(entryp); 46850276Speter 46962449Speter return (OK); 47050276Speter} 47150276Speter 47262449Speterint 47362449Speter_nc_capcmp(const char *s, const char *t) 47450276Speter/* compare two string capabilities, stripping out padding */ 47550276Speter{ 47650276Speter if (!s && !t) 47762449Speter return (0); 47850276Speter else if (!s || !t) 47962449Speter return (1); 48050276Speter 48162449Speter for (;;) { 48262449Speter if (s[0] == '$' && s[1] == '<') { 48362449Speter for (s += 2;; s++) 48462449Speter if (!(isdigit(*s) || *s == '.' || *s == '*' || *s == '/' || 48566963Speter *s == '>')) 48650276Speter break; 48750276Speter } 48850276Speter 48962449Speter if (t[0] == '$' && t[1] == '<') { 49062449Speter for (t += 2;; t++) 49162449Speter if (!(isdigit(*t) || *t == '.' || *t == '*' || *t == '/' || 49266963Speter *t == '>')) 49350276Speter break; 49450276Speter } 49550276Speter 49650276Speter /* we've now pushed s and t past any padding they were pointing at */ 49750276Speter 49850276Speter if (*s == '\0' && *t == '\0') 49962449Speter return (0); 50050276Speter 50150276Speter if (*s != *t) 50262449Speter return (*t - *s); 50350276Speter 50450276Speter /* else *s == *t but one is not NUL, so continue */ 50550276Speter s++, t++; 50650276Speter } 50750276Speter} 50850276Speter 50966963Speterstatic void 51066963Speterappend_acs0(string_desc *dst, int code, int src) 51166963Speter{ 51266963Speter if (src != 0) { 51366963Speter char temp[3]; 51466963Speter temp[0] = code; 51566963Speter temp[1] = src; 51666963Speter temp[2] = 0; 51766963Speter _nc_safe_strcat(dst, temp); 51866963Speter } 51966963Speter} 52066963Speter 52166963Speterstatic void 52266963Speterappend_acs(string_desc *dst, int code, char *src) 52366963Speter{ 52466963Speter if (src != 0 && strlen(src) == 1) { 52566963Speter append_acs0(dst, code, *src); 52666963Speter } 52766963Speter} 52866963Speter 52950276Speter/* 53050276Speter * The ko capability, if present, consists of a comma-separated capability 53150276Speter * list. For each capability, we may assume there is a keycap that sends the 53250276Speter * string which is the value of that capability. 53350276Speter */ 53462449Spetertypedef struct { 53562449Speter const char *from; 53662449Speter const char *to; 53762449Speter} assoc; 53850276Speterstatic assoc const ko_xlate[] = 53950276Speter{ 54062449Speter {"al", "kil1"}, /* insert line key -> KEY_IL */ 54162449Speter {"bt", "kcbt"}, /* back tab -> KEY_BTAB */ 54262449Speter {"cd", "ked"}, /* clear-to-eos key -> KEY_EOL */ 54362449Speter {"ce", "kel"}, /* clear-to-eol key -> KEY_EOS */ 54462449Speter {"cl", "kclr"}, /* clear key -> KEY_CLEAR */ 54562449Speter {"ct", "tbc"}, /* clear all tabs -> KEY_CATAB */ 54662449Speter {"dc", "kdch1"}, /* delete char -> KEY_DC */ 54762449Speter {"dl", "kdl1"}, /* delete line -> KEY_DL */ 54862449Speter {"do", "kcud1"}, /* down key -> KEY_DOWN */ 54962449Speter {"ei", "krmir"}, /* exit insert key -> KEY_EIC */ 55062449Speter {"ho", "khome"}, /* home key -> KEY_HOME */ 55162449Speter {"ic", "kich1"}, /* insert char key -> KEY_IC */ 55262449Speter {"im", "kIC"}, /* insert-mode key -> KEY_SIC */ 55362449Speter {"le", "kcub1"}, /* le key -> KEY_LEFT */ 55462449Speter {"nd", "kcuf1"}, /* nd key -> KEY_RIGHT */ 55562449Speter {"nl", "kent"}, /* new line key -> KEY_ENTER */ 55662449Speter {"st", "khts"}, /* set-tab key -> KEY_STAB */ 55762449Speter {"ta", CANCELLED_STRING}, 55862449Speter {"up", "kcuu1"}, /* up-arrow key -> KEY_UP */ 55962449Speter {(char *) 0, (char *) 0}, 56050276Speter}; 56150276Speter 56250276Speter/* 56350276Speter * This routine fills in string caps that either had defaults under 56450276Speter * termcap or can be manufactured from obsolete termcap capabilities. 56550276Speter * It was lifted from Ross Ridge's mytinfo package. 56650276Speter */ 56750276Speter 56850276Speterstatic const char C_CR[] = "\r"; 56950276Speterstatic const char C_LF[] = "\n"; 57050276Speterstatic const char C_BS[] = "\b"; 57150276Speterstatic const char C_HT[] = "\t"; 57250276Speter 57350276Speter/* 57450276Speter * Note that WANTED and PRESENT are not simple inverses! If a capability 57550276Speter * has been explicitly cancelled, it's not considered WANTED. 57650276Speter */ 57750276Speter#define WANTED(s) ((s) == ABSENT_STRING) 57850276Speter#define PRESENT(s) (((s) != ABSENT_STRING) && ((s) != CANCELLED_STRING)) 57950276Speter 58050276Speter/* 58150276Speter * This bit of legerdemain turns all the terminfo variable names into 58250276Speter * references to locations in the arrays Booleans, Numbers, and Strings --- 58350276Speter * precisely what's needed. 58450276Speter */ 58550276Speter 58650276Speter#undef CUR 58750276Speter#define CUR tp-> 58850276Speter 58966963Speterstatic void 59062449Speterpostprocess_termcap(TERMTYPE * tp, bool has_base) 59150276Speter{ 59250276Speter char buf[MAX_LINE * 2 + 2]; 59366963Speter string_desc result; 59450276Speter 59550276Speter /* 59650276Speter * TERMCAP DEFAULTS AND OBSOLETE-CAPABILITY TRANSLATIONS 59750276Speter * 59850276Speter * This first part of the code is the functional inverse of the 59950276Speter * fragment in capdefaults.c. 60050276Speter * ---------------------------------------------------------------------- 60150276Speter */ 60250276Speter 60350276Speter /* if there was a tc entry, assume we picked up defaults via that */ 60462449Speter if (!has_base) { 60550276Speter if (WANTED(init_3string) && termcap_init2) 60650276Speter init_3string = _nc_save_str(termcap_init2); 60750276Speter 60850276Speter if (WANTED(reset_2string) && termcap_reset) 60950276Speter reset_2string = _nc_save_str(termcap_reset); 61050276Speter 61150276Speter if (WANTED(carriage_return)) { 61250276Speter if (carriage_return_delay > 0) { 61350276Speter sprintf(buf, "%s$<%d>", C_CR, carriage_return_delay); 61450276Speter carriage_return = _nc_save_str(buf); 61550276Speter } else 61650276Speter carriage_return = _nc_save_str(C_CR); 61750276Speter } 61850276Speter if (WANTED(cursor_left)) { 61950276Speter if (backspace_delay > 0) { 62050276Speter sprintf(buf, "%s$<%d>", C_BS, backspace_delay); 62150276Speter cursor_left = _nc_save_str(buf); 62250276Speter } else if (backspaces_with_bs == 1) 62350276Speter cursor_left = _nc_save_str(C_BS); 62450276Speter else if (PRESENT(backspace_if_not_bs)) 62550276Speter cursor_left = backspace_if_not_bs; 62650276Speter } 62750276Speter /* vi doesn't use "do", but it does seems to use nl (or '\n') instead */ 62850276Speter if (WANTED(cursor_down)) { 62950276Speter if (PRESENT(linefeed_if_not_lf)) 63050276Speter cursor_down = linefeed_if_not_lf; 63150276Speter else if (linefeed_is_newline != 1) { 63250276Speter if (new_line_delay > 0) { 63350276Speter sprintf(buf, "%s$<%d>", C_LF, new_line_delay); 63450276Speter cursor_down = _nc_save_str(buf); 63550276Speter } else 63650276Speter cursor_down = _nc_save_str(C_LF); 63750276Speter } 63850276Speter } 63950276Speter if (WANTED(scroll_forward) && crt_no_scrolling != 1) { 64050276Speter if (PRESENT(linefeed_if_not_lf)) 64150276Speter cursor_down = linefeed_if_not_lf; 64250276Speter else if (linefeed_is_newline != 1) { 64350276Speter if (new_line_delay > 0) { 64450276Speter sprintf(buf, "%s$<%d>", C_LF, new_line_delay); 64550276Speter scroll_forward = _nc_save_str(buf); 64650276Speter } else 64750276Speter scroll_forward = _nc_save_str(C_LF); 64850276Speter } 64950276Speter } 65050276Speter if (WANTED(newline)) { 65150276Speter if (linefeed_is_newline == 1) { 65250276Speter if (new_line_delay > 0) { 65350276Speter sprintf(buf, "%s$<%d>", C_LF, new_line_delay); 65450276Speter newline = _nc_save_str(buf); 65550276Speter } else 65650276Speter newline = _nc_save_str(C_LF); 65750276Speter } else if (PRESENT(carriage_return) && PRESENT(scroll_forward)) { 65866963Speter _nc_str_init(&result, buf, sizeof(buf)); 65966963Speter if (_nc_safe_strcat(&result, carriage_return) 66066963Speter && _nc_safe_strcat(&result, scroll_forward)) 66166963Speter newline = _nc_save_str(buf); 66250276Speter } else if (PRESENT(carriage_return) && PRESENT(cursor_down)) { 66366963Speter _nc_str_init(&result, buf, sizeof(buf)); 66466963Speter if (_nc_safe_strcat(&result, carriage_return) 66566963Speter && _nc_safe_strcat(&result, cursor_down)) 66666963Speter newline = _nc_save_str(buf); 66750276Speter } 66850276Speter } 66950276Speter } 67050276Speter 67150276Speter /* 67250276Speter * Inverse of capdefaults.c code ends here. 67350276Speter * ---------------------------------------------------------------------- 67450276Speter * 67550276Speter * TERMCAP-TO TERMINFO MAPPINGS FOR SOURCE TRANSLATION 67650276Speter * 67750276Speter * These translations will *not* be inverted by tgetent(). 67850276Speter */ 67950276Speter 68062449Speter if (!has_base) { 68150276Speter /* 68250276Speter * We wait until now to decide if we've got a working cr because even 68350276Speter * one that doesn't work can be used for newline. Unfortunately the 68450276Speter * space allocated for it is wasted. 68550276Speter */ 68650276Speter if (return_does_clr_eol == 1 || no_correctly_working_cr == 1) 68750276Speter carriage_return = ABSENT_STRING; 68850276Speter 68950276Speter /* 69050276Speter * Supposedly most termcap entries have ta now and '\t' is no longer a 69150276Speter * default, but it doesn't seem to be true... 69250276Speter */ 69350276Speter if (WANTED(tab)) { 69450276Speter if (horizontal_tab_delay > 0) { 69550276Speter sprintf(buf, "%s$<%d>", C_HT, horizontal_tab_delay); 69650276Speter tab = _nc_save_str(buf); 69750276Speter } else 69850276Speter tab = _nc_save_str(C_HT); 69950276Speter } 70050276Speter if (init_tabs == ABSENT_NUMERIC && has_hardware_tabs == TRUE) 70150276Speter init_tabs = 8; 70250276Speter 70350276Speter /* 70450276Speter * Assume we can beep with ^G unless we're given bl@. 70550276Speter */ 70650276Speter if (WANTED(bell)) 70750276Speter bell = _nc_save_str("\007"); 70850276Speter } 70950276Speter 71050276Speter /* 71150276Speter * Translate the old termcap :pt: capability to it#8 + ht=\t 71250276Speter */ 71350276Speter if (has_hardware_tabs == TRUE) { 71450276Speter if (init_tabs != 8 && init_tabs != ABSENT_NUMERIC) 71550276Speter _nc_warning("hardware tabs with a width other than 8: %d", init_tabs); 71662449Speter else { 71750276Speter if (tab && _nc_capcmp(tab, C_HT)) 71850276Speter _nc_warning("hardware tabs with a non-^I tab string %s", 71966963Speter _nc_visbuf(tab)); 72062449Speter else { 72150276Speter if (WANTED(tab)) 72250276Speter tab = _nc_save_str(C_HT); 72350276Speter init_tabs = 8; 72450276Speter } 72550276Speter } 72650276Speter } 72750276Speter /* 72850276Speter * Now translate the ko capability, if there is one. This 72950276Speter * isn't from mytinfo... 73050276Speter */ 73162449Speter if (PRESENT(other_non_function_keys)) { 73266963Speter char *base = other_non_function_keys; 73366963Speter char *bp, *cp, *dp; 73462449Speter struct name_table_entry const *from_ptr; 73562449Speter struct name_table_entry const *to_ptr; 73662449Speter assoc const *ap; 73762449Speter char buf2[MAX_TERMINFO_LENGTH]; 73862449Speter bool foundim; 73950276Speter 74050276Speter /* we're going to use this for a special case later */ 74150276Speter dp = strchr(other_non_function_keys, 'i'); 74266963Speter foundim = (dp != 0) && (dp[1] == 'm'); 74350276Speter 74450276Speter /* look at each comma-separated capability in the ko string... */ 74566963Speter for (base = other_non_function_keys; 74666963Speter (cp = strchr(base, ',')) != 0; 74766963Speter base = cp + 1) { 74866963Speter size_t len = cp - base; 74966963Speter 75050276Speter for (ap = ko_xlate; ap->from; ap++) 75166963Speter if (len == strlen(ap->from) 75266963Speter && strncmp(ap->from, base, len) == 0) 75350276Speter break; 75462449Speter if (!ap->to) { 75566963Speter _nc_warning("unknown capability `%.*s' in ko string", 75666963Speter (int) len, base); 75750276Speter continue; 75862449Speter } else if (ap->to == CANCELLED_STRING) /* ignore it */ 75950276Speter continue; 76050276Speter 76150276Speter /* now we know we found a match in ko_table, so... */ 76250276Speter 76350276Speter from_ptr = _nc_find_entry(ap->from, _nc_cap_hash_table); 76462449Speter to_ptr = _nc_find_entry(ap->to, _nc_info_hash_table); 76550276Speter 76650276Speter if (!from_ptr || !to_ptr) /* should never happen! */ 76750276Speter _nc_err_abort("ko translation table is invalid, I give up"); 76850276Speter 76962449Speter if (WANTED(tp->Strings[from_ptr->nte_index])) { 77050276Speter _nc_warning("no value for ko capability %s", ap->from); 77150276Speter continue; 77250276Speter } 77350276Speter 77462449Speter if (tp->Strings[to_ptr->nte_index]) { 77550276Speter /* There's no point in warning about it if it's the same 77650276Speter * string; that's just an inefficiency. 77750276Speter */ 77850276Speter if (strcmp( 77966963Speter tp->Strings[from_ptr->nte_index], 78066963Speter tp->Strings[to_ptr->nte_index]) != 0) 78150276Speter _nc_warning("%s (%s) already has an explicit value %s, ignoring ko", 78266963Speter ap->to, ap->from, 78366963Speter _nc_visbuf(tp->Strings[to_ptr->nte_index])); 78450276Speter continue; 78550276Speter } 78650276Speter 78750276Speter /* 78850276Speter * The magic moment -- copy the mapped key string over, 78950276Speter * stripping out padding. 79050276Speter */ 79166963Speter for (dp = buf2, bp = tp->Strings[from_ptr->nte_index]; *bp; bp++) { 79266963Speter if (bp[0] == '$' && bp[1] == '<') { 79366963Speter while (*bp && *bp != '>') { 79466963Speter ++bp; 79566963Speter } 79662449Speter } else 79766963Speter *dp++ = *bp; 79850276Speter } 79950276Speter *dp++ = '\0'; 80050276Speter 80150276Speter tp->Strings[to_ptr->nte_index] = _nc_save_str(buf2); 80266963Speter } 80350276Speter 80450276Speter /* 80550276Speter * Note: ko=im and ko=ic both want to grab the `Insert' 80650276Speter * keycap. There's a kich1 but no ksmir, so the ic capability 80750276Speter * got mapped to kich1 and im to kIC to avoid a collision. 80850276Speter * If the description has im but not ic, hack kIC back to kich1. 80950276Speter */ 81062449Speter if (foundim && WANTED(key_ic) && key_sic) { 81150276Speter key_ic = key_sic; 81250276Speter key_sic = ABSENT_STRING; 81350276Speter } 81450276Speter } 81550276Speter 81662449Speter if (!hard_copy) { 81750276Speter if (WANTED(key_backspace)) 81850276Speter key_backspace = _nc_save_str(C_BS); 81950276Speter if (WANTED(key_left)) 82050276Speter key_left = _nc_save_str(C_BS); 82150276Speter if (WANTED(key_down)) 82250276Speter key_down = _nc_save_str(C_LF); 82350276Speter } 82450276Speter 82550276Speter /* 82650276Speter * Translate XENIX forms characters. 82750276Speter */ 82850276Speter if (PRESENT(acs_ulcorner) || 82950276Speter PRESENT(acs_llcorner) || 83050276Speter PRESENT(acs_urcorner) || 83150276Speter PRESENT(acs_lrcorner) || 83250276Speter PRESENT(acs_ltee) || 83350276Speter PRESENT(acs_rtee) || 83450276Speter PRESENT(acs_btee) || 83550276Speter PRESENT(acs_ttee) || 83650276Speter PRESENT(acs_hline) || 83750276Speter PRESENT(acs_vline) || 83862449Speter PRESENT(acs_plus)) { 83966963Speter char buf2[MAX_TERMCAP_LENGTH]; 84050276Speter 84166963Speter _nc_str_init(&result, buf2, sizeof(buf2)); 84266963Speter _nc_safe_strcat(&result, acs_chars); 84350276Speter 84466963Speter append_acs (&result, 'j', acs_lrcorner); 84566963Speter append_acs (&result, 'k', acs_urcorner); 84666963Speter append_acs (&result, 'l', acs_ulcorner); 84766963Speter append_acs (&result, 'm', acs_llcorner); 84866963Speter append_acs (&result, 'n', acs_plus); 84966963Speter append_acs (&result, 'q', acs_hline); 85066963Speter append_acs (&result, 't', acs_ltee); 85166963Speter append_acs (&result, 'u', acs_rtee); 85266963Speter append_acs (&result, 'v', acs_btee); 85366963Speter append_acs (&result, 'w', acs_ttee); 85466963Speter append_acs (&result, 'x', acs_vline); 85550276Speter 85666963Speter if (buf2[0]) { 85750276Speter acs_chars = _nc_save_str(buf2); 85850276Speter _nc_warning("acsc string synthesized from XENIX capabilities"); 85950276Speter } 86062449Speter } else if (acs_chars == 0 86166963Speter && enter_alt_charset_mode != 0 86266963Speter && exit_alt_charset_mode != 0) { 86362449Speter acs_chars = 86462449Speter _nc_save_str("``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~"); 86550276Speter } 86650276Speter} 86750276Speter 86866963Speterstatic void 86962449Speterpostprocess_terminfo(TERMTYPE * tp) 87050276Speter{ 87150276Speter /* 87250276Speter * TERMINFO-TO-TERMINFO MAPPINGS FOR SOURCE TRANSLATION 87350276Speter * ---------------------------------------------------------------------- 87450276Speter */ 87550276Speter 87650276Speter /* 87750276Speter * Translate AIX forms characters. 87850276Speter */ 87962449Speter if (PRESENT(box_chars_1)) { 88066963Speter char buf2[MAX_TERMCAP_LENGTH]; 88166963Speter string_desc result; 88250276Speter 88366963Speter _nc_str_init(&result, buf2, sizeof(buf2)); 88466963Speter _nc_safe_strcat(&result, acs_chars); 88550276Speter 88666963Speter append_acs0 (&result, 'l', box_chars_1[0]); /* ACS_ULCORNER */ 88766963Speter append_acs0 (&result, 'q', box_chars_1[1]); /* ACS_HLINE */ 88866963Speter append_acs0 (&result, 'k', box_chars_1[2]); /* ACS_URCORNER */ 88966963Speter append_acs0 (&result, 'x', box_chars_1[3]); /* ACS_VLINE */ 89066963Speter append_acs0 (&result, 'j', box_chars_1[4]); /* ACS_LRCORNER */ 89166963Speter append_acs0 (&result, 'm', box_chars_1[5]); /* ACS_LLCORNER */ 89266963Speter append_acs0 (&result, 'w', box_chars_1[6]); /* ACS_TTEE */ 89366963Speter append_acs0 (&result, 'u', box_chars_1[7]); /* ACS_RTEE */ 89466963Speter append_acs0 (&result, 'v', box_chars_1[8]); /* ACS_BTEE */ 89566963Speter append_acs0 (&result, 't', box_chars_1[9]); /* ACS_LTEE */ 89666963Speter append_acs0 (&result, 'n', box_chars_1[10]); /* ACS_PLUS */ 89750276Speter 89866963Speter if (buf2[0]) { 89950276Speter acs_chars = _nc_save_str(buf2); 90050276Speter _nc_warning("acsc string synthesized from AIX capabilities"); 90150276Speter box_chars_1 = ABSENT_STRING; 90250276Speter } 90350276Speter } 90450276Speter /* 90550276Speter * ---------------------------------------------------------------------- 90650276Speter */ 90750276Speter} 90850276Speter 90950276Speter/* 91050276Speter * Do a linear search through the terminfo tables to find a given full-name. 91150276Speter * We don't expect to do this often, so there's no hashing function. 91250276Speter * 91350276Speter * In effect, this scans through the 3 lists of full-names, and looks them 91450276Speter * up in _nc_info_table, which is organized so that the nte_index fields are 91550276Speter * sorted, but the nte_type fields are not necessarily grouped together. 91650276Speter */ 91766963Speterstatic struct name_table_entry const * 91862449Speterlookup_fullname(const char *find) 91950276Speter{ 92050276Speter int state = -1; 92150276Speter 92250276Speter for (;;) { 92350276Speter int count = 0; 92450276Speter NCURSES_CONST char *const *names; 92550276Speter 92650276Speter switch (++state) { 92750276Speter case BOOLEAN: 92850276Speter names = boolfnames; 92950276Speter break; 93050276Speter case STRING: 93150276Speter names = strfnames; 93250276Speter break; 93350276Speter case NUMBER: 93450276Speter names = numfnames; 93550276Speter break; 93650276Speter default: 93750276Speter return NOTFOUND; 93850276Speter } 93950276Speter 94050276Speter for (count = 0; names[count] != 0; count++) { 94150276Speter if (!strcmp(names[count], find)) { 94262449Speter struct name_table_entry const *entry_ptr = _nc_get_table(FALSE); 94362449Speter while (entry_ptr->nte_type != state 94466963Speter || entry_ptr->nte_index != count) 94562449Speter entry_ptr++; 94650276Speter return entry_ptr; 94750276Speter } 94850276Speter } 94950276Speter } 95050276Speter} 95150276Speter 95250276Speter/* parse_entry.c ends here */ 953