parse_entry.c revision 97049
150276Speter/**************************************************************************** 297049Speter * Copyright (c) 1998-2001,2002 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 5097049SpeterMODULE_ID("$Id: parse_entry.c,v 1.55 2002/04/22 00:01:30 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 19876726SpeterNCURSES_EXPORT(int) 19976726Speter_nc_parse_entry 20076726Speter(struct entry *entryp, int literal, bool silent) 20150276Speter{ 20262449Speter int token_type; 20362449Speter struct name_table_entry const *entry_ptr; 20466963Speter char *ptr, *base; 20550276Speter 20676726Speter token_type = _nc_get_token(silent); 20750276Speter 20850276Speter if (token_type == EOF) 20962449Speter return (EOF); 21050276Speter if (token_type != NAMES) 21150276Speter _nc_err_abort("Entry does not start with terminal names in column one"); 21250276Speter 21350276Speter _nc_init_entry(&entryp->tterm); 21450276Speter 21550276Speter entryp->cstart = _nc_comment_start; 21650276Speter entryp->cend = _nc_comment_end; 21750276Speter entryp->startline = _nc_start_line; 21850276Speter DEBUG(2, ("Comment range is %ld to %ld", entryp->cstart, entryp->cend)); 21950276Speter 22050276Speter /* junk the 2-character termcap name, if present */ 22150276Speter ptr = _nc_curr_token.tk_name; 22262449Speter if (ptr[2] == '|') { 22350276Speter ptr = _nc_curr_token.tk_name + 3; 22450276Speter _nc_curr_token.tk_name[2] = '\0'; 22550276Speter } 22650276Speter 22750276Speter entryp->tterm.str_table = entryp->tterm.term_names = _nc_save_str(ptr); 22850276Speter 22950276Speter DEBUG(1, ("Starting '%s'", ptr)); 23050276Speter 23150276Speter /* 23250276Speter * We do this because the one-token lookahead in the parse loop 23350276Speter * results in the terminal type getting prematurely set to correspond 23450276Speter * to that of the next entry. 23550276Speter */ 23650276Speter _nc_set_type(_nc_first_name(entryp->tterm.term_names)); 23750276Speter 23850276Speter /* check for overly-long names and aliases */ 23966963Speter for (base = entryp->tterm.term_names; (ptr = strchr(base, '|')) != 0; 24066963Speter base = ptr + 1) { 24166963Speter if (ptr - base > MAX_ALIAS) { 24266963Speter _nc_warning("%s `%.*s' may be too long", 24366963Speter (base == entryp->tterm.term_names) 24466963Speter ? "primary name" 24566963Speter : "alias", 24697049Speter (int) (ptr - base), base); 24766963Speter } 24866963Speter } 24950276Speter 25050276Speter entryp->nuses = 0; 25150276Speter 25276726Speter for (token_type = _nc_get_token(silent); 25366963Speter token_type != EOF && token_type != NAMES; 25476726Speter token_type = _nc_get_token(silent)) { 25550276Speter if (strcmp(_nc_curr_token.tk_name, "use") == 0 25650276Speter || strcmp(_nc_curr_token.tk_name, "tc") == 0) { 25762449Speter entryp->uses[entryp->nuses].name = _nc_save_str(_nc_curr_token.tk_valstring); 25850276Speter entryp->uses[entryp->nuses].line = _nc_curr_line; 25950276Speter entryp->nuses++; 26050276Speter } else { 26150276Speter /* normal token lookup */ 26250276Speter entry_ptr = _nc_find_entry(_nc_curr_token.tk_name, 26366963Speter _nc_syntax ? _nc_cap_hash_table : _nc_info_hash_table); 26450276Speter 26550276Speter /* 26650276Speter * Our kluge to handle aliasing. The reason it's done 26750276Speter * this ugly way, with a linear search, is so the hashing 26850276Speter * machinery doesn't have to be made really complicated 26950276Speter * (also we get better warnings this way). No point in 27050276Speter * making this case fast, aliased caps aren't common now 27150276Speter * and will get rarer. 27250276Speter */ 27362449Speter if (entry_ptr == NOTFOUND) { 27462449Speter const struct alias *ap; 27550276Speter 27662449Speter if (_nc_syntax == SYN_TERMCAP) { 27750276Speter for (ap = _nc_capalias_table; ap->from; ap++) 27862449Speter if (strcmp(ap->from, _nc_curr_token.tk_name) == 0) { 27962449Speter if (ap->to == (char *) 0) { 28050276Speter _nc_warning("%s (%s termcap extension) ignored", 28166963Speter ap->from, ap->source); 28250276Speter goto nexttok; 28350276Speter } 28450276Speter 28550276Speter entry_ptr = _nc_find_entry(ap->to, _nc_cap_hash_table); 28650276Speter if (entry_ptr && !silent) 28762449Speter _nc_warning("%s (%s termcap extension) aliased to %s", 28866963Speter ap->from, ap->source, ap->to); 28950276Speter break; 29050276Speter } 29162449Speter } else { /* if (_nc_syntax == SYN_TERMINFO) */ 29250276Speter for (ap = _nc_infoalias_table; ap->from; ap++) 29362449Speter if (strcmp(ap->from, _nc_curr_token.tk_name) == 0) { 29462449Speter if (ap->to == (char *) 0) { 29550276Speter _nc_warning("%s (%s terminfo extension) ignored", 29666963Speter ap->from, ap->source); 29750276Speter goto nexttok; 29850276Speter } 29950276Speter 30050276Speter entry_ptr = _nc_find_entry(ap->to, _nc_info_hash_table); 30150276Speter if (entry_ptr && !silent) 30262449Speter _nc_warning("%s (%s terminfo extension) aliased to %s", 30366963Speter ap->from, ap->source, ap->to); 30450276Speter break; 30550276Speter } 30650276Speter 30750276Speter if (entry_ptr == NOTFOUND) { 30850276Speter entry_ptr = lookup_fullname(_nc_curr_token.tk_name); 30950276Speter } 31050276Speter } 31150276Speter } 31250276Speter#if NCURSES_XNAMES 31350276Speter /* 31450276Speter * If we have extended-names active, we will automatically 31550276Speter * define a name based on its context. 31650276Speter */ 31750276Speter if (entry_ptr == NOTFOUND 31862449Speter && _nc_user_definable 31962449Speter && (entry_ptr = _nc_extend_names(entryp, 32066963Speter _nc_curr_token.tk_name, 32166963Speter token_type)) != 0) { 32262449Speter if (_nc_tracing >= DEBUG_LEVEL(1)) 32362449Speter _nc_warning("extended capability '%s'", _nc_curr_token.tk_name); 32450276Speter } 32550276Speter#endif /* NCURSES_XNAMES */ 32650276Speter 32750276Speter /* can't find this cap name, not even as an alias */ 32850276Speter if (entry_ptr == NOTFOUND) { 32950276Speter if (!silent) 33050276Speter _nc_warning("unknown capability '%s'", 33166963Speter _nc_curr_token.tk_name); 33250276Speter continue; 33350276Speter } 33450276Speter 33550276Speter /* deal with bad type/value combinations. */ 33662449Speter if (token_type != CANCEL && entry_ptr->nte_type != token_type) { 33750276Speter /* 33850276Speter * Nasty special cases here handle situations in which type 33950276Speter * information can resolve name clashes. Normal lookup 34050276Speter * finds the last instance in the capability table of a 34150276Speter * given name, regardless of type. find_type_entry looks 34250276Speter * for a first matching instance with given type. So as 34350276Speter * long as all ambiguous names occur in pairs of distinct 34450276Speter * type, this will do the job. 34550276Speter */ 34650276Speter 34750276Speter /* tell max_attributes from arrow_key_map */ 34850276Speter if (token_type == NUMBER && !strcmp("ma", _nc_curr_token.tk_name)) 34950276Speter entry_ptr = _nc_find_type_entry("ma", NUMBER, 35066963Speter _nc_get_table(_nc_syntax 35166963Speter != 0)); 35250276Speter 35350276Speter /* map terminfo's string MT to MT */ 35462449Speter else if (token_type == STRING && !strcmp("MT", _nc_curr_token.tk_name)) 35550276Speter entry_ptr = _nc_find_type_entry("MT", STRING, 35666963Speter _nc_get_table(_nc_syntax 35766963Speter != 0)); 35850276Speter 35950276Speter /* treat strings without following "=" as empty strings */ 36062449Speter else if (token_type == BOOLEAN && entry_ptr->nte_type == STRING) 36150276Speter token_type = STRING; 36250276Speter /* we couldn't recover; skip this token */ 36362449Speter else { 36462449Speter if (!silent) { 36550276Speter const char *type_name; 36662449Speter switch (entry_ptr->nte_type) { 36750276Speter case BOOLEAN: 36862449Speter type_name = "boolean"; 36962449Speter break; 37050276Speter case STRING: 37162449Speter type_name = "string"; 37262449Speter break; 37350276Speter case NUMBER: 37462449Speter type_name = "numeric"; 37562449Speter break; 37650276Speter default: 37762449Speter type_name = "unknown"; 37862449Speter break; 37950276Speter } 38050276Speter _nc_warning("wrong type used for %s capability '%s'", 38166963Speter type_name, _nc_curr_token.tk_name); 38250276Speter } 38350276Speter continue; 38450276Speter } 38550276Speter } 38650276Speter 38750276Speter /* now we know that the type/value combination is OK */ 38850276Speter switch (token_type) { 38950276Speter case CANCEL: 39050276Speter switch (entry_ptr->nte_type) { 39150276Speter case BOOLEAN: 39250276Speter entryp->tterm.Booleans[entry_ptr->nte_index] = CANCELLED_BOOLEAN; 39350276Speter break; 39450276Speter 39550276Speter case NUMBER: 39650276Speter entryp->tterm.Numbers[entry_ptr->nte_index] = CANCELLED_NUMERIC; 39750276Speter break; 39850276Speter 39950276Speter case STRING: 40050276Speter entryp->tterm.Strings[entry_ptr->nte_index] = CANCELLED_STRING; 40150276Speter break; 40250276Speter } 40350276Speter break; 40450276Speter 40550276Speter case BOOLEAN: 40650276Speter entryp->tterm.Booleans[entry_ptr->nte_index] = TRUE; 40750276Speter break; 40850276Speter 40950276Speter case NUMBER: 41050276Speter entryp->tterm.Numbers[entry_ptr->nte_index] = 41150276Speter _nc_curr_token.tk_valnumber; 41250276Speter break; 41350276Speter 41450276Speter case STRING: 41550276Speter ptr = _nc_curr_token.tk_valstring; 41662449Speter if (_nc_syntax == SYN_TERMCAP) 41750276Speter ptr = _nc_captoinfo(_nc_curr_token.tk_name, 41866963Speter ptr, 41966963Speter parametrized[entry_ptr->nte_index]); 42050276Speter entryp->tterm.Strings[entry_ptr->nte_index] = _nc_save_str(ptr); 42150276Speter break; 42250276Speter 42350276Speter default: 42450276Speter if (!silent) 42550276Speter _nc_warning("unknown token type"); 42662449Speter _nc_panic_mode((_nc_syntax == SYN_TERMCAP) ? ':' : ','); 42750276Speter continue; 42850276Speter } 42962449Speter } /* end else cur_token.name != "use" */ 43062449Speter nexttok: 43162449Speter continue; /* cannot have a label w/o statement */ 43262449Speter } /* endwhile (not EOF and not NAMES) */ 43350276Speter 43450276Speter _nc_push_token(token_type); 43550276Speter _nc_set_type(_nc_first_name(entryp->tterm.term_names)); 43650276Speter 43750276Speter /* 43850276Speter * Try to deduce as much as possible from extension capabilities 43950276Speter * (this includes obsolete BSD capabilities). Sigh...it would be more 44050276Speter * space-efficient to call this after use resolution, but it has 44150276Speter * to be done before entry allocation is wrapped up. 44250276Speter */ 44350276Speter if (!literal) { 44462449Speter if (_nc_syntax == SYN_TERMCAP) { 44562449Speter bool has_base_entry = FALSE; 44662449Speter int i; 44750276Speter 44850276Speter /* 44950276Speter * Don't insert defaults if this is a `+' entry meant only 45050276Speter * for inclusion in other entries (not sure termcap ever 45150276Speter * had these, actually). 45250276Speter */ 45350276Speter if (strchr(entryp->tterm.term_names, '+')) 45450276Speter has_base_entry = TRUE; 45550276Speter else 45650276Speter /* 45750276Speter * Otherwise, look for a base entry that will already 45850276Speter * have picked up defaults via translation. 45950276Speter */ 46050276Speter for (i = 0; i < entryp->nuses; i++) 46162449Speter if (!strchr((char *) entryp->uses[i].name, '+')) 46250276Speter has_base_entry = TRUE; 46350276Speter 46450276Speter postprocess_termcap(&entryp->tterm, has_base_entry); 46562449Speter } else 46650276Speter postprocess_terminfo(&entryp->tterm); 46750276Speter } 46876726Speter _nc_wrap_entry(entryp, FALSE); 46950276Speter 47062449Speter return (OK); 47150276Speter} 47250276Speter 47376726SpeterNCURSES_EXPORT(int) 47462449Speter_nc_capcmp(const char *s, const char *t) 47550276Speter/* compare two string capabilities, stripping out padding */ 47650276Speter{ 47750276Speter if (!s && !t) 47862449Speter return (0); 47950276Speter else if (!s || !t) 48062449Speter return (1); 48150276Speter 48262449Speter for (;;) { 48362449Speter if (s[0] == '$' && s[1] == '<') { 48462449Speter for (s += 2;; s++) 48597049Speter if (!(isdigit(UChar(*s)) 48676726Speter || *s == '.' 48776726Speter || *s == '*' 48876726Speter || *s == '/' 48976726Speter || *s == '>')) 49050276Speter break; 49150276Speter } 49250276Speter 49362449Speter if (t[0] == '$' && t[1] == '<') { 49462449Speter for (t += 2;; t++) 49597049Speter if (!(isdigit(UChar(*t)) 49676726Speter || *t == '.' 49776726Speter || *t == '*' 49876726Speter || *t == '/' 49976726Speter || *t == '>')) 50050276Speter break; 50150276Speter } 50250276Speter 50350276Speter /* we've now pushed s and t past any padding they were pointing at */ 50450276Speter 50550276Speter if (*s == '\0' && *t == '\0') 50662449Speter return (0); 50750276Speter 50850276Speter if (*s != *t) 50962449Speter return (*t - *s); 51050276Speter 51150276Speter /* else *s == *t but one is not NUL, so continue */ 51250276Speter s++, t++; 51350276Speter } 51450276Speter} 51550276Speter 51666963Speterstatic void 51776726Speterappend_acs0(string_desc * dst, int code, int src) 51866963Speter{ 51966963Speter if (src != 0) { 52066963Speter char temp[3]; 52166963Speter temp[0] = code; 52266963Speter temp[1] = src; 52366963Speter temp[2] = 0; 52466963Speter _nc_safe_strcat(dst, temp); 52566963Speter } 52666963Speter} 52766963Speter 52866963Speterstatic void 52976726Speterappend_acs(string_desc * dst, int code, char *src) 53066963Speter{ 53166963Speter if (src != 0 && strlen(src) == 1) { 53266963Speter append_acs0(dst, code, *src); 53366963Speter } 53466963Speter} 53566963Speter 53650276Speter/* 53750276Speter * The ko capability, if present, consists of a comma-separated capability 53850276Speter * list. For each capability, we may assume there is a keycap that sends the 53950276Speter * string which is the value of that capability. 54050276Speter */ 54162449Spetertypedef struct { 54262449Speter const char *from; 54362449Speter const char *to; 54462449Speter} assoc; 54550276Speterstatic assoc const ko_xlate[] = 54650276Speter{ 54762449Speter {"al", "kil1"}, /* insert line key -> KEY_IL */ 54862449Speter {"bt", "kcbt"}, /* back tab -> KEY_BTAB */ 54962449Speter {"cd", "ked"}, /* clear-to-eos key -> KEY_EOL */ 55062449Speter {"ce", "kel"}, /* clear-to-eol key -> KEY_EOS */ 55162449Speter {"cl", "kclr"}, /* clear key -> KEY_CLEAR */ 55262449Speter {"ct", "tbc"}, /* clear all tabs -> KEY_CATAB */ 55362449Speter {"dc", "kdch1"}, /* delete char -> KEY_DC */ 55462449Speter {"dl", "kdl1"}, /* delete line -> KEY_DL */ 55562449Speter {"do", "kcud1"}, /* down key -> KEY_DOWN */ 55662449Speter {"ei", "krmir"}, /* exit insert key -> KEY_EIC */ 55762449Speter {"ho", "khome"}, /* home key -> KEY_HOME */ 55862449Speter {"ic", "kich1"}, /* insert char key -> KEY_IC */ 55962449Speter {"im", "kIC"}, /* insert-mode key -> KEY_SIC */ 56062449Speter {"le", "kcub1"}, /* le key -> KEY_LEFT */ 56162449Speter {"nd", "kcuf1"}, /* nd key -> KEY_RIGHT */ 56262449Speter {"nl", "kent"}, /* new line key -> KEY_ENTER */ 56362449Speter {"st", "khts"}, /* set-tab key -> KEY_STAB */ 56462449Speter {"ta", CANCELLED_STRING}, 56562449Speter {"up", "kcuu1"}, /* up-arrow key -> KEY_UP */ 56662449Speter {(char *) 0, (char *) 0}, 56750276Speter}; 56850276Speter 56950276Speter/* 57050276Speter * This routine fills in string caps that either had defaults under 57150276Speter * termcap or can be manufactured from obsolete termcap capabilities. 57250276Speter * It was lifted from Ross Ridge's mytinfo package. 57350276Speter */ 57450276Speter 57550276Speterstatic const char C_CR[] = "\r"; 57650276Speterstatic const char C_LF[] = "\n"; 57750276Speterstatic const char C_BS[] = "\b"; 57850276Speterstatic const char C_HT[] = "\t"; 57950276Speter 58050276Speter/* 58150276Speter * Note that WANTED and PRESENT are not simple inverses! If a capability 58250276Speter * has been explicitly cancelled, it's not considered WANTED. 58350276Speter */ 58450276Speter#define WANTED(s) ((s) == ABSENT_STRING) 58550276Speter#define PRESENT(s) (((s) != ABSENT_STRING) && ((s) != CANCELLED_STRING)) 58650276Speter 58750276Speter/* 58850276Speter * This bit of legerdemain turns all the terminfo variable names into 58950276Speter * references to locations in the arrays Booleans, Numbers, and Strings --- 59050276Speter * precisely what's needed. 59150276Speter */ 59250276Speter 59350276Speter#undef CUR 59450276Speter#define CUR tp-> 59550276Speter 59666963Speterstatic void 59762449Speterpostprocess_termcap(TERMTYPE * tp, bool has_base) 59850276Speter{ 59950276Speter char buf[MAX_LINE * 2 + 2]; 60066963Speter string_desc result; 60150276Speter 60250276Speter /* 60350276Speter * TERMCAP DEFAULTS AND OBSOLETE-CAPABILITY TRANSLATIONS 60450276Speter * 60550276Speter * This first part of the code is the functional inverse of the 60650276Speter * fragment in capdefaults.c. 60750276Speter * ---------------------------------------------------------------------- 60850276Speter */ 60950276Speter 61050276Speter /* if there was a tc entry, assume we picked up defaults via that */ 61162449Speter if (!has_base) { 61250276Speter if (WANTED(init_3string) && termcap_init2) 61350276Speter init_3string = _nc_save_str(termcap_init2); 61450276Speter 61550276Speter if (WANTED(reset_2string) && termcap_reset) 61650276Speter reset_2string = _nc_save_str(termcap_reset); 61750276Speter 61850276Speter if (WANTED(carriage_return)) { 61950276Speter if (carriage_return_delay > 0) { 62050276Speter sprintf(buf, "%s$<%d>", C_CR, carriage_return_delay); 62150276Speter carriage_return = _nc_save_str(buf); 62250276Speter } else 62350276Speter carriage_return = _nc_save_str(C_CR); 62450276Speter } 62550276Speter if (WANTED(cursor_left)) { 62650276Speter if (backspace_delay > 0) { 62750276Speter sprintf(buf, "%s$<%d>", C_BS, backspace_delay); 62850276Speter cursor_left = _nc_save_str(buf); 62950276Speter } else if (backspaces_with_bs == 1) 63050276Speter cursor_left = _nc_save_str(C_BS); 63150276Speter else if (PRESENT(backspace_if_not_bs)) 63250276Speter cursor_left = backspace_if_not_bs; 63350276Speter } 63450276Speter /* vi doesn't use "do", but it does seems to use nl (or '\n') instead */ 63550276Speter if (WANTED(cursor_down)) { 63650276Speter if (PRESENT(linefeed_if_not_lf)) 63750276Speter cursor_down = linefeed_if_not_lf; 63850276Speter else if (linefeed_is_newline != 1) { 63950276Speter if (new_line_delay > 0) { 64050276Speter sprintf(buf, "%s$<%d>", C_LF, new_line_delay); 64150276Speter cursor_down = _nc_save_str(buf); 64250276Speter } else 64350276Speter cursor_down = _nc_save_str(C_LF); 64450276Speter } 64550276Speter } 64650276Speter if (WANTED(scroll_forward) && crt_no_scrolling != 1) { 64750276Speter if (PRESENT(linefeed_if_not_lf)) 64850276Speter cursor_down = linefeed_if_not_lf; 64950276Speter else if (linefeed_is_newline != 1) { 65050276Speter if (new_line_delay > 0) { 65150276Speter sprintf(buf, "%s$<%d>", C_LF, new_line_delay); 65250276Speter scroll_forward = _nc_save_str(buf); 65350276Speter } else 65450276Speter scroll_forward = _nc_save_str(C_LF); 65550276Speter } 65650276Speter } 65750276Speter if (WANTED(newline)) { 65850276Speter if (linefeed_is_newline == 1) { 65950276Speter if (new_line_delay > 0) { 66050276Speter sprintf(buf, "%s$<%d>", C_LF, new_line_delay); 66150276Speter newline = _nc_save_str(buf); 66250276Speter } else 66350276Speter newline = _nc_save_str(C_LF); 66450276Speter } else if (PRESENT(carriage_return) && PRESENT(scroll_forward)) { 66566963Speter _nc_str_init(&result, buf, sizeof(buf)); 66666963Speter if (_nc_safe_strcat(&result, carriage_return) 66776726Speter && _nc_safe_strcat(&result, scroll_forward)) 66866963Speter newline = _nc_save_str(buf); 66950276Speter } else if (PRESENT(carriage_return) && PRESENT(cursor_down)) { 67066963Speter _nc_str_init(&result, buf, sizeof(buf)); 67166963Speter if (_nc_safe_strcat(&result, carriage_return) 67276726Speter && _nc_safe_strcat(&result, cursor_down)) 67366963Speter newline = _nc_save_str(buf); 67450276Speter } 67550276Speter } 67650276Speter } 67750276Speter 67850276Speter /* 67950276Speter * Inverse of capdefaults.c code ends here. 68050276Speter * ---------------------------------------------------------------------- 68150276Speter * 68250276Speter * TERMCAP-TO TERMINFO MAPPINGS FOR SOURCE TRANSLATION 68350276Speter * 68450276Speter * These translations will *not* be inverted by tgetent(). 68550276Speter */ 68650276Speter 68762449Speter if (!has_base) { 68850276Speter /* 68950276Speter * We wait until now to decide if we've got a working cr because even 69050276Speter * one that doesn't work can be used for newline. Unfortunately the 69150276Speter * space allocated for it is wasted. 69250276Speter */ 69350276Speter if (return_does_clr_eol == 1 || no_correctly_working_cr == 1) 69450276Speter carriage_return = ABSENT_STRING; 69550276Speter 69650276Speter /* 69750276Speter * Supposedly most termcap entries have ta now and '\t' is no longer a 69850276Speter * default, but it doesn't seem to be true... 69950276Speter */ 70050276Speter if (WANTED(tab)) { 70150276Speter if (horizontal_tab_delay > 0) { 70250276Speter sprintf(buf, "%s$<%d>", C_HT, horizontal_tab_delay); 70350276Speter tab = _nc_save_str(buf); 70450276Speter } else 70550276Speter tab = _nc_save_str(C_HT); 70650276Speter } 70750276Speter if (init_tabs == ABSENT_NUMERIC && has_hardware_tabs == TRUE) 70850276Speter init_tabs = 8; 70950276Speter 71050276Speter /* 71150276Speter * Assume we can beep with ^G unless we're given bl@. 71250276Speter */ 71350276Speter if (WANTED(bell)) 71450276Speter bell = _nc_save_str("\007"); 71550276Speter } 71650276Speter 71750276Speter /* 71850276Speter * Translate the old termcap :pt: capability to it#8 + ht=\t 71950276Speter */ 72050276Speter if (has_hardware_tabs == TRUE) { 72150276Speter if (init_tabs != 8 && init_tabs != ABSENT_NUMERIC) 72250276Speter _nc_warning("hardware tabs with a width other than 8: %d", init_tabs); 72362449Speter else { 72450276Speter if (tab && _nc_capcmp(tab, C_HT)) 72550276Speter _nc_warning("hardware tabs with a non-^I tab string %s", 72666963Speter _nc_visbuf(tab)); 72762449Speter else { 72850276Speter if (WANTED(tab)) 72950276Speter tab = _nc_save_str(C_HT); 73050276Speter init_tabs = 8; 73150276Speter } 73250276Speter } 73350276Speter } 73450276Speter /* 73550276Speter * Now translate the ko capability, if there is one. This 73650276Speter * isn't from mytinfo... 73750276Speter */ 73862449Speter if (PRESENT(other_non_function_keys)) { 73966963Speter char *base = other_non_function_keys; 74066963Speter char *bp, *cp, *dp; 74162449Speter struct name_table_entry const *from_ptr; 74262449Speter struct name_table_entry const *to_ptr; 74362449Speter assoc const *ap; 74462449Speter char buf2[MAX_TERMINFO_LENGTH]; 74562449Speter bool foundim; 74650276Speter 74750276Speter /* we're going to use this for a special case later */ 74850276Speter dp = strchr(other_non_function_keys, 'i'); 74966963Speter foundim = (dp != 0) && (dp[1] == 'm'); 75050276Speter 75150276Speter /* look at each comma-separated capability in the ko string... */ 75266963Speter for (base = other_non_function_keys; 75366963Speter (cp = strchr(base, ',')) != 0; 75466963Speter base = cp + 1) { 75566963Speter size_t len = cp - base; 75666963Speter 75750276Speter for (ap = ko_xlate; ap->from; ap++) 75866963Speter if (len == strlen(ap->from) 75966963Speter && strncmp(ap->from, base, len) == 0) 76050276Speter break; 76162449Speter if (!ap->to) { 76266963Speter _nc_warning("unknown capability `%.*s' in ko string", 76366963Speter (int) len, base); 76450276Speter continue; 76562449Speter } else if (ap->to == CANCELLED_STRING) /* ignore it */ 76650276Speter continue; 76750276Speter 76850276Speter /* now we know we found a match in ko_table, so... */ 76950276Speter 77050276Speter from_ptr = _nc_find_entry(ap->from, _nc_cap_hash_table); 77162449Speter to_ptr = _nc_find_entry(ap->to, _nc_info_hash_table); 77250276Speter 77350276Speter if (!from_ptr || !to_ptr) /* should never happen! */ 77450276Speter _nc_err_abort("ko translation table is invalid, I give up"); 77550276Speter 77662449Speter if (WANTED(tp->Strings[from_ptr->nte_index])) { 77750276Speter _nc_warning("no value for ko capability %s", ap->from); 77850276Speter continue; 77950276Speter } 78050276Speter 78162449Speter if (tp->Strings[to_ptr->nte_index]) { 78250276Speter /* There's no point in warning about it if it's the same 78350276Speter * string; that's just an inefficiency. 78450276Speter */ 78550276Speter if (strcmp( 78666963Speter tp->Strings[from_ptr->nte_index], 78766963Speter tp->Strings[to_ptr->nte_index]) != 0) 78850276Speter _nc_warning("%s (%s) already has an explicit value %s, ignoring ko", 78966963Speter ap->to, ap->from, 79066963Speter _nc_visbuf(tp->Strings[to_ptr->nte_index])); 79150276Speter continue; 79250276Speter } 79350276Speter 79450276Speter /* 79550276Speter * The magic moment -- copy the mapped key string over, 79650276Speter * stripping out padding. 79750276Speter */ 79866963Speter for (dp = buf2, bp = tp->Strings[from_ptr->nte_index]; *bp; bp++) { 79966963Speter if (bp[0] == '$' && bp[1] == '<') { 80066963Speter while (*bp && *bp != '>') { 80166963Speter ++bp; 80266963Speter } 80362449Speter } else 80466963Speter *dp++ = *bp; 80550276Speter } 80650276Speter *dp++ = '\0'; 80750276Speter 80850276Speter tp->Strings[to_ptr->nte_index] = _nc_save_str(buf2); 80966963Speter } 81050276Speter 81150276Speter /* 81250276Speter * Note: ko=im and ko=ic both want to grab the `Insert' 81350276Speter * keycap. There's a kich1 but no ksmir, so the ic capability 81450276Speter * got mapped to kich1 and im to kIC to avoid a collision. 81550276Speter * If the description has im but not ic, hack kIC back to kich1. 81650276Speter */ 81762449Speter if (foundim && WANTED(key_ic) && key_sic) { 81850276Speter key_ic = key_sic; 81950276Speter key_sic = ABSENT_STRING; 82050276Speter } 82150276Speter } 82250276Speter 82376726Speter if (!has_base) { 82476726Speter if (!hard_copy) { 82576726Speter if (WANTED(key_backspace)) 82676726Speter key_backspace = _nc_save_str(C_BS); 82776726Speter if (WANTED(key_left)) 82876726Speter key_left = _nc_save_str(C_BS); 82976726Speter if (WANTED(key_down)) 83076726Speter key_down = _nc_save_str(C_LF); 83176726Speter } 83250276Speter } 83350276Speter 83450276Speter /* 83550276Speter * Translate XENIX forms characters. 83650276Speter */ 83750276Speter if (PRESENT(acs_ulcorner) || 83850276Speter PRESENT(acs_llcorner) || 83950276Speter PRESENT(acs_urcorner) || 84050276Speter PRESENT(acs_lrcorner) || 84150276Speter PRESENT(acs_ltee) || 84250276Speter PRESENT(acs_rtee) || 84350276Speter PRESENT(acs_btee) || 84450276Speter PRESENT(acs_ttee) || 84550276Speter PRESENT(acs_hline) || 84650276Speter PRESENT(acs_vline) || 84762449Speter PRESENT(acs_plus)) { 84866963Speter char buf2[MAX_TERMCAP_LENGTH]; 84950276Speter 85066963Speter _nc_str_init(&result, buf2, sizeof(buf2)); 85166963Speter _nc_safe_strcat(&result, acs_chars); 85250276Speter 85376726Speter append_acs(&result, 'j', acs_lrcorner); 85476726Speter append_acs(&result, 'k', acs_urcorner); 85576726Speter append_acs(&result, 'l', acs_ulcorner); 85676726Speter append_acs(&result, 'm', acs_llcorner); 85776726Speter append_acs(&result, 'n', acs_plus); 85876726Speter append_acs(&result, 'q', acs_hline); 85976726Speter append_acs(&result, 't', acs_ltee); 86076726Speter append_acs(&result, 'u', acs_rtee); 86176726Speter append_acs(&result, 'v', acs_btee); 86276726Speter append_acs(&result, 'w', acs_ttee); 86376726Speter append_acs(&result, 'x', acs_vline); 86450276Speter 86566963Speter if (buf2[0]) { 86650276Speter acs_chars = _nc_save_str(buf2); 86750276Speter _nc_warning("acsc string synthesized from XENIX capabilities"); 86850276Speter } 86962449Speter } else if (acs_chars == 0 87066963Speter && enter_alt_charset_mode != 0 87166963Speter && exit_alt_charset_mode != 0) { 87262449Speter acs_chars = 87362449Speter _nc_save_str("``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~"); 87450276Speter } 87550276Speter} 87650276Speter 87766963Speterstatic void 87862449Speterpostprocess_terminfo(TERMTYPE * tp) 87950276Speter{ 88050276Speter /* 88150276Speter * TERMINFO-TO-TERMINFO MAPPINGS FOR SOURCE TRANSLATION 88250276Speter * ---------------------------------------------------------------------- 88350276Speter */ 88450276Speter 88550276Speter /* 88650276Speter * Translate AIX forms characters. 88750276Speter */ 88862449Speter if (PRESENT(box_chars_1)) { 88966963Speter char buf2[MAX_TERMCAP_LENGTH]; 89066963Speter string_desc result; 89150276Speter 89266963Speter _nc_str_init(&result, buf2, sizeof(buf2)); 89366963Speter _nc_safe_strcat(&result, acs_chars); 89450276Speter 89576726Speter append_acs0(&result, 'l', box_chars_1[0]); /* ACS_ULCORNER */ 89676726Speter append_acs0(&result, 'q', box_chars_1[1]); /* ACS_HLINE */ 89776726Speter append_acs0(&result, 'k', box_chars_1[2]); /* ACS_URCORNER */ 89876726Speter append_acs0(&result, 'x', box_chars_1[3]); /* ACS_VLINE */ 89976726Speter append_acs0(&result, 'j', box_chars_1[4]); /* ACS_LRCORNER */ 90076726Speter append_acs0(&result, 'm', box_chars_1[5]); /* ACS_LLCORNER */ 90176726Speter append_acs0(&result, 'w', box_chars_1[6]); /* ACS_TTEE */ 90276726Speter append_acs0(&result, 'u', box_chars_1[7]); /* ACS_RTEE */ 90376726Speter append_acs0(&result, 'v', box_chars_1[8]); /* ACS_BTEE */ 90476726Speter append_acs0(&result, 't', box_chars_1[9]); /* ACS_LTEE */ 90576726Speter append_acs0(&result, 'n', box_chars_1[10]); /* ACS_PLUS */ 90650276Speter 90766963Speter if (buf2[0]) { 90850276Speter acs_chars = _nc_save_str(buf2); 90950276Speter _nc_warning("acsc string synthesized from AIX capabilities"); 91050276Speter box_chars_1 = ABSENT_STRING; 91150276Speter } 91250276Speter } 91350276Speter /* 91450276Speter * ---------------------------------------------------------------------- 91550276Speter */ 91650276Speter} 91750276Speter 91850276Speter/* 91950276Speter * Do a linear search through the terminfo tables to find a given full-name. 92050276Speter * We don't expect to do this often, so there's no hashing function. 92150276Speter * 92250276Speter * In effect, this scans through the 3 lists of full-names, and looks them 92350276Speter * up in _nc_info_table, which is organized so that the nte_index fields are 92450276Speter * sorted, but the nte_type fields are not necessarily grouped together. 92550276Speter */ 92666963Speterstatic struct name_table_entry const * 92762449Speterlookup_fullname(const char *find) 92850276Speter{ 92950276Speter int state = -1; 93050276Speter 93150276Speter for (;;) { 93250276Speter int count = 0; 93350276Speter NCURSES_CONST char *const *names; 93450276Speter 93550276Speter switch (++state) { 93650276Speter case BOOLEAN: 93750276Speter names = boolfnames; 93850276Speter break; 93950276Speter case STRING: 94050276Speter names = strfnames; 94150276Speter break; 94250276Speter case NUMBER: 94350276Speter names = numfnames; 94450276Speter break; 94550276Speter default: 94650276Speter return NOTFOUND; 94750276Speter } 94850276Speter 94950276Speter for (count = 0; names[count] != 0; count++) { 95050276Speter if (!strcmp(names[count], find)) { 95162449Speter struct name_table_entry const *entry_ptr = _nc_get_table(FALSE); 95262449Speter while (entry_ptr->nte_type != state 95366963Speter || entry_ptr->nte_index != count) 95462449Speter entry_ptr++; 95550276Speter return entry_ptr; 95650276Speter } 95750276Speter } 95850276Speter } 95950276Speter} 96050276Speter 96150276Speter/* parse_entry.c ends here */ 962