/****************************************************************************
- * Copyright (c) 1998-2016,2017 Free Software Foundation, Inc. *
+ * Copyright (c) 1998-2018,2019 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 *
#include <ctype.h>
#include <tic.h>
-MODULE_ID("$Id: parse_entry.c,v 1.85 2017/06/24 22:59:46 tom Exp $")
+MODULE_ID("$Id: parse_entry.c,v 1.97 2019/08/03 23:10:38 tom Exp $")
#ifdef LINT
static short const parametrized[] =
#if NCURSES_XNAMES
static struct name_table_entry const *
-_nc_extend_names(ENTRY * entryp, char *name, int token_type)
+_nc_extend_names(ENTRY * entryp, const char *name, int token_type)
{
static struct name_table_entry temp;
TERMTYPE2 *tp = &(entryp->tterm);
return &temp;
}
+
+static const char *
+usertype2s(int mask)
+{
+ const char *result = "unknown";
+ if (mask & (1 << BOOLEAN)) {
+ result = "boolean";
+ } else if (mask & (1 << NUMBER)) {
+ result = "number";
+ } else if (mask & (1 << STRING)) {
+ result = "string";
+ }
+ return result;
+}
+
+static bool
+expected_type(const char *name, int token_type, bool silent)
+{
+ struct user_table_entry const *entry = _nc_find_user_entry(name);
+ bool result = TRUE;
+ if ((entry != 0) && (token_type != CANCEL)) {
+ int have_type = (1 << token_type);
+ if (!(entry->ute_type & have_type)) {
+ if (!silent)
+ _nc_warning("expected %s-type for %s, have %s",
+ usertype2s(entry->ute_type),
+ name,
+ usertype2s(have_type));
+ result = FALSE;
+ }
+ }
+ return result;
+}
#endif /* NCURSES_XNAMES */
+static bool
+valid_entryname(const char *name)
+{
+ bool result = TRUE;
+ int ch;
+ while ((ch = UChar(*name++)) != '\0') {
+ if (ch <= ' ' || ch > '~' || ch == '/') {
+ result = FALSE;
+ break;
+ }
+ }
+ return result;
+}
+
/*
* int
* _nc_parse_entry(entry, literal, silent)
{ bad_tc_usage = TRUE; \
_nc_warning("Legacy termcap allows only a trailing tc= clause"); }
-#define MAX_NUMBER 0x7fff /* positive shorts only */
+#define MAX_NUMBER MAX_OF_TYPE(NCURSES_INT2)
NCURSES_EXPORT(int)
_nc_parse_entry(ENTRY * entryp, int literal, bool silent)
int token_type;
struct name_table_entry const *entry_ptr;
char *ptr, *base;
+ const char *name;
bool bad_tc_usage = FALSE;
token_type = _nc_get_token(silent);
* 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 (_nc_syntax == SYN_TERMCAP
#if NCURSES_XNAMES
&& !_nc_user_definable
#endif
) {
- if (ptr[2] == '|') {
+ if (ok_TC2(ptr[0]) && ok_TC2(ptr[1]) && (ptr[2] == '|')) {
ptr += 3;
_nc_curr_token.tk_name[2] = '\0';
}
* results in the terminal type getting prematurely set to correspond
* to that of the next entry.
*/
- _nc_set_type(_nc_first_name(entryp->tterm.term_names));
+ name = _nc_first_name(entryp->tterm.term_names);
+ if (!valid_entryname(name)) {
+ _nc_warning("invalid entry name \"%s\"", name);
+ name = "invalid";
+ }
+ _nc_set_type(name);
/* check for overly-long names and aliases */
for (base = entryp->tterm.term_names; (ptr = strchr(base, '|')) != 0;
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) {
+ if (!VALID_STRING(_nc_curr_token.tk_valstring)
+ || _nc_curr_token.tk_valstring[0] == '\0') {
+ _nc_warning("missing name for use-clause");
+ continue;
+ } else if (!valid_entryname(_nc_curr_token.tk_valstring)) {
+ _nc_warning("invalid name for use-clause \"%s\"",
+ _nc_curr_token.tk_valstring);
+ continue;
+ } else if (entryp->nuses >= MAX_USES) {
+ _nc_warning("too many use-clauses, ignored \"%s\"",
+ _nc_curr_token.tk_valstring);
+ continue;
+ }
entryp->uses[entryp->nuses].name = _nc_save_str(_nc_curr_token.tk_valstring);
entryp->uses[entryp->nuses].line = _nc_curr_line;
entryp->nuses++;
* define a name based on its context.
*/
if (entry_ptr == NOTFOUND
- && _nc_user_definable
- && (entry_ptr = _nc_extend_names(entryp,
- _nc_curr_token.tk_name,
- token_type)) != 0) {
- if (_nc_tracing >= DEBUG_LEVEL(1))
- _nc_warning("extended capability '%s'", _nc_curr_token.tk_name);
+ && _nc_user_definable) {
+ if (expected_type(_nc_curr_token.tk_name, token_type, silent)) {
+ if ((entry_ptr = _nc_extend_names(entryp,
+ _nc_curr_token.tk_name,
+ token_type)) != 0) {
+ if (_nc_tracing >= DEBUG_LEVEL(1)) {
+ _nc_warning("extended capability '%s'",
+ _nc_curr_token.tk_name);
+ }
+ }
+ } else {
+ /* ignore it: we have already printed error message */
+ continue;
+ }
}
#endif /* NCURSES_XNAMES */
break;
case NUMBER:
+#if !NCURSES_EXT_NUMBERS
if (_nc_curr_token.tk_valnumber > MAX_NUMBER) {
entryp->tterm.Numbers[entry_ptr->nte_index] = MAX_NUMBER;
- } else {
+ } else
+#endif
+ {
entryp->tterm.Numbers[entry_ptr->nte_index] =
- (short) _nc_curr_token.tk_valnumber;
+ (NCURSES_INT2) _nc_curr_token.tk_valnumber;
}
break;
* Otherwise, look for a base entry that will already
* have picked up defaults via translation.
*/
- for (i = 0; i < entryp->nuses; i++)
- if (!strchr((char *) entryp->uses[i].name, '+'))
+ for (i = 0; i < entryp->nuses; i++) {
+ if (entryp->uses[i].name != 0
+ && !strchr(entryp->uses[i].name, '+'))
has_base_entry = TRUE;
+ }
}
postprocess_termcap(&entryp->tterm, has_base_entry);
static void
append_acs(string_desc * dst, int code, char *src)
{
- if (src != 0 && strlen(src) == 1) {
+ if (VALID_STRING(src) && strlen(src) == 1) {
append_acs0(dst, code, *src);
}
}
static const char C_BS[] = "\b";
static const char C_HT[] = "\t";
-/*
- * Note that WANTED and PRESENT are not simple inverses! If a capability
- * has been explicitly cancelled, it's not considered WANTED.
- */
-#define WANTED(s) ((s) == ABSENT_STRING)
-#define PRESENT(s) (((s) != ABSENT_STRING) && ((s) != CANCELLED_STRING))
-
/*
* This bit of legerdemain turns all the terminfo variable names into
* references to locations in the arrays Booleans, Numbers, and Strings ---
/* if there was a tc entry, assume we picked up defaults via that */
if (!has_base) {
- if (WANTED(init_3string) && termcap_init2)
+ if (WANTED(init_3string) && PRESENT(termcap_init2))
init_3string = _nc_save_str(termcap_init2);
- if (WANTED(reset_2string) && termcap_reset)
+ if (WANTED(reset_2string) && PRESENT(termcap_reset))
reset_2string = _nc_save_str(termcap_reset);
if (WANTED(carriage_return)) {
if (init_tabs != 8 && init_tabs != ABSENT_NUMERIC)
_nc_warning("hardware tabs with a width other than 8: %d", init_tabs);
else {
- if (tab && _nc_capcmp(tab, C_HT))
+ if (PRESENT(tab) && _nc_capcmp(tab, C_HT))
_nc_warning("hardware tabs with a non-^I tab string %s",
_nc_visbuf(tab));
else {
}
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;
}
* The magic moment -- copy the mapped key string over,
* stripping out padding.
*/
- for (dp = buf2, bp = tp->Strings[from_ptr->nte_index]; *bp; bp++) {
- if (bp[0] == '$' && bp[1] == '<') {
- while (*bp && *bp != '>') {
- ++bp;
- }
- } else
- *dp++ = *bp;
- }
- *dp = '\0';
+ bp = tp->Strings[from_ptr->nte_index];
+ if (VALID_STRING(bp)) {
+ for (dp = buf2; *bp; bp++) {
+ if (bp[0] == '$' && bp[1] == '<') {
+ while (*bp && *bp != '>') {
+ ++bp;
+ }
+ } else
+ *dp++ = *bp;
+ }
+ *dp = '\0';
- tp->Strings[to_ptr->nte_index] = _nc_save_str(buf2);
+ tp->Strings[to_ptr->nte_index] = _nc_save_str(buf2);
+ } else {
+ tp->Strings[to_ptr->nte_index] = bp;
+ }
}
/*
* got mapped to kich1 and im to kIC to avoid a collision.
* If the description has im but not ic, hack kIC back to kich1.
*/
- if (foundim && WANTED(key_ic) && key_sic) {
+ if (foundim && WANTED(key_ic) && PRESENT(key_sic)) {
key_ic = key_sic;
key_sic = ABSENT_STRING;
}
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) {
+ } else if (acs_chars == ABSENT_STRING
+ && PRESENT(enter_alt_charset_mode)
+ && PRESENT(exit_alt_charset_mode)) {
acs_chars = _nc_save_str(VT_ACSC);
}
}