X-Git-Url: https://ncurses.scripts.mit.edu/?p=ncurses.git;a=blobdiff_plain;f=progs%2Ftic.c;h=705cac6caf9f731af9b25012c1f218178dd8a5e6;hp=478da6c472a22ada8392fbe9ec3735ad52aeee7a;hb=ade723c546e6559187580c695f7f4637eac13125;hpb=0fbd5e192896b3e446832d0a451df2cec5f5ae40 diff --git a/progs/tic.c b/progs/tic.c index 478da6c4..705cac6c 100644 --- a/progs/tic.c +++ b/progs/tic.c @@ -1,5 +1,5 @@ /**************************************************************************** - * 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 * @@ -48,7 +48,7 @@ #include #include -MODULE_ID("$Id: tic.c,v 1.248 2017/12/16 23:05:21 tom Exp $") +MODULE_ID("$Id: tic.c,v 1.268 2019/02/23 21:49:28 tom Exp $") #define STDIN_NAME "" @@ -59,6 +59,7 @@ static FILE *tmp_fp; static bool capdump = FALSE; /* running as infotocap? */ static bool infodump = FALSE; /* running as captoinfo? */ static bool showsummary = FALSE; +static unsigned debug_level; static char **namelst = 0; static const char *to_remove; @@ -680,7 +681,6 @@ main(int argc, char *argv[]) char my_tmpname[PATH_MAX]; char my_altfile[PATH_MAX]; int v_opt = -1; - unsigned debug_level; int smart_defaults = TRUE; char *termcap; ENTRY *qp; @@ -1095,6 +1095,50 @@ main(int argc, char *argv[]) static void check_acs(TERMTYPE2 *tp) { + int vt100_smacs = 0; + int vt100_rmacs = 0; + int vt100_enacs = 0; + + /* + * ena_acs is not always necessary, but if it is present, the enter/exit + * capabilities should be. + */ + ANDMISSING(ena_acs, enter_alt_charset_mode); + ANDMISSING(ena_acs, exit_alt_charset_mode); + PAIRED(exit_alt_charset_mode, exit_alt_charset_mode); + + /* + * vt100-like is frequently used, but perhaps ena_acs is missing, etc. + */ + if (VALID_STRING(enter_alt_charset_mode)) { + vt100_smacs = (!strcmp("\033(0", enter_alt_charset_mode) + ? 2 + : (!strcmp("\016", enter_alt_charset_mode) + ? 1 + : 0)); + } + if (VALID_STRING(exit_alt_charset_mode)) { + vt100_rmacs = (!strcmp("\033(B", exit_alt_charset_mode) + ? 2 + : (!strcmp("\017", exit_alt_charset_mode) + ? 1 + : 0)); + } + if (VALID_STRING(ena_acs)) { + vt100_enacs = (!strcmp("\033(B\033)0", ena_acs) + ? 2 + : 0); + } + if (vt100_rmacs && vt100_smacs && (vt100_rmacs != vt100_smacs)) { + _nc_warning("rmacs/smacs are inconsistent"); + } + if ((vt100_rmacs == 2) && (vt100_smacs == 2) && vt100_enacs) { + _nc_warning("rmacs/smacs make enacs redundant"); + } + if ((vt100_rmacs == 1) && (vt100_smacs == 1) && !vt100_enacs) { + _nc_warning("VT100-style rmacs/smacs require enacs"); + } + if (VALID_STRING(acs_chars)) { const char *boxes = "lmkjtuvwqxn"; char mapped[256]; @@ -1129,6 +1173,27 @@ check_acs(TERMTYPE2 *tp) } } +static bool +same_color(NCURSES_CONST char *oldcap, NCURSES_CONST char *newcap, int limit) +{ + bool result = FALSE; + if (limit > 16) + limit = 16; + if (limit >= 8) { + int n; + int same; + for (n = same = 0; n < limit; ++n) { + char *oldvalue = strdup(TPARM_1(oldcap, n)); + char *newvalue = strdup(TPARM_1(newcap, n)); + same += !strcmp(oldvalue, newvalue); + free(oldvalue); + free(newvalue); + } + result = (same == limit); + } + return result; +} + /* * Check if the color capabilities are consistent */ @@ -1145,21 +1210,29 @@ check_colors(TERMTYPE2 *tp) PAIRED(set_color_pair, initialize_pair); if (VALID_STRING(set_foreground) - && VALID_STRING(set_a_foreground) - && !_nc_capcmp(set_foreground, set_a_foreground)) - _nc_warning("expected setf/setaf to be different"); + && VALID_STRING(set_a_foreground)) { + if (!_nc_capcmp(set_foreground, set_a_foreground)) { + _nc_warning("expected setf/setaf to be different"); + } else if (same_color(set_foreground, set_a_foreground, max_colors)) { + _nc_warning("setf/setaf are equivalent"); + } + } if (VALID_STRING(set_background) - && VALID_STRING(set_a_background) - && !_nc_capcmp(set_background, set_a_background)) - _nc_warning("expected setb/setab to be different"); + && VALID_STRING(set_a_background)) { + if (!_nc_capcmp(set_background, set_a_background)) { + _nc_warning("expected setb/setab to be different"); + } else if (same_color(set_background, set_a_background, max_colors)) { + _nc_warning("setb/setab are equivalent"); + } + } /* see: has_colors() */ if (VALID_NUMERIC(max_colors) && VALID_NUMERIC(max_pairs) - && (((set_foreground != NULL) - && (set_background != NULL)) - || ((set_a_foreground != NULL) - && (set_a_background != NULL)) + && ((VALID_STRING(set_foreground) + && VALID_STRING(set_background)) + || (VALID_STRING(set_a_foreground) + && VALID_STRING(set_a_background)) || set_color_pair)) { if (!VALID_STRING(orig_pair) && !VALID_STRING(orig_colors)) _nc_warning("expected either op/oc string for resetting colors"); @@ -1614,6 +1687,9 @@ check_screen(TERMTYPE2 *tp) bool have_kmouse = FALSE; bool use_sgr_39_49 = FALSE; char *name = _nc_first_name(tp->term_names); + bool is_screen = !strncmp(name, "screen", 6); + bool screen_base = (is_screen + && strchr(name, '.') == 0); if (!VALID_BOOLEAN(have_bce)) { have_bce = FALSE; @@ -1634,28 +1710,29 @@ check_screen(TERMTYPE2 *tp) } if (have_XM && have_XT) { - _nc_warning("Screen's XT capability conflicts with XM"); - } else if (have_XT - && strstr(name, "screen") != 0 - && strchr(name, '.') != 0) { - _nc_warning("Screen's \"screen\" entries should not have XT set"); + _nc_warning("screen's XT capability conflicts with XM"); + } else if (have_XT && screen_base) { + _nc_warning("screen's \"screen\" entries should not have XT set"); } else if (have_XT) { - if (!have_kmouse && have_bce) { + if (!have_kmouse && is_screen) { if (VALID_STRING(key_mouse)) { - _nc_warning("Value of kmous inconsistent with screen's usage"); + _nc_warning("value of kmous inconsistent with screen's usage"); } else { - _nc_warning("Expected kmous capability with XT"); + _nc_warning("expected kmous capability with XT"); } } if (!have_bce && max_colors > 0) - _nc_warning("Expected bce capability with XT"); + _nc_warning("expected bce capability with XT"); if (!use_sgr_39_49 && have_bce && max_colors > 0) - _nc_warning("Expected orig_colors capability with XT to have 39/49 parameters"); + _nc_warning("expected orig_colors capability with XT to have 39/49 parameters"); if (VALID_STRING(to_status_line)) _nc_warning("\"tsl\" capability is redundant, given XT"); } else { - if (have_kmouse && !have_XM) - _nc_warning("Expected XT to be set, given kmous"); + if (have_kmouse + && !have_XM + && !screen_base && strchr(name, '+') == 0) { + _nc_warning("expected XT to be set, given kmous"); + } } } #endif @@ -1755,13 +1832,71 @@ expected_params(const char *name) return result; } +typedef struct { + const char *name; + int n_type; + int n_parms; +} USERCAPS; + +/* + * These are user-capabilities that happen to be used in ncurses' terminal + * database. + */ +static USERCAPS * +lookup_user_capability(const char *name) +{ + /* *INDENT-OFF* */ +#define DATA(name,type,parms) { name, type, parms } + static USERCAPS table[] = { + DATA( "AX", BOOLEAN, 0 ), + DATA( "Cr", STRING, 0 ), + DATA( "Cs", STRING, 1 ), + DATA( "E0", STRING, 0 ), + DATA( "E3", STRING, 0 ), + DATA( "G0", BOOLEAN, 0 ), + DATA( "Ms", STRING, 2 ), + DATA( "RGB", BOOLEAN, 0 ), /* FIXME can be number or string */ + DATA( "S0", STRING, 1 ), + DATA( "Se", STRING, 0 ), + DATA( "Smulx", STRING, 1 ), + DATA( "Ss", STRING, 1 ), + DATA( "TS", STRING, 0 ), + DATA( "U8", NUMBER, 0 ), + DATA( "XM", STRING, 1 ), + DATA( "XT", BOOLEAN, 0 ), + DATA( "grbom", STRING, 0 ), + DATA( "gsbom", STRING, 0 ), + DATA( "rmxx", STRING, 0 ), + DATA( "smxx", STRING, 0 ), + DATA( "xm", STRING, 9 ), + }; +#undef DATA + /* *INDENT-ON* */ + + size_t n; + USERCAPS *result = 0; + if (*name != 'k') { + for (n = 0; n < SIZEOF(table); ++n) { + if (!strcmp(name, table[n].name)) { + result = &table[n]; + break; + } + } + } + return result; +} + /* + * If a given name is likely to be a user-capability, return the number of + * parameters it would be used with. If not, return -1. + * * ncurses assumes that u6 could be used for getting the cursor-position, but * that is not implemented. Make a special case for that, to quiet needless * warnings. * - * There are other string-capability extensions (see terminfo.src) which could - * have parameters such as "Ss", "%u", but are not used by ncurses. + * The other string-capability extensions (see terminfo.src) which could have + * parameters such as "Ss", "%u", are not used by ncurses. But we check those + * anyway, to validate the terminfo database. */ static int is_user_capability(const char *name) @@ -1769,8 +1904,14 @@ is_user_capability(const char *name) int result = -1; if (name[0] == 'u' && (name[1] >= '0' && name[1] <= '9') && - name[2] == '\0') + name[2] == '\0') { result = (name[1] == '6') ? 2 : 0; + } else if (using_extensions) { + USERCAPS *p = lookup_user_capability(name); + if (p != 0) { + result = p->n_parms; + } + } return result; } @@ -1818,11 +1959,15 @@ check_params(TERMTYPE2 *tp, const char *name, char *value, int extended) } if (extended) { - if (actual > 0) { - _nc_warning("extended %s capability has %d parameters", + int check = is_user_capability(name); + if (check != actual) { + _nc_warning("extended %s capability has %d parameters, expected %d", + name, actual, check); + } else if (debug_level > 1) { + _nc_warning("extended %s capability has %d parameters, as expected", name, actual); - expected = actual; } + expected = actual; } if (params[0]) { @@ -1856,8 +2001,8 @@ check_params(TERMTYPE2 *tp, const char *name, char *value, int extended) if ((user_cap == analyzed) && using_extensions) { ; /* ignore */ } else if (user_cap >= 0) { - _nc_warning("tparm will use %d parameters for %s", - analyzed, name); + _nc_warning("tparm will use %d parameters for %s, expected %d", + analyzed, name, user_cap); } else { _nc_warning("tparm analyzed %d parameters for %s, expected %d", analyzed, name, actual); @@ -2071,7 +2216,7 @@ check_1_infotocap(const char *name, NCURSES_CONST char *value, int count) myParam(9)); break; } - return result; + return strdup(result); } #define IsDelay(ch) ((ch) == '.' || isdigit(UChar(ch))) @@ -2223,7 +2368,8 @@ check_infotocap(TERMTYPE2 *tp, int i, const char *value) || !strcmp(name, "setb") || !strcmp(name, "setaf") || !strcmp(name, "setab")) { - limit = max_colors; + if ((limit = max_colors) > 16) + limit = 16; } for (count = 0; count < limit; ++count) { char *ti_check = check_1_infotocap(name, ti_value, count); @@ -2239,6 +2385,8 @@ check_infotocap(TERMTYPE2 *tp, int i, const char *value) _nc_warning("tparm-conversion of %s(%d) differs between\n\tterminfo %s\n\ttermcap %s", name, count, ti_check, tc_check); } + free(ti_check); + free(tc_check); } } else if (params == 0 && !same_ti_tc(ti_value, tc_value, &embedded)) { if (embedded) { @@ -2332,7 +2480,7 @@ similar_sgr(int num, char *a, char *b) ; } else if (b[0] == '$' && b[1] == '<') { - _nc_warning("Did not find delay %s", _nc_visbuf(b)); + _nc_warning("did not find delay %s", _nc_visbuf(b)); } else { _nc_warning("checking sgr(%s) %s\n\tcompare to %s\n\tunmatched %s", sgr_names[num], _nc_visbuf2(1, base_a), @@ -2520,7 +2668,7 @@ check_conflict(TERMTYPE2 *tp) check[k] = 1; if (first) { if (!conflict) { - _nc_warning("Conflicting key definitions (using the last)"); + _nc_warning("conflicting key definitions (using the last)"); conflict = TRUE; } fprintf(stderr, "..."); @@ -2697,6 +2845,63 @@ check_sgr_param(TERMTYPE2 *tp, int code, const char *name, char *value) } } +static int +standard_type(const char *name) +{ + int result = -1; + const struct name_table_entry *np; + + if ((np = _nc_find_entry(name, _nc_get_hash_table(0))) != 0) { + result = np->nte_type; + } + return result; +} + +static const char * +name_of_type(int type) +{ + const char *result = "unknown"; + switch (type) { + case BOOLEAN: + result = "boolean"; + break; + case NUMBER: + result = "number"; + break; + case STRING: + result = "string"; + break; + } + return result; +} + +static void +check_user_capability_type(const char *name, int actual) +{ + USERCAPS *p = lookup_user_capability(name); + if (p != 0) { + if (p->n_type != actual) + _nc_warning("expected %s to be %s, but actually %s", + name, + name_of_type(p->n_type), + name_of_type(actual) + ); + } else { + int expected = standard_type(name); + if (expected >= 0) { + _nc_warning("expected %s to be %s, but actually %s", + name, + name_of_type(p->n_type), + name_of_type(expected) + ); + } else if (*name != 'k') { + _nc_warning("undocumented %s capability %s", + name_of_type(actual), + name); + } + } +} + /* other sanity-checks (things that we don't want in the normal * logic that reads a terminfo entry) */ @@ -2716,7 +2921,7 @@ check_termtype(TERMTYPE2 *tp, bool literal) * check for consistent number of parameters. */ if (j >= SIZEOF(parametrized) || - is_user_capability(name) > 0 || + is_user_capability(name) >= 0 || parametrized[j] > 0) { check_params(tp, name, a, (j >= STRCOUNT)); } @@ -2726,6 +2931,18 @@ check_termtype(TERMTYPE2 *tp, bool literal) } } } +#if NCURSES_XNAMES + /* in extended mode, verify that each extension is expected type */ + for_each_ext_boolean(j, tp) { + check_user_capability_type(ExtBoolname(tp, (int) j, strnames), BOOLEAN); + } + for_each_ext_number(j, tp) { + check_user_capability_type(ExtNumname(tp, (int) j, strnames), NUMBER); + } + for_each_ext_string(j, tp) { + check_user_capability_type(ExtStrname(tp, (int) j, strnames), STRING); + } +#endif /* NCURSES_XNAMES */ check_acs(tp); check_colors(tp);