X-Git-Url: http://ncurses.scripts.mit.edu/?a=blobdiff_plain;ds=sidebyside;f=progs%2Ftic.c;h=fc77b34445ff84bf7ceb0411e251231a2435d803;hb=HEAD;hp=775889d688ed1d6ade1f9aa433d937a41a33b94a;hpb=a5fe3726f7d4374e9b1551b535c8617b423996f2;p=ncurses.git diff --git a/progs/tic.c b/progs/tic.c index 775889d6..fc77b344 100644 --- a/progs/tic.c +++ b/progs/tic.c @@ -1,5 +1,5 @@ /**************************************************************************** - * Copyright 2018-2020,2021 Thomas E. Dickey * + * Copyright 2018-2023,2024 Thomas E. Dickey * * Copyright 1998-2017,2018 Free Software Foundation, Inc. * * * * Permission is hereby granted, free of charge, to any person obtaining a * @@ -49,7 +49,7 @@ #include #include -MODULE_ID("$Id: tic.c,v 1.295 2021/04/17 15:18:02 tom Exp $") +MODULE_ID("$Id: tic.c,v 1.325 2024/03/02 19:33:22 tom Exp $") #define STDIN_NAME "" @@ -312,9 +312,9 @@ put_translate(int c) if (used + 1 >= have) { have += 132; - if ((namebuf = typeRealloc(char, have, namebuf)) == 0) + if ((namebuf = typeRealloc(char, have, namebuf)) == NULL) failed("put_translate namebuf"); - if ((suffix = typeRealloc(char, have, suffix)) == 0) + if ((suffix = typeRealloc(char, have, suffix)) == NULL) failed("put_translate suffix"); } if (c == '\n' || c == '@') { @@ -400,7 +400,7 @@ open_tempfile(char *filename) } #else if (tmpnam(filename) != 0) - result = fopen(filename, "w"); + result = safe_fopen(filename, "w"); #endif return result; } @@ -413,12 +413,12 @@ copy_input(FILE *source, const char *filename, char *alt_file) FILE *target; int ch; - if (alt_file == 0) + if (alt_file == NULL) alt_file = my_altfile; - if (source == 0) { + if (source == NULL) { failed("copy_input (source)"); - } else if ((target = open_tempfile(alt_file)) == 0) { + } else if ((target = open_tempfile(alt_file)) == NULL) { failed("copy_input (target)"); } else { clearerr(source); @@ -442,7 +442,7 @@ copy_input(FILE *source, const char *filename, char *alt_file) * the one that we were writing on before starting to read from the * second stream. */ - result = fopen(alt_file, "r+"); + result = safe_fopen(alt_file, "r+"); fclose(target); to_remove = strdup(alt_file); } @@ -458,18 +458,21 @@ open_input(const char *filename, char *alt_file) if (!strcmp(filename, "-")) { fp = copy_input(stdin, STDIN_NAME, alt_file); - } else if (stat(filename, &sb) < 0) { - fprintf(stderr, "%s: %s %s\n", _nc_progname, filename, strerror(errno)); + } else if (stat(filename, &sb) == -1) { + fprintf(stderr, "%s: cannot open '%s': %s\n", _nc_progname, + filename, strerror(errno)); ExitProgram(EXIT_FAILURE); } else if ((mode = (sb.st_mode & S_IFMT)) == S_IFDIR || (mode != S_IFREG && mode != S_IFCHR && mode != S_IFIFO)) { - fprintf(stderr, "%s: %s is not a file\n", _nc_progname, filename); + fprintf(stderr, "%s: cannot open '%s'; it is not a file\n", + _nc_progname, filename); ExitProgram(EXIT_FAILURE); } else { - fp = fopen(filename, "r"); + fp = safe_fopen(filename, "r"); - if (fp == 0) { - fprintf(stderr, "%s: Can't open %s\n", _nc_progname, filename); + if (fp == NULL) { + fprintf(stderr, "%s: cannot open '%s': %s\n", _nc_progname, + filename, strerror(errno)); ExitProgram(EXIT_FAILURE); } if (mode != S_IFREG) { @@ -477,7 +480,8 @@ open_input(const char *filename, char *alt_file) FILE *fp2 = copy_input(fp, filename, alt_file); fp = fp2; } else { - fprintf(stderr, "%s: %s is not a file\n", _nc_progname, filename); + fprintf(stderr, "%s: cannot open '%s'; it is not a" + " file\n", _nc_progname, filename); ExitProgram(EXIT_FAILURE); } } @@ -495,7 +499,7 @@ make_namelist(char *src) unsigned pass, n, nn; char buffer[BUFSIZ]; - if (src == 0) { + if (src == NULL) { /* EMPTY */ ; } else if (strchr(src, '/') != 0) { /* a filename */ FILE *fp = open_input(src, (char *) 0); @@ -512,7 +516,7 @@ make_namelist(char *src) } } if (pass == 1) { - if ((dst = typeCalloc(char *, nn + 1)) == 0) + if ((dst = typeCalloc(char *, nn + 1)) == NULL) failed("make_namelist"); rewind(fp); } @@ -536,7 +540,7 @@ make_namelist(char *src) break; } if (pass == 1) { - if ((dst = typeCalloc(char *, nn + 1)) == 0) + if ((dst = typeCalloc(char *, nn + 1)) == NULL) failed("make_namelist"); } } @@ -578,7 +582,7 @@ valid_db_path(const char *nominal) size_t need = strlen(nominal) + sizeof(suffix); char *result = malloc(need); - if (result == 0) + if (result == NULL) failed("valid_db_path"); _nc_STRCPY(result, nominal, need); if (strcmp(result + need - sizeof(suffix), suffix)) { @@ -643,8 +647,8 @@ show_databases(const char *outdir) char *result; const char *tried = 0; - if (outdir == 0) { - outdir = _nc_tic_dir(0); + if (outdir == NULL) { + outdir = _nc_tic_dir(NULL); } if ((result = valid_db_path(outdir)) != 0) { printf("%s\n", result); @@ -682,7 +686,6 @@ int main(int argc, char *argv[]) { char my_tmpname[PATH_MAX]; - char my_altfile[PATH_MAX]; int v_opt = -1; int smart_defaults = TRUE; char *termcap; @@ -701,7 +704,7 @@ main(int argc, char *argv[]) bool forceresolve = FALSE; /* force resolution */ bool limited = TRUE; char *tversion = (char *) NULL; - const char *source_file = "terminfo"; + const char *source_file; char *outdir = (char *) NULL; bool check_only = FALSE; bool suppress_untranslatable = FALSE; @@ -723,7 +726,8 @@ main(int argc, char *argv[]) sortmode = S_TERMCAP; } #if NCURSES_XNAMES - use_extended_names(FALSE); + /* set this directly to avoid interaction with -v and -D options */ + _nc_user_definable = FALSE; #endif _nc_strict_bsd = 0; @@ -776,7 +780,7 @@ main(int argc, char *argv[]) break; case 'D': debug_level = VtoTrace(v_opt); - set_trace_level(debug_level); + use_verbosity(debug_level); show_databases(outdir); ExitProgram(EXIT_SUCCESS); break; @@ -854,7 +858,6 @@ main(int argc, char *argv[]) _nc_disable_period = TRUE; /* FALLTHRU */ case 'x': - use_extended_names(TRUE); using_extensions = TRUE; break; #endif @@ -864,8 +867,23 @@ main(int argc, char *argv[]) last_opt = this_opt; } + /* + * If the -v option is set, it may override the $NCURSES_TRACE environment + * variable, e.g., for -v3 and up. + */ debug_level = VtoTrace(v_opt); - set_trace_level(debug_level); + use_verbosity(debug_level); + + /* + * Do this after setting debug_level, since the function calls START_TRACE, + * which uses the $NCURSES_TRACE environment variable if _nc_tracing bits + * for tracing are zero. + */ +#if NCURSES_XNAMES + if (using_extensions) { + use_extended_names(TRUE); + } +#endif if (_nc_tracing) { save_check_termtype = _nc_check_termtype2; @@ -878,7 +896,7 @@ main(int argc, char *argv[]) * One problem with immedhook is it means we can't do -e. Problem * is that we can't guarantee that for each terminal listed, all the * terminals it depends on will have been kept in core for reference - * resolution -- in fact it's certain the primitive types at the end + * resolution -- in fact it is certain the primitive types at the end * of reference chains *won't* be in core unless they were explicitly * in the select list themselves. */ @@ -932,7 +950,8 @@ main(int argc, char *argv[]) } } - if (tmp_fp == 0) { + if (tmp_fp == NULL) { + char my_altfile[PATH_MAX]; tmp_fp = open_input(source_file, my_altfile); if (!strcmp(source_file, "-")) { source_file = STDIN_NAME; @@ -1081,7 +1100,7 @@ main(int argc, char *argv[]) if (total != 0) fprintf(log_fp, "%d entries written to %s\n", total, - _nc_tic_dir((char *) 0)); + _nc_tic_dir(NULL)); else fprintf(log_fp, "No entries written\n"); } @@ -1154,6 +1173,7 @@ check_acs(TERMTYPE2 *tp) char *q; memset(mapped, 0, sizeof(mapped)); + memset(missing, 0, sizeof(missing)); for (p = acs_chars; *p != '\0'; p += 2) { if (p[1] == '\0') { _nc_warning("acsc has odd number of characters"); @@ -1218,7 +1238,7 @@ check_colors(TERMTYPE2 *tp) char *value; if ((max_colors > 0) != (max_pairs > 0) - || ((max_colors > max_pairs) && (initialize_pair == 0))) + || ((max_colors > max_pairs) && !VALID_STRING(initialize_pair))) _nc_warning("inconsistent values for max_colors (%d) and max_pairs (%d)", max_colors, max_pairs); @@ -1335,10 +1355,9 @@ check_ansi_cursor(char *list[4]) for (j = 0; j < 4; ++j) { skip[j] = FALSE; for (k = 0; k < j; ++k) { - if (j != k - && !strcmp(list[j], list[k])) { + if (!strcmp(list[j], list[k])) { char *value = _nc_tic_expand(list[k], TRUE, 0); - _nc_warning("repeated cursor control %s\n", value); + _nc_warning("repeated cursor control %s", value); repeated = TRUE; } } @@ -1367,19 +1386,19 @@ check_ansi_cursor(char *list[4]) continue; if (memcmp(list[j], up, prefix)) { char *value = _nc_tic_expand(list[j], TRUE, 0); - _nc_warning("inconsistent prefix for %s\n", value); + _nc_warning("inconsistent prefix for %s", value); continue; } if (strlen(list[j]) < suffix) { char *value = _nc_tic_expand(list[j], TRUE, 0); - _nc_warning("inconsistent length for %s, expected %d\n", + _nc_warning("inconsistent length for %s, expected %d", value, (int) suffix + 1); continue; } want = "BADC"[j]; if (list[j][suffix] != want) { char *value = _nc_tic_expand(list[j], TRUE, 0); - _nc_warning("inconsistent suffix for %s, expected %c, have %c\n", + _nc_warning("inconsistent suffix for %s, expected %c, have %c", value, want, list[j][suffix]); } } @@ -1412,7 +1431,7 @@ check_cursor(TERMTYPE2 *tp) check_noaddress(tp, "hard_copy"); } else if (generic_type) { check_noaddress(tp, "generic_type"); - } else if (strchr(tp->term_names, '+') == 0) { + } else if (strchr(tp->term_names, '+') == NULL) { int y = 0; int x = 0; if (PRESENT(column_address)) @@ -1669,20 +1688,10 @@ check_printer(TERMTYPE2 *tp) ANDMISSING(start_char_set_def, stop_char_set_def); #endif - /* if we have a parameterized form, then the non-parameterized is easy */ -#if defined(set_bottom_margin_parm) && defined(set_bottom_margin) - ANDMISSING(set_bottom_margin_parm, set_bottom_margin); -#endif -#if defined(set_left_margin_parm) && defined(set_left_margin) - ANDMISSING(set_left_margin_parm, set_left_margin); -#endif -#if defined(set_right_margin_parm) && defined(set_right_margin) - ANDMISSING(set_right_margin_parm, set_right_margin); -#endif -#if defined(set_top_margin_parm) && defined(set_top_margin) - ANDMISSING(set_top_margin_parm, set_top_margin); -#endif - + /* + * If we have a parameterized form, then the non-parameterized is easy. + * note: parameterized/non-parameterized margin settings are unrelated. + */ #if defined(parm_down_micro) && defined(micro_down) ANDMISSING(parm_down_micro, micro_down); #endif @@ -1721,7 +1730,7 @@ check_screen(TERMTYPE2 *tp) char *name = _nc_first_name(tp->term_names); bool is_screen = !strncmp(name, "screen", 6); bool screen_base = (is_screen - && strchr(name, '.') == 0); + && strchr(name, '.') == NULL); if (!VALID_BOOLEAN(have_bce)) { have_bce = FALSE; @@ -1751,6 +1760,8 @@ check_screen(TERMTYPE2 *tp) } else if (have_XT && screen_base) { _nc_warning("screen's \"screen\" entries should not have XT set"); } else if (have_XT) { + char *s; + if (!have_kmouse && is_screen) { if (VALID_STRING(key_mouse)) { _nc_warning("value of kmous inconsistent with screen's usage"); @@ -1766,12 +1777,14 @@ check_screen(TERMTYPE2 *tp) "to have 39/49 parameters", name_39_49); } } - if (VALID_STRING(to_status_line)) + if (VALID_STRING(to_status_line) + && (s = strchr(to_status_line, ';')) != NULL + && *++s == '\0') _nc_warning("\"tsl\" capability is redundant, given XT"); } else { if (have_kmouse && !have_XM - && !screen_base && strchr(name, '+') == 0) { + && !screen_base && strchr(name, '+') == NULL) { _nc_warning("expected XT to be set, given kmous"); } } @@ -1922,23 +1935,82 @@ is_user_capability(const char *name) return result; } +static bool +line_capability(const char *name) +{ + bool result = FALSE; + static const char *table[] = + { + "csr", /* change_scroll_region */ + "clear", /* clear_screen */ + "ed", /* clr_eos */ + "cwin", /* create_window */ + "cup", /* cursor_address */ + "cud1", /* cursor_down */ + "home", /* cursor_home */ + "mrcup", /* cursor_mem_address */ + "ll", /* cursor_to_ll */ + "cuu1", /* cursor_up */ + "dl1", /* delete_line */ + "hd", /* down_half_line */ + "flash", /* flash_screen */ + "ff", /* form_feed */ + "il1", /* insert_line */ + "nel", /* newline */ + "dl", /* parm_delete_line */ + "cud", /* parm_down_cursor */ + "indn", /* parm_index */ + "il", /* parm_insert_line */ + "rin", /* parm_rindex */ + "cuu", /* parm_up_cursor */ + "mc0", /* print_screen */ + "vpa", /* row_address */ + "ind", /* scroll_forward */ + "ri", /* scroll_reverse */ + "hu", /* up_half_line */ + }; + size_t n; + for (n = 0; n < SIZEOF(table); ++n) { + if (!strcmp(name, table[n])) { + result = TRUE; + break; + } + } + return result; +} + /* * Make a quick sanity check for the parameters which are used in the given * strings. If there are no "%p" tokens, then there should be no other "%" * markers. */ static void -check_params(TERMTYPE2 *tp, const char *name, char *value, int extended) +check_params(TERMTYPE2 *tp, const char *name, const char *value, int extended) { int expected = expected_params(name); int actual = 0; int n; bool params[1 + NUM_PARM]; - char *s = value; + const char *s = value; +#ifdef set_left_margin_parm + if (!strcmp(name, "smgrp") + && !VALID_STRING(set_left_margin_parm)) + expected = 2; +#endif +#ifdef set_right_margin_parm + if (!strcmp(name, "smglp") + && !VALID_STRING(set_right_margin_parm)) + expected = 2; +#endif #ifdef set_top_margin_parm if (!strcmp(name, "smgbp") - && set_top_margin_parm == 0) + && !VALID_STRING(set_top_margin_parm)) + expected = 2; +#endif +#ifdef set_bottom_margin_parm + if (!strcmp(name, "smgtp") + && !VALID_STRING(set_bottom_margin_parm)) expected = 2; #endif @@ -2000,10 +2072,11 @@ check_params(TERMTYPE2 *tp, const char *name, char *value, int extended) * may not have been fully translated. Also, tparm does its own analysis. * Report differences here. */ + _nc_reset_tparm(NULL); if (actual >= 0) { char *p_is_s[NUM_PARM]; int popcount; - int analyzed = _nc_tparm_analyze(value, p_is_s, &popcount); + int analyzed = _nc_tparm_analyze(NULL, value, p_is_s, &popcount); if (analyzed < popcount) { analyzed = popcount; } @@ -2021,54 +2094,37 @@ check_params(TERMTYPE2 *tp, const char *name, char *value, int extended) _nc_warning("tparm analyzed %d parameters for %s, expected %d", analyzed, name, actual); } + } else if (expected > 0 + && actual == expected + && guess_tparm_type(expected, p_is_s) == Numbers) { + int limit = 1; + + if (!strcmp(name, "setf") + || !strcmp(name, "setb") + || !strcmp(name, "setaf") + || !strcmp(name, "setab")) { + if ((limit = max_colors) > 256) + limit = 256; + } else if (line_capability(name)) { + limit = 24; + } else if (is_user_capability(name) < 0) { + limit = 80; + } + for (n = 0; n < limit; ++n) { + _nc_reset_tparm(NULL); + (void) TPARM_9(value, n, n, n, n, n, n, n, n, n); + if (_nc_tparm_err) { + _nc_warning("problem%s in tparm(%s, %d, ...)", + (_nc_tparm_err == 1) ? "" : "s", + name, n); + if (debug_level < 2) + break; + } + } } } } -static bool -line_capability(const char *name) -{ - bool result = FALSE; - static const char *table[] = - { - "csr", /* change_scroll_region */ - "clear", /* clear_screen */ - "ed", /* clr_eos */ - "cwin", /* create_window */ - "cup", /* cursor_address */ - "cud1", /* cursor_down */ - "home", /* cursor_home */ - "mrcup", /* cursor_mem_address */ - "ll", /* cursor_to_ll */ - "cuu1", /* cursor_up */ - "dl1", /* delete_line */ - "hd", /* down_half_line */ - "flash", /* flash_screen */ - "ff", /* form_feed */ - "il1", /* insert_line */ - "nel", /* newline */ - "dl", /* parm_delete_line */ - "cud", /* parm_down_cursor */ - "indn", /* parm_index */ - "il", /* parm_insert_line */ - "rin", /* parm_rindex */ - "cuu", /* parm_up_cursor */ - "mc0", /* print_screen */ - "vpa", /* row_address */ - "ind", /* scroll_forward */ - "ri", /* scroll_reverse */ - "hu", /* up_half_line */ - }; - size_t n; - for (n = 0; n < SIZEOF(table); ++n) { - if (!strcmp(name, table[n])) { - result = TRUE; - break; - } - } - return result; -} - /* * Check for DEC VT100 private mode for reverse video. */ @@ -2111,7 +2167,7 @@ check_delays(TERMTYPE2 *tp, const char *name, const char *value) for (q = base; *q != '\0'; ++q) { if (*q == '>') { - if (mark == 0) + if (mark == NULL) mark = q; break; } else if (*q == '*' || *q == '/') { @@ -2119,7 +2175,7 @@ check_delays(TERMTYPE2 *tp, const char *name, const char *value) ++proportional; if (*q == '/') ++mandatory; - if (mark == 0) + if (mark == NULL) mark = q; } else if (!(isalnum(UChar(*q)) || strchr("+-.", *q) != 0)) { break; @@ -2141,7 +2197,7 @@ check_delays(TERMTYPE2 *tp, const char *name, const char *value) _nc_warning("non-line capability using proportional delay: %s", name); } else if (!xon_xoff && !mandatory && - strchr(_nc_first_name(tp->term_names), '+') == 0) { + strchr(_nc_first_name(tp->term_names), '+') == NULL) { _nc_warning("%s in %s is used since no xon/xoff", (proportional ? "proportional delay" @@ -2206,8 +2262,9 @@ check_1_infotocap(const char *name, NCURSES_CONST char *value, int count) next += strlen(next) + 1; } + _nc_reset_tparm(NULL); expect = tparm_type(name); - nparam = _nc_tparm_analyze(value, p_is_s, &ignored); + nparam = _nc_tparm_analyze(NULL, value, p_is_s, &ignored); actual = guess_tparm_type(nparam, p_is_s); if (expect != actual) { @@ -2215,10 +2272,17 @@ check_1_infotocap(const char *name, NCURSES_CONST char *value, int count) actual = Other; } + _nc_reset_tparm(NULL); switch (actual) { + case Str: + result = TPARM_1(value, strings[1]); + break; case Num_Str: result = TPARM_2(value, numbers[1], strings[2]); break; + case Str_Str: + result = TPARM_2(value, strings[1], strings[2]); + break; case Num_Str_Str: result = TPARM_3(value, numbers[1], strings[2], strings[3]); break; @@ -2279,7 +2343,7 @@ parse_delay_value(const char *src, double *delays, int *always) } } while (*src == '*' || *src == '/') { - if (always == 0 && *src == '/') + if (always == NULL && *src == '/') break; if (*src++ == '*') { star = 1; @@ -2380,60 +2444,63 @@ static void check_infotocap(TERMTYPE2 *tp, int i, const char *value) { const char *name = ExtStrname(tp, i, strnames); - int params = ((i < (int) SIZEOF(parametrized)) - ? parametrized[i] - : ((*value == 'k') - ? 0 - : has_params(value, FALSE))); char *ti_value = NULL; - char *tc_value; - bool embedded; assert(SIZEOF(parametrized) == STRCOUNT); if (!VALID_STRING(value) || (ti_value = strdup(value)) == NULL) { _nc_warning("tic-expansion of %s failed", name); - } else if ((tc_value = _nc_infotocap(name, ti_value, params)) == ABSENT_STRING) { - _nc_warning("tic-conversion of %s failed", name); - } else if (params > 0) { - int limit = 5; - int count; - bool first = TRUE; - - if (!strcmp(name, "setf") - || !strcmp(name, "setb") - || !strcmp(name, "setaf") - || !strcmp(name, "setab")) { - if ((limit = max_colors) > 16) - limit = 16; - } - for (count = 0; count < limit; ++count) { - char *ti_check = check_1_infotocap(name, ti_value, count); - char *tc_check = check_1_infotocap(name, tc_value, count); - - if (strcmp(ti_check, tc_check)) { - if (first) { - fprintf(stderr, "check_infotocap(%s)\n", name); - fprintf(stderr, "...ti '%s'\n", _nc_visbuf2(0, ti_value)); - fprintf(stderr, "...tc '%s'\n", _nc_visbuf2(0, tc_value)); - first = FALSE; + } else { + char *tc_value; + bool embedded; + int params = ((i < (int) SIZEOF(parametrized)) + ? parametrized[i] + : ((*value == 'k') + ? 0 + : has_params(value, FALSE))); + + if ((tc_value = _nc_infotocap(name, ti_value, params)) == ABSENT_STRING) { + _nc_warning("tic-conversion of %s failed", name); + } else if (params > 0) { + int limit = 5; + int count; + bool first = TRUE; + + if (!strcmp(name, "setf") + || !strcmp(name, "setb") + || !strcmp(name, "setaf") + || !strcmp(name, "setab")) { + if ((limit = max_colors) > 256) + limit = 256; + } + for (count = 0; count < limit; ++count) { + char *ti_check = check_1_infotocap(name, ti_value, count); + char *tc_check = check_1_infotocap(name, tc_value, count); + + if (strcmp(ti_check, tc_check)) { + if (first) { + fprintf(stderr, "check_infotocap(%s)\n", name); + fprintf(stderr, "...ti '%s'\n", _nc_visbuf2(0, ti_value)); + fprintf(stderr, "...tc '%s'\n", _nc_visbuf2(0, tc_value)); + first = FALSE; + } + _nc_warning("tparm-conversion of %s(%d) differs between\n\tterminfo %s\n\ttermcap %s", + name, count, + _nc_visbuf2(0, ti_check), + _nc_visbuf2(1, tc_check)); } - _nc_warning("tparm-conversion of %s(%d) differs between\n\tterminfo %s\n\ttermcap %s", - name, count, - _nc_visbuf2(0, ti_check), - _nc_visbuf2(1, tc_check)); + free(ti_check); + free(tc_check); + } + } else if (params == 0 && !same_ti_tc(ti_value, tc_value, &embedded)) { + if (embedded) { + _nc_warning("termcap equivalent of %s cannot use embedded delay", name); + } else { + _nc_warning("tic-conversion of %s changed value\n\tfrom %s\n\tto %s", + name, ti_value, tc_value); } - free(ti_check); - free(tc_check); - } - } else if (params == 0 && !same_ti_tc(ti_value, tc_value, &embedded)) { - if (embedded) { - _nc_warning("termcap equivalent of %s cannot use embedded delay", name); - } else { - _nc_warning("tic-conversion of %s changed value\n\tfrom %s\n\tto %s", - name, ti_value, tc_value); } + free(ti_value); } - free(ti_value); } static char * @@ -2636,7 +2703,7 @@ get_fkey_list(TERMTYPE2 *tp) int used = 0; unsigned j; - if (result == 0) + if (result == NULL) failed("get_fkey_list"); for (j = 0; all_fkeys[j].code; j++) { @@ -2682,14 +2749,13 @@ show_fkey_name(NAME_VALUE * data) static void check_conflict(TERMTYPE2 *tp) { - bool conflict = FALSE; - if (!(_nc_syntax == SYN_TERMCAP && capdump)) { char *check = calloc((size_t) (NUM_STRINGS(tp) + 1), sizeof(char)); NAME_VALUE *given = get_fkey_list(tp); unsigned j, k; + bool conflict = FALSE; - if (check == 0) + if (check == NULL) failed("check_conflict"); for (j = 0; given[j].keycode; ++j) { @@ -2939,6 +3005,190 @@ check_user_capability_type(const char *name, int actual) } #endif +#define IN_DELAY "0123456789*/." + +static bool +check_ANSI_cap(const char *value, int nparams, char final) +{ + bool result = FALSE; + if (VALID_STRING(value) && csi_length(value) > 0) { + char *p_is_s[NUM_PARM]; + int popcount; + int analyzed = _nc_tparm_analyze(NULL, value, p_is_s, &popcount); + if (analyzed < popcount) { + analyzed = popcount; + } + if (analyzed == nparams) { + bool numbers = TRUE; + int p; + for (p = 0; p < nparams; ++p) { + if (p_is_s[p]) { + numbers = FALSE; + break; + } + } + if (numbers) { + int in_delay = 0; + p = (int) strlen(value); + while (p-- > 0) { + char ch = value[p]; + if (ch == final) { + result = TRUE; + break; + } + switch (in_delay) { + case 0: + if (ch == '>') + in_delay = 1; + break; + case 1: + if (strchr(IN_DELAY, value[p]) != NULL) + break; + if (ch != '<') + p = 0; + in_delay = 2; + break; + case 2: + if (ch != '$') + p = 0; + in_delay = 0; + break; + } + } + } + } + } + return result; +} + +static const char * +skip_Delay(const char *value) +{ + const char *result = value; + + if (*value == '$') { + ++result; + if (*result++ == '<') { + while (strchr(IN_DELAY, *result) != NULL) + ++result; + if (*result++ != '>') { + result = value; + } + } else { + result = value; + } + } + return result; +} + +static bool +isValidString(const char *value, const char *expect) +{ + bool result = FALSE; + if (VALID_STRING(value)) { + if (!strcmp(value, expect)) + result = TRUE; + } + return result; +} + +static bool +isValidEscape(const char *value, const char *expect) +{ + bool result = FALSE; + if (VALID_STRING(value)) { + if (*value == '\033') { + size_t need = strlen(expect); + size_t have = strlen(value) - 1; + if (have >= need && !strncmp(value + 1, expect, need)) { + if (*skip_Delay(value + need + 1) == '\0') { + result = TRUE; + } + } + } + } + return result; +} + +static int +guess_ANSI_VTxx(TERMTYPE2 *tp) +{ + int result = -1; + int checks = 0; + + /* VT100s have scrolling region, but ANSI (ECMA-48) does not specify */ + if (check_ANSI_cap(change_scroll_region, 2, 'r') && + (isValidEscape(scroll_forward, "D") || + isValidString(scroll_forward, "\n") || + isValidEscape(scroll_forward, "6")) && + (isValidEscape(scroll_reverse, "M") || + isValidEscape(scroll_reverse, "9"))) { + checks |= 2; + } + if (check_ANSI_cap(cursor_address, 2, 'H') && + check_ANSI_cap(cursor_up, 0, 'A') && + (check_ANSI_cap(cursor_down, 0, 'B') || + isValidString(cursor_down, "\n")) && + check_ANSI_cap(cursor_right, 0, 'C') && + (check_ANSI_cap(cursor_left, 0, 'D') || + isValidString(cursor_left, "\b")) && + check_ANSI_cap(clr_eos, 0, 'J') && + check_ANSI_cap(clr_bol, 0, 'K') && + check_ANSI_cap(clr_eol, 0, 'K')) { + checks |= 1; + } + if (checks == 3) + result = 1; + if (checks == 1) + result = 0; + return result; +} + +/* + * u6/u7 and u8/u9 are query/response extensions which most terminals support. + * In particular, any ECMA-48 terminal should support these, though the details + * for u9 are implementation dependent. + */ +#if defined(user6) && defined(user7) && defined(user8) && defined(user9) +static void +check_user_6789(TERMTYPE2 *tp) +{ + /* + * Check if the terminal is known to not + */ +#define NO_QUERY(longname,shortname) \ + if (PRESENT(longname)) _nc_warning(#shortname " is not supported") + if (tigetflag("NQ") > 0) { + NO_QUERY(user6, u6); + NO_QUERY(user7, u7); + NO_QUERY(user8, u8); + NO_QUERY(user9, u9); + return; + } + + PAIRED(user6, user7); + PAIRED(user8, user9); + + if (strchr(tp->term_names, '+') != NULL) + return; + + switch (guess_ANSI_VTxx(tp)) { + case 1: + if (!PRESENT(user8)) { + _nc_warning("expected u8/u9 for device-attributes"); + } + /* FALLTHRU */ + case 0: + if (!PRESENT(user6)) { + _nc_warning("expected u6/u7 for cursor-position"); + } + break; + } +} +#else +#define check_user_6789(tp) /* nothing */ +#endif + /* other sanity-checks (things that we don't want in the normal * logic that reads a terminfo entry) */ @@ -2987,6 +3237,7 @@ check_termtype(TERMTYPE2 *tp, bool literal) check_keypad(tp); check_printer(tp); check_screen(tp); + check_user_6789(tp); /* * These are probably both or none. @@ -3052,7 +3303,7 @@ check_termtype(TERMTYPE2 *tp, bool literal) if (PRESENT(exit_attribute_mode)) { char *check_sgr0 = _nc_trim_sgr0(tp); - if (check_sgr0 == 0 || *check_sgr0 == '\0') { + if (check_sgr0 == NULL || *check_sgr0 == '\0') { _nc_warning("trimmed sgr0 is empty"); } else { show_where(2);