X-Git-Url: https://ncurses.scripts.mit.edu/?p=ncurses.git;a=blobdiff_plain;f=ncurses%2Ftinfo%2Fparse_entry.c;h=3fa2f254cb91dd650137efe1f3ed20e690f21adb;hp=1aff562d0dd681d2aa7564c08cfd1b8d436705b7;hb=690589d8f19e38925db061296d4f704e4a965bb2;hpb=b1f61d9f3aa244512045a6b02e759825d7049d34 diff --git a/ncurses/tinfo/parse_entry.c b/ncurses/tinfo/parse_entry.c index 1aff562d..3fa2f254 100644 --- a/ncurses/tinfo/parse_entry.c +++ b/ncurses/tinfo/parse_entry.c @@ -1,5 +1,5 @@ /**************************************************************************** - * Copyright (c) 1998,1999,2000 Free Software Foundation, Inc. * + * Copyright (c) 1998-2016,2017 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 * @@ -29,6 +29,7 @@ /**************************************************************************** * Author: Zeyd M. Ben-Halim 1992,1995 * * and: Eric S. Raymond * + * and: Thomas E. Dickey 1996-on * ****************************************************************************/ /* @@ -40,14 +41,13 @@ * from the input stream. */ +#define __INTERNAL_CAPS_VISIBLE #include #include #include -#define __INTERNAL_CAPS_VISIBLE -#include -MODULE_ID("$Id: parse_entry.c,v 1.44 2000/04/30 00:17:42 tom Exp $") +MODULE_ID("$Id: parse_entry.c,v 1.86 2017/06/28 00:53:12 tom Exp $") #ifdef LINT static short const parametrized[] = @@ -56,8 +56,8 @@ static short const parametrized[] = #include #endif -static void postprocess_termcap(TERMTYPE *, bool); -static void postprocess_terminfo(TERMTYPE *); +static void postprocess_termcap(TERMTYPE2 *, bool); +static void postprocess_terminfo(TERMTYPE2 *); static struct name_table_entry const *lookup_fullname(const char *name); #if NCURSES_XNAMES @@ -66,7 +66,7 @@ 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); + TERMTYPE2 *tp = &(entryp->tterm); unsigned offset = 0; unsigned actual; unsigned tindex; @@ -83,13 +83,13 @@ _nc_extend_names(ENTRY * entryp, char *name, int token_type) case NUMBER: first = tp->ext_Booleans; last = tp->ext_Numbers + first; - offset = tp->ext_Booleans + tp->ext_Numbers; + offset = (unsigned) (tp->ext_Booleans + tp->ext_Numbers); tindex = tp->num_Numbers; break; case STRING: - first = tp->ext_Booleans + tp->ext_Numbers; + first = (unsigned) (tp->ext_Booleans + tp->ext_Numbers); last = tp->ext_Strings + first; - offset = tp->ext_Booleans + tp->ext_Numbers + tp->ext_Strings; + offset = (unsigned) (tp->ext_Booleans + tp->ext_Numbers + tp->ext_Strings); tindex = tp->num_Strings; break; case CANCEL: @@ -136,32 +136,36 @@ _nc_extend_names(ENTRY * entryp, char *name, int token_type) break; } } + +#define for_each_value(max) \ + for (last = (unsigned) (max - 1); last > tindex; last--) + 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->ext_Booleans++; + tp->num_Booleans++; + TYPE_REALLOC(NCURSES_SBOOL, tp->num_Booleans, tp->Booleans); + for_each_value(tp->num_Booleans) 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->ext_Numbers++; + tp->num_Numbers++; + TYPE_REALLOC(NCURSES_INT2, tp->num_Numbers, tp->Numbers); + for_each_value(tp->num_Numbers) 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->ext_Strings++; + tp->num_Strings++; + TYPE_REALLOC(char *, tp->num_Strings, tp->Strings); + for_each_value(tp->num_Strings) tp->Strings[last] = tp->Strings[last - 1]; break; } actual = NUM_EXT_NAMES(tp); - tp->ext_Names = typeRealloc(char *, actual, tp->ext_Names); + TYPE_REALLOC(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); @@ -169,7 +173,7 @@ _nc_extend_names(ENTRY * entryp, char *name, int token_type) temp.nte_name = tp->ext_Names[offset]; temp.nte_type = token_type; - temp.nte_index = tindex; + temp.nte_index = (short) tindex; temp.nte_link = -1; return &temp; @@ -188,43 +192,68 @@ _nc_extend_names(ENTRY * entryp, char *name, int token_type) * 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 + * check for existence 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) +#define BAD_TC_USAGE if (!bad_tc_usage) \ + { bad_tc_usage = TRUE; \ + _nc_warning("Legacy termcap allows only a trailing tc= clause"); } + +#define MAX_NUMBER 0x7fff /* positive shorts only */ + +NCURSES_EXPORT(int) +_nc_parse_entry(ENTRY * entryp, int literal, bool silent) { int token_type; struct name_table_entry const *entry_ptr; - char *ptr, namecpy[MAX_NAME_SIZE + 1]; + char *ptr, *base; + bool bad_tc_usage = FALSE; - token_type = _nc_get_token(); + token_type = _nc_get_token(silent); 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); + _nc_init_entry(entryp); 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 */ + /* + * Strip off the 2-character termcap name, if present. Originally termcap + * used that as an indexing aid. We can retain 2-character terminfo names, + * but note that they would be lost if we translate to/from termcap. This + * feature is supposedly obsolete since "newer" BSD implementations do not + * use it; however our reference for this feature is SunOS 4.x, which + * implemented it. Note that the resulting terminal type was never the + * 2-character name, but was instead the first alias after that. + */ +#define ok_TC2(s) (isgraph(UChar(s)) && (s) != '|') ptr = _nc_curr_token.tk_name; - if (ptr[2] == '|') { - ptr = _nc_curr_token.tk_name + 3; - _nc_curr_token.tk_name[2] = '\0'; + if (_nc_syntax == SYN_TERMCAP +#if NCURSES_XNAMES + && !_nc_user_definable +#endif + ) { + if (ok_TC2(ptr[0]) && ok_TC2(ptr[1]) && (ptr[2] == '|')) { + ptr += 3; + _nc_curr_token.tk_name[2] = '\0'; + } } entryp->tterm.str_table = entryp->tterm.term_names = _nc_save_str(ptr); + if (entryp->tterm.str_table == 0) + return (ERR); + DEBUG(1, ("Starting '%s'", ptr)); /* @@ -235,31 +264,37 @@ _nc_parse_entry(struct entry *entryp, int literal, bool silent) _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); + for (base = entryp->tterm.term_names; (ptr = strchr(base, '|')) != 0; + base = ptr + 1) { + if (ptr - base > MAX_ALIAS) { + _nc_warning("%s `%.*s' may be too long", + (base == entryp->tterm.term_names) + ? "primary name" + : "alias", + (int) (ptr - base), base); + } + } 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) { + for (token_type = _nc_get_token(silent); + token_type != EOF && token_type != NAMES; + token_type = _nc_get_token(silent)) { + bool is_use = (strcmp(_nc_curr_token.tk_name, "use") == 0); + bool is_tc = !is_use && (strcmp(_nc_curr_token.tk_name, "tc") == 0); + if (is_use || is_tc) { entryp->uses[entryp->nuses].name = _nc_save_str(_nc_curr_token.tk_valstring); entryp->uses[entryp->nuses].line = _nc_curr_line; - entryp->nuses++; + if (VALID_STRING(entryp->uses[entryp->nuses].name)) { + entryp->nuses++; + if (entryp->nuses > 1 && is_tc) { + BAD_TC_USAGE + } + } } else { /* normal token lookup */ entry_ptr = _nc_find_entry(_nc_curr_token.tk_name, - _nc_syntax ? _nc_cap_hash_table : _nc_info_hash_table); + _nc_get_hash_table(_nc_syntax)); /* * Our kluge to handle aliasing. The reason it's done @@ -273,33 +308,38 @@ _nc_parse_entry(struct entry *entryp, int literal, bool silent) const struct alias *ap; if (_nc_syntax == SYN_TERMCAP) { - for (ap = _nc_capalias_table; ap->from; ap++) + if (entryp->nuses != 0) { + BAD_TC_USAGE + } + for (ap = _nc_get_alias_table(TRUE); 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); + ap->from, ap->source); goto nexttok; } - entry_ptr = _nc_find_entry(ap->to, _nc_cap_hash_table); + entry_ptr = _nc_find_entry(ap->to, + _nc_get_hash_table(TRUE)); if (entry_ptr && !silent) _nc_warning("%s (%s termcap extension) aliased to %s", - ap->from, ap->source, ap->to); + ap->from, ap->source, ap->to); break; } } else { /* if (_nc_syntax == SYN_TERMINFO) */ - for (ap = _nc_infoalias_table; ap->from; ap++) + for (ap = _nc_get_alias_table(FALSE); 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); + ap->from, ap->source); goto nexttok; } - entry_ptr = _nc_find_entry(ap->to, _nc_info_hash_table); + entry_ptr = _nc_find_entry(ap->to, + _nc_get_hash_table(FALSE)); if (entry_ptr && !silent) _nc_warning("%s (%s terminfo extension) aliased to %s", - ap->from, ap->source, ap->to); + ap->from, ap->source, ap->to); break; } @@ -316,7 +356,8 @@ _nc_parse_entry(struct entry *entryp, int literal, bool silent) if (entry_ptr == NOTFOUND && _nc_user_definable && (entry_ptr = _nc_extend_names(entryp, - _nc_curr_token.tk_name, token_type)) != 0) { + _nc_curr_token.tk_name, + token_type)) != 0) { if (_nc_tracing >= DEBUG_LEVEL(1)) _nc_warning("extended capability '%s'", _nc_curr_token.tk_name); } @@ -326,12 +367,21 @@ _nc_parse_entry(struct entry *entryp, int literal, bool silent) if (entry_ptr == NOTFOUND) { if (!silent) _nc_warning("unknown capability '%s'", - _nc_curr_token.tk_name); + _nc_curr_token.tk_name); continue; } /* deal with bad type/value combinations. */ - if (token_type != CANCEL && entry_ptr->nte_type != token_type) { + if (token_type == CANCEL) { + /* + * Prefer terminfo in this (long-obsolete) ambiguity: + */ + if (!strcmp("ma", _nc_curr_token.tk_name)) { + entry_ptr = _nc_find_type_entry("ma", NUMBER, + _nc_syntax != 0); + assert(entry_ptr != 0); + } + } else if (entry_ptr->nte_type != token_type) { /* * Nasty special cases here handle situations in which type * information can resolve name clashes. Normal lookup @@ -342,21 +392,26 @@ _nc_parse_entry(struct entry *entryp, int literal, bool silent) * type, this will do the job. */ - /* tell max_attributes from arrow_key_map */ - if (token_type == NUMBER && !strcmp("ma", _nc_curr_token.tk_name)) + if (token_type == NUMBER + && !strcmp("ma", _nc_curr_token.tk_name)) { + /* tell max_attributes from arrow_key_map */ entry_ptr = _nc_find_type_entry("ma", NUMBER, - _nc_get_table(_nc_syntax != 0)); + _nc_syntax != 0); + assert(entry_ptr != 0); - /* map terminfo's string MT to MT */ - else if (token_type == STRING && !strcmp("MT", _nc_curr_token.tk_name)) + } else if (token_type == STRING + && !strcmp("MT", _nc_curr_token.tk_name)) { + /* map terminfo's string MT to MT */ entry_ptr = _nc_find_type_entry("MT", STRING, - _nc_get_table(_nc_syntax != 0)); + _nc_syntax != 0); + assert(entry_ptr != 0); - /* treat strings without following "=" as empty strings */ - else if (token_type == BOOLEAN && entry_ptr->nte_type == STRING) + } else if (token_type == BOOLEAN + && entry_ptr->nte_type == STRING) { + /* treat strings without following "=" as empty strings */ token_type = STRING; - /* we couldn't recover; skip this token */ - else { + } else { + /* we couldn't recover; skip this token */ if (!silent) { const char *type_name; switch (entry_ptr->nte_type) { @@ -374,7 +429,7 @@ _nc_parse_entry(struct entry *entryp, int literal, bool silent) break; } _nc_warning("wrong type used for %s capability '%s'", - type_name, _nc_curr_token.tk_name); + type_name, _nc_curr_token.tk_name); } continue; } @@ -403,23 +458,27 @@ _nc_parse_entry(struct entry *entryp, int literal, bool silent) break; case NUMBER: - entryp->tterm.Numbers[entry_ptr->nte_index] = - _nc_curr_token.tk_valnumber; + if (_nc_curr_token.tk_valnumber > MAX_NUMBER) { + entryp->tterm.Numbers[entry_ptr->nte_index] = MAX_NUMBER; + } else { + entryp->tterm.Numbers[entry_ptr->nte_index] = + (short) _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]); + 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) ? ':' : ','); + _nc_panic_mode((char) ((_nc_syntax == SYN_TERMCAP) ? ':' : ',')); continue; } } /* end else cur_token.name != "use" */ @@ -439,16 +498,16 @@ _nc_parse_entry(struct entry *entryp, int literal, bool silent) 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, '+')) + if (strchr(entryp->tterm.term_names, '+')) { has_base_entry = TRUE; - else + } else { + unsigned i; /* * Otherwise, look for a base entry that will already * have picked up defaults via translation. @@ -456,50 +515,84 @@ _nc_parse_entry(struct entry *entryp, int literal, bool silent) for (i = 0; i < entryp->nuses; i++) if (!strchr((char *) entryp->uses[i].name, '+')) has_base_entry = TRUE; + } postprocess_termcap(&entryp->tterm, has_base_entry); } else postprocess_terminfo(&entryp->tterm); } - _nc_wrap_entry(entryp); + _nc_wrap_entry(entryp, FALSE); return (OK); } -int +NCURSES_EXPORT(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); + bool ok_s = VALID_STRING(s); + bool ok_t = VALID_STRING(t); + + if (ok_s && ok_t) { + for (;;) { + if (s[0] == '$' && s[1] == '<') { + for (s += 2;; s++) { + if (!(isdigit(UChar(*s)) + || *s == '.' + || *s == '*' + || *s == '/' + || *s == '>')) { + break; + } + } + } - 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(UChar(*t)) + || *t == '.' + || *t == '*' + || *t == '/' + || *t == '>')) { + 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 pointed at */ + + if (*s == '\0' && *t == '\0') + return (0); - /* we've now pushed s and t past any padding they were pointing at */ + if (*s != *t) + return (*t - *s); - if (*s == '\0' && *t == '\0') - return (0); + /* else *s == *t but one is not NUL, so continue */ + s++, t++; + } + } else if (ok_s || ok_t) { + return 1; + } + return 0; +} - if (*s != *t) - return (*t - *s); +static void +append_acs0(string_desc * dst, int code, int src) +{ + if (src != 0) { + char temp[3]; + temp[0] = (char) code; + temp[1] = (char) src; + temp[2] = 0; + _nc_safe_strcat(dst, temp); + } +} - /* else *s == *t but one is not NUL, so continue */ - s++, t++; +static void +append_acs(string_desc * dst, int code, char *src) +{ + if (VALID_STRING(src) && strlen(src) == 1) { + append_acs0(dst, code, *src); } } @@ -508,32 +601,32 @@ _nc_capcmp(const char *s, const char *t) * list. For each capability, we may assume there is a keycap that sends the * string which is the value of that capability. */ +#define DATA(from, to) { { from }, { to } } typedef struct { - const char *from; - const char *to; + const char from[3]; + const char to[6]; } 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}, + DATA("al", "kil1"), /* insert line key -> KEY_IL */ + DATA("bt", "kcbt"), /* back tab -> KEY_BTAB */ + DATA("cd", "ked"), /* clear-to-eos key -> KEY_EOL */ + DATA("ce", "kel"), /* clear-to-eol key -> KEY_EOS */ + DATA("cl", "kclr"), /* clear key -> KEY_CLEAR */ + DATA("ct", "tbc"), /* clear all tabs -> KEY_CATAB */ + DATA("dc", "kdch1"), /* delete char -> KEY_DC */ + DATA("dl", "kdl1"), /* delete line -> KEY_DL */ + DATA("do", "kcud1"), /* down key -> KEY_DOWN */ + DATA("ei", "krmir"), /* exit insert key -> KEY_EIC */ + DATA("ho", "khome"), /* home key -> KEY_HOME */ + DATA("ic", "kich1"), /* insert char key -> KEY_IC */ + DATA("im", "kIC"), /* insert-mode key -> KEY_SIC */ + DATA("le", "kcub1"), /* le key -> KEY_LEFT */ + DATA("nd", "kcuf1"), /* nd key -> KEY_RIGHT */ + DATA("nl", "kent"), /* new line key -> KEY_ENTER */ + DATA("st", "khts"), /* set-tab key -> KEY_STAB */ + DATA("ta", ""), + DATA("up", "kcuu1"), /* up-arrow key -> KEY_UP */ }; /* @@ -563,11 +656,11 @@ static const char C_HT[] = "\t"; #undef CUR #define CUR tp-> -static -void -postprocess_termcap(TERMTYPE * tp, bool has_base) +static void +postprocess_termcap(TERMTYPE2 *tp, bool has_base) { char buf[MAX_LINE * 2 + 2]; + string_desc result; /* * TERMCAP DEFAULTS AND OBSOLETE-CAPABILITY TRANSLATIONS @@ -587,27 +680,30 @@ postprocess_termcap(TERMTYPE * tp, bool has_base) if (WANTED(carriage_return)) { if (carriage_return_delay > 0) { - sprintf(buf, "%s$<%d>", C_CR, carriage_return_delay); + _nc_SPRINTF(buf, _nc_SLIMIT(sizeof(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); + _nc_SPRINTF(buf, _nc_SLIMIT(sizeof(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 */ + /* vi doesn't use "do", but it does seem 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); + _nc_SPRINTF(buf, _nc_SLIMIT(sizeof(buf)) + "%s$<%d>", C_LF, new_line_delay); cursor_down = _nc_save_str(buf); } else cursor_down = _nc_save_str(C_LF); @@ -618,7 +714,8 @@ postprocess_termcap(TERMTYPE * tp, bool has_base) 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); + _nc_SPRINTF(buf, _nc_SLIMIT(sizeof(buf)) + "%s$<%d>", C_LF, new_line_delay); scroll_forward = _nc_save_str(buf); } else scroll_forward = _nc_save_str(C_LF); @@ -627,22 +724,21 @@ postprocess_termcap(TERMTYPE * tp, bool has_base) if (WANTED(newline)) { if (linefeed_is_newline == 1) { if (new_line_delay > 0) { - sprintf(buf, "%s$<%d>", C_LF, new_line_delay); + _nc_SPRINTF(buf, _nc_SLIMIT(sizeof(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); + _nc_str_init(&result, buf, sizeof(buf)); + if (_nc_safe_strcat(&result, carriage_return) + && _nc_safe_strcat(&result, scroll_forward)) + 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); + _nc_str_init(&result, buf, sizeof(buf)); + if (_nc_safe_strcat(&result, carriage_return) + && _nc_safe_strcat(&result, cursor_down)) + newline = _nc_save_str(buf); } } } @@ -671,7 +767,8 @@ postprocess_termcap(TERMTYPE * tp, bool has_base) */ if (WANTED(tab)) { if (horizontal_tab_delay > 0) { - sprintf(buf, "%s$<%d>", C_HT, horizontal_tab_delay); + _nc_SPRINTF(buf, _nc_SLIMIT(sizeof(buf)) + "%s$<%d>", C_HT, horizontal_tab_delay); tab = _nc_save_str(buf); } else tab = _nc_save_str(C_HT); @@ -695,7 +792,7 @@ postprocess_termcap(TERMTYPE * tp, bool has_base) else { if (tab && _nc_capcmp(tab, C_HT)) _nc_warning("hardware tabs with a non-^I tab string %s", - _nc_visbuf(tab)); + _nc_visbuf(tab)); else { if (WANTED(tab)) tab = _nc_save_str(C_HT); @@ -708,32 +805,43 @@ postprocess_termcap(TERMTYPE * tp, bool has_base) * isn't from mytinfo... */ if (PRESENT(other_non_function_keys)) { - char *dp, *cp = strtok(other_non_function_keys, ","); + char *base; + char *bp, *cp, *dp; 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'; + foundim = (dp != 0) && (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) + for (base = other_non_function_keys; + (cp = strchr(base, ',')) != 0; + base = cp + 1) { + size_t len = (unsigned) (cp - base); + size_t n; + assoc const *ap = 0; + + for (n = 0; n < SIZEOF(ko_xlate); ++n) { + if (len == strlen(ko_xlate[n].from) + && strncmp(ko_xlate[n].from, base, len) == 0) { + ap = ko_xlate + n; break; - if (!ap->to) { - _nc_warning("unknown capability `%s' in ko string", cp); + } + } + if (ap == 0) { + _nc_warning("unknown capability `%.*s' in ko string", + (int) len, base); continue; - } else if (ap->to == CANCELLED_STRING) /* ignore it */ + } else if (ap->to[0] == '\0') /* 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); + from_ptr = _nc_find_entry(ap->from, _nc_get_hash_table(TRUE)); + to_ptr = _nc_find_entry(ap->to, _nc_get_hash_table(FALSE)); if (!from_ptr || !to_ptr) /* should never happen! */ _nc_err_abort("ko translation table is invalid, I give up"); @@ -744,15 +852,14 @@ postprocess_termcap(TERMTYPE * tp, bool has_base) } if (tp->Strings[to_ptr->nte_index]) { + const char *s = tp->Strings[from_ptr->nte_index]; + const char *t = 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) + if (VALID_STRING(s) && VALID_STRING(t) && strcmp(s, t) != 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])); + ap->to, ap->from, t); continue; } @@ -760,22 +867,18 @@ postprocess_termcap(TERMTYPE * tp, bool has_base) * 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; + for (dp = buf2, bp = tp->Strings[from_ptr->nte_index]; *bp; bp++) { + if (bp[0] == '$' && bp[1] == '<') { + while (*bp && *bp != '>') { + ++bp; + } } else - *dp++ = *cp; + *dp++ = *bp; } - *dp++ = '\0'; + *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' @@ -789,13 +892,15 @@ postprocess_termcap(TERMTYPE * tp, bool has_base) } } - 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); + if (!has_base) { + 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); + } } /* @@ -812,75 +917,36 @@ postprocess_termcap(TERMTYPE * tp, bool has_base) 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'; + char buf2[MAX_TERMCAP_LENGTH]; + + _nc_str_init(&result, buf2, sizeof(buf2)); + _nc_safe_strcat(&result, acs_chars); + + append_acs(&result, 'j', acs_lrcorner); + append_acs(&result, 'k', acs_urcorner); + append_acs(&result, 'l', acs_ulcorner); + append_acs(&result, 'm', acs_llcorner); + append_acs(&result, 'n', acs_plus); + append_acs(&result, 'q', acs_hline); + append_acs(&result, 't', acs_ltee); + append_acs(&result, 'u', acs_rtee); + append_acs(&result, 'v', acs_btee); + append_acs(&result, 'w', acs_ttee); + append_acs(&result, 'x', acs_vline); + + if (buf2[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{{||}}~~"); + && enter_alt_charset_mode != 0 + && exit_alt_charset_mode != 0) { + acs_chars = _nc_save_str(VT_ACSC); } } -static -void -postprocess_terminfo(TERMTYPE * tp) +static void +postprocess_terminfo(TERMTYPE2 *tp) { /* * TERMINFO-TO-TERMINFO MAPPINGS FOR SOURCE TRANSLATION @@ -891,60 +957,25 @@ postprocess_terminfo(TERMTYPE * tp) * 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'; + char buf2[MAX_TERMCAP_LENGTH]; + string_desc result; + + _nc_str_init(&result, buf2, sizeof(buf2)); + _nc_safe_strcat(&result, acs_chars); + + append_acs0(&result, 'l', box_chars_1[0]); /* ACS_ULCORNER */ + append_acs0(&result, 'q', box_chars_1[1]); /* ACS_HLINE */ + append_acs0(&result, 'k', box_chars_1[2]); /* ACS_URCORNER */ + append_acs0(&result, 'x', box_chars_1[3]); /* ACS_VLINE */ + append_acs0(&result, 'j', box_chars_1[4]); /* ACS_LRCORNER */ + append_acs0(&result, 'm', box_chars_1[5]); /* ACS_LLCORNER */ + append_acs0(&result, 'w', box_chars_1[6]); /* ACS_TTEE */ + append_acs0(&result, 'u', box_chars_1[7]); /* ACS_RTEE */ + append_acs0(&result, 'v', box_chars_1[8]); /* ACS_BTEE */ + append_acs0(&result, 't', box_chars_1[9]); /* ACS_LTEE */ + append_acs0(&result, 'n', box_chars_1[10]); /* ACS_PLUS */ + + if (buf2[0]) { acs_chars = _nc_save_str(buf2); _nc_warning("acsc string synthesized from AIX capabilities"); box_chars_1 = ABSENT_STRING; @@ -963,8 +994,7 @@ postprocess_terminfo(TERMTYPE * tp) * 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 * +static struct name_table_entry const * lookup_fullname(const char *find) { int state = -1; @@ -991,7 +1021,7 @@ lookup_fullname(const char *find) 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->nte_index != count) entry_ptr++; return entry_ptr; }